Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / shaderrender / vktShaderRenderDerivateTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Shader derivate function tests.
24  *
25  * \todo [2013-06-25 pyry] Missing features:
26  *  - lines and points
27  *  - projected coordinates
28  *  - continous non-trivial functions (sin, exp)
29  *  - non-continous functions (step)
30  *//*--------------------------------------------------------------------*/
31
32 #include "vktShaderRenderDerivateTests.hpp"
33 #include "vktShaderRender.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkQueryUtil.hpp"
36
37 #include "gluTextureUtil.hpp"
38
39 #include "tcuStringTemplate.hpp"
40 #include "tcuSurface.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVectorUtil.hpp"
43 #include "tcuTextureUtil.hpp"
44 #include "tcuRGBA.hpp"
45 #include "tcuFloat.hpp"
46 #include "tcuInterval.hpp"
47
48 #include "deUniquePtr.hpp"
49 #include "glwEnums.hpp"
50
51 #include <sstream>
52 #include <string>
53
54 namespace vkt
55 {
56 namespace sr
57 {
58 namespace
59 {
60
61 using namespace vk;
62
63 using std::vector;
64 using std::string;
65 using std::map;
66 using tcu::TestLog;
67 using std::ostringstream;
68
69 enum
70 {
71         VIEWPORT_WIDTH                  = 99,
72         VIEWPORT_HEIGHT                 = 133,
73         MAX_FAILED_MESSAGES             = 10
74 };
75
76 enum DerivateFunc
77 {
78         DERIVATE_DFDX                   = 0,
79         DERIVATE_DFDXFINE,
80         DERIVATE_DFDXCOARSE,
81
82         DERIVATE_DFDY,
83         DERIVATE_DFDYFINE,
84         DERIVATE_DFDYCOARSE,
85
86         DERIVATE_FWIDTH,
87         DERIVATE_FWIDTHFINE,
88         DERIVATE_FWIDTHCOARSE,
89
90         DERIVATE_LAST
91 };
92
93 enum SurfaceType
94 {
95         SURFACETYPE_UNORM_FBO   = 0,
96         SURFACETYPE_FLOAT_FBO,  // \note Uses RGBA32UI fbo actually, since FP rendertargets are not in core spec.
97
98         SURFACETYPE_LAST
99 };
100
101 // Utilities
102
103 static const char* getDerivateFuncName (DerivateFunc func)
104 {
105         switch (func)
106         {
107                 case DERIVATE_DFDX:                             return "dFdx";
108                 case DERIVATE_DFDXFINE:                 return "dFdxFine";
109                 case DERIVATE_DFDXCOARSE:               return "dFdxCoarse";
110                 case DERIVATE_DFDY:                             return "dFdy";
111                 case DERIVATE_DFDYFINE:                 return "dFdyFine";
112                 case DERIVATE_DFDYCOARSE:               return "dFdyCoarse";
113                 case DERIVATE_FWIDTH:                   return "fwidth";
114                 case DERIVATE_FWIDTHFINE:               return "fwidthFine";
115                 case DERIVATE_FWIDTHCOARSE:             return "fwidthCoarse";
116                 default:
117                         DE_ASSERT(false);
118                         return DE_NULL;
119         }
120 }
121
122 static const char* getDerivateFuncCaseName (DerivateFunc func)
123 {
124         switch (func)
125         {
126                 case DERIVATE_DFDX:                             return "dfdx";
127                 case DERIVATE_DFDXFINE:                 return "dfdxfine";
128                 case DERIVATE_DFDXCOARSE:               return "dfdxcoarse";
129                 case DERIVATE_DFDY:                             return "dfdy";
130                 case DERIVATE_DFDYFINE:                 return "dfdyfine";
131                 case DERIVATE_DFDYCOARSE:               return "dfdycoarse";
132                 case DERIVATE_FWIDTH:                   return "fwidth";
133                 case DERIVATE_FWIDTHFINE:               return "fwidthfine";
134                 case DERIVATE_FWIDTHCOARSE:             return "fwidthcoarse";
135                 default:
136                         DE_ASSERT(false);
137                         return DE_NULL;
138         }
139 }
140
141 static inline bool isDfdxFunc (DerivateFunc func)
142 {
143         return func == DERIVATE_DFDX || func == DERIVATE_DFDXFINE || func == DERIVATE_DFDXCOARSE;
144 }
145
146 static inline bool isDfdyFunc (DerivateFunc func)
147 {
148         return func == DERIVATE_DFDY || func == DERIVATE_DFDYFINE || func == DERIVATE_DFDYCOARSE;
149 }
150
151 static inline bool isFwidthFunc (DerivateFunc func)
152 {
153         return func == DERIVATE_FWIDTH || func == DERIVATE_FWIDTHFINE || func == DERIVATE_FWIDTHCOARSE;
154 }
155
156 static inline tcu::BVec4 getDerivateMask (glu::DataType type)
157 {
158         switch (type)
159         {
160                 case glu::TYPE_FLOAT:           return tcu::BVec4(true, false, false, false);
161                 case glu::TYPE_FLOAT_VEC2:      return tcu::BVec4(true, true, false, false);
162                 case glu::TYPE_FLOAT_VEC3:      return tcu::BVec4(true, true, true, false);
163                 case glu::TYPE_FLOAT_VEC4:      return tcu::BVec4(true, true, true, true);
164                 default:
165                         DE_ASSERT(false);
166                         return tcu::BVec4(true);
167         }
168 }
169
170 static inline tcu::Vec4 readDerivate (const tcu::ConstPixelBufferAccess& surface, const tcu::Vec4& derivScale, const tcu::Vec4& derivBias, int x, int y)
171 {
172         return (surface.getPixel(x, y) - derivBias) / derivScale;
173 }
174
175 static inline tcu::UVec4 getCompExpBits (const tcu::Vec4& v)
176 {
177         return tcu::UVec4(tcu::Float32(v[0]).exponentBits(),
178                                           tcu::Float32(v[1]).exponentBits(),
179                                           tcu::Float32(v[2]).exponentBits(),
180                                           tcu::Float32(v[3]).exponentBits());
181 }
182
183 float computeFloatingPointError (const float value, const int numAccurateBits)
184 {
185         const int               numGarbageBits  = 23-numAccurateBits;
186         const deUint32  mask                    = (1u<<numGarbageBits)-1u;
187         const int               exp                             = tcu::Float32(value).exponent();
188
189         return tcu::Float32::construct(+1, exp, (1u<<23) | mask).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
190 }
191
192 static int getNumMantissaBits (const glu::Precision precision)
193 {
194         switch (precision)
195         {
196                 case glu::PRECISION_HIGHP:              return 23;
197                 case glu::PRECISION_MEDIUMP:    return 10;
198                 case glu::PRECISION_LOWP:               return 6;
199                 default:
200                         DE_ASSERT(false);
201                         return 0;
202         }
203 }
204
205 static int getMinExponent (const glu::Precision precision)
206 {
207         switch (precision)
208         {
209                 case glu::PRECISION_HIGHP:              return -126;
210                 case glu::PRECISION_MEDIUMP:    return -14;
211                 case glu::PRECISION_LOWP:               return -8;
212                 default:
213                         DE_ASSERT(false);
214                         return 0;
215         }
216 }
217
218 static float getSingleULPForExponent (int exp, int numMantissaBits)
219 {
220         if (numMantissaBits > 0)
221         {
222                 DE_ASSERT(numMantissaBits <= 23);
223
224                 const int ulpBitNdx = 23-numMantissaBits;
225                 return tcu::Float32::construct(+1, exp, (1<<23) | (1 << ulpBitNdx)).asFloat() - tcu::Float32::construct(+1, exp, (1<<23)).asFloat();
226         }
227         else
228         {
229                 DE_ASSERT(numMantissaBits == 0);
230                 return tcu::Float32::construct(+1, exp, (1<<23)).asFloat();
231         }
232 }
233
234 static float getSingleULPForValue (float value, int numMantissaBits)
235 {
236         const int exp = tcu::Float32(value).exponent();
237         return getSingleULPForExponent(exp, numMantissaBits);
238 }
239
240 static float convertFloatFlushToZeroRtn (float value, int minExponent, int numAccurateBits)
241 {
242         if (value == 0.0f)
243         {
244                 return 0.0f;
245         }
246         else
247         {
248                 const tcu::Float32      inputFloat                      = tcu::Float32(value);
249                 const int                       numTruncatedBits        = 23-numAccurateBits;
250                 const deUint32          truncMask                       = (1u<<numTruncatedBits)-1u;
251
252                 if (value > 0.0f)
253                 {
254                         if (value > 0.0f && tcu::Float32(value).exponent() < minExponent)
255                         {
256                                 // flush to zero if possible
257                                 return 0.0f;
258                         }
259                         else
260                         {
261                                 // just mask away non-representable bits
262                                 return tcu::Float32::construct(+1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).asFloat();
263                         }
264                 }
265                 else
266                 {
267                         if (inputFloat.mantissa() & truncMask)
268                         {
269                                 // decrement one ulp if truncated bits are non-zero (i.e. if value is not representable)
270                                 return tcu::Float32::construct(-1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).asFloat() - getSingleULPForExponent(inputFloat.exponent(), numAccurateBits);
271                         }
272                         else
273                         {
274                                 // value is representable, no need to do anything
275                                 return value;
276                         }
277                 }
278         }
279 }
280
281 static float convertFloatFlushToZeroRtp (float value, int minExponent, int numAccurateBits)
282 {
283         return -convertFloatFlushToZeroRtn(-value, minExponent, numAccurateBits);
284 }
285
286 static float addErrorUlp (float value, float numUlps, int numMantissaBits)
287 {
288         return value + numUlps * getSingleULPForValue(value, numMantissaBits);
289 }
290
291 enum
292 {
293         INTERPOLATION_LOST_BITS = 3, // number mantissa of bits allowed to be lost in varying interpolation
294 };
295
296 static inline tcu::Vec4 getDerivateThreshold (const glu::Precision precision, const tcu::Vec4& valueMin, const tcu::Vec4& valueMax, const tcu::Vec4& expectedDerivate)
297 {
298         const int                       baseBits                = getNumMantissaBits(precision);
299         const tcu::UVec4        derivExp                = getCompExpBits(expectedDerivate);
300         const tcu::UVec4        maxValueExp             = max(getCompExpBits(valueMin), getCompExpBits(valueMax));
301         const tcu::UVec4        numBitsLost             = maxValueExp - min(maxValueExp, derivExp);
302         const tcu::IVec4        numAccurateBits = max(baseBits - numBitsLost.asInt() - (int)INTERPOLATION_LOST_BITS, tcu::IVec4(0));
303
304         return tcu::Vec4(computeFloatingPointError(expectedDerivate[0], numAccurateBits[0]),
305                                          computeFloatingPointError(expectedDerivate[1], numAccurateBits[1]),
306                                          computeFloatingPointError(expectedDerivate[2], numAccurateBits[2]),
307                                          computeFloatingPointError(expectedDerivate[3], numAccurateBits[3]));
308 }
309
310 struct LogVecComps
311 {
312         const tcu::Vec4&        v;
313         int                                     numComps;
314
315         LogVecComps (const tcu::Vec4& v_, int numComps_)
316                 : v                     (v_)
317                 , numComps      (numComps_)
318         {
319         }
320 };
321
322 std::ostream& operator<< (std::ostream& str, const LogVecComps& v)
323 {
324         DE_ASSERT(de::inRange(v.numComps, 1, 4));
325         if (v.numComps == 1)            return str << v.v[0];
326         else if (v.numComps == 2)       return str << v.v.toWidth<2>();
327         else if (v.numComps == 3)       return str << v.v.toWidth<3>();
328         else                                            return str << v.v;
329 }
330
331 enum VerificationLogging
332 {
333         LOG_ALL = 0,
334         LOG_NOTHING
335 };
336
337 static bool verifyConstantDerivate (tcu::TestLog&                                               log,
338                                                                         const tcu::ConstPixelBufferAccess&      result,
339                                                                         const tcu::PixelBufferAccess&           errorMask,
340                                                                         glu::DataType                                           dataType,
341                                                                         const tcu::Vec4&                                        reference,
342                                                                         const tcu::Vec4&                                        threshold,
343                                                                         const tcu::Vec4&                                        scale,
344                                                                         const tcu::Vec4&                                        bias,
345                                                                         VerificationLogging                                     logPolicy = LOG_ALL)
346 {
347         const int                       numComps                = glu::getDataTypeFloatScalars(dataType);
348         const tcu::BVec4        mask                    = tcu::logicalNot(getDerivateMask(dataType));
349         int                                     numFailedPixels = 0;
350
351         if (logPolicy == LOG_ALL)
352                 log << TestLog::Message << "Expecting " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps) << TestLog::EndMessage;
353
354         for (int y = 0; y < result.getHeight(); y++)
355         {
356                 for (int x = 0; x < result.getWidth(); x++)
357                 {
358                         const tcu::Vec4         resDerivate             = readDerivate(result, scale, bias, x, y);
359                         const bool                      isOk                    = tcu::allEqual(tcu::logicalOr(tcu::lessThanEqual(tcu::abs(reference - resDerivate), threshold), mask), tcu::BVec4(true));
360
361                         if (!isOk)
362                         {
363                                 if (numFailedPixels < MAX_FAILED_MESSAGES && logPolicy == LOG_ALL)
364                                         log << TestLog::Message << "FAIL: got " << LogVecComps(resDerivate, numComps)
365                                                                                         << ", diff = " << LogVecComps(tcu::abs(reference - resDerivate), numComps)
366                                                                                         << ", at x = " << x << ", y = " << y
367                                                 << TestLog::EndMessage;
368                                 numFailedPixels += 1;
369                                 errorMask.setPixel(tcu::RGBA::red().toVec(), x, y);
370                         }
371                 }
372         }
373
374         if (numFailedPixels >= MAX_FAILED_MESSAGES && logPolicy == LOG_ALL)
375                 log << TestLog::Message << "..." << TestLog::EndMessage;
376
377         if (numFailedPixels > 0 && logPolicy == LOG_ALL)
378                 log << TestLog::Message << "FAIL: found " << numFailedPixels << " failed pixels" << TestLog::EndMessage;
379
380         return numFailedPixels == 0;
381 }
382
383 struct Linear2DFunctionEvaluator
384 {
385         tcu::Matrix<float, 4, 3> matrix;
386
387         //      .-----.
388         //      | s_x |
389         //  M x | s_y |
390         //      | 1.0 |
391         //      '-----'
392         tcu::Vec4 evaluateAt (float screenX, float screenY) const;
393 };
394
395 tcu::Vec4 Linear2DFunctionEvaluator::evaluateAt (float screenX, float screenY) const
396 {
397         const tcu::Vec3 position(screenX, screenY, 1.0f);
398         return matrix * position;
399 }
400
401 static bool reverifyConstantDerivateWithFlushRelaxations (tcu::TestLog&                                                 log,
402                                                                                                                   const tcu::ConstPixelBufferAccess&    result,
403                                                                                                                   const tcu::PixelBufferAccess&                 errorMask,
404                                                                                                                   glu::DataType                                                 dataType,
405                                                                                                                   glu::Precision                                                precision,
406                                                                                                                   const tcu::Vec4&                                              derivScale,
407                                                                                                                   const tcu::Vec4&                                              derivBias,
408                                                                                                                   const tcu::Vec4&                                              surfaceThreshold,
409                                                                                                                   DerivateFunc                                                  derivateFunc,
410                                                                                                                   const Linear2DFunctionEvaluator&              function)
411 {
412         DE_ASSERT(result.getWidth() == errorMask.getWidth());
413         DE_ASSERT(result.getHeight() == errorMask.getHeight());
414         DE_ASSERT(isDfdxFunc(derivateFunc) || isDfdyFunc(derivateFunc));
415
416         const tcu::IVec4        red                                             (255, 0, 0, 255);
417         const tcu::IVec4        green                                   (0, 255, 0, 255);
418         const float                     divisionErrorUlps               = 2.5f;
419
420         const int                       numComponents                   = glu::getDataTypeFloatScalars(dataType);
421         const int                       numBits                                 = getNumMantissaBits(precision);
422         const int                       minExponent                             = getMinExponent(precision);
423
424         const int                       numVaryingSampleBits    = numBits - INTERPOLATION_LOST_BITS;
425         int                                     numFailedPixels                 = 0;
426
427         tcu::clear(errorMask, green);
428
429         // search for failed pixels
430         for (int y = 0; y < result.getHeight(); ++y)
431         for (int x = 0; x < result.getWidth(); ++x)
432         {
433                 //                 flushToZero?(f2z?(functionValueCurrent) - f2z?(functionValueBefore))
434                 // flushToZero? ( ------------------------------------------------------------------------ +- 2.5 ULP )
435                 //                                                  dx
436
437                 const tcu::Vec4 resultDerivative                = readDerivate(result, derivScale, derivBias, x, y);
438
439                 // sample at the front of the back pixel and the back of the front pixel to cover the whole area of
440                 // legal sample positions. In general case this is NOT OK, but we know that the target funtion is
441                 // (mostly*) linear which allows us to take the sample points at arbitrary points. This gets us the
442                 // maximum difference possible in exponents which are used in error bound calculations.
443                 // * non-linearity may happen around zero or with very high function values due to subnorms not
444                 //   behaving well.
445                 const tcu::Vec4 functionValueForward    = (isDfdxFunc(derivateFunc))
446                                                                                                         ? (function.evaluateAt((float)x + 2.0f, (float)y + 0.5f))
447                                                                                                         : (function.evaluateAt((float)x + 0.5f, (float)y + 2.0f));
448                 const tcu::Vec4 functionValueBackward   = (isDfdyFunc(derivateFunc))
449                                                                                                         ? (function.evaluateAt((float)x - 1.0f, (float)y + 0.5f))
450                                                                                                         : (function.evaluateAt((float)x + 0.5f, (float)y - 1.0f));
451
452                 bool    anyComponentFailed                              = false;
453
454                 // check components separately
455                 for (int c = 0; c < numComponents; ++c)
456                 {
457                         // Simulate interpolation. Add allowed interpolation error and round to target precision. Allow one half ULP (i.e. correct rounding)
458                         const tcu::Interval     forwardComponent                (convertFloatFlushToZeroRtn(addErrorUlp((float)functionValueForward[c],  -0.5f, numVaryingSampleBits), minExponent, numBits),
459                                                                                                                  convertFloatFlushToZeroRtp(addErrorUlp((float)functionValueForward[c],  +0.5f, numVaryingSampleBits), minExponent, numBits));
460                         const tcu::Interval     backwardComponent               (convertFloatFlushToZeroRtn(addErrorUlp((float)functionValueBackward[c], -0.5f, numVaryingSampleBits), minExponent, numBits),
461                                                                                                                  convertFloatFlushToZeroRtp(addErrorUlp((float)functionValueBackward[c], +0.5f, numVaryingSampleBits), minExponent, numBits));
462                         const int                       maxValueExp                             = de::max(de::max(tcu::Float32(forwardComponent.lo()).exponent(),   tcu::Float32(forwardComponent.hi()).exponent()),
463                                                                                                                                   de::max(tcu::Float32(backwardComponent.lo()).exponent(),  tcu::Float32(backwardComponent.hi()).exponent()));
464
465                         // subtraction in numerator will likely cause a cancellation of the most
466                         // significant bits. Apply error bounds.
467
468                         const tcu::Interval     numerator                               (forwardComponent - backwardComponent);
469                         const int                       numeratorLoExp                  = tcu::Float32(numerator.lo()).exponent();
470                         const int                       numeratorHiExp                  = tcu::Float32(numerator.hi()).exponent();
471                         const int                       numeratorLoBitsLost             = de::max(0, maxValueExp - numeratorLoExp); //!< must clamp to zero since if forward and backward components have different
472                         const int                       numeratorHiBitsLost             = de::max(0, maxValueExp - numeratorHiExp); //!< sign, numerator might have larger exponent than its operands.
473                         const int                       numeratorLoBits                 = de::max(0, numBits - numeratorLoBitsLost);
474                         const int                       numeratorHiBits                 = de::max(0, numBits - numeratorHiBitsLost);
475
476                         const tcu::Interval     numeratorRange                  (convertFloatFlushToZeroRtn((float)numerator.lo(), minExponent, numeratorLoBits),
477                                                                                                                  convertFloatFlushToZeroRtp((float)numerator.hi(), minExponent, numeratorHiBits));
478
479                         const tcu::Interval     divisionRange                   = numeratorRange / 3.0f; // legal sample area is anywhere within this and neighboring pixels (i.e. size = 3)
480                         const tcu::Interval     divisionResultRange             (convertFloatFlushToZeroRtn(addErrorUlp((float)divisionRange.lo(), -divisionErrorUlps, numBits), minExponent, numBits),
481                                                                                                                  convertFloatFlushToZeroRtp(addErrorUlp((float)divisionRange.hi(), +divisionErrorUlps, numBits), minExponent, numBits));
482                         const tcu::Interval     finalResultRange                (divisionResultRange.lo() - surfaceThreshold[c], divisionResultRange.hi() + surfaceThreshold[c]);
483
484                         if (resultDerivative[c] >= finalResultRange.lo() && resultDerivative[c] <= finalResultRange.hi())
485                         {
486                                 // value ok
487                         }
488                         else
489                         {
490                                 if (numFailedPixels < MAX_FAILED_MESSAGES)
491                                         log << tcu::TestLog::Message
492                                                 << "Error in pixel at " << x << ", " << y << " with component " << c << " (channel " << ("rgba"[c]) << ")\n"
493                                                 << "\tGot pixel value " << result.getPixelInt(x, y) << "\n"
494                                                 << "\t\tdFd" << ((isDfdxFunc(derivateFunc)) ? ('x') : ('y')) << " ~= " << resultDerivative[c] << "\n"
495                                                 << "\t\tdifference to a valid range: "
496                                                         << ((resultDerivative[c] < finalResultRange.lo()) ? ("-") : ("+"))
497                                                         << ((resultDerivative[c] < finalResultRange.lo()) ? (finalResultRange.lo() - resultDerivative[c]) : (resultDerivative[c] - finalResultRange.hi()))
498                                                         << "\n"
499                                                 << "\tDerivative value range:\n"
500                                                 << "\t\tMin: " << finalResultRange.lo() << "\n"
501                                                 << "\t\tMax: " << finalResultRange.hi() << "\n"
502                                                 << tcu::TestLog::EndMessage;
503
504                                 ++numFailedPixels;
505                                 anyComponentFailed = true;
506                         }
507                 }
508
509                 if (anyComponentFailed)
510                         errorMask.setPixel(red, x, y);
511         }
512
513         if (numFailedPixels >= MAX_FAILED_MESSAGES)
514                 log << TestLog::Message << "..." << TestLog::EndMessage;
515
516         if (numFailedPixels > 0)
517                 log << TestLog::Message << "FAIL: found " << numFailedPixels << " failed pixels" << TestLog::EndMessage;
518
519         return numFailedPixels == 0;
520 }
521
522 // TestCase utils
523
524 struct DerivateCaseDefinition
525 {
526         DerivateCaseDefinition (void)
527         {
528                 func                                    = DERIVATE_LAST;
529                 dataType                                = glu::TYPE_LAST;
530                 precision                               = glu::PRECISION_LAST;
531                 inNonUniformControlFlow = false;
532                 coordDataType                   = glu::TYPE_LAST;
533                 coordPrecision                  = glu::PRECISION_LAST;
534                 surfaceType                             = SURFACETYPE_UNORM_FBO;
535                 numSamples                              = 0;
536         }
537
538         DerivateFunc                    func;
539         glu::DataType                   dataType;
540         glu::Precision                  precision;
541         bool                                    inNonUniformControlFlow;
542
543         glu::DataType                   coordDataType;
544         glu::Precision                  coordPrecision;
545
546         SurfaceType                             surfaceType;
547         int                                             numSamples;
548 };
549
550 struct DerivateCaseValues
551 {
552         tcu::Vec4       coordMin;
553         tcu::Vec4       coordMax;
554         tcu::Vec4       derivScale;
555         tcu::Vec4       derivBias;
556 };
557
558 struct TextureCaseValues
559 {
560         tcu::Vec4       texValueMin;
561         tcu::Vec4       texValueMax;
562 };
563
564 class DerivateUniformSetup : public UniformSetup
565 {
566 public:
567                                                 DerivateUniformSetup            (bool useSampler);
568         virtual                         ~DerivateUniformSetup           (void);
569
570         virtual void            setup                                           (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const;
571
572 private:
573         const bool                      m_useSampler;
574 };
575
576 DerivateUniformSetup::DerivateUniformSetup (bool useSampler)
577         : m_useSampler(useSampler)
578 {
579 }
580
581 DerivateUniformSetup::~DerivateUniformSetup (void)
582 {
583 }
584
585 // TriangleDerivateCaseInstance
586
587 class TriangleDerivateCaseInstance : public ShaderRenderCaseInstance
588 {
589 public:
590                                                                         TriangleDerivateCaseInstance    (Context&                                               context,
591                                                                                                                                          const UniformSetup&                    uniformSetup,
592                                                                                                                                          const DerivateCaseDefinition&  definitions,
593                                                                                                                                          const DerivateCaseValues&              values);
594         virtual                                                 ~TriangleDerivateCaseInstance   (void);
595         virtual tcu::TestStatus                 iterate                                                 (void);
596         DerivateCaseDefinition                  getDerivateCaseDefinition               (void) { return m_definitions; }
597         DerivateCaseValues                              getDerivateCaseValues                   (void) { return m_values; }
598
599 protected:
600         virtual bool                                    verify                                                  (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask) = 0;
601         tcu::Vec4                                               getSurfaceThreshold                             (void) const;
602         virtual void                                    setupDefaultInputs                              (void);
603
604         const DerivateCaseDefinition&   m_definitions;
605         const DerivateCaseValues&               m_values;
606 };
607
608 static VkSampleCountFlagBits getVkSampleCount (int numSamples)
609 {
610         switch (numSamples)
611         {
612                 case 0:         return VK_SAMPLE_COUNT_1_BIT;
613                 case 2:         return VK_SAMPLE_COUNT_2_BIT;
614                 case 4:         return VK_SAMPLE_COUNT_4_BIT;
615                 default:
616                         DE_ASSERT(false);
617                         return (VkSampleCountFlagBits)0;
618         }
619 }
620
621 TriangleDerivateCaseInstance::TriangleDerivateCaseInstance (Context&                                            context,
622                                                                                                                         const UniformSetup&                             uniformSetup,
623                                                                                                                         const DerivateCaseDefinition&   definitions,
624                                                                                                                         const DerivateCaseValues&               values)
625         : ShaderRenderCaseInstance      (context, true, DE_NULL, uniformSetup, DE_NULL)
626         , m_definitions                         (definitions)
627         , m_values                                      (values)
628 {
629         m_renderSize    = tcu::UVec2(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
630         m_colorFormat   = vk::mapTextureFormat(glu::mapGLInternalFormat(m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO ? GL_RGBA32UI : GL_RGBA8));
631
632         setSampleCount(getVkSampleCount(definitions.numSamples));
633 }
634
635 TriangleDerivateCaseInstance::~TriangleDerivateCaseInstance (void)
636 {
637 }
638
639 tcu::Vec4 TriangleDerivateCaseInstance::getSurfaceThreshold (void) const
640 {
641         switch (m_definitions.surfaceType)
642         {
643                 case SURFACETYPE_UNORM_FBO:                             return tcu::IVec4(1).asFloat() / 255.0f;
644                 case SURFACETYPE_FLOAT_FBO:                             return tcu::Vec4(0.0f);
645                 default:
646                         DE_ASSERT(false);
647                         return tcu::Vec4(0.0f);
648         }
649 }
650
651 void TriangleDerivateCaseInstance::setupDefaultInputs (void)
652 {
653         const int               numVertices                     = 4;
654         const float             positions[]                     =
655         {
656                 -1.0f, -1.0f, 0.0f, 1.0f,
657                 -1.0f,  1.0f, 0.0f, 1.0f,
658                 1.0f, -1.0f, 0.0f, 1.0f,
659                 1.0f,  1.0f, 0.0f, 1.0f
660         };
661         const float             coords[]                        =
662         {
663                 m_values.coordMin.x(), m_values.coordMin.y(), m_values.coordMin.z(),                                                            m_values.coordMax.w(),
664                 m_values.coordMin.x(), m_values.coordMax.y(), (m_values.coordMin.z()+m_values.coordMax.z())*0.5f,       (m_values.coordMin.w()+m_values.coordMax.w())*0.5f,
665                 m_values.coordMax.x(), m_values.coordMin.y(), (m_values.coordMin.z()+m_values.coordMax.z())*0.5f,       (m_values.coordMin.w()+m_values.coordMax.w())*0.5f,
666                 m_values.coordMax.x(), m_values.coordMax.y(), m_values.coordMax.z(),                                                            m_values.coordMin.w()
667         };
668
669         addAttribute(0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 4 * (deUint32)sizeof(float), numVertices, positions);
670         if (m_definitions.coordDataType != glu::TYPE_LAST)
671                 addAttribute(1u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 4 * (deUint32)sizeof(float), numVertices, coords);
672 }
673
674 tcu::TestStatus TriangleDerivateCaseInstance::iterate (void)
675 {
676         tcu::TestLog&                           log                             = m_context.getTestContext().getLog();
677         const deUint32                          numVertices             = 4;
678         const deUint32                          numTriangles    = 2;
679         const deUint16                          indices[]               = { 0, 2, 1, 2, 3, 1 };
680         tcu::TextureLevel                       resultImage;
681
682         if (m_definitions.inNonUniformControlFlow)
683         {
684                 if (!m_context.contextSupports(vk::ApiVersion(0, 1, 1, 0)))
685                         throw tcu::NotSupportedError("Derivatives in dynamic control flow requires Vulkan 1.1");
686
687                 vk::VkPhysicalDeviceSubgroupProperties subgroupProperties;
688                 deMemset(&subgroupProperties, 0, sizeof(subgroupProperties));
689                 subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
690
691                 vk::VkPhysicalDeviceProperties2 properties2;
692                 deMemset(&properties2, 0, sizeof(properties2));
693                 properties2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
694                 properties2.pNext = &subgroupProperties;
695
696                 m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &properties2);
697
698                 if (subgroupProperties.subgroupSize < 4)
699                         throw tcu::NotSupportedError("Derivatives in dynamic control flow requires subgroupSize >= 4");
700
701                 if ((subgroupProperties.supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) == 0)
702                         throw tcu::NotSupportedError("Derivative dynamic control flow tests require VK_SUBGROUP_FEATURE_BALLOT_BIT");
703
704                 if ((subgroupProperties.supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) == 0)
705                         throw tcu::NotSupportedError("Derivative dynamic control flow tests require subgroup supported stage including VK_SHADER_STAGE_FRAGMENT_BIT");
706         }
707
708         setup();
709
710         render(numVertices, numTriangles, indices);
711
712         {
713                 const tcu::TextureLevel&                renderedImage   = getResultImage();
714
715                 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
716                 {
717                         const tcu::TextureFormat        dataFormat              (tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
718
719                         resultImage.setStorage(dataFormat, renderedImage.getWidth(), renderedImage.getHeight());
720                         tcu::copy(resultImage.getAccess(), tcu::ConstPixelBufferAccess(dataFormat, renderedImage.getSize(), renderedImage.getAccess().getDataPtr()));
721                 }
722                 else
723                 {
724                         resultImage = renderedImage;
725                 }
726         }
727
728         // Verify
729         {
730                 tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
731                 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
732
733                 const bool isOk = verify(resultImage.getAccess(), errorMask.getAccess());
734
735                 log << TestLog::ImageSet("Result", "Result images")
736                         << TestLog::Image("Rendered", "Rendered image", resultImage);
737
738                 if (!isOk)
739                         log << TestLog::Image("ErrorMask", "Error mask", errorMask);
740
741                 log << TestLog::EndImageSet;
742
743                 if (isOk)
744                         return tcu::TestStatus::pass("Pass");
745                 else
746                         return tcu::TestStatus::fail("Image comparison failed");
747         }
748 }
749
750 void DerivateUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
751 {
752         DerivateCaseDefinition  definitions             = dynamic_cast<TriangleDerivateCaseInstance&>(instance).getDerivateCaseDefinition();
753         DerivateCaseValues              values                  = dynamic_cast<TriangleDerivateCaseInstance&>(instance).getDerivateCaseValues();
754
755         DE_ASSERT(glu::isDataTypeFloatOrVec(definitions.dataType));
756
757         instance.addUniform(0u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, glu::getDataTypeScalarSize(definitions.dataType) * sizeof(float), values.derivScale.getPtr());
758         instance.addUniform(1u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, glu::getDataTypeScalarSize(definitions.dataType) * sizeof(float), values.derivBias.getPtr());
759
760         if (m_useSampler)
761                 instance.useSampler(2u, 0u); // To the uniform binding location 2 bind the texture 0
762 }
763
764 // TriangleDerivateCase
765
766 class TriangleDerivateCase : public ShaderRenderCase
767 {
768 public:
769                                                                         TriangleDerivateCase    (tcu::TestContext&              testCtx,
770                                                                                                                          const std::string&             name,
771                                                                                                                          const std::string&             description,
772                                                                                                                          const UniformSetup*    uniformSetup);
773         virtual                                                 ~TriangleDerivateCase   (void);
774
775 protected:
776         mutable DerivateCaseDefinition  m_definitions;
777         mutable DerivateCaseValues              m_values;
778 };
779
780 TriangleDerivateCase::TriangleDerivateCase (tcu::TestContext&           testCtx,
781                                                                                         const std::string&              name,
782                                                                                         const std::string&              description,
783                                                                                         const UniformSetup*             uniformSetup)
784         : ShaderRenderCase              (testCtx, name, description, false, (ShaderEvaluator*)DE_NULL, uniformSetup, DE_NULL)
785         , m_definitions                 ()
786 {
787 }
788
789 TriangleDerivateCase::~TriangleDerivateCase (void)
790 {
791 }
792
793 static std::string genVertexSource (glu::DataType coordType, glu::Precision precision)
794 {
795         DE_ASSERT(coordType == glu::TYPE_LAST || glu::isDataTypeFloatOrVec(coordType));
796
797         const std::string vertexTmpl =
798                 "#version 450\n"
799                 "layout(location = 0) in highp vec4 a_position;\n"
800                 + string(coordType != glu::TYPE_LAST ? "layout(location = 1) in ${PRECISION} ${DATATYPE} a_coord;\n"
801                                                                                            "layout(location = 0) out ${PRECISION} ${DATATYPE} v_coord;\n" : "") +
802                 "out gl_PerVertex {\n"
803                 "       vec4 gl_Position;\n"
804                 "};\n"
805                 "void main (void)\n"
806                 "{\n"
807                 "       gl_Position = a_position;\n"
808                 + string(coordType != glu::TYPE_LAST ? "        v_coord = a_coord;\n" : "") +
809                 "}\n";
810
811         map<string, string> vertexParams;
812
813         if (coordType != glu::TYPE_LAST)
814         {
815                 vertexParams["PRECISION"]       = glu::getPrecisionName(precision);
816                 vertexParams["DATATYPE"]        = glu::getDataTypeName(coordType);
817         }
818
819         return tcu::StringTemplate(vertexTmpl).specialize(vertexParams);
820 }
821
822 // ConstantDerivateCaseInstance
823
824 class ConstantDerivateCaseInstance : public TriangleDerivateCaseInstance
825 {
826 public:
827                                                                 ConstantDerivateCaseInstance    (Context&                                               context,
828                                                                                                                                  const UniformSetup&                    uniformSetup,
829                                                                                                                                  const DerivateCaseDefinition&  definitions,
830                                                                                                                                  const DerivateCaseValues&              values);
831         virtual                                         ~ConstantDerivateCaseInstance   (void);
832
833         virtual bool                            verify                                                  (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
834 };
835
836 ConstantDerivateCaseInstance::ConstantDerivateCaseInstance (Context&                                                    context,
837                                                                                                                         const UniformSetup&                                     uniformSetup,
838                                                                                                                         const DerivateCaseDefinition&           definitions,
839                                                                                                                         const DerivateCaseValues&                       values)
840         : TriangleDerivateCaseInstance  (context, uniformSetup, definitions, values)
841 {
842 }
843
844 ConstantDerivateCaseInstance::~ConstantDerivateCaseInstance (void)
845 {
846 }
847
848 bool ConstantDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
849 {
850         const tcu::Vec4 reference       (0.0f); // Derivate of constant argument should always be 0
851         const tcu::Vec4 threshold       = getSurfaceThreshold() / abs(m_values.derivScale);
852
853         return verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
854                                                                   reference, threshold, m_values.derivScale, m_values.derivBias);
855 }
856
857 // ConstantDerivateCase
858
859 class ConstantDerivateCase : public TriangleDerivateCase
860 {
861 public:
862                                                         ConstantDerivateCase            (tcu::TestContext&              testCtx,
863                                                                                                                  const std::string&             name,
864                                                                                                                  const std::string&             description,
865                                                                                                                  DerivateFunc                   func,
866                                                                                                                  glu::DataType                  type);
867         virtual                                 ~ConstantDerivateCase           (void);
868
869         virtual void                    initPrograms                            (vk::SourceCollections& programCollection) const;
870         virtual TestInstance*   createInstance                          (Context& context) const;
871 };
872
873 ConstantDerivateCase::ConstantDerivateCase (tcu::TestContext&           testCtx,
874                                                                                         const std::string&              name,
875                                                                                         const std::string&              description,
876                                                                                         DerivateFunc                    func,
877                                                                                         glu::DataType                   type)
878         : TriangleDerivateCase  (testCtx, name, description, new DerivateUniformSetup(false))
879 {
880         m_definitions.func                              = func;
881         m_definitions.dataType                  = type;
882         m_definitions.precision                 = glu::PRECISION_HIGHP;
883 }
884
885 ConstantDerivateCase::~ConstantDerivateCase (void)
886 {
887 }
888
889 TestInstance* ConstantDerivateCase::createInstance (Context& context) const
890 {
891         DE_ASSERT(m_uniformSetup != DE_NULL);
892         return new ConstantDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values);
893 }
894
895 void ConstantDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
896 {
897         const char* fragmentTmpl =
898                 "#version 450\n"
899                 "layout(location = 0) out mediump vec4 o_color;\n"
900                 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
901                 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; }; \n"
902                 "void main (void)\n"
903                 "{\n"
904                 "       ${PRECISION} ${DATATYPE} res = ${FUNC}(${VALUE}) * u_scale + u_bias;\n"
905                 "       o_color = ${CAST_TO_OUTPUT};\n"
906                 "}\n";
907
908         map<string, string> fragmentParams;
909         fragmentParams["PRECISION"]                     = glu::getPrecisionName(m_definitions.precision);
910         fragmentParams["DATATYPE"]                      = glu::getDataTypeName(m_definitions.dataType);
911         fragmentParams["FUNC"]                          = getDerivateFuncName(m_definitions.func);
912         fragmentParams["VALUE"]                         = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "vec4(1.0, 7.2, -1e5, 0.0)" :
913                                                                                   m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec3(1e2, 8.0, 0.01)" :
914                                                                                   m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec2(-0.0, 2.7)" :
915                                                                                   /* TYPE_FLOAT */                                                                 "7.7";
916         fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
917                                                                                   m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
918                                                                                   m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
919                                                                                   /* TYPE_FLOAT */                                                                 "vec4(res, 0.0, 0.0, 1.0)";
920
921         std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
922         programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
923         programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
924
925         m_values.derivScale             = tcu::Vec4(1e3f, 1e3f, 1e3f, 1e3f);
926         m_values.derivBias              = tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f);
927 }
928
929 // Linear cases
930
931 class LinearDerivateUniformSetup : public DerivateUniformSetup
932 {
933 public:
934                                         LinearDerivateUniformSetup              (bool useSampler, BaseUniformType usedDefaultUniform);
935         virtual                 ~LinearDerivateUniformSetup             (void);
936
937         virtual void    setup                                                   (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
938
939 private:
940         const BaseUniformType   m_usedDefaultUniform;
941 };
942
943 LinearDerivateUniformSetup::LinearDerivateUniformSetup (bool useSampler, BaseUniformType usedDefaultUniform)
944         : DerivateUniformSetup  (useSampler)
945         , m_usedDefaultUniform  (usedDefaultUniform)
946 {
947 }
948
949 LinearDerivateUniformSetup::~LinearDerivateUniformSetup (void)
950 {
951 }
952
953 void LinearDerivateUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const
954 {
955         DerivateUniformSetup::setup(instance, constCoords);
956
957         if (m_usedDefaultUniform != U_LAST)
958                 switch (m_usedDefaultUniform)
959                 {
960                         case UB_TRUE:
961                         case UI_ONE:
962                         case UI_TWO:
963                                 instance.useUniform(2u, m_usedDefaultUniform);
964                                 break;
965                         default:
966                                 DE_ASSERT(false);
967                                 break;
968                 }
969 }
970
971 class LinearDerivateCaseInstance : public TriangleDerivateCaseInstance
972 {
973 public:
974                                                                 LinearDerivateCaseInstance      (Context&                                               context,
975                                                                                                                          const UniformSetup&                    uniformSetup,
976                                                                                                                          const DerivateCaseDefinition&  definitions,
977                                                                                                                          const DerivateCaseValues&              values);
978         virtual                                         ~LinearDerivateCaseInstance     (void);
979
980         virtual bool                            verify                                          (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
981 };
982
983 LinearDerivateCaseInstance::LinearDerivateCaseInstance (Context&                                                context,
984                                                                                                                 const UniformSetup&                             uniformSetup,
985                                                                                                                 const DerivateCaseDefinition&   definitions,
986                                                                                                                 const DerivateCaseValues&               values)
987         : TriangleDerivateCaseInstance  (context, uniformSetup, definitions, values)
988 {
989 }
990
991 LinearDerivateCaseInstance::~LinearDerivateCaseInstance (void)
992 {
993 }
994
995 bool LinearDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
996 {
997         const tcu::Vec4         xScale                          = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
998         const tcu::Vec4         yScale                          = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
999         const tcu::Vec4         surfaceThreshold        = getSurfaceThreshold() / abs(m_values.derivScale);
1000
1001         if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
1002         {
1003                 const bool                      isX                     = isDfdxFunc(m_definitions.func);
1004                 const float                     div                     = isX ? float(result.getWidth()) : float(result.getHeight());
1005                 const tcu::Vec4         scale           = isX ? xScale : yScale;
1006                 tcu::Vec4                       reference       = ((m_values.coordMax - m_values.coordMin) / div);
1007                 const tcu::Vec4         opThreshold     = getDerivateThreshold(m_definitions.precision, m_values.coordMin, m_values.coordMax, reference);
1008                 const tcu::Vec4         threshold       = max(surfaceThreshold, opThreshold);
1009                 const int                       numComps        = glu::getDataTypeFloatScalars(m_definitions.dataType);
1010
1011                 /* adjust the reference value for the correct dfdx or dfdy sample adjacency */
1012                 reference = reference * scale;
1013
1014                 m_context.getTestContext().getLog()
1015                         << tcu::TestLog::Message
1016                         << "Verifying result image.\n"
1017                         << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
1018                         << tcu::TestLog::EndMessage;
1019
1020                 // short circuit if result is strictly within the normal value error bounds.
1021                 // This improves performance significantly.
1022                 if (verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
1023                                                                    reference, threshold, m_values.derivScale, m_values.derivBias,
1024                                                                    LOG_NOTHING))
1025                 {
1026                         m_context.getTestContext().getLog()
1027                                 << tcu::TestLog::Message
1028                                 << "No incorrect derivatives found, result valid."
1029                                 << tcu::TestLog::EndMessage;
1030
1031                         return true;
1032                 }
1033
1034                 // some pixels exceed error bounds calculated for normal values. Verify that these
1035                 // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1036
1037                 m_context.getTestContext().getLog()
1038                         << tcu::TestLog::Message
1039                         << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
1040                         << "\tVerifying each result derivative is within its range of legal result values."
1041                         << tcu::TestLog::EndMessage;
1042
1043                 {
1044                         const tcu::UVec2                        viewportSize    (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1045                         const float                                     w                               = float(viewportSize.x());
1046                         const float                                     h                               = float(viewportSize.y());
1047                         const tcu::Vec4                         valueRamp               = (m_values.coordMax - m_values.coordMin);
1048                         Linear2DFunctionEvaluator       function;
1049
1050                         function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_values.coordMin.x()));
1051                         function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_values.coordMin.y()));
1052                         function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_values.coordMin.z() + m_values.coordMin.z()) / 2.0f);
1053                         function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_values.coordMax.w() + m_values.coordMax.w()) / 2.0f);
1054
1055                         return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), result, errorMask,
1056                                                                                                                                 m_definitions.dataType, m_definitions.precision, m_values.derivScale,
1057                                                                                                                                 m_values.derivBias, surfaceThreshold, m_definitions.func,
1058                                                                                                                                 function);
1059                 }
1060         }
1061         else
1062         {
1063                 DE_ASSERT(isFwidthFunc(m_definitions.func));
1064                 const float                     w                       = float(result.getWidth());
1065                 const float                     h                       = float(result.getHeight());
1066
1067                 const tcu::Vec4         dx                      = ((m_values.coordMax - m_values.coordMin) / w) * xScale;
1068                 const tcu::Vec4         dy                      = ((m_values.coordMax - m_values.coordMin) / h) * yScale;
1069                 const tcu::Vec4         reference       = tcu::abs(dx) + tcu::abs(dy);
1070                 const tcu::Vec4         dxThreshold     = getDerivateThreshold(m_definitions.precision, m_values.coordMin*xScale, m_values.coordMax*xScale, dx);
1071                 const tcu::Vec4         dyThreshold     = getDerivateThreshold(m_definitions.precision, m_values.coordMin*yScale, m_values.coordMax*yScale, dy);
1072                 const tcu::Vec4         threshold       = max(surfaceThreshold, max(dxThreshold, dyThreshold));
1073
1074                 return verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
1075                                                                           reference, threshold, m_values.derivScale, m_values.derivBias);
1076         }
1077 }
1078
1079 // LinearDerivateCase
1080
1081 class LinearDerivateCase : public TriangleDerivateCase
1082 {
1083 public:
1084                                                         LinearDerivateCase                      (tcu::TestContext&              testCtx,
1085                                                                                                                  const std::string&             name,
1086                                                                                                                  const std::string&             description,
1087                                                                                                                  DerivateFunc                   func,
1088                                                                                                                  glu::DataType                  type,
1089                                                                                                                  glu::Precision                 precision,
1090                                                                                                                  bool                                   inNonUniformControlFlow,
1091                                                                                                                  SurfaceType                    surfaceType,
1092                                                                                                                  int                                    numSamples,
1093                                                                                                                  const std::string&             fragmentSrcTmpl,
1094                                                                                                                  BaseUniformType                usedDefaultUniform);
1095         virtual                                 ~LinearDerivateCase                     (void);
1096
1097         virtual void                    initPrograms                            (vk::SourceCollections& programCollection) const;
1098         virtual TestInstance*   createInstance                          (Context& context) const;
1099
1100 private:
1101         const std::string               m_fragmentTmpl;
1102 };
1103
1104 LinearDerivateCase::LinearDerivateCase (tcu::TestContext&               testCtx,
1105                                                                                 const std::string&              name,
1106                                                                                 const std::string&              description,
1107                                                                                 DerivateFunc                    func,
1108                                                                                 glu::DataType                   type,
1109                                                                                 glu::Precision                  precision,
1110                                                                                 bool                                    inNonUniformControlFlow,
1111                                                                                 SurfaceType                             surfaceType,
1112                                                                                 int                                             numSamples,
1113                                                                                 const std::string&              fragmentSrcTmpl,
1114                                                                                 BaseUniformType                 usedDefaultUniform)
1115         : TriangleDerivateCase  (testCtx, name, description, new LinearDerivateUniformSetup(false, usedDefaultUniform))
1116         , m_fragmentTmpl                (fragmentSrcTmpl)
1117 {
1118         m_definitions.func                                              = func;
1119         m_definitions.dataType                                  = type;
1120         m_definitions.precision                                 = precision;
1121         m_definitions.inNonUniformControlFlow   = inNonUniformControlFlow;
1122         m_definitions.coordDataType                             = m_definitions.dataType;
1123         m_definitions.coordPrecision                    = m_definitions.precision;
1124         m_definitions.surfaceType                               = surfaceType;
1125         m_definitions.numSamples                                = numSamples;
1126 }
1127
1128 LinearDerivateCase::~LinearDerivateCase (void)
1129 {
1130 }
1131
1132 TestInstance* LinearDerivateCase::createInstance (Context& context) const
1133 {
1134         DE_ASSERT(m_uniformSetup != DE_NULL);
1135         return new LinearDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values);
1136 }
1137
1138 void LinearDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
1139 {
1140         const SpirvVersion                              spirvVersion = m_definitions.inNonUniformControlFlow ? vk::SPIRV_VERSION_1_3 : vk::SPIRV_VERSION_1_0;
1141         const vk::ShaderBuildOptions    buildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u);
1142
1143         const tcu::UVec2        viewportSize    (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1144         const float                     w                               = float(viewportSize.x());
1145         const float                     h                               = float(viewportSize.y());
1146         const bool                      packToInt               = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
1147         map<string, string>     fragmentParams;
1148
1149         fragmentParams["OUTPUT_TYPE"]           = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
1150         fragmentParams["OUTPUT_PREC"]           = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
1151         fragmentParams["PRECISION"]                     = glu::getPrecisionName(m_definitions.precision);
1152         fragmentParams["DATATYPE"]                      = glu::getDataTypeName(m_definitions.dataType);
1153         fragmentParams["FUNC"]                          = getDerivateFuncName(m_definitions.func);
1154
1155         if (packToInt)
1156         {
1157                 fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
1158                                                                                           m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
1159                                                                                           m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
1160                                                                                           /* TYPE_FLOAT */                                                                 "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
1161         }
1162         else
1163         {
1164                 fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
1165                                                                                           m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
1166                                                                                           m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
1167                                                                                           /* TYPE_FLOAT */                                                                 "vec4(res, 0.0, 0.0, 1.0)";
1168         }
1169
1170         std::string fragmentSrc = tcu::StringTemplate(m_fragmentTmpl).specialize(fragmentParams);
1171         programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
1172         programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc) << buildOptions;
1173
1174         switch (m_definitions.precision)
1175         {
1176                 case glu::PRECISION_HIGHP:
1177                         m_values.coordMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
1178                         m_values.coordMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
1179                         break;
1180
1181                 case glu::PRECISION_MEDIUMP:
1182                         m_values.coordMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
1183                         m_values.coordMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
1184                         break;
1185
1186                 case glu::PRECISION_LOWP:
1187                         m_values.coordMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
1188                         m_values.coordMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
1189                         break;
1190
1191                 default:
1192                         DE_ASSERT(false);
1193         }
1194
1195         if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
1196         {
1197                 // No scale or bias used for accuracy.
1198                 m_values.derivScale     = tcu::Vec4(1.0f);
1199                 m_values.derivBias              = tcu::Vec4(0.0f);
1200         }
1201         else
1202         {
1203                 // Compute scale - bias that normalizes to 0..1 range.
1204                 const tcu::Vec4 dx = (m_values.coordMax - m_values.coordMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
1205                 const tcu::Vec4 dy = (m_values.coordMax - m_values.coordMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
1206
1207                 if (isDfdxFunc(m_definitions.func))
1208                         m_values.derivScale = 0.5f / dx;
1209                 else if (isDfdyFunc(m_definitions.func))
1210                         m_values.derivScale = 0.5f / dy;
1211                 else if (isFwidthFunc(m_definitions.func))
1212                         m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
1213                 else
1214                         DE_ASSERT(false);
1215
1216                 m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1217         }
1218 }
1219
1220 // TextureDerivateCaseInstance
1221
1222 class TextureDerivateCaseInstance : public TriangleDerivateCaseInstance
1223 {
1224 public:
1225                                                                 TextureDerivateCaseInstance             (Context&                                                       context,
1226                                                                                                                                  const UniformSetup&                            uniformSetup,
1227                                                                                                                                  const DerivateCaseDefinition&          definitions,
1228                                                                                                                                  const DerivateCaseValues&                      values,
1229                                                                                                                                  const TextureCaseValues&                       textureValues);
1230         virtual                                         ~TextureDerivateCaseInstance    (void);
1231
1232         virtual bool                            verify                                                  (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
1233
1234 private:
1235         const TextureCaseValues&        m_textureValues;
1236 };
1237
1238 TextureDerivateCaseInstance::TextureDerivateCaseInstance (Context&                                                      context,
1239                                                                                                                   const UniformSetup&                           uniformSetup,
1240                                                                                                                   const DerivateCaseDefinition&         definitions,
1241                                                                                                                   const DerivateCaseValues&                     values,
1242                                                                                                                   const TextureCaseValues&                      textureValues)
1243         : TriangleDerivateCaseInstance  (context, uniformSetup, definitions, values)
1244         , m_textureValues                               (textureValues)
1245 {
1246         de::MovePtr<tcu::Texture2D>             texture;
1247
1248         // Lowp and mediump cases use RGBA16F format, while highp uses RGBA32F.
1249         {
1250                 const tcu::UVec2                        viewportSize    (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1251                 const tcu::TextureFormat        format                  = glu::mapGLInternalFormat(m_definitions.precision == glu::PRECISION_HIGHP ? GL_RGBA32F : GL_RGBA16F);
1252
1253                 texture = de::MovePtr<tcu::Texture2D>(new tcu::Texture2D(format, viewportSize.x(), viewportSize.y()));
1254                 texture->allocLevel(0);
1255         }
1256
1257         // Fill with gradients.
1258         {
1259                 const tcu::PixelBufferAccess level0 = texture->getLevel(0);
1260                 for (int y = 0; y < level0.getHeight(); y++)
1261                 {
1262                         for (int x = 0; x < level0.getWidth(); x++)
1263                         {
1264                                 const float             xf              = (float(x)+0.5f) / float(level0.getWidth());
1265                                 const float             yf              = (float(y)+0.5f) / float(level0.getHeight());
1266                                 const tcu::Vec4 s               = tcu::Vec4(xf, yf, (xf+yf)/2.0f, 1.0f - (xf+yf)/2.0f);
1267
1268                                 level0.setPixel(m_textureValues.texValueMin + (m_textureValues.texValueMax - m_textureValues.texValueMin)*s, x, y);
1269                         }
1270                 }
1271         }
1272
1273         de::SharedPtr<TextureBinding>   testTexture             (new TextureBinding(texture.release(),
1274                                                                                                                                                 tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE,
1275                                                                                                                                                                          tcu::Sampler::CLAMP_TO_EDGE,
1276                                                                                                                                                                          tcu::Sampler::CLAMP_TO_EDGE,
1277                                                                                                                                                                          tcu::Sampler::NEAREST,
1278                                                                                                                                                                          tcu::Sampler::NEAREST,
1279                                                                                                                                                                          0.0f,
1280                                                                                                                                                                          true,
1281                                                                                                                                                                          tcu::Sampler::COMPAREMODE_NONE,
1282                                                                                                                                                                          0,
1283                                                                                                                                                                          tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
1284                                                                                                                                                                          true)));
1285         m_textures.push_back(testTexture);
1286 }
1287
1288 TextureDerivateCaseInstance::~TextureDerivateCaseInstance (void)
1289 {
1290 }
1291
1292 bool TextureDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
1293 {
1294         // \note Edges are ignored in comparison
1295         if (result.getWidth() < 2 || result.getHeight() < 2)
1296                 throw tcu::NotSupportedError("Too small viewport");
1297
1298         tcu::ConstPixelBufferAccess     compareArea                     = tcu::getSubregion(result, 1, 1, result.getWidth()-2, result.getHeight()-2);
1299         tcu::PixelBufferAccess          maskArea                        = tcu::getSubregion(errorMask, 1, 1, errorMask.getWidth()-2, errorMask.getHeight()-2);
1300         const tcu::Vec4                         xScale                          = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
1301         const tcu::Vec4                         yScale                          = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
1302         const float                                     w                                       = float(result.getWidth());
1303         const float                                     h                                       = float(result.getHeight());
1304
1305         const tcu::Vec4                         surfaceThreshold        = getSurfaceThreshold() / abs(m_values.derivScale);
1306
1307         if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
1308         {
1309                 const bool                      isX                     = isDfdxFunc(m_definitions.func);
1310                 const float                     div                     = isX ? w : h;
1311                 const tcu::Vec4         scale           = isX ? xScale : yScale;
1312                 tcu::Vec4                       reference       = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / div);
1313                 const tcu::Vec4         opThreshold     = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin, m_textureValues.texValueMax, reference);
1314                 const tcu::Vec4         threshold       = max(surfaceThreshold, opThreshold);
1315                 const int                       numComps        = glu::getDataTypeFloatScalars(m_definitions.dataType);
1316
1317                 /* adjust the reference value for the correct dfdx or dfdy sample adjacency */
1318                 reference = reference * scale;
1319
1320                 m_context.getTestContext().getLog()
1321                         << tcu::TestLog::Message
1322                         << "Verifying result image.\n"
1323                         << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
1324                         << tcu::TestLog::EndMessage;
1325
1326                 // short circuit if result is strictly within the normal value error bounds.
1327                 // This improves performance significantly.
1328                 if (verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
1329                                                                    reference, threshold, m_values.derivScale, m_values.derivBias,
1330                                                                    LOG_NOTHING))
1331                 {
1332                         m_context.getTestContext().getLog()
1333                                 << tcu::TestLog::Message
1334                                 << "No incorrect derivatives found, result valid."
1335                                 << tcu::TestLog::EndMessage;
1336
1337                         return true;
1338                 }
1339
1340                 // some pixels exceed error bounds calculated for normal values. Verify that these
1341                 // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1342
1343                 m_context.getTestContext().getLog()
1344                         << tcu::TestLog::Message
1345                         << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
1346                         << "\tVerifying each result derivative is within its range of legal result values."
1347                         << tcu::TestLog::EndMessage;
1348
1349                 {
1350                         const tcu::Vec4                         valueRamp               = (m_textureValues.texValueMax - m_textureValues.texValueMin);
1351                         Linear2DFunctionEvaluator       function;
1352
1353                         function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_textureValues.texValueMin.x()));
1354                         function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_textureValues.texValueMin.y()));
1355                         function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_textureValues.texValueMin.z() + m_textureValues.texValueMin.z()) / 2.0f);
1356                         function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_textureValues.texValueMax.w() + m_textureValues.texValueMax.w()) / 2.0f);
1357
1358                         return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), compareArea, maskArea,
1359                                                                                                                                 m_definitions.dataType, m_definitions.precision, m_values.derivScale,
1360                                                                                                                                 m_values.derivBias, surfaceThreshold, m_definitions.func,
1361                                                                                                                                 function);
1362                 }
1363         }
1364         else
1365         {
1366                 DE_ASSERT(isFwidthFunc(m_definitions.func));
1367                 const tcu::Vec4 dx                      = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / w) * xScale;
1368                 const tcu::Vec4 dy                      = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / h) * yScale;
1369                 const tcu::Vec4 reference       = tcu::abs(dx) + tcu::abs(dy);
1370                 const tcu::Vec4 dxThreshold     = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*xScale, m_textureValues.texValueMax*xScale, dx);
1371                 const tcu::Vec4 dyThreshold     = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*yScale, m_textureValues.texValueMax*yScale, dy);
1372                 const tcu::Vec4 threshold       = max(surfaceThreshold, max(dxThreshold, dyThreshold));
1373
1374                 return verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
1375                                                                           reference, threshold, m_values.derivScale, m_values.derivBias);
1376         }
1377 }
1378
1379 // TextureDerivateCase
1380
1381 class TextureDerivateCase : public TriangleDerivateCase
1382 {
1383 public:
1384                                                         TextureDerivateCase                     (tcu::TestContext&              testCtx,
1385                                                                                                                  const std::string&             name,
1386                                                                                                                  const std::string&             description,
1387                                                                                                                  DerivateFunc                   func,
1388                                                                                                                  glu::DataType                  type,
1389                                                                                                                  glu::Precision                 precision,
1390                                                                                                                  SurfaceType                    surfaceType,
1391                                                                                                                  int                                    numSamples);
1392         virtual                                 ~TextureDerivateCase            (void);
1393
1394         virtual void                    initPrograms                            (vk::SourceCollections& programCollection) const;
1395         virtual TestInstance*   createInstance                          (Context& context) const;
1396
1397 private:
1398         mutable TextureCaseValues       m_textureValues;
1399 };
1400
1401 TextureDerivateCase::TextureDerivateCase (tcu::TestContext&             testCtx,
1402                                                                                   const std::string&    name,
1403                                                                                   const std::string&    description,
1404                                                                                   DerivateFunc                  func,
1405                                                                                   glu::DataType                 type,
1406                                                                                   glu::Precision                precision,
1407                                                                                   SurfaceType                   surfaceType,
1408                                                                                   int                                   numSamples)
1409         : TriangleDerivateCase  (testCtx, name, description, new DerivateUniformSetup(true))
1410 {
1411         m_definitions.dataType                  = type;
1412         m_definitions.func                              = func;
1413         m_definitions.precision                 = precision;
1414         m_definitions.coordDataType             = glu::TYPE_FLOAT_VEC2;
1415         m_definitions.coordPrecision    = glu::PRECISION_HIGHP;
1416         m_definitions.surfaceType               = surfaceType;
1417         m_definitions.numSamples                = numSamples;
1418 }
1419
1420 TextureDerivateCase::~TextureDerivateCase (void)
1421 {
1422 }
1423
1424 TestInstance* TextureDerivateCase::createInstance (Context& context) const
1425 {
1426         DE_ASSERT(m_uniformSetup != DE_NULL);
1427         return new TextureDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values, m_textureValues);
1428 }
1429
1430 void TextureDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
1431 {
1432         // Generate shader
1433         {
1434                 const char* fragmentTmpl =
1435                         "#version 450\n"
1436                         "layout(location = 0) in highp vec2 v_coord;\n"
1437                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1438                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1439                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1440                         "layout(binding = 2) uniform ${PRECISION} sampler2D u_sampler;\n"
1441                         "void main (void)\n"
1442                         "{\n"
1443                         "       ${PRECISION} vec4 tex = texture(u_sampler, v_coord);\n"
1444                         "       ${PRECISION} ${DATATYPE} res = ${FUNC}(tex${SWIZZLE}) * u_scale + u_bias;\n"
1445                         "       o_color = ${CAST_TO_OUTPUT};\n"
1446                         "}\n";
1447
1448                 const bool                      packToInt               = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
1449                 map<string, string> fragmentParams;
1450
1451                 fragmentParams["OUTPUT_TYPE"]           = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
1452                 fragmentParams["OUTPUT_PREC"]           = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
1453                 fragmentParams["PRECISION"]                     = glu::getPrecisionName(m_definitions.precision);
1454                 fragmentParams["DATATYPE"]                      = glu::getDataTypeName(m_definitions.dataType);
1455                 fragmentParams["FUNC"]                          = getDerivateFuncName(m_definitions.func);
1456                 fragmentParams["SWIZZLE"]                       = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "" :
1457                                                                                           m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? ".xyz" :
1458                                                                                           m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? ".xy" :
1459                                                                                           /* TYPE_FLOAT */                                                                 ".x";
1460
1461                 if (packToInt)
1462                 {
1463                         fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
1464                                                                                                   m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
1465                                                                                                   m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
1466                                                                                                   /* TYPE_FLOAT */                                                                 "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
1467                 }
1468                 else
1469                 {
1470                         fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
1471                                                                                                   m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
1472                                                                                                   m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
1473                                                                                                   /* TYPE_FLOAT */                                                                 "vec4(res, 0.0, 0.0, 1.0)";
1474                 }
1475
1476                 std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
1477                 programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
1478                 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
1479         }
1480
1481         // Texture size matches viewport and nearest sampling is used. Thus texture sampling
1482         // is equal to just interpolating the texture value range.
1483
1484         // Determine value range for texture.
1485
1486         switch (m_definitions.precision)
1487         {
1488                 case glu::PRECISION_HIGHP:
1489                         m_textureValues.texValueMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
1490                         m_textureValues.texValueMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
1491                         break;
1492
1493                 case glu::PRECISION_MEDIUMP:
1494                         m_textureValues.texValueMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
1495                         m_textureValues.texValueMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
1496                         break;
1497
1498                 case glu::PRECISION_LOWP:
1499                         m_textureValues.texValueMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
1500                         m_textureValues.texValueMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
1501                         break;
1502
1503                 default:
1504                         DE_ASSERT(false);
1505         }
1506
1507         // Texture coordinates
1508         m_values.coordMin = tcu::Vec4(0.0f);
1509         m_values.coordMax = tcu::Vec4(1.0f);
1510
1511         if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
1512         {
1513                 // No scale or bias used for accuracy.
1514                 m_values.derivScale             = tcu::Vec4(1.0f);
1515                 m_values.derivBias              = tcu::Vec4(0.0f);
1516         }
1517         else
1518         {
1519                 // Compute scale - bias that normalizes to 0..1 range.
1520                 const tcu::UVec2        viewportSize    (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1521                 const float                     w                               = float(viewportSize.x());
1522                 const float                     h                               = float(viewportSize.y());
1523                 const tcu::Vec4         dx                              = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
1524                 const tcu::Vec4         dy                              = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
1525
1526                 if (isDfdxFunc(m_definitions.func))
1527                         m_values.derivScale = 0.5f / dx;
1528                 else if (isDfdyFunc(m_definitions.func))
1529                         m_values.derivScale = 0.5f / dy;
1530                 else if (isFwidthFunc(m_definitions.func))
1531                         m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
1532                 else
1533                         DE_ASSERT(false);
1534
1535                 m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1536         }
1537 }
1538
1539 // ShaderDerivateTests
1540
1541 class ShaderDerivateTests : public tcu::TestCaseGroup
1542 {
1543 public:
1544                                                         ShaderDerivateTests             (tcu::TestContext& testCtx);
1545         virtual                                 ~ShaderDerivateTests    (void);
1546
1547         virtual void                    init                                    (void);
1548
1549 private:
1550                                                         ShaderDerivateTests             (const ShaderDerivateTests&);           // not allowed!
1551         ShaderDerivateTests&    operator=                               (const ShaderDerivateTests&);           // not allowed!
1552 };
1553
1554 ShaderDerivateTests::ShaderDerivateTests (tcu::TestContext& testCtx)
1555         : TestCaseGroup(testCtx, "derivate", "Derivate Function Tests")
1556 {
1557 }
1558
1559 ShaderDerivateTests::~ShaderDerivateTests (void)
1560 {
1561 }
1562
1563 struct FunctionSpec
1564 {
1565         std::string             name;
1566         DerivateFunc    function;
1567         glu::DataType   dataType;
1568         glu::Precision  precision;
1569
1570         FunctionSpec (const std::string& name_, DerivateFunc function_, glu::DataType dataType_, glu::Precision precision_)
1571                 : name          (name_)
1572                 , function      (function_)
1573                 , dataType      (dataType_)
1574                 , precision     (precision_)
1575         {
1576         }
1577 };
1578
1579 void ShaderDerivateTests::init (void)
1580 {
1581         static const struct
1582         {
1583                 const char*                     name;
1584                 const char*                     description;
1585                 const char*                     source;
1586                 BaseUniformType         usedDefaultUniform;
1587                 bool                            inNonUniformControlFlow;
1588         } s_linearDerivateCases[] =
1589         {
1590                 {
1591                         "linear",
1592                         "Basic derivate of linearly interpolated argument",
1593
1594                         "#version 450\n"
1595                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1596                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1597                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1598                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1599                         "void main (void)\n"
1600                         "{\n"
1601                         "       ${PRECISION} ${DATATYPE} res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1602                         "       o_color = ${CAST_TO_OUTPUT};\n"
1603                         "}\n",
1604
1605                         U_LAST,
1606                         false
1607                 },
1608                 {
1609                         "in_function",
1610                         "Derivate of linear function argument",
1611
1612                         "#version 450\n"
1613                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1614                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1615                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1616                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1617                         "\n"
1618                         "${PRECISION} ${DATATYPE} computeRes (${PRECISION} ${DATATYPE} value)\n"
1619                         "{\n"
1620                         "       return ${FUNC}(v_coord) * u_scale + u_bias;\n"
1621                         "}\n"
1622                         "\n"
1623                         "void main (void)\n"
1624                         "{\n"
1625                         "       ${PRECISION} ${DATATYPE} res = computeRes(v_coord);\n"
1626                         "       o_color = ${CAST_TO_OUTPUT};\n"
1627                         "}\n",
1628
1629                         U_LAST,
1630                         false
1631                 },
1632                 {
1633                         "static_if",
1634                         "Derivate of linearly interpolated value in static if",
1635
1636                         "#version 450\n"
1637                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1638                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1639                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1640                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1641                         "void main (void)\n"
1642                         "{\n"
1643                         "       ${PRECISION} ${DATATYPE} res;\n"
1644                         "       if (false)\n"
1645                         "               res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
1646                         "       else\n"
1647                         "               res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1648                         "       o_color = ${CAST_TO_OUTPUT};\n"
1649                         "}\n",
1650
1651                         U_LAST,
1652                         false
1653                 },
1654                 {
1655                         "static_loop",
1656                         "Derivate of linearly interpolated value in static loop",
1657
1658                         "#version 450\n"
1659                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1660                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1661                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1662                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1663                         "void main (void)\n"
1664                         "{\n"
1665                         "       ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1666                         "       for (int i = 0; i < 2; i++)\n"
1667                         "               res += ${FUNC}(v_coord * float(i));\n"
1668                         "       res = res * u_scale + u_bias;\n"
1669                         "       o_color = ${CAST_TO_OUTPUT};\n"
1670                         "}\n",
1671
1672                         U_LAST,
1673                         false
1674                 },
1675                 {
1676                         "static_switch",
1677                         "Derivate of linearly interpolated value in static switch",
1678
1679                         "#version 450\n"
1680                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1681                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1682                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1683                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1684                         "void main (void)\n"
1685                         "{\n"
1686                         "       ${PRECISION} ${DATATYPE} res;\n"
1687                         "       switch (1)\n"
1688                         "       {\n"
1689                         "               case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias;     break;\n"
1690                         "               case 1: res = ${FUNC}(v_coord) * u_scale + u_bias;      break;\n"
1691                         "       }\n"
1692                         "       o_color = ${CAST_TO_OUTPUT};\n"
1693                         "}\n",
1694
1695                         U_LAST,
1696                         false
1697                 },
1698                 {
1699                         "uniform_if",
1700                         "Derivate of linearly interpolated value in uniform if",
1701
1702                         "#version 450\n"
1703                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1704                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1705                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1706                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1707                         "layout(binding = 2, std140) uniform Ui_true { bool ub_true; };\n"
1708                         "void main (void)\n"
1709                         "{\n"
1710                         "       ${PRECISION} ${DATATYPE} res;\n"
1711                         "       if (ub_true)"
1712                         "               res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1713                         "       else\n"
1714                         "               res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
1715                         "       o_color = ${CAST_TO_OUTPUT};\n"
1716                         "}\n",
1717
1718                         UB_TRUE,
1719                         false
1720                 },
1721                 {
1722                         "uniform_loop",
1723                         "Derivate of linearly interpolated value in uniform loop",
1724
1725                         "#version 450\n"
1726                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1727                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1728                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1729                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1730                         "layout(binding = 2, std140) uniform Ui_two { int ui_two; };\n"
1731                         "void main (void)\n"
1732                         "{\n"
1733                         "       ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1734                         "       for (int i = 0; i < ui_two; i++)\n"
1735                         "               res += ${FUNC}(v_coord * float(i));\n"
1736                         "       res = res * u_scale + u_bias;\n"
1737                         "       o_color = ${CAST_TO_OUTPUT};\n"
1738                         "}\n",
1739
1740                         UI_TWO,
1741                         false
1742                 },
1743                 {
1744                         "uniform_switch",
1745                         "Derivate of linearly interpolated value in uniform switch",
1746
1747                         "#version 450\n"
1748                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1749                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1750                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1751                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1752                         "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1753                         "void main (void)\n"
1754                         "{\n"
1755                         "       ${PRECISION} ${DATATYPE} res;\n"
1756                         "       switch (ui_one)\n"
1757                         "       {\n"
1758                         "               case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias;     break;\n"
1759                         "               case 1: res = ${FUNC}(v_coord) * u_scale + u_bias;      break;\n"
1760                         "       }\n"
1761                         "       o_color = ${CAST_TO_OUTPUT};\n"
1762                         "}\n",
1763
1764                         UI_ONE,
1765                         false
1766                 },
1767                 {
1768                         "dynamic_if",
1769                         "Derivate of linearly interpolated value in static if",
1770
1771                         "#version 450\n"
1772                         "#extension GL_KHR_shader_subgroup_ballot : require\n"
1773                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1774                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1775                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1776                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1777                         "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1778                         "void main (void)\n"
1779                         "{\n"
1780                         "       ${PRECISION} ${DATATYPE} res;\n"
1781                         "       bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1782                         "       uvec4 quad_ballot = uvec4(0);\n"
1783                         "       quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1784                         "       bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1785                         "       if (quad_uniform)\n"
1786                         "               res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1787                         "       else\n"
1788                         "               res = ${FUNC}(v_coord * float(ui_one)) * u_scale + u_bias;\n"
1789                         "       o_color = ${CAST_TO_OUTPUT};\n"
1790                         "}\n",
1791
1792                         UI_ONE,
1793                         true
1794                 },
1795                 {
1796                         "dynamic_loop",
1797                         "Derivate of linearly interpolated value in uniform loop",
1798
1799                         "#version 450\n"
1800                         "#extension GL_KHR_shader_subgroup_ballot : require\n"
1801                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1802                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1803                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1804                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1805                         "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1806                         "void main (void)\n"
1807                         "{\n"
1808                         "       ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1809                         "       bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1810                         "       uvec4 quad_ballot = uvec4(0);\n"
1811                         "       quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1812                         "       bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1813                         "       for (int i = 0; i < ui_one + int(quad_uniform); i++)\n"
1814                         "               res = ${FUNC}(v_coord * float(i - int(quad_uniform) + 1));\n"
1815                         "       res = res * u_scale + u_bias;\n"
1816                         "       o_color = ${CAST_TO_OUTPUT};\n"
1817                         "}\n",
1818
1819                         UI_ONE,
1820                         true
1821                 },
1822                 {
1823                         "dynamic_switch",
1824                         "Derivate of linearly interpolated value in uniform switch",
1825
1826                         "#version 450\n"
1827                         "#extension GL_KHR_shader_subgroup_ballot : require\n"
1828                         "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1829                         "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1830                         "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1831                         "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1832                         "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1833                         "void main (void)\n"
1834                         "{\n"
1835                         "       ${PRECISION} ${DATATYPE} res;\n"
1836                         "       bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1837                         "       uvec4 quad_ballot = uvec4(0);\n"
1838                         "       quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1839                         "       bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1840                         "       switch (int(quad_uniform))\n"
1841                         "       {\n"
1842                         "               case 0: res = ${FUNC}(v_coord) * u_scale + u_bias;      break;\n"
1843                         "               case 1: res = ${FUNC}(v_coord * float(ui_one)) * u_scale + u_bias;      break;\n"
1844                         "       }\n"
1845                         "       o_color = ${CAST_TO_OUTPUT};\n"
1846                         "}\n",
1847
1848                         UI_ONE,
1849                         true
1850                 },
1851         };
1852
1853         static const struct
1854         {
1855                 const char*             name;
1856                 SurfaceType             surfaceType;
1857                 int                             numSamples;
1858         } s_fboConfigs[] =
1859         {
1860                 { "fbo",                        SURFACETYPE_UNORM_FBO,          0 },
1861                 { "fbo_msaa2",          SURFACETYPE_UNORM_FBO,          2 },
1862                 { "fbo_msaa4",          SURFACETYPE_UNORM_FBO,          4 },
1863                 { "fbo_float",          SURFACETYPE_FLOAT_FBO,          0 },
1864         };
1865
1866         static const struct
1867         {
1868                 const char*             name;
1869                 SurfaceType             surfaceType;
1870                 int                             numSamples;
1871         } s_textureConfigs[] =
1872         {
1873                 { "basic",                      SURFACETYPE_UNORM_FBO,          0 },
1874                 { "msaa4",                      SURFACETYPE_UNORM_FBO,          4 },
1875                 { "float",                      SURFACETYPE_FLOAT_FBO,          0 },
1876         };
1877
1878         // .dfdx[fine|coarse], .dfdy[fine|coarse], .fwidth[fine|coarse]
1879         for (int funcNdx = 0; funcNdx < DERIVATE_LAST; funcNdx++)
1880         {
1881                 const DerivateFunc                                      function                = DerivateFunc(funcNdx);
1882                 de::MovePtr<tcu::TestCaseGroup>         functionGroup   (new tcu::TestCaseGroup(m_testCtx, getDerivateFuncCaseName(function), getDerivateFuncName(function)));
1883
1884                 // .constant - no precision variants, checks that derivate of constant arguments is 0
1885                 {
1886                         de::MovePtr<tcu::TestCaseGroup> constantGroup   (new tcu::TestCaseGroup(m_testCtx, "constant", "Derivate of constant argument"));
1887
1888                         for (int vecSize = 1; vecSize <= 4; vecSize++)
1889                         {
1890                                 const glu::DataType                     dataType                = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1891                                 constantGroup->addChild(new ConstantDerivateCase(m_testCtx, glu::getDataTypeName(dataType), "", function, dataType));
1892                         }
1893
1894                         functionGroup->addChild(constantGroup.release());
1895                 }
1896
1897                 // Cases based on LinearDerivateCase
1898                 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_linearDerivateCases); caseNdx++)
1899                 {
1900                         de::MovePtr<tcu::TestCaseGroup> linearCaseGroup (new tcu::TestCaseGroup(m_testCtx, s_linearDerivateCases[caseNdx].name, s_linearDerivateCases[caseNdx].description));
1901                         const char*                                             source                  = s_linearDerivateCases[caseNdx].source;
1902
1903                         for (int vecSize = 1; vecSize <= 4; vecSize++)
1904                         {
1905                                 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1906                                 {
1907                                         const glu::DataType             dataType                = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1908                                         const glu::Precision    precision               = glu::Precision(precNdx);
1909                                         const SurfaceType               surfaceType             = SURFACETYPE_UNORM_FBO;
1910                                         const int                               numSamples              = 0;
1911                                         std::ostringstream              caseName;
1912
1913                                         if (caseNdx != 0 && precision == glu::PRECISION_LOWP)
1914                                                 continue; // Skip as lowp doesn't actually produce any bits when rendered to default FB.
1915
1916                                         caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1917
1918                                         linearCaseGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, s_linearDerivateCases[caseNdx].inNonUniformControlFlow, surfaceType, numSamples, source, s_linearDerivateCases[caseNdx].usedDefaultUniform));
1919                                 }
1920                         }
1921
1922                         functionGroup->addChild(linearCaseGroup.release());
1923                 }
1924
1925                 // Fbo cases
1926                 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_fboConfigs); caseNdx++)
1927                 {
1928                         de::MovePtr<tcu::TestCaseGroup> fboGroup                (new tcu::TestCaseGroup(m_testCtx, s_fboConfigs[caseNdx].name, "Derivate usage when rendering into FBO"));
1929                         const char*                                             source                  = s_linearDerivateCases[0].source; // use source from .linear group
1930                         const SurfaceType                               surfaceType             = s_fboConfigs[caseNdx].surfaceType;
1931                         const int                                               numSamples              = s_fboConfigs[caseNdx].numSamples;
1932
1933                         for (int vecSize = 1; vecSize <= 4; vecSize++)
1934                         {
1935                                 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1936                                 {
1937                                         const glu::DataType             dataType                = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1938                                         const glu::Precision    precision               = glu::Precision(precNdx);
1939                                         std::ostringstream              caseName;
1940
1941                                         if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
1942                                                 continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1943
1944                                         caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1945
1946                                         fboGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, false, surfaceType, numSamples, source, U_LAST));
1947                                 }
1948                         }
1949
1950                         functionGroup->addChild(fboGroup.release());
1951                 }
1952
1953                 // .texture
1954                 {
1955                         de::MovePtr<tcu::TestCaseGroup>         textureGroup    (new tcu::TestCaseGroup(m_testCtx, "texture", "Derivate of texture lookup result"));
1956
1957                         for (int texCaseNdx = 0; texCaseNdx < DE_LENGTH_OF_ARRAY(s_textureConfigs); texCaseNdx++)
1958                         {
1959                                 de::MovePtr<tcu::TestCaseGroup> caseGroup               (new tcu::TestCaseGroup(m_testCtx, s_textureConfigs[texCaseNdx].name, ""));
1960                                 const SurfaceType                               surfaceType             = s_textureConfigs[texCaseNdx].surfaceType;
1961                                 const int                                               numSamples              = s_textureConfigs[texCaseNdx].numSamples;
1962
1963                                 for (int vecSize = 1; vecSize <= 4; vecSize++)
1964                                 {
1965                                         for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1966                                         {
1967                                                 const glu::DataType             dataType                = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1968                                                 const glu::Precision    precision               = glu::Precision(precNdx);
1969                                                 std::ostringstream              caseName;
1970
1971                                                 if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
1972                                                         continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1973
1974                                                 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1975
1976                                                 caseGroup->addChild(new TextureDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples));
1977                                         }
1978                                 }
1979
1980                                 textureGroup->addChild(caseGroup.release());
1981                         }
1982
1983                         functionGroup->addChild(textureGroup.release());
1984                 }
1985
1986                 addChild(functionGroup.release());
1987         }
1988 }
1989
1990 } // anonymous
1991
1992 tcu::TestCaseGroup* createDerivateTests (tcu::TestContext& testCtx)
1993 {
1994         return new ShaderDerivateTests(testCtx);
1995 }
1996
1997 } // sr
1998 } // vkt