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::__anonfb80ce440111::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::__anonfb80ce440111::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(0, 1, 1, 0)))
685 throw tcu::NotSupportedError("Derivatives in dynamic control flow requires Vulkan 1.1");
686
687 vk::VkPhysicalDeviceSubgroupProperties subgroupProperties;
688 deMemset(&subgroupProperties, 0, sizeof(subgroupProperties));
689 subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
690
691 vk::VkPhysicalDeviceProperties2 properties2;
692 deMemset(&properties2, 0, sizeof(properties2));
693 properties2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
694 properties2.pNext = &subgroupProperties;
695
696 m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &properties2);
697
698 if (subgroupProperties.subgroupSize < 4)
699 throw tcu::NotSupportedError("Derivatives in dynamic control flow requires subgroupSize >= 4");
700
701 if ((subgroupProperties.supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) == 0)
702 throw tcu::NotSupportedError("Derivative dynamic control flow tests require VK_SUBGROUP_FEATURE_BALLOT_BIT");
703
704 if ((subgroupProperties.supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) == 0)
705 throw tcu::NotSupportedError("Derivative dynamic control flow tests require subgroup supported stage including VK_SHADER_STAGE_FRAGMENT_BIT");
706 }
707
708 setup();
709
710 render(numVertices, numTriangles, indices);
711
712 {
713 const tcu::TextureLevel& renderedImage = getResultImage();
714
715 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
716 {
717 const tcu::TextureFormat dataFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
718
719 resultImage.setStorage(dataFormat, renderedImage.getWidth(), renderedImage.getHeight());
720 tcu::copy(resultImage.getAccess(), tcu::ConstPixelBufferAccess(dataFormat, renderedImage.getSize(), renderedImage.getAccess().getDataPtr()));
721 }
722 else
723 {
724 resultImage = renderedImage;
725 }
726 }
727
728 // Verify
729 {
730 tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
731 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
732
733 const bool isOk = verify(resultImage.getAccess(), errorMask.getAccess());
734
735 log << TestLog::ImageSet("Result", "Result images")
736 << TestLog::Image("Rendered", "Rendered image", resultImage);
737
738 if (!isOk)
739 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
740
741 log << TestLog::EndImageSet;
742
743 if (isOk)
744 return tcu::TestStatus::pass("Pass");
745 else
746 return tcu::TestStatus::fail("Image comparison failed");
747 }
748 }
749
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 0.0f,
1280 true,
1281 tcu::Sampler::COMPAREMODE_NONE,
1282 0,
1283 tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
1284 true)));
1285 m_textures.push_back(testTexture);
1286 }
1287
~TextureDerivateCaseInstance(void)1288 TextureDerivateCaseInstance::~TextureDerivateCaseInstance (void)
1289 {
1290 }
1291
verify(const tcu::ConstPixelBufferAccess & result,const tcu::PixelBufferAccess & errorMask)1292 bool TextureDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
1293 {
1294 // \note Edges are ignored in comparison
1295 if (result.getWidth() < 2 || result.getHeight() < 2)
1296 throw tcu::NotSupportedError("Too small viewport");
1297
1298 tcu::ConstPixelBufferAccess compareArea = tcu::getSubregion(result, 1, 1, result.getWidth()-2, result.getHeight()-2);
1299 tcu::PixelBufferAccess maskArea = tcu::getSubregion(errorMask, 1, 1, errorMask.getWidth()-2, errorMask.getHeight()-2);
1300 const tcu::Vec4 xScale = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
1301 const tcu::Vec4 yScale = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
1302 const float w = float(result.getWidth());
1303 const float h = float(result.getHeight());
1304
1305 const tcu::Vec4 surfaceThreshold = getSurfaceThreshold() / abs(m_values.derivScale);
1306
1307 if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
1308 {
1309 const bool isX = isDfdxFunc(m_definitions.func);
1310 const float div = isX ? w : h;
1311 const tcu::Vec4 scale = isX ? xScale : yScale;
1312 tcu::Vec4 reference = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / div);
1313 const tcu::Vec4 opThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin, m_textureValues.texValueMax, reference);
1314 const tcu::Vec4 threshold = max(surfaceThreshold, opThreshold);
1315 const int numComps = glu::getDataTypeFloatScalars(m_definitions.dataType);
1316
1317 /* adjust the reference value for the correct dfdx or dfdy sample adjacency */
1318 reference = reference * scale;
1319
1320 m_context.getTestContext().getLog()
1321 << tcu::TestLog::Message
1322 << "Verifying result image.\n"
1323 << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
1324 << tcu::TestLog::EndMessage;
1325
1326 // short circuit if result is strictly within the normal value error bounds.
1327 // This improves performance significantly.
1328 if (verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
1329 reference, threshold, m_values.derivScale, m_values.derivBias,
1330 LOG_NOTHING))
1331 {
1332 m_context.getTestContext().getLog()
1333 << tcu::TestLog::Message
1334 << "No incorrect derivatives found, result valid."
1335 << tcu::TestLog::EndMessage;
1336
1337 return true;
1338 }
1339
1340 // some pixels exceed error bounds calculated for normal values. Verify that these
1341 // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1342
1343 m_context.getTestContext().getLog()
1344 << tcu::TestLog::Message
1345 << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
1346 << "\tVerifying each result derivative is within its range of legal result values."
1347 << tcu::TestLog::EndMessage;
1348
1349 {
1350 const tcu::Vec4 valueRamp = (m_textureValues.texValueMax - m_textureValues.texValueMin);
1351 Linear2DFunctionEvaluator function;
1352
1353 function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_textureValues.texValueMin.x()));
1354 function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_textureValues.texValueMin.y()));
1355 function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_textureValues.texValueMin.z() + m_textureValues.texValueMin.z()) / 2.0f);
1356 function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_textureValues.texValueMax.w() + m_textureValues.texValueMax.w()) / 2.0f);
1357
1358 return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), compareArea, maskArea,
1359 m_definitions.dataType, m_definitions.precision, m_values.derivScale,
1360 m_values.derivBias, surfaceThreshold, m_definitions.func,
1361 function);
1362 }
1363 }
1364 else
1365 {
1366 DE_ASSERT(isFwidthFunc(m_definitions.func));
1367 const tcu::Vec4 dx = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / w) * xScale;
1368 const tcu::Vec4 dy = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / h) * yScale;
1369 const tcu::Vec4 reference = tcu::abs(dx) + tcu::abs(dy);
1370 const tcu::Vec4 dxThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*xScale, m_textureValues.texValueMax*xScale, dx);
1371 const tcu::Vec4 dyThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*yScale, m_textureValues.texValueMax*yScale, dy);
1372 const tcu::Vec4 threshold = max(surfaceThreshold, max(dxThreshold, dyThreshold));
1373
1374 return verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
1375 reference, threshold, m_values.derivScale, m_values.derivBias);
1376 }
1377 }
1378
1379 // TextureDerivateCase
1380
1381 class TextureDerivateCase : public TriangleDerivateCase
1382 {
1383 public:
1384 TextureDerivateCase (tcu::TestContext& testCtx,
1385 const std::string& name,
1386 const std::string& description,
1387 DerivateFunc func,
1388 glu::DataType type,
1389 glu::Precision precision,
1390 SurfaceType surfaceType,
1391 int numSamples);
1392 virtual ~TextureDerivateCase (void);
1393
1394 virtual void initPrograms (vk::SourceCollections& programCollection) const;
1395 virtual TestInstance* createInstance (Context& context) const;
1396
1397 private:
1398 mutable TextureCaseValues m_textureValues;
1399 };
1400
TextureDerivateCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,DerivateFunc func,glu::DataType type,glu::Precision precision,SurfaceType surfaceType,int numSamples)1401 TextureDerivateCase::TextureDerivateCase (tcu::TestContext& testCtx,
1402 const std::string& name,
1403 const std::string& description,
1404 DerivateFunc func,
1405 glu::DataType type,
1406 glu::Precision precision,
1407 SurfaceType surfaceType,
1408 int numSamples)
1409 : TriangleDerivateCase (testCtx, name, description, new DerivateUniformSetup(true))
1410 {
1411 m_definitions.dataType = type;
1412 m_definitions.func = func;
1413 m_definitions.precision = precision;
1414 m_definitions.coordDataType = glu::TYPE_FLOAT_VEC2;
1415 m_definitions.coordPrecision = glu::PRECISION_HIGHP;
1416 m_definitions.surfaceType = surfaceType;
1417 m_definitions.numSamples = numSamples;
1418 }
1419
~TextureDerivateCase(void)1420 TextureDerivateCase::~TextureDerivateCase (void)
1421 {
1422 }
1423
createInstance(Context & context) const1424 TestInstance* TextureDerivateCase::createInstance (Context& context) const
1425 {
1426 DE_ASSERT(m_uniformSetup != DE_NULL);
1427 return new TextureDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values, m_textureValues);
1428 }
1429
initPrograms(vk::SourceCollections & programCollection) const1430 void TextureDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
1431 {
1432 // Generate shader
1433 {
1434 const char* fragmentTmpl =
1435 "#version 450\n"
1436 "layout(location = 0) in highp vec2 v_coord;\n"
1437 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1438 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1439 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1440 "layout(binding = 2) uniform ${PRECISION} sampler2D u_sampler;\n"
1441 "void main (void)\n"
1442 "{\n"
1443 " ${PRECISION} vec4 tex = texture(u_sampler, v_coord);\n"
1444 " ${PRECISION} ${DATATYPE} res = ${FUNC}(tex${SWIZZLE}) * u_scale + u_bias;\n"
1445 " o_color = ${CAST_TO_OUTPUT};\n"
1446 "}\n";
1447
1448 const bool packToInt = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
1449 map<string, string> fragmentParams;
1450
1451 fragmentParams["OUTPUT_TYPE"] = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
1452 fragmentParams["OUTPUT_PREC"] = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
1453 fragmentParams["PRECISION"] = glu::getPrecisionName(m_definitions.precision);
1454 fragmentParams["DATATYPE"] = glu::getDataTypeName(m_definitions.dataType);
1455 fragmentParams["FUNC"] = getDerivateFuncName(m_definitions.func);
1456 fragmentParams["SWIZZLE"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "" :
1457 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? ".xyz" :
1458 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? ".xy" :
1459 /* TYPE_FLOAT */ ".x";
1460
1461 if (packToInt)
1462 {
1463 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
1464 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
1465 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
1466 /* TYPE_FLOAT */ "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
1467 }
1468 else
1469 {
1470 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
1471 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
1472 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
1473 /* TYPE_FLOAT */ "vec4(res, 0.0, 0.0, 1.0)";
1474 }
1475
1476 std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
1477 programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
1478 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
1479 }
1480
1481 // Texture size matches viewport and nearest sampling is used. Thus texture sampling
1482 // is equal to just interpolating the texture value range.
1483
1484 // Determine value range for texture.
1485
1486 switch (m_definitions.precision)
1487 {
1488 case glu::PRECISION_HIGHP:
1489 m_textureValues.texValueMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
1490 m_textureValues.texValueMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
1491 break;
1492
1493 case glu::PRECISION_MEDIUMP:
1494 m_textureValues.texValueMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
1495 m_textureValues.texValueMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
1496 break;
1497
1498 case glu::PRECISION_LOWP:
1499 m_textureValues.texValueMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
1500 m_textureValues.texValueMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
1501 break;
1502
1503 default:
1504 DE_ASSERT(false);
1505 }
1506
1507 // Texture coordinates
1508 m_values.coordMin = tcu::Vec4(0.0f);
1509 m_values.coordMax = tcu::Vec4(1.0f);
1510
1511 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
1512 {
1513 // No scale or bias used for accuracy.
1514 m_values.derivScale = tcu::Vec4(1.0f);
1515 m_values.derivBias = tcu::Vec4(0.0f);
1516 }
1517 else
1518 {
1519 // Compute scale - bias that normalizes to 0..1 range.
1520 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1521 const float w = float(viewportSize.x());
1522 const float h = float(viewportSize.y());
1523 const tcu::Vec4 dx = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
1524 const tcu::Vec4 dy = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
1525
1526 if (isDfdxFunc(m_definitions.func))
1527 m_values.derivScale = 0.5f / dx;
1528 else if (isDfdyFunc(m_definitions.func))
1529 m_values.derivScale = 0.5f / dy;
1530 else if (isFwidthFunc(m_definitions.func))
1531 m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
1532 else
1533 DE_ASSERT(false);
1534
1535 m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1536 }
1537 }
1538
1539 // ShaderDerivateTests
1540
1541 class ShaderDerivateTests : public tcu::TestCaseGroup
1542 {
1543 public:
1544 ShaderDerivateTests (tcu::TestContext& testCtx);
1545 virtual ~ShaderDerivateTests (void);
1546
1547 virtual void init (void);
1548
1549 private:
1550 ShaderDerivateTests (const ShaderDerivateTests&); // not allowed!
1551 ShaderDerivateTests& operator= (const ShaderDerivateTests&); // not allowed!
1552 };
1553
ShaderDerivateTests(tcu::TestContext & testCtx)1554 ShaderDerivateTests::ShaderDerivateTests (tcu::TestContext& testCtx)
1555 : TestCaseGroup(testCtx, "derivate", "Derivate Function Tests")
1556 {
1557 }
1558
~ShaderDerivateTests(void)1559 ShaderDerivateTests::~ShaderDerivateTests (void)
1560 {
1561 }
1562
1563 struct FunctionSpec
1564 {
1565 std::string name;
1566 DerivateFunc function;
1567 glu::DataType dataType;
1568 glu::Precision precision;
1569
FunctionSpecvkt::sr::__anonfb80ce440111::FunctionSpec1570 FunctionSpec (const std::string& name_, DerivateFunc function_, glu::DataType dataType_, glu::Precision precision_)
1571 : name (name_)
1572 , function (function_)
1573 , dataType (dataType_)
1574 , precision (precision_)
1575 {
1576 }
1577 };
1578
init(void)1579 void ShaderDerivateTests::init (void)
1580 {
1581 static const struct
1582 {
1583 const char* name;
1584 const char* description;
1585 const char* source;
1586 BaseUniformType usedDefaultUniform;
1587 bool inNonUniformControlFlow;
1588 } s_linearDerivateCases[] =
1589 {
1590 {
1591 "linear",
1592 "Basic derivate of linearly interpolated argument",
1593
1594 "#version 450\n"
1595 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1596 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1597 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1598 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1599 "void main (void)\n"
1600 "{\n"
1601 " ${PRECISION} ${DATATYPE} res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1602 " o_color = ${CAST_TO_OUTPUT};\n"
1603 "}\n",
1604
1605 U_LAST,
1606 false
1607 },
1608 {
1609 "in_function",
1610 "Derivate of linear function argument",
1611
1612 "#version 450\n"
1613 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1614 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1615 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1616 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1617 "\n"
1618 "${PRECISION} ${DATATYPE} computeRes (${PRECISION} ${DATATYPE} value)\n"
1619 "{\n"
1620 " return ${FUNC}(v_coord) * u_scale + u_bias;\n"
1621 "}\n"
1622 "\n"
1623 "void main (void)\n"
1624 "{\n"
1625 " ${PRECISION} ${DATATYPE} res = computeRes(v_coord);\n"
1626 " o_color = ${CAST_TO_OUTPUT};\n"
1627 "}\n",
1628
1629 U_LAST,
1630 false
1631 },
1632 {
1633 "static_if",
1634 "Derivate of linearly interpolated value in static if",
1635
1636 "#version 450\n"
1637 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1638 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1639 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1640 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1641 "void main (void)\n"
1642 "{\n"
1643 " ${PRECISION} ${DATATYPE} res;\n"
1644 " if (false)\n"
1645 " res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
1646 " else\n"
1647 " res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1648 " o_color = ${CAST_TO_OUTPUT};\n"
1649 "}\n",
1650
1651 U_LAST,
1652 false
1653 },
1654 {
1655 "static_loop",
1656 "Derivate of linearly interpolated value in static loop",
1657
1658 "#version 450\n"
1659 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1660 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1661 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1662 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1663 "void main (void)\n"
1664 "{\n"
1665 " ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1666 " for (int i = 0; i < 2; i++)\n"
1667 " res += ${FUNC}(v_coord * float(i));\n"
1668 " res = res * u_scale + u_bias;\n"
1669 " o_color = ${CAST_TO_OUTPUT};\n"
1670 "}\n",
1671
1672 U_LAST,
1673 false
1674 },
1675 {
1676 "static_switch",
1677 "Derivate of linearly interpolated value in static switch",
1678
1679 "#version 450\n"
1680 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1681 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1682 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1683 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1684 "void main (void)\n"
1685 "{\n"
1686 " ${PRECISION} ${DATATYPE} res;\n"
1687 " switch (1)\n"
1688 " {\n"
1689 " case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias; break;\n"
1690 " case 1: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n"
1691 " }\n"
1692 " o_color = ${CAST_TO_OUTPUT};\n"
1693 "}\n",
1694
1695 U_LAST,
1696 false
1697 },
1698 {
1699 "uniform_if",
1700 "Derivate of linearly interpolated value in uniform if",
1701
1702 "#version 450\n"
1703 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1704 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1705 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1706 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1707 "layout(binding = 2, std140) uniform Ui_true { bool ub_true; };\n"
1708 "void main (void)\n"
1709 "{\n"
1710 " ${PRECISION} ${DATATYPE} res;\n"
1711 " if (ub_true)"
1712 " res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1713 " else\n"
1714 " res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
1715 " o_color = ${CAST_TO_OUTPUT};\n"
1716 "}\n",
1717
1718 UB_TRUE,
1719 false
1720 },
1721 {
1722 "uniform_loop",
1723 "Derivate of linearly interpolated value in uniform loop",
1724
1725 "#version 450\n"
1726 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1727 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1728 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1729 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1730 "layout(binding = 2, std140) uniform Ui_two { int ui_two; };\n"
1731 "void main (void)\n"
1732 "{\n"
1733 " ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1734 " for (int i = 0; i < ui_two; i++)\n"
1735 " res += ${FUNC}(v_coord * float(i));\n"
1736 " res = res * u_scale + u_bias;\n"
1737 " o_color = ${CAST_TO_OUTPUT};\n"
1738 "}\n",
1739
1740 UI_TWO,
1741 false
1742 },
1743 {
1744 "uniform_switch",
1745 "Derivate of linearly interpolated value in uniform switch",
1746
1747 "#version 450\n"
1748 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1749 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1750 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1751 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1752 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1753 "void main (void)\n"
1754 "{\n"
1755 " ${PRECISION} ${DATATYPE} res;\n"
1756 " switch (ui_one)\n"
1757 " {\n"
1758 " case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias; break;\n"
1759 " case 1: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n"
1760 " }\n"
1761 " o_color = ${CAST_TO_OUTPUT};\n"
1762 "}\n",
1763
1764 UI_ONE,
1765 false
1766 },
1767 {
1768 "dynamic_if",
1769 "Derivate of linearly interpolated value in static if",
1770
1771 "#version 450\n"
1772 "#extension GL_KHR_shader_subgroup_ballot : require\n"
1773 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1774 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1775 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1776 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1777 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1778 "void main (void)\n"
1779 "{\n"
1780 " ${PRECISION} ${DATATYPE} res;\n"
1781 " bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1782 " uvec4 quad_ballot = uvec4(0);\n"
1783 " quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1784 " bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1785 " if (quad_uniform)\n"
1786 " res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1787 " else\n"
1788 " res = ${FUNC}(v_coord * float(ui_one)) * u_scale + u_bias;\n"
1789 " o_color = ${CAST_TO_OUTPUT};\n"
1790 "}\n",
1791
1792 UI_ONE,
1793 true
1794 },
1795 {
1796 "dynamic_loop",
1797 "Derivate of linearly interpolated value in uniform loop",
1798
1799 "#version 450\n"
1800 "#extension GL_KHR_shader_subgroup_ballot : require\n"
1801 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1802 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1803 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1804 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1805 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1806 "void main (void)\n"
1807 "{\n"
1808 " ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1809 " bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1810 " uvec4 quad_ballot = uvec4(0);\n"
1811 " quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1812 " bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1813 " for (int i = 0; i < ui_one + int(quad_uniform); i++)\n"
1814 " res = ${FUNC}(v_coord * float(i - int(quad_uniform) + 1));\n"
1815 " res = res * u_scale + u_bias;\n"
1816 " o_color = ${CAST_TO_OUTPUT};\n"
1817 "}\n",
1818
1819 UI_ONE,
1820 true
1821 },
1822 {
1823 "dynamic_switch",
1824 "Derivate of linearly interpolated value in uniform switch",
1825
1826 "#version 450\n"
1827 "#extension GL_KHR_shader_subgroup_ballot : require\n"
1828 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1829 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1830 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1831 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1832 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1833 "void main (void)\n"
1834 "{\n"
1835 " ${PRECISION} ${DATATYPE} res;\n"
1836 " bool non_uniform = ((uint(gl_FragCoord.x * 0.4) + uint(gl_FragCoord.y * 0.3)) & 2) != 0;\n"
1837 " uvec4 quad_ballot = uvec4(0);\n"
1838 " quad_ballot[gl_SubgroupInvocationID >> 5] = 0xf << (gl_SubgroupInvocationID & 0x1c);\n"
1839 " bool quad_uniform = (subgroupBallot(non_uniform) & quad_ballot) == quad_ballot;\n"
1840 " switch (int(quad_uniform))\n"
1841 " {\n"
1842 " case 0: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n"
1843 " case 1: res = ${FUNC}(v_coord * float(ui_one)) * u_scale + u_bias; break;\n"
1844 " }\n"
1845 " o_color = ${CAST_TO_OUTPUT};\n"
1846 "}\n",
1847
1848 UI_ONE,
1849 true
1850 },
1851 };
1852
1853 static const struct
1854 {
1855 const char* name;
1856 SurfaceType surfaceType;
1857 int numSamples;
1858 } s_fboConfigs[] =
1859 {
1860 { "fbo", SURFACETYPE_UNORM_FBO, 0 },
1861 { "fbo_msaa2", SURFACETYPE_UNORM_FBO, 2 },
1862 { "fbo_msaa4", SURFACETYPE_UNORM_FBO, 4 },
1863 { "fbo_float", SURFACETYPE_FLOAT_FBO, 0 },
1864 };
1865
1866 static const struct
1867 {
1868 const char* name;
1869 SurfaceType surfaceType;
1870 int numSamples;
1871 } s_textureConfigs[] =
1872 {
1873 { "basic", SURFACETYPE_UNORM_FBO, 0 },
1874 { "msaa4", SURFACETYPE_UNORM_FBO, 4 },
1875 { "float", SURFACETYPE_FLOAT_FBO, 0 },
1876 };
1877
1878 // .dfdx[fine|coarse], .dfdy[fine|coarse], .fwidth[fine|coarse]
1879 for (int funcNdx = 0; funcNdx < DERIVATE_LAST; funcNdx++)
1880 {
1881 const DerivateFunc function = DerivateFunc(funcNdx);
1882 de::MovePtr<tcu::TestCaseGroup> functionGroup (new tcu::TestCaseGroup(m_testCtx, getDerivateFuncCaseName(function), getDerivateFuncName(function)));
1883
1884 // .constant - no precision variants, checks that derivate of constant arguments is 0
1885 {
1886 de::MovePtr<tcu::TestCaseGroup> constantGroup (new tcu::TestCaseGroup(m_testCtx, "constant", "Derivate of constant argument"));
1887
1888 for (int vecSize = 1; vecSize <= 4; vecSize++)
1889 {
1890 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1891 constantGroup->addChild(new ConstantDerivateCase(m_testCtx, glu::getDataTypeName(dataType), "", function, dataType));
1892 }
1893
1894 functionGroup->addChild(constantGroup.release());
1895 }
1896
1897 // Cases based on LinearDerivateCase
1898 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_linearDerivateCases); caseNdx++)
1899 {
1900 de::MovePtr<tcu::TestCaseGroup> linearCaseGroup (new tcu::TestCaseGroup(m_testCtx, s_linearDerivateCases[caseNdx].name, s_linearDerivateCases[caseNdx].description));
1901 const char* source = s_linearDerivateCases[caseNdx].source;
1902
1903 for (int vecSize = 1; vecSize <= 4; vecSize++)
1904 {
1905 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1906 {
1907 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1908 const glu::Precision precision = glu::Precision(precNdx);
1909 const SurfaceType surfaceType = SURFACETYPE_UNORM_FBO;
1910 const int numSamples = 0;
1911 std::ostringstream caseName;
1912
1913 if (caseNdx != 0 && precision == glu::PRECISION_LOWP)
1914 continue; // Skip as lowp doesn't actually produce any bits when rendered to default FB.
1915
1916 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1917
1918 linearCaseGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, s_linearDerivateCases[caseNdx].inNonUniformControlFlow, surfaceType, numSamples, source, s_linearDerivateCases[caseNdx].usedDefaultUniform));
1919 }
1920 }
1921
1922 functionGroup->addChild(linearCaseGroup.release());
1923 }
1924
1925 // Fbo cases
1926 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_fboConfigs); caseNdx++)
1927 {
1928 de::MovePtr<tcu::TestCaseGroup> fboGroup (new tcu::TestCaseGroup(m_testCtx, s_fboConfigs[caseNdx].name, "Derivate usage when rendering into FBO"));
1929 const char* source = s_linearDerivateCases[0].source; // use source from .linear group
1930 const SurfaceType surfaceType = s_fboConfigs[caseNdx].surfaceType;
1931 const int numSamples = s_fboConfigs[caseNdx].numSamples;
1932
1933 for (int vecSize = 1; vecSize <= 4; vecSize++)
1934 {
1935 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1936 {
1937 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1938 const glu::Precision precision = glu::Precision(precNdx);
1939 std::ostringstream caseName;
1940
1941 if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
1942 continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1943
1944 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1945
1946 fboGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, false, surfaceType, numSamples, source, U_LAST));
1947 }
1948 }
1949
1950 functionGroup->addChild(fboGroup.release());
1951 }
1952
1953 // .texture
1954 {
1955 de::MovePtr<tcu::TestCaseGroup> textureGroup (new tcu::TestCaseGroup(m_testCtx, "texture", "Derivate of texture lookup result"));
1956
1957 for (int texCaseNdx = 0; texCaseNdx < DE_LENGTH_OF_ARRAY(s_textureConfigs); texCaseNdx++)
1958 {
1959 de::MovePtr<tcu::TestCaseGroup> caseGroup (new tcu::TestCaseGroup(m_testCtx, s_textureConfigs[texCaseNdx].name, ""));
1960 const SurfaceType surfaceType = s_textureConfigs[texCaseNdx].surfaceType;
1961 const int numSamples = s_textureConfigs[texCaseNdx].numSamples;
1962
1963 for (int vecSize = 1; vecSize <= 4; vecSize++)
1964 {
1965 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1966 {
1967 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1968 const glu::Precision precision = glu::Precision(precNdx);
1969 std::ostringstream caseName;
1970
1971 if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
1972 continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1973
1974 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1975
1976 caseGroup->addChild(new TextureDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples));
1977 }
1978 }
1979
1980 textureGroup->addChild(caseGroup.release());
1981 }
1982
1983 functionGroup->addChild(textureGroup.release());
1984 }
1985
1986 addChild(functionGroup.release());
1987 }
1988 }
1989
1990 } // anonymous
1991
createDerivateTests(tcu::TestContext & testCtx)1992 tcu::TestCaseGroup* createDerivateTests (tcu::TestContext& testCtx)
1993 {
1994 return new ShaderDerivateTests(testCtx);
1995 }
1996
1997 } // sr
1998 } // vkt
1999