1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2014-2016 The Khronos Group Inc. 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 22 */ /*-------------------------------------------------------------------*/ 23 24 #include "glcSampleVariablesTests.hpp" 25 #include "deMath.h" 26 #include "deRandom.hpp" 27 #include "deStringUtil.hpp" 28 #include "gluContextInfo.hpp" 29 #include "gluDrawUtil.hpp" 30 #include "gluPixelTransfer.hpp" 31 #include "gluShaderProgram.hpp" 32 #include "glw.h" 33 #include "glwFunctions.hpp" 34 #include "tcuCommandLine.hpp" 35 #include "tcuStringTemplate.hpp" 36 #include "tcuSurface.hpp" 37 #include "tcuTestLog.hpp" 38 39 namespace tcu 40 { 41 static bool operator<(tcu::Vec4 const& k1, tcu::Vec4 const& k2) 42 { 43 if (k1.y() < k2.y()) 44 { 45 return true; 46 } 47 else if (k1.y() == k2.y()) 48 { 49 return k1.x() < k2.x(); 50 } 51 else 52 { 53 return false; 54 } 55 } 56 } 57 58 namespace deqp 59 { 60 61 using tcu::TestLog; 62 using std::string; 63 using std::vector; 64 65 static std::string specializeVersion(std::string const& source, glu::GLSLVersion version, 66 std::string const& sampler = "", std::string const& outType = "") 67 { 68 DE_ASSERT(version == glu::GLSL_VERSION_310_ES || version >= glu::GLSL_VERSION_400); 69 std::map<std::string, std::string> args; 70 args["VERSION_DECL"] = glu::getGLSLVersionDeclaration(version); 71 args["SAMPLER"] = sampler; 72 args["OUT_TYPE"] = outType; 73 if (version == glu::GLSL_VERSION_310_ES) 74 { 75 args["OES_SV_RQ"] = "#extension GL_OES_sample_variables : require\n"; 76 args["OES_SV_EN"] = "#extension GL_OES_sample_variables : enable\n"; 77 } 78 else 79 { 80 args["OES_SV_RQ"] = ""; 81 args["OES_SV_EN"] = ""; 82 } 83 return tcu::StringTemplate(source.c_str()).specialize(args); 84 } 85 86 class SampleShadingExtensionCase : public TestCase 87 { 88 public: 89 SampleShadingExtensionCase(Context& context, const char* name, const char* description, 90 glu::GLSLVersion glslVersion); 91 ~SampleShadingExtensionCase(); 92 93 IterateResult iterate(); 94 95 protected: 96 glu::GLSLVersion m_glslVersion; 97 }; 98 99 SampleShadingExtensionCase::SampleShadingExtensionCase(Context& context, const char* name, const char* description, 100 glu::GLSLVersion glslVersion) 101 : TestCase(context, name, description), m_glslVersion(glslVersion) 102 { 103 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES); 104 } 105 106 SampleShadingExtensionCase::~SampleShadingExtensionCase() 107 { 108 } 109 110 SampleShadingExtensionCase::IterateResult SampleShadingExtensionCase::iterate() 111 { 112 TestLog& log = m_testCtx.getLog(); 113 114 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables")) 115 { 116 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables"); 117 return STOP; 118 } 119 120 static char const* vss = "${VERSION_DECL}\n" 121 "in highp vec4 a_position;\n" 122 "void main()\n" 123 "{\n" 124 " gl_Position = a_position;\n" 125 "}\n"; 126 127 { 128 static char const* fss = "${VERSION_DECL}\n" 129 "${OES_SV_RQ}" 130 "out highp vec4 o_color;\n" 131 "void main()\n" 132 "{\n" 133 " for (int i = 0; i < (gl_MaxSamples + 31) / 32; ++i) {\n" 134 " gl_SampleMask[i] = gl_SampleMaskIn[i];\n" 135 " }\n" 136 " o_color = vec4(gl_SampleID, gl_SamplePosition.x, gl_SamplePosition.y, 1);\n" 137 "}\n"; 138 139 glu::ShaderProgram programRequire(m_context.getRenderContext(), 140 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(), 141 specializeVersion(fss, m_glslVersion).c_str())); 142 log << programRequire; 143 if (!programRequire.isOk()) 144 { 145 TCU_FAIL("Compile failed"); 146 } 147 } 148 149 { 150 static char const* fss = "${VERSION_DECL}\n" 151 "${OES_SV_EN}" 152 "out highp vec4 o_color;\n" 153 "void main()\n" 154 "{\n" 155 "#if !GL_OES_sample_variables\n" 156 " this is broken\n" 157 "#endif\n" 158 " for (int i = 0; i < (gl_MaxSamples + 31) / 32; ++i) {\n" 159 " gl_SampleMask[i] = gl_SampleMaskIn[i];\n" 160 " }\n" 161 " o_color = vec4(gl_SampleID, gl_SamplePosition.x, gl_SamplePosition.y, 1);\n" 162 "}\n"; 163 164 glu::ShaderProgram programEnable(m_context.getRenderContext(), 165 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(), 166 specializeVersion(fss, m_glslVersion).c_str())); 167 log << programEnable; 168 if (!programEnable.isOk()) 169 { 170 TCU_FAIL("Compile failed"); 171 } 172 } 173 174 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 175 return STOP; 176 } 177 178 class SampleShadingMaskCase : public TestCase 179 { 180 public: 181 SampleShadingMaskCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, 182 GLenum internalFormat, tcu::TextureFormat const& texFormat, const char* sampler, 183 const char* outType, GLint samples, GLint sampleMask); 184 ~SampleShadingMaskCase(); 185 186 IterateResult iterate(); 187 188 protected: 189 glu::GLSLVersion m_glslVersion; 190 GLenum m_internalFormat; 191 tcu::TextureFormat m_texFormat; 192 std::string m_sampler; 193 std::string m_outType; 194 GLint m_samples; 195 GLint m_sampleMask; 196 197 enum 198 { 199 WIDTH = 16, 200 HEIGHT = 16, 201 MAX_SAMPLES = 4, 202 }; 203 }; 204 205 SampleShadingMaskCase::SampleShadingMaskCase(Context& context, const char* name, const char* description, 206 glu::GLSLVersion glslVersion, GLenum internalFormat, 207 tcu::TextureFormat const& texFormat, const char* sampler, 208 const char* outType, GLint samples, GLint sampleMask) 209 : TestCase(context, name, description) 210 , m_glslVersion(glslVersion) 211 , m_internalFormat(internalFormat) 212 , m_texFormat(texFormat) 213 , m_sampler(sampler) 214 , m_outType(outType) 215 , m_samples(samples) 216 , m_sampleMask(sampleMask) 217 { 218 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_400); 219 } 220 221 SampleShadingMaskCase::~SampleShadingMaskCase() 222 { 223 } 224 225 SampleShadingMaskCase::IterateResult SampleShadingMaskCase::iterate() 226 { 227 TestLog& log = m_testCtx.getLog(); 228 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 229 bool isOk = true; 230 bool supportsRgba32f = false; 231 232 if (m_glslVersion == glu::GLSL_VERSION_310_ES && 233 !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables")) 234 { 235 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables"); 236 return STOP; 237 } 238 239 supportsRgba32f = isContextTypeGLCore(m_context.getRenderContext().getType()) ? 240 true : 241 (m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float") || 242 m_context.getContextInfo().isExtensionSupported("GL_ARB_color_buffer_float")); 243 244 if (m_internalFormat == GL_RGBA32F && !supportsRgba32f) 245 { 246 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Internalformat rgba32f not supported"); 247 return STOP; 248 } 249 250 GLint maxSamples; 251 if (((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)) || 252 ((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RG)) || 253 ((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::R)) || 254 ((m_texFormat.type == tcu::TextureFormat::HALF_FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA))) 255 { 256 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, m_internalFormat, GL_SAMPLES, 1, &maxSamples); 257 if (m_samples > maxSamples) 258 { 259 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, 260 "Test sample count greater than samples that the format supports"); 261 return STOP; 262 } 263 } 264 else if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 || 265 m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8) 266 { 267 gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &maxSamples); 268 if (m_samples > maxSamples) 269 { 270 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_INTEGER_SAMPLES"); 271 return STOP; 272 } 273 } 274 else 275 { 276 gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples); 277 if (m_samples > maxSamples) 278 { 279 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_SAMPLES"); 280 return STOP; 281 } 282 } 283 284 // Create a multisample texture, or a regular texture if samples is zero. 285 GLuint tex; 286 gl.genTextures(1, &tex); 287 GLenum target; 288 if (m_samples) 289 { 290 target = GL_TEXTURE_2D_MULTISAMPLE; 291 gl.bindTexture(target, tex); 292 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, m_internalFormat, WIDTH, HEIGHT, GL_FALSE); 293 } 294 else 295 { 296 target = GL_TEXTURE_2D; 297 gl.bindTexture(target, tex); 298 gl.texStorage2D(GL_TEXTURE_2D, 1, m_internalFormat, WIDTH, HEIGHT); 299 if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 || 300 m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || m_texFormat.type == tcu::TextureFormat::FLOAT) 301 { 302 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 303 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 304 } 305 } 306 307 // Create a framebuffer with the texture attached and clear to "green". 308 GLuint fboMs; 309 gl.genFramebuffers(1, &fboMs); 310 gl.bindFramebuffer(GL_FRAMEBUFFER, fboMs); 311 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex, 0); 312 gl.viewport(0, 0, WIDTH, HEIGHT); 313 if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8) 314 { 315 GLint color[4] = { 0, 1, 0, 1 }; 316 gl.clearBufferiv(GL_COLOR, 0, color); 317 } 318 else if (m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8) 319 { 320 GLuint color[4] = { 0, 1, 0, 1 }; 321 gl.clearBufferuiv(GL_COLOR, 0, color); 322 } 323 else 324 { 325 GLfloat color[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; 326 gl.clearBufferfv(GL_COLOR, 0, color); 327 } 328 329 static deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 }; 330 331 { 332 // Draw a quad setting all samples to "red". We only expect "red" 333 // to be written if the sample mask bit for that sample is 1. 334 335 static char const* vss = "${VERSION_DECL}\n" 336 "in highp vec2 a_position;\n" 337 "void main()\n" 338 "{\n" 339 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 340 "}\n"; 341 342 static char const* fss = "${VERSION_DECL}\n" 343 "${OES_SV_RQ}" 344 "layout(location = 0) out highp ${OUT_TYPE} o_color;\n" 345 "uniform int u_sampleMask;\n" 346 "void main()\n" 347 "{\n" 348 " for (int i = 0; i < (gl_NumSamples + 31) / 32; ++i) {\n" 349 " gl_SampleMask[i] = u_sampleMask & gl_SampleMaskIn[i];\n" 350 " }\n" 351 " o_color = ${OUT_TYPE}(1, 0, 0, 1);\n" 352 "}\n"; 353 354 glu::ShaderProgram program( 355 m_context.getRenderContext(), 356 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(), 357 specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str())); 358 log << program; 359 if (!program.isOk()) 360 { 361 TCU_FAIL("Compile failed"); 362 } 363 364 static float const position[] = { 365 -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f, 366 }; 367 368 gl.useProgram(program.getProgram()); 369 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_sampleMask"), m_sampleMask); 370 371 glu::VertexArrayBinding vertexArrays[] = { 372 glu::va::Float("a_position", 2, 4, 0, &position[0]), 373 }; 374 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), 375 &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0])); 376 377 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad"); 378 } 379 380 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); 381 gl.deleteFramebuffers(1, &fboMs); 382 383 GLsizei width = WIDTH * ((m_samples) ? m_samples : 1); 384 385 GLuint rbo; 386 gl.genRenderbuffers(1, &rbo); 387 gl.bindRenderbuffer(GL_RENDERBUFFER, rbo); 388 gl.renderbufferStorage(GL_RENDERBUFFER, m_internalFormat, width, HEIGHT); 389 390 GLuint fbo; 391 gl.genFramebuffers(1, &fbo); 392 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); 393 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); 394 gl.viewport(0, 0, width, HEIGHT); 395 396 { 397 // Resolve the multi-sample texture into a render-buffer sized such that 398 // the width can hold all samples of a pixel. 399 static char const* vss = "${VERSION_DECL}\n" 400 "in highp vec2 a_position;\n" 401 "void main(void)\n" 402 "{\n" 403 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 404 "}\n"; 405 406 static char const* fss = "${VERSION_DECL}\n" 407 "uniform highp ${SAMPLER} u_tex;\n" 408 "uniform highp ${SAMPLER}MS u_texMS;\n" 409 "uniform int u_samples;\n" 410 "layout(location = 0) out highp ${OUT_TYPE} o_color;\n" 411 "void main(void)\n" 412 "{\n" 413 " if (u_samples > 0) {\n" 414 " ivec2 coord = ivec2(int(gl_FragCoord.x) / u_samples, gl_FragCoord.y);\n" 415 " int sampleId = int(gl_FragCoord.x) % u_samples;\n" 416 " o_color = texelFetch(u_texMS, coord, sampleId);\n" 417 " } else {\n" 418 " ivec2 coord = ivec2(gl_FragCoord.x, gl_FragCoord.y);\n" 419 " o_color = texelFetch(u_tex, coord, 0);\n" 420 " }\n" 421 "}\n"; 422 423 glu::ShaderProgram program( 424 m_context.getRenderContext(), 425 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(), 426 specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str())); 427 log << program; 428 if (!program.isOk()) 429 { 430 TCU_FAIL("Compile failed"); 431 } 432 433 static float const position[] = { 434 -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f, 435 }; 436 437 gl.useProgram(program.getProgram()); 438 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_samples"), m_samples); 439 if (m_samples > 0) 440 { 441 // only MS sampler needed, TU 1 is not used 442 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 1); 443 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 0); 444 } 445 else 446 { 447 // only non-MS sampler needed, TU 1 is not used 448 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 0); 449 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 1); 450 } 451 452 glu::VertexArrayBinding vertexArrays[] = { 453 glu::va::Float("a_position", 2, 4, 0, &position[0]), 454 }; 455 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), 456 &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0])); 457 458 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad"); 459 } 460 461 tcu::TextureLevel results(m_texFormat, width, HEIGHT); 462 tcu::PixelBufferAccess pixels = results.getAccess(); 463 std::vector<tcu::Vec4> result(pixels.getHeight() * pixels.getWidth()); 464 465 if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8) 466 { 467 std::vector<GLint> data(pixels.getHeight() * pixels.getWidth() * 4); 468 gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]); 469 for (unsigned int i = 0; i < data.size(); i += 4) 470 { 471 result[i / 4] = 472 tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]); 473 } 474 } 475 else if (pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8) 476 { 477 std::vector<GLuint> data(pixels.getHeight() * pixels.getWidth() * 4); 478 gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]); 479 for (unsigned int i = 0; i < data.size(); i += 4) 480 { 481 result[i / 4] = 482 tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]); 483 } 484 } 485 else 486 { 487 glu::readPixels(m_context.getRenderContext(), 0, 0, pixels); 488 } 489 490 for (int y = 0; y < HEIGHT; ++y) 491 { 492 for (int x = 0; x < WIDTH; ++x) 493 { 494 GLint samples = (m_samples) ? m_samples : 1; 495 for (int sample = 0; sample < samples; ++sample) 496 { 497 tcu::Vec4 pixel; 498 if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8 || 499 pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8) 500 { 501 pixel = result[y * WIDTH + x * samples + sample]; 502 } 503 else 504 { 505 pixel = pixels.getPixel(x * samples + sample, y); 506 } 507 508 // Make sure only those samples where the sample mask bit is 509 // non-zero have the "red" pixel values. 510 if (!m_samples || (m_sampleMask & (1 << sample))) 511 { 512 if (pixel != tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)) 513 { 514 isOk = false; 515 } 516 } 517 else 518 { 519 if (pixel != tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)) 520 { 521 isOk = false; 522 } 523 } 524 } 525 } 526 } 527 528 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); 529 gl.deleteFramebuffers(1, &fbo); 530 531 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 532 gl.deleteRenderbuffers(1, &rbo); 533 534 gl.bindTexture(target, 0); 535 gl.deleteTextures(1, &tex); 536 537 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail"); 538 return STOP; 539 } 540 541 class SampleShadingPositionCase : public TestCase 542 { 543 public: 544 SampleShadingPositionCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, 545 GLint samples, GLboolean fixedSampleLocations); 546 ~SampleShadingPositionCase(); 547 548 IterateResult iterate(); 549 550 protected: 551 glu::GLSLVersion m_glslVersion; 552 GLint m_samples; 553 GLboolean m_fixedSampleLocations; 554 555 enum 556 { 557 WIDTH = 8, 558 HEIGHT = 8, 559 MAX_SAMPLES = 8, 560 }; 561 }; 562 563 SampleShadingPositionCase::SampleShadingPositionCase(Context& context, const char* name, const char* description, 564 glu::GLSLVersion glslVersion, GLint samples, 565 GLboolean fixedSampleLocations) 566 : TestCase(context, name, description) 567 , m_glslVersion(glslVersion) 568 , m_samples(samples) 569 , m_fixedSampleLocations(fixedSampleLocations) 570 { 571 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_400); 572 } 573 574 SampleShadingPositionCase::~SampleShadingPositionCase() 575 { 576 } 577 578 SampleShadingPositionCase::IterateResult SampleShadingPositionCase::iterate() 579 { 580 TestLog& log = m_testCtx.getLog(); 581 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 582 bool isOk = true; 583 584 if (m_glslVersion == glu::GLSL_VERSION_310_ES && 585 !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables")) 586 { 587 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables"); 588 return STOP; 589 } 590 591 GLint maxSamples; 592 gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples); 593 if (m_samples > maxSamples) 594 { 595 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count great than MAX_SAMPLES"); 596 return STOP; 597 } 598 599 // Create a multisample texture, or a regular texture if samples is zero. 600 GLuint tex; 601 gl.genTextures(1, &tex); 602 GLenum target; 603 if (m_samples) 604 { 605 target = GL_TEXTURE_2D_MULTISAMPLE; 606 gl.bindTexture(target, tex); 607 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, WIDTH, HEIGHT, 608 m_fixedSampleLocations); 609 } 610 else 611 { 612 target = GL_TEXTURE_2D; 613 gl.bindTexture(target, tex); 614 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, WIDTH, HEIGHT); 615 } 616 617 // Attach the texture to the framebuffer to render to it. 618 GLuint fboMs; 619 gl.genFramebuffers(1, &fboMs); 620 gl.bindFramebuffer(GL_FRAMEBUFFER, fboMs); 621 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex, 0); 622 gl.viewport(0, 0, WIDTH, HEIGHT); 623 624 // Save all the sample positions for this multisample framebuffer. 625 std::vector<tcu::Vec4> samplePositions; 626 if (m_samples) 627 { 628 samplePositions.resize(m_samples); 629 for (int sample = 0; sample < m_samples; ++sample) 630 { 631 GLfloat position[2]; 632 gl.getMultisamplefv(GL_SAMPLE_POSITION, sample, position); 633 samplePositions[sample] = tcu::Vec4(position[0], position[1], 0.0f, 1.0f); 634 } 635 } 636 637 static deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 }; 638 639 { 640 // Render all the sample positions to each pixel sample. 641 642 static char const* vss = "${VERSION_DECL}\n" 643 "in highp vec2 a_position;\n" 644 "void main()\n" 645 "{\n" 646 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 647 "}\n"; 648 649 static char const* fss = "${VERSION_DECL}\n" 650 "${OES_SV_RQ}" 651 "layout(location = 0) out highp vec4 o_color;\n" 652 "void main()\n" 653 "{\n" 654 " o_color = vec4(gl_SamplePosition, 0, 1);\n" 655 "}\n"; 656 657 glu::ShaderProgram program(m_context.getRenderContext(), 658 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(), 659 specializeVersion(fss, m_glslVersion).c_str())); 660 log << program; 661 if (!program.isOk()) 662 { 663 TCU_FAIL("Compile failed"); 664 } 665 666 const float position[] = { 667 -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f, 668 }; 669 670 gl.useProgram(program.getProgram()); 671 672 glu::VertexArrayBinding vertexArrays[] = { 673 glu::va::Float("a_position", 2, 4, 0, &position[0]), 674 }; 675 676 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), 677 &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0])); 678 679 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad"); 680 } 681 682 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); 683 gl.deleteFramebuffers(1, &fboMs); 684 685 // Create a regular non-multisample render buffer to resolve to multisample texture into. 686 // The width is increased to save all samples of the pixel. 687 688 GLsizei width = WIDTH * ((m_samples) ? m_samples : 1); 689 690 GLuint rbo; 691 gl.genRenderbuffers(1, &rbo); 692 gl.bindRenderbuffer(GL_RENDERBUFFER, rbo); 693 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, HEIGHT); 694 695 GLuint fbo; 696 gl.genFramebuffers(1, &fbo); 697 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); 698 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); 699 gl.viewport(0, 0, width, HEIGHT); 700 701 { 702 // Resolve the multisample texture to the renderbuffer. 703 704 static char const* vss = "${VERSION_DECL}\n" 705 "in highp vec2 a_position;\n" 706 "void main(void)\n" 707 "{\n" 708 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 709 "}\n"; 710 711 static char const* fss = "${VERSION_DECL}\n" 712 "uniform highp sampler2D u_tex;\n" 713 "uniform highp sampler2DMS u_texMS;\n" 714 "uniform int u_samples;\n" 715 "layout(location = 0) out highp vec4 o_color;\n" 716 "void main(void)\n" 717 "{\n" 718 " if (u_samples > 0) {\n" 719 " ivec2 coord = ivec2(int(gl_FragCoord.x) / u_samples, gl_FragCoord.y);\n" 720 " int sampleId = int(gl_FragCoord.x) % u_samples;\n" 721 " o_color = texelFetch(u_texMS, coord, sampleId);\n" 722 " } else {\n" 723 " ivec2 coord = ivec2(gl_FragCoord.x, gl_FragCoord.y);\n" 724 " o_color = texelFetch(u_tex, coord, 0);\n" 725 " }\n" 726 "}\n"; 727 728 glu::ShaderProgram program(m_context.getRenderContext(), 729 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(), 730 specializeVersion(fss, m_glslVersion).c_str())); 731 log << program; 732 if (!program.isOk()) 733 { 734 TCU_FAIL("Compile failed"); 735 } 736 737 static float const position[] = { 738 -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f, 739 }; 740 741 gl.useProgram(program.getProgram()); 742 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_samples"), m_samples); 743 if (m_samples > 0) 744 { 745 // only MS sampler needed, TU 1 is not used 746 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 1); 747 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 0); 748 } 749 else 750 { 751 // only non-MS sampler needed, TU 1 is not used 752 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 0); 753 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 1); 754 } 755 756 glu::VertexArrayBinding vertexArrays[] = { 757 glu::va::Float("a_position", 2, 4, 0, &position[0]), 758 }; 759 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), 760 &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0])); 761 762 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad"); 763 } 764 765 // Read the renderbuffer pixels and verify we get back what we're expecting. 766 tcu::TextureLevel results(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), width, 767 HEIGHT); 768 tcu::PixelBufferAccess pixels = results.getAccess(); 769 glu::readPixels(m_context.getRenderContext(), 0, 0, pixels); 770 if (m_samples) 771 { 772 // If m_fixedSampleLocations are used make sure the first pixel's samples 773 // all match the SAMPLE_POSITION state saved earlier. 774 std::set<tcu::Vec4> fixedSampleLocations; 775 if (m_fixedSampleLocations) 776 { 777 for (int sample = 0; sample < m_samples; ++sample) 778 { 779 tcu::Vec4 pixel = pixels.getPixel(sample, 0); 780 fixedSampleLocations.insert(pixel); 781 if (deFloatAbs(pixel.x() - samplePositions[sample].x()) > 0.01 || 782 deFloatAbs(pixel.y() - samplePositions[sample].y()) > 0.01) 783 { 784 785 isOk = false; 786 } 787 } 788 } 789 790 // Verify all samples of every pixel to make sure each position is unique. 791 for (int y = 0; y < HEIGHT; ++y) 792 { 793 for (int x = 0; x < WIDTH; ++x) 794 { 795 std::set<tcu::Vec4> uniquePixels; 796 for (int sample = 0; sample < m_samples; ++sample) 797 { 798 uniquePixels.insert(pixels.getPixel(x * m_samples + sample, y)); 799 } 800 if ((GLint)uniquePixels.size() != m_samples) 801 { 802 isOk = false; 803 } 804 // For the m_fixedSampleLocations case make sure each position 805 // matches the sample positions of pixel(0, 0) saved earlier. 806 if (m_fixedSampleLocations) 807 { 808 if (fixedSampleLocations != uniquePixels) 809 { 810 isOk = false; 811 } 812 } 813 } 814 } 815 } 816 else 817 { 818 // For the non-multisample case make sure all the positions are (0.5,0.5). 819 for (int y = 0; y < pixels.getHeight(); ++y) 820 { 821 for (int x = 0; x < pixels.getWidth(); ++x) 822 { 823 tcu::Vec4 pixel = pixels.getPixel(x, y); 824 if (deFloatAbs(pixel.x() - 0.5f) > 0.01 || deFloatAbs(pixel.y() - 0.5f) > 0.01 || pixel.z() != 0.0f || 825 pixel.w() != 1.0f) 826 { 827 isOk = false; 828 } 829 } 830 } 831 } 832 833 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); 834 gl.deleteFramebuffers(1, &fbo); 835 836 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 837 gl.deleteRenderbuffers(1, &rbo); 838 839 gl.bindTexture(target, 0); 840 gl.deleteTextures(1, &tex); 841 842 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail"); 843 return STOP; 844 } 845 846 SampleVariablesTests::SampleVariablesTests(Context& context, glu::GLSLVersion glslVersion) 847 : TestCaseGroup(context, "sample_variables", "Sample Variables tests"), m_glslVersion(glslVersion) 848 { 849 } 850 851 SampleVariablesTests::~SampleVariablesTests() 852 { 853 } 854 855 void SampleVariablesTests::init() 856 { 857 de::Random rnd(m_context.getTestContext().getCommandLine().getBaseSeed()); 858 859 struct Sample 860 { 861 char const* name; 862 GLint samples; 863 } samples[] = { 864 { "samples_0", 0 }, { "samples_1", 1 }, { "samples_2", 2 }, { "samples_4", 4 }, { "samples_8", 8 }, 865 }; 866 867 // sample_variables.extension 868 if (m_glslVersion == glu::GLSL_VERSION_310_ES) 869 { 870 tcu::TestCaseGroup* extensionCaseGroup = new tcu::TestCaseGroup(m_testCtx, "verification", ""); 871 extensionCaseGroup->addChild( 872 new SampleShadingExtensionCase(m_context, "extension", "#extension verification", m_glslVersion)); 873 addChild(extensionCaseGroup); 874 } 875 876 // sample_variables.mask 877 tcu::TestCaseGroup* maskGroup = new tcu::TestCaseGroup(m_testCtx, "mask", "gl_SampleMask tests"); 878 addChild(maskGroup); 879 struct Format 880 { 881 char const* name; 882 GLenum internalFormat; 883 tcu::TextureFormat textureFormat; 884 char const* sampler; 885 char const* outType; 886 } formats[] = { 887 { "rgba8", GL_RGBA8, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), "sampler2D", 888 "vec4" }, 889 { "rgba8i", GL_RGBA8I, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8), 890 "isampler2D", "ivec4" }, 891 { "rgba8ui", GL_RGBA8UI, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8), 892 "usampler2D", "uvec4" }, 893 { "rgba32f", GL_RGBA32F, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), "sampler2D", 894 "vec4" }, 895 }; 896 for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); ++format) 897 { 898 tcu::TestCaseGroup* maskFormatGroup = new tcu::TestCaseGroup(m_testCtx, formats[format].name, ""); 899 maskGroup->addChild(maskFormatGroup); 900 901 for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample) 902 { 903 tcu::TestCaseGroup* maskFormatSampleGroup = new tcu::TestCaseGroup(m_testCtx, samples[sample].name, ""); 904 maskFormatGroup->addChild(maskFormatSampleGroup); 905 906 maskFormatSampleGroup->addChild( 907 new SampleShadingMaskCase(m_context, "mask_zero", "", m_glslVersion, formats[format].internalFormat, 908 formats[format].textureFormat, formats[format].sampler, 909 formats[format].outType, samples[sample].samples, 0)); 910 911 for (int mask = 0; mask < SAMPLE_MASKS; ++mask) 912 { 913 std::stringstream ss; 914 ss << "mask_" << mask; 915 maskFormatSampleGroup->addChild(new SampleShadingMaskCase( 916 m_context, ss.str().c_str(), "", m_glslVersion, formats[format].internalFormat, 917 formats[format].textureFormat, formats[format].sampler, formats[format].outType, 918 samples[sample].samples, rnd.getUint32())); 919 } 920 } 921 } 922 923 // sample_variables.position 924 tcu::TestCaseGroup* positionGroup = new tcu::TestCaseGroup(m_testCtx, "position", "gl_SamplePosition tests"); 925 addChild(positionGroup); 926 struct Fixed 927 { 928 char const* name; 929 GLboolean fixedSampleLocations; 930 } fixed[] = { 931 { "non-fixed", GL_FALSE }, { "fixed", GL_TRUE }, 932 }; 933 for (int j = 0; j < DE_LENGTH_OF_ARRAY(fixed); ++j) 934 { 935 tcu::TestCaseGroup* positionFixedGroup = new tcu::TestCaseGroup(m_testCtx, fixed[j].name, ""); 936 positionGroup->addChild(positionFixedGroup); 937 for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample) 938 { 939 positionFixedGroup->addChild(new SampleShadingPositionCase(m_context, samples[sample].name, "", 940 m_glslVersion, samples[sample].samples, 941 fixed[j].fixedSampleLocations)); 942 } 943 } 944 } 945 946 } // glcts 947