1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.0 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 Special float stress tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es2sSpecialFloatTests.hpp" 25 #include "gluRenderContext.hpp" 26 #include "gluShaderProgram.hpp" 27 #include "gluPixelTransfer.hpp" 28 #include "gluStrUtil.hpp" 29 #include "gluContextInfo.hpp" 30 #include "glwEnums.hpp" 31 #include "glwFunctions.hpp" 32 #include "tcuRenderTarget.hpp" 33 #include "tcuSurface.hpp" 34 #include "tcuTestLog.hpp" 35 #include "tcuVectorUtil.hpp" 36 #include "deStringUtil.hpp" 37 #include "deMath.h" 38 #include "deRandom.hpp" 39 40 #include <limits> 41 #include <sstream> 42 43 using namespace glw; 44 45 namespace deqp 46 { 47 namespace gles2 48 { 49 namespace Stress 50 { 51 namespace 52 { 53 54 static const int TEST_CANVAS_SIZE = 256; 55 static const int TEST_TEXTURE_SIZE = 128; 56 static const int TEST_TEXTURE_CUBE_SIZE = 32; 57 static const deUint32 s_specialFloats[] = 58 { 59 0x00000000, // zero 60 0x80000000, // negative zero 61 0x3F800000, // one 62 0xBF800000, // negative one 63 0x00800000, // minimum positive normalized value 64 0x80800000, // maximum negative normalized value 65 0x00000001, // minimum positive denorm value 66 0x80000001, // maximum negative denorm value 67 0x7F7FFFFF, // maximum finite value. 68 0xFF7FFFFF, // minimum finite value. 69 0x7F800000, // inf 70 0xFF800000, // -inf 71 0x34000000, // epsilon 72 0xB4000000, // negative epsilon 73 0x7FC00000, // quiet_NaN 74 0xFFC00000, // negative quiet_NaN 75 0x7FC00001, // signaling_NaN 76 0xFFC00001, // negative signaling_NaN 77 0x7FEAAAAA, // quiet payloaded NaN (payload of repeated pattern of 101010...) 78 0xFFEAAAAA, // negative quiet payloaded NaN ( .. ) 79 0x7FAAAAAA, // signaling payloaded NaN ( .. ) 80 0xFFAAAAAA, // negative signaling payloaded NaN ( .. ) 81 }; 82 83 static const char* const s_colorPassthroughFragmentShaderSource = "varying mediump vec4 v_out;\n" 84 "void main ()\n" 85 "{\n" 86 " gl_FragColor = v_out;\n" 87 "}\n"; 88 static const char* const s_attrPassthroughVertexShaderSource = "attribute highp vec4 a_pos;\n" 89 "attribute highp vec4 a_attr;\n" 90 "varying mediump vec4 v_attr;\n" 91 "void main ()\n" 92 "{\n" 93 " v_attr = a_attr;\n" 94 " gl_Position = a_pos;\n" 95 "}\n"; 96 97 class RenderCase : public TestCase 98 { 99 public: 100 enum RenderTargetType 101 { 102 RENDERTARGETTYPE_SCREEN, 103 RENDERTARGETTYPE_FBO 104 }; 105 106 RenderCase (Context& context, const char* name, const char* desc, RenderTargetType renderTargetType = RENDERTARGETTYPE_SCREEN); 107 virtual ~RenderCase (void); 108 109 virtual void init (void); 110 virtual void deinit (void); 111 112 protected: 113 bool checkResultImage (const tcu::Surface& result); 114 bool drawTestPattern (bool useTexture); 115 116 virtual std::string genVertexSource (void) const = 0; 117 virtual std::string genFragmentSource (void) const = 0; 118 119 const glu::ShaderProgram* m_program; 120 const RenderTargetType m_renderTargetType; 121 }; 122 123 RenderCase::RenderCase (Context& context, const char* name, const char* desc, RenderTargetType renderTargetType) 124 : TestCase (context, name, desc) 125 , m_program (DE_NULL) 126 , m_renderTargetType (renderTargetType) 127 { 128 } 129 130 RenderCase::~RenderCase (void) 131 { 132 deinit(); 133 } 134 135 void RenderCase::init (void) 136 { 137 const int width = m_context.getRenderTarget().getWidth(); 138 const int height = m_context.getRenderTarget().getHeight(); 139 140 // check target size 141 if (m_renderTargetType == RENDERTARGETTYPE_SCREEN) 142 { 143 if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE) 144 throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE)); 145 } 146 else if (m_renderTargetType == RENDERTARGETTYPE_FBO) 147 { 148 GLint maxTexSize = 0; 149 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); 150 151 if (maxTexSize < TEST_CANVAS_SIZE) 152 throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_CANVAS_SIZE)); 153 } 154 else 155 DE_ASSERT(false); 156 157 // gen shader 158 159 m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shader." << tcu::TestLog::EndMessage; 160 161 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(genFragmentSource())); 162 m_testCtx.getLog() << *m_program; 163 164 if (!m_program->isOk()) 165 throw tcu::TestError("shader compile failed"); 166 } 167 168 void RenderCase::deinit (void) 169 { 170 if (m_program) 171 { 172 delete m_program; 173 m_program = DE_NULL; 174 } 175 } 176 177 bool RenderCase::checkResultImage (const tcu::Surface& result) 178 { 179 tcu::Surface errorMask (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 180 bool error = false; 181 182 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image." << tcu::TestLog::EndMessage; 183 184 for (int y = 0; y < TEST_CANVAS_SIZE; ++y) 185 for (int x = 0; x < TEST_CANVAS_SIZE; ++x) 186 { 187 const tcu::RGBA col = result.getPixel(x, y); 188 189 if (col.getGreen() == 255) 190 errorMask.setPixel(x, y, tcu::RGBA::green()); 191 else 192 { 193 errorMask.setPixel(x, y, tcu::RGBA::red()); 194 error = true; 195 } 196 } 197 198 if (error) 199 { 200 m_testCtx.getLog() << tcu::TestLog::Message << "Result image has missing or invalid pixels" << tcu::TestLog::EndMessage; 201 m_testCtx.getLog() 202 << tcu::TestLog::ImageSet("Results", "Result verification") 203 << tcu::TestLog::Image("Result", "Result", result) 204 << tcu::TestLog::Image("Error mask", "Error mask", errorMask) 205 << tcu::TestLog::EndImageSet; 206 } 207 else 208 { 209 m_testCtx.getLog() 210 << tcu::TestLog::ImageSet("Results", "Result verification") 211 << tcu::TestLog::Image("Result", "Result", result) 212 << tcu::TestLog::EndImageSet; 213 } 214 215 return !error; 216 } 217 218 bool RenderCase::drawTestPattern (bool useTexture) 219 { 220 static const tcu::Vec4 fullscreenQuad[4] = 221 { 222 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 223 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 224 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 225 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 226 }; 227 const char* const vertexSource = "attribute highp vec4 a_pos;\n" 228 "varying mediump vec4 v_position;\n" 229 "void main ()\n" 230 "{\n" 231 " v_position = a_pos;\n" 232 " gl_Position = a_pos;\n" 233 "}\n"; 234 const char* const fragmentSourceNoTex = "varying mediump vec4 v_position;\n" 235 "void main ()\n" 236 "{\n" 237 " gl_FragColor = vec4((v_position.x + 1.0) * 0.5, 1.0, 1.0, 1.0);\n" 238 "}\n"; 239 const char* const fragmentSourceTex = "uniform mediump sampler2D u_sampler;\n" 240 "varying mediump vec4 v_position;\n" 241 "void main ()\n" 242 "{\n" 243 " gl_FragColor = texture2D(u_sampler, v_position.xy);\n" 244 "}\n"; 245 const char* const fragmentSource = (useTexture) ? (fragmentSourceTex) : (fragmentSourceNoTex); 246 const tcu::RGBA formatThreshold = m_context.getRenderTarget().getPixelFormat().getColorThreshold(); 247 248 tcu::Surface resultImage (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 249 tcu::Surface errorMask (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 250 bool error = false; 251 252 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a test pattern to detect " << ((useTexture) ? ("texture sampling") : ("")) << " side-effects." << tcu::TestLog::EndMessage; 253 254 // draw pattern 255 { 256 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 257 const glu::ShaderProgram patternProgram (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource)); 258 const GLint positionLoc = gl.getAttribLocation(patternProgram.getProgram(), "a_pos"); 259 GLuint textureID = 0; 260 261 if (useTexture) 262 { 263 const int textureSize = 32; 264 std::vector<tcu::Vector<deUint8, 4> > buffer(textureSize*textureSize); 265 266 for (int x = 0; x < textureSize; ++x) 267 for (int y = 0; y < textureSize; ++y) 268 { 269 // sum of two axis aligned gradients. Each gradient is 127 at the edges and 0 at the center. 270 // pattern is symmetric (x and y) => no discontinuity near boundary => no need to worry of results with LINEAR filtering near boundaries 271 const deUint8 redComponent = (deUint8)de::clamp(de::abs((float)x / (float)textureSize - 0.5f) * 255.0f + de::abs((float)y / (float)textureSize - 0.5f) * 255.0f, 0.0f, 255.0f); 272 273 buffer[x * textureSize + y] = tcu::Vector<deUint8, 4>(redComponent, 255, 255, 255); 274 } 275 276 gl.genTextures(1, &textureID); 277 gl.bindTexture(GL_TEXTURE_2D, textureID); 278 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureSize, textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer[0].getPtr()); 279 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 280 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 281 } 282 283 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 284 gl.clear(GL_COLOR_BUFFER_BIT); 285 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 286 gl.useProgram(patternProgram.getProgram()); 287 288 if (useTexture) 289 gl.uniform1i(gl.getUniformLocation(patternProgram.getProgram(), "u_sampler"), 0); 290 291 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &fullscreenQuad[0]); 292 293 gl.enableVertexAttribArray(positionLoc); 294 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 295 gl.disableVertexAttribArray(positionLoc); 296 297 gl.useProgram(0); 298 gl.finish(); 299 GLU_EXPECT_NO_ERROR(gl.getError(), "RenderCase::drawTestPattern"); 300 301 if (textureID) 302 gl.deleteTextures(1, &textureID); 303 304 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess()); 305 } 306 307 // verify pattern 308 for (int y = 0; y < TEST_CANVAS_SIZE; ++y) 309 for (int x = 0; x < TEST_CANVAS_SIZE; ++x) 310 { 311 const float texGradientPosX = deFloatFrac((float)x * 2.0f / (float)TEST_CANVAS_SIZE); 312 const float texGradientPosY = deFloatFrac((float)y * 2.0f / (float)TEST_CANVAS_SIZE); 313 const deUint8 texRedComponent = (deUint8)de::clamp(de::abs(texGradientPosX - 0.5f) * 255.0f + de::abs(texGradientPosY - 0.5f) * 255.0f, 0.0f, 255.0f); 314 315 const tcu::RGBA refColTexture = tcu::RGBA(texRedComponent, 255, 255, 255); 316 const tcu::RGBA refColGradient = tcu::RGBA((int)((float)x / (float)TEST_CANVAS_SIZE * 255.0f), 255, 255, 255); 317 const tcu::RGBA& refCol = (useTexture) ? (refColTexture) : (refColGradient); 318 319 const int colorThreshold = 10; 320 const tcu::RGBA col = resultImage.getPixel(x, y); 321 const tcu::IVec4 colorDiff = tcu::abs(col.toIVec() - refCol.toIVec()); 322 323 if (colorDiff.x() > formatThreshold.getRed() + colorThreshold || 324 colorDiff.y() > formatThreshold.getGreen() + colorThreshold || 325 colorDiff.z() > formatThreshold.getBlue() + colorThreshold) 326 { 327 errorMask.setPixel(x, y, tcu::RGBA::red()); 328 error = true; 329 } 330 else 331 errorMask.setPixel(x, y, tcu::RGBA::green()); 332 } 333 334 // report error 335 if (error) 336 { 337 m_testCtx.getLog() << tcu::TestLog::Message << "Test pattern has missing/invalid pixels" << tcu::TestLog::EndMessage; 338 m_testCtx.getLog() 339 << tcu::TestLog::ImageSet("Results", "Result verification") 340 << tcu::TestLog::Image("Result", "Result", resultImage) 341 << tcu::TestLog::Image("Error mask", "Error mask", errorMask) 342 << tcu::TestLog::EndImageSet; 343 } 344 else 345 m_testCtx.getLog() << tcu::TestLog::Message << "No side-effects found." << tcu::TestLog::EndMessage; 346 347 return !error; 348 } 349 350 class FramebufferRenderCase : public RenderCase 351 { 352 public: 353 enum FrameBufferType 354 { 355 FBO_DEFAULT = 0, 356 FBO_RGBA, 357 FBO_RGBA4, 358 FBO_RGB5_A1, 359 FBO_RGB565, 360 FBO_RGBA_FLOAT16, 361 362 FBO_LAST 363 }; 364 365 FramebufferRenderCase (Context& context, const char* name, const char* desc, FrameBufferType fboType); 366 virtual ~FramebufferRenderCase (void); 367 368 virtual void init (void); 369 virtual void deinit (void); 370 IterateResult iterate (void); 371 372 virtual void testFBO (void) = DE_NULL; 373 374 protected: 375 const FrameBufferType m_fboType; 376 377 private: 378 GLuint m_texID; 379 GLuint m_fboID; 380 }; 381 382 FramebufferRenderCase::FramebufferRenderCase (Context& context, const char* name, const char* desc, FrameBufferType fboType) 383 : RenderCase (context, name, desc, (fboType == FBO_DEFAULT) ? (RENDERTARGETTYPE_SCREEN) : (RENDERTARGETTYPE_FBO)) 384 , m_fboType (fboType) 385 , m_texID (0) 386 , m_fboID (0) 387 { 388 DE_ASSERT(m_fboType < FBO_LAST); 389 } 390 391 FramebufferRenderCase::~FramebufferRenderCase (void) 392 { 393 deinit(); 394 } 395 396 void FramebufferRenderCase::init (void) 397 { 398 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 399 400 // check requirements 401 if (m_fboType == FBO_RGBA_FLOAT16) 402 { 403 // half float texture is allowed (OES_texture_half_float) and it is color renderable (EXT_color_buffer_half_float) 404 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_texture_half_float") || 405 !m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_half_float")) 406 throw tcu::NotSupportedError("Color renderable half float texture required."); 407 } 408 409 // gen shader 410 RenderCase::init(); 411 412 // create render target 413 if (m_fboType == FBO_DEFAULT) 414 { 415 m_testCtx.getLog() << tcu::TestLog::Message << "Using default framebuffer." << tcu::TestLog::EndMessage; 416 } 417 else 418 { 419 GLuint internalFormat = 0; 420 GLuint format = 0; 421 GLuint type = 0; 422 423 #if !defined(GL_HALF_FLOAT_OES) 424 # define GL_HALF_FLOAT_OES 0x8D61 425 #endif 426 427 switch (m_fboType) 428 { 429 case FBO_RGBA: internalFormat = GL_RGBA; format = GL_RGBA; type = GL_UNSIGNED_BYTE; break; 430 case FBO_RGBA4: internalFormat = GL_RGBA; format = GL_RGBA; type = GL_UNSIGNED_SHORT_4_4_4_4; break; 431 case FBO_RGB5_A1: internalFormat = GL_RGBA; format = GL_RGBA; type = GL_UNSIGNED_SHORT_5_5_5_1; break; 432 case FBO_RGB565: internalFormat = GL_RGB; format = GL_RGB; type = GL_UNSIGNED_SHORT_5_6_5; break; 433 case FBO_RGBA_FLOAT16: internalFormat = GL_RGBA; format = GL_RGBA; type = GL_HALF_FLOAT_OES; break; 434 435 default: 436 DE_ASSERT(false); 437 break; 438 } 439 440 m_testCtx.getLog() << tcu::TestLog::Message 441 << "Creating fbo. Texture internalFormat = " << glu::getTextureFormatStr(internalFormat) 442 << ", format = " << glu::getTextureFormatStr(format) 443 << ", type = " << glu::getTypeStr(type) 444 << tcu::TestLog::EndMessage; 445 446 // gen texture 447 gl.genTextures(1, &m_texID); 448 gl.bindTexture(GL_TEXTURE_2D, m_texID); 449 gl.texImage2D(GL_TEXTURE_2D, 0, internalFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, 0, format, type, DE_NULL); 450 GLU_EXPECT_NO_ERROR(gl.getError(), "texture init"); 451 452 // gen fbo 453 gl.genFramebuffers(1, &m_fboID); 454 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID); 455 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texID, 0); 456 GLU_EXPECT_NO_ERROR(gl.getError(), "fbo init"); 457 458 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 459 throw tcu::NotSupportedError("could not create fbo for testing."); 460 } 461 } 462 463 void FramebufferRenderCase::deinit (void) 464 { 465 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 466 467 if (m_texID) 468 { 469 gl.deleteTextures(1, &m_texID); 470 m_texID = 0; 471 } 472 473 if (m_fboID) 474 { 475 gl.deleteFramebuffers(1, &m_fboID); 476 m_fboID = 0; 477 } 478 } 479 480 FramebufferRenderCase::IterateResult FramebufferRenderCase::iterate (void) 481 { 482 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 483 484 // bind fbo (or don't if we are using default) 485 if (m_fboID) 486 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID); 487 488 // do something with special floats 489 testFBO(); 490 491 return STOP; 492 } 493 494 /*--------------------------------------------------------------------*//*! 495 * \brief Tests special floats as vertex attributes 496 * 497 * Tests that special floats transferred to the shader using vertex 498 * attributes do not change the results of normal floating point 499 * calculations. Special floats are put to 4-vector's x and y components and 500 * value 1.0 is put to z and w. The resulting fragment's green channel 501 * should be 1.0 everywhere. 502 * 503 * After the calculation test a test pattern is drawn to detect possible 504 * floating point operation anomalies. 505 *//*--------------------------------------------------------------------*/ 506 class VertexAttributeCase : public RenderCase 507 { 508 public: 509 enum Storage 510 { 511 STORAGE_BUFFER = 0, 512 STORAGE_CLIENT, 513 514 STORAGE_LAST 515 }; 516 enum ShaderType 517 { 518 TYPE_VERTEX = 0, 519 TYPE_FRAGMENT, 520 521 TYPE_LAST 522 }; 523 524 VertexAttributeCase (Context& context, const char* name, const char* desc, Storage storage, ShaderType type); 525 ~VertexAttributeCase (void); 526 527 void init (void); 528 void deinit (void); 529 IterateResult iterate (void); 530 531 private: 532 std::string genVertexSource (void) const; 533 std::string genFragmentSource (void) const; 534 535 const Storage m_storage; 536 const ShaderType m_type; 537 GLuint m_positionVboID; 538 GLuint m_attribVboID; 539 GLuint m_elementVboID; 540 }; 541 542 VertexAttributeCase::VertexAttributeCase (Context& context, const char* name, const char* desc, Storage storage, ShaderType type) 543 : RenderCase (context, name, desc) 544 , m_storage (storage) 545 , m_type (type) 546 , m_positionVboID (0) 547 , m_attribVboID (0) 548 , m_elementVboID (0) 549 { 550 DE_ASSERT(storage < STORAGE_LAST); 551 DE_ASSERT(type < TYPE_LAST); 552 } 553 554 VertexAttributeCase::~VertexAttributeCase (void) 555 { 556 deinit(); 557 } 558 559 void VertexAttributeCase::init (void) 560 { 561 RenderCase::init(); 562 563 // init gl resources 564 if (m_storage == STORAGE_BUFFER) 565 { 566 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 567 568 gl.genBuffers(1, &m_positionVboID); 569 gl.genBuffers(1, &m_attribVboID); 570 gl.genBuffers(1, &m_elementVboID); 571 } 572 } 573 574 void VertexAttributeCase::deinit (void) 575 { 576 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 577 578 RenderCase::deinit(); 579 580 if (m_attribVboID) 581 { 582 gl.deleteBuffers(1, &m_attribVboID); 583 m_attribVboID = 0; 584 } 585 586 if (m_positionVboID) 587 { 588 gl.deleteBuffers(1, &m_positionVboID); 589 m_positionVboID = 0; 590 } 591 592 if (m_elementVboID) 593 { 594 gl.deleteBuffers(1, &m_elementVboID); 595 m_elementVboID = 0; 596 } 597 } 598 599 VertexAttributeCase::IterateResult VertexAttributeCase::iterate (void) 600 { 601 // Create a [s_specialFloats] X [s_specialFloats] grid of vertices with each vertex having 2 [s_specialFloats] values 602 // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen 603 604 std::vector<tcu::Vec4> gridVertices (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats)); 605 std::vector<tcu::UVec4> gridAttributes (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats)); 606 std::vector<deUint16> indices ((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6); 607 tcu::Surface resultImage (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 608 609 // vertices 610 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x) 611 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y) 612 { 613 const deUint32 one = 0x3F800000; 614 const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1] 615 const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; 616 617 gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 618 gridAttributes[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one); 619 } 620 621 // tiles 622 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x) 623 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y) 624 { 625 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6; 626 627 indices[baseNdx + 0] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0)); 628 indices[baseNdx + 1] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1)); 629 indices[baseNdx + 2] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0)); 630 631 indices[baseNdx + 3] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0)); 632 indices[baseNdx + 4] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1)); 633 indices[baseNdx + 5] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1)); 634 } 635 636 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a grid with the shader. Setting a_attr for each vertex to (special, special, 1, 1)." << tcu::TestLog::EndMessage; 637 638 // Draw grid 639 { 640 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 641 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos"); 642 const GLint attribLoc = gl.getAttribLocation(m_program->getProgram(), "a_attr"); 643 644 if (m_storage == STORAGE_BUFFER) 645 { 646 gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID); 647 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridVertices.size() * sizeof(tcu::Vec4)), &gridVertices[0], GL_STATIC_DRAW); 648 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate"); 649 650 gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID); 651 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridAttributes.size() * sizeof(tcu::UVec4)), &gridAttributes[0], GL_STATIC_DRAW); 652 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate"); 653 654 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementVboID); 655 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size() * sizeof(deUint16)), &indices[0], GL_STATIC_DRAW); 656 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate"); 657 } 658 659 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 660 gl.clear(GL_COLOR_BUFFER_BIT); 661 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 662 gl.useProgram(m_program->getProgram()); 663 664 if (m_storage == STORAGE_BUFFER) 665 { 666 gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID); 667 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 668 669 gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID); 670 gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 671 672 gl.enableVertexAttribArray(positionLoc); 673 gl.enableVertexAttribArray(attribLoc); 674 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, DE_NULL); 675 gl.disableVertexAttribArray(positionLoc); 676 gl.disableVertexAttribArray(attribLoc); 677 678 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 679 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 680 } 681 else if (m_storage == STORAGE_CLIENT) 682 { 683 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]); 684 gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridAttributes[0]); 685 686 gl.enableVertexAttribArray(positionLoc); 687 gl.enableVertexAttribArray(attribLoc); 688 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]); 689 gl.disableVertexAttribArray(positionLoc); 690 gl.disableVertexAttribArray(attribLoc); 691 } 692 else 693 DE_ASSERT(false); 694 695 gl.useProgram(0); 696 gl.finish(); 697 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate"); 698 699 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess()); 700 } 701 702 // verify everywhere was drawn (all pixels have Green = 255) 703 if (!checkResultImage(resultImage)) 704 { 705 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments"); 706 return STOP; 707 } 708 709 // test drawing still works 710 if (!drawTestPattern(false)) 711 { 712 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed"); 713 return STOP; 714 } 715 716 // all ok 717 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 718 return STOP; 719 } 720 721 std::string VertexAttributeCase::genVertexSource (void) const 722 { 723 if (m_type == TYPE_VERTEX) 724 return 725 "attribute highp vec4 a_pos;\n" 726 "attribute highp vec4 a_attr;\n" 727 "varying mediump vec4 v_out;\n" 728 "void main ()\n" 729 "{\n" 730 " highp vec2 a1 = a_attr.xz + a_attr.yw; // add\n" 731 " highp vec2 a2 = a_attr.xz - a_attr.yw; // sub\n" 732 " highp vec2 a3 = a_attr.xz * a_attr.yw; // mul\n" 733 " highp vec2 a4 = a_attr.xz / a_attr.yw; // div\n" 734 " highp vec2 a5 = a_attr.xz + a_attr.yw * a_attr.xz; // fma\n" 735 "\n" 736 " highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n" 737 " v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n" 738 " gl_Position = a_pos;\n" 739 "}\n"; 740 else 741 return s_attrPassthroughVertexShaderSource; 742 } 743 744 std::string VertexAttributeCase::genFragmentSource (void) const 745 { 746 if (m_type == TYPE_VERTEX) 747 return s_colorPassthroughFragmentShaderSource; 748 else 749 return 750 "varying mediump vec4 v_attr;\n" 751 "void main ()\n" 752 "{\n" 753 " mediump vec2 a1 = v_attr.xz + v_attr.yw; // add\n" 754 " mediump vec2 a2 = v_attr.xz - v_attr.yw; // sub\n" 755 " mediump vec2 a3 = v_attr.xz * v_attr.yw; // mul\n" 756 " mediump vec2 a4 = v_attr.xz / v_attr.yw; // div\n" 757 " mediump vec2 a5 = v_attr.xz + v_attr.yw * v_attr.xz; // fma\n" 758 "\n" 759 " const mediump float epsilon = 0.1; // allow small differences. To results to be wrong they must be more wrong than that.\n" 760 " mediump float green = 1.0 + epsilon - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n" 761 " gl_FragColor = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n" 762 "}\n"; 763 } 764 765 /*--------------------------------------------------------------------*//*! 766 * \brief Tests special floats as uniforms 767 * 768 * Tests that special floats transferred to the shader as uniforms do 769 * not change the results of normal floating point calculations. Special 770 * floats are put to 4-vector's x and y components and value 1.0 is put to 771 * z and w. The resulting fragment's green channel should be 1.0 772 * everywhere. 773 * 774 * After the calculation test a test pattern is drawn to detect possible 775 * floating point operation anomalies. 776 *//*--------------------------------------------------------------------*/ 777 class UniformCase : public RenderCase 778 { 779 public: 780 enum ShaderType 781 { 782 TYPE_VERTEX = 0, 783 TYPE_FRAGMENT, 784 }; 785 786 UniformCase (Context& context, const char* name, const char* desc, ShaderType type); 787 ~UniformCase (void); 788 789 void init (void); 790 void deinit (void); 791 IterateResult iterate (void); 792 793 private: 794 std::string genVertexSource (void) const; 795 std::string genFragmentSource (void) const; 796 797 const ShaderType m_type; 798 }; 799 800 UniformCase::UniformCase (Context& context, const char* name, const char* desc, ShaderType type) 801 : RenderCase (context, name, desc) 802 , m_type (type) 803 { 804 } 805 806 UniformCase::~UniformCase (void) 807 { 808 deinit(); 809 } 810 811 void UniformCase::init (void) 812 { 813 RenderCase::init(); 814 } 815 816 void UniformCase::deinit (void) 817 { 818 RenderCase::deinit(); 819 } 820 821 UniformCase::IterateResult UniformCase::iterate (void) 822 { 823 // Create a [s_specialFloats] X [s_specialFloats] grid of tile with each tile having 2 [s_specialFloats] values 824 // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen 825 826 std::vector<tcu::Vec4> gridVertices ((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1)); 827 std::vector<deUint16> indices (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6); 828 tcu::Surface resultImage (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 829 830 // vertices 831 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x) 832 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y) 833 { 834 const float posX = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1] 835 const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; 836 837 gridVertices[x * (DE_LENGTH_OF_ARRAY(s_specialFloats)+1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 838 } 839 840 // tiles 841 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x) 842 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y) 843 { 844 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats)) + y) * 6; 845 846 indices[baseNdx + 0] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0)); 847 indices[baseNdx + 1] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1)); 848 indices[baseNdx + 2] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0)); 849 850 indices[baseNdx + 3] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0)); 851 indices[baseNdx + 4] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1)); 852 indices[baseNdx + 5] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1)); 853 } 854 855 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a grid with the shader. Setting u_special for vertex each tile to (special, special, 1, 1)." << tcu::TestLog::EndMessage; 856 857 // Draw grid 858 { 859 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 860 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos"); 861 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special"); 862 863 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 864 gl.clear(GL_COLOR_BUFFER_BIT); 865 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 866 gl.useProgram(m_program->getProgram()); 867 868 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]); 869 gl.enableVertexAttribArray(positionLoc); 870 871 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x) 872 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y) 873 { 874 const deUint32 one = 0x3F800000; 875 const tcu::UVec4 uniformValue = tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one); 876 const int indexIndex = (x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y) * 6; 877 878 gl.uniform4fv(specialLoc, 1, (const float*)uniformValue.getPtr()); 879 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]); 880 } 881 882 gl.disableVertexAttribArray(positionLoc); 883 884 gl.useProgram(0); 885 gl.finish(); 886 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformCase::iterate"); 887 888 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess()); 889 } 890 891 // verify everywhere was drawn (all pixels have Green = 255) 892 if (!checkResultImage(resultImage)) 893 { 894 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments"); 895 return STOP; 896 } 897 898 // test drawing still works 899 if (!drawTestPattern(false)) 900 { 901 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed"); 902 return STOP; 903 } 904 905 // all ok 906 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 907 return STOP; 908 } 909 910 std::string UniformCase::genVertexSource (void) const 911 { 912 if (m_type == TYPE_VERTEX) 913 return 914 "attribute highp vec4 a_pos;\n" 915 "uniform highp vec4 u_special;\n" 916 "varying mediump vec4 v_out;\n" 917 "void main ()\n" 918 "{\n" 919 " highp vec2 a1 = u_special.xz + u_special.yw; // add\n" 920 " highp vec2 a2 = u_special.xz - u_special.yw; // sub\n" 921 " highp vec2 a3 = u_special.xz * u_special.yw; // mul\n" 922 " highp vec2 a4 = u_special.xz / u_special.yw; // div\n" 923 " highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n" 924 "\n" 925 " highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n" 926 " v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n" 927 " gl_Position = a_pos;\n" 928 "}\n"; 929 else 930 return 931 "attribute highp vec4 a_pos;\n" 932 "void main ()\n" 933 "{\n" 934 " gl_Position = a_pos;\n" 935 "}\n"; 936 } 937 938 std::string UniformCase::genFragmentSource (void) const 939 { 940 if (m_type == TYPE_VERTEX) 941 return s_colorPassthroughFragmentShaderSource; 942 else 943 return 944 "uniform mediump vec4 u_special;\n" 945 "void main ()\n" 946 "{\n" 947 " mediump vec2 a1 = u_special.xz + u_special.yw; // add\n" 948 " mediump vec2 a2 = u_special.xz - u_special.yw; // sub\n" 949 " mediump vec2 a3 = u_special.xz * u_special.yw; // mul\n" 950 " mediump vec2 a4 = u_special.xz / u_special.yw; // div\n" 951 " mediump vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n" 952 " mediump vec2 a6 = mod(u_special.xz, u_special.yw);\n" 953 " mediump vec2 a7 = mix(u_special.xz, u_special.yw, a6);\n" 954 "\n" 955 " mediump float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y + a7.y) - 7.0);\n" 956 " gl_FragColor = vec4(a1.x*a3.x, green, a5.x*a4.x + a2.x*a7.x, 1.0);\n" 957 "}\n"; 958 } 959 960 /*--------------------------------------------------------------------*//*! 961 * \brief Tests special floats as texture samping arguments 962 * 963 * Tests that special floats given as texture coordinates or LOD levels 964 * to sampling functions do not return invalid values (values not in the 965 * texture). Every texel's green component is 1.0. 966 * 967 * After the calculation test a test pattern is drawn to detect possible 968 * texture sampling anomalies. 969 *//*--------------------------------------------------------------------*/ 970 class TextureSamplerCase : public RenderCase 971 { 972 public: 973 enum ShaderType 974 { 975 TYPE_VERTEX = 0, 976 TYPE_FRAGMENT, 977 978 TYPE_LAST 979 }; 980 enum TestType 981 { 982 TEST_TEX_COORD = 0, 983 TEST_LOD, 984 TEST_TEX_COORD_CUBE, 985 986 TEST_LAST 987 }; 988 989 TextureSamplerCase (Context& context, const char* name, const char* desc, ShaderType type, TestType testType); 990 ~TextureSamplerCase (void); 991 992 void init (void); 993 void deinit (void); 994 IterateResult iterate (void); 995 996 private: 997 std::string genVertexSource (void) const; 998 std::string genFragmentSource (void) const; 999 1000 const ShaderType m_type; 1001 const TestType m_testType; 1002 GLuint m_textureID; 1003 }; 1004 1005 TextureSamplerCase::TextureSamplerCase (Context& context, const char* name, const char* desc, ShaderType type, TestType testType) 1006 : RenderCase (context, name, desc) 1007 , m_type (type) 1008 , m_testType (testType) 1009 , m_textureID (0) 1010 { 1011 DE_ASSERT(type < TYPE_LAST); 1012 DE_ASSERT(testType < TEST_LAST); 1013 } 1014 1015 TextureSamplerCase::~TextureSamplerCase (void) 1016 { 1017 deinit(); 1018 } 1019 1020 void TextureSamplerCase::init (void) 1021 { 1022 // requirements 1023 { 1024 GLint maxTextureSize = 0; 1025 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); 1026 if (maxTextureSize < TEST_TEXTURE_SIZE) 1027 throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_TEXTURE_SIZE)); 1028 } 1029 1030 // vertex shader supports textures? 1031 if (m_type == TYPE_VERTEX) 1032 { 1033 GLint maxVertexTexUnits = 0; 1034 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTexUnits); 1035 if (maxVertexTexUnits < 1) 1036 throw tcu::NotSupportedError("GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS must be at least 1"); 1037 } 1038 1039 RenderCase::init(); 1040 1041 // gen texture 1042 { 1043 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1044 std::vector<deUint8> texData (TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE*4); 1045 de::Random rnd (12345); 1046 1047 gl.genTextures(1, &m_textureID); 1048 1049 for (int x = 0; x < TEST_TEXTURE_SIZE; ++x) 1050 for (int y = 0; y < TEST_TEXTURE_SIZE; ++y) 1051 { 1052 // RGBA8, green and alpha channel are always 255 for verification 1053 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 0] = rnd.getUint32() & 0xFF; 1054 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 1] = 0xFF; 1055 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 2] = rnd.getUint32() & 0xFF; 1056 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 3] = 0xFF; 1057 } 1058 1059 if (m_testType == TEST_TEX_COORD) 1060 { 1061 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D texture with a test pattern." << tcu::TestLog::EndMessage; 1062 1063 gl.bindTexture(GL_TEXTURE_2D, m_textureID); 1064 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]); 1065 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1066 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1067 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init"); 1068 } 1069 else if (m_testType == TEST_LOD) 1070 { 1071 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a mipmapped 2D texture with a test pattern." << tcu::TestLog::EndMessage; 1072 1073 gl.bindTexture(GL_TEXTURE_2D, m_textureID); 1074 1075 for (int level = 0; (TEST_TEXTURE_SIZE >> level); ++level) 1076 gl.texImage2D(GL_TEXTURE_2D, level, GL_RGBA, TEST_TEXTURE_SIZE >> level, TEST_TEXTURE_SIZE >> level, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]); 1077 1078 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1079 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 1080 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init"); 1081 } 1082 else if (m_testType == TEST_TEX_COORD_CUBE) 1083 { 1084 DE_STATIC_ASSERT(TEST_TEXTURE_CUBE_SIZE <= TEST_TEXTURE_SIZE); 1085 1086 static const GLenum faces[] = 1087 { 1088 GL_TEXTURE_CUBE_MAP_POSITIVE_X, 1089 GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 1090 GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 1091 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 1092 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 1093 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 1094 }; 1095 1096 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a cube map with a test pattern." << tcu::TestLog::EndMessage; 1097 1098 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID); 1099 1100 for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); ++faceNdx) 1101 gl.texImage2D(faces[faceNdx], 0, GL_RGBA, TEST_TEXTURE_CUBE_SIZE, TEST_TEXTURE_CUBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]); 1102 1103 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1104 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1105 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init"); 1106 } 1107 else 1108 DE_ASSERT(DE_FALSE); 1109 } 1110 } 1111 1112 void TextureSamplerCase::deinit (void) 1113 { 1114 RenderCase::deinit(); 1115 1116 if (m_textureID) 1117 { 1118 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1119 1120 gl.deleteTextures(1, &m_textureID); 1121 m_textureID = 0; 1122 } 1123 } 1124 1125 TextureSamplerCase::IterateResult TextureSamplerCase::iterate (void) 1126 { 1127 // Draw a grid and texture it with a texture and sample it using special special values. The result samples should all have the green channel at 255 as per the test image. 1128 1129 std::vector<tcu::Vec4> gridVertices (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats)); 1130 std::vector<tcu::UVec2> gridTexCoords (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats)); 1131 std::vector<deUint16> indices ((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6); 1132 tcu::Surface resultImage (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1133 1134 // vertices 1135 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x) 1136 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y) 1137 { 1138 const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1] 1139 const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; 1140 1141 gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1142 gridTexCoords[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::UVec2(s_specialFloats[x], s_specialFloats[y]); 1143 } 1144 1145 // tiles 1146 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x) 1147 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y) 1148 { 1149 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6; 1150 1151 indices[baseNdx + 0] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0)); 1152 indices[baseNdx + 1] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1)); 1153 indices[baseNdx + 2] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0)); 1154 1155 indices[baseNdx + 3] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0)); 1156 indices[baseNdx + 4] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1)); 1157 indices[baseNdx + 5] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1)); 1158 } 1159 1160 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a textured grid with the shader. Sampling from the texture using special floating point values." << tcu::TestLog::EndMessage; 1161 1162 // Draw grid 1163 { 1164 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1165 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos"); 1166 const GLint texCoordLoc = gl.getAttribLocation(m_program->getProgram(), "a_attr"); 1167 const GLint samplerLoc = gl.getUniformLocation(m_program->getProgram(), "u_sampler"); 1168 1169 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 1170 gl.clear(GL_COLOR_BUFFER_BIT); 1171 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1172 gl.useProgram(m_program->getProgram()); 1173 1174 gl.uniform1i(samplerLoc, 0); 1175 if (m_testType != TEST_TEX_COORD_CUBE) 1176 gl.bindTexture(GL_TEXTURE_2D, m_textureID); 1177 else 1178 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID); 1179 1180 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]); 1181 gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]); 1182 1183 gl.enableVertexAttribArray(positionLoc); 1184 gl.enableVertexAttribArray(texCoordLoc); 1185 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]); 1186 gl.disableVertexAttribArray(positionLoc); 1187 gl.disableVertexAttribArray(texCoordLoc); 1188 1189 gl.useProgram(0); 1190 gl.finish(); 1191 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::iterate"); 1192 1193 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess()); 1194 } 1195 1196 // verify everywhere was drawn and samples were from the texture (all pixels have Green = 255) 1197 if (!checkResultImage(resultImage)) 1198 { 1199 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments"); 1200 return STOP; 1201 } 1202 1203 // test drawing and textures still works 1204 if (!drawTestPattern(true)) 1205 { 1206 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed"); 1207 return STOP; 1208 } 1209 1210 // all ok 1211 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1212 return STOP; 1213 } 1214 1215 std::string TextureSamplerCase::genVertexSource (void) const 1216 { 1217 // vertex shader is passthrough, fragment does the calculations 1218 if (m_type == TYPE_FRAGMENT) 1219 return s_attrPassthroughVertexShaderSource; 1220 1221 // vertex shader does the calculations 1222 std::ostringstream buf; 1223 buf << "attribute highp vec4 a_pos;\n" 1224 "attribute highp vec2 a_attr;\n"; 1225 1226 if (m_testType != TEST_TEX_COORD_CUBE) 1227 buf << "uniform highp sampler2D u_sampler;\n"; 1228 else 1229 buf << "uniform highp samplerCube u_sampler;\n"; 1230 1231 buf << "varying mediump vec4 v_out;\n" 1232 "void main ()\n" 1233 "{\n"; 1234 1235 if (m_testType == TEST_TEX_COORD) 1236 buf << " v_out = texture2DLod(u_sampler, a_attr, 0.0);\n"; 1237 else if (m_testType == TEST_LOD) 1238 buf << " v_out = texture2DLod(u_sampler, a_attr, a_attr.x);\n"; 1239 else if (m_testType == TEST_TEX_COORD_CUBE) 1240 buf << " v_out = textureCubeLod(u_sampler, vec3(a_attr, a_attr.x+a_attr.y), 0.0);\n"; 1241 else 1242 DE_ASSERT(DE_FALSE); 1243 1244 buf << "\n" 1245 " gl_Position = a_pos;\n" 1246 "}\n"; 1247 1248 return buf.str(); 1249 } 1250 1251 std::string TextureSamplerCase::genFragmentSource (void) const 1252 { 1253 // fragment shader is passthrough 1254 if (m_type == TYPE_VERTEX) 1255 return s_colorPassthroughFragmentShaderSource; 1256 1257 // fragment shader does the calculations 1258 std::ostringstream buf; 1259 if (m_testType != TEST_TEX_COORD_CUBE) 1260 buf << "uniform mediump sampler2D u_sampler;\n"; 1261 else 1262 buf << "uniform mediump samplerCube u_sampler;\n"; 1263 1264 buf << "varying mediump vec4 v_attr;\n" 1265 "void main ()\n" 1266 "{\n"; 1267 1268 if (m_testType == TEST_TEX_COORD) 1269 buf << " gl_FragColor = texture2D(u_sampler, v_attr.xy);\n"; 1270 else if (m_testType == TEST_LOD) 1271 buf << " gl_FragColor = texture2D(u_sampler, v_attr.xy, v_attr.x);\n"; 1272 else if (m_testType == TEST_TEX_COORD_CUBE) 1273 buf << " gl_FragColor = textureCube(u_sampler, vec3(v_attr.xy, v_attr.x + v_attr.y));\n"; 1274 else 1275 DE_ASSERT(DE_FALSE); 1276 1277 buf << "}\n"; 1278 1279 return buf.str(); 1280 } 1281 1282 /*--------------------------------------------------------------------*//*! 1283 * \brief Tests special floats as fragment shader outputs 1284 * 1285 * Tests that outputting special floats from a fragment shader does not change 1286 * the normal floating point values of outputted from a fragment shader. Special 1287 * floats are outputted in the green component, normal floating point values 1288 * in the red and blue component. Potential changes are tested by rendering 1289 * test pattern two times with different floating point values. The resulting 1290 * images' red and blue channels should be equal. 1291 *//*--------------------------------------------------------------------*/ 1292 class OutputCase : public FramebufferRenderCase 1293 { 1294 public: 1295 OutputCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type); 1296 ~OutputCase (void); 1297 1298 void testFBO (void); 1299 1300 private: 1301 std::string genVertexSource (void) const; 1302 std::string genFragmentSource (void) const; 1303 }; 1304 1305 OutputCase::OutputCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type) 1306 : FramebufferRenderCase (context, name, desc, type) 1307 { 1308 } 1309 1310 OutputCase::~OutputCase (void) 1311 { 1312 deinit(); 1313 } 1314 1315 void OutputCase::testFBO (void) 1316 { 1317 // Create a 1 X [s_specialFloats] grid of tiles (stripes). 1318 std::vector<tcu::Vec4> gridVertices ((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * 2); 1319 std::vector<deUint16> indices (DE_LENGTH_OF_ARRAY(s_specialFloats) * 6); 1320 tcu::TextureFormat textureFormat (tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8)); 1321 tcu::TextureLevel specialImage (textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1322 tcu::TextureLevel normalImage (textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1323 1324 // vertices 1325 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y) 1326 { 1327 const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1] 1328 1329 gridVertices[y * 2 + 0] = tcu::Vec4(-1.0, posY, 0.0f, 1.0f); 1330 gridVertices[y * 2 + 1] = tcu::Vec4( 1.0, posY, 0.0f, 1.0f); 1331 } 1332 1333 // tiles 1334 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y) 1335 { 1336 const int baseNdx = y * 6; 1337 1338 indices[baseNdx + 0] = (deUint16)((y + 0) * 2); 1339 indices[baseNdx + 1] = (deUint16)((y + 1) * 2); 1340 indices[baseNdx + 2] = (deUint16)((y + 1) * 2 + 1); 1341 1342 indices[baseNdx + 3] = (deUint16)((y + 0) * 2); 1343 indices[baseNdx + 4] = (deUint16)((y + 1) * 2 + 1); 1344 indices[baseNdx + 5] = (deUint16)((y + 0) * 2 + 1); 1345 } 1346 1347 // Draw grids 1348 { 1349 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1350 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos"); 1351 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special"); 1352 1353 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 1354 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1355 gl.useProgram(m_program->getProgram()); 1356 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw"); 1357 1358 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]); 1359 gl.enableVertexAttribArray(positionLoc); 1360 1361 // draw 2 passes. Special and normal. 1362 for (int passNdx = 0; passNdx < 2; ++passNdx) 1363 { 1364 const bool specialPass = (passNdx == 0); 1365 1366 m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx << ": Drawing stripes with the shader. Setting u_special for each stripe to (" << ((specialPass) ? ("special") : ("1.0")) << ")." << tcu::TestLog::EndMessage; 1367 1368 // draw stripes 1369 gl.clear(GL_COLOR_BUFFER_BIT); 1370 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y) 1371 { 1372 const deUint32 one = 0x3F800000; 1373 const deUint32 special = s_specialFloats[y]; 1374 const deUint32 uniformValue = (specialPass) ? (special) : (one); 1375 const int indexIndex = y * 6; 1376 1377 gl.uniform1fv(specialLoc, 1, (const float*)&uniformValue); 1378 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]); 1379 } 1380 1381 gl.finish(); 1382 glu::readPixels(m_context.getRenderContext(), 0, 0, ((specialPass) ? (specialImage) : (normalImage)).getAccess()); 1383 } 1384 1385 gl.disableVertexAttribArray(positionLoc); 1386 gl.useProgram(0); 1387 GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate"); 1388 } 1389 1390 // Check results 1391 { 1392 tcu::Surface errorMask (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1393 const tcu::RGBA badPixelColor = tcu::RGBA::red(); 1394 const tcu::RGBA okPixelColor = tcu::RGBA::green(); 1395 int badPixels = 0; 1396 1397 m_testCtx.getLog() << tcu::TestLog::Message << "Checking passes have identical red and blue channels and the green channel is correct in the constant pass." << tcu::TestLog::EndMessage; 1398 1399 for (int y = 0; y < specialImage.getHeight(); ++y) 1400 for (int x = 0; x < specialImage.getWidth(); ++x) 1401 { 1402 const float greenThreshold = 0.1f; 1403 const tcu::Vec4 cNormal = normalImage.getAccess().getPixel(x, y); 1404 const tcu::Vec4 cSpecial = specialImage.getAccess().getPixel(x, y); 1405 1406 if (cNormal.x() != cSpecial.x() || cNormal.z() != cSpecial.z() || cNormal.y() < 1.0f - greenThreshold) 1407 { 1408 ++badPixels; 1409 errorMask.setPixel(x, y, badPixelColor); 1410 } 1411 else 1412 errorMask.setPixel(x, y, okPixelColor); 1413 } 1414 1415 m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)." << tcu::TestLog::EndMessage; 1416 1417 if (badPixels) 1418 { 1419 m_testCtx.getLog() 1420 << tcu::TestLog::ImageSet("Results", "Result verification") 1421 << tcu::TestLog::Image("Image with special green channel", "Image with special green channel", specialImage) 1422 << tcu::TestLog::Image("Image with constant green channel", "Image with constant green channel", normalImage) 1423 << tcu::TestLog::Image("Error Mask", "Error Mask", errorMask) 1424 << tcu::TestLog::EndImageSet; 1425 1426 // all ok? 1427 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 1428 } 1429 else 1430 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1431 } 1432 } 1433 1434 std::string OutputCase::genVertexSource (void) const 1435 { 1436 return 1437 "attribute highp vec4 a_pos;\n" 1438 "varying mediump vec2 v_pos;\n" 1439 "void main ()\n" 1440 "{\n" 1441 " gl_Position = a_pos;\n" 1442 " v_pos = a_pos.xy;\n" 1443 "}\n"; 1444 } 1445 1446 std::string OutputCase::genFragmentSource (void) const 1447 { 1448 return 1449 "uniform mediump float u_special;\n" 1450 "varying mediump vec2 v_pos;\n" 1451 "void main ()\n" 1452 "{\n" 1453 " gl_FragColor = vec4((v_pos.x + 1.0) * 0.5, u_special, (v_pos.y + 1.0) * 0.5, 1.0);\n" 1454 "}\n"; 1455 } 1456 1457 /*--------------------------------------------------------------------*//*! 1458 * \brief Tests special floats in blending 1459 * 1460 * Tests special floats as alpha and color components with various blending 1461 * modes. Test draws a test pattern and then does various blend operations 1462 * with special float values. After the blending test another test pattern 1463 * is drawn to detect possible blending anomalies. Test patterns should be 1464 * identical. 1465 *//*--------------------------------------------------------------------*/ 1466 class BlendingCase : public FramebufferRenderCase 1467 { 1468 public: 1469 BlendingCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type); 1470 ~BlendingCase (void); 1471 1472 void testFBO (void); 1473 1474 private: 1475 void drawTestImage (tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex); 1476 1477 std::string genVertexSource (void) const; 1478 std::string genFragmentSource (void) const; 1479 }; 1480 1481 BlendingCase::BlendingCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type) 1482 : FramebufferRenderCase (context, name, desc, type) 1483 { 1484 } 1485 1486 BlendingCase::~BlendingCase (void) 1487 { 1488 deinit(); 1489 } 1490 1491 void BlendingCase::testFBO (void) 1492 { 1493 static const GLenum equations[] = 1494 { 1495 GL_FUNC_ADD, 1496 GL_FUNC_SUBTRACT, 1497 GL_FUNC_REVERSE_SUBTRACT, 1498 }; 1499 static const GLenum functions[] = 1500 { 1501 GL_ZERO, 1502 GL_ONE, 1503 GL_SRC_COLOR, 1504 GL_ONE_MINUS_SRC_COLOR, 1505 GL_SRC_ALPHA, 1506 GL_ONE_MINUS_SRC_ALPHA, 1507 }; 1508 1509 // Create a [BlendFuncs] X [s_specialFloats] grid of tiles. ( BlendFuncs = equations x functions ) 1510 1511 const int numBlendFuncs = DE_LENGTH_OF_ARRAY(equations) * DE_LENGTH_OF_ARRAY(functions); 1512 std::vector<tcu::Vec4> gridVertices ((numBlendFuncs + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1)); 1513 std::vector<deUint16> indices (numBlendFuncs * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6); 1514 tcu::TextureFormat textureFormat (tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8)); 1515 tcu::TextureLevel beforeImage (textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1516 tcu::TextureLevel afterImage (textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1517 1518 // vertices 1519 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x) 1520 for (int y = 0; y < numBlendFuncs + 1; ++y) 1521 { 1522 const float posX = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats)] to [-1, 1] 1523 const float posY = (float)y / (float)numBlendFuncs * 2.0f - 1.0f; 1524 1525 gridVertices[x * (numBlendFuncs + 1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f); 1526 } 1527 1528 // tiles 1529 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x) 1530 for (int y = 0; y < numBlendFuncs; ++y) 1531 { 1532 const int baseNdx = (x * numBlendFuncs + y) * 6; 1533 1534 indices[baseNdx + 0] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+0)); 1535 indices[baseNdx + 1] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+1)); 1536 indices[baseNdx + 2] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+0)); 1537 1538 indices[baseNdx + 3] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+0)); 1539 indices[baseNdx + 4] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+1)); 1540 indices[baseNdx + 5] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+1)); 1541 } 1542 1543 // Draw tiles 1544 { 1545 const int numPasses = 5; 1546 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1547 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos"); 1548 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special"); 1549 1550 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 1551 gl.clear(GL_COLOR_BUFFER_BIT); 1552 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1553 gl.useProgram(m_program->getProgram()); 1554 gl.enable(GL_BLEND); 1555 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw"); 1556 1557 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]); 1558 gl.enableVertexAttribArray(positionLoc); 1559 1560 // draw "before" image 1561 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing pre-draw pattern." << tcu::TestLog::EndMessage; 1562 drawTestImage(beforeImage.getAccess(), specialLoc, (int)gridVertices.size() - 1); 1563 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw pattern"); 1564 1565 // draw multiple passes with special floats 1566 gl.clear(GL_COLOR_BUFFER_BIT); 1567 for (int passNdx = 0; passNdx < numPasses; ++passNdx) 1568 { 1569 de::Random rnd(123 + 567 * passNdx); 1570 1571 m_testCtx.getLog() 1572 << tcu::TestLog::Message 1573 << "Pass " << passNdx << ": Drawing tiles with the shader.\n" 1574 << "\tVarying u_special for each tile.\n" 1575 << "\tVarying blend function and blend equation for each tile.\n" 1576 << tcu::TestLog::EndMessage; 1577 1578 // draw tiles 1579 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x) 1580 for (int y = 0; y < numBlendFuncs; ++y) 1581 { 1582 const GLenum blendEquation = equations[y % DE_LENGTH_OF_ARRAY(equations)]; 1583 const GLenum blendFunction = functions[y / DE_LENGTH_OF_ARRAY(equations)]; 1584 const GLenum blendFunctionDst = rnd.choose<GLenum>(DE_ARRAY_BEGIN(functions), DE_ARRAY_END(functions)); 1585 const int indexIndex = (x * numBlendFuncs + y) * 6; 1586 1587 // "rnd.get"s are run in a deterministic order 1588 const deUint32 componentR = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats)); 1589 const deUint32 componentG = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats)); 1590 const deUint32 componentB = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats)); 1591 const deUint32 componentA = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats)); 1592 const tcu::UVec4 uniformValue = tcu::UVec4(componentR, componentG, componentB, componentA); 1593 1594 gl.uniform4fv(specialLoc, 1, (const float*)uniformValue.getPtr()); 1595 gl.blendEquation(blendEquation); 1596 gl.blendFunc(blendFunction, blendFunctionDst); 1597 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]); 1598 } 1599 } 1600 GLU_EXPECT_NO_ERROR(gl.getError(), "special passes"); 1601 1602 // draw "after" image 1603 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing post-draw pattern." << tcu::TestLog::EndMessage; 1604 drawTestImage(afterImage.getAccess(), specialLoc, (int)gridVertices.size() - 1); 1605 GLU_EXPECT_NO_ERROR(gl.getError(), "post-draw pattern"); 1606 1607 gl.disableVertexAttribArray(positionLoc); 1608 gl.useProgram(0); 1609 GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate"); 1610 } 1611 1612 // Check results 1613 { 1614 tcu::Surface errorMask (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE); 1615 const tcu::RGBA badPixelColor = tcu::RGBA::red(); 1616 const tcu::RGBA okPixelColor = tcu::RGBA::green(); 1617 int badPixels = 0; 1618 1619 m_testCtx.getLog() << tcu::TestLog::Message << "Checking patterns are identical." << tcu::TestLog::EndMessage; 1620 1621 for (int y = 0; y < beforeImage.getHeight(); ++y) 1622 for (int x = 0; x < beforeImage.getWidth(); ++x) 1623 { 1624 const tcu::Vec4 cBefore = beforeImage.getAccess().getPixel(x, y); 1625 const tcu::Vec4 cAfter = afterImage.getAccess().getPixel(x, y); 1626 1627 if (cBefore != cAfter) 1628 { 1629 ++badPixels; 1630 errorMask.setPixel(x, y, badPixelColor); 1631 } 1632 else 1633 errorMask.setPixel(x, y, okPixelColor); 1634 } 1635 1636 m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)." << tcu::TestLog::EndMessage; 1637 1638 if (badPixels) 1639 { 1640 m_testCtx.getLog() 1641 << tcu::TestLog::ImageSet("Results", "Result verification") 1642 << tcu::TestLog::Image("Pattern drawn before special float blending", "Pattern drawn before special float blending", beforeImage) 1643 << tcu::TestLog::Image("Pattern drawn after special float blending", "Pattern drawn after special float blending", afterImage) 1644 << tcu::TestLog::EndImageSet; 1645 1646 // all ok? 1647 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 1648 } 1649 else 1650 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1651 } 1652 } 1653 1654 void BlendingCase::drawTestImage (tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex) 1655 { 1656 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1657 de::Random rnd (123); 1658 1659 gl.clear(GL_COLOR_BUFFER_BIT); 1660 gl.blendEquation(GL_FUNC_ADD); 1661 gl.blendFunc(GL_ONE, GL_ONE); 1662 1663 for (int tri = 0; tri < 20; ++tri) 1664 { 1665 tcu::Vec4 color; 1666 color.x() = rnd.getFloat(); 1667 color.y() = rnd.getFloat(); 1668 color.z() = rnd.getFloat(); 1669 color.w() = rnd.getFloat(); 1670 gl.uniform4fv(uColorLoc, 1, color.getPtr()); 1671 1672 deUint16 indices[3]; 1673 indices[0] = (deUint16)rnd.getInt(0, maxVertexIndex); 1674 indices[1] = (deUint16)rnd.getInt(0, maxVertexIndex); 1675 indices[2] = (deUint16)rnd.getInt(0, maxVertexIndex); 1676 1677 gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices); 1678 } 1679 1680 gl.finish(); 1681 glu::readPixels(m_context.getRenderContext(), 0, 0, dst); 1682 } 1683 1684 std::string BlendingCase::genVertexSource (void) const 1685 { 1686 return 1687 "attribute highp vec4 a_pos;\n" 1688 "void main ()\n" 1689 "{\n" 1690 " gl_Position = a_pos;\n" 1691 "}\n"; 1692 } 1693 1694 std::string BlendingCase::genFragmentSource (void) const 1695 { 1696 return 1697 "uniform mediump vec4 u_special;\n" 1698 "void main ()\n" 1699 "{\n" 1700 " gl_FragColor = u_special;\n" 1701 "}\n"; 1702 } 1703 1704 } //anonymous 1705 1706 SpecialFloatTests::SpecialFloatTests (Context& context) 1707 : TestCaseGroup(context, "special_float", "Special float tests") 1708 { 1709 } 1710 1711 SpecialFloatTests::~SpecialFloatTests (void) 1712 { 1713 } 1714 1715 void SpecialFloatTests::init (void) 1716 { 1717 tcu::TestCaseGroup* const vertexGroup = new tcu::TestCaseGroup(m_testCtx, "vertex", "Run vertex shader with special float values"); 1718 tcu::TestCaseGroup* const fragmentGroup = new tcu::TestCaseGroup(m_testCtx, "fragment", "Run fragment shader with special float values"); 1719 tcu::TestCaseGroup* const framebufferGroup = new tcu::TestCaseGroup(m_testCtx, "framebuffer", "Test framebuffers containing special float values"); 1720 1721 // .vertex 1722 { 1723 vertexGroup->addChild(new VertexAttributeCase (m_context, "attribute_buffer", "special attribute values in a buffer", VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_VERTEX)); 1724 vertexGroup->addChild(new VertexAttributeCase (m_context, "attribute_client", "special attribute values in a client storage", VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_VERTEX)); 1725 vertexGroup->addChild(new UniformCase (m_context, "uniform", "special uniform values", UniformCase::TYPE_VERTEX)); 1726 vertexGroup->addChild(new TextureSamplerCase (m_context, "sampler_tex_coord", "special texture coords", TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD)); 1727 vertexGroup->addChild(new TextureSamplerCase (m_context, "sampler_tex_coord_cube", "special texture coords to cubemap", TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD_CUBE)); 1728 vertexGroup->addChild(new TextureSamplerCase (m_context, "sampler_lod", "special texture lod", TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_LOD)); 1729 1730 addChild(vertexGroup); 1731 } 1732 1733 // .fragment 1734 { 1735 fragmentGroup->addChild(new VertexAttributeCase (m_context, "attribute_buffer", "special attribute values in a buffer", VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_FRAGMENT)); 1736 fragmentGroup->addChild(new VertexAttributeCase (m_context, "attribute_client", "special attribute values in a client storage", VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_FRAGMENT)); 1737 fragmentGroup->addChild(new UniformCase (m_context, "uniform", "special uniform values", UniformCase::TYPE_FRAGMENT)); 1738 fragmentGroup->addChild(new TextureSamplerCase (m_context, "sampler_tex_coord", "special texture coords", TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD)); 1739 fragmentGroup->addChild(new TextureSamplerCase (m_context, "sampler_tex_coord_cube", "special texture coords to cubemap", TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD_CUBE)); 1740 fragmentGroup->addChild(new TextureSamplerCase (m_context, "sampler_lod", "special texture lod", TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_LOD)); 1741 1742 addChild(fragmentGroup); 1743 } 1744 1745 // .framebuffer 1746 { 1747 framebufferGroup->addChild(new OutputCase (m_context, "write_default", "write special floating point values to default framebuffer", FramebufferRenderCase::FBO_DEFAULT)); 1748 framebufferGroup->addChild(new OutputCase (m_context, "write_rgba", "write special floating point values to RGBA framebuffer", FramebufferRenderCase::FBO_RGBA)); 1749 framebufferGroup->addChild(new OutputCase (m_context, "write_rgba4", "write special floating point values to RGBA4 framebuffer", FramebufferRenderCase::FBO_RGBA4)); 1750 framebufferGroup->addChild(new OutputCase (m_context, "write_rgb5_a1", "write special floating point values to RGB5_A1 framebuffer", FramebufferRenderCase::FBO_RGB5_A1)); 1751 framebufferGroup->addChild(new OutputCase (m_context, "write_rgb565", "write special floating point values to RGB565 framebuffer", FramebufferRenderCase::FBO_RGB565)); 1752 framebufferGroup->addChild(new OutputCase (m_context, "write_float16", "write special floating point values to float16 framebuffer", FramebufferRenderCase::FBO_RGBA_FLOAT16)); 1753 1754 framebufferGroup->addChild(new BlendingCase (m_context, "blend_default", "blend special floating point values in a default framebuffer", FramebufferRenderCase::FBO_DEFAULT)); 1755 framebufferGroup->addChild(new BlendingCase (m_context, "blend_rgba", "blend special floating point values in a RGBA framebuffer", FramebufferRenderCase::FBO_RGBA)); 1756 framebufferGroup->addChild(new BlendingCase (m_context, "blend_float16", "blend special floating point values in a float16 framebuffer", FramebufferRenderCase::FBO_RGBA_FLOAT16)); 1757 1758 addChild(framebufferGroup); 1759 } 1760 } 1761 1762 } // Stress 1763 } // gles2 1764 } // deqp 1765