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