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::__anon6be423a10111::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::__anon6be423a10111::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
705 setup();
706
707 render(numVertices, numTriangles, indices);
708
709 {
710 const tcu::TextureLevel& renderedImage = getResultImage();
711
712 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
713 {
714 const tcu::TextureFormat dataFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
715
716 resultImage.setStorage(dataFormat, renderedImage.getWidth(), renderedImage.getHeight());
717 tcu::copy(resultImage.getAccess(), tcu::ConstPixelBufferAccess(dataFormat, renderedImage.getSize(), renderedImage.getAccess().getDataPtr()));
718 }
719 else
720 {
721 resultImage = renderedImage;
722 }
723 }
724
725 // Verify
726 {
727 tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
728 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
729
730 const bool isOk = verify(resultImage.getAccess(), errorMask.getAccess());
731
732 log << TestLog::ImageSet("Result", "Result images")
733 << TestLog::Image("Rendered", "Rendered image", resultImage);
734
735 if (!isOk)
736 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
737
738 log << TestLog::EndImageSet;
739
740 if (isOk)
741 return tcu::TestStatus::pass("Pass");
742 else
743 return tcu::TestStatus::fail("Image comparison failed");
744 }
745 }
746
setup(ShaderRenderCaseInstance & instance,const tcu::Vec4 &) const747 void DerivateUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
748 {
749 DerivateCaseDefinition definitions = dynamic_cast<TriangleDerivateCaseInstance&>(instance).getDerivateCaseDefinition();
750 DerivateCaseValues values = dynamic_cast<TriangleDerivateCaseInstance&>(instance).getDerivateCaseValues();
751
752 DE_ASSERT(glu::isDataTypeFloatOrVec(definitions.dataType));
753
754 instance.addUniform(0u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, glu::getDataTypeScalarSize(definitions.dataType) * sizeof(float), values.derivScale.getPtr());
755 instance.addUniform(1u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, glu::getDataTypeScalarSize(definitions.dataType) * sizeof(float), values.derivBias.getPtr());
756
757 if (m_useSampler)
758 instance.useSampler(2u, 0u); // To the uniform binding location 2 bind the texture 0
759 }
760
761 // TriangleDerivateCase
762
763 class TriangleDerivateCase : public ShaderRenderCase
764 {
765 public:
766 TriangleDerivateCase (tcu::TestContext& testCtx,
767 const std::string& name,
768 const std::string& description,
769 const UniformSetup* uniformSetup);
770 virtual ~TriangleDerivateCase (void);
771
772 protected:
773 mutable DerivateCaseDefinition m_definitions;
774 mutable DerivateCaseValues m_values;
775 };
776
TriangleDerivateCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const UniformSetup * uniformSetup)777 TriangleDerivateCase::TriangleDerivateCase (tcu::TestContext& testCtx,
778 const std::string& name,
779 const std::string& description,
780 const UniformSetup* uniformSetup)
781 : ShaderRenderCase (testCtx, name, description, false, (ShaderEvaluator*)DE_NULL, uniformSetup, DE_NULL)
782 , m_definitions ()
783 {
784 }
785
~TriangleDerivateCase(void)786 TriangleDerivateCase::~TriangleDerivateCase (void)
787 {
788 }
789
genVertexSource(glu::DataType coordType,glu::Precision precision)790 static std::string genVertexSource (glu::DataType coordType, glu::Precision precision)
791 {
792 DE_ASSERT(coordType == glu::TYPE_LAST || glu::isDataTypeFloatOrVec(coordType));
793
794 const std::string vertexTmpl =
795 "#version 450\n"
796 "layout(location = 0) in highp vec4 a_position;\n"
797 + string(coordType != glu::TYPE_LAST ? "layout(location = 1) in ${PRECISION} ${DATATYPE} a_coord;\n"
798 "layout(location = 0) out ${PRECISION} ${DATATYPE} v_coord;\n" : "") +
799 "out gl_PerVertex {\n"
800 " vec4 gl_Position;\n"
801 "};\n"
802 "void main (void)\n"
803 "{\n"
804 " gl_Position = a_position;\n"
805 + string(coordType != glu::TYPE_LAST ? " v_coord = a_coord;\n" : "") +
806 "}\n";
807
808 map<string, string> vertexParams;
809
810 if (coordType != glu::TYPE_LAST)
811 {
812 vertexParams["PRECISION"] = glu::getPrecisionName(precision);
813 vertexParams["DATATYPE"] = glu::getDataTypeName(coordType);
814 }
815
816 return tcu::StringTemplate(vertexTmpl).specialize(vertexParams);
817 }
818
819 // ConstantDerivateCaseInstance
820
821 class ConstantDerivateCaseInstance : public TriangleDerivateCaseInstance
822 {
823 public:
824 ConstantDerivateCaseInstance (Context& context,
825 const UniformSetup& uniformSetup,
826 const DerivateCaseDefinition& definitions,
827 const DerivateCaseValues& values);
828 virtual ~ConstantDerivateCaseInstance (void);
829
830 virtual bool verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
831 };
832
ConstantDerivateCaseInstance(Context & context,const UniformSetup & uniformSetup,const DerivateCaseDefinition & definitions,const DerivateCaseValues & values)833 ConstantDerivateCaseInstance::ConstantDerivateCaseInstance (Context& context,
834 const UniformSetup& uniformSetup,
835 const DerivateCaseDefinition& definitions,
836 const DerivateCaseValues& values)
837 : TriangleDerivateCaseInstance (context, uniformSetup, definitions, values)
838 {
839 }
840
~ConstantDerivateCaseInstance(void)841 ConstantDerivateCaseInstance::~ConstantDerivateCaseInstance (void)
842 {
843 }
844
verify(const tcu::ConstPixelBufferAccess & result,const tcu::PixelBufferAccess & errorMask)845 bool ConstantDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
846 {
847 const tcu::Vec4 reference (0.0f); // Derivate of constant argument should always be 0
848 const tcu::Vec4 threshold = getSurfaceThreshold() / abs(m_values.derivScale);
849
850 return verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
851 reference, threshold, m_values.derivScale, m_values.derivBias);
852 }
853
854 // ConstantDerivateCase
855
856 class ConstantDerivateCase : public TriangleDerivateCase
857 {
858 public:
859 ConstantDerivateCase (tcu::TestContext& testCtx,
860 const std::string& name,
861 const std::string& description,
862 DerivateFunc func,
863 glu::DataType type);
864 virtual ~ConstantDerivateCase (void);
865
866 virtual void initPrograms (vk::SourceCollections& programCollection) const;
867 virtual TestInstance* createInstance (Context& context) const;
868 };
869
ConstantDerivateCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,DerivateFunc func,glu::DataType type)870 ConstantDerivateCase::ConstantDerivateCase (tcu::TestContext& testCtx,
871 const std::string& name,
872 const std::string& description,
873 DerivateFunc func,
874 glu::DataType type)
875 : TriangleDerivateCase (testCtx, name, description, new DerivateUniformSetup(false))
876 {
877 m_definitions.func = func;
878 m_definitions.dataType = type;
879 m_definitions.precision = glu::PRECISION_HIGHP;
880 }
881
~ConstantDerivateCase(void)882 ConstantDerivateCase::~ConstantDerivateCase (void)
883 {
884 }
885
createInstance(Context & context) const886 TestInstance* ConstantDerivateCase::createInstance (Context& context) const
887 {
888 DE_ASSERT(m_uniformSetup != DE_NULL);
889 return new ConstantDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values);
890 }
891
initPrograms(vk::SourceCollections & programCollection) const892 void ConstantDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
893 {
894 const char* fragmentTmpl =
895 "#version 450\n"
896 "layout(location = 0) out mediump vec4 o_color;\n"
897 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
898 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; }; \n"
899 "void main (void)\n"
900 "{\n"
901 " ${PRECISION} ${DATATYPE} res = ${FUNC}(${VALUE}) * u_scale + u_bias;\n"
902 " o_color = ${CAST_TO_OUTPUT};\n"
903 "}\n";
904
905 map<string, string> fragmentParams;
906 fragmentParams["PRECISION"] = glu::getPrecisionName(m_definitions.precision);
907 fragmentParams["DATATYPE"] = glu::getDataTypeName(m_definitions.dataType);
908 fragmentParams["FUNC"] = getDerivateFuncName(m_definitions.func);
909 fragmentParams["VALUE"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "vec4(1.0, 7.2, -1e5, 0.0)" :
910 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec3(1e2, 8.0, 0.01)" :
911 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec2(-0.0, 2.7)" :
912 /* TYPE_FLOAT */ "7.7";
913 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
914 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
915 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
916 /* TYPE_FLOAT */ "vec4(res, 0.0, 0.0, 1.0)";
917
918 std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
919 programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
920 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
921
922 m_values.derivScale = tcu::Vec4(1e3f, 1e3f, 1e3f, 1e3f);
923 m_values.derivBias = tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f);
924 }
925
926 // Linear cases
927
928 class LinearDerivateUniformSetup : public DerivateUniformSetup
929 {
930 public:
931 LinearDerivateUniformSetup (bool useSampler, BaseUniformType usedDefaultUniform);
932 virtual ~LinearDerivateUniformSetup (void);
933
934 virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
935
936 private:
937 const BaseUniformType m_usedDefaultUniform;
938 };
939
LinearDerivateUniformSetup(bool useSampler,BaseUniformType usedDefaultUniform)940 LinearDerivateUniformSetup::LinearDerivateUniformSetup (bool useSampler, BaseUniformType usedDefaultUniform)
941 : DerivateUniformSetup (useSampler)
942 , m_usedDefaultUniform (usedDefaultUniform)
943 {
944 }
945
~LinearDerivateUniformSetup(void)946 LinearDerivateUniformSetup::~LinearDerivateUniformSetup (void)
947 {
948 }
949
setup(ShaderRenderCaseInstance & instance,const tcu::Vec4 & constCoords) const950 void LinearDerivateUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const
951 {
952 DerivateUniformSetup::setup(instance, constCoords);
953
954 if (m_usedDefaultUniform != U_LAST)
955 switch (m_usedDefaultUniform)
956 {
957 case UB_TRUE:
958 case UI_ONE:
959 case UI_TWO:
960 instance.useUniform(2u, m_usedDefaultUniform);
961 break;
962 default:
963 DE_ASSERT(false);
964 break;
965 }
966 }
967
968 class LinearDerivateCaseInstance : public TriangleDerivateCaseInstance
969 {
970 public:
971 LinearDerivateCaseInstance (Context& context,
972 const UniformSetup& uniformSetup,
973 const DerivateCaseDefinition& definitions,
974 const DerivateCaseValues& values);
975 virtual ~LinearDerivateCaseInstance (void);
976
977 virtual bool verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
978 };
979
LinearDerivateCaseInstance(Context & context,const UniformSetup & uniformSetup,const DerivateCaseDefinition & definitions,const DerivateCaseValues & values)980 LinearDerivateCaseInstance::LinearDerivateCaseInstance (Context& context,
981 const UniformSetup& uniformSetup,
982 const DerivateCaseDefinition& definitions,
983 const DerivateCaseValues& values)
984 : TriangleDerivateCaseInstance (context, uniformSetup, definitions, values)
985 {
986 }
987
~LinearDerivateCaseInstance(void)988 LinearDerivateCaseInstance::~LinearDerivateCaseInstance (void)
989 {
990 }
991
verify(const tcu::ConstPixelBufferAccess & result,const tcu::PixelBufferAccess & errorMask)992 bool LinearDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
993 {
994 const tcu::Vec4 xScale = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
995 const tcu::Vec4 yScale = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
996 const tcu::Vec4 surfaceThreshold = getSurfaceThreshold() / abs(m_values.derivScale);
997
998 if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
999 {
1000 const bool isX = isDfdxFunc(m_definitions.func);
1001 const float div = isX ? float(result.getWidth()) : float(result.getHeight());
1002 const tcu::Vec4 scale = isX ? xScale : yScale;
1003 tcu::Vec4 reference = ((m_values.coordMax - m_values.coordMin) / div);
1004 const tcu::Vec4 opThreshold = getDerivateThreshold(m_definitions.precision, m_values.coordMin, m_values.coordMax, reference);
1005 const tcu::Vec4 threshold = max(surfaceThreshold, opThreshold);
1006 const int numComps = glu::getDataTypeFloatScalars(m_definitions.dataType);
1007
1008 /* adjust the reference value for the correct dfdx or dfdy sample adjacency */
1009 reference = reference * scale;
1010
1011 m_context.getTestContext().getLog()
1012 << tcu::TestLog::Message
1013 << "Verifying result image.\n"
1014 << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
1015 << tcu::TestLog::EndMessage;
1016
1017 // short circuit if result is strictly within the normal value error bounds.
1018 // This improves performance significantly.
1019 if (verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
1020 reference, threshold, m_values.derivScale, m_values.derivBias,
1021 LOG_NOTHING))
1022 {
1023 m_context.getTestContext().getLog()
1024 << tcu::TestLog::Message
1025 << "No incorrect derivatives found, result valid."
1026 << tcu::TestLog::EndMessage;
1027
1028 return true;
1029 }
1030
1031 // some pixels exceed error bounds calculated for normal values. Verify that these
1032 // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1033
1034 m_context.getTestContext().getLog()
1035 << tcu::TestLog::Message
1036 << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
1037 << "\tVerifying each result derivative is within its range of legal result values."
1038 << tcu::TestLog::EndMessage;
1039
1040 {
1041 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1042 const float w = float(viewportSize.x());
1043 const float h = float(viewportSize.y());
1044 const tcu::Vec4 valueRamp = (m_values.coordMax - m_values.coordMin);
1045 Linear2DFunctionEvaluator function;
1046
1047 function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_values.coordMin.x()));
1048 function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_values.coordMin.y()));
1049 function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_values.coordMin.z() + m_values.coordMin.z()) / 2.0f);
1050 function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_values.coordMax.w() + m_values.coordMax.w()) / 2.0f);
1051
1052 return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), result, errorMask,
1053 m_definitions.dataType, m_definitions.precision, m_values.derivScale,
1054 m_values.derivBias, surfaceThreshold, m_definitions.func,
1055 function);
1056 }
1057 }
1058 else
1059 {
1060 DE_ASSERT(isFwidthFunc(m_definitions.func));
1061 const float w = float(result.getWidth());
1062 const float h = float(result.getHeight());
1063
1064 const tcu::Vec4 dx = ((m_values.coordMax - m_values.coordMin) / w) * xScale;
1065 const tcu::Vec4 dy = ((m_values.coordMax - m_values.coordMin) / h) * yScale;
1066 const tcu::Vec4 reference = tcu::abs(dx) + tcu::abs(dy);
1067 const tcu::Vec4 dxThreshold = getDerivateThreshold(m_definitions.precision, m_values.coordMin*xScale, m_values.coordMax*xScale, dx);
1068 const tcu::Vec4 dyThreshold = getDerivateThreshold(m_definitions.precision, m_values.coordMin*yScale, m_values.coordMax*yScale, dy);
1069 const tcu::Vec4 threshold = max(surfaceThreshold, max(dxThreshold, dyThreshold));
1070
1071 return verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
1072 reference, threshold, m_values.derivScale, m_values.derivBias);
1073 }
1074 }
1075
1076 // LinearDerivateCase
1077
1078 class LinearDerivateCase : public TriangleDerivateCase
1079 {
1080 public:
1081 LinearDerivateCase (tcu::TestContext& testCtx,
1082 const std::string& name,
1083 const std::string& description,
1084 DerivateFunc func,
1085 glu::DataType type,
1086 glu::Precision precision,
1087 bool inNonUniformControlFlow,
1088 SurfaceType surfaceType,
1089 int numSamples,
1090 const std::string& fragmentSrcTmpl,
1091 BaseUniformType usedDefaultUniform);
1092 virtual ~LinearDerivateCase (void);
1093
1094 virtual void initPrograms (vk::SourceCollections& programCollection) const;
1095 virtual TestInstance* createInstance (Context& context) const;
1096
1097 private:
1098 const std::string m_fragmentTmpl;
1099 };
1100
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)1101 LinearDerivateCase::LinearDerivateCase (tcu::TestContext& testCtx,
1102 const std::string& name,
1103 const std::string& description,
1104 DerivateFunc func,
1105 glu::DataType type,
1106 glu::Precision precision,
1107 bool inNonUniformControlFlow,
1108 SurfaceType surfaceType,
1109 int numSamples,
1110 const std::string& fragmentSrcTmpl,
1111 BaseUniformType usedDefaultUniform)
1112 : TriangleDerivateCase (testCtx, name, description, new LinearDerivateUniformSetup(false, usedDefaultUniform))
1113 , m_fragmentTmpl (fragmentSrcTmpl)
1114 {
1115 m_definitions.func = func;
1116 m_definitions.dataType = type;
1117 m_definitions.precision = precision;
1118 m_definitions.inNonUniformControlFlow = inNonUniformControlFlow;
1119 m_definitions.coordDataType = m_definitions.dataType;
1120 m_definitions.coordPrecision = m_definitions.precision;
1121 m_definitions.surfaceType = surfaceType;
1122 m_definitions.numSamples = numSamples;
1123 }
1124
~LinearDerivateCase(void)1125 LinearDerivateCase::~LinearDerivateCase (void)
1126 {
1127 }
1128
createInstance(Context & context) const1129 TestInstance* LinearDerivateCase::createInstance (Context& context) const
1130 {
1131 DE_ASSERT(m_uniformSetup != DE_NULL);
1132 return new LinearDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values);
1133 }
1134
initPrograms(vk::SourceCollections & programCollection) const1135 void LinearDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
1136 {
1137 const SpirvVersion spirvVersion = m_definitions.inNonUniformControlFlow ? vk::SPIRV_VERSION_1_3 : vk::SPIRV_VERSION_1_0;
1138 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u);
1139
1140 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1141 const float w = float(viewportSize.x());
1142 const float h = float(viewportSize.y());
1143 const bool packToInt = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
1144 map<string, string> fragmentParams;
1145
1146 fragmentParams["OUTPUT_TYPE"] = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
1147 fragmentParams["OUTPUT_PREC"] = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
1148 fragmentParams["PRECISION"] = glu::getPrecisionName(m_definitions.precision);
1149 fragmentParams["DATATYPE"] = glu::getDataTypeName(m_definitions.dataType);
1150 fragmentParams["FUNC"] = getDerivateFuncName(m_definitions.func);
1151
1152 if (packToInt)
1153 {
1154 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
1155 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
1156 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
1157 /* TYPE_FLOAT */ "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
1158 }
1159 else
1160 {
1161 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
1162 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
1163 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
1164 /* TYPE_FLOAT */ "vec4(res, 0.0, 0.0, 1.0)";
1165 }
1166
1167 std::string fragmentSrc = tcu::StringTemplate(m_fragmentTmpl).specialize(fragmentParams);
1168 programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
1169 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc) << buildOptions;
1170
1171 switch (m_definitions.precision)
1172 {
1173 case glu::PRECISION_HIGHP:
1174 m_values.coordMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
1175 m_values.coordMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
1176 break;
1177
1178 case glu::PRECISION_MEDIUMP:
1179 m_values.coordMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
1180 m_values.coordMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
1181 break;
1182
1183 case glu::PRECISION_LOWP:
1184 m_values.coordMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
1185 m_values.coordMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
1186 break;
1187
1188 default:
1189 DE_ASSERT(false);
1190 }
1191
1192 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
1193 {
1194 // No scale or bias used for accuracy.
1195 m_values.derivScale = tcu::Vec4(1.0f);
1196 m_values.derivBias = tcu::Vec4(0.0f);
1197 }
1198 else
1199 {
1200 // Compute scale - bias that normalizes to 0..1 range.
1201 const tcu::Vec4 dx = (m_values.coordMax - m_values.coordMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
1202 const tcu::Vec4 dy = (m_values.coordMax - m_values.coordMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
1203
1204 if (isDfdxFunc(m_definitions.func))
1205 m_values.derivScale = 0.5f / dx;
1206 else if (isDfdyFunc(m_definitions.func))
1207 m_values.derivScale = 0.5f / dy;
1208 else if (isFwidthFunc(m_definitions.func))
1209 m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
1210 else
1211 DE_ASSERT(false);
1212
1213 m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1214 }
1215 }
1216
1217 // TextureDerivateCaseInstance
1218
1219 class TextureDerivateCaseInstance : public TriangleDerivateCaseInstance
1220 {
1221 public:
1222 TextureDerivateCaseInstance (Context& context,
1223 const UniformSetup& uniformSetup,
1224 const DerivateCaseDefinition& definitions,
1225 const DerivateCaseValues& values,
1226 const TextureCaseValues& textureValues);
1227 virtual ~TextureDerivateCaseInstance (void);
1228
1229 virtual bool verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
1230
1231 private:
1232 const TextureCaseValues& m_textureValues;
1233 };
1234
TextureDerivateCaseInstance(Context & context,const UniformSetup & uniformSetup,const DerivateCaseDefinition & definitions,const DerivateCaseValues & values,const TextureCaseValues & textureValues)1235 TextureDerivateCaseInstance::TextureDerivateCaseInstance (Context& context,
1236 const UniformSetup& uniformSetup,
1237 const DerivateCaseDefinition& definitions,
1238 const DerivateCaseValues& values,
1239 const TextureCaseValues& textureValues)
1240 : TriangleDerivateCaseInstance (context, uniformSetup, definitions, values)
1241 , m_textureValues (textureValues)
1242 {
1243 de::MovePtr<tcu::Texture2D> texture;
1244
1245 // Lowp and mediump cases use RGBA16F format, while highp uses RGBA32F.
1246 {
1247 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1248 const tcu::TextureFormat format = glu::mapGLInternalFormat(m_definitions.precision == glu::PRECISION_HIGHP ? GL_RGBA32F : GL_RGBA16F);
1249
1250 texture = de::MovePtr<tcu::Texture2D>(new tcu::Texture2D(format, viewportSize.x(), viewportSize.y()));
1251 texture->allocLevel(0);
1252 }
1253
1254 // Fill with gradients.
1255 {
1256 const tcu::PixelBufferAccess level0 = texture->getLevel(0);
1257 for (int y = 0; y < level0.getHeight(); y++)
1258 {
1259 for (int x = 0; x < level0.getWidth(); x++)
1260 {
1261 const float xf = (float(x)+0.5f) / float(level0.getWidth());
1262 const float yf = (float(y)+0.5f) / float(level0.getHeight());
1263 const tcu::Vec4 s = tcu::Vec4(xf, yf, (xf+yf)/2.0f, 1.0f - (xf+yf)/2.0f);
1264
1265 level0.setPixel(m_textureValues.texValueMin + (m_textureValues.texValueMax - m_textureValues.texValueMin)*s, x, y);
1266 }
1267 }
1268 }
1269
1270 de::SharedPtr<TextureBinding> testTexture (new TextureBinding(texture.release(),
1271 tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE,
1272 tcu::Sampler::CLAMP_TO_EDGE,
1273 tcu::Sampler::CLAMP_TO_EDGE,
1274 tcu::Sampler::NEAREST,
1275 tcu::Sampler::NEAREST)));
1276 m_textures.push_back(testTexture);
1277 }
1278
~TextureDerivateCaseInstance(void)1279 TextureDerivateCaseInstance::~TextureDerivateCaseInstance (void)
1280 {
1281 }
1282
verify(const tcu::ConstPixelBufferAccess & result,const tcu::PixelBufferAccess & errorMask)1283 bool TextureDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
1284 {
1285 // \note Edges are ignored in comparison
1286 if (result.getWidth() < 2 || result.getHeight() < 2)
1287 throw tcu::NotSupportedError("Too small viewport");
1288
1289 tcu::ConstPixelBufferAccess compareArea = tcu::getSubregion(result, 1, 1, result.getWidth()-2, result.getHeight()-2);
1290 tcu::PixelBufferAccess maskArea = tcu::getSubregion(errorMask, 1, 1, errorMask.getWidth()-2, errorMask.getHeight()-2);
1291 const tcu::Vec4 xScale = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
1292 const tcu::Vec4 yScale = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
1293 const float w = float(result.getWidth());
1294 const float h = float(result.getHeight());
1295
1296 const tcu::Vec4 surfaceThreshold = getSurfaceThreshold() / abs(m_values.derivScale);
1297
1298 if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
1299 {
1300 const bool isX = isDfdxFunc(m_definitions.func);
1301 const float div = isX ? w : h;
1302 const tcu::Vec4 scale = isX ? xScale : yScale;
1303 tcu::Vec4 reference = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / div);
1304 const tcu::Vec4 opThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin, m_textureValues.texValueMax, reference);
1305 const tcu::Vec4 threshold = max(surfaceThreshold, opThreshold);
1306 const int numComps = glu::getDataTypeFloatScalars(m_definitions.dataType);
1307
1308 /* adjust the reference value for the correct dfdx or dfdy sample adjacency */
1309 reference = reference * scale;
1310
1311 m_context.getTestContext().getLog()
1312 << tcu::TestLog::Message
1313 << "Verifying result image.\n"
1314 << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
1315 << tcu::TestLog::EndMessage;
1316
1317 // short circuit if result is strictly within the normal value error bounds.
1318 // This improves performance significantly.
1319 if (verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
1320 reference, threshold, m_values.derivScale, m_values.derivBias,
1321 LOG_NOTHING))
1322 {
1323 m_context.getTestContext().getLog()
1324 << tcu::TestLog::Message
1325 << "No incorrect derivatives found, result valid."
1326 << tcu::TestLog::EndMessage;
1327
1328 return true;
1329 }
1330
1331 // some pixels exceed error bounds calculated for normal values. Verify that these
1332 // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1333
1334 m_context.getTestContext().getLog()
1335 << tcu::TestLog::Message
1336 << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
1337 << "\tVerifying each result derivative is within its range of legal result values."
1338 << tcu::TestLog::EndMessage;
1339
1340 {
1341 const tcu::Vec4 valueRamp = (m_textureValues.texValueMax - m_textureValues.texValueMin);
1342 Linear2DFunctionEvaluator function;
1343
1344 function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_textureValues.texValueMin.x()));
1345 function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_textureValues.texValueMin.y()));
1346 function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_textureValues.texValueMin.z() + m_textureValues.texValueMin.z()) / 2.0f);
1347 function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_textureValues.texValueMax.w() + m_textureValues.texValueMax.w()) / 2.0f);
1348
1349 return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), compareArea, maskArea,
1350 m_definitions.dataType, m_definitions.precision, m_values.derivScale,
1351 m_values.derivBias, surfaceThreshold, m_definitions.func,
1352 function);
1353 }
1354 }
1355 else
1356 {
1357 DE_ASSERT(isFwidthFunc(m_definitions.func));
1358 const tcu::Vec4 dx = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / w) * xScale;
1359 const tcu::Vec4 dy = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / h) * yScale;
1360 const tcu::Vec4 reference = tcu::abs(dx) + tcu::abs(dy);
1361 const tcu::Vec4 dxThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*xScale, m_textureValues.texValueMax*xScale, dx);
1362 const tcu::Vec4 dyThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*yScale, m_textureValues.texValueMax*yScale, dy);
1363 const tcu::Vec4 threshold = max(surfaceThreshold, max(dxThreshold, dyThreshold));
1364
1365 return verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
1366 reference, threshold, m_values.derivScale, m_values.derivBias);
1367 }
1368 }
1369
1370 // TextureDerivateCase
1371
1372 class TextureDerivateCase : public TriangleDerivateCase
1373 {
1374 public:
1375 TextureDerivateCase (tcu::TestContext& testCtx,
1376 const std::string& name,
1377 const std::string& description,
1378 DerivateFunc func,
1379 glu::DataType type,
1380 glu::Precision precision,
1381 SurfaceType surfaceType,
1382 int numSamples);
1383 virtual ~TextureDerivateCase (void);
1384
1385 virtual void initPrograms (vk::SourceCollections& programCollection) const;
1386 virtual TestInstance* createInstance (Context& context) const;
1387
1388 private:
1389 mutable TextureCaseValues m_textureValues;
1390 };
1391
TextureDerivateCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,DerivateFunc func,glu::DataType type,glu::Precision precision,SurfaceType surfaceType,int numSamples)1392 TextureDerivateCase::TextureDerivateCase (tcu::TestContext& testCtx,
1393 const std::string& name,
1394 const std::string& description,
1395 DerivateFunc func,
1396 glu::DataType type,
1397 glu::Precision precision,
1398 SurfaceType surfaceType,
1399 int numSamples)
1400 : TriangleDerivateCase (testCtx, name, description, new DerivateUniformSetup(true))
1401 {
1402 m_definitions.dataType = type;
1403 m_definitions.func = func;
1404 m_definitions.precision = precision;
1405 m_definitions.coordDataType = glu::TYPE_FLOAT_VEC2;
1406 m_definitions.coordPrecision = glu::PRECISION_HIGHP;
1407 m_definitions.surfaceType = surfaceType;
1408 m_definitions.numSamples = numSamples;
1409 }
1410
~TextureDerivateCase(void)1411 TextureDerivateCase::~TextureDerivateCase (void)
1412 {
1413 }
1414
createInstance(Context & context) const1415 TestInstance* TextureDerivateCase::createInstance (Context& context) const
1416 {
1417 DE_ASSERT(m_uniformSetup != DE_NULL);
1418 return new TextureDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values, m_textureValues);
1419 }
1420
initPrograms(vk::SourceCollections & programCollection) const1421 void TextureDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
1422 {
1423 // Generate shader
1424 {
1425 const char* fragmentTmpl =
1426 "#version 450\n"
1427 "layout(location = 0) in highp vec2 v_coord;\n"
1428 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1429 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1430 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1431 "layout(binding = 2) uniform ${PRECISION} sampler2D u_sampler;\n"
1432 "void main (void)\n"
1433 "{\n"
1434 " ${PRECISION} vec4 tex = texture(u_sampler, v_coord);\n"
1435 " ${PRECISION} ${DATATYPE} res = ${FUNC}(tex${SWIZZLE}) * u_scale + u_bias;\n"
1436 " o_color = ${CAST_TO_OUTPUT};\n"
1437 "}\n";
1438
1439 const bool packToInt = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
1440 map<string, string> fragmentParams;
1441
1442 fragmentParams["OUTPUT_TYPE"] = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
1443 fragmentParams["OUTPUT_PREC"] = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
1444 fragmentParams["PRECISION"] = glu::getPrecisionName(m_definitions.precision);
1445 fragmentParams["DATATYPE"] = glu::getDataTypeName(m_definitions.dataType);
1446 fragmentParams["FUNC"] = getDerivateFuncName(m_definitions.func);
1447 fragmentParams["SWIZZLE"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "" :
1448 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? ".xyz" :
1449 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? ".xy" :
1450 /* TYPE_FLOAT */ ".x";
1451
1452 if (packToInt)
1453 {
1454 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
1455 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
1456 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
1457 /* TYPE_FLOAT */ "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
1458 }
1459 else
1460 {
1461 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
1462 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
1463 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
1464 /* TYPE_FLOAT */ "vec4(res, 0.0, 0.0, 1.0)";
1465 }
1466
1467 std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
1468 programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
1469 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
1470 }
1471
1472 // Texture size matches viewport and nearest sampling is used. Thus texture sampling
1473 // is equal to just interpolating the texture value range.
1474
1475 // Determine value range for texture.
1476
1477 switch (m_definitions.precision)
1478 {
1479 case glu::PRECISION_HIGHP:
1480 m_textureValues.texValueMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
1481 m_textureValues.texValueMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
1482 break;
1483
1484 case glu::PRECISION_MEDIUMP:
1485 m_textureValues.texValueMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
1486 m_textureValues.texValueMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
1487 break;
1488
1489 case glu::PRECISION_LOWP:
1490 m_textureValues.texValueMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
1491 m_textureValues.texValueMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
1492 break;
1493
1494 default:
1495 DE_ASSERT(false);
1496 }
1497
1498 // Texture coordinates
1499 m_values.coordMin = tcu::Vec4(0.0f);
1500 m_values.coordMax = tcu::Vec4(1.0f);
1501
1502 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
1503 {
1504 // No scale or bias used for accuracy.
1505 m_values.derivScale = tcu::Vec4(1.0f);
1506 m_values.derivBias = tcu::Vec4(0.0f);
1507 }
1508 else
1509 {
1510 // Compute scale - bias that normalizes to 0..1 range.
1511 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1512 const float w = float(viewportSize.x());
1513 const float h = float(viewportSize.y());
1514 const tcu::Vec4 dx = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
1515 const tcu::Vec4 dy = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
1516
1517 if (isDfdxFunc(m_definitions.func))
1518 m_values.derivScale = 0.5f / dx;
1519 else if (isDfdyFunc(m_definitions.func))
1520 m_values.derivScale = 0.5f / dy;
1521 else if (isFwidthFunc(m_definitions.func))
1522 m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
1523 else
1524 DE_ASSERT(false);
1525
1526 m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1527 }
1528 }
1529
1530 // ShaderDerivateTests
1531
1532 class ShaderDerivateTests : public tcu::TestCaseGroup
1533 {
1534 public:
1535 ShaderDerivateTests (tcu::TestContext& testCtx);
1536 virtual ~ShaderDerivateTests (void);
1537
1538 virtual void init (void);
1539
1540 private:
1541 ShaderDerivateTests (const ShaderDerivateTests&); // not allowed!
1542 ShaderDerivateTests& operator= (const ShaderDerivateTests&); // not allowed!
1543 };
1544
ShaderDerivateTests(tcu::TestContext & testCtx)1545 ShaderDerivateTests::ShaderDerivateTests (tcu::TestContext& testCtx)
1546 : TestCaseGroup(testCtx, "derivate", "Derivate Function Tests")
1547 {
1548 }
1549
~ShaderDerivateTests(void)1550 ShaderDerivateTests::~ShaderDerivateTests (void)
1551 {
1552 }
1553
1554 struct FunctionSpec
1555 {
1556 std::string name;
1557 DerivateFunc function;
1558 glu::DataType dataType;
1559 glu::Precision precision;
1560
FunctionSpecvkt::sr::__anon6be423a10111::FunctionSpec1561 FunctionSpec (const std::string& name_, DerivateFunc function_, glu::DataType dataType_, glu::Precision precision_)
1562 : name (name_)
1563 , function (function_)
1564 , dataType (dataType_)
1565 , precision (precision_)
1566 {
1567 }
1568 };
1569
init(void)1570 void ShaderDerivateTests::init (void)
1571 {
1572 static const struct
1573 {
1574 const char* name;
1575 const char* description;
1576 const char* source;
1577 BaseUniformType usedDefaultUniform;
1578 bool inNonUniformControlFlow;
1579 } s_linearDerivateCases[] =
1580 {
1581 {
1582 "linear",
1583 "Basic derivate of linearly interpolated argument",
1584
1585 "#version 450\n"
1586 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1587 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1588 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1589 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1590 "void main (void)\n"
1591 "{\n"
1592 " ${PRECISION} ${DATATYPE} res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1593 " o_color = ${CAST_TO_OUTPUT};\n"
1594 "}\n",
1595
1596 U_LAST,
1597 false
1598 },
1599 {
1600 "in_function",
1601 "Derivate of linear function argument",
1602
1603 "#version 450\n"
1604 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1605 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1606 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1607 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1608 "\n"
1609 "${PRECISION} ${DATATYPE} computeRes (${PRECISION} ${DATATYPE} value)\n"
1610 "{\n"
1611 " return ${FUNC}(v_coord) * u_scale + u_bias;\n"
1612 "}\n"
1613 "\n"
1614 "void main (void)\n"
1615 "{\n"
1616 " ${PRECISION} ${DATATYPE} res = computeRes(v_coord);\n"
1617 " o_color = ${CAST_TO_OUTPUT};\n"
1618 "}\n",
1619
1620 U_LAST,
1621 false
1622 },
1623 {
1624 "static_if",
1625 "Derivate of linearly interpolated value in static if",
1626
1627 "#version 450\n"
1628 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1629 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1630 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1631 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1632 "void main (void)\n"
1633 "{\n"
1634 " ${PRECISION} ${DATATYPE} res;\n"
1635 " if (false)\n"
1636 " res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
1637 " else\n"
1638 " res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1639 " o_color = ${CAST_TO_OUTPUT};\n"
1640 "}\n",
1641
1642 U_LAST,
1643 false
1644 },
1645 {
1646 "static_loop",
1647 "Derivate of linearly interpolated value in static loop",
1648
1649 "#version 450\n"
1650 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1651 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1652 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1653 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1654 "void main (void)\n"
1655 "{\n"
1656 " ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1657 " for (int i = 0; i < 2; i++)\n"
1658 " res += ${FUNC}(v_coord * float(i));\n"
1659 " res = res * u_scale + u_bias;\n"
1660 " o_color = ${CAST_TO_OUTPUT};\n"
1661 "}\n",
1662
1663 U_LAST,
1664 false
1665 },
1666 {
1667 "static_switch",
1668 "Derivate of linearly interpolated value in static switch",
1669
1670 "#version 450\n"
1671 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1672 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1673 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1674 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1675 "void main (void)\n"
1676 "{\n"
1677 " ${PRECISION} ${DATATYPE} res;\n"
1678 " switch (1)\n"
1679 " {\n"
1680 " case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias; break;\n"
1681 " case 1: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n"
1682 " }\n"
1683 " o_color = ${CAST_TO_OUTPUT};\n"
1684 "}\n",
1685
1686 U_LAST,
1687 false
1688 },
1689 {
1690 "uniform_if",
1691 "Derivate of linearly interpolated value in uniform if",
1692
1693 "#version 450\n"
1694 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1695 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1696 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1697 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1698 "layout(binding = 2, std140) uniform Ui_true { bool ub_true; };\n"
1699 "void main (void)\n"
1700 "{\n"
1701 " ${PRECISION} ${DATATYPE} res;\n"
1702 " if (ub_true)"
1703 " res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1704 " else\n"
1705 " res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
1706 " o_color = ${CAST_TO_OUTPUT};\n"
1707 "}\n",
1708
1709 UB_TRUE,
1710 false
1711 },
1712 {
1713 "uniform_loop",
1714 "Derivate of linearly interpolated value in uniform loop",
1715
1716 "#version 450\n"
1717 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1718 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1719 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1720 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1721 "layout(binding = 2, std140) uniform Ui_two { int ui_two; };\n"
1722 "void main (void)\n"
1723 "{\n"
1724 " ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1725 " for (int i = 0; i < ui_two; i++)\n"
1726 " res += ${FUNC}(v_coord * float(i));\n"
1727 " res = res * u_scale + u_bias;\n"
1728 " o_color = ${CAST_TO_OUTPUT};\n"
1729 "}\n",
1730
1731 UI_TWO,
1732 false
1733 },
1734 {
1735 "uniform_switch",
1736 "Derivate of linearly interpolated value in uniform switch",
1737
1738 "#version 450\n"
1739 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1740 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1741 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1742 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1743 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1744 "void main (void)\n"
1745 "{\n"
1746 " ${PRECISION} ${DATATYPE} res;\n"
1747 " switch (ui_one)\n"
1748 " {\n"
1749 " case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias; break;\n"
1750 " case 1: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n"
1751 " }\n"
1752 " o_color = ${CAST_TO_OUTPUT};\n"
1753 "}\n",
1754
1755 UI_ONE,
1756 false
1757 },
1758 {
1759 "dynamic_if",
1760 "Derivate of linearly interpolated value in static if",
1761
1762 "#version 450\n"
1763 "#extension GL_KHR_shader_subgroup_ballot : require\n"
1764 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1765 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1766 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1767 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1768 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1769 "void main (void)\n"
1770 "{\n"
1771 " ${PRECISION} ${DATATYPE} res;\n"
1772 " bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1773 " uvec4 quad_ballot = uvec4(0);\n"
1774 " quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1775 " bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1776 " if (quad_uniform)\n"
1777 " res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1778 " else\n"
1779 " res = ${FUNC}(v_coord * float(ui_one)) * u_scale + u_bias;\n"
1780 " o_color = ${CAST_TO_OUTPUT};\n"
1781 "}\n",
1782
1783 UI_ONE,
1784 true
1785 },
1786 {
1787 "dynamic_loop",
1788 "Derivate of linearly interpolated value in uniform loop",
1789
1790 "#version 450\n"
1791 "#extension GL_KHR_shader_subgroup_ballot : require\n"
1792 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1793 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1794 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1795 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1796 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1797 "void main (void)\n"
1798 "{\n"
1799 " ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1800 " bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1801 " uvec4 quad_ballot = uvec4(0);\n"
1802 " quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1803 " bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1804 " for (int i = 0; i < ui_one + int(quad_uniform); i++)\n"
1805 " res = ${FUNC}(v_coord * float(i - int(quad_uniform) + 1));\n"
1806 " res = res * u_scale + u_bias;\n"
1807 " o_color = ${CAST_TO_OUTPUT};\n"
1808 "}\n",
1809
1810 UI_ONE,
1811 true
1812 },
1813 {
1814 "dynamic_switch",
1815 "Derivate of linearly interpolated value in uniform switch",
1816
1817 "#version 450\n"
1818 "#extension GL_KHR_shader_subgroup_ballot : require\n"
1819 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1820 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1821 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1822 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1823 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1824 "void main (void)\n"
1825 "{\n"
1826 " ${PRECISION} ${DATATYPE} res;\n"
1827 " bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1828 " uvec4 quad_ballot = uvec4(0);\n"
1829 " quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1830 " bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1831 " switch (int(quad_uniform))\n"
1832 " {\n"
1833 " case 0: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n"
1834 " case 1: res = ${FUNC}(v_coord * float(ui_one)) * u_scale + u_bias; break;\n"
1835 " }\n"
1836 " o_color = ${CAST_TO_OUTPUT};\n"
1837 "}\n",
1838
1839 UI_ONE,
1840 true
1841 },
1842 };
1843
1844 static const struct
1845 {
1846 const char* name;
1847 SurfaceType surfaceType;
1848 int numSamples;
1849 } s_fboConfigs[] =
1850 {
1851 { "fbo", SURFACETYPE_UNORM_FBO, 0 },
1852 { "fbo_msaa2", SURFACETYPE_UNORM_FBO, 2 },
1853 { "fbo_msaa4", SURFACETYPE_UNORM_FBO, 4 },
1854 { "fbo_float", SURFACETYPE_FLOAT_FBO, 0 },
1855 };
1856
1857 static const struct
1858 {
1859 const char* name;
1860 SurfaceType surfaceType;
1861 int numSamples;
1862 } s_textureConfigs[] =
1863 {
1864 { "basic", SURFACETYPE_UNORM_FBO, 0 },
1865 { "msaa4", SURFACETYPE_UNORM_FBO, 4 },
1866 { "float", SURFACETYPE_FLOAT_FBO, 0 },
1867 };
1868
1869 // .dfdx[fine|coarse], .dfdy[fine|coarse], .fwidth[fine|coarse]
1870 for (int funcNdx = 0; funcNdx < DERIVATE_LAST; funcNdx++)
1871 {
1872 const DerivateFunc function = DerivateFunc(funcNdx);
1873 de::MovePtr<tcu::TestCaseGroup> functionGroup (new tcu::TestCaseGroup(m_testCtx, getDerivateFuncCaseName(function), getDerivateFuncName(function)));
1874
1875 // .constant - no precision variants, checks that derivate of constant arguments is 0
1876 {
1877 de::MovePtr<tcu::TestCaseGroup> constantGroup (new tcu::TestCaseGroup(m_testCtx, "constant", "Derivate of constant argument"));
1878
1879 for (int vecSize = 1; vecSize <= 4; vecSize++)
1880 {
1881 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1882 constantGroup->addChild(new ConstantDerivateCase(m_testCtx, glu::getDataTypeName(dataType), "", function, dataType));
1883 }
1884
1885 functionGroup->addChild(constantGroup.release());
1886 }
1887
1888 // Cases based on LinearDerivateCase
1889 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_linearDerivateCases); caseNdx++)
1890 {
1891 de::MovePtr<tcu::TestCaseGroup> linearCaseGroup (new tcu::TestCaseGroup(m_testCtx, s_linearDerivateCases[caseNdx].name, s_linearDerivateCases[caseNdx].description));
1892 const char* source = s_linearDerivateCases[caseNdx].source;
1893
1894 for (int vecSize = 1; vecSize <= 4; vecSize++)
1895 {
1896 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1897 {
1898 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1899 const glu::Precision precision = glu::Precision(precNdx);
1900 const SurfaceType surfaceType = SURFACETYPE_UNORM_FBO;
1901 const int numSamples = 0;
1902 std::ostringstream caseName;
1903
1904 if (caseNdx != 0 && precision == glu::PRECISION_LOWP)
1905 continue; // Skip as lowp doesn't actually produce any bits when rendered to default FB.
1906
1907 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1908
1909 linearCaseGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, s_linearDerivateCases[caseNdx].inNonUniformControlFlow, surfaceType, numSamples, source, s_linearDerivateCases[caseNdx].usedDefaultUniform));
1910 }
1911 }
1912
1913 functionGroup->addChild(linearCaseGroup.release());
1914 }
1915
1916 // Fbo cases
1917 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_fboConfigs); caseNdx++)
1918 {
1919 de::MovePtr<tcu::TestCaseGroup> fboGroup (new tcu::TestCaseGroup(m_testCtx, s_fboConfigs[caseNdx].name, "Derivate usage when rendering into FBO"));
1920 const char* source = s_linearDerivateCases[0].source; // use source from .linear group
1921 const SurfaceType surfaceType = s_fboConfigs[caseNdx].surfaceType;
1922 const int numSamples = s_fboConfigs[caseNdx].numSamples;
1923
1924 for (int vecSize = 1; vecSize <= 4; vecSize++)
1925 {
1926 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1927 {
1928 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1929 const glu::Precision precision = glu::Precision(precNdx);
1930 std::ostringstream caseName;
1931
1932 if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
1933 continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1934
1935 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1936
1937 fboGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, false, surfaceType, numSamples, source, U_LAST));
1938 }
1939 }
1940
1941 functionGroup->addChild(fboGroup.release());
1942 }
1943
1944 // .texture
1945 {
1946 de::MovePtr<tcu::TestCaseGroup> textureGroup (new tcu::TestCaseGroup(m_testCtx, "texture", "Derivate of texture lookup result"));
1947
1948 for (int texCaseNdx = 0; texCaseNdx < DE_LENGTH_OF_ARRAY(s_textureConfigs); texCaseNdx++)
1949 {
1950 de::MovePtr<tcu::TestCaseGroup> caseGroup (new tcu::TestCaseGroup(m_testCtx, s_textureConfigs[texCaseNdx].name, ""));
1951 const SurfaceType surfaceType = s_textureConfigs[texCaseNdx].surfaceType;
1952 const int numSamples = s_textureConfigs[texCaseNdx].numSamples;
1953
1954 for (int vecSize = 1; vecSize <= 4; vecSize++)
1955 {
1956 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1957 {
1958 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1959 const glu::Precision precision = glu::Precision(precNdx);
1960 std::ostringstream caseName;
1961
1962 if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
1963 continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1964
1965 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1966
1967 caseGroup->addChild(new TextureDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples));
1968 }
1969 }
1970
1971 textureGroup->addChild(caseGroup.release());
1972 }
1973
1974 functionGroup->addChild(textureGroup.release());
1975 }
1976
1977 addChild(functionGroup.release());
1978 }
1979 }
1980
1981 } // anonymous
1982
createDerivateTests(tcu::TestContext & testCtx)1983 tcu::TestCaseGroup* createDerivateTests (tcu::TestContext& testCtx)
1984 {
1985 return new ShaderDerivateTests(testCtx);
1986 }
1987
1988 } // sr
1989 } // vkt
1990