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