1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 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 Shader precision tests.
22 *
23 * \note Floating-point case uses R32UI render target and uses
24 * floatBitsToUint() in shader to write out floating-point value bits.
25 * This is done since ES3 core doesn't support FP render targets.
26 *//*--------------------------------------------------------------------*/
27
28 #include "es3fShaderPrecisionTests.hpp"
29 #include "tcuVector.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuVectorUtil.hpp"
32 #include "tcuFloat.hpp"
33 #include "tcuFormatUtil.hpp"
34 #include "gluRenderContext.hpp"
35 #include "gluShaderProgram.hpp"
36 #include "gluShaderUtil.hpp"
37 #include "gluDrawUtil.hpp"
38 #include "deRandom.hpp"
39 #include "deString.h"
40
41 #include "glwEnums.hpp"
42 #include "glwFunctions.hpp"
43
44 #include <algorithm>
45
46 namespace deqp
47 {
48 namespace gles3
49 {
50 namespace Functional
51 {
52
53 using std::string;
54 using std::vector;
55 using std::ostringstream;
56 using tcu::TestLog;
57
58 enum
59 {
60 FRAMEBUFFER_WIDTH = 32,
61 FRAMEBUFFER_HEIGHT = 32
62 };
63
createFloatPrecisionEvalProgram(const glu::RenderContext & context,glu::Precision precision,const char * evalOp,bool isVertexCase)64 static glu::ShaderProgram* createFloatPrecisionEvalProgram (const glu::RenderContext& context, glu::Precision precision, const char* evalOp, bool isVertexCase)
65 {
66 glu::DataType type = glu::TYPE_FLOAT;
67 glu::DataType outType = glu::TYPE_UINT;
68 const char* typeName = glu::getDataTypeName(type);
69 const char* outTypeName = glu::getDataTypeName(outType);
70 const char* precName = glu::getPrecisionName(precision);
71 ostringstream vtx;
72 ostringstream frag;
73 ostringstream& op = isVertexCase ? vtx : frag;
74
75 vtx << "#version 300 es\n"
76 << "in highp vec4 a_position;\n"
77 << "in " << precName << " " << typeName << " a_in0;\n"
78 << "in " << precName << " " << typeName << " a_in1;\n";
79 frag << "#version 300 es\n"
80 << "layout(location = 0) out highp " << outTypeName << " o_out;\n";
81
82 if (isVertexCase)
83 {
84 vtx << "flat out " << precName << " " << typeName << " v_out;\n";
85 frag << "flat in " << precName << " " << typeName << " v_out;\n";
86 }
87 else
88 {
89 vtx << "flat out " << precName << " " << typeName << " v_in0;\n"
90 << "flat out " << precName << " " << typeName << " v_in1;\n";
91 frag << "flat in " << precName << " " << typeName << " v_in0;\n"
92 << "flat in " << precName << " " << typeName << " v_in1;\n";
93 }
94
95 vtx << "\nvoid main (void)\n{\n"
96 << " gl_Position = a_position;\n";
97 frag << "\nvoid main (void)\n{\n";
98
99 op << "\t" << precName << " " << typeName << " in0 = " << (isVertexCase ? "a_" : "v_") << "in0;\n"
100 << "\t" << precName << " " << typeName << " in1 = " << (isVertexCase ? "a_" : "v_") << "in1;\n";
101
102 if (!isVertexCase)
103 op << "\t" << precName << " " << typeName << " res;\n";
104
105 op << "\t" << (isVertexCase ? "v_out" : "res") << " = " << evalOp << ";\n";
106
107 if (isVertexCase)
108 {
109 frag << " o_out = floatBitsToUint(v_out);\n";
110 }
111 else
112 {
113 vtx << " v_in0 = a_in0;\n"
114 << " v_in1 = a_in1;\n";
115 frag << " o_out = floatBitsToUint(res);\n";
116 }
117
118 vtx << "}\n";
119 frag << "}\n";
120
121 return new glu::ShaderProgram(context, glu::makeVtxFragSources(vtx.str(), frag.str()));
122 }
123
createIntUintPrecisionEvalProgram(const glu::RenderContext & context,glu::DataType type,glu::Precision precision,const char * evalOp,bool isVertexCase)124 static glu::ShaderProgram* createIntUintPrecisionEvalProgram (const glu::RenderContext& context, glu::DataType type, glu::Precision precision, const char* evalOp, bool isVertexCase)
125 {
126 const char* typeName = glu::getDataTypeName(type);
127 const char* precName = glu::getPrecisionName(precision);
128 ostringstream vtx;
129 ostringstream frag;
130 ostringstream& op = isVertexCase ? vtx : frag;
131
132 vtx << "#version 300 es\n"
133 << "in highp vec4 a_position;\n"
134 << "in " << precName << " " << typeName << " a_in0;\n"
135 << "in " << precName << " " << typeName << " a_in1;\n";
136 frag << "#version 300 es\n"
137 << "layout(location = 0) out " << precName << " " << typeName << " o_out;\n";
138
139 if (isVertexCase)
140 {
141 vtx << "flat out " << precName << " " << typeName << " v_out;\n";
142 frag << "flat in " << precName << " " << typeName << " v_out;\n";
143 }
144 else
145 {
146 vtx << "flat out " << precName << " " << typeName << " v_in0;\n"
147 << "flat out " << precName << " " << typeName << " v_in1;\n";
148 frag << "flat in " << precName << " " << typeName << " v_in0;\n"
149 << "flat in " << precName << " " << typeName << " v_in1;\n";
150 }
151
152 vtx << "\nvoid main (void)\n{\n"
153 << " gl_Position = a_position;\n";
154 frag << "\nvoid main (void)\n{\n";
155
156 op << "\t" << precName << " " << typeName << " in0 = " << (isVertexCase ? "a_" : "v_") << "in0;\n"
157 << "\t" << precName << " " << typeName << " in1 = " << (isVertexCase ? "a_" : "v_") << "in1;\n";
158
159 op << "\t" << (isVertexCase ? "v_" : "o_") << "out = " << evalOp << ";\n";
160
161 if (isVertexCase)
162 {
163 frag << " o_out = v_out;\n";
164 }
165 else
166 {
167 vtx << " v_in0 = a_in0;\n"
168 << " v_in1 = a_in1;\n";
169 }
170
171 vtx << "}\n";
172 frag << "}\n";
173
174 return new glu::ShaderProgram(context, glu::makeVtxFragSources(vtx.str(), frag.str()));
175 }
176
177 class ShaderFloatPrecisionCase : public TestCase
178 {
179 public:
180 typedef double (*EvalFunc) (double in0, double in1);
181
182 ShaderFloatPrecisionCase (Context& context, const char* name, const char* desc, const char* op, EvalFunc evalFunc, glu::Precision precision, const tcu::Vec2& rangeA, const tcu::Vec2& rangeB, bool isVertexCase);
183 ~ShaderFloatPrecisionCase (void);
184
185 void init (void);
186 void deinit (void);
187 IterateResult iterate (void);
188
189 protected:
190 bool compare (float in0, float in1, double reference, float result)
191 #if (DE_COMPILER == DE_COMPILER_GCC) && (DE_CPU == DE_CPU_ARM_64)
192 # if (__GNUC__ == 4) && (__GNUC_MINOR__ == 9) && (__GNUC_PATCHLEVEL__ == 0)
193 // Some prerelease GCC 4.9 versions have a bug in shift right when
194 // targeting ARMv8.
195 //
196 // If compiler wants to perform logical shift by variable/register
197 // in fp/vector registers it uses USHL that selects shift direction
198 // based on shift operand value. Thus for right shifts the shift
199 // operand needs to be negated.
200 //
201 // The bug is in right shift pattern; it doesn't mark shift operand
202 // as clobbered and thus later code using that same register may
203 // see the negated value.
204 //
205 // Workaround is to disable optimization for this function.
206 //
207 // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61633
208 __attribute__((optimize(0)))
209 # endif
210 #endif
211 ;
212
213 private:
214 ShaderFloatPrecisionCase (const ShaderFloatPrecisionCase& other);
215 ShaderFloatPrecisionCase& operator= (const ShaderFloatPrecisionCase& other);
216
217 // Case parameters.
218 std::string m_op;
219 EvalFunc m_evalFunc;
220 glu::Precision m_precision;
221 tcu::Vec2 m_rangeA;
222 tcu::Vec2 m_rangeB;
223 bool m_isVertexCase;
224
225 int m_numTestsPerIter;
226 int m_numIters;
227 de::Random m_rnd;
228
229 // Iteration state.
230 glu::ShaderProgram* m_program;
231 deUint32 m_framebuffer;
232 deUint32 m_renderbuffer;
233 int m_iterNdx;
234 };
235
ShaderFloatPrecisionCase(Context & context,const char * name,const char * desc,const char * op,EvalFunc evalFunc,glu::Precision precision,const tcu::Vec2 & rangeA,const tcu::Vec2 & rangeB,bool isVertexCase)236 ShaderFloatPrecisionCase::ShaderFloatPrecisionCase (Context& context, const char* name, const char* desc, const char* op, EvalFunc evalFunc, glu::Precision precision, const tcu::Vec2& rangeA, const tcu::Vec2& rangeB, bool isVertexCase)
237 : TestCase (context, name, desc)
238 , m_op (op)
239 , m_evalFunc (evalFunc)
240 , m_precision (precision)
241 , m_rangeA (rangeA)
242 , m_rangeB (rangeB)
243 , m_isVertexCase (isVertexCase)
244 , m_numTestsPerIter (32)
245 , m_numIters (4)
246 , m_rnd (deStringHash(name))
247 , m_program (DE_NULL)
248 , m_framebuffer (0)
249 , m_renderbuffer (0)
250 , m_iterNdx (0)
251 {
252 }
253
~ShaderFloatPrecisionCase(void)254 ShaderFloatPrecisionCase::~ShaderFloatPrecisionCase (void)
255 {
256 ShaderFloatPrecisionCase::deinit();
257 }
258
init(void)259 void ShaderFloatPrecisionCase::init (void)
260 {
261 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
262 TestLog& log = m_testCtx.getLog();
263
264 DE_ASSERT(!m_program && !m_framebuffer && !m_renderbuffer);
265
266 // Create program.
267 m_program = createFloatPrecisionEvalProgram(m_context.getRenderContext(), m_precision, m_op.c_str(), m_isVertexCase);
268 log << *m_program;
269
270 TCU_CHECK(m_program->isOk());
271
272 // Create framebuffer.
273 gl.genFramebuffers(1, &m_framebuffer);
274 gl.genRenderbuffers(1, &m_renderbuffer);
275
276 gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
277 gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
278
279 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
280 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer);
281
282 GLU_EXPECT_NO_ERROR(gl.getError(), "Post framebuffer setup");
283 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
284
285 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
286
287 // Initialize test result to pass.
288 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
289 m_iterNdx = 0;
290 }
291
deinit(void)292 void ShaderFloatPrecisionCase::deinit (void)
293 {
294 delete m_program;
295
296 if (m_framebuffer)
297 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_framebuffer);
298
299 if (m_renderbuffer)
300 m_context.getRenderContext().getFunctions().deleteRenderbuffers(1, &m_renderbuffer);
301
302 m_program = DE_NULL;
303 m_framebuffer = 0;
304 m_renderbuffer = 0;
305 }
306
compare(float in0,float in1,double reference,float result)307 bool ShaderFloatPrecisionCase::compare (float in0, float in1, double reference, float result)
308 {
309 // Comparison is done using 64-bit reference value to accurately evaluate rounding mode error.
310 // If 32-bit reference value is used, 2 bits of rounding error must be allowed.
311
312 // For mediump and lowp types the comparison currently allows 3 bits of rounding error:
313 // two bits from conversions and one from actual operation.
314
315 // \todo [2013-09-30 pyry] Make this more strict: determine if rounding can actually happen.
316
317 const int mantissaBits = m_precision == glu::PRECISION_HIGHP ? 23 : 10;
318 const int numPrecBits = 52 - mantissaBits;
319
320 const int in0Exp = tcu::Float32(in0).exponent();
321 const int in1Exp = tcu::Float32(in1).exponent();
322 const int resExp = tcu::Float32(result).exponent();
323 const int numLostBits = de::max(de::max(in0Exp-resExp, in1Exp-resExp), 0); // Lost due to mantissa shift.
324
325 const int roundingUlpError = m_precision == glu::PRECISION_HIGHP ? 1 : 3;
326 const int maskBits = numLostBits + numPrecBits;
327
328 m_testCtx.getLog() << TestLog::Message << "Assuming " << mantissaBits << " mantissa bits, " << numLostBits << " bits lost in operation, and " << roundingUlpError << " ULP rounding error."
329 << TestLog::EndMessage;
330
331 {
332 const deUint64 refBits = tcu::Float64(reference).bits();
333 const deUint64 resBits = tcu::Float64(result).bits();
334 const deUint64 accurateRefBits = refBits >> maskBits;
335 const deUint64 accurateResBits = resBits >> maskBits;
336 const deUint64 ulpDiff = (deUint64)de::abs((deInt64)accurateRefBits - (deInt64)accurateResBits);
337
338 if (ulpDiff > (deUint64)roundingUlpError)
339 {
340 m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed! ULP diff (ignoring lost/undefined bits) = " << ulpDiff << TestLog::EndMessage;
341 return false;
342 }
343 else
344 return true;
345 }
346 }
347
iterate(void)348 ShaderFloatPrecisionCase::IterateResult ShaderFloatPrecisionCase::iterate (void)
349 {
350 // Constant data.
351 const float position[] =
352 {
353 -1.0f, -1.0f, 0.0f, 1.0f,
354 -1.0f, 1.0f, 0.0f, 1.0f,
355 1.0f, -1.0f, 0.0f, 1.0f,
356 1.0f, 1.0f, 0.0f, 1.0f
357 };
358 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
359
360 const int numVertices = 4;
361 float in0Arr[4] = { 0.0f };
362 float in1Arr[4] = { 0.0f };
363
364 TestLog& log = m_testCtx.getLog();
365 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
366 vector<glu::VertexArrayBinding> vertexArrays;
367
368 // Image read from GL.
369 std::vector<float> pixels (FRAMEBUFFER_WIDTH*FRAMEBUFFER_HEIGHT*4);
370
371 // \todo [2012-05-03 pyry] Could be cached.
372 deUint32 prog = m_program->getProgram();
373
374 gl.useProgram(prog);
375 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
376
377 vertexArrays.push_back(glu::va::Float("a_position", 4, numVertices, 0, &position[0]));
378 vertexArrays.push_back(glu::va::Float("a_in0", 1, numVertices, 0, &in0Arr[0]));
379 vertexArrays.push_back(glu::va::Float("a_in1", 1, numVertices, 0, &in1Arr[0]));
380
381 GLU_EXPECT_NO_ERROR(gl.getError(), "After program setup");
382
383 // Compute values and reference.
384 for (int testNdx = 0; testNdx < m_numTestsPerIter; testNdx++)
385 {
386 const float in0 = m_rnd.getFloat(m_rangeA.x(), m_rangeA.y());
387 const float in1 = m_rnd.getFloat(m_rangeB.x(), m_rangeB.y());
388 const double refD = m_evalFunc((double)in0, (double)in1);
389 const float refF = tcu::Float64(refD).asFloat(); // Uses RTE rounding mode.
390
391 log << TestLog::Message << "iter " << m_iterNdx << ", test " << testNdx << ": "
392 << "in0 = " << in0 << " / " << tcu::toHex(tcu::Float32(in0).bits())
393 << ", in1 = " << in1 << " / " << tcu::toHex(tcu::Float32(in1).bits())
394 << TestLog::EndMessage
395 << TestLog::Message << " reference = " << refF << " / " << tcu::toHex(tcu::Float32(refF).bits()) << TestLog::EndMessage;
396
397 std::fill(&in0Arr[0], &in0Arr[0] + DE_LENGTH_OF_ARRAY(in0Arr), in0);
398 std::fill(&in1Arr[0], &in1Arr[0] + DE_LENGTH_OF_ARRAY(in1Arr), in1);
399
400 glu::draw(m_context.getRenderContext(), prog, (int)vertexArrays.size(), &vertexArrays[0],
401 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
402 gl.readPixels(0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
403 GLU_EXPECT_NO_ERROR(gl.getError(), "After render");
404
405 log << TestLog::Message << " result = " << pixels[0] << " / " << tcu::toHex(tcu::Float32(pixels[0]).bits()) << TestLog::EndMessage;
406
407 // Verify results
408 {
409 const bool firstPixelOk = compare(in0, in1, refD, pixels[0]);
410
411 if (firstPixelOk)
412 {
413 // Check that rest of pixels match to first one.
414 const deUint32 firstPixelBits = tcu::Float32(pixels[0]).bits();
415 bool allPixelsOk = true;
416
417 for (int y = 0; y < FRAMEBUFFER_HEIGHT; y++)
418 {
419 for (int x = 0; x < FRAMEBUFFER_WIDTH; x++)
420 {
421 const deUint32 pixelBits = tcu::Float32(pixels[(y*FRAMEBUFFER_WIDTH + x)*4]).bits();
422
423 if (pixelBits != firstPixelBits)
424 {
425 log << TestLog::Message << "ERROR: Inconsistent results, got " << tcu::toHex(pixelBits) << " at (" << x << ", " << y << ")" << TestLog::EndMessage;
426 allPixelsOk = false;
427 }
428 }
429
430 if (!allPixelsOk)
431 break;
432 }
433
434 if (!allPixelsOk)
435 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsistent values in framebuffer");
436 }
437 else
438 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed");
439 }
440
441 if (m_testCtx.getTestResult() != QP_TEST_RESULT_PASS)
442 break;
443 }
444
445 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
446 GLU_EXPECT_NO_ERROR(gl.getError(), "After iteration");
447
448 m_iterNdx += 1;
449 return (m_iterNdx < m_numIters && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) ? CONTINUE : STOP;
450 }
451
452 class ShaderIntPrecisionCase : public TestCase
453 {
454 public:
455 typedef int (*EvalFunc) (int a, int b);
456
457 ShaderIntPrecisionCase (Context& context, const char* name, const char* desc, const char* op, EvalFunc evalFunc, glu::Precision precision, int bits, const tcu::IVec2& rangeA, const tcu::IVec2& rangeB, bool isVertexCase);
458 ~ShaderIntPrecisionCase (void);
459
460 void init (void);
461 void deinit (void);
462 IterateResult iterate (void);
463
464 private:
465 ShaderIntPrecisionCase (const ShaderIntPrecisionCase& other);
466 ShaderIntPrecisionCase& operator= (const ShaderIntPrecisionCase& other);
467
468 // Case parameters.
469 std::string m_op;
470 EvalFunc m_evalFunc;
471 glu::Precision m_precision;
472 int m_bits;
473 tcu::IVec2 m_rangeA;
474 tcu::IVec2 m_rangeB;
475 bool m_isVertexCase;
476
477 int m_numTestsPerIter;
478 int m_numIters;
479 de::Random m_rnd;
480
481 // Iteration state.
482 glu::ShaderProgram* m_program;
483 deUint32 m_framebuffer;
484 deUint32 m_renderbuffer;
485 int m_iterNdx;
486 };
487
ShaderIntPrecisionCase(Context & context,const char * name,const char * desc,const char * op,EvalFunc evalFunc,glu::Precision precision,int bits,const tcu::IVec2 & rangeA,const tcu::IVec2 & rangeB,bool isVertexCase)488 ShaderIntPrecisionCase::ShaderIntPrecisionCase (Context& context, const char* name, const char* desc, const char* op, EvalFunc evalFunc, glu::Precision precision, int bits, const tcu::IVec2& rangeA, const tcu::IVec2& rangeB, bool isVertexCase)
489 : TestCase (context, name, desc)
490 , m_op (op)
491 , m_evalFunc (evalFunc)
492 , m_precision (precision)
493 , m_bits (bits)
494 , m_rangeA (rangeA)
495 , m_rangeB (rangeB)
496 , m_isVertexCase (isVertexCase)
497 , m_numTestsPerIter (32)
498 , m_numIters (4)
499 , m_rnd (deStringHash(name))
500 , m_program (DE_NULL)
501 , m_framebuffer (0)
502 , m_renderbuffer (0)
503 , m_iterNdx (0)
504 {
505 }
506
~ShaderIntPrecisionCase(void)507 ShaderIntPrecisionCase::~ShaderIntPrecisionCase (void)
508 {
509 ShaderIntPrecisionCase::deinit();
510 }
511
init(void)512 void ShaderIntPrecisionCase::init (void)
513 {
514 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
515 TestLog& log = m_testCtx.getLog();
516
517 DE_ASSERT(!m_program && !m_framebuffer && !m_renderbuffer);
518
519 // Create program.
520 m_program = createIntUintPrecisionEvalProgram(m_context.getRenderContext(), glu::TYPE_INT, m_precision, m_op.c_str(), m_isVertexCase);
521 log << *m_program;
522
523 TCU_CHECK(m_program->isOk());
524
525 // Create framebuffer.
526 gl.genFramebuffers(1, &m_framebuffer);
527 gl.genRenderbuffers(1, &m_renderbuffer);
528
529 gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
530 gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32I, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
531
532 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
533 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer);
534
535 GLU_EXPECT_NO_ERROR(gl.getError(), "Post framebuffer setup");
536 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
537
538 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
539
540 // Initialize test result to pass.
541 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
542 m_iterNdx = 0;
543
544 log << TestLog::Message << "Number of accurate bits assumed = " << m_bits << TestLog::EndMessage;
545 }
546
deinit(void)547 void ShaderIntPrecisionCase::deinit (void)
548 {
549 delete m_program;
550
551 if (m_framebuffer)
552 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_framebuffer);
553
554 if (m_renderbuffer)
555 m_context.getRenderContext().getFunctions().deleteRenderbuffers(1, &m_renderbuffer);
556
557 m_program = DE_NULL;
558 m_framebuffer = 0;
559 m_renderbuffer = 0;
560 }
561
extendTo32Bit(int value,int bits)562 inline int extendTo32Bit (int value, int bits)
563 {
564 return (value & ((1<<(bits-1))-1)) | (((value & (1<<(bits-1))) << (32-bits)) >> (32-bits));
565 }
566
iterate(void)567 ShaderIntPrecisionCase::IterateResult ShaderIntPrecisionCase::iterate (void)
568 {
569 // Constant data.
570 const float position[] =
571 {
572 -1.0f, -1.0f, 0.0f, 1.0f,
573 -1.0f, 1.0f, 0.0f, 1.0f,
574 1.0f, -1.0f, 0.0f, 1.0f,
575 1.0f, 1.0f, 0.0f, 1.0f
576 };
577 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
578
579 const int numVertices = 4;
580 int in0Arr[4] = { 0 };
581 int in1Arr[4] = { 0 };
582
583 TestLog& log = m_testCtx.getLog();
584 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
585 deUint32 mask = m_bits == 32 ? 0xffffffffu : ((1u<<m_bits)-1);
586 vector<int> pixels (FRAMEBUFFER_WIDTH*FRAMEBUFFER_HEIGHT*4);
587 vector<glu::VertexArrayBinding> vertexArrays;
588
589 deUint32 prog = m_program->getProgram();
590
591 // \todo [2012-05-03 pyry] A bit hacky. getInt() should work fine with ranges like this.
592 bool isMaxRangeA = m_rangeA.x() == (int)0x80000000 && m_rangeA.y() == (int)0x7fffffff;
593 bool isMaxRangeB = m_rangeB.x() == (int)0x80000000 && m_rangeB.y() == (int)0x7fffffff;
594
595 gl.useProgram(prog);
596 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
597
598 vertexArrays.push_back(glu::va::Float("a_position", 4, numVertices, 0, &position[0]));
599 vertexArrays.push_back(glu::va::Int32("a_in0", 1, numVertices, 0, &in0Arr[0]));
600 vertexArrays.push_back(glu::va::Int32("a_in1", 1, numVertices, 0, &in1Arr[0]));
601
602 GLU_EXPECT_NO_ERROR(gl.getError(), "After program setup");
603
604 // Compute values and reference.
605 for (int testNdx = 0; testNdx < m_numTestsPerIter; testNdx++)
606 {
607 int in0 = extendTo32Bit(((isMaxRangeA ? (int)m_rnd.getUint32() : m_rnd.getInt(m_rangeA.x(), m_rangeA.y())) & mask), m_bits);
608 int in1 = extendTo32Bit(((isMaxRangeB ? (int)m_rnd.getUint32() : m_rnd.getInt(m_rangeB.x(), m_rangeB.y())) & mask), m_bits);
609 int refMasked = m_evalFunc(in0, in1) & mask;
610 int refOut = extendTo32Bit(refMasked, m_bits);
611
612 log << TestLog::Message << "iter " << m_iterNdx << ", test " << testNdx << ": "
613 << "in0 = " << in0 << ", in1 = " << in1 << ", ref out = " << refOut << " / " << tcu::toHex(refMasked)
614 << TestLog::EndMessage;
615
616 std::fill(&in0Arr[0], &in0Arr[0] + DE_LENGTH_OF_ARRAY(in0Arr), in0);
617 std::fill(&in1Arr[0], &in1Arr[0] + DE_LENGTH_OF_ARRAY(in1Arr), in1);
618
619 glu::draw(m_context.getRenderContext(), prog, (int)vertexArrays.size(), &vertexArrays[0],
620 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
621 gl.readPixels(0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, GL_RGBA_INTEGER, GL_INT, &pixels[0]);
622 GLU_EXPECT_NO_ERROR(gl.getError(), "After render");
623
624 // Compare pixels.
625 for (int y = 0; y < FRAMEBUFFER_HEIGHT; y++)
626 {
627 for (int x = 0; x < FRAMEBUFFER_WIDTH; x++)
628 {
629 int cmpOut = pixels[(y*FRAMEBUFFER_WIDTH + x)*4];
630 int cmpMasked = cmpOut & mask;
631
632 if (cmpMasked != refMasked)
633 {
634 log << TestLog::Message << "Comparison failed (at " << x << ", " << y << "): "
635 << "got " << cmpOut << " / " << tcu::toHex(cmpOut)
636 << TestLog::EndMessage;
637 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
638 return STOP;
639 }
640 }
641 }
642 }
643
644 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
645 GLU_EXPECT_NO_ERROR(gl.getError(), "After iteration");
646
647 m_iterNdx += 1;
648 return (m_iterNdx < m_numIters) ? CONTINUE : STOP;
649 }
650
651 class ShaderUintPrecisionCase : public TestCase
652 {
653 public:
654 typedef deUint32 (*EvalFunc) (deUint32 a, deUint32 b);
655
656 ShaderUintPrecisionCase (Context& context, const char* name, const char* desc, const char* op, EvalFunc evalFunc, glu::Precision precision, int bits, const tcu::UVec2& rangeA, const tcu::UVec2& rangeB, bool isVertexCase);
657 ~ShaderUintPrecisionCase (void);
658
659 void init (void);
660 void deinit (void);
661 IterateResult iterate (void);
662
663 private:
664 ShaderUintPrecisionCase (const ShaderUintPrecisionCase& other);
665 ShaderUintPrecisionCase& operator= (const ShaderUintPrecisionCase& other);
666
667 // Case parameters.
668 std::string m_op;
669 EvalFunc m_evalFunc;
670 glu::Precision m_precision;
671 int m_bits;
672 tcu::UVec2 m_rangeA;
673 tcu::UVec2 m_rangeB;
674 bool m_isVertexCase;
675
676 int m_numTestsPerIter;
677 int m_numIters;
678 de::Random m_rnd;
679
680 // Iteration state.
681 glu::ShaderProgram* m_program;
682 deUint32 m_framebuffer;
683 deUint32 m_renderbuffer;
684 int m_iterNdx;
685 };
686
ShaderUintPrecisionCase(Context & context,const char * name,const char * desc,const char * op,EvalFunc evalFunc,glu::Precision precision,int bits,const tcu::UVec2 & rangeA,const tcu::UVec2 & rangeB,bool isVertexCase)687 ShaderUintPrecisionCase::ShaderUintPrecisionCase (Context& context, const char* name, const char* desc, const char* op, EvalFunc evalFunc, glu::Precision precision, int bits, const tcu::UVec2& rangeA, const tcu::UVec2& rangeB, bool isVertexCase)
688 : TestCase (context, name, desc)
689 , m_op (op)
690 , m_evalFunc (evalFunc)
691 , m_precision (precision)
692 , m_bits (bits)
693 , m_rangeA (rangeA)
694 , m_rangeB (rangeB)
695 , m_isVertexCase (isVertexCase)
696 , m_numTestsPerIter (32)
697 , m_numIters (4)
698 , m_rnd (deStringHash(name))
699 , m_program (DE_NULL)
700 , m_framebuffer (0)
701 , m_renderbuffer (0)
702 , m_iterNdx (0)
703 {
704 }
705
~ShaderUintPrecisionCase(void)706 ShaderUintPrecisionCase::~ShaderUintPrecisionCase (void)
707 {
708 ShaderUintPrecisionCase::deinit();
709 }
710
init(void)711 void ShaderUintPrecisionCase::init (void)
712 {
713 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
714 TestLog& log = m_testCtx.getLog();
715
716 DE_ASSERT(!m_program && !m_framebuffer && !m_renderbuffer);
717
718 // Create program.
719 m_program = createIntUintPrecisionEvalProgram(m_context.getRenderContext(), glu::TYPE_UINT, m_precision, m_op.c_str(), m_isVertexCase);
720 log << *m_program;
721
722 TCU_CHECK(m_program->isOk());
723
724 // Create framebuffer.
725 gl.genFramebuffers(1, &m_framebuffer);
726 gl.genRenderbuffers(1, &m_renderbuffer);
727
728 gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
729 gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
730
731 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
732 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer);
733
734 GLU_EXPECT_NO_ERROR(gl.getError(), "Post framebuffer setup");
735 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
736
737 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
738
739 // Initialize test result to pass.
740 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
741 m_iterNdx = 0;
742
743 log << TestLog::Message << "Number of accurate bits assumed = " << m_bits << TestLog::EndMessage;
744 }
745
deinit(void)746 void ShaderUintPrecisionCase::deinit (void)
747 {
748 delete m_program;
749
750 if (m_framebuffer)
751 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_framebuffer);
752
753 if (m_renderbuffer)
754 m_context.getRenderContext().getFunctions().deleteRenderbuffers(1, &m_renderbuffer);
755
756 m_program = DE_NULL;
757 m_framebuffer = 0;
758 m_renderbuffer = 0;
759 }
760
iterate(void)761 ShaderUintPrecisionCase::IterateResult ShaderUintPrecisionCase::iterate (void)
762 {
763 // Constant data.
764 const float position[] =
765 {
766 -1.0f, -1.0f, 0.0f, 1.0f,
767 -1.0f, 1.0f, 0.0f, 1.0f,
768 1.0f, -1.0f, 0.0f, 1.0f,
769 1.0f, 1.0f, 0.0f, 1.0f
770 };
771 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
772
773 const int numVertices = 4;
774 deUint32 in0Arr[4] = { 0 };
775 deUint32 in1Arr[4] = { 0 };
776
777 TestLog& log = m_testCtx.getLog();
778 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
779 deUint32 mask = m_bits == 32 ? 0xffffffffu : ((1u<<m_bits)-1);
780 vector<deUint32> pixels (FRAMEBUFFER_WIDTH*FRAMEBUFFER_HEIGHT*4);
781 vector<glu::VertexArrayBinding> vertexArrays;
782
783 deUint32 prog = m_program->getProgram();
784
785 // \todo [2012-05-03 pyry] A bit hacky.
786 bool isMaxRangeA = m_rangeA.x() == 0 && m_rangeA.y() == 0xffffffff;
787 bool isMaxRangeB = m_rangeB.x() == 0 && m_rangeB.y() == 0xffffffff;
788
789 gl.useProgram(prog);
790 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
791
792 vertexArrays.push_back(glu::va::Float("a_position", 4, numVertices, 0, &position[0]));
793 vertexArrays.push_back(glu::va::Uint32("a_in0", 1, numVertices, 0, &in0Arr[0]));
794 vertexArrays.push_back(glu::va::Uint32("a_in1", 1, numVertices, 0, &in1Arr[0]));
795
796 GLU_EXPECT_NO_ERROR(gl.getError(), "After program setup");
797
798 // Compute values and reference.
799 for (int testNdx = 0; testNdx < m_numTestsPerIter; testNdx++)
800 {
801 deUint32 in0 = (isMaxRangeA ? m_rnd.getUint32() : (m_rangeA.x() + m_rnd.getUint32()%(m_rangeA.y()-m_rangeA.x()+1))) & mask;
802 deUint32 in1 = (isMaxRangeB ? m_rnd.getUint32() : (m_rangeB.x() + m_rnd.getUint32()%(m_rangeB.y()-m_rangeB.x()+1))) & mask;
803 deUint32 refOut = m_evalFunc(in0, in1) & mask;
804
805 log << TestLog::Message << "iter " << m_iterNdx << ", test " << testNdx << ": "
806 << "in0 = " << tcu::toHex(in0) << ", in1 = " << tcu::toHex(in1) << ", ref out = " << tcu::toHex(refOut)
807 << TestLog::EndMessage;
808
809 std::fill(&in0Arr[0], &in0Arr[0] + DE_LENGTH_OF_ARRAY(in0Arr), in0);
810 std::fill(&in1Arr[0], &in1Arr[0] + DE_LENGTH_OF_ARRAY(in1Arr), in1);
811
812 glu::draw(m_context.getRenderContext(), prog, (int)vertexArrays.size(), &vertexArrays[0],
813 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
814 gl.readPixels(0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
815 GLU_EXPECT_NO_ERROR(gl.getError(), "After render");
816
817 // Compare pixels.
818 for (int y = 0; y < FRAMEBUFFER_HEIGHT; y++)
819 {
820 for (int x = 0; x < FRAMEBUFFER_WIDTH; x++)
821 {
822 deUint32 cmpOut = pixels[(y*FRAMEBUFFER_WIDTH + x)*4];
823 deUint32 cmpMasked = cmpOut & mask;
824
825 if (cmpMasked != refOut)
826 {
827 log << TestLog::Message << "Comparison failed (at " << x << ", " << y << "): "
828 << "got " << tcu::toHex(cmpOut)
829 << TestLog::EndMessage;
830 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
831 return STOP;
832 }
833 }
834 }
835 }
836
837 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
838 GLU_EXPECT_NO_ERROR(gl.getError(), "After iteration");
839
840 m_iterNdx += 1;
841 return (m_iterNdx < m_numIters) ? CONTINUE : STOP;
842 }
843
ShaderPrecisionTests(Context & context)844 ShaderPrecisionTests::ShaderPrecisionTests (Context& context)
845 : TestCaseGroup(context, "precision", "Shader precision requirements validation tests")
846 {
847 }
848
~ShaderPrecisionTests(void)849 ShaderPrecisionTests::~ShaderPrecisionTests (void)
850 {
851 }
852
init(void)853 void ShaderPrecisionTests::init (void)
854 {
855 using tcu::add;
856 using tcu::sub;
857 using tcu::mul;
858 using tcu::div;
859 using tcu::Vec2;
860 using tcu::IVec2;
861 using tcu::UVec2;
862
863 // Exp = Emax-2, Mantissa = 0
864 float minF32 = tcu::Float32((1u<<31) | (0xfdu<<23) | 0x0u).asFloat();
865 float maxF32 = tcu::Float32((0u<<31) | (0xfdu<<23) | 0x0u).asFloat();
866 float minF16 = tcu::Float16((deUint16)((1u<<15) | (0x1du<<10) | 0x0u)).asFloat();
867 float maxF16 = tcu::Float16((deUint16)((0u<<15) | (0x1du<<10) | 0x0u)).asFloat();
868 tcu::Vec2 fullRange32F (minF32, maxF32);
869 tcu::Vec2 fullRange16F (minF16, maxF16);
870 tcu::IVec2 fullRange32I (0x80000000, 0x7fffffff);
871 tcu::IVec2 fullRange16I (-(1<<15), (1<<15)-1);
872 tcu::IVec2 fullRange8I (-(1<<7), (1<<7)-1);
873 tcu::UVec2 fullRange32U (0u, 0xffffffffu);
874 tcu::UVec2 fullRange16U (0u, 0xffffu);
875 tcu::UVec2 fullRange8U (0u, 0xffu);
876
877 // \note Right now it is not programmatically verified that the results shouldn't end up being inf/nan but
878 // actual values used are ok.
879
880 static const struct
881 {
882 const char* name;
883 const char* op;
884 ShaderFloatPrecisionCase::EvalFunc evalFunc;
885 glu::Precision precision;
886 tcu::Vec2 rangeA;
887 tcu::Vec2 rangeB;
888 } floatCases[] =
889 {
890 // Name Op Eval Precision RangeA RangeB
891 { "highp_add", "in0 + in1", add<double>, glu::PRECISION_HIGHP, fullRange32F, fullRange32F },
892 { "highp_sub", "in0 - in1", sub<double>, glu::PRECISION_HIGHP, fullRange32F, fullRange32F },
893 { "highp_mul", "in0 * in1", mul<double>, glu::PRECISION_HIGHP, Vec2(-1e5f, 1e5f), Vec2(-1e5f, 1e5f) },
894 { "highp_div", "in0 / in1", div<double>, glu::PRECISION_HIGHP, Vec2(-1e5f, 1e5f), Vec2(-1e5f, 1e5f) },
895 { "mediump_add", "in0 + in1", add<double>, glu::PRECISION_MEDIUMP, fullRange16F, fullRange16F },
896 { "mediump_sub", "in0 - in1", sub<double>, glu::PRECISION_MEDIUMP, fullRange16F, fullRange16F },
897 { "mediump_mul", "in0 * in1", mul<double>, glu::PRECISION_MEDIUMP, Vec2(-1e2f, 1e2f), Vec2(-1e2f, 1e2f) },
898 { "mediump_div", "in0 / in1", div<double>, glu::PRECISION_MEDIUMP, Vec2(-1e2f, 1e2f), Vec2(-1e2f, 1e2f) }
899 };
900
901 static const struct
902 {
903 const char* name;
904 const char* op;
905 ShaderIntPrecisionCase::EvalFunc evalFunc;
906 glu::Precision precision;
907 int bits;
908 tcu::IVec2 rangeA;
909 tcu::IVec2 rangeB;
910 } intCases[] =
911 {
912 // Name Op Eval Precision Bits RangeA RangeB
913 { "highp_add", "in0 + in1", add<int>, glu::PRECISION_HIGHP, 32, fullRange32I, fullRange32I },
914 { "highp_sub", "in0 - in1", sub<int>, glu::PRECISION_HIGHP, 32, fullRange32I, fullRange32I },
915 { "highp_mul", "in0 * in1", mul<int>, glu::PRECISION_HIGHP, 32, fullRange32I, fullRange32I },
916 { "highp_div", "in0 / in1", div<int>, glu::PRECISION_HIGHP, 32, fullRange32I, IVec2(-10000, -1) },
917 { "mediump_add", "in0 + in1", add<int>, glu::PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I },
918 { "mediump_sub", "in0 - in1", sub<int>, glu::PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I },
919 { "mediump_mul", "in0 * in1", mul<int>, glu::PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I },
920 { "mediump_div", "in0 / in1", div<int>, glu::PRECISION_MEDIUMP, 16, fullRange16I, IVec2(1, 1000) },
921 { "lowp_add", "in0 + in1", add<int>, glu::PRECISION_LOWP, 8, fullRange8I, fullRange8I },
922 { "lowp_sub", "in0 - in1", sub<int>, glu::PRECISION_LOWP, 8, fullRange8I, fullRange8I },
923 { "lowp_mul", "in0 * in1", mul<int>, glu::PRECISION_LOWP, 8, fullRange8I, fullRange8I },
924 { "lowp_div", "in0 / in1", div<int>, glu::PRECISION_LOWP, 8, fullRange8I, IVec2(-50, -1) }
925 };
926
927 static const struct
928 {
929 const char* name;
930 const char* op;
931 ShaderUintPrecisionCase::EvalFunc evalFunc;
932 glu::Precision precision;
933 int bits;
934 tcu::UVec2 rangeA;
935 tcu::UVec2 rangeB;
936 } uintCases[] =
937 {
938 // Name Op Eval Precision Bits RangeA RangeB
939 { "highp_add", "in0 + in1", add<deUint32>, glu::PRECISION_HIGHP, 32, fullRange32U, fullRange32U },
940 { "highp_sub", "in0 - in1", sub<deUint32>, glu::PRECISION_HIGHP, 32, fullRange32U, fullRange32U },
941 { "highp_mul", "in0 * in1", mul<deUint32>, glu::PRECISION_HIGHP, 32, fullRange32U, fullRange32U },
942 { "highp_div", "in0 / in1", div<deUint32>, glu::PRECISION_HIGHP, 32, fullRange32U, UVec2(1u, 10000u) },
943 { "mediump_add", "in0 + in1", add<deUint32>, glu::PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U },
944 { "mediump_sub", "in0 - in1", sub<deUint32>, glu::PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U },
945 { "mediump_mul", "in0 * in1", mul<deUint32>, glu::PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U },
946 { "mediump_div", "in0 / in1", div<deUint32>, glu::PRECISION_MEDIUMP, 16, fullRange16U, UVec2(1, 1000u) },
947 { "lowp_add", "in0 + in1", add<deUint32>, glu::PRECISION_LOWP, 8, fullRange8U, fullRange8U },
948 { "lowp_sub", "in0 - in1", sub<deUint32>, glu::PRECISION_LOWP, 8, fullRange8U, fullRange8U },
949 { "lowp_mul", "in0 * in1", mul<deUint32>, glu::PRECISION_LOWP, 8, fullRange8U, fullRange8U },
950 { "lowp_div", "in0 / in1", div<deUint32>, glu::PRECISION_LOWP, 8, fullRange8U, UVec2(1, 50u) }
951 };
952
953 tcu::TestCaseGroup* floatGroup = new tcu::TestCaseGroup(m_testCtx, "float", "Floating-point precision tests");
954 addChild(floatGroup);
955 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(floatCases); ndx++)
956 {
957 floatGroup->addChild(new ShaderFloatPrecisionCase(m_context,
958 (string(floatCases[ndx].name) + "_vertex").c_str(), "",
959 floatCases[ndx].op,
960 floatCases[ndx].evalFunc,
961 floatCases[ndx].precision,
962 floatCases[ndx].rangeA,
963 floatCases[ndx].rangeB,
964 true));
965 floatGroup->addChild(new ShaderFloatPrecisionCase(m_context,
966 (string(floatCases[ndx].name) + "_fragment").c_str(), "",
967 floatCases[ndx].op,
968 floatCases[ndx].evalFunc,
969 floatCases[ndx].precision,
970 floatCases[ndx].rangeA,
971 floatCases[ndx].rangeB,
972 false));
973 }
974
975 tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "int", "Integer precision tests");
976 addChild(intGroup);
977 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intCases); ndx++)
978 {
979 intGroup->addChild(new ShaderIntPrecisionCase(m_context,
980 (string(intCases[ndx].name) + "_vertex").c_str(), "",
981 intCases[ndx].op,
982 intCases[ndx].evalFunc,
983 intCases[ndx].precision,
984 intCases[ndx].bits,
985 intCases[ndx].rangeA,
986 intCases[ndx].rangeB,
987 true));
988 intGroup->addChild(new ShaderIntPrecisionCase(m_context,
989 (string(intCases[ndx].name) + "_fragment").c_str(), "",
990 intCases[ndx].op,
991 intCases[ndx].evalFunc,
992 intCases[ndx].precision,
993 intCases[ndx].bits,
994 intCases[ndx].rangeA,
995 intCases[ndx].rangeB,
996 false));
997 }
998
999 tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uint", "Unsigned integer precision tests");
1000 addChild(uintGroup);
1001 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(uintCases); ndx++)
1002 {
1003 uintGroup->addChild(new ShaderUintPrecisionCase(m_context,
1004 (string(uintCases[ndx].name) + "_vertex").c_str(), "",
1005 uintCases[ndx].op,
1006 uintCases[ndx].evalFunc,
1007 uintCases[ndx].precision,
1008 uintCases[ndx].bits,
1009 uintCases[ndx].rangeA,
1010 uintCases[ndx].rangeB,
1011 true));
1012 uintGroup->addChild(new ShaderUintPrecisionCase(m_context,
1013 (string(uintCases[ndx].name) + "_fragment").c_str(), "",
1014 uintCases[ndx].op,
1015 uintCases[ndx].evalFunc,
1016 uintCases[ndx].precision,
1017 uintCases[ndx].bits,
1018 uintCases[ndx].rangeA,
1019 uintCases[ndx].rangeB,
1020 false));
1021 }
1022 }
1023
1024 } // Functional
1025 } // gles3
1026 } // deqp
1027