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