1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Multisample interpolation tests 22 *//*--------------------------------------------------------------------*/ 23 24#include "es31fShaderMultisampleInterpolationTests.hpp" 25#include "es31fMultisampleShaderRenderCase.hpp" 26#include "tcuTestLog.hpp" 27#include "tcuRGBA.hpp" 28#include "tcuSurface.hpp" 29#include "tcuRenderTarget.hpp" 30#include "gluContextInfo.hpp" 31#include "gluShaderProgram.hpp" 32#include "gluRenderContext.hpp" 33#include "glwFunctions.hpp" 34#include "glwEnums.hpp" 35#include "deStringUtil.hpp" 36#include "deMath.h" 37 38#include <map> 39 40namespace deqp 41{ 42namespace gles31 43{ 44namespace Functional 45{ 46namespace 47{ 48 49 50static bool verifyGreenImage (const tcu::Surface& image, tcu::TestLog& log) 51{ 52 bool error = false; 53 54 log << tcu::TestLog::Message << "Verifying result image, expecting green." << tcu::TestLog::EndMessage; 55 56 // all pixels must be green 57 58 for (int y = 0; y < image.getHeight(); ++y) 59 for (int x = 0; x < image.getWidth(); ++x) 60 { 61 const tcu::RGBA color = image.getPixel(x, y); 62 const int greenThreshold = 8; 63 64 if (color.getRed() > 0 || color.getGreen() < 255-greenThreshold || color.getBlue() > 0) 65 error = true; 66 } 67 68 if (error) 69 log << tcu::TestLog::Image("ResultImage", "Result Image", image.getAccess()) 70 << tcu::TestLog::Message 71 << "Image verification failed." 72 << tcu::TestLog::EndMessage; 73 else 74 log << tcu::TestLog::Image("ResultImage", "Result Image", image.getAccess()) 75 << tcu::TestLog::Message 76 << "Image verification passed." 77 << tcu::TestLog::EndMessage; 78 79 return !error; 80} 81 82class MultisampleShadeCountRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase 83{ 84public: 85 MultisampleShadeCountRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); 86 virtual ~MultisampleShadeCountRenderCase (void); 87 88 void init (void); 89 90private: 91 enum 92 { 93 RENDER_SIZE = 128 94 }; 95 96 virtual std::string getIterationDescription (int iteration) const; 97 bool verifyImage (const tcu::Surface& resultImage); 98}; 99 100MultisampleShadeCountRenderCase::MultisampleShadeCountRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) 101 : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_PER_ITERATION_SHADER) 102{ 103 m_numIterations = -1; // must be set by deriving class 104} 105 106MultisampleShadeCountRenderCase::~MultisampleShadeCountRenderCase (void) 107{ 108} 109 110void MultisampleShadeCountRenderCase::init (void) 111{ 112 // requirements 113 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation")) 114 throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension"); 115 116 MultisampleShaderRenderUtil::MultisampleRenderCase::init(); 117} 118 119std::string MultisampleShadeCountRenderCase::getIterationDescription (int iteration) const 120{ 121 // must be overriden 122 DE_UNREF(iteration); 123 DE_ASSERT(false); 124 return ""; 125} 126 127bool MultisampleShadeCountRenderCase::verifyImage (const tcu::Surface& resultImage) 128{ 129 const bool isSingleSampleTarget = (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1); 130 const int numShadesRequired = (isSingleSampleTarget) ? (2) : (m_numTargetSamples + 1); 131 const int rareThreshold = 100; 132 int rareCount = 0; 133 std::map<deUint32, int> shadeFrequency; 134 135 m_testCtx.getLog() 136 << tcu::TestLog::Image("ResultImage", "Result Image", resultImage.getAccess()) 137 << tcu::TestLog::Message 138 << "Verifying image has (at least) " << numShadesRequired << " different shades.\n" 139 << "Excluding pixels with no full coverage (pixels on the shared edge of the triangle pair)." 140 << tcu::TestLog::EndMessage; 141 142 for (int y = 0; y < RENDER_SIZE; ++y) 143 for (int x = 0; x < RENDER_SIZE; ++x) 144 { 145 const tcu::RGBA color = resultImage.getPixel(x, y); 146 const deUint32 packed = ((deUint32)color.getRed()) + ((deUint32)color.getGreen() << 8) + ((deUint32)color.getGreen() << 16); 147 148 // on the triangle edge, skip 149 if (x == y) 150 continue; 151 152 if (shadeFrequency.find(packed) == shadeFrequency.end()) 153 shadeFrequency[packed] = 1; 154 else 155 shadeFrequency[packed] = shadeFrequency[packed] + 1; 156 } 157 158 for (std::map<deUint32, int>::const_iterator it = shadeFrequency.begin(); it != shadeFrequency.end(); ++it) 159 if (it->second < rareThreshold) 160 rareCount++; 161 162 m_testCtx.getLog() 163 << tcu::TestLog::Message 164 << "Found " << (int)shadeFrequency.size() << " different shades.\n" 165 << "\tRare (less than " << rareThreshold << " pixels): " << rareCount << "\n" 166 << "\tCommon: " << (int)shadeFrequency.size() - rareCount << "\n" 167 << tcu::TestLog::EndMessage; 168 169 if ((int)shadeFrequency.size() < numShadesRequired) 170 { 171 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage; 172 return false; 173 } 174 return true; 175} 176 177class SampleQualifierRenderCase : public MultisampleShadeCountRenderCase 178{ 179public: 180 SampleQualifierRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); 181 ~SampleQualifierRenderCase (void); 182 183 void init (void); 184 185private: 186 std::string genVertexSource (int numTargetSamples) const; 187 std::string genFragmentSource (int numTargetSamples) const; 188 std::string getIterationDescription (int iteration) const; 189}; 190 191SampleQualifierRenderCase::SampleQualifierRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) 192 : MultisampleShadeCountRenderCase(context, name, description, numSamples, target) 193{ 194 m_numIterations = 6; // float, vec2, .3, .4, array, struct 195} 196 197SampleQualifierRenderCase::~SampleQualifierRenderCase (void) 198{ 199} 200 201void SampleQualifierRenderCase::init (void) 202{ 203 const bool isSingleSampleTarget = (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1); 204 205 // test purpose and expectations 206 if (isSingleSampleTarget) 207 { 208 m_testCtx.getLog() 209 << tcu::TestLog::Message 210 << "Verifying that a sample-qualified varying is given different values for different samples.\n" 211 << " Render high-frequency function, map result to black/white.\n" 212 << " => Resulting image image should contain both black and white pixels.\n" 213 << tcu::TestLog::EndMessage; 214 } 215 else 216 { 217 m_testCtx.getLog() 218 << tcu::TestLog::Message 219 << "Verifying that a sample-qualified varying is given different values for different samples.\n" 220 << " Render high-frequency function, map result to black/white.\n" 221 << " => Resulting image should contain n+1 shades of gray, n = sample count.\n" 222 << tcu::TestLog::EndMessage; 223 } 224 225 MultisampleShadeCountRenderCase::init(); 226} 227 228std::string SampleQualifierRenderCase::genVertexSource (int numTargetSamples) const 229{ 230 DE_UNREF(numTargetSamples); 231 232 std::ostringstream buf; 233 234 buf << "#version 310 es\n" 235 "#extension GL_OES_shader_multisample_interpolation : require\n" 236 "in highp vec4 a_position;\n"; 237 238 if (m_iteration == 0) 239 buf << "sample out highp float v_input;\n"; 240 else if (m_iteration == 1) 241 buf << "sample out highp vec2 v_input;\n"; 242 else if (m_iteration == 2) 243 buf << "sample out highp vec3 v_input;\n"; 244 else if (m_iteration == 3) 245 buf << "sample out highp vec4 v_input;\n"; 246 else if (m_iteration == 4) 247 buf << "sample out highp float[2] v_input;\n"; 248 else if (m_iteration == 5) 249 buf << "struct VaryingStruct { highp float a; highp float b; };\n" 250 "sample out VaryingStruct v_input;\n"; 251 else 252 DE_ASSERT(false); 253 254 buf << "void main (void)\n" 255 "{\n" 256 " gl_Position = a_position;\n"; 257 258 if (m_iteration == 0) 259 buf << " v_input = a_position.x + exp(a_position.y) + step(0.9, a_position.x)*step(a_position.y, -0.9)*8.0;\n"; 260 else if (m_iteration == 1) 261 buf << " v_input = a_position.xy;\n"; 262 else if (m_iteration == 2) 263 buf << " v_input = vec3(a_position.xy, a_position.x * 2.0 - a_position.y);\n"; 264 else if (m_iteration == 3) 265 buf << " v_input = vec4(a_position.xy, a_position.x * 2.0 - a_position.y, a_position.x*a_position.y);\n"; 266 else if (m_iteration == 4) 267 buf << " v_input[0] = a_position.x;\n" 268 " v_input[1] = a_position.y;\n"; 269 else if (m_iteration == 5) 270 buf << " v_input.a = a_position.x;\n" 271 " v_input.b = a_position.y;\n"; 272 else 273 DE_ASSERT(false); 274 275 buf << "}"; 276 277 return buf.str(); 278} 279 280std::string SampleQualifierRenderCase::genFragmentSource (int numTargetSamples) const 281{ 282 DE_UNREF(numTargetSamples); 283 284 std::ostringstream buf; 285 286 buf << "#version 310 es\n" 287 "#extension GL_OES_shader_multisample_interpolation : require\n"; 288 289 if (m_iteration == 0) 290 buf << "sample in highp float v_input;\n"; 291 else if (m_iteration == 1) 292 buf << "sample in highp vec2 v_input;\n"; 293 else if (m_iteration == 2) 294 buf << "sample in highp vec3 v_input;\n"; 295 else if (m_iteration == 3) 296 buf << "sample in highp vec4 v_input;\n"; 297 else if (m_iteration == 4) 298 buf << "sample in highp float[2] v_input;\n"; 299 else if (m_iteration == 5) 300 buf << "struct VaryingStruct { highp float a; highp float b; };\n" 301 "sample in VaryingStruct v_input;\n"; 302 else 303 DE_ASSERT(false); 304 305 buf << "layout(location = 0) out mediump vec4 fragColor;\n" 306 "void main (void)\n" 307 "{\n"; 308 309 if (m_iteration == 0) 310 buf << " highp float field = exp(v_input) + v_input*v_input;\n"; 311 else if (m_iteration == 1) 312 buf << " highp float field = dot(v_input.xy, v_input.xy) + dot(21.0 * v_input.xx, sin(3.1 * v_input.xy));\n"; 313 else if (m_iteration == 2) 314 buf << " highp float field = dot(v_input.xy, v_input.xy) + dot(21.0 * v_input.zx, sin(3.1 * v_input.zy));\n"; 315 else if (m_iteration == 3) 316 buf << " highp float field = dot(v_input.xy, v_input.zw) + dot(21.0 * v_input.zy, sin(3.1 * v_input.zw));\n"; 317 else if (m_iteration == 4) 318 buf << " highp float field = dot(vec2(v_input[0], v_input[1]), vec2(v_input[0], v_input[1])) + dot(21.0 * vec2(v_input[0]), sin(3.1 * vec2(v_input[0], v_input[1])));\n"; 319 else if (m_iteration == 5) 320 buf << " highp float field = dot(vec2(v_input.a, v_input.b), vec2(v_input.a, v_input.b)) + dot(21.0 * vec2(v_input.a), sin(3.1 * vec2(v_input.a, v_input.b)));\n"; 321 else 322 DE_ASSERT(false); 323 324 buf << " fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" 325 "\n" 326 " if (fract(field) > 0.5)\n" 327 " fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n" 328 "}"; 329 330 return buf.str(); 331} 332 333std::string SampleQualifierRenderCase::getIterationDescription (int iteration) const 334{ 335 if (iteration == 0) 336 return "Test with float varying"; 337 else if (iteration == 1) 338 return "Test with vec2 varying"; 339 else if (iteration == 2) 340 return "Test with vec3 varying"; 341 else if (iteration == 3) 342 return "Test with vec4 varying"; 343 else if (iteration == 4) 344 return "Test with array varying"; 345 else if (iteration == 5) 346 return "Test with struct varying"; 347 348 DE_ASSERT(false); 349 return ""; 350} 351 352class InterpolateAtSampleRenderCase : public MultisampleShadeCountRenderCase 353{ 354public: 355 enum IndexingMode 356 { 357 INDEXING_STATIC, 358 INDEXING_DYNAMIC, 359 360 INDEXING_LAST 361 }; 362 InterpolateAtSampleRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, IndexingMode mode); 363 ~InterpolateAtSampleRenderCase (void); 364 365 void init (void); 366 void preDraw (void); 367 368private: 369 std::string genVertexSource (int numTargetSamples) const; 370 std::string genFragmentSource (int numTargetSamples) const; 371 std::string getIterationDescription (int iteration) const; 372 373 const IndexingMode m_indexMode; 374}; 375 376InterpolateAtSampleRenderCase::InterpolateAtSampleRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, IndexingMode mode) 377 : MultisampleShadeCountRenderCase (context, name, description, numSamples, target) 378 , m_indexMode (mode) 379{ 380 DE_ASSERT(mode < INDEXING_LAST); 381 382 m_numIterations = 5; // float, vec2, .3, .4, array 383} 384 385InterpolateAtSampleRenderCase::~InterpolateAtSampleRenderCase (void) 386{ 387} 388 389void InterpolateAtSampleRenderCase::init (void) 390{ 391 const bool isSingleSampleTarget = (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1); 392 393 // test purpose and expectations 394 if (isSingleSampleTarget) 395 { 396 m_testCtx.getLog() 397 << tcu::TestLog::Message 398 << "Verifying that a interpolateAtSample returns different values for different samples.\n" 399 << " Render high-frequency function, map result to black/white.\n" 400 << " => Resulting image image should contain both black and white pixels.\n" 401 << tcu::TestLog::EndMessage; 402 } 403 else 404 { 405 m_testCtx.getLog() 406 << tcu::TestLog::Message 407 << "Verifying that a interpolateAtSample returns different values for different samples.\n" 408 << " Render high-frequency function, map result to black/white.\n" 409 << " => Resulting image should contain n+1 shades of gray, n = sample count.\n" 410 << tcu::TestLog::EndMessage; 411 } 412 413 MultisampleShadeCountRenderCase::init(); 414} 415 416void InterpolateAtSampleRenderCase::preDraw (void) 417{ 418 if (m_indexMode == INDEXING_DYNAMIC) 419 { 420 const deInt32 range = m_numTargetSamples; 421 const deInt32 offset = 1; 422 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 423 const deInt32 offsetLoc = gl.getUniformLocation(m_program->getProgram(), "u_offset"); 424 const deInt32 rangeLoc = gl.getUniformLocation(m_program->getProgram(), "u_range"); 425 426 if (offsetLoc == -1) 427 throw tcu::TestError("Location of u_offset was -1"); 428 if (rangeLoc == -1) 429 throw tcu::TestError("Location of u_range was -1"); 430 431 gl.uniform1i(offsetLoc, 0); 432 gl.uniform1i(rangeLoc, m_numTargetSamples); 433 GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms"); 434 435 m_testCtx.getLog() 436 << tcu::TestLog::Message 437 << "Set u_offset = " << offset << "\n" 438 << "Set u_range = " << range 439 << tcu::TestLog::EndMessage; 440 } 441} 442 443std::string InterpolateAtSampleRenderCase::genVertexSource (int numTargetSamples) const 444{ 445 DE_UNREF(numTargetSamples); 446 447 std::ostringstream buf; 448 449 buf << "#version 310 es\n" 450 "in highp vec4 a_position;\n"; 451 452 if (m_iteration == 0) 453 buf << "out highp float v_input;\n"; 454 else if (m_iteration == 1) 455 buf << "out highp vec2 v_input;\n"; 456 else if (m_iteration == 2) 457 buf << "out highp vec3 v_input;\n"; 458 else if (m_iteration == 3) 459 buf << "out highp vec4 v_input;\n"; 460 else if (m_iteration == 4) 461 buf << "out highp vec2[2] v_input;\n"; 462 else 463 DE_ASSERT(false); 464 465 buf << "void main (void)\n" 466 "{\n" 467 " gl_Position = a_position;\n"; 468 469 if (m_iteration == 0) 470 buf << " v_input = a_position.x + exp(a_position.y) + step(0.9, a_position.x)*step(a_position.y, -0.9)*8.0;\n"; 471 else if (m_iteration == 1) 472 buf << " v_input = a_position.xy;\n"; 473 else if (m_iteration == 2) 474 buf << " v_input = vec3(a_position.xy, a_position.x * 2.0 - a_position.y);\n"; 475 else if (m_iteration == 3) 476 buf << " v_input = vec4(a_position.xy, a_position.x * 2.0 - a_position.y, a_position.x*a_position.y);\n"; 477 else if (m_iteration == 4) 478 buf << " v_input[0] = a_position.yx + vec2(0.5, 0.5);\n" 479 " v_input[1] = a_position.xy;\n"; 480 else 481 DE_ASSERT(false); 482 483 buf << "}"; 484 485 return buf.str(); 486} 487 488std::string InterpolateAtSampleRenderCase::genFragmentSource (int numTargetSamples) const 489{ 490 std::ostringstream buf; 491 492 buf << "#version 310 es\n" 493 "#extension GL_OES_shader_multisample_interpolation : require\n"; 494 495 if (m_iteration == 0) 496 buf << "in highp float v_input;\n"; 497 else if (m_iteration == 1) 498 buf << "in highp vec2 v_input;\n"; 499 else if (m_iteration == 2) 500 buf << "in highp vec3 v_input;\n"; 501 else if (m_iteration == 3) 502 buf << "in highp vec4 v_input;\n"; 503 else if (m_iteration == 4) 504 buf << "in highp vec2[2] v_input;\n"; 505 else 506 DE_ASSERT(false); 507 508 buf << "layout(location = 0) out mediump vec4 fragColor;\n"; 509 510 if (m_indexMode == INDEXING_DYNAMIC) 511 buf << "uniform highp int u_offset;\n" 512 "uniform highp int u_range;\n"; 513 514 buf << "void main (void)\n" 515 "{\n" 516 " mediump int coverage = 0;\n" 517 "\n"; 518 519 if (m_indexMode == INDEXING_STATIC) 520 { 521 for (int ndx = 0; ndx < numTargetSamples; ++ndx) 522 { 523 if (m_iteration == 0) 524 buf << " highp float sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n"; 525 else if (m_iteration == 1) 526 buf << " highp vec2 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n"; 527 else if (m_iteration == 2) 528 buf << " highp vec3 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n"; 529 else if (m_iteration == 3) 530 buf << " highp vec4 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n"; 531 else if (m_iteration == 4) 532 buf << " highp vec2 sampleInput" << ndx << " = interpolateAtSample(v_input[1], " << ndx << ");\n"; 533 else 534 DE_ASSERT(false); 535 } 536 buf << "\n"; 537 538 for (int ndx = 0; ndx < numTargetSamples; ++ndx) 539 { 540 if (m_iteration == 0) 541 buf << " highp float field" << ndx << " = exp(sampleInput" << ndx << ") + sampleInput" << ndx << "*sampleInput" << ndx << ";\n"; 542 else if (m_iteration == 1 || m_iteration == 4) 543 buf << " highp float field" << ndx << " = dot(sampleInput" << ndx << ", sampleInput" << ndx << ") + dot(21.0 * sampleInput" << ndx << ".xx, sin(3.1 * sampleInput" << ndx << "));\n"; 544 else if (m_iteration == 2) 545 buf << " highp float field" << ndx << " = dot(sampleInput" << ndx << ".xy, sampleInput" << ndx << ".xy) + dot(21.0 * sampleInput" << ndx << ".zx, sin(3.1 * sampleInput" << ndx << ".zy));\n"; 546 else if (m_iteration == 3) 547 buf << " highp float field" << ndx << " = dot(sampleInput" << ndx << ".xy, sampleInput" << ndx << ".zw) + dot(21.0 * sampleInput" << ndx << ".zy, sin(3.1 * sampleInput" << ndx << ".zw));\n"; 548 else 549 DE_ASSERT(false); 550 } 551 buf << "\n"; 552 553 for (int ndx = 0; ndx < numTargetSamples; ++ndx) 554 buf << " if (fract(field" << ndx << ") <= 0.5)\n" 555 " ++coverage;\n"; 556 } 557 else if (m_indexMode == INDEXING_DYNAMIC) 558 { 559 buf << " for (int ndx = 0; ndx < " << numTargetSamples << "; ++ndx)\n" 560 " {\n"; 561 562 if (m_iteration == 0) 563 buf << " highp float sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n"; 564 else if (m_iteration == 1) 565 buf << " highp vec2 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n"; 566 else if (m_iteration == 2) 567 buf << " highp vec3 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n"; 568 else if (m_iteration == 3) 569 buf << " highp vec4 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n"; 570 else if (m_iteration == 4) 571 buf << " highp vec2 sampleInput = interpolateAtSample(v_input[1], (u_offset + ndx) % u_range);\n"; 572 else 573 DE_ASSERT(false); 574 575 if (m_iteration == 0) 576 buf << " highp float field = exp(sampleInput) + sampleInput*sampleInput;\n"; 577 else if (m_iteration == 1 || m_iteration == 4) 578 buf << " highp float field = dot(sampleInput, sampleInput) + dot(21.0 * sampleInput.xx, sin(3.1 * sampleInput));\n"; 579 else if (m_iteration == 2) 580 buf << " highp float field = dot(sampleInput.xy, sampleInput.xy) + dot(21.0 * sampleInput.zx, sin(3.1 * sampleInput.zy));\n"; 581 else if (m_iteration == 3) 582 buf << " highp float field = dot(sampleInput.xy, sampleInput.zw) + dot(21.0 * sampleInput.zy, sin(3.1 * sampleInput.zw));\n"; 583 else 584 DE_ASSERT(false); 585 586 buf << " if (fract(field) <= 0.5)\n" 587 " ++coverage;\n" 588 " }\n"; 589 } 590 591 buf << " fragColor = vec4(vec3(float(coverage) / float(" << numTargetSamples << ")), 1.0);\n" 592 "}"; 593 594 return buf.str(); 595} 596 597std::string InterpolateAtSampleRenderCase::getIterationDescription (int iteration) const 598{ 599 if (iteration == 0) 600 return "Test with float varying"; 601 else if (iteration < 4) 602 return "Test with vec" + de::toString(iteration+1) + " varying"; 603 else if (iteration == 4) 604 return "Test with array varying"; 605 606 DE_ASSERT(false); 607 return ""; 608} 609 610class SingleSampleInterpolateAtSampleCase : public MultisampleShaderRenderUtil::MultisampleRenderCase 611{ 612public: 613 enum SampleCase 614 { 615 SAMPLE_0 = 0, 616 SAMPLE_N, 617 618 SAMPLE_LAST 619 }; 620 621 SingleSampleInterpolateAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, SampleCase sampleCase); 622 virtual ~SingleSampleInterpolateAtSampleCase (void); 623 624 void init (void); 625 626private: 627 enum 628 { 629 RENDER_SIZE = 32 630 }; 631 632 std::string genVertexSource (int numTargetSamples) const; 633 std::string genFragmentSource (int numTargetSamples) const; 634 bool verifyImage (const tcu::Surface& resultImage); 635 636 const SampleCase m_sampleCase; 637}; 638 639SingleSampleInterpolateAtSampleCase::SingleSampleInterpolateAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, SampleCase sampleCase) 640 : MultisampleShaderRenderUtil::MultisampleRenderCase (context, name, description, numSamples, target, RENDER_SIZE) 641 , m_sampleCase (sampleCase) 642{ 643 DE_ASSERT(numSamples == 0); 644 DE_ASSERT(sampleCase < SAMPLE_LAST); 645} 646 647SingleSampleInterpolateAtSampleCase::~SingleSampleInterpolateAtSampleCase (void) 648{ 649} 650 651void SingleSampleInterpolateAtSampleCase::init (void) 652{ 653 // requirements 654 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation")) 655 throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension"); 656 if (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1) 657 throw tcu::NotSupportedError("Non-multisample framebuffer required"); 658 659 // test purpose and expectations 660 m_testCtx.getLog() 661 << tcu::TestLog::Message 662 << "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n" 663 << " Interpolate varying containing screen space location.\n" 664 << " => fract(screen space location) should be (about) (0.5, 0.5)\n" 665 << tcu::TestLog::EndMessage; 666 667 MultisampleShaderRenderUtil::MultisampleRenderCase::init(); 668} 669 670std::string SingleSampleInterpolateAtSampleCase::genVertexSource (int numTargetSamples) const 671{ 672 DE_UNREF(numTargetSamples); 673 674 std::ostringstream buf; 675 676 buf << "#version 310 es\n" 677 "in highp vec4 a_position;\n" 678 "out highp vec2 v_position;\n" 679 "void main (void)\n" 680 "{\n" 681 " gl_Position = a_position;\n" 682 " v_position = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n" 683 "}\n"; 684 685 return buf.str(); 686} 687 688std::string SingleSampleInterpolateAtSampleCase::genFragmentSource (int numTargetSamples) const 689{ 690 DE_UNREF(numTargetSamples); 691 692 std::ostringstream buf; 693 694 buf << "#version 310 es\n" 695 "#extension GL_OES_shader_multisample_interpolation : require\n" 696 "in highp vec2 v_position;\n" 697 "layout(location = 0) out mediump vec4 fragColor;\n" 698 "void main (void)\n" 699 "{\n" 700 " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n"; // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE) 701 702 if (m_sampleCase == SAMPLE_0) 703 { 704 buf << " highp vec2 samplePosition = interpolateAtSample(v_position, 0);\n" 705 " highp vec2 positionInsideAPixel = fract(samplePosition);\n" 706 "\n" 707 " if (abs(positionInsideAPixel.x - 0.5) <= threshold && abs(positionInsideAPixel.y - 0.5) <= threshold)\n" 708 " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 709 " else\n" 710 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 711 "}\n"; 712 } 713 else if (m_sampleCase == SAMPLE_N) 714 { 715 buf << " bool allOk = true;\n" 716 " for (int sampleNdx = 159; sampleNdx < 163; ++sampleNdx)\n" 717 " {\n" 718 " highp vec2 samplePosition = interpolateAtSample(v_position, sampleNdx);\n" 719 " highp vec2 positionInsideAPixel = fract(samplePosition);\n" 720 " if (abs(positionInsideAPixel.x - 0.5) > threshold || abs(positionInsideAPixel.y - 0.5) > threshold)\n" 721 " allOk = false;\n" 722 " }\n" 723 "\n" 724 " if (allOk)\n" 725 " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 726 " else\n" 727 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 728 "}\n"; 729 } 730 else 731 DE_ASSERT(false); 732 733 return buf.str(); 734} 735 736bool SingleSampleInterpolateAtSampleCase::verifyImage (const tcu::Surface& resultImage) 737{ 738 return verifyGreenImage(resultImage, m_testCtx.getLog()); 739} 740 741class CentroidRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase 742{ 743public: 744 CentroidRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, int renderSize); 745 virtual ~CentroidRenderCase (void); 746 747 void init (void); 748 749private: 750 void setupRenderData (void); 751}; 752 753CentroidRenderCase::CentroidRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, int renderSize) 754 : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, renderSize) 755{ 756} 757 758CentroidRenderCase::~CentroidRenderCase (void) 759{ 760} 761 762void CentroidRenderCase::init (void) 763{ 764 // requirements 765 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation")) 766 throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension"); 767 768 MultisampleShaderRenderUtil::MultisampleRenderCase::init(); 769} 770 771void CentroidRenderCase::setupRenderData (void) 772{ 773 const int numTriangles = 200; 774 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 775 std::vector<tcu::Vec4> data (numTriangles * 3 * 3); 776 777 m_renderMode = GL_TRIANGLES; 778 m_renderCount = numTriangles * 3; 779 m_renderSceneDescription = "triangle fan of narrow triangles"; 780 781 m_renderAttribs["a_position"].offset = 0; 782 m_renderAttribs["a_position"].stride = sizeof(float[4]) * 3; 783 m_renderAttribs["a_barycentricsA"].offset = sizeof(float[4]); 784 m_renderAttribs["a_barycentricsA"].stride = sizeof(float[4]) * 3; 785 m_renderAttribs["a_barycentricsB"].offset = sizeof(float[4]) * 2; 786 m_renderAttribs["a_barycentricsB"].stride = sizeof(float[4]) * 3; 787 788 for (int triangleNdx = 0; triangleNdx < numTriangles; ++triangleNdx) 789 { 790 const float angle = ((float)triangleNdx) / numTriangles * 2.0f * DE_PI; 791 const float nextAngle = ((float)triangleNdx + 1.0f) / numTriangles * 2.0f * DE_PI; 792 793 data[(triangleNdx * 3 + 0) * 3 + 0] = tcu::Vec4(0.2f, -0.3f, 0.0f, 1.0f); 794 data[(triangleNdx * 3 + 0) * 3 + 1] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f); 795 data[(triangleNdx * 3 + 0) * 3 + 2] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f); 796 797 data[(triangleNdx * 3 + 1) * 3 + 0] = tcu::Vec4(2.0f * cos(angle), 2.0f * sin(angle), 0.0f, 1.0f); 798 data[(triangleNdx * 3 + 1) * 3 + 1] = tcu::Vec4(0.0f, 1.0f, 0.0f, 0.0f); 799 data[(triangleNdx * 3 + 1) * 3 + 2] = tcu::Vec4(0.0f, 1.0f, 0.0f, 0.0f); 800 801 data[(triangleNdx * 3 + 2) * 3 + 0] = tcu::Vec4(2.0f * cos(nextAngle), 2.0f * sin(nextAngle), 0.0f, 1.0f); 802 data[(triangleNdx * 3 + 2) * 3 + 1] = tcu::Vec4(0.0f, 0.0f, 1.0f, 0.0f); 803 data[(triangleNdx * 3 + 2) * 3 + 2] = tcu::Vec4(0.0f, 0.0f, 1.0f, 0.0f); 804 } 805 806 gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer); 807 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(data.size() * sizeof(tcu::Vec4)), data[0].getPtr(), GL_STATIC_DRAW); 808} 809 810class CentroidQualifierAtSampleCase : public CentroidRenderCase 811{ 812public: 813 CentroidQualifierAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); 814 virtual ~CentroidQualifierAtSampleCase (void); 815 816 void init (void); 817 818private: 819 enum 820 { 821 RENDER_SIZE = 128 822 }; 823 824 std::string genVertexSource (int numTargetSamples) const; 825 std::string genFragmentSource (int numTargetSamples) const; 826 bool verifyImage (const tcu::Surface& resultImage); 827}; 828 829CentroidQualifierAtSampleCase::CentroidQualifierAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) 830 : CentroidRenderCase(context, name, description, numSamples, target, RENDER_SIZE) 831{ 832} 833 834CentroidQualifierAtSampleCase::~CentroidQualifierAtSampleCase (void) 835{ 836} 837 838void CentroidQualifierAtSampleCase::init (void) 839{ 840 // test purpose and expectations 841 m_testCtx.getLog() 842 << tcu::TestLog::Message 843 << "Verifying that interpolateAtSample ignores the centroid-qualifier.\n" 844 << " Draw a fan of narrow triangles (large number of pixels on the edges).\n" 845 << " Set varyings 'barycentricsA' and 'barycentricsB' to contain barycentric coordinates.\n" 846 << " Add centroid-qualifier for barycentricsB.\n" 847 << " => interpolateAtSample(barycentricsB, N) ~= interpolateAtSample(barycentricsA, N)\n" 848 << tcu::TestLog::EndMessage; 849 850 CentroidRenderCase::init(); 851} 852 853std::string CentroidQualifierAtSampleCase::genVertexSource (int numTargetSamples) const 854{ 855 DE_UNREF(numTargetSamples); 856 857 return "#version 310 es\n" 858 "in highp vec4 a_position;\n" 859 "in highp vec4 a_barycentricsA;\n" 860 "in highp vec4 a_barycentricsB;\n" 861 "out highp vec3 v_barycentricsA;\n" 862 "centroid out highp vec3 v_barycentricsB;\n" 863 "void main (void)\n" 864 "{\n" 865 " gl_Position = a_position;\n" 866 " v_barycentricsA = a_barycentricsA.xyz;\n" 867 " v_barycentricsB = a_barycentricsB.xyz;\n" 868 "}\n"; 869} 870 871std::string CentroidQualifierAtSampleCase::genFragmentSource (int numTargetSamples) const 872{ 873 DE_UNREF(numTargetSamples); 874 875 std::ostringstream buf; 876 877 buf << "#version 310 es\n" 878 "#extension GL_OES_shader_multisample_interpolation : require\n" 879 "in highp vec3 v_barycentricsA;\n" 880 "centroid in highp vec3 v_barycentricsB;\n" 881 "layout(location = 0) out mediump vec4 fragColor;\n" 882 "void main (void)\n" 883 "{\n" 884 " const highp float threshold = 0.0005;\n" 885 " bool allOk = true;\n" 886 "\n" 887 " for (int sampleNdx = 0; sampleNdx < " << numTargetSamples << "; ++sampleNdx)\n" 888 " {\n" 889 " highp vec3 sampleA = interpolateAtSample(v_barycentricsA, sampleNdx);\n" 890 " highp vec3 sampleB = interpolateAtSample(v_barycentricsB, sampleNdx);\n" 891 " bool valuesEqual = all(lessThan(abs(sampleA - sampleB), vec3(threshold)));\n" 892 " if (!valuesEqual)\n" 893 " allOk = false;\n" 894 " }\n" 895 "\n" 896 " if (allOk)\n" 897 " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 898 " else\n" 899 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 900 "}\n"; 901 902 return buf.str(); 903} 904 905bool CentroidQualifierAtSampleCase::verifyImage (const tcu::Surface& resultImage) 906{ 907 return verifyGreenImage(resultImage, m_testCtx.getLog()); 908} 909 910class InterpolateAtSampleIDCase : public MultisampleShaderRenderUtil::MultisampleRenderCase 911{ 912public: 913 InterpolateAtSampleIDCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); 914 virtual ~InterpolateAtSampleIDCase (void); 915 916 void init (void); 917private: 918 enum 919 { 920 RENDER_SIZE = 32 921 }; 922 923 std::string genVertexSource (int numTargetSamples) const; 924 std::string genFragmentSource (int numTargetSamples) const; 925 bool verifyImage (const tcu::Surface& resultImage); 926}; 927 928InterpolateAtSampleIDCase::InterpolateAtSampleIDCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) 929 : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE) 930{ 931} 932 933InterpolateAtSampleIDCase::~InterpolateAtSampleIDCase (void) 934{ 935} 936 937void InterpolateAtSampleIDCase::init (void) 938{ 939 // requirements 940 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation")) 941 throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension"); 942 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables")) 943 throw tcu::NotSupportedError("Test requires GL_OES_sample_variables extension"); 944 945 // test purpose and expectations 946 m_testCtx.getLog() 947 << tcu::TestLog::Message 948 << "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n" 949 << " Interpolate varying containing screen space location.\n" 950 << " => interpolateAtSample(varying, sampleID) = varying" 951 << tcu::TestLog::EndMessage; 952 953 MultisampleShaderRenderUtil::MultisampleRenderCase::init(); 954} 955 956std::string InterpolateAtSampleIDCase::genVertexSource (int numTargetSamples) const 957{ 958 DE_UNREF(numTargetSamples); 959 960 std::ostringstream buf; 961 962 buf << "#version 310 es\n" 963 "#extension GL_OES_shader_multisample_interpolation : require\n" 964 "in highp vec4 a_position;\n" 965 "sample out highp vec2 v_screenPosition;\n" 966 "void main (void)\n" 967 "{\n" 968 " gl_Position = a_position;\n" 969 " v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n" 970 "}\n"; 971 972 return buf.str(); 973} 974 975std::string InterpolateAtSampleIDCase::genFragmentSource (int numTargetSamples) const 976{ 977 DE_UNREF(numTargetSamples); 978 979 return "#version 310 es\n" 980 "#extension GL_OES_sample_variables : require\n" 981 "#extension GL_OES_shader_multisample_interpolation : require\n" 982 "sample in highp vec2 v_screenPosition;\n" 983 "layout(location = 0) out mediump vec4 fragColor;\n" 984 "void main (void)\n" 985 "{\n" 986 " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE) 987 "\n" 988 " highp vec2 offsetValue = interpolateAtSample(v_screenPosition, gl_SampleID);\n" 989 " highp vec2 refValue = v_screenPosition;\n" 990 "\n" 991 " bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n" 992 " if (valuesEqual)\n" 993 " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 994 " else\n" 995 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 996 "}\n"; 997} 998 999bool InterpolateAtSampleIDCase::verifyImage (const tcu::Surface& resultImage) 1000{ 1001 return verifyGreenImage(resultImage, m_testCtx.getLog()); 1002} 1003 1004class InterpolateAtCentroidCase : public CentroidRenderCase 1005{ 1006public: 1007 enum TestType 1008 { 1009 TEST_CONSISTENCY = 0, 1010 TEST_ARRAY_ELEMENT, 1011 1012 TEST_LAST 1013 }; 1014 1015 InterpolateAtCentroidCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType type); 1016 virtual ~InterpolateAtCentroidCase (void); 1017 1018 void init (void); 1019 1020private: 1021 enum 1022 { 1023 RENDER_SIZE = 128 1024 }; 1025 1026 std::string genVertexSource (int numTargetSamples) const; 1027 std::string genFragmentSource (int numTargetSamples) const; 1028 bool verifyImage (const tcu::Surface& resultImage); 1029 1030 const TestType m_type; 1031}; 1032 1033InterpolateAtCentroidCase::InterpolateAtCentroidCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType type) 1034 : CentroidRenderCase (context, name, description, numSamples, target, RENDER_SIZE) 1035 , m_type (type) 1036{ 1037} 1038 1039InterpolateAtCentroidCase::~InterpolateAtCentroidCase (void) 1040{ 1041} 1042 1043void InterpolateAtCentroidCase::init (void) 1044{ 1045 // test purpose and expectations 1046 if (m_type == TEST_CONSISTENCY) 1047 { 1048 m_testCtx.getLog() 1049 << tcu::TestLog::Message 1050 << "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid-qualified varying.\n" 1051 << " Draw a fan of narrow triangles (large number of pixels on the edges).\n" 1052 << " Set varyings 'barycentricsA' and 'barycentricsB' to contain barycentric coordinates.\n" 1053 << " Add centroid-qualifier for barycentricsB.\n" 1054 << " => interpolateAtCentroid(barycentricsA) ~= barycentricsB\n" 1055 << tcu::TestLog::EndMessage; 1056 } 1057 else if (m_type == TEST_ARRAY_ELEMENT) 1058 { 1059 m_testCtx.getLog() 1060 << tcu::TestLog::Message 1061 << "Testing interpolateAtCentroid with element of array as an argument." 1062 << tcu::TestLog::EndMessage; 1063 } 1064 else 1065 DE_ASSERT(false); 1066 1067 CentroidRenderCase::init(); 1068} 1069 1070std::string InterpolateAtCentroidCase::genVertexSource (int numTargetSamples) const 1071{ 1072 DE_UNREF(numTargetSamples); 1073 1074 if (m_type == TEST_CONSISTENCY) 1075 return "#version 310 es\n" 1076 "in highp vec4 a_position;\n" 1077 "in highp vec4 a_barycentricsA;\n" 1078 "in highp vec4 a_barycentricsB;\n" 1079 "out highp vec3 v_barycentricsA;\n" 1080 "centroid out highp vec3 v_barycentricsB;\n" 1081 "void main (void)\n" 1082 "{\n" 1083 " gl_Position = a_position;\n" 1084 " v_barycentricsA = a_barycentricsA.xyz;\n" 1085 " v_barycentricsB = a_barycentricsB.xyz;\n" 1086 "}\n"; 1087 else if (m_type == TEST_ARRAY_ELEMENT) 1088 return "#version 310 es\n" 1089 "in highp vec4 a_position;\n" 1090 "in highp vec4 a_barycentricsA;\n" 1091 "in highp vec4 a_barycentricsB;\n" 1092 "out highp vec3[2] v_barycentrics;\n" 1093 "void main (void)\n" 1094 "{\n" 1095 " gl_Position = a_position;\n" 1096 " v_barycentrics[0] = a_barycentricsA.xyz;\n" 1097 " v_barycentrics[1] = a_barycentricsB.xyz;\n" 1098 "}\n"; 1099 1100 DE_ASSERT(false); 1101 return ""; 1102} 1103 1104std::string InterpolateAtCentroidCase::genFragmentSource (int numTargetSamples) const 1105{ 1106 DE_UNREF(numTargetSamples); 1107 1108 if (m_type == TEST_CONSISTENCY) 1109 return "#version 310 es\n" 1110 "#extension GL_OES_shader_multisample_interpolation : require\n" 1111 "in highp vec3 v_barycentricsA;\n" 1112 "centroid in highp vec3 v_barycentricsB;\n" 1113 "layout(location = 0) out highp vec4 fragColor;\n" 1114 "void main (void)\n" 1115 "{\n" 1116 " const highp float threshold = 0.0005;\n" 1117 "\n" 1118 " highp vec3 centroidASampled = interpolateAtCentroid(v_barycentricsA);\n" 1119 " bool valuesEqual = all(lessThan(abs(centroidASampled - v_barycentricsB), vec3(threshold)));\n" 1120 " bool centroidAIsInvalid = any(greaterThan(centroidASampled, vec3(1.0))) ||\n" 1121 " any(lessThan(centroidASampled, vec3(0.0)));\n" 1122 " bool centroidBIsInvalid = any(greaterThan(v_barycentricsB, vec3(1.0))) ||\n" 1123 " any(lessThan(v_barycentricsB, vec3(0.0)));\n" 1124 "\n" 1125 " if (valuesEqual && !centroidAIsInvalid && !centroidBIsInvalid)\n" 1126 " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 1127 " else if (centroidAIsInvalid || centroidBIsInvalid)\n" 1128 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 1129 " else\n" 1130 " fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n" 1131 "}\n"; 1132 else if (m_type == TEST_ARRAY_ELEMENT) 1133 return "#version 310 es\n" 1134 "#extension GL_OES_shader_multisample_interpolation : require\n" 1135 "in highp vec3[2] v_barycentrics;\n" 1136 "layout(location = 0) out mediump vec4 fragColor;\n" 1137 "void main (void)\n" 1138 "{\n" 1139 " const highp float threshold = 0.0005;\n" 1140 "\n" 1141 " highp vec3 centroidInterpolated = interpolateAtCentroid(v_barycentrics[1]);\n" 1142 " bool centroidIsInvalid = any(greaterThan(centroidInterpolated, vec3(1.0))) ||\n" 1143 " any(lessThan(centroidInterpolated, vec3(0.0)));\n" 1144 "\n" 1145 " if (!centroidIsInvalid)\n" 1146 " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 1147 " else\n" 1148 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 1149 "}\n"; 1150 1151 DE_ASSERT(false); 1152 return ""; 1153} 1154 1155bool InterpolateAtCentroidCase::verifyImage (const tcu::Surface& resultImage) 1156{ 1157 return verifyGreenImage(resultImage, m_testCtx.getLog()); 1158} 1159 1160class InterpolateAtOffsetCase : public MultisampleShaderRenderUtil::MultisampleRenderCase 1161{ 1162public: 1163 enum TestType 1164 { 1165 TEST_QUALIFIER_NONE = 0, 1166 TEST_QUALIFIER_CENTROID, 1167 TEST_QUALIFIER_SAMPLE, 1168 TEST_ARRAY_ELEMENT, 1169 1170 TEST_LAST 1171 }; 1172 InterpolateAtOffsetCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType testType); 1173 virtual ~InterpolateAtOffsetCase (void); 1174 1175 void init (void); 1176private: 1177 enum 1178 { 1179 RENDER_SIZE = 32 1180 }; 1181 1182 std::string genVertexSource (int numTargetSamples) const; 1183 std::string genFragmentSource (int numTargetSamples) const; 1184 bool verifyImage (const tcu::Surface& resultImage); 1185 1186 const TestType m_testType; 1187}; 1188 1189InterpolateAtOffsetCase::InterpolateAtOffsetCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType testType) 1190 : MultisampleShaderRenderUtil::MultisampleRenderCase (context, name, description, numSamples, target, RENDER_SIZE) 1191 , m_testType (testType) 1192{ 1193 DE_ASSERT(testType < TEST_LAST); 1194} 1195 1196InterpolateAtOffsetCase::~InterpolateAtOffsetCase (void) 1197{ 1198} 1199 1200void InterpolateAtOffsetCase::init (void) 1201{ 1202 // requirements 1203 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation")) 1204 throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension"); 1205 1206 // test purpose and expectations 1207 m_testCtx.getLog() 1208 << tcu::TestLog::Message 1209 << "Verifying that interpolateAtOffset returns correct values.\n" 1210 << " Interpolate varying containing screen space location.\n" 1211 << " => interpolateAtOffset(varying, offset) should be \"varying value at the pixel center\" + offset" 1212 << tcu::TestLog::EndMessage; 1213 1214 MultisampleShaderRenderUtil::MultisampleRenderCase::init(); 1215} 1216 1217std::string InterpolateAtOffsetCase::genVertexSource (int numTargetSamples) const 1218{ 1219 DE_UNREF(numTargetSamples); 1220 1221 std::ostringstream buf; 1222 buf << "#version 310 es\n" 1223 << "#extension GL_OES_shader_multisample_interpolation : require\n" 1224 << "in highp vec4 a_position;\n"; 1225 1226 if (m_testType == TEST_QUALIFIER_NONE || m_testType == TEST_QUALIFIER_CENTROID || m_testType == TEST_QUALIFIER_SAMPLE) 1227 { 1228 const char* const qualifier = (m_testType == TEST_QUALIFIER_CENTROID) ? ("centroid ") : (m_testType == TEST_QUALIFIER_SAMPLE) ? ("sample ") : (""); 1229 buf << qualifier << "out highp vec2 v_screenPosition;\n" 1230 << qualifier << "out highp vec2 v_offset;\n"; 1231 } 1232 else if (m_testType == TEST_ARRAY_ELEMENT) 1233 { 1234 buf << "out highp vec2[2] v_screenPosition;\n" 1235 << "out highp vec2 v_offset;\n"; 1236 } 1237 else 1238 DE_ASSERT(false); 1239 1240 buf << "void main (void)\n" 1241 << "{\n" 1242 << " gl_Position = a_position;\n"; 1243 1244 if (m_testType != TEST_ARRAY_ELEMENT) 1245 buf << " v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"; 1246 else 1247 buf << " v_screenPosition[0] = a_position.xy; // not used\n" 1248 " v_screenPosition[1] = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"; 1249 1250 buf << " v_offset = a_position.xy * 0.5f;\n" 1251 << "}\n"; 1252 1253 return buf.str(); 1254} 1255 1256std::string InterpolateAtOffsetCase::genFragmentSource (int numTargetSamples) const 1257{ 1258 DE_UNREF(numTargetSamples); 1259 1260 const char* const arrayIndexing = (m_testType == TEST_ARRAY_ELEMENT) ? ("[1]") : (""); 1261 std::ostringstream buf; 1262 1263 buf << "#version 310 es\n" 1264 "#extension GL_OES_shader_multisample_interpolation : require\n"; 1265 1266 if (m_testType == TEST_QUALIFIER_NONE || m_testType == TEST_QUALIFIER_CENTROID || m_testType == TEST_QUALIFIER_SAMPLE) 1267 { 1268 const char* const qualifier = (m_testType == TEST_QUALIFIER_CENTROID) ? ("centroid ") : (m_testType == TEST_QUALIFIER_SAMPLE) ? ("sample ") : (""); 1269 buf << qualifier << "in highp vec2 v_screenPosition;\n" 1270 << qualifier << "in highp vec2 v_offset;\n"; 1271 } 1272 else if (m_testType == TEST_ARRAY_ELEMENT) 1273 { 1274 buf << "in highp vec2[2] v_screenPosition;\n" 1275 << "in highp vec2 v_offset;\n"; 1276 } 1277 else 1278 DE_ASSERT(false); 1279 1280 buf << "layout(location = 0) out mediump vec4 fragColor;\n" 1281 "void main (void)\n" 1282 "{\n" 1283 " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE) 1284 "\n" 1285 " highp vec2 pixelCenter = floor(v_screenPosition" << arrayIndexing << ") + vec2(0.5, 0.5);\n" 1286 " highp vec2 offsetValue = interpolateAtOffset(v_screenPosition" << arrayIndexing << ", v_offset);\n" 1287 " highp vec2 refValue = pixelCenter + v_offset;\n" 1288 "\n" 1289 " bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n" 1290 " if (valuesEqual)\n" 1291 " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 1292 " else\n" 1293 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 1294 "}\n"; 1295 1296 return buf.str(); 1297} 1298 1299bool InterpolateAtOffsetCase::verifyImage (const tcu::Surface& resultImage) 1300{ 1301 return verifyGreenImage(resultImage, m_testCtx.getLog()); 1302} 1303 1304class InterpolateAtSamplePositionCase : public MultisampleShaderRenderUtil::MultisampleRenderCase 1305{ 1306public: 1307 InterpolateAtSamplePositionCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); 1308 virtual ~InterpolateAtSamplePositionCase (void); 1309 1310 void init (void); 1311private: 1312 enum 1313 { 1314 RENDER_SIZE = 32 1315 }; 1316 1317 std::string genVertexSource (int numTargetSamples) const; 1318 std::string genFragmentSource (int numTargetSamples) const; 1319 bool verifyImage (const tcu::Surface& resultImage); 1320}; 1321 1322InterpolateAtSamplePositionCase::InterpolateAtSamplePositionCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) 1323 : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE) 1324{ 1325} 1326 1327InterpolateAtSamplePositionCase::~InterpolateAtSamplePositionCase (void) 1328{ 1329} 1330 1331void InterpolateAtSamplePositionCase::init (void) 1332{ 1333 // requirements 1334 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation")) 1335 throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension"); 1336 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables")) 1337 throw tcu::NotSupportedError("Test requires GL_OES_sample_variables extension"); 1338 1339 // test purpose and expectations 1340 m_testCtx.getLog() 1341 << tcu::TestLog::Message 1342 << "Verifying that interpolateAtOffset with the offset of current sample position returns consistent values.\n" 1343 << " Interpolate varying containing screen space location.\n" 1344 << " => interpolateAtOffset(varying, currentOffset) = varying" 1345 << tcu::TestLog::EndMessage; 1346 1347 MultisampleShaderRenderUtil::MultisampleRenderCase::init(); 1348} 1349 1350std::string InterpolateAtSamplePositionCase::genVertexSource (int numTargetSamples) const 1351{ 1352 DE_UNREF(numTargetSamples); 1353 1354 std::ostringstream buf; 1355 1356 buf << "#version 310 es\n" 1357 "#extension GL_OES_shader_multisample_interpolation : require\n" 1358 "in highp vec4 a_position;\n" 1359 "sample out highp vec2 v_screenPosition;\n" 1360 "void main (void)\n" 1361 "{\n" 1362 " gl_Position = a_position;\n" 1363 " v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n" 1364 "}\n"; 1365 1366 return buf.str(); 1367} 1368 1369std::string InterpolateAtSamplePositionCase::genFragmentSource (int numTargetSamples) const 1370{ 1371 DE_UNREF(numTargetSamples); 1372 1373 return "#version 310 es\n" 1374 "#extension GL_OES_sample_variables : require\n" 1375 "#extension GL_OES_shader_multisample_interpolation : require\n" 1376 "sample in highp vec2 v_screenPosition;\n" 1377 "layout(location = 0) out mediump vec4 fragColor;\n" 1378 "void main (void)\n" 1379 "{\n" 1380 " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE) 1381 "\n" 1382 " highp vec2 offset = gl_SamplePosition - vec2(0.5, 0.5);\n" 1383 " highp vec2 offsetValue = interpolateAtOffset(v_screenPosition, offset);\n" 1384 " highp vec2 refValue = v_screenPosition;\n" 1385 "\n" 1386 " bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n" 1387 " if (valuesEqual)\n" 1388 " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" 1389 " else\n" 1390 " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 1391 "}\n"; 1392} 1393 1394bool InterpolateAtSamplePositionCase::verifyImage (const tcu::Surface& resultImage) 1395{ 1396 return verifyGreenImage(resultImage, m_testCtx.getLog()); 1397} 1398 1399} // anonymous 1400 1401ShaderMultisampleInterpolationTests::ShaderMultisampleInterpolationTests (Context& context) 1402 : TestCaseGroup(context, "multisample_interpolation", "Test multisample interpolation") 1403{ 1404} 1405 1406ShaderMultisampleInterpolationTests::~ShaderMultisampleInterpolationTests (void) 1407{ 1408} 1409 1410void ShaderMultisampleInterpolationTests::init (void) 1411{ 1412 using namespace MultisampleShaderRenderUtil; 1413 1414 static const struct RenderTarget 1415 { 1416 const char* name; 1417 const char* desc; 1418 int numSamples; 1419 MultisampleRenderCase::RenderTarget target; 1420 } targets[] = 1421 { 1422 { "default_framebuffer", "Test with default framebuffer", 0, MultisampleRenderCase::TARGET_DEFAULT }, 1423 { "singlesample_texture", "Test with singlesample texture", 0, MultisampleRenderCase::TARGET_TEXTURE }, 1424 { "multisample_texture_1", "Test with multisample texture", 1, MultisampleRenderCase::TARGET_TEXTURE }, 1425 { "multisample_texture_2", "Test with multisample texture", 2, MultisampleRenderCase::TARGET_TEXTURE }, 1426 { "multisample_texture_4", "Test with multisample texture", 4, MultisampleRenderCase::TARGET_TEXTURE }, 1427 { "multisample_texture_8", "Test with multisample texture", 8, MultisampleRenderCase::TARGET_TEXTURE }, 1428 { "multisample_texture_16", "Test with multisample texture", 16, MultisampleRenderCase::TARGET_TEXTURE }, 1429 { "singlesample_rbo", "Test with singlesample rbo", 0, MultisampleRenderCase::TARGET_RENDERBUFFER }, 1430 { "multisample_rbo_1", "Test with multisample rbo", 1, MultisampleRenderCase::TARGET_RENDERBUFFER }, 1431 { "multisample_rbo_2", "Test with multisample rbo", 2, MultisampleRenderCase::TARGET_RENDERBUFFER }, 1432 { "multisample_rbo_4", "Test with multisample rbo", 4, MultisampleRenderCase::TARGET_RENDERBUFFER }, 1433 { "multisample_rbo_8", "Test with multisample rbo", 8, MultisampleRenderCase::TARGET_RENDERBUFFER }, 1434 { "multisample_rbo_16", "Test with multisample rbo", 16, MultisampleRenderCase::TARGET_RENDERBUFFER }, 1435 }; 1436 1437 // .sample_qualifier 1438 { 1439 tcu::TestCaseGroup* const sampleQualifierGroup = new tcu::TestCaseGroup(m_testCtx, "sample_qualifier", "Test sample qualifier"); 1440 addChild(sampleQualifierGroup); 1441 1442 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1443 sampleQualifierGroup->addChild(new SampleQualifierRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target)); 1444 } 1445 1446 // .interpolate_at_sample 1447 { 1448 tcu::TestCaseGroup* const interpolateAtSampleGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_sample", "Test interpolateAtSample"); 1449 addChild(interpolateAtSampleGroup); 1450 1451 // .static_sample_number 1452 { 1453 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "static_sample_number", "Test interpolateAtSample sample number"); 1454 interpolateAtSampleGroup->addChild(group); 1455 1456 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1457 group->addChild(new InterpolateAtSampleRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtSampleRenderCase::INDEXING_STATIC)); 1458 } 1459 1460 // .dynamic_sample_number 1461 { 1462 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "dynamic_sample_number", "Test interpolateAtSample sample number"); 1463 interpolateAtSampleGroup->addChild(group); 1464 1465 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1466 group->addChild(new InterpolateAtSampleRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtSampleRenderCase::INDEXING_DYNAMIC)); 1467 } 1468 1469 // .non_multisample_buffer 1470 { 1471 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "non_multisample_buffer", "Test interpolateAtSample with non-multisample buffers"); 1472 interpolateAtSampleGroup->addChild(group); 1473 1474 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1475 if (targets[targetNdx].numSamples == 0) 1476 group->addChild(new SingleSampleInterpolateAtSampleCase(m_context, std::string("sample_0_").append(targets[targetNdx].name).c_str(), targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SingleSampleInterpolateAtSampleCase::SAMPLE_0)); 1477 1478 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1479 if (targets[targetNdx].numSamples == 0) 1480 group->addChild(new SingleSampleInterpolateAtSampleCase(m_context, std::string("sample_n_").append(targets[targetNdx].name).c_str(), targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SingleSampleInterpolateAtSampleCase::SAMPLE_N)); 1481 } 1482 1483 // .centroid_qualifier 1484 { 1485 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "centroid_qualified", "Test interpolateAtSample with centroid qualified varying"); 1486 interpolateAtSampleGroup->addChild(group); 1487 1488 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1489 group->addChild(new CentroidQualifierAtSampleCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target)); 1490 } 1491 1492 // .at_sample_id 1493 { 1494 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "at_sample_id", "Test interpolateAtOffset at current sample id"); 1495 interpolateAtSampleGroup->addChild(group); 1496 1497 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1498 group->addChild(new InterpolateAtSampleIDCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target)); 1499 } 1500 } 1501 1502 // .interpolate_at_centroid 1503 { 1504 tcu::TestCaseGroup* const methodGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_centroid", "Test interpolateAtCentroid"); 1505 addChild(methodGroup); 1506 1507 // .consistency 1508 { 1509 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "consistency", "Test interpolateAtCentroid return value is consistent to centroid qualified value"); 1510 methodGroup->addChild(group); 1511 1512 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1513 group->addChild(new InterpolateAtCentroidCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtCentroidCase::TEST_CONSISTENCY)); 1514 } 1515 1516 // .array_element 1517 { 1518 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "array_element", "Test interpolateAtCentroid with array element"); 1519 methodGroup->addChild(group); 1520 1521 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1522 group->addChild(new InterpolateAtCentroidCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtCentroidCase::TEST_ARRAY_ELEMENT)); 1523 } 1524 } 1525 1526 // .interpolate_at_offset 1527 { 1528 static const struct TestConfig 1529 { 1530 const char* name; 1531 InterpolateAtOffsetCase::TestType type; 1532 } configs[] = 1533 { 1534 { "no_qualifiers", InterpolateAtOffsetCase::TEST_QUALIFIER_NONE }, 1535 { "centroid_qualifier", InterpolateAtOffsetCase::TEST_QUALIFIER_CENTROID }, 1536 { "sample_qualifier", InterpolateAtOffsetCase::TEST_QUALIFIER_SAMPLE }, 1537 }; 1538 1539 tcu::TestCaseGroup* const methodGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_offset", "Test interpolateAtOffset"); 1540 addChild(methodGroup); 1541 1542 // .no_qualifiers 1543 // .centroid_qualifier 1544 // .sample_qualifier 1545 for (int configNdx = 0; configNdx < DE_LENGTH_OF_ARRAY(configs); ++configNdx) 1546 { 1547 tcu::TestCaseGroup* const qualifierGroup = new tcu::TestCaseGroup(m_testCtx, configs[configNdx].name, "Test interpolateAtOffset with qualified/non-qualified varying"); 1548 methodGroup->addChild(qualifierGroup); 1549 1550 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1551 qualifierGroup->addChild(new InterpolateAtOffsetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, configs[configNdx].type)); 1552 } 1553 1554 // .at_sample_position 1555 { 1556 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "at_sample_position", "Test interpolateAtOffset at sample position"); 1557 methodGroup->addChild(group); 1558 1559 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1560 group->addChild(new InterpolateAtSamplePositionCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target)); 1561 } 1562 1563 // .array_element 1564 { 1565 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "array_element", "Test interpolateAtOffset with array element"); 1566 methodGroup->addChild(group); 1567 1568 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) 1569 group->addChild(new InterpolateAtOffsetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtOffsetCase::TEST_ARRAY_ELEMENT)); 1570 } 1571 } 1572} 1573 1574} // Functional 1575} // gles31 1576} // deqp 1577