Add tests for VK_KHR_incremental_present
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fShaderPrecisionTests.cpp
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
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
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
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
254 ShaderFloatPrecisionCase::~ShaderFloatPrecisionCase (void)
255 {
256         ShaderFloatPrecisionCase::deinit();
257 }
258
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
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
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         = maskBits < 64 ? refBits >> (deUint64)maskBits : 0u;
335                 const deUint64  accurateResBits         = maskBits < 64 ? resBits >> (deUint64)maskBits : 0u;
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
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
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
507 ShaderIntPrecisionCase::~ShaderIntPrecisionCase (void)
508 {
509         ShaderIntPrecisionCase::deinit();
510 }
511
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
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
562 ShaderIntPrecisionCase::IterateResult ShaderIntPrecisionCase::iterate (void)
563 {
564         // Constant data.
565         const float position[] =
566         {
567                 -1.0f, -1.0f, 0.0f, 1.0f,
568                 -1.0f,  1.0f, 0.0f, 1.0f,
569                  1.0f, -1.0f, 0.0f, 1.0f,
570                  1.0f,  1.0f, 0.0f, 1.0f
571         };
572         const deUint16                                  indices[]       = { 0, 1, 2, 2, 1, 3 };
573
574         const int                                               numVertices     = 4;
575         int                                                             in0Arr[4]       = { 0 };
576         int                                                             in1Arr[4]       = { 0 };
577
578         TestLog&                                                log                     = m_testCtx.getLog();
579         const glw::Functions&                   gl                      = m_context.getRenderContext().getFunctions();
580         deUint32                                                mask            = m_bits == 32 ? 0xffffffffu : ((1u<<m_bits)-1);
581         vector<int>                                             pixels          (FRAMEBUFFER_WIDTH*FRAMEBUFFER_HEIGHT*4);
582         vector<glu::VertexArrayBinding> vertexArrays;
583
584         deUint32                                                prog            = m_program->getProgram();
585
586         // \todo [2012-05-03 pyry] A bit hacky. getInt() should work fine with ranges like this.
587         bool                                                    isMaxRangeA     = m_rangeA.x() == (int)0x80000000 && m_rangeA.y() == (int)0x7fffffff;
588         bool                                                    isMaxRangeB     = m_rangeB.x() == (int)0x80000000 && m_rangeB.y() == (int)0x7fffffff;
589
590         gl.useProgram(prog);
591         gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
592
593         vertexArrays.push_back(glu::va::Float("a_position", 4, numVertices, 0, &position[0]));
594         vertexArrays.push_back(glu::va::Int32("a_in0", 1, numVertices, 0, &in0Arr[0]));
595         vertexArrays.push_back(glu::va::Int32("a_in1", 1, numVertices, 0, &in1Arr[0]));
596
597         GLU_EXPECT_NO_ERROR(gl.getError(), "After program setup");
598
599         // Compute values and reference.
600         for (int testNdx = 0; testNdx < m_numTestsPerIter; testNdx++)
601         {
602                 int             in0                     = deSignExtendTo32(((isMaxRangeA ? (int)m_rnd.getUint32() : m_rnd.getInt(m_rangeA.x(), m_rangeA.y())) & mask), m_bits);
603                 int             in1                     = deSignExtendTo32(((isMaxRangeB ? (int)m_rnd.getUint32() : m_rnd.getInt(m_rangeB.x(), m_rangeB.y())) & mask), m_bits);
604                 int             refMasked       = m_evalFunc(in0, in1) & mask;
605                 int             refOut          = deSignExtendTo32(refMasked, m_bits);
606
607                 log << TestLog::Message << "iter " << m_iterNdx << ", test " << testNdx << ": "
608                                                                 << "in0 = " << in0 << ", in1 = " << in1 << ", ref out = " << refOut << " / " << tcu::toHex(refMasked)
609                         << TestLog::EndMessage;
610
611                 std::fill(&in0Arr[0], &in0Arr[0] + DE_LENGTH_OF_ARRAY(in0Arr), in0);
612                 std::fill(&in1Arr[0], &in1Arr[0] + DE_LENGTH_OF_ARRAY(in1Arr), in1);
613
614                 glu::draw(m_context.getRenderContext(), prog, (int)vertexArrays.size(), &vertexArrays[0],
615                                   glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
616                 gl.readPixels(0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, GL_RGBA_INTEGER, GL_INT, &pixels[0]);
617                 GLU_EXPECT_NO_ERROR(gl.getError(), "After render");
618
619                 // Compare pixels.
620                 for (int y = 0; y < FRAMEBUFFER_HEIGHT; y++)
621                 {
622                         for (int x = 0; x < FRAMEBUFFER_WIDTH; x++)
623                         {
624                                 int                     cmpOut          = pixels[(y*FRAMEBUFFER_WIDTH + x)*4];
625                                 int                     cmpMasked       = cmpOut & mask;
626
627                                 if (cmpMasked != refMasked)
628                                 {
629                                         log << TestLog::Message << "Comparison failed (at " << x << ", " << y << "): "
630                                                                                         << "got " << cmpOut << " / " << tcu::toHex(cmpOut)
631                                                 << TestLog::EndMessage;
632                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
633                                         return STOP;
634                                 }
635                         }
636                 }
637         }
638
639         gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
640         GLU_EXPECT_NO_ERROR(gl.getError(), "After iteration");
641
642         m_iterNdx += 1;
643         return (m_iterNdx < m_numIters) ? CONTINUE : STOP;
644 }
645
646 class ShaderUintPrecisionCase : public TestCase
647 {
648 public:
649         typedef deUint32                        (*EvalFunc)                                     (deUint32 a, deUint32 b);
650
651                                                                 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);
652                                                                 ~ShaderUintPrecisionCase        (void);
653
654         void                                            init                                            (void);
655         void                                            deinit                                          (void);
656         IterateResult                           iterate                                         (void);
657
658 private:
659                                                                 ShaderUintPrecisionCase         (const ShaderUintPrecisionCase& other);
660         ShaderUintPrecisionCase&        operator=                                       (const ShaderUintPrecisionCase& other);
661
662         // Case parameters.
663         std::string                                     m_op;
664         EvalFunc                                        m_evalFunc;
665         glu::Precision                          m_precision;
666         int                                                     m_bits;
667         tcu::UVec2                                      m_rangeA;
668         tcu::UVec2                                      m_rangeB;
669         bool                                            m_isVertexCase;
670
671         int                                                     m_numTestsPerIter;
672         int                                                     m_numIters;
673         de::Random                                      m_rnd;
674
675         // Iteration state.
676         glu::ShaderProgram*                     m_program;
677         deUint32                                        m_framebuffer;
678         deUint32                                        m_renderbuffer;
679         int                                                     m_iterNdx;
680 };
681
682 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)
683         : TestCase                      (context, name, desc)
684         , m_op                          (op)
685         , m_evalFunc            (evalFunc)
686         , m_precision           (precision)
687         , m_bits                        (bits)
688         , m_rangeA                      (rangeA)
689         , m_rangeB                      (rangeB)
690         , m_isVertexCase        (isVertexCase)
691         , m_numTestsPerIter     (32)
692         , m_numIters            (4)
693         , m_rnd                         (deStringHash(name))
694         , m_program                     (DE_NULL)
695         , m_framebuffer         (0)
696         , m_renderbuffer        (0)
697         , m_iterNdx                     (0)
698 {
699 }
700
701 ShaderUintPrecisionCase::~ShaderUintPrecisionCase (void)
702 {
703         ShaderUintPrecisionCase::deinit();
704 }
705
706 void ShaderUintPrecisionCase::init (void)
707 {
708         const glw::Functions&   gl      = m_context.getRenderContext().getFunctions();
709         TestLog&                                log     = m_testCtx.getLog();
710
711         DE_ASSERT(!m_program && !m_framebuffer && !m_renderbuffer);
712
713         // Create program.
714         m_program = createIntUintPrecisionEvalProgram(m_context.getRenderContext(), glu::TYPE_UINT, m_precision, m_op.c_str(), m_isVertexCase);
715         log << *m_program;
716
717         TCU_CHECK(m_program->isOk());
718
719         // Create framebuffer.
720         gl.genFramebuffers(1, &m_framebuffer);
721         gl.genRenderbuffers(1, &m_renderbuffer);
722
723         gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
724         gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
725
726         gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
727         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer);
728
729         GLU_EXPECT_NO_ERROR(gl.getError(), "Post framebuffer setup");
730         TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
731
732         gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
733
734         // Initialize test result to pass.
735         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
736         m_iterNdx = 0;
737
738         log << TestLog::Message << "Number of accurate bits assumed = " << m_bits << TestLog::EndMessage;
739 }
740
741 void ShaderUintPrecisionCase::deinit (void)
742 {
743         delete m_program;
744
745         if (m_framebuffer)
746                 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_framebuffer);
747
748         if (m_renderbuffer)
749                 m_context.getRenderContext().getFunctions().deleteRenderbuffers(1, &m_renderbuffer);
750
751         m_program               = DE_NULL;
752         m_framebuffer   = 0;
753         m_renderbuffer  = 0;
754 }
755
756 ShaderUintPrecisionCase::IterateResult ShaderUintPrecisionCase::iterate (void)
757 {
758         // Constant data.
759         const float position[] =
760         {
761                 -1.0f, -1.0f, 0.0f, 1.0f,
762                 -1.0f,  1.0f, 0.0f, 1.0f,
763                  1.0f, -1.0f, 0.0f, 1.0f,
764                  1.0f,  1.0f, 0.0f, 1.0f
765         };
766         const deUint16                                  indices[]       = { 0, 1, 2, 2, 1, 3 };
767
768         const int                                               numVertices     = 4;
769         deUint32                                                in0Arr[4]       = { 0 };
770         deUint32                                                in1Arr[4]       = { 0 };
771
772         TestLog&                                                log                     = m_testCtx.getLog();
773         const glw::Functions&                   gl                      = m_context.getRenderContext().getFunctions();
774         deUint32                                                mask            = m_bits == 32 ? 0xffffffffu : ((1u<<m_bits)-1);
775         vector<deUint32>                                pixels          (FRAMEBUFFER_WIDTH*FRAMEBUFFER_HEIGHT*4);
776         vector<glu::VertexArrayBinding> vertexArrays;
777
778         deUint32                                                prog            = m_program->getProgram();
779
780         // \todo [2012-05-03 pyry] A bit hacky.
781         bool                                                    isMaxRangeA     = m_rangeA.x() == 0 && m_rangeA.y() == 0xffffffff;
782         bool                                                    isMaxRangeB     = m_rangeB.x() == 0 && m_rangeB.y() == 0xffffffff;
783
784         gl.useProgram(prog);
785         gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
786
787         vertexArrays.push_back(glu::va::Float("a_position", 4, numVertices, 0, &position[0]));
788         vertexArrays.push_back(glu::va::Uint32("a_in0", 1, numVertices, 0, &in0Arr[0]));
789         vertexArrays.push_back(glu::va::Uint32("a_in1", 1, numVertices, 0, &in1Arr[0]));
790
791         GLU_EXPECT_NO_ERROR(gl.getError(), "After program setup");
792
793         // Compute values and reference.
794         for (int testNdx = 0; testNdx < m_numTestsPerIter; testNdx++)
795         {
796                 deUint32        in0             = (isMaxRangeA ? m_rnd.getUint32() : (m_rangeA.x() + m_rnd.getUint32()%(m_rangeA.y()-m_rangeA.x()+1))) & mask;
797                 deUint32        in1             = (isMaxRangeB ? m_rnd.getUint32() : (m_rangeB.x() + m_rnd.getUint32()%(m_rangeB.y()-m_rangeB.x()+1))) & mask;
798                 deUint32        refOut  = m_evalFunc(in0, in1) & mask;
799
800                 log << TestLog::Message << "iter " << m_iterNdx << ", test " << testNdx << ": "
801                                                                 << "in0 = " << tcu::toHex(in0) << ", in1 = " << tcu::toHex(in1) << ", ref out = " << tcu::toHex(refOut)
802                         << TestLog::EndMessage;
803
804                 std::fill(&in0Arr[0], &in0Arr[0] + DE_LENGTH_OF_ARRAY(in0Arr), in0);
805                 std::fill(&in1Arr[0], &in1Arr[0] + DE_LENGTH_OF_ARRAY(in1Arr), in1);
806
807                 glu::draw(m_context.getRenderContext(), prog, (int)vertexArrays.size(), &vertexArrays[0],
808                                   glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
809                 gl.readPixels(0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
810                 GLU_EXPECT_NO_ERROR(gl.getError(), "After render");
811
812                 // Compare pixels.
813                 for (int y = 0; y < FRAMEBUFFER_HEIGHT; y++)
814                 {
815                         for (int x = 0; x < FRAMEBUFFER_WIDTH; x++)
816                         {
817                                 deUint32        cmpOut          = pixels[(y*FRAMEBUFFER_WIDTH + x)*4];
818                                 deUint32        cmpMasked       = cmpOut & mask;
819
820                                 if (cmpMasked != refOut)
821                                 {
822                                         log << TestLog::Message << "Comparison failed (at " << x << ", " << y << "): "
823                                                                                         << "got " << tcu::toHex(cmpOut)
824                                                 << TestLog::EndMessage;
825                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
826                                         return STOP;
827                                 }
828                         }
829                 }
830         }
831
832         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
833         GLU_EXPECT_NO_ERROR(gl.getError(), "After iteration");
834
835         m_iterNdx += 1;
836         return (m_iterNdx < m_numIters) ? CONTINUE : STOP;
837 }
838
839 ShaderPrecisionTests::ShaderPrecisionTests (Context& context)
840         : TestCaseGroup(context, "precision", "Shader precision requirements validation tests")
841 {
842 }
843
844 ShaderPrecisionTests::~ShaderPrecisionTests (void)
845 {
846 }
847
848 void ShaderPrecisionTests::init (void)
849 {
850         using tcu::add;
851         using tcu::sub;
852         using tcu::mul;
853         using tcu::div;
854         using tcu::Vec2;
855         using tcu::IVec2;
856         using tcu::UVec2;
857
858         // Exp = Emax-2, Mantissa = 0
859         float           minF32                  = tcu::Float32((1u<<31) | (0xfdu<<23) | 0x0u).asFloat();
860         float           maxF32                  = tcu::Float32((0u<<31) | (0xfdu<<23) | 0x0u).asFloat();
861         float           minF16                  = tcu::Float16((deUint16)((1u<<15) | (0x1du<<10) | 0x0u)).asFloat();
862         float           maxF16                  = tcu::Float16((deUint16)((0u<<15) | (0x1du<<10) | 0x0u)).asFloat();
863         tcu::Vec2       fullRange32F    (minF32, maxF32);
864         tcu::Vec2       fullRange16F    (minF16, maxF16);
865         tcu::IVec2      fullRange32I    (0x80000000, 0x7fffffff);
866         tcu::IVec2      fullRange16I    (-(1<<15), (1<<15)-1);
867         tcu::IVec2      fullRange8I             (-(1<<7), (1<<7)-1);
868         tcu::UVec2      fullRange32U    (0u, 0xffffffffu);
869         tcu::UVec2      fullRange16U    (0u, 0xffffu);
870         tcu::UVec2      fullRange8U             (0u, 0xffu);
871
872         // \note Right now it is not programmatically verified that the results shouldn't end up being inf/nan but
873         //       actual values used are ok.
874
875         static const struct
876         {
877                 const char*                                                     name;
878                 const char*                                                     op;
879                 ShaderFloatPrecisionCase::EvalFunc      evalFunc;
880                 glu::Precision                                          precision;
881                 tcu::Vec2                                                       rangeA;
882                 tcu::Vec2                                                       rangeB;
883         } floatCases[] =
884         {
885                 // Name                         Op                              Eval                    Precision                               RangeA                          RangeB
886                 { "highp_add",          "in0 + in1",    add<double>,    glu::PRECISION_HIGHP,   fullRange32F,           fullRange32F            },
887                 { "highp_sub",          "in0 - in1",    sub<double>,    glu::PRECISION_HIGHP,   fullRange32F,           fullRange32F            },
888                 { "highp_mul",          "in0 * in1",    mul<double>,    glu::PRECISION_HIGHP,   Vec2(-1e5f, 1e5f),      Vec2(-1e5f, 1e5f)       },
889                 { "highp_div",          "in0 / in1",    div<double>,    glu::PRECISION_HIGHP,   Vec2(-1e5f, 1e5f),      Vec2(-1e5f, 1e5f)       },
890                 { "mediump_add",        "in0 + in1",    add<double>,    glu::PRECISION_MEDIUMP, fullRange16F,           fullRange16F            },
891                 { "mediump_sub",        "in0 - in1",    sub<double>,    glu::PRECISION_MEDIUMP, fullRange16F,           fullRange16F            },
892                 { "mediump_mul",        "in0 * in1",    mul<double>,    glu::PRECISION_MEDIUMP, Vec2(-1e2f, 1e2f),      Vec2(-1e2f, 1e2f)       },
893                 { "mediump_div",        "in0 / in1",    div<double>,    glu::PRECISION_MEDIUMP, Vec2(-1e2f, 1e2f),      Vec2(-1e2f, 1e2f)       }
894         };
895
896         static const struct
897         {
898                 const char*                                                     name;
899                 const char*                                                     op;
900                 ShaderIntPrecisionCase::EvalFunc        evalFunc;
901                 glu::Precision                                          precision;
902                 int                                                                     bits;
903                 tcu::IVec2                                                      rangeA;
904                 tcu::IVec2                                                      rangeB;
905         } intCases[] =
906         {
907                 // Name                         Op                              Eval                            Precision                               Bits    RangeA                  RangeB
908                 { "highp_add",          "in0 + in1",    add<int>,                       glu::PRECISION_HIGHP,   32,             fullRange32I,   fullRange32I },
909                 { "highp_sub",          "in0 - in1",    sub<int>,                       glu::PRECISION_HIGHP,   32,             fullRange32I,   fullRange32I },
910                 { "highp_mul",          "in0 * in1",    mul<int>,                       glu::PRECISION_HIGHP,   32,             fullRange32I,   fullRange32I },
911                 { "highp_div",          "in0 / in1",    div<int>,                       glu::PRECISION_HIGHP,   32,             fullRange32I,   IVec2(-10000, -1) },
912                 { "mediump_add",        "in0 + in1",    add<int>,                       glu::PRECISION_MEDIUMP, 16,             fullRange16I,   fullRange16I },
913                 { "mediump_sub",        "in0 - in1",    sub<int>,                       glu::PRECISION_MEDIUMP, 16,             fullRange16I,   fullRange16I },
914                 { "mediump_mul",        "in0 * in1",    mul<int>,                       glu::PRECISION_MEDIUMP, 16,             fullRange16I,   fullRange16I },
915                 { "mediump_div",        "in0 / in1",    div<int>,                       glu::PRECISION_MEDIUMP, 16,             fullRange16I,   IVec2(1, 1000) },
916                 { "lowp_add",           "in0 + in1",    add<int>,                       glu::PRECISION_LOWP,    8,              fullRange8I,    fullRange8I },
917                 { "lowp_sub",           "in0 - in1",    sub<int>,                       glu::PRECISION_LOWP,    8,              fullRange8I,    fullRange8I },
918                 { "lowp_mul",           "in0 * in1",    mul<int>,                       glu::PRECISION_LOWP,    8,              fullRange8I,    fullRange8I },
919                 { "lowp_div",           "in0 / in1",    div<int>,                       glu::PRECISION_LOWP,    8,              fullRange8I,    IVec2(-50, -1) }
920         };
921
922         static const struct
923         {
924                 const char*                                                     name;
925                 const char*                                                     op;
926                 ShaderUintPrecisionCase::EvalFunc       evalFunc;
927                 glu::Precision                                          precision;
928                 int                                                                     bits;
929                 tcu::UVec2                                                      rangeA;
930                 tcu::UVec2                                                      rangeB;
931         } uintCases[] =
932         {
933                 // Name                         Op                              Eval                            Precision                               Bits    RangeA                  RangeB
934                 { "highp_add",          "in0 + in1",    add<deUint32>,          glu::PRECISION_HIGHP,   32,             fullRange32U,   fullRange32U },
935                 { "highp_sub",          "in0 - in1",    sub<deUint32>,          glu::PRECISION_HIGHP,   32,             fullRange32U,   fullRange32U },
936                 { "highp_mul",          "in0 * in1",    mul<deUint32>,          glu::PRECISION_HIGHP,   32,             fullRange32U,   fullRange32U },
937                 { "highp_div",          "in0 / in1",    div<deUint32>,          glu::PRECISION_HIGHP,   32,             fullRange32U,   UVec2(1u, 10000u) },
938                 { "mediump_add",        "in0 + in1",    add<deUint32>,          glu::PRECISION_MEDIUMP, 16,             fullRange16U,   fullRange16U },
939                 { "mediump_sub",        "in0 - in1",    sub<deUint32>,          glu::PRECISION_MEDIUMP, 16,             fullRange16U,   fullRange16U },
940                 { "mediump_mul",        "in0 * in1",    mul<deUint32>,          glu::PRECISION_MEDIUMP, 16,             fullRange16U,   fullRange16U },
941                 { "mediump_div",        "in0 / in1",    div<deUint32>,          glu::PRECISION_MEDIUMP, 16,             fullRange16U,   UVec2(1, 1000u) },
942                 { "lowp_add",           "in0 + in1",    add<deUint32>,          glu::PRECISION_LOWP,    8,              fullRange8U,    fullRange8U },
943                 { "lowp_sub",           "in0 - in1",    sub<deUint32>,          glu::PRECISION_LOWP,    8,              fullRange8U,    fullRange8U },
944                 { "lowp_mul",           "in0 * in1",    mul<deUint32>,          glu::PRECISION_LOWP,    8,              fullRange8U,    fullRange8U },
945                 { "lowp_div",           "in0 / in1",    div<deUint32>,          glu::PRECISION_LOWP,    8,              fullRange8U,    UVec2(1, 50u) }
946         };
947
948         tcu::TestCaseGroup* floatGroup = new tcu::TestCaseGroup(m_testCtx, "float", "Floating-point precision tests");
949         addChild(floatGroup);
950         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(floatCases); ndx++)
951         {
952                 floatGroup->addChild(new ShaderFloatPrecisionCase(m_context,
953                                                                                                                   (string(floatCases[ndx].name) + "_vertex").c_str(), "",
954                                                                                                                   floatCases[ndx].op,
955                                                                                                                   floatCases[ndx].evalFunc,
956                                                                                                                   floatCases[ndx].precision,
957                                                                                                                   floatCases[ndx].rangeA,
958                                                                                                                   floatCases[ndx].rangeB,
959                                                                                                                   true));
960                 floatGroup->addChild(new ShaderFloatPrecisionCase(m_context,
961                                                                                                                   (string(floatCases[ndx].name) + "_fragment").c_str(), "",
962                                                                                                                   floatCases[ndx].op,
963                                                                                                                   floatCases[ndx].evalFunc,
964                                                                                                                   floatCases[ndx].precision,
965                                                                                                                   floatCases[ndx].rangeA,
966                                                                                                                   floatCases[ndx].rangeB,
967                                                                                                                   false));
968         }
969
970         tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "int", "Integer precision tests");
971         addChild(intGroup);
972         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intCases); ndx++)
973         {
974                 intGroup->addChild(new ShaderIntPrecisionCase(m_context,
975                                                                                                           (string(intCases[ndx].name) + "_vertex").c_str(), "",
976                                                                                                           intCases[ndx].op,
977                                                                                                           intCases[ndx].evalFunc,
978                                                                                                           intCases[ndx].precision,
979                                                                                                           intCases[ndx].bits,
980                                                                                                           intCases[ndx].rangeA,
981                                                                                                           intCases[ndx].rangeB,
982                                                                                                           true));
983                 intGroup->addChild(new ShaderIntPrecisionCase(m_context,
984                                                                                                           (string(intCases[ndx].name) + "_fragment").c_str(), "",
985                                                                                                           intCases[ndx].op,
986                                                                                                           intCases[ndx].evalFunc,
987                                                                                                           intCases[ndx].precision,
988                                                                                                           intCases[ndx].bits,
989                                                                                                           intCases[ndx].rangeA,
990                                                                                                           intCases[ndx].rangeB,
991                                                                                                           false));
992         }
993
994         tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uint", "Unsigned integer precision tests");
995         addChild(uintGroup);
996         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(uintCases); ndx++)
997         {
998                 uintGroup->addChild(new ShaderUintPrecisionCase(m_context,
999                                                                                                                 (string(uintCases[ndx].name) + "_vertex").c_str(), "",
1000                                                                                                                 uintCases[ndx].op,
1001                                                                                                                 uintCases[ndx].evalFunc,
1002                                                                                                                 uintCases[ndx].precision,
1003                                                                                                                 uintCases[ndx].bits,
1004                                                                                                                 uintCases[ndx].rangeA,
1005                                                                                                                 uintCases[ndx].rangeB,
1006                                                                                                                 true));
1007                 uintGroup->addChild(new ShaderUintPrecisionCase(m_context,
1008                                                                                                                 (string(uintCases[ndx].name) + "_fragment").c_str(), "",
1009                                                                                                                 uintCases[ndx].op,
1010                                                                                                                 uintCases[ndx].evalFunc,
1011                                                                                                                 uintCases[ndx].precision,
1012                                                                                                                 uintCases[ndx].bits,
1013                                                                                                                 uintCases[ndx].rangeA,
1014                                                                                                                 uintCases[ndx].rangeB,
1015                                                                                                                 false));
1016         }
1017 }
1018
1019 } // Functional
1020 } // gles3
1021 } // deqp