1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2017 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 glcRobustnessTests.cpp 21 * \brief Conformance tests for the Robustness feature functionality. 22 */ /*-------------------------------------------------------------------*/ 23 24 #include "glcRobustnessTests.hpp" 25 #include "deSharedPtr.hpp" 26 #include "glcRobustBufferAccessBehaviorTests.hpp" 27 #include "gluContextInfo.hpp" 28 #include "gluPlatform.hpp" 29 #include "gluRenderContext.hpp" 30 #include "glwEnums.hpp" 31 #include "glwFunctions.hpp" 32 #include "tcuCommandLine.hpp" 33 #include "tcuTestLog.hpp" 34 #include <cstring> 35 36 using namespace glw; 37 using namespace deqp::RobustBufferAccessBehavior; 38 39 namespace glcts 40 { 41 42 namespace ResetNotificationStrategy 43 { 44 45 class RobustnessBase : public tcu::TestCase 46 { 47 public: 48 RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType); 49 50 glu::RenderContext* createRobustContext(glu::ResetNotificationStrategy reset); 51 52 private: 53 glu::ApiType m_ApiType; 54 }; 55 56 RobustnessBase::RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description, 57 glu::ApiType apiType) 58 : tcu::TestCase(testCtx, name, description), m_ApiType(apiType) 59 { 60 } 61 62 glu::RenderContext* RobustnessBase::createRobustContext(glu::ResetNotificationStrategy reset) 63 { 64 /* Create test context to verify if GL_KHR_robustness extension is available */ 65 { 66 deqp::Context context(m_testCtx, glu::ContextType(m_ApiType)); 67 if (!context.getContextInfo().isExtensionSupported("GL_KHR_robustness") && 68 !contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2))) 69 { 70 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, 71 "GL_KHR_robustness extension not supported"); 72 return NULL; 73 } 74 } 75 76 glu::RenderConfig renderCfg(glu::ContextType(m_ApiType, glu::CONTEXT_ROBUST)); 77 const tcu::CommandLine& commandLine = m_testCtx.getCommandLine(); 78 glu::parseRenderConfig(&renderCfg, commandLine); 79 80 if (commandLine.getSurfaceType() == tcu::SURFACETYPE_WINDOW) 81 renderCfg.resetNotificationStrategy = reset; 82 else 83 throw tcu::NotSupportedError("Test not supported in non-windowed context"); 84 85 /* Try to create core/es robusness context */ 86 return createRenderContext(m_testCtx.getPlatform(), commandLine, renderCfg); 87 } 88 89 class NoResetNotificationCase : public RobustnessBase 90 { 91 typedef glw::GLenum(GLW_APIENTRY* PFNGLGETGRAPHICSRESETSTATUS)(); 92 93 public: 94 NoResetNotificationCase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType) 95 : RobustnessBase(testCtx, name, description, apiType) 96 { 97 } 98 99 virtual IterateResult iterate(void) 100 { 101 glu::ResetNotificationStrategy strategy = glu::RESET_NOTIFICATION_STRATEGY_NO_RESET_NOTIFICATION; 102 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext(strategy)); 103 if (!robustContext.get()) 104 return STOP; 105 106 PFNGLGETGRAPHICSRESETSTATUS pGetGraphicsResetStatus = 107 (PFNGLGETGRAPHICSRESETSTATUS)robustContext->getProcAddress("glGetGraphicsResetStatus"); 108 109 if (DE_NULL == pGetGraphicsResetStatus) 110 { 111 m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, 112 "Pointer to function glGetGraphicsResetStatus is NULL."); 113 return STOP; 114 } 115 116 glw::GLint reset = 0; 117 118 const glw::Functions& gl = robustContext->getFunctions(); 119 gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset); 120 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv"); 121 122 if (reset != GL_NO_RESET_NOTIFICATION) 123 { 124 m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGet returned wrong value [" << reset 125 << ", expected " << GL_NO_RESET_NOTIFICATION << "]." << tcu::TestLog::EndMessage; 126 127 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 128 return STOP; 129 } 130 131 glw::GLint status = pGetGraphicsResetStatus(); 132 if (status != GL_NO_ERROR) 133 { 134 m_testCtx.getLog() << tcu::TestLog::Message 135 << "Test failed! glGetGraphicsResetStatus returned wrong value [" << status 136 << ", expected " << GL_NO_ERROR << "]." << tcu::TestLog::EndMessage; 137 138 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 139 return STOP; 140 } 141 142 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 143 return STOP; 144 } 145 }; 146 147 class LoseContextOnResetCase : public RobustnessBase 148 { 149 public: 150 LoseContextOnResetCase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType) 151 : RobustnessBase(testCtx, name, description, apiType) 152 { 153 } 154 155 virtual IterateResult iterate(void) 156 { 157 glu::ResetNotificationStrategy strategy = glu::RESET_NOTIFICATION_STRATEGY_LOSE_CONTEXT_ON_RESET; 158 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext(strategy)); 159 if (!robustContext.get()) 160 return STOP; 161 162 glw::GLint reset = 0; 163 164 const glw::Functions& gl = robustContext->getFunctions(); 165 gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset); 166 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv"); 167 168 if (reset != GL_LOSE_CONTEXT_ON_RESET) 169 { 170 m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGet returned wrong value [" << reset 171 << ", expected " << GL_LOSE_CONTEXT_ON_RESET << "]." << tcu::TestLog::EndMessage; 172 173 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 174 return STOP; 175 } 176 177 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 178 return STOP; 179 } 180 }; 181 182 } // ResetNotificationStrategy namespace 183 184 namespace RobustBufferAccessBehavior 185 { 186 187 static deqp::Context* createContext(tcu::TestContext& testCtx, glu::ApiType apiType) 188 { 189 deqp::Context* context = new deqp::Context(testCtx, glu::ContextType(apiType)); 190 if (!context) 191 { 192 testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to context is NULL."); 193 return DE_NULL; 194 } 195 196 if (!(contextSupports(context->getRenderContext().getType(), glu::ApiType::es(3, 2)) || 197 (context->getContextInfo().isExtensionSupported("GL_KHR_robustness") && 198 context->getContextInfo().isExtensionSupported("GL_KHR_robust_buffer_access_behavior")))) 199 { 200 testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); 201 delete context; 202 return DE_NULL; 203 } 204 205 return context; 206 } 207 208 /** Implementation of test GetnUniformTest. Description follows: 209 * 210 * This test verifies if read uniform variables to the buffer with bufSize less than expected result with GL_INVALID_OPERATION error; 211 **/ 212 class GetnUniformTest : public tcu::TestCase 213 { 214 public: 215 /* Public methods */ 216 GetnUniformTest(tcu::TestContext& testCtx, glu::ApiType apiType); 217 virtual ~GetnUniformTest() 218 { 219 } 220 221 /* Public methods inherited from TestCase */ 222 virtual tcu::TestNode::IterateResult iterate(void); 223 224 private: 225 /* Private methods */ 226 std::string getComputeShader(bool glslES320); 227 228 bool verifyResult(const void* inputData, const void* resultData, int size, const char* method); 229 bool verifyError(glw::GLint error, glw::GLint expectedError, const char* method); 230 231 glu::ApiType m_ApiType; 232 }; 233 234 /** Constructor 235 * 236 * @param context Test context 237 **/ 238 GetnUniformTest::GetnUniformTest(tcu::TestContext& testCtx, glu::ApiType apiType) 239 : tcu::TestCase(testCtx, "getnuniform", "Verifies if read uniform variables to the buffer with bufSize less than " 240 "expected result with GL_INVALID_OPERATION") 241 , m_ApiType(apiType) 242 { 243 /* Nothing to be done here */ 244 } 245 246 /** Execute test 247 * 248 * @return tcu::TestNode::STOP 249 **/ 250 tcu::TestNode::IterateResult GetnUniformTest::iterate() 251 { 252 de::SharedPtr<deqp::Context> context(createContext(m_testCtx, m_ApiType)); 253 if (!context.get()) 254 return STOP; 255 256 /* GL funtion pointers. */ 257 typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMFV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize, 258 glw::GLfloat * params); 259 typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMIV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize, 260 glw::GLint * params); 261 typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMUIV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize, 262 glw::GLuint * params); 263 264 /* Function pointers need to be grabbed only for GL4.5 but it is done also for ES for consistency */ 265 glu::RenderContext& renderContext = context->getRenderContext(); 266 PFNGLGETNUNIFORMFV pGetnUniformfv = (PFNGLGETNUNIFORMFV)renderContext.getProcAddress("glGetnUniformfv"); 267 PFNGLGETNUNIFORMIV pGetnUniformiv = (PFNGLGETNUNIFORMIV)renderContext.getProcAddress("glGetnUniformiv"); 268 PFNGLGETNUNIFORMUIV pGetnUniformuiv = (PFNGLGETNUNIFORMUIV)renderContext.getProcAddress("glGetnUniformuiv"); 269 270 if ((DE_NULL == pGetnUniformfv) || (DE_NULL == pGetnUniformiv) || (DE_NULL == pGetnUniformuiv)) 271 { 272 m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to function glGetnUniform* is NULL."); 273 return STOP; 274 } 275 276 const Functions& gl = renderContext.getFunctions(); 277 278 const GLfloat input4f[] = { 1.0f, 5.4f, 3.14159f, 1.28f }; 279 const GLint input3i[] = { 10, -20, -30 }; 280 const GLuint input4ui[] = { 10, 20, 30, 40 }; 281 282 /* Test result indicator */ 283 bool test_result = true; 284 285 /* Iterate over all cases */ 286 Program program(*context); 287 288 /* Compute Shader */ 289 bool glslES320 = contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)); 290 const std::string& cs = getComputeShader(glslES320); 291 292 /* Shaders initialization */ 293 program.Init(cs /* cs */, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */); 294 program.Use(); 295 296 /* For gl4.5 use shader storage buffer */ 297 GLuint buf; 298 if (!glslES320) 299 { 300 gl.genBuffers(1, &buf); 301 GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers"); 302 303 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buf); 304 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase"); 305 306 gl.bufferData(GL_SHADER_STORAGE_BUFFER, 16, DE_NULL, GL_STREAM_DRAW); 307 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData"); 308 } 309 310 /* passing uniform values */ 311 gl.programUniform4fv(program.m_id, 11, 1, input4f); 312 GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform4fv"); 313 314 gl.programUniform3iv(program.m_id, 12, 1, input3i); 315 GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform3iv"); 316 317 gl.programUniform4uiv(program.m_id, 13, 1, input4ui); 318 GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform4uiv"); 319 320 gl.dispatchCompute(1, 1, 1); 321 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 322 323 /* veryfing gfetnUniform error messages */ 324 GLfloat result4f[4]; 325 GLint result3i[3]; 326 GLuint result4ui[4]; 327 328 pGetnUniformfv(program.m_id, 11, sizeof(GLfloat) * 4, result4f); 329 test_result = test_result && 330 verifyResult((void*)input4f, (void*)result4f, sizeof(GLfloat) * 4, "getnUniformfv [false negative]"); 331 test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformfv [false negative]"); 332 333 pGetnUniformfv(program.m_id, 11, sizeof(GLfloat) * 3, result4f); 334 test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformfv [false positive]"); 335 336 pGetnUniformiv(program.m_id, 12, sizeof(GLint) * 3, result3i); 337 test_result = test_result && 338 verifyResult((void*)input3i, (void*)result3i, sizeof(GLint) * 3, "getnUniformiv [false negative]"); 339 test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformiv [false negative]"); 340 341 pGetnUniformiv(program.m_id, 12, sizeof(GLint) * 2, result3i); 342 test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformiv [false positive]"); 343 344 pGetnUniformuiv(program.m_id, 13, sizeof(GLuint) * 4, result4ui); 345 test_result = test_result && verifyResult((void*)input4ui, (void*)result4ui, sizeof(GLuint) * 4, 346 "getnUniformuiv [false negative]"); 347 test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformuiv [false negative]"); 348 349 pGetnUniformuiv(program.m_id, 13, sizeof(GLuint) * 3, result4ui); 350 test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformuiv [false positive]"); 351 352 /* Set result */ 353 if (true == test_result) 354 { 355 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 356 } 357 else 358 { 359 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 360 } 361 362 if (!glslES320) 363 { 364 gl.deleteBuffers(1, &buf); 365 } 366 367 /* Done */ 368 return tcu::TestNode::STOP; 369 } 370 371 std::string GetnUniformTest::getComputeShader(bool glslES320) 372 { 373 std::stringstream shader; 374 shader << "#version " << (glslES320 ? "320 es\n" : "450\n"); 375 shader << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 376 "layout (location = 11) uniform vec4 inputf;\n" 377 "layout (location = 12) uniform ivec3 inputi;\n" 378 "layout (location = 13) uniform uvec4 inputu;\n"; 379 if (glslES320) 380 { 381 shader << "shared float valuef;\n" 382 "shared int valuei;\n" 383 "shared uint valueu;\n"; 384 } 385 else 386 { 387 shader << "layout (std140, binding = 0) buffer ssbo {" 388 " float valuef;\n" 389 " int valuei;\n" 390 " uint valueu;\n" 391 "};\n"; 392 } 393 shader << "void main()\n" 394 "{\n" 395 " valuef = inputf.r + inputf.g + inputf.b + inputf.a;\n" 396 " valuei = inputi.r + inputi.g + inputi.b;\n" 397 " valueu = inputu.r + inputu.g + inputu.b + inputu.a;\n" 398 "}\n"; 399 400 return shader.str(); 401 } 402 403 bool GetnUniformTest::verifyResult(const void* inputData, const void* resultData, int size, const char* method) 404 { 405 int diff = memcmp(inputData, resultData, size); 406 if (diff != 0) 407 { 408 m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " result is not as expected." 409 << tcu::TestLog::EndMessage; 410 411 return false; 412 } 413 414 return true; 415 } 416 417 bool GetnUniformTest::verifyError(GLint error, GLint expectedError, const char* method) 418 { 419 if (error != expectedError) 420 { 421 m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " throws unexpected error [" 422 << error << "]." << tcu::TestLog::EndMessage; 423 424 return false; 425 } 426 427 return true; 428 } 429 430 /** Implementation of test ReadnPixelsTest. Description follows: 431 * 432 * This test verifies if read pixels to the buffer with bufSize less than expected result with GL_INVALID_OPERATION error; 433 **/ 434 class ReadnPixelsTest : public tcu::TestCase 435 { 436 public: 437 /* Public methods */ 438 ReadnPixelsTest(tcu::TestContext& testCtx, glu::ApiType apiType); 439 virtual ~ReadnPixelsTest() 440 { 441 } 442 443 /* Public methods inherited from TestCase */ 444 virtual tcu::TestNode::IterateResult iterate(void); 445 446 private: 447 /* Private methods */ 448 void cleanTexture(deqp::Context& context, glw::GLuint texture_id); 449 bool verifyResults(deqp::Context& context); 450 bool verifyError(glw::GLint error, glw::GLint expectedError, const char* method); 451 452 glu::ApiType m_ApiType; 453 }; 454 455 /** Constructor 456 * 457 * @param context Test context 458 **/ 459 ReadnPixelsTest::ReadnPixelsTest(tcu::TestContext& testCtx, glu::ApiType apiType) 460 : tcu::TestCase(testCtx, "readnpixels", 461 "Verifies if read pixels to the buffer with bufSize less than expected result " 462 "with GL_INVALID_OPERATION error") 463 , m_ApiType(apiType) 464 { 465 /* Nothing to be done here */ 466 } 467 468 /** Execute test 469 * 470 * @return tcu::TestNode::STOP 471 **/ 472 tcu::TestNode::IterateResult ReadnPixelsTest::iterate() 473 { 474 de::SharedPtr<deqp::Context> context(createContext(m_testCtx, m_ApiType)); 475 if (!context.get()) 476 return STOP; 477 478 /* GL funtion pointers. */ 479 typedef void(GLW_APIENTRY * PFNGLREADNPIXELS)(glw::GLint x, glw::GLint y, glw::GLsizei width, glw::GLsizei height, 480 glw::GLenum format, glw::GLenum type, glw::GLsizei bufSize, 481 glw::GLvoid * data); 482 483 PFNGLREADNPIXELS pReadnPixels = (PFNGLREADNPIXELS)context->getRenderContext().getProcAddress("glReadnPixels"); 484 485 if (DE_NULL == pReadnPixels) 486 { 487 m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to function glReadnPixels is NULL."); 488 return STOP; 489 } 490 491 static const GLuint elements[] = { 492 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1, 493 }; 494 495 static const GLfloat vertices[] = { 496 0.0f, 0.0f, 0.0f, 1.0f, /* 0 */ 497 -1.0f, 0.0f, 0.0f, 1.0f, /* 1 */ 498 -1.0f, 1.0f, 0.0f, 1.0f, /* 2 */ 499 0.0f, 1.0f, 0.0f, 1.0f, /* 3 */ 500 1.0f, 1.0f, 0.0f, 1.0f, /* 4 */ 501 1.0f, 0.0f, 0.0f, 1.0f, /* 5 */ 502 1.0f, -1.0f, 0.0f, 1.0f, /* 6 */ 503 0.0f, -1.0f, 0.0f, 1.0f, /* 7 */ 504 -1.0f, -1.0f, 0.0f, 1.0f, /* 8 */ 505 }; 506 507 bool glslES320 = contextSupports(context->getRenderContext().getType(), glu::ApiType::es(3, 2)); 508 std::string fs("#version "); 509 fs += (glslES320 ? "320 es\n" : "450\n"); 510 fs += "layout (location = 0) out lowp uvec4 out_fs_color;\n" 511 "\n" 512 "void main()\n" 513 "{\n" 514 " out_fs_color = uvec4(1, 0, 0, 1);\n" 515 "}\n" 516 "\n"; 517 518 std::string vs("#version "); 519 vs += (glslES320 ? "320 es\n" : "450\n"); 520 vs += "layout (location = 0) in vec4 in_vs_position;\n" 521 "\n" 522 "void main()\n" 523 "{\n" 524 " gl_Position = in_vs_position;\n" 525 "}\n" 526 "\n"; 527 528 static const GLuint height = 8; 529 static const GLuint width = 8; 530 static const GLuint n_vertices = 24; 531 532 /* GL entry points */ 533 const Functions& gl = context->getRenderContext().getFunctions(); 534 535 /* Test case objects */ 536 Program program(*context); 537 Texture texture(*context); 538 Buffer elements_buffer(*context); 539 Buffer vertices_buffer(*context); 540 VertexArray vao(*context); 541 542 /* Vertex array initialization */ 543 VertexArray::Generate(gl, vao.m_id); 544 VertexArray::Bind(gl, vao.m_id); 545 546 /* Texture initialization */ 547 Texture::Generate(gl, texture.m_id); 548 Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D); 549 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R8UI, width, height, 0); 550 Texture::Bind(gl, 0, GL_TEXTURE_2D); 551 552 /* Framebuffer initialization */ 553 GLuint fbo; 554 gl.genFramebuffers(1, &fbo); 555 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers"); 556 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); 557 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer"); 558 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.m_id, 0); 559 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D"); 560 561 /* Buffers initialization */ 562 elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(elements), elements); 563 vertices_buffer.InitData(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(vertices), vertices); 564 565 /* Shaders initialization */ 566 program.Init("" /* cs */, fs, "" /* gs */, "" /* tcs */, "" /* tes */, vs); 567 Program::Use(gl, program.m_id); 568 569 /* Vertex buffer initialization */ 570 vertices_buffer.Bind(); 571 gl.bindVertexBuffer(0 /* bindindex = location */, vertices_buffer.m_id, 0 /* offset */, 16 /* stride */); 572 gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 16, NULL); 573 gl.enableVertexAttribArray(0 /* location */); 574 575 /* Binding elements/indices buffer */ 576 elements_buffer.Bind(); 577 578 cleanTexture(*context, texture.m_id); 579 580 gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */); 581 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements"); 582 583 /* Set result */ 584 if (verifyResults(*context)) 585 { 586 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 587 } 588 else 589 { 590 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 591 } 592 593 /* Done */ 594 return tcu::TestNode::STOP; 595 } 596 597 /** Fill texture with value 128 598 * 599 * @param texture_id Id of texture 600 **/ 601 void ReadnPixelsTest::cleanTexture(deqp::Context& context, glw::GLuint texture_id) 602 { 603 static const GLuint height = 8; 604 static const GLuint width = 8; 605 606 const Functions& gl = context.getRenderContext().getFunctions(); 607 608 GLubyte pixels[width * height]; 609 for (GLuint i = 0; i < width * height; ++i) 610 { 611 pixels[i] = 64; 612 } 613 614 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 615 616 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 0 /* depth */, 617 GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels); 618 619 /* Unbind */ 620 Texture::Bind(gl, 0, GL_TEXTURE_2D); 621 } 622 623 /** Verifies glReadnPixels results 624 * 625 * @return true when glReadnPixels , false otherwise 626 **/ 627 bool ReadnPixelsTest::verifyResults(deqp::Context& context) 628 { 629 static const GLuint height = 8; 630 static const GLuint width = 8; 631 static const GLuint pixel_size = 4 * sizeof(GLuint); 632 633 const Functions& gl = context.getRenderContext().getFunctions(); 634 635 //Valid buffer size test 636 const GLint bufSizeValid = width * height * pixel_size; 637 GLubyte pixelsValid[bufSizeValid]; 638 639 gl.readnPixels(0, 0, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, bufSizeValid, pixelsValid); 640 GLU_EXPECT_NO_ERROR(gl.getError(), "ReadnPixels"); 641 642 //Verify glReadnPixels result 643 for (unsigned int i = 0; i < width * height; ++i) 644 { 645 const size_t offset = i * pixel_size; 646 const GLuint value = *(GLuint*)(pixelsValid + offset); 647 648 if (value != 1) 649 { 650 context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel value: " << value 651 << ". Offset: " << offset << tcu::TestLog::EndMessage; 652 return false; 653 } 654 } 655 656 //Invalid buffer size test 657 const GLint bufSizeInvalid = width * height * pixel_size - 1; 658 GLubyte pixelsInvalid[bufSizeInvalid]; 659 660 gl.readnPixels(0, 0, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, bufSizeInvalid, pixelsInvalid); 661 if (!verifyError(gl.getError(), GL_INVALID_OPERATION, "ReadnPixels [false positive]")) 662 return false; 663 664 return true; 665 } 666 667 /** Verify operation errors 668 * 669 * @param error OpenGL ES error code 670 * @param expectedError Expected error code 671 * @param method Method name marker 672 * 673 * @return true when error is as expected, false otherwise 674 **/ 675 bool ReadnPixelsTest::verifyError(GLint error, GLint expectedError, const char* method) 676 { 677 if (error != expectedError) 678 { 679 m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " throws unexpected error [" 680 << error << "]." << tcu::TestLog::EndMessage; 681 682 return false; 683 } 684 685 return true; 686 } 687 688 } // RobustBufferAccessBehavior namespace 689 690 RobustnessTests::RobustnessTests(tcu::TestContext& testCtx, glu::ApiType apiType) 691 : tcu::TestCaseGroup(testCtx, "robustness", 692 "Verifies API coverage and functionality of GL_KHR_robustness extension.") 693 , m_ApiType(apiType) 694 { 695 } 696 697 void RobustnessTests::init(void) 698 { 699 tcu::TestCaseGroup::init(); 700 701 try 702 { 703 addChild(new ResetNotificationStrategy::NoResetNotificationCase( 704 m_testCtx, "no_reset_notification", "Verifies if NO_RESET_NOTIFICATION strategy works as expected.", 705 m_ApiType)); 706 addChild(new ResetNotificationStrategy::LoseContextOnResetCase( 707 m_testCtx, "lose_context_on_reset", "Verifies if LOSE_CONTEXT_ON_RESET strategy works as expected.", 708 m_ApiType)); 709 710 addChild(new RobustBufferAccessBehavior::GetnUniformTest(m_testCtx, m_ApiType)); 711 addChild(new RobustBufferAccessBehavior::ReadnPixelsTest(m_testCtx, m_ApiType)); 712 } 713 catch (...) 714 { 715 // Destroy context. 716 tcu::TestCaseGroup::deinit(); 717 throw; 718 } 719 } 720 721 } // glcts namespace 722