1/*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2014-2019 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/** 25 * \file gl2fClipControlTests.cpp 26 * \brief Implements conformance tests for "EXT_clip_control" functionality. 27 */ /*-------------------------------------------------------------------*/ 28 29#include "es2fClipControlTests.hpp" 30 31#include "deSharedPtr.hpp" 32 33#include "gluContextInfo.hpp" 34#include "gluDrawUtil.hpp" 35#include "gluDefs.hpp" 36#include "gluPixelTransfer.hpp" 37#include "gluShaderProgram.hpp" 38 39#include "tcuFuzzyImageCompare.hpp" 40#include "tcuImageCompare.hpp" 41#include "tcuRenderTarget.hpp" 42#include "tcuSurface.hpp" 43#include "tcuTestLog.hpp" 44 45#include "glw.h" 46#include "glwFunctions.hpp" 47 48#include <cmath> 49 50namespace deqp 51{ 52namespace gles2 53{ 54namespace Functional 55{ 56 57class ClipControlApi 58{ 59public: 60 ClipControlApi(Context& context) : m_context(context) 61 { 62 if (!Supported(m_context)) 63 { 64 throw tcu::NotSupportedError("Required extension EXT_clip_control is not supported"); 65 } 66 clipControl = context.getRenderContext().getFunctions().clipControl; 67 } 68 69 static bool Supported(Context& context) 70 { 71 return context.getContextInfo().isExtensionSupported("GL_EXT_clip_control"); 72 } 73 74 glw::glClipControlFunc clipControl; 75 76private: 77 Context& m_context; 78}; 79 80class ClipControlBaseTest : public TestCase 81{ 82protected: 83 ClipControlBaseTest(Context& context, const char* name, const char* description) 84 : TestCase(context, name, description) 85 { 86 } 87 88 void init() override 89 { 90 ClipControlApi api(m_context); 91 } 92 93 bool verifyState(glw::GLenum origin, glw::GLenum depth) 94 { 95 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 96 97 bool ret = true; 98 99 glw::GLint retI; 100 gl.getIntegerv(GL_CLIP_ORIGIN, &retI); 101 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_CLIP_ORIGIN"); 102 103 ret &= (static_cast<glw::GLenum>(retI) == origin); 104 105 gl.getIntegerv(GL_CLIP_DEPTH_MODE, &retI); 106 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_CLIP_DEPTH_MODE"); 107 108 ret &= (static_cast<glw::GLenum>(retI) == depth); 109 110 return ret; 111 } 112}; 113 114class ClipControlRenderBaseTest : public ClipControlBaseTest 115{ 116protected: 117 ClipControlRenderBaseTest(Context& context, const char* name, const char* description) 118 : ClipControlBaseTest(context, name, description), m_fbo(0), m_rboC(0), m_depthTexure(0) 119 { 120 } 121 122 const char* fsh() 123 { 124 return "void main() {" 125 "\n" 126 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);" 127 "\n" 128 "}"; 129 } 130 131 bool fuzzyDepthCompare(tcu::TestLog& log, const char* imageSetName, const char* imageSetDesc, 132 const tcu::TextureLevel& reference, const tcu::TextureLevel& result, float threshold, 133 const tcu::TextureLevel* importanceMask = NULL) 134 { 135 (void)imageSetName; 136 (void)imageSetDesc; 137 bool depthOk = true; 138 float difference = 0.0f; 139 140 for (int y = 0; y < result.getHeight() && depthOk; y++) 141 { 142 for (int x = 0; x < result.getWidth() && depthOk; x++) 143 { 144 float ref = reference.getAccess().getPixDepth(x, y); 145 float res = result.getAccess().getPixel(x,y).x(); 146 difference = std::abs(ref - res); 147 if (importanceMask) 148 { 149 difference *= importanceMask->getAccess().getPixDepth(x, y); 150 } 151 depthOk &= (difference < threshold); 152 } 153 } 154 155 if (!depthOk) 156 log << tcu::TestLog::Message << "Image comparison failed: difference = " << difference 157 << ", threshold = " << threshold << tcu::TestLog::EndMessage; 158 tcu::Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f); 159 tcu::Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f); 160 log << tcu::TestLog::ImageSet("Result", "Depth image comparison result") 161 << tcu::TestLog::Image("Result", "Result", result.getAccess(), pixelScale, pixelBias) 162 << tcu::TestLog::Image("Reference", "Reference", reference.getAccess(), pixelScale, pixelBias); 163 if (importanceMask) 164 { 165 log << tcu::TestLog::Image("Importance mask", "mask", importanceMask->getAccess(), pixelScale, pixelBias); 166 } 167 log << tcu::TestLog::EndImageSet; 168 169 return depthOk; 170 } 171 172 virtual void init(void) 173 { 174 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 175 glw::GLuint viewportW = renderTarget.getWidth(); 176 glw::GLuint viewportH = renderTarget.getHeight(); 177 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 178 179 gl.genFramebuffers(1, &m_fbo); 180 gl.genRenderbuffers(1, &m_rboC); 181 gl.genTextures(1, &m_depthTexure); 182 183 gl.bindRenderbuffer(GL_RENDERBUFFER, m_rboC); 184 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, viewportW, viewportH); 185 186 gl.bindTexture(GL_TEXTURE_2D, m_depthTexure); 187 gl.texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewportW, viewportH, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, DE_NULL); 188 189 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 190 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rboC); 191 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexure, 0); 192 } 193 194 virtual void deinit(void) 195 { 196 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 197 gl.deleteFramebuffers(1, &m_fbo); 198 gl.deleteRenderbuffers(1, &m_rboC); 199 gl.deleteTextures(1, &m_depthTexure); 200 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 201 } 202 203 GLuint getDepthTexture() 204 { 205 return m_depthTexure; 206 } 207 208private: 209 GLuint m_fbo, m_rboC, m_depthTexure; 210}; 211 212/* 213 Verify the following state values are implemented and return a valid 214 initial value by calling GetIntegerv: 215 216 Get Value Initial Value 217 ------------------------------------------------------- 218 CLIP_ORIGIN LOWER_LEFT 219 CLIP_DEPTH_MODE NEGATIVE_ONE_TO_ONE 220 221 Verify no GL error is generated. 222 */ 223class ClipControlInitialState : public ClipControlBaseTest 224{ 225public: 226 ClipControlInitialState(Context& context, const char* name) 227 : ClipControlBaseTest(context, name, "Verify initial state") 228 { 229 } 230 231 IterateResult iterate() override 232 { 233 if (!verifyState(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE)) 234 { 235 TCU_FAIL("Wrong intitial state: GL_CLIP_ORIGIN should be GL_LOWER_LEFT," 236 " GL_CLIP_ORIGIN should be NEGATIVE_ONE_TO_ONE"); 237 } 238 239 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS)); 240 return STOP; 241 } 242}; 243 244/* 245 Modify the state to each of the following combinations and after each 246 state change verify the state values: 247 248 ClipControl(UPPER_LEFT, ZERO_TO_ONE) 249 ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE) 250 ClipControl(LOWER_LEFT, ZERO_TO_ONE) 251 ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE) 252 253 Verify no GL error is generated. 254 255 */ 256class ClipControlModifyGetState : public ClipControlBaseTest 257{ 258public: 259 ClipControlModifyGetState(Context& context, const char* name) 260 : ClipControlBaseTest(context, name, "Verify initial state") 261 { 262 } 263 264 void deinit() override 265 { 266 if (ClipControlApi::Supported(m_context)) 267 { 268 ClipControlApi cc(m_context); 269 cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); 270 } 271 } 272 273 IterateResult iterate() override 274 { 275 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 276 ClipControlApi cc(m_context); 277 278 GLenum cases[4][2] = { 279 { GL_UPPER_LEFT, GL_ZERO_TO_ONE }, 280 { GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE }, 281 { GL_LOWER_LEFT, GL_ZERO_TO_ONE }, 282 { GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE }, 283 }; 284 285 for (size_t i = 0; i < DE_LENGTH_OF_ARRAY(cases); i++) 286 { 287 cc.clipControl(cases[i][0], cases[i][1]); 288 GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()"); 289 if (!verifyState(cases[i][0], cases[i][1])) 290 { 291 TCU_FAIL("Wrong ClipControl state after ClipControl() call"); 292 } 293 } 294 295 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS)); 296 return STOP; 297 } 298}; 299 300/* 301 Check that ClipControl generate an GL_INVALID_ENUM error if origin is 302 not GL_LOWER_LEFT or GL_UPPER_LEFT. 303 304 Check that ClipControl generate an GL_INVALID_ENUM error if depth is 305 not GL_NEGATIVE_ONE_TO_ONE or GL_ZERO_TO_ONE. 306 307 Test is based on OpenGL 4.5 Core Profile Specification May 28th Section 308 13.5 Primitive Clipping: 309 "An INVALID_ENUM error is generated if origin is not LOWER_LEFT or 310 UPPER_LEFT. 311 An INVALID_ENUM error is generated if depth is not NEGATIVE_ONE_- 312 TO_ONE or ZERO_TO_ONE." 313 */ 314class ClipControlErrors : public ClipControlBaseTest 315{ 316public: 317 ClipControlErrors(Context& context, const char* name) 318 : ClipControlBaseTest(context, name, "Verify that proper errors are generated when using ClipControl.") 319 { 320 } 321 322 void deinit() override 323 { 324 if (ClipControlApi::Supported(m_context)) 325 { 326 ClipControlApi cc(m_context); 327 cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); 328 } 329 } 330 331 IterateResult iterate() override 332 { 333 /* API query */ 334 tcu::TestLog& log = m_testCtx.getLog(); 335 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 336 ClipControlApi cc(m_context); 337 338 /* Finding improper value. */ 339 GLenum improper_value = GL_NONE; 340 341 while ((GL_UPPER_LEFT == improper_value) || (GL_LOWER_LEFT == improper_value) || 342 (GL_ZERO_TO_ONE == improper_value) || (GL_NEGATIVE_ONE_TO_ONE == improper_value)) 343 { 344 ++improper_value; 345 } 346 347 /* Test setup. */ 348 GLenum cases[5][2] = { { GL_UPPER_LEFT, improper_value }, 349 { GL_LOWER_LEFT, improper_value }, 350 { improper_value, GL_ZERO_TO_ONE }, 351 { improper_value, GL_NEGATIVE_ONE_TO_ONE }, 352 { improper_value, improper_value } }; 353 354 /* Test iterations. */ 355 for (size_t i = 0; i < DE_LENGTH_OF_ARRAY(cases); i++) 356 { 357 cc.clipControl(cases[i][0], cases[i][1]); 358 359 if (GL_INVALID_ENUM != gl.getError()) 360 { 361 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL)); 362 363 log << tcu::TestLog::Message 364 << "ClipControl have not generated GL_INVALID_ENUM error when called with invalid value (" 365 << cases[i][0] << ", " << cases[i][1] << ")." << tcu::TestLog::EndMessage; 366 } 367 } 368 369 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS)); 370 return STOP; 371 } 372}; 373 374/* 375 Clip Control Origin Test 376 377 * Basic <origin> behavior can be tested by rendering to a viewport with 378 clip coordinates where -1.0 <= x_c <= 0.0 and -1.0 <= y_c <= 0.0. 379 When <origin> is LOWER_LEFT the "bottom left" portion of the window 380 is rendered and when UPPER_LEFT is used the "top left" portion of the 381 window is rendered. The default framebuffer should be bound. Here is the 382 basic outline of the test: 383 384 - Clear the default framebuffer to red (1,0,0). 385 - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE) 386 - Render a triangle fan covering (-1.0, -1.0) to (0.0, 0.0) and 387 write a pixel value of green (0,1,0). 388 - Read back the default framebuffer with ReadPixels 389 - Verify the green pixels at the top and red at the bottom. 390 391 Repeat the above test with LOWER_LEFT and verify green at the bottom 392 and red at the top. 393 */ 394class ClipControlOriginTest : public ClipControlRenderBaseTest 395{ 396public: 397 ClipControlOriginTest(Context& context, const char* name) 398 : ClipControlRenderBaseTest(context, name, "Clip Control Origin Test"), m_vao(0), m_vbo(0) 399 { 400 } 401 402 void deinit() override 403 { 404 ClipControlRenderBaseTest::deinit(); 405 406 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 407 if (ClipControlApi::Supported(m_context)) 408 { 409 ClipControlApi cc(m_context); 410 cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); 411 } 412 413 gl.clearColor(0.0, 0.0, 0.0, 0.0); 414 if (m_vao) 415 { 416 gl.deleteVertexArrays(1, &m_vao); 417 } 418 if (m_vbo) 419 { 420 gl.deleteBuffers(1, &m_vbo); 421 } 422 } 423 424 IterateResult iterate() override 425 { 426 427 tcu::TestLog& log = m_testCtx.getLog(); 428 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 429 ClipControlApi cc(m_context); 430 431 //Render a triangle fan covering(-1.0, -1.0) to(1.0, 0.0) and 432 //write a pixel value of green(0, 1, 0). 433 434 de::SharedPtr<glu::ShaderProgram> program( 435 new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh()))); 436 437 log << (*program); 438 if (!program->isOk()) 439 { 440 TCU_FAIL("Program compilation failed"); 441 } 442 443 gl.genVertexArrays(1, &m_vao); 444 gl.bindVertexArray(m_vao); 445 446 gl.genBuffers(1, &m_vbo); 447 448 const float vertex_data0[] = { -1.0, -1.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0 }; 449 450 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo); 451 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW); 452 453 gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); 454 gl.enableVertexAttribArray(0); 455 456 gl.useProgram(program->getProgram()); 457 458 glw::GLenum origins[] = { GL_UPPER_LEFT, GL_LOWER_LEFT }; 459 460 qpTestResult result = QP_TEST_RESULT_PASS; 461 462 for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++) 463 { 464 //Clear the default framebuffer to red(1, 0, 0). 465 gl.clearColor(1.0, 0.0, 0.0, 1.0); 466 gl.clear(GL_COLOR_BUFFER_BIT); 467 468 //Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE) 469 cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE); 470 GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()"); 471 472 //test method modification: use GL_TRIANGLE_STRIP, not FAN. 473 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 474 475 //Read back the default framebuffer with ReadPixels 476 //Verify the green pixels at the top and red at the bottom. 477 qpTestResult loopResult = ValidateFramebuffer(m_context, origins[orig]); 478 if (loopResult != QP_TEST_RESULT_PASS) 479 { 480 result = loopResult; 481 } 482 } 483 484 m_testCtx.setTestResult(result, qpGetTestResultName(result)); 485 486 return STOP; 487 } 488 489 const char* vsh() 490 { 491 return "attribute highp vec2 Position;" 492 "\n" 493 "void main() {" 494 "\n" 495 " gl_Position = vec4(Position, 0.0, 1.0);" 496 "\n" 497 "}"; 498 } 499 500 qpTestResult ValidateFramebuffer(Context& context, glw::GLenum origin) 501 { 502 const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget(); 503 glw::GLsizei viewportW = renderTarget.getWidth(); 504 glw::GLsizei viewportH = renderTarget.getHeight(); 505 tcu::Surface renderedFrame(viewportW, viewportH); 506 tcu::Surface referenceFrame(viewportW, viewportH); 507 508 tcu::TestLog& log = context.getTestContext().getLog(); 509 510 for (int y = 0; y < renderedFrame.getHeight(); y++) 511 { 512 float yCoord = (float)(y) / (float)renderedFrame.getHeight(); 513 514 for (int x = 0; x < renderedFrame.getWidth(); x++) 515 { 516 517 float xCoord = (float)(x) / (float)renderedFrame.getWidth(); 518 519 bool greenQuadrant; 520 521 if (origin == GL_UPPER_LEFT) 522 { 523 greenQuadrant = (yCoord > 0.5 && xCoord <= 0.5); 524 } 525 else 526 { 527 greenQuadrant = (yCoord <= 0.5 && xCoord <= 0.5); 528 } 529 530 if (greenQuadrant) 531 { 532 referenceFrame.setPixel(x, y, tcu::RGBA::green()); 533 } 534 else 535 { 536 referenceFrame.setPixel(x, y, tcu::RGBA::red()); 537 } 538 } 539 } 540 541 glu::readPixels(context.getRenderContext(), 0, 0, renderedFrame.getAccess()); 542 543 if (tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, 544 tcu::COMPARE_LOG_RESULT)) 545 { 546 return QP_TEST_RESULT_PASS; 547 } 548 else 549 { 550 return QP_TEST_RESULT_FAIL; 551 } 552 } 553 554 glw::GLuint m_vao, m_vbo; 555}; 556 557 558 559/* 560 Clip Control Origin With Face Culling Test 561 562 * Face culling should be tested with both <origin> settings. 563 The reason for that is, when doing Y-inversion, implementation 564 should not flip the calculated area sign for the triangle. 565 In other words, culling of CCW and CW triangles should 566 be orthogonal to used <origin> mode. Both triangle windings 567 and both <origin> modes should be tested. Here is the basic 568 outline of the test: 569 570 - Clear the framebuffer to red (1,0,0). 571 - Enable GL_CULL_FACE, leave default front face & cull face (CCW, BACK) 572 - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE) 573 - Render a counter-clockwise triangles covering 574 (-1.0, -1.0) to (0.0, 1.0) and write a pixel value of green (0,1,0). 575 - Render a clockwise triangles covering 576 (0.0, -1.0) to (1.0, 1.0) and write a pixel value of green (0,1,0). 577 - Read back the framebuffer with ReadPixels 578 - Verify the green pixels at the left and red at the right. 579 580 Repeat above test for ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE) 581 */ 582class ClipControlFaceCulling : public ClipControlRenderBaseTest 583{ 584public: 585 ClipControlFaceCulling(Context& context, const char* name) 586 : ClipControlRenderBaseTest(context, name, "Face culling test, both origins"), m_vao(0), m_vbo(0) 587 { 588 } 589 590 void deinit() 591 { 592 ClipControlRenderBaseTest::deinit(); 593 594 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 595 596 if (ClipControlApi::Supported(m_context)) 597 { 598 ClipControlApi cc(m_context); 599 cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); 600 } 601 602 gl.disable(GL_CULL_FACE); 603 604 gl.clearColor(0.0, 0.0, 0.0, 0.0); 605 606 gl.disable(GL_DEPTH_TEST); 607 gl.depthFunc(GL_LESS); 608 609 if (m_vao) 610 { 611 gl.deleteVertexArrays(1, &m_vao); 612 } 613 if (m_vbo) 614 { 615 gl.deleteBuffers(1, &m_vbo); 616 } 617 } 618 619 IterateResult iterate() 620 { 621 622 tcu::TestLog& log = m_testCtx.getLog(); 623 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 624 ClipControlApi cc(m_context); 625 626 //Enable GL_CULL_FACE, leave default front face & cull face(CCW, BACK) 627 gl.enable(GL_CULL_FACE); 628 629 //Render a counter-clockwise triangles covering 630 //(-1.0, -1.0) to(0.0, 1.0) and write a pixel value of green(0, 1, 0). 631 //Render a clockwise triangles covering 632 //(0.0, -1.0) to(1.0, 1.0) and write a pixel value of green(0, 1, 0). 633 de::SharedPtr<glu::ShaderProgram> program( 634 new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh()))); 635 636 log << (*program); 637 if (!program->isOk()) 638 { 639 TCU_FAIL("Program compilation failed"); 640 } 641 642 gl.genVertexArrays(1, &m_vao); 643 gl.bindVertexArray(m_vao); 644 645 gl.genBuffers(1, &m_vbo); 646 647 const float vertex_data0[] = { 648 //CCW 649 -1.0, -1.0, 0.0, -1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, -1.0, 1.0, 650 //CW 651 0.0, -1.0, 0.0, 1.0, 1.0, -1.0, 1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 652 }; 653 654 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo); 655 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW); 656 657 gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); 658 gl.enableVertexAttribArray(0); 659 660 gl.useProgram(program->getProgram()); 661 662 glw::GLenum origins[] = { GL_UPPER_LEFT, GL_LOWER_LEFT }; 663 664 qpTestResult result = QP_TEST_RESULT_PASS; 665 666 for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++) 667 { 668 //Clear the framebuffer to red (1,0,0). 669 gl.clearColor(1.0, 0.0, 0.0, 1.0); 670 gl.clear(GL_COLOR_BUFFER_BIT); 671 672 gl.drawArrays(GL_TRIANGLES, 0, 12); 673 674 //Set ClipControl(<origin>, NEGATIVE_ONE_TO_ONE) 675 cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE); 676 GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()"); 677 678 //Read back the framebuffer with ReadPixels 679 //Verify the green pixels at the left and red at the right. 680 qpTestResult loopResult = ValidateFramebuffer(m_context); 681 if (loopResult != QP_TEST_RESULT_PASS) 682 { 683 result = loopResult; 684 } 685 } 686 m_testCtx.setTestResult(result, qpGetTestResultName(result)); 687 688 return STOP; 689 } 690 691 const char* vsh() 692 { 693 return "attribute highp vec3 Position;" 694 "\n" 695 "void main() {" 696 "\n" 697 " gl_Position = vec4(Position, 1.0);" 698 "\n" 699 "}"; 700 } 701 702 qpTestResult ValidateFramebuffer(Context& context) 703 { 704 const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget(); 705 glw::GLsizei viewportW = renderTarget.getWidth(); 706 glw::GLsizei viewportH = renderTarget.getHeight(); 707 tcu::Surface renderedColorFrame(viewportW, viewportH); 708 tcu::Surface referenceColorFrame(viewportW, viewportH); 709 tcu::TestLog& log = context.getTestContext().getLog(); 710 711 for (int y = 0; y < renderedColorFrame.getHeight(); y++) 712 { 713 for (int x = 0; x < renderedColorFrame.getWidth(); x++) 714 { 715 float xCoord = (float)(x) / (float)renderedColorFrame.getWidth(); 716 717 if (xCoord < 0.5f) 718 { 719 referenceColorFrame.setPixel(x, y, tcu::RGBA::green()); 720 } 721 else 722 { 723 referenceColorFrame.setPixel(x, y, tcu::RGBA::red()); 724 } 725 } 726 } 727 728 glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess()); 729 if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame, 730 0.05f, tcu::COMPARE_LOG_RESULT)) 731 { 732 733 return QP_TEST_RESULT_FAIL; 734 } 735 return QP_TEST_RESULT_PASS; 736 } 737 738 glw::GLuint m_vao, m_vbo; 739}; 740 741/* 742 Viewport Bounds Test 743 744 * Viewport bounds should be tested, to ensure that rendering with flipped 745 origin affects only viewport area. 746 747 This can be done by clearing the window to blue, making viewport 748 a non-symmetric-in-any-way subset of the window, than rendering 749 full-viewport multiple color quad. The (-1.0, -1.0)..(0.0, 0.0) quadrant 750 of a quad is red, the rest is green. 751 Whatever the origin is, the area outside of the viewport should stay blue. 752 If origin is LOWER_LEFT the "lower left" portion of the viewport is red, 753 if origin is UPPER_LEFT the "top left" portion of the viewport is red 754 (and in both cases the rest of viewport is green). 755 756 Here is the basic outline of the test: 757 758 - Clear the default framebuffer to blue (0,0,1). 759 - Set viewport to A = (x, y, w, h) = (1/8, 1/4, 1/2, 1/4) in terms of proportional window size 760 - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE) 761 - Render a triangle strip covering (-1.0, -1.0) to (1.0, 1.0). 762 Write a pixel value of red (0,1,0) to (-1.0, -1.0)..(0.0, 0.0), other parts are green 763 - Reset viewport to defaults 764 - Read back the default framebuffer with ReadPixels 765 - Verify: 766 - regions outside A viewport are green 767 - Inside A viewport upper upper left portion is red, rest is green. 768 769 Repeat the above test with LOWER_LEFT origin and lower left portion of A is red, 770 rest is green. 771 */ 772class ClipControlViewportBounds : public ClipControlRenderBaseTest 773{ 774public: 775 ClipControlViewportBounds(Context& context, const char* name) 776 : ClipControlRenderBaseTest(context, name, "Clip Control Origin Test"), m_vao(0), m_vbo(0) 777 { 778 } 779 780 void deinit() override 781 { 782 ClipControlRenderBaseTest::deinit(); 783 784 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 785 glw::GLsizei windowW = renderTarget.getWidth(); 786 glw::GLsizei windowH = renderTarget.getHeight(); 787 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 788 789 if (ClipControlApi::Supported(m_context)) 790 { 791 ClipControlApi cc(m_context); 792 cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); 793 } 794 795 gl.clearColor(0.0, 0.0, 0.0, 0.0); 796 gl.viewport(0, 0, windowW, windowH); 797 798 if (m_vao) 799 { 800 gl.deleteVertexArrays(1, &m_vao); 801 } 802 if (m_vbo) 803 { 804 gl.deleteBuffers(1, &m_vbo); 805 } 806 } 807 808 IterateResult iterate() override 809 { 810 tcu::TestLog& log = m_testCtx.getLog(); 811 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 812 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 813 glw::GLsizei windowW = renderTarget.getWidth(); 814 glw::GLsizei windowH = renderTarget.getHeight(); 815 ClipControlApi cc(m_context); 816 817 //Clear the default framebuffer to blue (0,0,1). 818 gl.clearColor(0.0, 0.0, 1.0, 1.0); 819 gl.clear(GL_COLOR_BUFFER_BIT); 820 821 de::SharedPtr<glu::ShaderProgram> program( 822 new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh()))); 823 824 log << (*program); 825 if (!program->isOk()) 826 { 827 TCU_FAIL("Program compilation failed"); 828 } 829 gl.genVertexArrays(1, &m_vao); 830 gl.bindVertexArray(m_vao); 831 832 gl.genBuffers(1, &m_vbo); 833 834 const float vertex_data0[] = { -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0 }; 835 836 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo); 837 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW); 838 839 gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); 840 gl.enableVertexAttribArray(0); 841 842 gl.useProgram(program->getProgram()); 843 844 glw::GLenum origins[] = { GL_UPPER_LEFT, GL_LOWER_LEFT }; 845 846 qpTestResult result = QP_TEST_RESULT_PASS; 847 848 for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++) 849 { 850 //Set viewport to A = (x, y, w, h) = (1/8, 1/4, 1/2, 1/4) in terms of proportional window size 851 gl.viewport(static_cast<glw::GLint>((0.125f * static_cast<float>(windowW))+0.5f), 852 static_cast<glw::GLint>((0.25f * static_cast<float>(windowH))+0.5f), 853 static_cast<glw::GLsizei>((0.5f * static_cast<float>(windowW))+0.5f), 854 static_cast<glw::GLsizei>((0.25f * static_cast<float>(windowH))+0.5f)); 855 856 //Set ClipControl(<origin>, NEGATIVE_ONE_TO_ONE) 857 cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE); 858 GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()"); 859 860 //Render a triangle strip covering (-1.0, -1.0) to (1.0, 1.0). 861 //Write a pixel value of red (0,1,0) to (-1.0, -1.0)..(0.0, 0.0), other parts are green 862 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 863 864 gl.viewport(0, 0, windowW, windowH); 865 866 //Read back the default framebuffer with ReadPixels 867 //Verify the green pixels at the top and red at the bottom. 868 qpTestResult loopResult = ValidateFramebuffer(m_context, origins[orig]); 869 if (loopResult != QP_TEST_RESULT_PASS) 870 { 871 result = loopResult; 872 } 873 } 874 m_testCtx.setTestResult(result, qpGetTestResultName(result)); 875 return STOP; 876 } 877 878 const char* vsh() 879 { 880 return "attribute highp vec2 Position;" 881 "\n" 882 "varying highp vec2 PositionOut;" 883 "\n" 884 "void main() {" 885 "\n" 886 " gl_Position = vec4(Position, 0.0, 1.0);" 887 "\n" 888 " PositionOut = Position;" 889 "\n" 890 "}"; 891 } 892 893 const char* fsh() 894 { 895 return "varying highp vec2 PositionOut;" 896 "\n" 897 "void main() {" 898 "\n" 899 " if (PositionOut.x < 0.0 && PositionOut.y < 0.0)" 900 "\n" 901 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);" 902 "\n" 903 " else" 904 "\n" 905 " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);" 906 "\n" 907 "}"; 908 } 909 910 qpTestResult ValidateFramebuffer(Context& context, glw::GLenum origin) 911 { 912 const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget(); 913 glw::GLsizei windowW = renderTarget.getWidth(); 914 glw::GLsizei windowH = renderTarget.getHeight(); 915 tcu::Surface renderedFrame(windowW, windowH); 916 tcu::Surface referenceFrame(windowW, windowH); 917 918 tcu::TestLog& log = context.getTestContext().getLog(); 919 920 for (int y = 0; y < renderedFrame.getHeight(); y++) 921 { 922 float yCoord = static_cast<float>(y) / static_cast<float>(renderedFrame.getHeight()); 923 float yVPCoord = (yCoord - 0.25f) * 4.0f; 924 925 for (int x = 0; x < renderedFrame.getWidth(); x++) 926 { 927 float xCoord = static_cast<float>(x) / static_cast<float>(renderedFrame.getWidth()); 928 float xVPCoord = (xCoord - 0.125f) * 2.0f; 929 930 if (xVPCoord > 0.0f && xVPCoord < 1.0f && yVPCoord > 0.0f && yVPCoord < 1.0f) 931 { 932 933 bool greenQuadrant; 934 935 //inside viewport 936 if (origin == GL_UPPER_LEFT) 937 { 938 greenQuadrant = (yVPCoord > 0.5f && xVPCoord <= 0.5f); 939 } 940 else 941 { 942 greenQuadrant = (yVPCoord <= 0.5f && xVPCoord <= 0.5f); 943 } 944 945 if (greenQuadrant) 946 { 947 referenceFrame.setPixel(x, y, tcu::RGBA::green()); 948 } 949 else 950 { 951 referenceFrame.setPixel(x, y, tcu::RGBA::red()); 952 } 953 } 954 else 955 { 956 //outside viewport 957 referenceFrame.setPixel(x, y, tcu::RGBA::blue()); 958 } 959 } 960 } 961 962 glu::readPixels(context.getRenderContext(), 0, 0, renderedFrame.getAccess()); 963 964 if (tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, 965 tcu::COMPARE_LOG_RESULT)) 966 { 967 return QP_TEST_RESULT_PASS; 968 } 969 else 970 { 971 return QP_TEST_RESULT_FAIL; 972 } 973 } 974 975 glw::GLuint m_vao, m_vbo; 976}; 977 978/* Depth Mode Test 979 980 * Basic <depth> behavior can be tested by writing specific z_c (z 981 clip coordinates) and observing its clipping and transformation. 982 Create and bind a framebuffer object with a floating-point depth 983 buffer attachment. Make sure depth clamping is disabled. The best 984 steps for verifying the correct depth mode: 985 986 - Clear the depth buffer to 0.5. 987 - Set ClipControl(LOWER_LEFT, ZERO_TO_ONE) 988 - Enable(DEPTH_TEST) with DepthFunc(ALWAYS) 989 - Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0). 990 - Read back the floating-point depth buffer with ReadPixels 991 - Verify that the pixels with a Z clip coordinate less than 0.0 are 992 clipped and those coordinates from 0.0 to 1.0 update the depth 993 buffer with values 0.0 to 1.0. 994 */ 995 996class ClipControlDepthModeTest : public ClipControlRenderBaseTest 997{ 998public: 999 ClipControlDepthModeTest(Context& context, const char* name, const char* subname) 1000 : ClipControlRenderBaseTest(context, name, subname) 1001 { 1002 1003 } 1004 1005 void init() override 1006 { 1007 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1008 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 1009 glw::GLuint viewportW = renderTarget.getWidth(); 1010 glw::GLuint viewportH = renderTarget.getHeight(); 1011 1012 ClipControlRenderBaseTest::init(); 1013 1014 gl.genFramebuffers(1, &m_fboD); 1015 1016 gl.genTextures(1, &m_texDepthResolve); 1017 gl.bindTexture(GL_TEXTURE_2D, m_texDepthResolve); 1018 setupTexture(); 1019 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, viewportW, viewportH, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 1020 } 1021 1022 void deinit() override 1023 { 1024 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1025 1026 gl.deleteTextures(1, &m_texDepthResolve); 1027 gl.deleteFramebuffers(1, &m_fboD); 1028 1029 ClipControlRenderBaseTest::deinit(); 1030 } 1031 1032 void setupTexture() 1033 { 1034 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1035 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1036 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1037 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1038 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1039 } 1040 1041 void readDepthPixels(const tcu::PixelBufferAccess& pixelBuf) 1042 { 1043 1044 const char* vs = "\n" 1045 "attribute vec4 pos;\n" 1046 "attribute vec2 UV;\n" 1047 "varying highp vec2 vUV;\n" 1048 "void main() {\n" 1049 " gl_Position = pos;\n" 1050 " vUV = UV;\n" 1051 "}\n"; 1052 1053 const char* fs = "\n" 1054 "precision mediump float;\n" 1055 "varying vec2 vUV;\n" 1056 "uniform sampler2D tex;\n" 1057 "void main() {\n" 1058 " gl_FragColor = texture2D(tex, vUV).rrrr;\n" 1059 "}\n"; 1060 1061 const glu::RenderContext& renderContext = m_context.getRenderContext(); 1062 const glw::Functions& gl = renderContext.getFunctions(); 1063 const tcu::RenderTarget& renderTarget = renderContext.getRenderTarget(); 1064 glw::GLsizei windowW = renderTarget.getWidth(); 1065 glw::GLsizei windowH = renderTarget.getHeight(); 1066 1067 glu::ShaderProgram program(renderContext, glu::makeVtxFragSources(vs, fs)); 1068 1069 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboD); 1070 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texDepthResolve, 0); 1071 1072 gl.disable(GL_DEPTH_TEST); 1073 gl.depthMask(GL_FALSE); 1074 gl.disable(GL_STENCIL_TEST); 1075 gl.viewport(0, 0, windowW, windowH); 1076 gl.clearColor(0.0f, 0.2f, 1.0f, 1.0f); 1077 gl.clear(GL_COLOR_BUFFER_BIT); 1078 1079 const int texLoc = gl.getUniformLocation(program.getProgram(), "tex"); 1080 1081 gl.bindVertexArray(0); 1082 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 1083 1084 gl.bindTexture(GL_TEXTURE_2D, getDepthTexture()); 1085 setupTexture(); 1086 1087 gl.useProgram(program.getProgram()); 1088 gl.uniform1i(texLoc, 0); 1089 1090 { 1091 const GLfloat vertices[] = { 1092 -1.0f, -1.0f, 0.0f, 1.0f, 1093 1.0f, -1.0f, 0.0f, 1.0f, 1094 -1.0f, 1.0f, 0.0f, 1.0f, 1095 1.0f, 1.0f, 0.0f, 1.0f, 1096 }; 1097 const GLfloat texCoords[] = { 1098 0.0f, 0.0f, 1099 1.0f, 0.0f, 1100 0.0f, 1.0f, 1101 1.0f, 1.0f, 1102 }; 1103 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 }; 1104 1105 const glu::VertexArrayBinding vertexArray[] = { glu::va::Float("pos", 4, 4, 0, vertices), 1106 glu::va::Float("UV", 2, 4, 0, texCoords) }; 1107 1108 glu::draw(renderContext, program.getProgram(), 2, vertexArray, 1109 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), indices)); 1110 } 1111 glu::readPixels(renderContext, 0, 0, pixelBuf); 1112 } 1113 1114 GLuint m_fboD; 1115 GLuint m_texDepthResolve; 1116 1117}; 1118 1119class ClipControlDepthModeZeroToOneTest : public ClipControlDepthModeTest 1120{ 1121public: 1122 ClipControlDepthModeZeroToOneTest(Context& context, const char* name) 1123 : ClipControlDepthModeTest(context, name, "Depth Mode Test, ZERO_TO_ONE"), m_vao(0), m_vbo(0) 1124 { 1125 1126 } 1127 1128 void deinit() override 1129 { 1130 ClipControlDepthModeTest::deinit(); 1131 1132 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1133 1134 if (ClipControlApi::Supported(m_context)) 1135 { 1136 ClipControlApi cc(m_context); 1137 cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); 1138 } 1139 1140 gl.clearDepthf(0.0f); 1141 gl.clearColor(0.0, 0.0, 0.0, 0.0); 1142 1143 gl.disable(GL_DEPTH_TEST); 1144 gl.depthFunc(GL_LESS); 1145 1146 if (m_vao) 1147 { 1148 gl.deleteVertexArrays(1, &m_vao); 1149 } 1150 if (m_vbo) 1151 { 1152 gl.deleteBuffers(1, &m_vbo); 1153 } 1154 } 1155 1156 IterateResult iterate() override 1157 { 1158 1159 tcu::TestLog& log = m_testCtx.getLog(); 1160 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1161 ClipControlApi cc(m_context); 1162 1163 gl.clearColor(1.0, 0.0, 0.0, 1.0); 1164 gl.clear(GL_COLOR_BUFFER_BIT); 1165 1166 //Clear the depth buffer to 0.5. 1167 gl.clearDepthf(0.5); 1168 gl.clear(GL_DEPTH_BUFFER_BIT); 1169 1170 //Set ClipControl(LOWER_LEFT, ZERO_TO_ONE) 1171 cc.clipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); 1172 GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()"); 1173 1174 //Enable(DEPTH_TEST) with DepthFunc(ALWAYS) 1175 gl.enable(GL_DEPTH_TEST); 1176 gl.depthFunc(GL_ALWAYS); 1177 1178 //Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0). 1179 de::SharedPtr<glu::ShaderProgram> program( 1180 new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh()))); 1181 1182 log << (*program); 1183 if (!program->isOk()) 1184 { 1185 TCU_FAIL("Program compilation failed"); 1186 } 1187 1188 gl.genVertexArrays(1, &m_vao); 1189 gl.bindVertexArray(m_vao); 1190 1191 gl.genBuffers(1, &m_vbo); 1192 1193 const float vertex_data0[] = { 1194 -1.0, -1.0, -1.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1195 }; 1196 1197 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo); 1198 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW); 1199 1200 gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 1201 gl.enableVertexAttribArray(0); 1202 1203 gl.useProgram(program->getProgram()); 1204 1205 //test method modification: use GL_TRIANGLE_STRIP, not FAN. 1206 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 1207 1208 //Read back the floating-point depth buffer with ReadPixels 1209 //Verify that the pixels with a Z clip coordinate less than 0.0 are 1210 // clipped and those coordinates from 0.0 to 1.0 update the depth 1211 // buffer with values 0.0 to 1.0. 1212 qpTestResult result = ValidateFramebuffer(m_context); 1213 m_testCtx.setTestResult(result, qpGetTestResultName(result)); 1214 1215 return STOP; 1216 } 1217 1218 const char* vsh() 1219 { 1220 return "attribute vec3 Position;" 1221 "\n" 1222 "void main() {" 1223 "\n" 1224 " gl_Position = vec4(Position, 1.0);" 1225 "\n" 1226 "}"; 1227 } 1228 1229 qpTestResult ValidateFramebuffer(Context& context) 1230 { 1231 const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget(); 1232 glw::GLuint viewportW = renderTarget.getWidth(); 1233 glw::GLuint viewportH = renderTarget.getHeight(); 1234 tcu::Surface renderedColorFrame(viewportW, viewportH); 1235 tcu::Surface referenceColorFrame(viewportW, viewportH); 1236 tcu::TextureFormat depthReadbackFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8); 1237 tcu::TextureFormat depthFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16); 1238 tcu::TextureLevel renderedDepthFrame(depthReadbackFormat, viewportW, viewportH); 1239 tcu::TextureLevel referenceDepthFrame(depthFormat, viewportW, viewportH); 1240 tcu::TextureLevel importanceMaskFrame(depthFormat, viewportW, viewportH); 1241 1242 tcu::TestLog& log = context.getTestContext().getLog(); 1243 1244 const float rasterizationError = 1245 2.0f / (float)renderedColorFrame.getHeight() + 2.0f / (float)renderedColorFrame.getWidth(); 1246 1247 for (int y = 0; y < renderedColorFrame.getHeight(); y++) 1248 { 1249 float yCoord = ((float)(y) + 0.5f) / (float)renderedColorFrame.getHeight(); 1250 1251 for (int x = 0; x < renderedColorFrame.getWidth(); x++) 1252 { 1253 float xCoord = ((float)(x) + 0.5f) / (float)renderedColorFrame.getWidth(); 1254 1255 if (yCoord >= 1.0 - xCoord - rasterizationError && yCoord <= 1.0 - xCoord + rasterizationError) 1256 { 1257 importanceMaskFrame.getAccess().setPixDepth(0.0f, x, y); 1258 } 1259 else 1260 { 1261 importanceMaskFrame.getAccess().setPixDepth(1.0f, x, y); 1262 } 1263 1264 if (yCoord < 1.0 - xCoord) 1265 { 1266 referenceColorFrame.setPixel(x, y, tcu::RGBA::red()); 1267 referenceDepthFrame.getAccess().setPixDepth(0.5f, x, y); 1268 } 1269 else 1270 { 1271 referenceColorFrame.setPixel(x, y, tcu::RGBA::green()); 1272 1273 referenceDepthFrame.getAccess().setPixDepth(-1.0f + xCoord + yCoord, x, y); 1274 } 1275 } 1276 } 1277 1278 glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess()); 1279 if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame, 1280 0.05f, tcu::COMPARE_LOG_RESULT)) 1281 { 1282 1283 return QP_TEST_RESULT_FAIL; 1284 } 1285 1286 readDepthPixels(renderedDepthFrame.getAccess()); 1287 if (!fuzzyDepthCompare(log, "Result", "Depth image comparison result", referenceDepthFrame, renderedDepthFrame, 1288 0.05f, &importanceMaskFrame)) 1289 { 1290 return QP_TEST_RESULT_FAIL; 1291 } 1292 return QP_TEST_RESULT_PASS; 1293 } 1294 1295 glw::GLuint m_vao, m_vbo; 1296}; 1297 1298/* 1299 Do the same as above, but use the default NEGATIVE_ONE_TO_ONE depth mode: 1300 1301 - Clear the depth buffer to 0.5. 1302 - Set ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE) 1303 - Enable(DEPTH_TEST) with DepthFunc(ALWAYS) 1304 - Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0). 1305 - Read back the floating-point depth buffer with ReadPixels 1306 - Verify that no pixels are clipped and the depth buffer contains 1307 values from 0.0 to 1.0. 1308 */ 1309class ClipControlDepthModeOneToOneTest : public ClipControlDepthModeTest 1310{ 1311public: 1312 ClipControlDepthModeOneToOneTest(Context& context, const char* name) 1313 : ClipControlDepthModeTest(context, name, "Depth Mode Test, ONE_TO_ONE"), m_vao(0), m_vbo(0) 1314 { 1315 } 1316 1317 void deinit() override 1318 { 1319 ClipControlDepthModeTest::deinit(); 1320 1321 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1322 1323 if (ClipControlApi::Supported(m_context)) 1324 { 1325 ClipControlApi cc(m_context); 1326 cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); 1327 } 1328 1329 gl.clearDepthf(0.0); 1330 gl.clearColor(0.0, 0.0, 0.0, 0.0); 1331 1332 gl.disable(GL_DEPTH_TEST); 1333 gl.depthFunc(GL_LESS); 1334 1335 if (m_vao) 1336 { 1337 gl.deleteVertexArrays(1, &m_vao); 1338 } 1339 if (m_vbo) 1340 { 1341 gl.deleteBuffers(1, &m_vbo); 1342 } 1343 } 1344 1345 IterateResult iterate() override 1346 { 1347 tcu::TestLog& log = m_testCtx.getLog(); 1348 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1349 ClipControlApi cc(m_context); 1350 1351 gl.clearColor(1.0, 0.0, 0.0, 1.0); 1352 gl.clear(GL_COLOR_BUFFER_BIT); 1353 1354 //Clear the depth buffer to 0.5. 1355 gl.clearDepthf(0.5f); 1356 gl.clear(GL_DEPTH_BUFFER_BIT); 1357 1358 //Set ClipControl(LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE) 1359 cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); 1360 GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()"); 1361 1362 //Enable(DEPTH_TEST) with DepthFunc(ALWAYS) 1363 gl.enable(GL_DEPTH_TEST); 1364 gl.depthFunc(GL_ALWAYS); 1365 1366 //Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0). 1367 de::SharedPtr<glu::ShaderProgram> program( 1368 new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh()))); 1369 1370 log << (*program); 1371 if (!program->isOk()) 1372 { 1373 TCU_FAIL("Program compilation failed"); 1374 } 1375 1376 gl.genVertexArrays(1, &m_vao); 1377 gl.bindVertexArray(m_vao); 1378 1379 gl.genBuffers(1, &m_vbo); 1380 1381 const float vertex_data0[] = { 1382 -1.0, -1.0, -1.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1383 }; 1384 1385 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo); 1386 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW); 1387 1388 gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 1389 gl.enableVertexAttribArray(0); 1390 1391 gl.useProgram(program->getProgram()); 1392 1393 //test method modification: use GL_TRIANGLE_STRIP, not FAN. 1394 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 1395 1396 //Read back the floating-point depth buffer with ReadPixels 1397 //Verify that the pixels with a Z clip coordinate less than 0.0 are 1398 // clipped and those coordinates from 0.0 to 1.0 update the depth 1399 // buffer with values 0.0 to 1.0. 1400 qpTestResult result = ValidateFramebuffer(m_context); 1401 m_testCtx.setTestResult(result, qpGetTestResultName(result)); 1402 1403 return STOP; 1404 } 1405 1406 const char* vsh() 1407 { 1408 return "attribute vec3 Position;" 1409 "\n" 1410 "void main() {" 1411 "\n" 1412 " gl_Position = vec4(Position, 1.0);" 1413 "\n" 1414 "}"; 1415 } 1416 1417 qpTestResult ValidateFramebuffer(Context& context) 1418 { 1419 const tcu::RenderTarget& renderTarget = context.getRenderContext().getRenderTarget(); 1420 glw::GLuint viewportW = renderTarget.getWidth(); 1421 glw::GLuint viewportH = renderTarget.getHeight(); 1422 tcu::Surface renderedColorFrame(viewportW, viewportH); 1423 tcu::Surface referenceColorFrame(viewportW, viewportH); 1424 tcu::TextureFormat depthReadbackFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8); 1425 tcu::TextureFormat depthFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16); 1426 tcu::TextureLevel renderedDepthFrame(depthReadbackFormat, viewportW, viewportH); 1427 tcu::TextureLevel referenceDepthFrame(depthFormat, viewportW, viewportH); 1428 1429 tcu::TestLog& log = context.getTestContext().getLog(); 1430 1431 for (int y = 0; y < renderedColorFrame.getHeight(); y++) 1432 { 1433 float yCoord = (float)(y) / (float)renderedColorFrame.getHeight(); 1434 for (int x = 0; x < renderedColorFrame.getWidth(); x++) 1435 { 1436 float xCoord = (float)(x) / (float)renderedColorFrame.getWidth(); 1437 1438 referenceColorFrame.setPixel(x, y, tcu::RGBA::green()); 1439 referenceDepthFrame.getAccess().setPixDepth((xCoord + yCoord) * 0.5f, x, y); 1440 } 1441 } 1442 1443 glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess()); 1444 if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame, 1445 0.05f, tcu::COMPARE_LOG_RESULT)) 1446 { 1447 return QP_TEST_RESULT_FAIL; 1448 } 1449 1450 readDepthPixels(renderedDepthFrame.getAccess()); 1451 if (!fuzzyDepthCompare(log, "Result", "Depth image comparison result", referenceDepthFrame, renderedDepthFrame, 1452 0.05f)) 1453 { 1454 return QP_TEST_RESULT_FAIL; 1455 } 1456 1457 return QP_TEST_RESULT_PASS; 1458 } 1459 1460 glw::GLuint m_vao, m_vbo; 1461}; 1462 1463 1464/** Constructor. 1465 * 1466 * @param context Rendering context. 1467 **/ 1468ClipControlTests::ClipControlTests(Context& context) 1469 : TestCaseGroup(context, "clip_control", "Verifies \"clip_control\" functionality") 1470{ 1471 /* Left blank on purpose */ 1472} 1473 1474/** Destructor. 1475 * 1476 **/ 1477ClipControlTests::~ClipControlTests() 1478{ 1479} 1480 1481/** Initializes a texture_storage_multisample test group. 1482 * 1483 **/ 1484void ClipControlTests::init(void) 1485{ 1486 addChild(new ClipControlInitialState(m_context, "initial")); 1487 addChild(new ClipControlModifyGetState(m_context, "modify_get")); 1488 addChild(new ClipControlErrors(m_context, "errors")); 1489 addChild(new ClipControlOriginTest(m_context, "origin")); 1490 addChild(new ClipControlDepthModeZeroToOneTest(m_context, "depth_mode_zero_to_one")); 1491 addChild(new ClipControlDepthModeOneToOneTest(m_context, "depth_mode_one_to_one")); 1492 addChild(new ClipControlFaceCulling(m_context, "face_culling")); 1493 addChild(new ClipControlViewportBounds(m_context, "viewport_bounds")); 1494} 1495} 1496} 1497} 1498 1499