blob: deaf76194b82ff8b0996758e30ee9dc95e0f9bd1 [file] [log] [blame]
Jarkko Poyry3c827362014-09-02 11:48:52 +03001/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Floating-point packing and unpacking function tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fShaderPackingFunctionTests.hpp"
25#include "glsShaderExecUtil.hpp"
26#include "tcuTestLog.hpp"
27#include "tcuFormatUtil.hpp"
28#include "tcuFloat.hpp"
29#include "deRandom.hpp"
30#include "deMath.h"
31#include "deString.h"
32
33namespace deqp
34{
35namespace gles31
36{
37namespace Functional
38{
39
40using std::string;
41using tcu::TestLog;
42using namespace gls::ShaderExecUtil;
43
44namespace
45{
46
47inline deUint32 getUlpDiff (float a, float b)
48{
49 const deUint32 aBits = tcu::Float32(a).bits();
50 const deUint32 bBits = tcu::Float32(b).bits();
51 return aBits > bBits ? aBits - bBits : bBits - aBits;
52}
53
54struct HexFloat
55{
56 const float value;
57 HexFloat (const float value_) : value(value_) {}
58};
59
60std::ostream& operator<< (std::ostream& str, const HexFloat& v)
61{
62 return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
63}
64
65} // anonymous
66
67// ShaderPackingFunctionCase
68
69class ShaderPackingFunctionCase : public TestCase
70{
71public:
72 ShaderPackingFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType);
73 ~ShaderPackingFunctionCase (void);
74
75 void init (void);
76 void deinit (void);
77
78protected:
79 glu::ShaderType m_shaderType;
80 ShaderSpec m_spec;
81 ShaderExecutor* m_executor;
82
83private:
84 ShaderPackingFunctionCase (const ShaderPackingFunctionCase& other);
85 ShaderPackingFunctionCase& operator= (const ShaderPackingFunctionCase& other);
86};
87
88ShaderPackingFunctionCase::ShaderPackingFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
89 : TestCase (context, name, description)
90 , m_shaderType (shaderType)
91 , m_executor (DE_NULL)
92{
93 m_spec.version = glu::GLSL_VERSION_310_ES;
94}
95
96ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
97{
98 ShaderPackingFunctionCase::deinit();
99}
100
101void ShaderPackingFunctionCase::init (void)
102{
103 DE_ASSERT(!m_executor);
104
105 m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
106 m_testCtx.getLog() << m_executor;
107
108 if (!m_executor->isOk())
109 throw tcu::TestError("Compile failed");
110}
111
112void ShaderPackingFunctionCase::deinit (void)
113{
114 delete m_executor;
115 m_executor = DE_NULL;
116}
117
118// Test cases
119
120static const char* getPrecisionPostfix (glu::Precision precision)
121{
122 static const char* s_postfix[] =
123 {
124 "_lowp",
125 "_mediump",
126 "_highp"
127 };
128 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
129 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
130 return s_postfix[precision];
131}
132
133static const char* getShaderTypePostfix (glu::ShaderType shaderType)
134{
135 static const char* s_postfix[] =
136 {
137 "_vertex",
138 "_fragment",
139 "_geometry",
140 "_tess_control",
141 "_tess_eval",
142 "_compute"
143 };
144 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
145 return s_postfix[shaderType];
146}
147
148class PackSnorm2x16Case : public ShaderPackingFunctionCase
149{
150public:
151 PackSnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
152 : ShaderPackingFunctionCase (context, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType)
153 , m_precision (precision)
154 {
155 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
156 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
157
158 m_spec.source = "out0 = packSnorm2x16(in0);";
159 }
160
161 IterateResult iterate (void)
162 {
163 de::Random rnd (deStringHash(getName()) ^ 0x776002);
164 std::vector<tcu::Vec2> inputs;
165 std::vector<deUint32> outputs;
166 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
167 m_precision == glu::PRECISION_MEDIUMP ? 33 : // (2^-10) * (2^15) + 1
168 m_precision == glu::PRECISION_LOWP ? 129 : 0; // (2^-8) * (2^15) + 1
169
170 // Special values to check.
171 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
172 inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
173 inputs.push_back(tcu::Vec2(0.5f, -0.5f));
174 inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
175 inputs.push_back(tcu::Vec2(0.25f, -0.75f));
176
177 // Random values, mostly in range.
178 for (int ndx = 0; ndx < 15; ndx++)
179 {
180 const float x = rnd.getFloat()*2.5f - 1.25f;
181 const float y = rnd.getFloat()*2.5f - 1.25f;
182 inputs.push_back(tcu::Vec2(x, y));
183 }
184
185 // Large random values.
186 for (int ndx = 0; ndx < 80; ndx++)
187 {
188 const float x = rnd.getFloat()*1e6f - 0.5e6f;
189 const float y = rnd.getFloat()*1e6f - 0.5e6f;
190 inputs.push_back(tcu::Vec2(x, y));
191 }
192
193 outputs.resize(inputs.size());
194
195 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
196
197 {
198 const void* in = &inputs[0];
199 void* out = &outputs[0];
200
201 m_executor->useProgram();
202 m_executor->execute((int)inputs.size(), &in, &out);
203 }
204
205 // Verify
206 {
207 const int numValues = (int)inputs.size();
208 const int maxPrints = 10;
209 int numFailed = 0;
210
211 for (int valNdx = 0; valNdx < numValues; valNdx++)
212 {
213 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
214 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
215 const deUint32 ref = (ref1 << 16) | ref0;
216 const deUint32 res = outputs[valNdx];
217 const deUint16 res0 = (deUint16)(res & 0xffff);
218 const deUint16 res1 = (deUint16)(res >> 16);
219 const int diff0 = de::abs((int)ref0 - (int)res0);
220 const int diff1 = de::abs((int)ref1 - (int)res1);
221
222 if (diff0 > maxDiff || diff1 > maxDiff)
223 {
224 if (numFailed < maxPrints)
225 {
226 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
227 << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
228 << ", got " << tcu::toHex(res)
229 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
230 << TestLog::EndMessage;
231 }
232 else if (numFailed == maxPrints)
233 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
234
235 numFailed += 1;
236 }
237 }
238
239 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
240
241 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
242 numFailed == 0 ? "Pass" : "Result comparison failed");
243 }
244
245 return STOP;
246 }
247
248private:
249 glu::Precision m_precision;
250};
251
252class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
253{
254public:
255 UnpackSnorm2x16Case (Context& context, glu::ShaderType shaderType)
256 : ShaderPackingFunctionCase(context, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
257 {
258 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
259 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
260
261 m_spec.source = "out0 = unpackSnorm2x16(in0);";
262 }
263
264 IterateResult iterate (void)
265 {
266 const deUint32 maxDiff = 1; // Rounding error.
267 de::Random rnd (deStringHash(getName()) ^ 0x776002);
268 std::vector<deUint32> inputs;
269 std::vector<tcu::Vec2> outputs;
270
271 inputs.push_back(0x00000000u);
272 inputs.push_back(0x7fff8000u);
273 inputs.push_back(0x80007fffu);
274 inputs.push_back(0xffffffffu);
275 inputs.push_back(0x0001fffeu);
276
277 // Random values.
278 for (int ndx = 0; ndx < 95; ndx++)
279 inputs.push_back(rnd.getUint32());
280
281 outputs.resize(inputs.size());
282
283 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
284
285 {
286 const void* in = &inputs[0];
287 void* out = &outputs[0];
288
289 m_executor->useProgram();
290 m_executor->execute((int)inputs.size(), &in, &out);
291 }
292
293 // Verify
294 {
295 const int numValues = (int)inputs.size();
296 const int maxPrints = 10;
297 int numFailed = 0;
298
299 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
300 {
301 const deInt16 in0 = (deInt16)(deUint16)(inputs[valNdx] & 0xffff);
302 const deInt16 in1 = (deInt16)(deUint16)(inputs[valNdx] >> 16);
303 const float ref0 = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
304 const float ref1 = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
305 const float res0 = outputs[valNdx].x();
306 const float res1 = outputs[valNdx].y();
307
308 const deUint32 diff0 = getUlpDiff(ref0, res0);
309 const deUint32 diff1 = getUlpDiff(ref1, res1);
310
311 if (diff0 > maxDiff || diff1 > maxDiff)
312 {
313 if (numFailed < maxPrints)
314 {
315 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
316 << " expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
317 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
318 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
319 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
320 << TestLog::EndMessage;
321 }
322 else if (numFailed == maxPrints)
323 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
324
325 numFailed += 1;
326 }
327 }
328
329 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
330
331 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
332 numFailed == 0 ? "Pass" : "Result comparison failed");
333 }
334
335 return STOP;
336 }
337};
338
339class PackUnorm2x16Case : public ShaderPackingFunctionCase
340{
341public:
342 PackUnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
343 : ShaderPackingFunctionCase (context, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType)
344 , m_precision (precision)
345 {
346 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
347 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
348
349 m_spec.source = "out0 = packUnorm2x16(in0);";
350 }
351
352 IterateResult iterate (void)
353 {
354 de::Random rnd (deStringHash(getName()) ^ 0x776002);
355 std::vector<tcu::Vec2> inputs;
356 std::vector<deUint32> outputs;
357 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
358 m_precision == glu::PRECISION_MEDIUMP ? 65 : // (2^-10) * (2^16) + 1
359 m_precision == glu::PRECISION_LOWP ? 257 : 0; // (2^-8) * (2^16) + 1
360
361 // Special values to check.
362 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
363 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
364 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
365 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
366 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
367
368 // Random values, mostly in range.
369 for (int ndx = 0; ndx < 15; ndx++)
370 {
371 const float x = rnd.getFloat()*1.25f;
372 const float y = rnd.getFloat()*1.25f;
373 inputs.push_back(tcu::Vec2(x, y));
374 }
375
376 // Large random values.
377 for (int ndx = 0; ndx < 80; ndx++)
378 {
379 const float x = rnd.getFloat()*1e6f - 1e5f;
380 const float y = rnd.getFloat()*1e6f - 1e5f;
381 inputs.push_back(tcu::Vec2(x, y));
382 }
383
384 outputs.resize(inputs.size());
385
386 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
387
388 {
389 const void* in = &inputs[0];
390 void* out = &outputs[0];
391
392 m_executor->useProgram();
393 m_executor->execute((int)inputs.size(), &in, &out);
394 }
395
396 // Verify
397 {
398 const int numValues = (int)inputs.size();
399 const int maxPrints = 10;
400 int numFailed = 0;
401
402 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
403 {
404 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
405 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
406 const deUint32 ref = (ref1 << 16) | ref0;
407 const deUint32 res = outputs[valNdx];
408 const deUint16 res0 = (deUint16)(res & 0xffff);
409 const deUint16 res1 = (deUint16)(res >> 16);
410 const int diff0 = de::abs((int)ref0 - (int)res0);
411 const int diff1 = de::abs((int)ref1 - (int)res1);
412
413 if (diff0 > maxDiff || diff1 > maxDiff)
414 {
415 if (numFailed < maxPrints)
416 {
417 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
418 << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
419 << ", got " << tcu::toHex(res)
420 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
421 << TestLog::EndMessage;
422 }
423 else if (numFailed == maxPrints)
424 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
425
426 numFailed += 1;
427 }
428 }
429
430 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
431
432 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
433 numFailed == 0 ? "Pass" : "Result comparison failed");
434 }
435
436 return STOP;
437 }
438
439private:
440 glu::Precision m_precision;
441};
442
443class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
444{
445public:
446 UnpackUnorm2x16Case (Context& context, glu::ShaderType shaderType)
447 : ShaderPackingFunctionCase(context, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
448 {
449 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
450 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
451
452 m_spec.source = "out0 = unpackUnorm2x16(in0);";
453 }
454
455 IterateResult iterate (void)
456 {
457 const deUint32 maxDiff = 1; // Rounding error.
458 de::Random rnd (deStringHash(getName()) ^ 0x776002);
459 std::vector<deUint32> inputs;
460 std::vector<tcu::Vec2> outputs;
461
462 inputs.push_back(0x00000000u);
463 inputs.push_back(0x7fff8000u);
464 inputs.push_back(0x80007fffu);
465 inputs.push_back(0xffffffffu);
466 inputs.push_back(0x0001fffeu);
467
468 // Random values.
469 for (int ndx = 0; ndx < 95; ndx++)
470 inputs.push_back(rnd.getUint32());
471
472 outputs.resize(inputs.size());
473
474 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
475
476 {
477 const void* in = &inputs[0];
478 void* out = &outputs[0];
479
480 m_executor->useProgram();
481 m_executor->execute((int)inputs.size(), &in, &out);
482 }
483
484 // Verify
485 {
486 const int numValues = (int)inputs.size();
487 const int maxPrints = 10;
488 int numFailed = 0;
489
490 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
491 {
492 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff);
493 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16);
494 const float ref0 = float(in0) / 65535.0f;
495 const float ref1 = float(in1) / 65535.0f;
496 const float res0 = outputs[valNdx].x();
497 const float res1 = outputs[valNdx].y();
498
499 const deUint32 diff0 = getUlpDiff(ref0, res0);
500 const deUint32 diff1 = getUlpDiff(ref1, res1);
501
502 if (diff0 > maxDiff || diff1 > maxDiff)
503 {
504 if (numFailed < maxPrints)
505 {
506 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
507 << " expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
508 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
509 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
510 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
511 << TestLog::EndMessage;
512 }
513 else if (numFailed == maxPrints)
514 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
515
516 numFailed += 1;
517 }
518 }
519
520 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
521
522 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
523 numFailed == 0 ? "Pass" : "Result comparison failed");
524 }
525
526 return STOP;
527 }
528};
529
530class PackHalf2x16Case : public ShaderPackingFunctionCase
531{
532public:
533 PackHalf2x16Case (Context& context, glu::ShaderType shaderType)
534 : ShaderPackingFunctionCase(context, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
535 {
536 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
537 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
538
539 m_spec.source = "out0 = packHalf2x16(in0);";
540 }
541
542 IterateResult iterate (void)
543 {
544 const int maxDiff = 0; // Values can be represented exactly in mediump.
545 de::Random rnd (deStringHash(getName()) ^ 0x776002);
546 std::vector<tcu::Vec2> inputs;
547 std::vector<deUint32> outputs;
548
549 // Special values to check.
550 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
551 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
552 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
553 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
554 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
555
556 // Random values.
557 {
558 const int minExp = -14;
559 const int maxExp = 15;
560
561 for (int ndx = 0; ndx < 95; ndx++)
562 {
563 tcu::Vec2 v;
564 for (int c = 0; c < 2; c++)
565 {
566 const int s = rnd.getBool() ? 1 : -1;
567 const int exp = rnd.getInt(minExp, maxExp);
568 const deUint32 mantissa = rnd.getUint32() & ((1<<23)-1);
569
570 v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
571 }
572 inputs.push_back(v);
573 }
574 }
575
576 // Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
577 for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
578 *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
579
580 outputs.resize(inputs.size());
581
582 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
583
584 {
585 const void* in = &inputs[0];
586 void* out = &outputs[0];
587
588 m_executor->useProgram();
589 m_executor->execute((int)inputs.size(), &in, &out);
590 }
591
592 // Verify
593 {
594 const int numValues = (int)inputs.size();
595 const int maxPrints = 10;
596 int numFailed = 0;
597
598 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
599 {
600 const deUint16 ref0 = (deUint16)tcu::Float16(inputs[valNdx].x()).bits();
601 const deUint16 ref1 = (deUint16)tcu::Float16(inputs[valNdx].y()).bits();
602 const deUint32 ref = (ref1 << 16) | ref0;
603 const deUint32 res = outputs[valNdx];
604 const deUint16 res0 = (deUint16)(res & 0xffff);
605 const deUint16 res1 = (deUint16)(res >> 16);
606 const int diff0 = de::abs((int)ref0 - (int)res0);
607 const int diff1 = de::abs((int)ref1 - (int)res1);
608
609 if (diff0 > maxDiff || diff1 > maxDiff)
610 {
611 if (numFailed < maxPrints)
612 {
613 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
614 << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
615 << ", got " << tcu::toHex(res)
616 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
617 << TestLog::EndMessage;
618 }
619 else if (numFailed == maxPrints)
620 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
621
622 numFailed += 1;
623 }
624 }
625
626 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
627
628 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
629 numFailed == 0 ? "Pass" : "Result comparison failed");
630 }
631
632 return STOP;
633 }
634};
635
636class UnpackHalf2x16Case : public ShaderPackingFunctionCase
637{
638public:
639 UnpackHalf2x16Case (Context& context, glu::ShaderType shaderType)
640 : ShaderPackingFunctionCase(context, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
641 {
642 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
643 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
644
645 m_spec.source = "out0 = unpackHalf2x16(in0);";
646 }
647
648 IterateResult iterate (void)
649 {
650 const int maxDiff = 0; // All bits must be accurate.
651 de::Random rnd (deStringHash(getName()) ^ 0x776002);
652 std::vector<deUint32> inputs;
653 std::vector<tcu::Vec2> outputs;
654
655 // Special values.
656 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
657 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
658 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
659 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
660
661 // Construct random values.
662 {
663 const int minExp = -14;
664 const int maxExp = 15;
665 const int mantBits = 10;
666
667 for (int ndx = 0; ndx < 96; ndx++)
668 {
669 deUint32 inVal = 0;
670 for (int c = 0; c < 2; c++)
671 {
672 const int s = rnd.getBool() ? 1 : -1;
673 const int exp = rnd.getInt(minExp, maxExp);
674 const deUint32 mantissa = rnd.getUint32() & ((1<<mantBits)-1);
Jarkko Pöyry7a161d22015-05-19 20:44:07 -0700675 const deUint16 value = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits();
Jarkko Poyry3c827362014-09-02 11:48:52 +0300676
677 inVal |= value << (16*c);
678 }
679 inputs.push_back(inVal);
680 }
681 }
682
683 outputs.resize(inputs.size());
684
685 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
686
687 {
688 const void* in = &inputs[0];
689 void* out = &outputs[0];
690
691 m_executor->useProgram();
692 m_executor->execute((int)inputs.size(), &in, &out);
693 }
694
695 // Verify
696 {
697 const int numValues = (int)inputs.size();
698 const int maxPrints = 10;
699 int numFailed = 0;
700
701 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
702 {
703 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff);
704 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16);
705 const float ref0 = tcu::Float16(in0).asFloat();
706 const float ref1 = tcu::Float16(in1).asFloat();
707 const float res0 = outputs[valNdx].x();
708 const float res1 = outputs[valNdx].y();
709
710 const deUint32 refBits0 = tcu::Float32(ref0).bits();
711 const deUint32 refBits1 = tcu::Float32(ref1).bits();
712 const deUint32 resBits0 = tcu::Float32(res0).bits();
713 const deUint32 resBits1 = tcu::Float32(res1).bits();
714
715 const int diff0 = de::abs((int)refBits0 - (int)resBits0);
716 const int diff1 = de::abs((int)refBits1 - (int)resBits1);
717
718 if (diff0 > maxDiff || diff1 > maxDiff)
719 {
720 if (numFailed < maxPrints)
721 {
722 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
723 << " expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
724 << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
725 << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")"
726 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
727 << TestLog::EndMessage;
728 }
729 else if (numFailed == maxPrints)
730 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
731
732 numFailed += 1;
733 }
734 }
735
736 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
737
738 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
739 numFailed == 0 ? "Pass" : "Result comparison failed");
740 }
741
742 return STOP;
743 }
744};
745
746class PackSnorm4x8Case : public ShaderPackingFunctionCase
747{
748public:
749 PackSnorm4x8Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
750 : ShaderPackingFunctionCase (context, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
751 , m_precision (precision)
752 {
753 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
754 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
755
756 m_spec.source = "out0 = packSnorm4x8(in0);";
757 }
758
759 IterateResult iterate (void)
760 {
761 de::Random rnd (deStringHash(getName()) ^ 0x42f2c0);
762 std::vector<tcu::Vec4> inputs;
763 std::vector<deUint32> outputs;
764 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
765 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^7) + 1
766 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^7) + 1
767
768 // Special values to check.
769 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
770 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
771 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
772 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
773 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
774
775 // Random values, mostly in range.
776 for (int ndx = 0; ndx < 15; ndx++)
777 {
778 const float x = rnd.getFloat()*2.5f - 1.25f;
779 const float y = rnd.getFloat()*2.5f - 1.25f;
780 const float z = rnd.getFloat()*2.5f - 1.25f;
781 const float w = rnd.getFloat()*2.5f - 1.25f;
782 inputs.push_back(tcu::Vec4(x, y, z, w));
783 }
784
785 // Large random values.
786 for (int ndx = 0; ndx < 80; ndx++)
787 {
788 const float x = rnd.getFloat()*1e6f - 0.5e6f;
789 const float y = rnd.getFloat()*1e6f - 0.5e6f;
790 const float z = rnd.getFloat()*1e6f - 0.5e6f;
791 const float w = rnd.getFloat()*1e6f - 0.5e6f;
792 inputs.push_back(tcu::Vec4(x, y, z, w));
793 }
794
795 outputs.resize(inputs.size());
796
797 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
798
799 {
800 const void* in = &inputs[0];
801 void* out = &outputs[0];
802
803 m_executor->useProgram();
804 m_executor->execute((int)inputs.size(), &in, &out);
805 }
806
807 // Verify
808 {
809 const int numValues = (int)inputs.size();
810 const int maxPrints = 10;
811 int numFailed = 0;
812
813 for (int valNdx = 0; valNdx < numValues; valNdx++)
814 {
815 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
816 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
817 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
818 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
819 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
820 const deUint32 res = outputs[valNdx];
821 const deUint16 res0 = (deUint8)(res & 0xff);
822 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
823 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
824 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
825 const int diff0 = de::abs((int)ref0 - (int)res0);
826 const int diff1 = de::abs((int)ref1 - (int)res1);
827 const int diff2 = de::abs((int)ref2 - (int)res2);
828 const int diff3 = de::abs((int)ref3 - (int)res3);
829
830 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
831 {
832 if (numFailed < maxPrints)
833 {
834 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
835 << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
836 << ", got " << tcu::toHex(res)
837 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
838 << TestLog::EndMessage;
839 }
840 else if (numFailed == maxPrints)
841 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
842
843 numFailed += 1;
844 }
845 }
846
847 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
848
849 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
850 numFailed == 0 ? "Pass" : "Result comparison failed");
851 }
852
853 return STOP;
854 }
855
856private:
857 glu::Precision m_precision;
858};
859
860class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
861{
862public:
863 UnpackSnorm4x8Case (Context& context, glu::ShaderType shaderType)
864 : ShaderPackingFunctionCase(context, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
865 {
866 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
867 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
868
869 m_spec.source = "out0 = unpackSnorm4x8(in0);";
870 }
871
872 IterateResult iterate (void)
873 {
874 const deUint32 maxDiff = 1; // Rounding error.
875 de::Random rnd (deStringHash(getName()) ^ 0x776002);
876 std::vector<deUint32> inputs;
877 std::vector<tcu::Vec4> outputs;
878
879 inputs.push_back(0x00000000u);
880 inputs.push_back(0x7fff8000u);
881 inputs.push_back(0x80007fffu);
882 inputs.push_back(0xffffffffu);
883 inputs.push_back(0x0001fffeu);
884
885 // Random values.
886 for (int ndx = 0; ndx < 95; ndx++)
887 inputs.push_back(rnd.getUint32());
888
889 outputs.resize(inputs.size());
890
891 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
892
893 {
894 const void* in = &inputs[0];
895 void* out = &outputs[0];
896
897 m_executor->useProgram();
898 m_executor->execute((int)inputs.size(), &in, &out);
899 }
900
901 // Verify
902 {
903 const int numValues = (int)inputs.size();
904 const int maxPrints = 10;
905 int numFailed = 0;
906
907 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
908 {
909 const deInt8 in0 = (deInt8)(deUint8)(inputs[valNdx] & 0xff);
910 const deInt8 in1 = (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
911 const deInt8 in2 = (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
912 const deInt8 in3 = (deInt8)(deUint8)(inputs[valNdx] >> 24);
913 const float ref0 = de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
914 const float ref1 = de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
915 const float ref2 = de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
916 const float ref3 = de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
917 const float res0 = outputs[valNdx].x();
918 const float res1 = outputs[valNdx].y();
919 const float res2 = outputs[valNdx].z();
920 const float res3 = outputs[valNdx].w();
921
922 const deUint32 diff0 = getUlpDiff(ref0, res0);
923 const deUint32 diff1 = getUlpDiff(ref1, res1);
924 const deUint32 diff2 = getUlpDiff(ref2, res2);
925 const deUint32 diff3 = getUlpDiff(ref3, res3);
926
927 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
928 {
929 if (numFailed < maxPrints)
930 {
931 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
932 << " expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
933 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
934 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
935 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
936 << TestLog::EndMessage;
937 }
938 else if (numFailed == maxPrints)
939 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
940
941 numFailed += 1;
942 }
943 }
944
945 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
946
947 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
948 numFailed == 0 ? "Pass" : "Result comparison failed");
949 }
950
951 return STOP;
952 }
953};
954
955class PackUnorm4x8Case : public ShaderPackingFunctionCase
956{
957public:
958 PackUnorm4x8Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
959 : ShaderPackingFunctionCase (context, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
960 , m_precision (precision)
961 {
962 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
963 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
964
965 m_spec.source = "out0 = packUnorm4x8(in0);";
966 }
967
968 IterateResult iterate (void)
969 {
970 de::Random rnd (deStringHash(getName()) ^ 0x776002);
971 std::vector<tcu::Vec4> inputs;
972 std::vector<deUint32> outputs;
973 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
974 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^8) + 1
975 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^8) + 1
976
977 // Special values to check.
978 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
979 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
980 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
981 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
982 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
983
984 // Random values, mostly in range.
985 for (int ndx = 0; ndx < 15; ndx++)
986 {
987 const float x = rnd.getFloat()*1.25f - 0.125f;
988 const float y = rnd.getFloat()*1.25f - 0.125f;
989 const float z = rnd.getFloat()*1.25f - 0.125f;
990 const float w = rnd.getFloat()*1.25f - 0.125f;
991 inputs.push_back(tcu::Vec4(x, y, z, w));
992 }
993
994 // Large random values.
995 for (int ndx = 0; ndx < 80; ndx++)
996 {
997 const float x = rnd.getFloat()*1e6f - 1e5f;
998 const float y = rnd.getFloat()*1e6f - 1e5f;
999 const float z = rnd.getFloat()*1e6f - 1e5f;
1000 const float w = rnd.getFloat()*1e6f - 1e5f;
1001 inputs.push_back(tcu::Vec4(x, y, z, w));
1002 }
1003
1004 outputs.resize(inputs.size());
1005
1006 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1007
1008 {
1009 const void* in = &inputs[0];
1010 void* out = &outputs[0];
1011
1012 m_executor->useProgram();
1013 m_executor->execute((int)inputs.size(), &in, &out);
1014 }
1015
1016 // Verify
1017 {
1018 const int numValues = (int)inputs.size();
1019 const int maxPrints = 10;
1020 int numFailed = 0;
1021
1022 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1023 {
1024 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1025 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1026 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1027 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1028 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
1029 const deUint32 res = outputs[valNdx];
1030 const deUint16 res0 = (deUint8)(res & 0xff);
1031 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
1032 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
1033 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
1034 const int diff0 = de::abs((int)ref0 - (int)res0);
1035 const int diff1 = de::abs((int)ref1 - (int)res1);
1036 const int diff2 = de::abs((int)ref2 - (int)res2);
1037 const int diff3 = de::abs((int)ref3 - (int)res3);
1038
1039 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1040 {
1041 if (numFailed < maxPrints)
1042 {
1043 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
1044 << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
1045 << ", got " << tcu::toHex(res)
1046 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1047 << TestLog::EndMessage;
1048 }
1049 else if (numFailed == maxPrints)
1050 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1051
1052 numFailed += 1;
1053 }
1054 }
1055
1056 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1057
1058 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
1059 numFailed == 0 ? "Pass" : "Result comparison failed");
1060 }
1061
1062 return STOP;
1063 }
1064
1065private:
1066 glu::Precision m_precision;
1067};
1068
1069class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
1070{
1071public:
1072 UnpackUnorm4x8Case (Context& context, glu::ShaderType shaderType)
1073 : ShaderPackingFunctionCase(context, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
1074 {
1075 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1076 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1077
1078 m_spec.source = "out0 = unpackUnorm4x8(in0);";
1079 }
1080
1081 IterateResult iterate (void)
1082 {
1083 const deUint32 maxDiff = 1; // Rounding error.
1084 de::Random rnd (deStringHash(getName()) ^ 0x776002);
1085 std::vector<deUint32> inputs;
1086 std::vector<tcu::Vec4> outputs;
1087
1088 inputs.push_back(0x00000000u);
1089 inputs.push_back(0x7fff8000u);
1090 inputs.push_back(0x80007fffu);
1091 inputs.push_back(0xffffffffu);
1092 inputs.push_back(0x0001fffeu);
1093
1094 // Random values.
1095 for (int ndx = 0; ndx < 95; ndx++)
1096 inputs.push_back(rnd.getUint32());
1097
1098 outputs.resize(inputs.size());
1099
1100 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1101
1102 {
1103 const void* in = &inputs[0];
1104 void* out = &outputs[0];
1105
1106 m_executor->useProgram();
1107 m_executor->execute((int)inputs.size(), &in, &out);
1108 }
1109
1110 // Verify
1111 {
1112 const int numValues = (int)inputs.size();
1113 const int maxPrints = 10;
1114 int numFailed = 0;
1115
1116 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1117 {
1118 const deUint8 in0 = (deUint8)(inputs[valNdx] & 0xff);
1119 const deUint8 in1 = (deUint8)((inputs[valNdx] >> 8) & 0xff);
1120 const deUint8 in2 = (deUint8)((inputs[valNdx] >> 16) & 0xff);
1121 const deUint8 in3 = (deUint8)(inputs[valNdx] >> 24);
1122 const float ref0 = de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
1123 const float ref1 = de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
1124 const float ref2 = de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
1125 const float ref3 = de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
1126 const float res0 = outputs[valNdx].x();
1127 const float res1 = outputs[valNdx].y();
1128 const float res2 = outputs[valNdx].z();
1129 const float res3 = outputs[valNdx].w();
1130
1131 const deUint32 diff0 = getUlpDiff(ref0, res0);
1132 const deUint32 diff1 = getUlpDiff(ref1, res1);
1133 const deUint32 diff2 = getUlpDiff(ref2, res2);
1134 const deUint32 diff3 = getUlpDiff(ref3, res3);
1135
1136 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1137 {
1138 if (numFailed < maxPrints)
1139 {
1140 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1141 << " expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1142 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1143 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1144 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1145 << TestLog::EndMessage;
1146 }
1147 else if (numFailed == maxPrints)
1148 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1149
1150 numFailed += 1;
1151 }
1152 }
1153
1154 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1155
1156 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
1157 numFailed == 0 ? "Pass" : "Result comparison failed");
1158 }
1159
1160 return STOP;
1161 }
1162};
1163
1164ShaderPackingFunctionTests::ShaderPackingFunctionTests (Context& context)
1165 : TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests")
1166{
1167}
1168
1169ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
1170{
1171}
1172
1173void ShaderPackingFunctionTests::init (void)
1174{
1175 // New built-in functions in GLES 3.1
1176 {
1177 const glu::ShaderType allShaderTypes[] =
1178 {
1179 glu::SHADERTYPE_VERTEX,
1180 glu::SHADERTYPE_TESSELLATION_CONTROL,
1181 glu::SHADERTYPE_TESSELLATION_EVALUATION,
1182 glu::SHADERTYPE_GEOMETRY,
1183 glu::SHADERTYPE_FRAGMENT,
1184 glu::SHADERTYPE_COMPUTE
1185 };
1186
1187 // packSnorm4x8
1188 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1189 {
1190 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1191 addChild(new PackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1192 }
1193
1194 // unpackSnorm4x8
1195 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1196 addChild(new UnpackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx]));
1197
1198 // packUnorm4x8
1199 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1200 {
1201 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1202 addChild(new PackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1203 }
1204
1205 // unpackUnorm4x8
1206 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1207 addChild(new UnpackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx]));
1208 }
1209
1210 // GLES 3 functions in new shader types.
1211 {
1212 const glu::ShaderType newShaderTypes[] =
1213 {
1214 glu::SHADERTYPE_GEOMETRY,
1215 glu::SHADERTYPE_COMPUTE
1216 };
1217
1218 // packSnorm2x16
1219 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1220 {
1221 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1222 addChild(new PackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1223 }
1224
1225 // unpackSnorm2x16
1226 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1227 addChild(new UnpackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1228
1229 // packUnorm2x16
1230 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1231 {
1232 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1233 addChild(new PackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1234 }
1235
1236 // unpackUnorm2x16
1237 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1238 addChild(new UnpackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1239
1240 // packHalf2x16
1241 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1242 addChild(new PackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1243
1244 // unpackHalf2x16
1245 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1246 addChild(new UnpackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1247 }
1248}
1249
1250} // Functional
1251} // gles31
1252} // deqp