1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
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
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 * \brief Shader derivate function tests.
25 * \todo [2013-06-25 pyry] Missing features:
27 * - projected coordinates
28 * - continous non-trivial functions (sin, exp)
29 * - non-continous functions (step)
30 *//*--------------------------------------------------------------------*/
32 #include "vktShaderRenderDerivateTests.hpp"
33 #include "vktShaderRender.hpp"
34 #include "vkImageUtil.hpp"
36 #include "gluTextureUtil.hpp"
38 #include "tcuStringTemplate.hpp"
39 #include "tcuSurface.hpp"
40 #include "tcuTestLog.hpp"
41 #include "tcuVectorUtil.hpp"
42 #include "tcuTextureUtil.hpp"
43 #include "tcuRGBA.hpp"
44 #include "tcuFloat.hpp"
45 #include "tcuInterval.hpp"
47 #include "deUniquePtr.hpp"
48 #include "glwEnums.hpp"
66 using std::ostringstream;
71 VIEWPORT_HEIGHT = 133,
72 MAX_FAILED_MESSAGES = 10
87 DERIVATE_FWIDTHCOARSE,
94 SURFACETYPE_UNORM_FBO = 0,
95 SURFACETYPE_FLOAT_FBO, // \note Uses RGBA32UI fbo actually, since FP rendertargets are not in core spec.
102 static const char* getDerivateFuncName (DerivateFunc func)
106 case DERIVATE_DFDX: return "dFdx";
107 case DERIVATE_DFDXFINE: return "dFdxFine";
108 case DERIVATE_DFDXCOARSE: return "dFdxCoarse";
109 case DERIVATE_DFDY: return "dFdy";
110 case DERIVATE_DFDYFINE: return "dFdyFine";
111 case DERIVATE_DFDYCOARSE: return "dFdyCoarse";
112 case DERIVATE_FWIDTH: return "fwidth";
113 case DERIVATE_FWIDTHFINE: return "fwidthFine";
114 case DERIVATE_FWIDTHCOARSE: return "fwidthCoarse";
121 static const char* getDerivateFuncCaseName (DerivateFunc func)
125 case DERIVATE_DFDX: return "dfdx";
126 case DERIVATE_DFDXFINE: return "dfdxfine";
127 case DERIVATE_DFDXCOARSE: return "dfdxcoarse";
128 case DERIVATE_DFDY: return "dfdy";
129 case DERIVATE_DFDYFINE: return "dfdyfine";
130 case DERIVATE_DFDYCOARSE: return "dfdycoarse";
131 case DERIVATE_FWIDTH: return "fwidth";
132 case DERIVATE_FWIDTHFINE: return "fwidthfine";
133 case DERIVATE_FWIDTHCOARSE: return "fwidthcoarse";
140 static inline bool isDfdxFunc (DerivateFunc func)
142 return func == DERIVATE_DFDX || func == DERIVATE_DFDXFINE || func == DERIVATE_DFDXCOARSE;
145 static inline bool isDfdyFunc (DerivateFunc func)
147 return func == DERIVATE_DFDY || func == DERIVATE_DFDYFINE || func == DERIVATE_DFDYCOARSE;
150 static inline bool isFwidthFunc (DerivateFunc func)
152 return func == DERIVATE_FWIDTH || func == DERIVATE_FWIDTHFINE || func == DERIVATE_FWIDTHCOARSE;
155 static inline tcu::BVec4 getDerivateMask (glu::DataType type)
159 case glu::TYPE_FLOAT: return tcu::BVec4(true, false, false, false);
160 case glu::TYPE_FLOAT_VEC2: return tcu::BVec4(true, true, false, false);
161 case glu::TYPE_FLOAT_VEC3: return tcu::BVec4(true, true, true, false);
162 case glu::TYPE_FLOAT_VEC4: return tcu::BVec4(true, true, true, true);
165 return tcu::BVec4(true);
169 static inline tcu::Vec4 readDerivate (const tcu::ConstPixelBufferAccess& surface, const tcu::Vec4& derivScale, const tcu::Vec4& derivBias, int x, int y)
171 return (surface.getPixel(x, y) - derivBias) / derivScale;
174 static inline tcu::UVec4 getCompExpBits (const tcu::Vec4& v)
176 return tcu::UVec4(tcu::Float32(v[0]).exponentBits(),
177 tcu::Float32(v[1]).exponentBits(),
178 tcu::Float32(v[2]).exponentBits(),
179 tcu::Float32(v[3]).exponentBits());
182 float computeFloatingPointError (const float value, const int numAccurateBits)
184 const int numGarbageBits = 23-numAccurateBits;
185 const deUint32 mask = (1u<<numGarbageBits)-1u;
186 const int exp = tcu::Float32(value).exponent();
188 return tcu::Float32::construct(+1, exp, (1u<<23) | mask).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
191 static int getNumMantissaBits (const glu::Precision precision)
195 case glu::PRECISION_HIGHP: return 23;
196 case glu::PRECISION_MEDIUMP: return 10;
197 case glu::PRECISION_LOWP: return 6;
204 static int getMinExponent (const glu::Precision precision)
208 case glu::PRECISION_HIGHP: return -126;
209 case glu::PRECISION_MEDIUMP: return -14;
210 case glu::PRECISION_LOWP: return -8;
217 static float getSingleULPForExponent (int exp, int numMantissaBits)
219 if (numMantissaBits > 0)
221 DE_ASSERT(numMantissaBits <= 23);
223 const int ulpBitNdx = 23-numMantissaBits;
224 return tcu::Float32::construct(+1, exp, (1<<23) | (1 << ulpBitNdx)).asFloat() - tcu::Float32::construct(+1, exp, (1<<23)).asFloat();
228 DE_ASSERT(numMantissaBits == 0);
229 return tcu::Float32::construct(+1, exp, (1<<23)).asFloat();
233 static float getSingleULPForValue (float value, int numMantissaBits)
235 const int exp = tcu::Float32(value).exponent();
236 return getSingleULPForExponent(exp, numMantissaBits);
239 static float convertFloatFlushToZeroRtn (float value, int minExponent, int numAccurateBits)
247 const tcu::Float32 inputFloat = tcu::Float32(value);
248 const int numTruncatedBits = 23-numAccurateBits;
249 const deUint32 truncMask = (1u<<numTruncatedBits)-1u;
253 if (value > 0.0f && tcu::Float32(value).exponent() < minExponent)
255 // flush to zero if possible
260 // just mask away non-representable bits
261 return tcu::Float32::construct(+1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).asFloat();
266 if (inputFloat.mantissa() & truncMask)
268 // decrement one ulp if truncated bits are non-zero (i.e. if value is not representable)
269 return tcu::Float32::construct(-1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).asFloat() - getSingleULPForExponent(inputFloat.exponent(), numAccurateBits);
273 // value is representable, no need to do anything
280 static float convertFloatFlushToZeroRtp (float value, int minExponent, int numAccurateBits)
282 return -convertFloatFlushToZeroRtn(-value, minExponent, numAccurateBits);
285 static float addErrorUlp (float value, float numUlps, int numMantissaBits)
287 return value + numUlps * getSingleULPForValue(value, numMantissaBits);
292 INTERPOLATION_LOST_BITS = 3, // number mantissa of bits allowed to be lost in varying interpolation
295 static inline tcu::Vec4 getDerivateThreshold (const glu::Precision precision, const tcu::Vec4& valueMin, const tcu::Vec4& valueMax, const tcu::Vec4& expectedDerivate)
297 const int baseBits = getNumMantissaBits(precision);
298 const tcu::UVec4 derivExp = getCompExpBits(expectedDerivate);
299 const tcu::UVec4 maxValueExp = max(getCompExpBits(valueMin), getCompExpBits(valueMax));
300 const tcu::UVec4 numBitsLost = maxValueExp - min(maxValueExp, derivExp);
301 const tcu::IVec4 numAccurateBits = max(baseBits - numBitsLost.asInt() - (int)INTERPOLATION_LOST_BITS, tcu::IVec4(0));
303 return tcu::Vec4(computeFloatingPointError(expectedDerivate[0], numAccurateBits[0]),
304 computeFloatingPointError(expectedDerivate[1], numAccurateBits[1]),
305 computeFloatingPointError(expectedDerivate[2], numAccurateBits[2]),
306 computeFloatingPointError(expectedDerivate[3], numAccurateBits[3]));
314 LogVecComps (const tcu::Vec4& v_, int numComps_)
316 , numComps (numComps_)
321 std::ostream& operator<< (std::ostream& str, const LogVecComps& v)
323 DE_ASSERT(de::inRange(v.numComps, 1, 4));
324 if (v.numComps == 1) return str << v.v[0];
325 else if (v.numComps == 2) return str << v.v.toWidth<2>();
326 else if (v.numComps == 3) return str << v.v.toWidth<3>();
327 else return str << v.v;
330 enum VerificationLogging
336 static bool verifyConstantDerivate (tcu::TestLog& log,
337 const tcu::ConstPixelBufferAccess& result,
338 const tcu::PixelBufferAccess& errorMask,
339 glu::DataType dataType,
340 const tcu::Vec4& reference,
341 const tcu::Vec4& threshold,
342 const tcu::Vec4& scale,
343 const tcu::Vec4& bias,
344 VerificationLogging logPolicy = LOG_ALL)
346 const int numComps = glu::getDataTypeFloatScalars(dataType);
347 const tcu::BVec4 mask = tcu::logicalNot(getDerivateMask(dataType));
348 int numFailedPixels = 0;
350 if (logPolicy == LOG_ALL)
351 log << TestLog::Message << "Expecting " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps) << TestLog::EndMessage;
353 for (int y = 0; y < result.getHeight(); y++)
355 for (int x = 0; x < result.getWidth(); x++)
357 const tcu::Vec4 resDerivate = readDerivate(result, scale, bias, x, y);
358 const bool isOk = tcu::allEqual(tcu::logicalOr(tcu::lessThanEqual(tcu::abs(reference - resDerivate), threshold), mask), tcu::BVec4(true));
362 if (numFailedPixels < MAX_FAILED_MESSAGES && logPolicy == LOG_ALL)
363 log << TestLog::Message << "FAIL: got " << LogVecComps(resDerivate, numComps)
364 << ", diff = " << LogVecComps(tcu::abs(reference - resDerivate), numComps)
365 << ", at x = " << x << ", y = " << y
366 << TestLog::EndMessage;
367 numFailedPixels += 1;
368 errorMask.setPixel(tcu::RGBA::red().toVec(), x, y);
373 if (numFailedPixels >= MAX_FAILED_MESSAGES && logPolicy == LOG_ALL)
374 log << TestLog::Message << "..." << TestLog::EndMessage;
376 if (numFailedPixels > 0 && logPolicy == LOG_ALL)
377 log << TestLog::Message << "FAIL: found " << numFailedPixels << " failed pixels" << TestLog::EndMessage;
379 return numFailedPixels == 0;
382 struct Linear2DFunctionEvaluator
384 tcu::Matrix<float, 4, 3> matrix;
391 tcu::Vec4 evaluateAt (float screenX, float screenY) const;
394 tcu::Vec4 Linear2DFunctionEvaluator::evaluateAt (float screenX, float screenY) const
396 const tcu::Vec3 position(screenX, screenY, 1.0f);
397 return matrix * position;
400 static bool reverifyConstantDerivateWithFlushRelaxations (tcu::TestLog& log,
401 const tcu::ConstPixelBufferAccess& result,
402 const tcu::PixelBufferAccess& errorMask,
403 glu::DataType dataType,
404 glu::Precision precision,
405 const tcu::Vec4& derivScale,
406 const tcu::Vec4& derivBias,
407 const tcu::Vec4& surfaceThreshold,
408 DerivateFunc derivateFunc,
409 const Linear2DFunctionEvaluator& function)
411 DE_ASSERT(result.getWidth() == errorMask.getWidth());
412 DE_ASSERT(result.getHeight() == errorMask.getHeight());
413 DE_ASSERT(isDfdxFunc(derivateFunc) || isDfdyFunc(derivateFunc));
415 const tcu::IVec4 red (255, 0, 0, 255);
416 const tcu::IVec4 green (0, 255, 0, 255);
417 const float divisionErrorUlps = 2.5f;
419 const int numComponents = glu::getDataTypeFloatScalars(dataType);
420 const int numBits = getNumMantissaBits(precision);
421 const int minExponent = getMinExponent(precision);
423 const int numVaryingSampleBits = numBits - INTERPOLATION_LOST_BITS;
424 int numFailedPixels = 0;
426 tcu::clear(errorMask, green);
428 // search for failed pixels
429 for (int y = 0; y < result.getHeight(); ++y)
430 for (int x = 0; x < result.getWidth(); ++x)
432 // flushToZero?(f2z?(functionValueCurrent) - f2z?(functionValueBefore))
433 // flushToZero? ( ------------------------------------------------------------------------ +- 2.5 ULP )
436 const tcu::Vec4 resultDerivative = readDerivate(result, derivScale, derivBias, x, y);
438 // sample at the front of the back pixel and the back of the front pixel to cover the whole area of
439 // legal sample positions. In general case this is NOT OK, but we know that the target funtion is
440 // (mostly*) linear which allows us to take the sample points at arbitrary points. This gets us the
441 // maximum difference possible in exponents which are used in error bound calculations.
442 // * non-linearity may happen around zero or with very high function values due to subnorms not
444 const tcu::Vec4 functionValueForward = (isDfdxFunc(derivateFunc))
445 ? (function.evaluateAt((float)x + 2.0f, (float)y + 0.5f))
446 : (function.evaluateAt((float)x + 0.5f, (float)y + 2.0f));
447 const tcu::Vec4 functionValueBackward = (isDfdyFunc(derivateFunc))
448 ? (function.evaluateAt((float)x - 1.0f, (float)y + 0.5f))
449 : (function.evaluateAt((float)x + 0.5f, (float)y - 1.0f));
451 bool anyComponentFailed = false;
453 // check components separately
454 for (int c = 0; c < numComponents; ++c)
456 // Simulate interpolation. Add allowed interpolation error and round to target precision. Allow one half ULP (i.e. correct rounding)
457 const tcu::Interval forwardComponent (convertFloatFlushToZeroRtn(addErrorUlp((float)functionValueForward[c], -0.5f, numVaryingSampleBits), minExponent, numBits),
458 convertFloatFlushToZeroRtp(addErrorUlp((float)functionValueForward[c], +0.5f, numVaryingSampleBits), minExponent, numBits));
459 const tcu::Interval backwardComponent (convertFloatFlushToZeroRtn(addErrorUlp((float)functionValueBackward[c], -0.5f, numVaryingSampleBits), minExponent, numBits),
460 convertFloatFlushToZeroRtp(addErrorUlp((float)functionValueBackward[c], +0.5f, numVaryingSampleBits), minExponent, numBits));
461 const int maxValueExp = de::max(de::max(tcu::Float32(forwardComponent.lo()).exponent(), tcu::Float32(forwardComponent.hi()).exponent()),
462 de::max(tcu::Float32(backwardComponent.lo()).exponent(), tcu::Float32(backwardComponent.hi()).exponent()));
464 // subtraction in numerator will likely cause a cancellation of the most
465 // significant bits. Apply error bounds.
467 const tcu::Interval numerator (forwardComponent - backwardComponent);
468 const int numeratorLoExp = tcu::Float32(numerator.lo()).exponent();
469 const int numeratorHiExp = tcu::Float32(numerator.hi()).exponent();
470 const int numeratorLoBitsLost = de::max(0, maxValueExp - numeratorLoExp); //!< must clamp to zero since if forward and backward components have different
471 const int numeratorHiBitsLost = de::max(0, maxValueExp - numeratorHiExp); //!< sign, numerator might have larger exponent than its operands.
472 const int numeratorLoBits = de::max(0, numBits - numeratorLoBitsLost);
473 const int numeratorHiBits = de::max(0, numBits - numeratorHiBitsLost);
475 const tcu::Interval numeratorRange (convertFloatFlushToZeroRtn((float)numerator.lo(), minExponent, numeratorLoBits),
476 convertFloatFlushToZeroRtp((float)numerator.hi(), minExponent, numeratorHiBits));
478 const tcu::Interval divisionRange = numeratorRange / 3.0f; // legal sample area is anywhere within this and neighboring pixels (i.e. size = 3)
479 const tcu::Interval divisionResultRange (convertFloatFlushToZeroRtn(addErrorUlp((float)divisionRange.lo(), -divisionErrorUlps, numBits), minExponent, numBits),
480 convertFloatFlushToZeroRtp(addErrorUlp((float)divisionRange.hi(), +divisionErrorUlps, numBits), minExponent, numBits));
481 const tcu::Interval finalResultRange (divisionResultRange.lo() - surfaceThreshold[c], divisionResultRange.hi() + surfaceThreshold[c]);
483 if (resultDerivative[c] >= finalResultRange.lo() && resultDerivative[c] <= finalResultRange.hi())
489 if (numFailedPixels < MAX_FAILED_MESSAGES)
490 log << tcu::TestLog::Message
491 << "Error in pixel at " << x << ", " << y << " with component " << c << " (channel " << ("rgba"[c]) << ")\n"
492 << "\tGot pixel value " << result.getPixelInt(x, y) << "\n"
493 << "\t\tdFd" << ((isDfdxFunc(derivateFunc)) ? ('x') : ('y')) << " ~= " << resultDerivative[c] << "\n"
494 << "\t\tdifference to a valid range: "
495 << ((resultDerivative[c] < finalResultRange.lo()) ? ("-") : ("+"))
496 << ((resultDerivative[c] < finalResultRange.lo()) ? (finalResultRange.lo() - resultDerivative[c]) : (resultDerivative[c] - finalResultRange.hi()))
498 << "\tDerivative value range:\n"
499 << "\t\tMin: " << finalResultRange.lo() << "\n"
500 << "\t\tMax: " << finalResultRange.hi() << "\n"
501 << tcu::TestLog::EndMessage;
504 anyComponentFailed = true;
508 if (anyComponentFailed)
509 errorMask.setPixel(red, x, y);
512 if (numFailedPixels >= MAX_FAILED_MESSAGES)
513 log << TestLog::Message << "..." << TestLog::EndMessage;
515 if (numFailedPixels > 0)
516 log << TestLog::Message << "FAIL: found " << numFailedPixels << " failed pixels" << TestLog::EndMessage;
518 return numFailedPixels == 0;
523 struct DerivateCaseDefinition
525 DerivateCaseDefinition (void)
527 func = DERIVATE_LAST;
528 dataType = glu::TYPE_LAST;
529 precision = glu::PRECISION_LAST;
530 coordDataType = glu::TYPE_LAST;
531 coordPrecision = glu::PRECISION_LAST;
532 surfaceType = SURFACETYPE_UNORM_FBO;
537 glu::DataType dataType;
538 glu::Precision precision;
540 glu::DataType coordDataType;
541 glu::Precision coordPrecision;
543 SurfaceType surfaceType;
547 struct DerivateCaseValues
551 tcu::Vec4 derivScale;
555 struct TextureCaseValues
557 tcu::Vec4 texValueMin;
558 tcu::Vec4 texValueMax;
561 class DerivateUniformSetup : public UniformSetup
564 DerivateUniformSetup (bool useSampler);
565 virtual ~DerivateUniformSetup (void);
567 virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const;
570 const bool m_useSampler;
573 DerivateUniformSetup::DerivateUniformSetup (bool useSampler)
574 : m_useSampler(useSampler)
578 DerivateUniformSetup::~DerivateUniformSetup (void)
582 // TriangleDerivateCaseInstance
584 class TriangleDerivateCaseInstance : public ShaderRenderCaseInstance
587 TriangleDerivateCaseInstance (Context& context,
588 const UniformSetup& uniformSetup,
589 const DerivateCaseDefinition& definitions,
590 const DerivateCaseValues& values);
591 virtual ~TriangleDerivateCaseInstance (void);
592 virtual tcu::TestStatus iterate (void);
593 DerivateCaseDefinition getDerivateCaseDefinition (void) { return m_definitions; }
594 DerivateCaseValues getDerivateCaseValues (void) { return m_values; }
597 virtual bool verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask) = 0;
598 tcu::Vec4 getSurfaceThreshold (void) const;
599 virtual void setupDefaultInputs (void);
601 const DerivateCaseDefinition& m_definitions;
602 const DerivateCaseValues& m_values;
605 static VkSampleCountFlagBits getVkSampleCount (int numSamples)
609 case 0: return VK_SAMPLE_COUNT_1_BIT;
610 case 2: return VK_SAMPLE_COUNT_2_BIT;
611 case 4: return VK_SAMPLE_COUNT_4_BIT;
614 return (VkSampleCountFlagBits)0;
618 TriangleDerivateCaseInstance::TriangleDerivateCaseInstance (Context& context,
619 const UniformSetup& uniformSetup,
620 const DerivateCaseDefinition& definitions,
621 const DerivateCaseValues& values)
622 : ShaderRenderCaseInstance (context, true, DE_NULL, uniformSetup, DE_NULL)
623 , m_definitions (definitions)
626 m_renderSize = tcu::UVec2(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
627 m_colorFormat = vk::mapTextureFormat(glu::mapGLInternalFormat(m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO ? GL_RGBA32UI : GL_RGBA8));
629 setSampleCount(getVkSampleCount(definitions.numSamples));
632 TriangleDerivateCaseInstance::~TriangleDerivateCaseInstance (void)
636 tcu::Vec4 TriangleDerivateCaseInstance::getSurfaceThreshold (void) const
638 switch (m_definitions.surfaceType)
640 case SURFACETYPE_UNORM_FBO: return tcu::IVec4(1).asFloat() / 255.0f;
641 case SURFACETYPE_FLOAT_FBO: return tcu::Vec4(0.0f);
644 return tcu::Vec4(0.0f);
648 void TriangleDerivateCaseInstance::setupDefaultInputs (void)
650 const int numVertices = 4;
651 const float positions[] =
653 -1.0f, -1.0f, 0.0f, 1.0f,
654 -1.0f, 1.0f, 0.0f, 1.0f,
655 1.0f, -1.0f, 0.0f, 1.0f,
656 1.0f, 1.0f, 0.0f, 1.0f
658 const float coords[] =
660 m_values.coordMin.x(), m_values.coordMin.y(), m_values.coordMin.z(), m_values.coordMax.w(),
661 m_values.coordMin.x(), m_values.coordMax.y(), (m_values.coordMin.z()+m_values.coordMax.z())*0.5f, (m_values.coordMin.w()+m_values.coordMax.w())*0.5f,
662 m_values.coordMax.x(), m_values.coordMin.y(), (m_values.coordMin.z()+m_values.coordMax.z())*0.5f, (m_values.coordMin.w()+m_values.coordMax.w())*0.5f,
663 m_values.coordMax.x(), m_values.coordMax.y(), m_values.coordMax.z(), m_values.coordMin.w()
666 addAttribute(0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 4 * (deUint32)sizeof(float), numVertices, positions);
667 if (m_definitions.coordDataType != glu::TYPE_LAST)
668 addAttribute(1u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 4 * (deUint32)sizeof(float), numVertices, coords);
671 tcu::TestStatus TriangleDerivateCaseInstance::iterate (void)
673 tcu::TestLog& log = m_context.getTestContext().getLog();
674 const deUint32 numVertices = 4;
675 const deUint32 numTriangles = 2;
676 const deUint16 indices[] = { 0, 2, 1, 2, 3, 1 };
677 tcu::TextureLevel resultImage;
681 render(numVertices, numTriangles, indices);
684 const tcu::TextureLevel& renderedImage = getResultImage();
686 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
688 const tcu::TextureFormat dataFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
690 resultImage.setStorage(dataFormat, renderedImage.getWidth(), renderedImage.getHeight());
691 tcu::copy(resultImage.getAccess(), tcu::ConstPixelBufferAccess(dataFormat, renderedImage.getSize(), renderedImage.getAccess().getDataPtr()));
695 resultImage = renderedImage;
701 tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
702 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
704 const bool isOk = verify(resultImage.getAccess(), errorMask.getAccess());
706 log << TestLog::ImageSet("Result", "Result images")
707 << TestLog::Image("Rendered", "Rendered image", resultImage);
710 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
712 log << TestLog::EndImageSet;
715 return tcu::TestStatus::pass("Pass");
717 return tcu::TestStatus::fail("Image comparison failed");
721 void DerivateUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
723 DerivateCaseDefinition definitions = dynamic_cast<TriangleDerivateCaseInstance&>(instance).getDerivateCaseDefinition();
724 DerivateCaseValues values = dynamic_cast<TriangleDerivateCaseInstance&>(instance).getDerivateCaseValues();
726 DE_ASSERT(glu::isDataTypeFloatOrVec(definitions.dataType));
728 instance.addUniform(0u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, glu::getDataTypeScalarSize(definitions.dataType) * sizeof(float), values.derivScale.getPtr());
729 instance.addUniform(1u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, glu::getDataTypeScalarSize(definitions.dataType) * sizeof(float), values.derivBias.getPtr());
732 instance.useSampler(2u, 0u); // To the uniform binding location 2 bind the texture 0
735 // TriangleDerivateCase
737 class TriangleDerivateCase : public ShaderRenderCase
740 TriangleDerivateCase (tcu::TestContext& testCtx,
741 const std::string& name,
742 const std::string& description,
743 const UniformSetup* uniformSetup);
744 virtual ~TriangleDerivateCase (void);
747 mutable DerivateCaseDefinition m_definitions;
748 mutable DerivateCaseValues m_values;
751 TriangleDerivateCase::TriangleDerivateCase (tcu::TestContext& testCtx,
752 const std::string& name,
753 const std::string& description,
754 const UniformSetup* uniformSetup)
755 : ShaderRenderCase (testCtx, name, description, false, (ShaderEvaluator*)DE_NULL, uniformSetup, DE_NULL)
760 TriangleDerivateCase::~TriangleDerivateCase (void)
764 static std::string genVertexSource (glu::DataType coordType, glu::Precision precision)
766 DE_ASSERT(coordType == glu::TYPE_LAST || glu::isDataTypeFloatOrVec(coordType));
768 const std::string vertexTmpl =
770 "layout(location = 0) in highp vec4 a_position;\n"
771 + string(coordType != glu::TYPE_LAST ? "layout(location = 1) in ${PRECISION} ${DATATYPE} a_coord;\n"
772 "layout(location = 0) out ${PRECISION} ${DATATYPE} v_coord;\n" : "") +
773 "out gl_PerVertex {\n"
774 " vec4 gl_Position;\n"
778 " gl_Position = a_position;\n"
779 + string(coordType != glu::TYPE_LAST ? " v_coord = a_coord;\n" : "") +
782 map<string, string> vertexParams;
784 if (coordType != glu::TYPE_LAST)
786 vertexParams["PRECISION"] = glu::getPrecisionName(precision);
787 vertexParams["DATATYPE"] = glu::getDataTypeName(coordType);
790 return tcu::StringTemplate(vertexTmpl).specialize(vertexParams);
793 // ConstantDerivateCaseInstance
795 class ConstantDerivateCaseInstance : public TriangleDerivateCaseInstance
798 ConstantDerivateCaseInstance (Context& context,
799 const UniformSetup& uniformSetup,
800 const DerivateCaseDefinition& definitions,
801 const DerivateCaseValues& values);
802 virtual ~ConstantDerivateCaseInstance (void);
804 virtual bool verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
807 ConstantDerivateCaseInstance::ConstantDerivateCaseInstance (Context& context,
808 const UniformSetup& uniformSetup,
809 const DerivateCaseDefinition& definitions,
810 const DerivateCaseValues& values)
811 : TriangleDerivateCaseInstance (context, uniformSetup, definitions, values)
815 ConstantDerivateCaseInstance::~ConstantDerivateCaseInstance (void)
819 bool ConstantDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
821 const tcu::Vec4 reference (0.0f); // Derivate of constant argument should always be 0
822 const tcu::Vec4 threshold = getSurfaceThreshold() / abs(m_values.derivScale);
824 return verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
825 reference, threshold, m_values.derivScale, m_values.derivBias);
828 // ConstantDerivateCase
830 class ConstantDerivateCase : public TriangleDerivateCase
833 ConstantDerivateCase (tcu::TestContext& testCtx,
834 const std::string& name,
835 const std::string& description,
838 virtual ~ConstantDerivateCase (void);
840 virtual void initPrograms (vk::SourceCollections& programCollection) const;
841 virtual TestInstance* createInstance (Context& context) const;
844 ConstantDerivateCase::ConstantDerivateCase (tcu::TestContext& testCtx,
845 const std::string& name,
846 const std::string& description,
849 : TriangleDerivateCase (testCtx, name, description, new DerivateUniformSetup(false))
851 m_definitions.func = func;
852 m_definitions.dataType = type;
853 m_definitions.precision = glu::PRECISION_HIGHP;
856 ConstantDerivateCase::~ConstantDerivateCase (void)
860 TestInstance* ConstantDerivateCase::createInstance (Context& context) const
862 DE_ASSERT(m_uniformSetup != DE_NULL);
863 return new ConstantDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values);
866 void ConstantDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
868 const char* fragmentTmpl =
870 "layout(location = 0) out mediump vec4 o_color;\n"
871 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
872 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; }; \n"
875 " ${PRECISION} ${DATATYPE} res = ${FUNC}(${VALUE}) * u_scale + u_bias;\n"
876 " o_color = ${CAST_TO_OUTPUT};\n"
879 map<string, string> fragmentParams;
880 fragmentParams["PRECISION"] = glu::getPrecisionName(m_definitions.precision);
881 fragmentParams["DATATYPE"] = glu::getDataTypeName(m_definitions.dataType);
882 fragmentParams["FUNC"] = getDerivateFuncName(m_definitions.func);
883 fragmentParams["VALUE"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "vec4(1.0, 7.2, -1e5, 0.0)" :
884 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec3(1e2, 8.0, 0.01)" :
885 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec2(-0.0, 2.7)" :
886 /* TYPE_FLOAT */ "7.7";
887 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
888 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
889 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
890 /* TYPE_FLOAT */ "vec4(res, 0.0, 0.0, 1.0)";
892 std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
893 programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
894 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
896 m_values.derivScale = tcu::Vec4(1e3f, 1e3f, 1e3f, 1e3f);
897 m_values.derivBias = tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f);
902 class LinearDerivateUniformSetup : public DerivateUniformSetup
905 LinearDerivateUniformSetup (bool useSampler, BaseUniformType usedDefaultUniform);
906 virtual ~LinearDerivateUniformSetup (void);
908 virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
911 const BaseUniformType m_usedDefaultUniform;
914 LinearDerivateUniformSetup::LinearDerivateUniformSetup (bool useSampler, BaseUniformType usedDefaultUniform)
915 : DerivateUniformSetup (useSampler)
916 , m_usedDefaultUniform (usedDefaultUniform)
920 LinearDerivateUniformSetup::~LinearDerivateUniformSetup (void)
924 void LinearDerivateUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const
926 DerivateUniformSetup::setup(instance, constCoords);
928 if (m_usedDefaultUniform != U_LAST)
929 switch (m_usedDefaultUniform)
934 instance.useUniform(2u, m_usedDefaultUniform);
942 class LinearDerivateCaseInstance : public TriangleDerivateCaseInstance
945 LinearDerivateCaseInstance (Context& context,
946 const UniformSetup& uniformSetup,
947 const DerivateCaseDefinition& definitions,
948 const DerivateCaseValues& values);
949 virtual ~LinearDerivateCaseInstance (void);
951 virtual bool verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
954 LinearDerivateCaseInstance::LinearDerivateCaseInstance (Context& context,
955 const UniformSetup& uniformSetup,
956 const DerivateCaseDefinition& definitions,
957 const DerivateCaseValues& values)
958 : TriangleDerivateCaseInstance (context, uniformSetup, definitions, values)
962 LinearDerivateCaseInstance::~LinearDerivateCaseInstance (void)
966 bool LinearDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
968 const tcu::Vec4 xScale = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
969 const tcu::Vec4 yScale = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
970 const tcu::Vec4 surfaceThreshold = getSurfaceThreshold() / abs(m_values.derivScale);
972 if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
974 const bool isX = isDfdxFunc(m_definitions.func);
975 const float div = isX ? float(result.getWidth()) : float(result.getHeight());
976 const tcu::Vec4 scale = isX ? xScale : yScale;
977 tcu::Vec4 reference = ((m_values.coordMax - m_values.coordMin) / div);
978 const tcu::Vec4 opThreshold = getDerivateThreshold(m_definitions.precision, m_values.coordMin, m_values.coordMax, reference);
979 const tcu::Vec4 threshold = max(surfaceThreshold, opThreshold);
980 const int numComps = glu::getDataTypeFloatScalars(m_definitions.dataType);
982 /* adjust the reference value for the correct dfdx or dfdy sample adjacency */
983 reference = reference * scale;
985 m_context.getTestContext().getLog()
986 << tcu::TestLog::Message
987 << "Verifying result image.\n"
988 << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
989 << tcu::TestLog::EndMessage;
991 // short circuit if result is strictly within the normal value error bounds.
992 // This improves performance significantly.
993 if (verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
994 reference, threshold, m_values.derivScale, m_values.derivBias,
997 m_context.getTestContext().getLog()
998 << tcu::TestLog::Message
999 << "No incorrect derivatives found, result valid."
1000 << tcu::TestLog::EndMessage;
1005 // some pixels exceed error bounds calculated for normal values. Verify that these
1006 // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1008 m_context.getTestContext().getLog()
1009 << tcu::TestLog::Message
1010 << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
1011 << "\tVerifying each result derivative is within its range of legal result values."
1012 << tcu::TestLog::EndMessage;
1015 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1016 const float w = float(viewportSize.x());
1017 const float h = float(viewportSize.y());
1018 const tcu::Vec4 valueRamp = (m_values.coordMax - m_values.coordMin);
1019 Linear2DFunctionEvaluator function;
1021 function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_values.coordMin.x()));
1022 function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_values.coordMin.y()));
1023 function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_values.coordMin.z() + m_values.coordMin.z()) / 2.0f);
1024 function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_values.coordMax.w() + m_values.coordMax.w()) / 2.0f);
1026 return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), result, errorMask,
1027 m_definitions.dataType, m_definitions.precision, m_values.derivScale,
1028 m_values.derivBias, surfaceThreshold, m_definitions.func,
1034 DE_ASSERT(isFwidthFunc(m_definitions.func));
1035 const float w = float(result.getWidth());
1036 const float h = float(result.getHeight());
1038 const tcu::Vec4 dx = ((m_values.coordMax - m_values.coordMin) / w) * xScale;
1039 const tcu::Vec4 dy = ((m_values.coordMax - m_values.coordMin) / h) * yScale;
1040 const tcu::Vec4 reference = tcu::abs(dx) + tcu::abs(dy);
1041 const tcu::Vec4 dxThreshold = getDerivateThreshold(m_definitions.precision, m_values.coordMin*xScale, m_values.coordMax*xScale, dx);
1042 const tcu::Vec4 dyThreshold = getDerivateThreshold(m_definitions.precision, m_values.coordMin*yScale, m_values.coordMax*yScale, dy);
1043 const tcu::Vec4 threshold = max(surfaceThreshold, max(dxThreshold, dyThreshold));
1045 return verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
1046 reference, threshold, m_values.derivScale, m_values.derivBias);
1050 // LinearDerivateCase
1052 class LinearDerivateCase : public TriangleDerivateCase
1055 LinearDerivateCase (tcu::TestContext& testCtx,
1056 const std::string& name,
1057 const std::string& description,
1060 glu::Precision precision,
1061 SurfaceType surfaceType,
1063 const std::string& fragmentSrcTmpl,
1064 BaseUniformType usedDefaultUniform);
1065 virtual ~LinearDerivateCase (void);
1067 virtual void initPrograms (vk::SourceCollections& programCollection) const;
1068 virtual TestInstance* createInstance (Context& context) const;
1071 const std::string m_fragmentTmpl;
1074 LinearDerivateCase::LinearDerivateCase (tcu::TestContext& testCtx,
1075 const std::string& name,
1076 const std::string& description,
1079 glu::Precision precision,
1080 SurfaceType surfaceType,
1082 const std::string& fragmentSrcTmpl,
1083 BaseUniformType usedDefaultUniform)
1084 : TriangleDerivateCase (testCtx, name, description, new LinearDerivateUniformSetup(false, usedDefaultUniform))
1085 , m_fragmentTmpl (fragmentSrcTmpl)
1087 m_definitions.func = func;
1088 m_definitions.dataType = type;
1089 m_definitions.precision = precision;
1090 m_definitions.coordDataType = m_definitions.dataType;
1091 m_definitions.coordPrecision = m_definitions.precision;
1092 m_definitions.surfaceType = surfaceType;
1093 m_definitions.numSamples = numSamples;
1096 LinearDerivateCase::~LinearDerivateCase (void)
1100 TestInstance* LinearDerivateCase::createInstance (Context& context) const
1102 DE_ASSERT(m_uniformSetup != DE_NULL);
1103 return new LinearDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values);
1106 void LinearDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
1108 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1109 const float w = float(viewportSize.x());
1110 const float h = float(viewportSize.y());
1111 const bool packToInt = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
1112 map<string, string> fragmentParams;
1114 fragmentParams["OUTPUT_TYPE"] = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
1115 fragmentParams["OUTPUT_PREC"] = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
1116 fragmentParams["PRECISION"] = glu::getPrecisionName(m_definitions.precision);
1117 fragmentParams["DATATYPE"] = glu::getDataTypeName(m_definitions.dataType);
1118 fragmentParams["FUNC"] = getDerivateFuncName(m_definitions.func);
1122 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
1123 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
1124 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
1125 /* TYPE_FLOAT */ "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
1129 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
1130 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
1131 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
1132 /* TYPE_FLOAT */ "vec4(res, 0.0, 0.0, 1.0)";
1135 std::string fragmentSrc = tcu::StringTemplate(m_fragmentTmpl).specialize(fragmentParams);
1136 programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
1137 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
1139 switch (m_definitions.precision)
1141 case glu::PRECISION_HIGHP:
1142 m_values.coordMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
1143 m_values.coordMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
1146 case glu::PRECISION_MEDIUMP:
1147 m_values.coordMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
1148 m_values.coordMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
1151 case glu::PRECISION_LOWP:
1152 m_values.coordMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
1153 m_values.coordMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
1160 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
1162 // No scale or bias used for accuracy.
1163 m_values.derivScale = tcu::Vec4(1.0f);
1164 m_values.derivBias = tcu::Vec4(0.0f);
1168 // Compute scale - bias that normalizes to 0..1 range.
1169 const tcu::Vec4 dx = (m_values.coordMax - m_values.coordMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
1170 const tcu::Vec4 dy = (m_values.coordMax - m_values.coordMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
1172 if (isDfdxFunc(m_definitions.func))
1173 m_values.derivScale = 0.5f / dx;
1174 else if (isDfdyFunc(m_definitions.func))
1175 m_values.derivScale = 0.5f / dy;
1176 else if (isFwidthFunc(m_definitions.func))
1177 m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
1181 m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1185 // TextureDerivateCaseInstance
1187 class TextureDerivateCaseInstance : public TriangleDerivateCaseInstance
1190 TextureDerivateCaseInstance (Context& context,
1191 const UniformSetup& uniformSetup,
1192 const DerivateCaseDefinition& definitions,
1193 const DerivateCaseValues& values,
1194 const TextureCaseValues& textureValues);
1195 virtual ~TextureDerivateCaseInstance (void);
1197 virtual bool verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
1200 const TextureCaseValues& m_textureValues;
1203 TextureDerivateCaseInstance::TextureDerivateCaseInstance (Context& context,
1204 const UniformSetup& uniformSetup,
1205 const DerivateCaseDefinition& definitions,
1206 const DerivateCaseValues& values,
1207 const TextureCaseValues& textureValues)
1208 : TriangleDerivateCaseInstance (context, uniformSetup, definitions, values)
1209 , m_textureValues (textureValues)
1211 de::MovePtr<tcu::Texture2D> texture;
1213 // Lowp and mediump cases use RGBA16F format, while highp uses RGBA32F.
1215 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1216 const tcu::TextureFormat format = glu::mapGLInternalFormat(m_definitions.precision == glu::PRECISION_HIGHP ? GL_RGBA32F : GL_RGBA16F);
1218 texture = de::MovePtr<tcu::Texture2D>(new tcu::Texture2D(format, viewportSize.x(), viewportSize.y()));
1219 texture->allocLevel(0);
1222 // Fill with gradients.
1224 const tcu::PixelBufferAccess level0 = texture->getLevel(0);
1225 for (int y = 0; y < level0.getHeight(); y++)
1227 for (int x = 0; x < level0.getWidth(); x++)
1229 const float xf = (float(x)+0.5f) / float(level0.getWidth());
1230 const float yf = (float(y)+0.5f) / float(level0.getHeight());
1231 const tcu::Vec4 s = tcu::Vec4(xf, yf, (xf+yf)/2.0f, 1.0f - (xf+yf)/2.0f);
1233 level0.setPixel(m_textureValues.texValueMin + (m_textureValues.texValueMax - m_textureValues.texValueMin)*s, x, y);
1238 de::SharedPtr<TextureBinding> testTexture (new TextureBinding(texture.release(),
1239 tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE,
1240 tcu::Sampler::CLAMP_TO_EDGE,
1241 tcu::Sampler::CLAMP_TO_EDGE,
1242 tcu::Sampler::NEAREST,
1243 tcu::Sampler::NEAREST)));
1244 m_textures.push_back(testTexture);
1247 TextureDerivateCaseInstance::~TextureDerivateCaseInstance (void)
1251 bool TextureDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
1253 // \note Edges are ignored in comparison
1254 if (result.getWidth() < 2 || result.getHeight() < 2)
1255 throw tcu::NotSupportedError("Too small viewport");
1257 tcu::ConstPixelBufferAccess compareArea = tcu::getSubregion(result, 1, 1, result.getWidth()-2, result.getHeight()-2);
1258 tcu::PixelBufferAccess maskArea = tcu::getSubregion(errorMask, 1, 1, errorMask.getWidth()-2, errorMask.getHeight()-2);
1259 const tcu::Vec4 xScale = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
1260 const tcu::Vec4 yScale = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
1261 const float w = float(result.getWidth());
1262 const float h = float(result.getHeight());
1264 const tcu::Vec4 surfaceThreshold = getSurfaceThreshold() / abs(m_values.derivScale);
1266 if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
1268 const bool isX = isDfdxFunc(m_definitions.func);
1269 const float div = isX ? w : h;
1270 const tcu::Vec4 scale = isX ? xScale : yScale;
1271 tcu::Vec4 reference = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / div);
1272 const tcu::Vec4 opThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin, m_textureValues.texValueMax, reference);
1273 const tcu::Vec4 threshold = max(surfaceThreshold, opThreshold);
1274 const int numComps = glu::getDataTypeFloatScalars(m_definitions.dataType);
1276 /* adjust the reference value for the correct dfdx or dfdy sample adjacency */
1277 reference = reference * scale;
1279 m_context.getTestContext().getLog()
1280 << tcu::TestLog::Message
1281 << "Verifying result image.\n"
1282 << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
1283 << tcu::TestLog::EndMessage;
1285 // short circuit if result is strictly within the normal value error bounds.
1286 // This improves performance significantly.
1287 if (verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
1288 reference, threshold, m_values.derivScale, m_values.derivBias,
1291 m_context.getTestContext().getLog()
1292 << tcu::TestLog::Message
1293 << "No incorrect derivatives found, result valid."
1294 << tcu::TestLog::EndMessage;
1299 // some pixels exceed error bounds calculated for normal values. Verify that these
1300 // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1302 m_context.getTestContext().getLog()
1303 << tcu::TestLog::Message
1304 << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
1305 << "\tVerifying each result derivative is within its range of legal result values."
1306 << tcu::TestLog::EndMessage;
1309 const tcu::Vec4 valueRamp = (m_textureValues.texValueMax - m_textureValues.texValueMin);
1310 Linear2DFunctionEvaluator function;
1312 function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_textureValues.texValueMin.x()));
1313 function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_textureValues.texValueMin.y()));
1314 function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_textureValues.texValueMin.z() + m_textureValues.texValueMin.z()) / 2.0f);
1315 function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_textureValues.texValueMax.w() + m_textureValues.texValueMax.w()) / 2.0f);
1317 return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), compareArea, maskArea,
1318 m_definitions.dataType, m_definitions.precision, m_values.derivScale,
1319 m_values.derivBias, surfaceThreshold, m_definitions.func,
1325 DE_ASSERT(isFwidthFunc(m_definitions.func));
1326 const tcu::Vec4 dx = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / w) * xScale;
1327 const tcu::Vec4 dy = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / h) * yScale;
1328 const tcu::Vec4 reference = tcu::abs(dx) + tcu::abs(dy);
1329 const tcu::Vec4 dxThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*xScale, m_textureValues.texValueMax*xScale, dx);
1330 const tcu::Vec4 dyThreshold = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*yScale, m_textureValues.texValueMax*yScale, dy);
1331 const tcu::Vec4 threshold = max(surfaceThreshold, max(dxThreshold, dyThreshold));
1333 return verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
1334 reference, threshold, m_values.derivScale, m_values.derivBias);
1338 // TextureDerivateCase
1340 class TextureDerivateCase : public TriangleDerivateCase
1343 TextureDerivateCase (tcu::TestContext& testCtx,
1344 const std::string& name,
1345 const std::string& description,
1348 glu::Precision precision,
1349 SurfaceType surfaceType,
1351 virtual ~TextureDerivateCase (void);
1353 virtual void initPrograms (vk::SourceCollections& programCollection) const;
1354 virtual TestInstance* createInstance (Context& context) const;
1357 mutable TextureCaseValues m_textureValues;
1360 TextureDerivateCase::TextureDerivateCase (tcu::TestContext& testCtx,
1361 const std::string& name,
1362 const std::string& description,
1365 glu::Precision precision,
1366 SurfaceType surfaceType,
1368 : TriangleDerivateCase (testCtx, name, description, new DerivateUniformSetup(true))
1370 m_definitions.dataType = type;
1371 m_definitions.func = func;
1372 m_definitions.precision = precision;
1373 m_definitions.coordDataType = glu::TYPE_FLOAT_VEC2;
1374 m_definitions.coordPrecision = glu::PRECISION_HIGHP;
1375 m_definitions.surfaceType = surfaceType;
1376 m_definitions.numSamples = numSamples;
1379 TextureDerivateCase::~TextureDerivateCase (void)
1383 TestInstance* TextureDerivateCase::createInstance (Context& context) const
1385 DE_ASSERT(m_uniformSetup != DE_NULL);
1386 return new TextureDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values, m_textureValues);
1389 void TextureDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
1393 const char* fragmentTmpl =
1395 "layout(location = 0) in highp vec2 v_coord;\n"
1396 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1397 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1398 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1399 "layout(binding = 2) uniform ${PRECISION} sampler2D u_sampler;\n"
1400 "void main (void)\n"
1402 " ${PRECISION} vec4 tex = texture(u_sampler, v_coord);\n"
1403 " ${PRECISION} ${DATATYPE} res = ${FUNC}(tex${SWIZZLE}) * u_scale + u_bias;\n"
1404 " o_color = ${CAST_TO_OUTPUT};\n"
1407 const bool packToInt = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
1408 map<string, string> fragmentParams;
1410 fragmentParams["OUTPUT_TYPE"] = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
1411 fragmentParams["OUTPUT_PREC"] = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
1412 fragmentParams["PRECISION"] = glu::getPrecisionName(m_definitions.precision);
1413 fragmentParams["DATATYPE"] = glu::getDataTypeName(m_definitions.dataType);
1414 fragmentParams["FUNC"] = getDerivateFuncName(m_definitions.func);
1415 fragmentParams["SWIZZLE"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "" :
1416 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? ".xyz" :
1417 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? ".xy" :
1418 /* TYPE_FLOAT */ ".x";
1422 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
1423 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
1424 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
1425 /* TYPE_FLOAT */ "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
1429 fragmentParams["CAST_TO_OUTPUT"] = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
1430 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
1431 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
1432 /* TYPE_FLOAT */ "vec4(res, 0.0, 0.0, 1.0)";
1435 std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
1436 programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
1437 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
1440 // Texture size matches viewport and nearest sampling is used. Thus texture sampling
1441 // is equal to just interpolating the texture value range.
1443 // Determine value range for texture.
1445 switch (m_definitions.precision)
1447 case glu::PRECISION_HIGHP:
1448 m_textureValues.texValueMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
1449 m_textureValues.texValueMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
1452 case glu::PRECISION_MEDIUMP:
1453 m_textureValues.texValueMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
1454 m_textureValues.texValueMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
1457 case glu::PRECISION_LOWP:
1458 m_textureValues.texValueMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
1459 m_textureValues.texValueMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
1466 // Texture coordinates
1467 m_values.coordMin = tcu::Vec4(0.0f);
1468 m_values.coordMax = tcu::Vec4(1.0f);
1470 if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
1472 // No scale or bias used for accuracy.
1473 m_values.derivScale = tcu::Vec4(1.0f);
1474 m_values.derivBias = tcu::Vec4(0.0f);
1478 // Compute scale - bias that normalizes to 0..1 range.
1479 const tcu::UVec2 viewportSize (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
1480 const float w = float(viewportSize.x());
1481 const float h = float(viewportSize.y());
1482 const tcu::Vec4 dx = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
1483 const tcu::Vec4 dy = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
1485 if (isDfdxFunc(m_definitions.func))
1486 m_values.derivScale = 0.5f / dx;
1487 else if (isDfdyFunc(m_definitions.func))
1488 m_values.derivScale = 0.5f / dy;
1489 else if (isFwidthFunc(m_definitions.func))
1490 m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
1494 m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1498 // ShaderDerivateTests
1500 class ShaderDerivateTests : public tcu::TestCaseGroup
1503 ShaderDerivateTests (tcu::TestContext& testCtx);
1504 virtual ~ShaderDerivateTests (void);
1506 virtual void init (void);
1509 ShaderDerivateTests (const ShaderDerivateTests&); // not allowed!
1510 ShaderDerivateTests& operator= (const ShaderDerivateTests&); // not allowed!
1513 ShaderDerivateTests::ShaderDerivateTests (tcu::TestContext& testCtx)
1514 : TestCaseGroup(testCtx, "derivate", "Derivate Function Tests")
1518 ShaderDerivateTests::~ShaderDerivateTests (void)
1525 DerivateFunc function;
1526 glu::DataType dataType;
1527 glu::Precision precision;
1529 FunctionSpec (const std::string& name_, DerivateFunc function_, glu::DataType dataType_, glu::Precision precision_)
1531 , function (function_)
1532 , dataType (dataType_)
1533 , precision (precision_)
1538 void ShaderDerivateTests::init (void)
1543 const char* description;
1545 BaseUniformType usedDefaultUniform;
1546 } s_linearDerivateCases[] =
1550 "Basic derivate of linearly interpolated argument",
1553 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1554 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1555 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1556 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1557 "void main (void)\n"
1559 " ${PRECISION} ${DATATYPE} res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1560 " o_color = ${CAST_TO_OUTPUT};\n"
1567 "Derivate of linear function argument",
1570 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1571 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1572 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1573 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1575 "${PRECISION} ${DATATYPE} computeRes (${PRECISION} ${DATATYPE} value)\n"
1577 " return ${FUNC}(v_coord) * u_scale + u_bias;\n"
1580 "void main (void)\n"
1582 " ${PRECISION} ${DATATYPE} res = computeRes(v_coord);\n"
1583 " o_color = ${CAST_TO_OUTPUT};\n"
1590 "Derivate of linearly interpolated value in static if",
1593 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1594 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1595 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1596 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1597 "void main (void)\n"
1599 " ${PRECISION} ${DATATYPE} res;\n"
1601 " res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
1603 " res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1604 " o_color = ${CAST_TO_OUTPUT};\n"
1611 "Derivate of linearly interpolated value in static loop",
1614 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1615 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1616 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1617 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1618 "void main (void)\n"
1620 " ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1621 " for (int i = 0; i < 2; i++)\n"
1622 " res += ${FUNC}(v_coord * float(i));\n"
1623 " res = res * u_scale + u_bias;\n"
1624 " o_color = ${CAST_TO_OUTPUT};\n"
1631 "Derivate of linearly interpolated value in static switch",
1634 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1635 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1636 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1637 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1638 "void main (void)\n"
1640 " ${PRECISION} ${DATATYPE} res;\n"
1643 " case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias; break;\n"
1644 " case 1: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n"
1646 " o_color = ${CAST_TO_OUTPUT};\n"
1653 "Derivate of linearly interpolated value in uniform if",
1656 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1657 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1658 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1659 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1660 "layout(binding = 2, std140) uniform Ui_true { bool ub_true; };\n"
1661 "void main (void)\n"
1663 " ${PRECISION} ${DATATYPE} res;\n"
1665 " res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
1667 " res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
1668 " o_color = ${CAST_TO_OUTPUT};\n"
1675 "Derivate of linearly interpolated value in uniform loop",
1678 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1679 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1680 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1681 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1682 "layout(binding = 2, std140) uniform Ui_two { int ui_two; };\n"
1683 "void main (void)\n"
1685 " ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
1686 " for (int i = 0; i < ui_two; i++)\n"
1687 " res += ${FUNC}(v_coord * float(i));\n"
1688 " res = res * u_scale + u_bias;\n"
1689 " o_color = ${CAST_TO_OUTPUT};\n"
1696 "Derivate of linearly interpolated value in uniform switch",
1699 "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
1700 "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
1701 "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
1702 "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
1703 "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
1704 "void main (void)\n"
1706 " ${PRECISION} ${DATATYPE} res;\n"
1707 " switch (ui_one)\n"
1709 " case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias; break;\n"
1710 " case 1: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n"
1712 " o_color = ${CAST_TO_OUTPUT};\n"
1722 SurfaceType surfaceType;
1726 { "fbo", SURFACETYPE_UNORM_FBO, 0 },
1727 { "fbo_msaa2", SURFACETYPE_UNORM_FBO, 2 },
1728 { "fbo_msaa4", SURFACETYPE_UNORM_FBO, 4 },
1729 { "fbo_float", SURFACETYPE_FLOAT_FBO, 0 },
1735 SurfaceType surfaceType;
1737 } s_textureConfigs[] =
1739 { "basic", SURFACETYPE_UNORM_FBO, 0 },
1740 { "msaa4", SURFACETYPE_UNORM_FBO, 4 },
1741 { "float", SURFACETYPE_FLOAT_FBO, 0 },
1744 // .dfdx[fine|coarse], .dfdy[fine|coarse], .fwidth[fine|coarse]
1745 for (int funcNdx = 0; funcNdx < DERIVATE_LAST; funcNdx++)
1747 const DerivateFunc function = DerivateFunc(funcNdx);
1748 de::MovePtr<tcu::TestCaseGroup> functionGroup (new tcu::TestCaseGroup(m_testCtx, getDerivateFuncCaseName(function), getDerivateFuncName(function)));
1750 // .constant - no precision variants, checks that derivate of constant arguments is 0
1752 de::MovePtr<tcu::TestCaseGroup> constantGroup (new tcu::TestCaseGroup(m_testCtx, "constant", "Derivate of constant argument"));
1754 for (int vecSize = 1; vecSize <= 4; vecSize++)
1756 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1757 constantGroup->addChild(new ConstantDerivateCase(m_testCtx, glu::getDataTypeName(dataType), "", function, dataType));
1760 functionGroup->addChild(constantGroup.release());
1763 // Cases based on LinearDerivateCase
1764 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_linearDerivateCases); caseNdx++)
1766 de::MovePtr<tcu::TestCaseGroup> linearCaseGroup (new tcu::TestCaseGroup(m_testCtx, s_linearDerivateCases[caseNdx].name, s_linearDerivateCases[caseNdx].description));
1767 const char* source = s_linearDerivateCases[caseNdx].source;
1769 for (int vecSize = 1; vecSize <= 4; vecSize++)
1771 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1773 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1774 const glu::Precision precision = glu::Precision(precNdx);
1775 const SurfaceType surfaceType = SURFACETYPE_UNORM_FBO;
1776 const int numSamples = 0;
1777 std::ostringstream caseName;
1779 if (caseNdx != 0 && precision == glu::PRECISION_LOWP)
1780 continue; // Skip as lowp doesn't actually produce any bits when rendered to default FB.
1782 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1784 linearCaseGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples, source, s_linearDerivateCases[caseNdx].usedDefaultUniform));
1788 functionGroup->addChild(linearCaseGroup.release());
1792 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_fboConfigs); caseNdx++)
1794 de::MovePtr<tcu::TestCaseGroup> fboGroup (new tcu::TestCaseGroup(m_testCtx, s_fboConfigs[caseNdx].name, "Derivate usage when rendering into FBO"));
1795 const char* source = s_linearDerivateCases[0].source; // use source from .linear group
1796 const SurfaceType surfaceType = s_fboConfigs[caseNdx].surfaceType;
1797 const int numSamples = s_fboConfigs[caseNdx].numSamples;
1799 for (int vecSize = 1; vecSize <= 4; vecSize++)
1801 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1803 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1804 const glu::Precision precision = glu::Precision(precNdx);
1805 std::ostringstream caseName;
1807 if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
1808 continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1810 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1812 fboGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples, source, U_LAST));
1816 functionGroup->addChild(fboGroup.release());
1821 de::MovePtr<tcu::TestCaseGroup> textureGroup (new tcu::TestCaseGroup(m_testCtx, "texture", "Derivate of texture lookup result"));
1823 for (int texCaseNdx = 0; texCaseNdx < DE_LENGTH_OF_ARRAY(s_textureConfigs); texCaseNdx++)
1825 de::MovePtr<tcu::TestCaseGroup> caseGroup (new tcu::TestCaseGroup(m_testCtx, s_textureConfigs[texCaseNdx].name, ""));
1826 const SurfaceType surfaceType = s_textureConfigs[texCaseNdx].surfaceType;
1827 const int numSamples = s_textureConfigs[texCaseNdx].numSamples;
1829 for (int vecSize = 1; vecSize <= 4; vecSize++)
1831 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1833 const glu::DataType dataType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1834 const glu::Precision precision = glu::Precision(precNdx);
1835 std::ostringstream caseName;
1837 if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
1838 continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1840 caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
1842 caseGroup->addChild(new TextureDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples));
1846 textureGroup->addChild(caseGroup.release());
1849 functionGroup->addChild(textureGroup.release());
1852 addChild(functionGroup.release());
1858 tcu::TestCaseGroup* createDerivateTests (tcu::TestContext& testCtx)
1860 return new ShaderDerivateTests(testCtx);