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