1/*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2014-2016 The Khronos Group Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ /*! 20 * \file 21 * \brief 22 */ /*-------------------------------------------------------------------*/ 23#include "es31cFramebufferNoAttachmentsTests.hpp" 24#include "gluContextInfo.hpp" 25#include "gluDefs.hpp" 26#include "gluStrUtil.hpp" 27#include "glw.h" 28#include "glwFunctions.hpp" 29#include "tcuTestLog.hpp" 30 31namespace glcts 32{ 33 34using tcu::TestLog; 35using std::string; 36using std::vector; 37using glcts::Context; 38 39// I tried to find something like this, but failed 40void checkErrorEqualsExpected(GLenum err, GLenum expected, const char* msg, const char* file, int line) 41{ 42 if (err != expected) 43 { 44 std::ostringstream msgStr; 45 msgStr << "glGetError() returned " << glu::getErrorStr(err) << ", expected " << glu::getErrorStr(expected); 46 47 if (msg) 48 msgStr << " in '" << msg << "'"; 49 50 if (err == GL_OUT_OF_MEMORY) 51 throw glu::OutOfMemoryError(msgStr.str().c_str(), "", file, line); 52 else 53 throw glu::Error(err, msgStr.str().c_str(), "", file, line); 54 } 55} 56 57#define GLU_EXPECT_ERROR(ERR, EXPECTED, MSG) checkErrorEqualsExpected((ERR), EXPECTED, MSG, __FILE__, __LINE__) 58 59// Contains expect_fbo_status() 60class FramebufferNoAttachmentsBaseCase : public TestCase 61{ 62public: 63 FramebufferNoAttachmentsBaseCase(Context& context, const char* name, const char* description); 64 ~FramebufferNoAttachmentsBaseCase(); 65 66protected: 67 void expect_fbo_status(GLenum target, GLenum expected_status, const char* fail_message); 68}; 69 70FramebufferNoAttachmentsBaseCase::FramebufferNoAttachmentsBaseCase(Context& context, const char* name, 71 const char* description) 72 : TestCase(context, name, description) 73{ 74} 75 76FramebufferNoAttachmentsBaseCase::~FramebufferNoAttachmentsBaseCase() 77{ 78} 79 80// API tests 81class FramebufferNoAttachmentsApiCase : public FramebufferNoAttachmentsBaseCase 82{ 83public: 84 FramebufferNoAttachmentsApiCase(Context& context, const char* name, const char* description); 85 ~FramebufferNoAttachmentsApiCase(); 86 87 IterateResult iterate(); 88 89private: 90 void begin_fbo_no_attachments(GLenum target); 91 void begin_fbo_with_multisample_renderbuffer(GLenum target); 92 void begin_fbo(GLenum target, unsigned test_case); 93 void end_fbo(GLenum target); 94 95private: 96 GLuint m_fbo; 97 GLuint m_renderbuffer; 98 GLuint m_texture; 99}; 100 101FramebufferNoAttachmentsApiCase::FramebufferNoAttachmentsApiCase(Context& context, const char* name, 102 const char* description) 103 : FramebufferNoAttachmentsBaseCase(context, name, description), m_fbo(0), m_renderbuffer(0), m_texture(0) 104{ 105} 106 107FramebufferNoAttachmentsApiCase::~FramebufferNoAttachmentsApiCase() 108{ 109} 110 111void FramebufferNoAttachmentsBaseCase::expect_fbo_status(GLenum target, GLenum expected_status, 112 const char* fail_message) 113{ 114 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 115 GLenum error; 116 117 error = gl.getError(); 118 if (error != GL_NO_ERROR) 119 { 120 std::ostringstream msgStr; 121 msgStr << "Error before glCheckFramebufferStatus() for '" << fail_message << "'\n"; 122 123 GLU_EXPECT_NO_ERROR(error, "Error before glCheckFramebufferStatus()"); 124 } 125 126 TCU_CHECK_MSG(gl.checkFramebufferStatus(target) == expected_status, fail_message); 127 128 error = gl.getError(); 129 if (error != GL_NO_ERROR) 130 { 131 std::ostringstream msgStr; 132 msgStr << "Error after glCheckFramebufferStatus() for '" << fail_message << "'\n"; 133 134 GLU_EXPECT_NO_ERROR(error, "Error after glCheckFramebufferStatus()"); 135 } 136} 137 138void FramebufferNoAttachmentsApiCase::begin_fbo_no_attachments(GLenum target) 139{ 140 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 141 142 gl.genFramebuffers(1, &m_fbo); 143 gl.bindFramebuffer(target, m_fbo); 144 145 // A freshly created framebuffer with no attachment is expected to be incomplete 146 // until default width and height is set. 147 expect_fbo_status(target, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT, 148 "error setting up framebuffer with multisample attachment"); 149} 150 151void FramebufferNoAttachmentsApiCase::begin_fbo_with_multisample_renderbuffer(GLenum target) 152{ 153 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 154 155 gl.genFramebuffers(1, &m_fbo); 156 gl.bindFramebuffer(target, m_fbo); 157 gl.genRenderbuffers(1, &m_renderbuffer); 158 gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer); 159 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, 101, 102); 160 gl.framebufferRenderbuffer(target, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer); 161 expect_fbo_status(target, GL_FRAMEBUFFER_COMPLETE, "framebuffer with an attachment should be complete"); 162} 163 164void FramebufferNoAttachmentsApiCase::begin_fbo(GLenum target, unsigned test_case) 165{ 166 switch (test_case) 167 { 168 case 0: 169 begin_fbo_no_attachments(target); 170 break; 171 case 1: 172 begin_fbo_with_multisample_renderbuffer(target); 173 break; 174 } 175} 176 177void FramebufferNoAttachmentsApiCase::end_fbo(GLenum target) 178{ 179 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 180 181 gl.bindFramebuffer(target, 0); 182 gl.deleteFramebuffers(1, &m_fbo); 183 gl.deleteRenderbuffers(1, &m_renderbuffer); 184 gl.deleteTextures(1, &m_texture); 185 GLU_EXPECT_NO_ERROR(gl.getError(), "error deleting framebuffer / renderbuffer / texture"); 186 m_fbo = 0; 187 m_renderbuffer = 0; 188 m_texture = 0; 189} 190 191FramebufferNoAttachmentsApiCase::IterateResult FramebufferNoAttachmentsApiCase::iterate() 192{ 193 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 194 bool isOk = true; 195 GLint binding; 196 197 GLenum targets[] = { 198 GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, 199 GL_FRAMEBUFFER // equivalent to DRAW_FRAMEBUFFER 200 }; 201 GLenum bindings[] = { 202 GL_DRAW_FRAMEBUFFER_BINDING, GL_READ_FRAMEBUFFER_BINDING, 203 GL_FRAMEBUFFER_BINDING // equivalent to DRAW_FRAMEBUFFER_BINDING 204 }; 205 GLenum pnames[] = { GL_FRAMEBUFFER_DEFAULT_WIDTH, GL_FRAMEBUFFER_DEFAULT_HEIGHT, GL_FRAMEBUFFER_DEFAULT_SAMPLES, 206 GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS }; 207 GLenum enums_invalid_list[] = { GL_NOTEQUAL, 208 GL_FRONT_FACE, 209 GL_PACK_ROW_LENGTH, 210 GL_FIXED, 211 GL_LINEAR_MIPMAP_NEAREST, 212 GL_RGBA4, 213 GL_TEXTURE_MAX_LOD, 214 GL_RG32F, 215 GL_ALIASED_POINT_SIZE_RANGE, 216 GL_VERTEX_ATTRIB_ARRAY_TYPE, 217 GL_DRAW_BUFFER7, 218 GL_MAX_COMBINED_UNIFORM_BLOCKS, 219 GL_MAX_VARYING_COMPONENTS, 220 GL_SRGB, 221 GL_RGB8UI, 222 GL_IMAGE_BINDING_NAME, 223 GL_TEXTURE_2D_MULTISAMPLE, 224 GL_COMPRESSED_R11_EAC, 225 GL_BUFFER_DATA_SIZE }; 226 227 GLint default_values[] = { 0, 0, 0, GL_FALSE }; 228 GLint valid_values[] = { 103, 104, 4, GL_TRUE }; 229 GLint min_values[] = { 0, 0, 0, -1 }; // Skip min_value test for boolean 230 GLint max_values[] = { 0, 0, 0, -1 }; // Skip max_value test for boolean. 231 232 unsigned num_targets = sizeof(targets) / sizeof(GLenum); 233 unsigned num_pnames = sizeof(pnames) / sizeof(GLenum); 234 unsigned num_enums_invalid_list = sizeof(enums_invalid_list) / sizeof(GLenum); 235 236 // Check for extra pnames allowed from supported extensions. 237 vector<GLenum> pnames_ext; 238 if (m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader") || 239 m_context.getContextInfo().isExtensionSupported("GL_OES_geometry_shader")) 240 { 241 pnames_ext.push_back(GL_FRAMEBUFFER_DEFAULT_LAYERS); 242 } 243 244 // "Random" invalid enums distributed roughly evenly throughout 16bit enum number range. 245 vector<GLenum> enums_invalid; 246 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader") && 247 !m_context.getContextInfo().isExtensionSupported("GL_OES_geometry_shader")) 248 { 249 enums_invalid.push_back(GL_FRAMEBUFFER_DEFAULT_LAYERS); 250 } 251 for (unsigned i = 0; i < num_enums_invalid_list; ++i) 252 { 253 enums_invalid.push_back(enums_invalid_list[i]); 254 } 255 256 gl.getIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &max_values[0]); 257 gl.getIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &max_values[1]); 258 gl.getIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &max_values[2]); 259 GLU_EXPECT_NO_ERROR( 260 gl.getError(), 261 "Querying GL_MAX_FRAMEBUFFER_WIDTH / GL_MAX_FRAMEBUFFER_HEIGHT / GL_MAX_FRAMEBUFFER_SAMPLES failed"); 262 263 TCU_CHECK_MSG(max_values[0] >= 2048, "GL_MAX_FRAMEBUFFER_WIDTH does not meet minimum requirements"); 264 265 TCU_CHECK_MSG(max_values[1] >= 2048, "GL_MAX_FRAMEBUFFER_HEIGHT does not meet minimum requirements"); 266 267 TCU_CHECK_MSG(max_values[2] >= 4, "GL_MAX_FRAMEBUFFER_SAMPLES does not meet minimum requirements"); 268 269 // It is valid to ask for number of samples > 0 and get 270 // implementation defined value which is above the requested 271 // value. We can use simple equality comparison by using 272 // reported maximum number of samples in our valid value 273 // set and get test. 274 valid_values[2] = max_values[2]; 275 276 // Invalid target 277 for (unsigned i = 0; i < enums_invalid.size(); ++i) 278 { 279 GLenum target = enums_invalid[i]; 280 bool is_valid = false; 281 for (unsigned j = 0; j < num_targets; ++j) 282 { 283 if (target == targets[j]) 284 { 285 is_valid = true; 286 break; 287 } 288 } 289 290 if (is_valid) 291 continue; 292 293 for (unsigned j = 0; j < num_pnames; ++j) 294 { 295 gl.framebufferParameteri(target, pnames[j], valid_values[j]); 296 GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_ENUM, 297 "Using glFramebufferParameteri() with invalid target should set GL_INVALID_ENUM"); 298 } 299 } 300 301 // For all valid targets 302 for (unsigned i = 0; i < num_targets; ++i) 303 { 304 GLenum target = targets[i]; 305 306 glGetIntegerv(bindings[i], &binding); 307 GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetIntegerv() " 308 "should not set GL error"); 309 310 // Using default framebuffer - GL_INVALID_OPERATION 311 for (unsigned j = 0; j < num_pnames; ++j) 312 { 313 GLint get_value = ~0; 314 GLenum pname = pnames[j]; 315 316 gl.framebufferParameteri(target, pname, valid_values[j]); 317 if (binding == 0) 318 { 319 GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_OPERATION, 320 "Using glFramebufferParameteri() on default framebuffer " 321 "should set GL_INVALID_OPERATION"); 322 } 323 else 324 { 325 GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() " 326 "should not set GL error"); 327 } 328 329 gl.getFramebufferParameteriv(target, pname, &get_value); 330 331 if (binding == 0) 332 { 333 GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_OPERATION, 334 "Using glGetFramebufferParameteriv() on default framebuffer " 335 "should set GL_INVALID_OPERATION"); 336 TCU_CHECK_MSG(get_value == ~0, "failed call to glGetFramebufferParameteriv() " 337 "should not modify params"); 338 } 339 else 340 { 341 GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() " 342 "should not set GL error"); 343 } 344 } 345 346 // j == 0 : fbo without attachments 347 // j == 1 : fbo with a multisample attachment 348 for (unsigned j = 0; j < 2; ++j) 349 { 350 glGetIntegerv(bindings[i], &binding); 351 GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetIntegerv() " 352 "should not set GL error"); 353 354 if (binding == 0) 355 { 356 // Check FBO status of default framebuffer 357 // TODO Check presence of default framebuffer - default framebuffer is complete 358 // only if it exists 359 expect_fbo_status(target, GL_FRAMEBUFFER_COMPLETE, "Default framebuffer should be complete"); 360 } 361 362 // Invalid pname - GL_INVALID_VALUE 363 begin_fbo(target, j); 364 for (unsigned k = 0; k < enums_invalid.size(); ++k) 365 { 366 GLenum pname = enums_invalid[k]; 367 bool is_valid = false; 368 for (unsigned m = 0; m < num_pnames; ++m) 369 { 370 if (pname == pnames[m]) 371 { 372 is_valid = true; 373 break; 374 } 375 } 376 377 // Ignore any pnames that are added by extensions. 378 for (unsigned m = 0; m < pnames_ext.size(); ++m) 379 { 380 if (pname == pnames_ext[m]) 381 { 382 is_valid = true; 383 break; 384 } 385 } 386 387 if (is_valid) 388 continue; 389 390 GLint get_value = ~0; 391 392 gl.framebufferParameteri(target, pname, 0); 393 GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_ENUM, "Calling glFramebufferParameteri() with invalid pname " 394 "should set GL_INVALID_ENUM"); 395 396 gl.getFramebufferParameteriv(target, pname, &get_value); 397 GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_ENUM, 398 "Calling glGetFramebufferParameteriv() with invalid pname " 399 "should set GL_INVALID_ENUM"); 400 401 TCU_CHECK_MSG(get_value == ~0, "Calling glGetFramebufferParameteriv() with invalid pname " 402 "should not modify params"); 403 } 404 end_fbo(target); 405 406 // Valid set and get 407 begin_fbo(target, j); 408 { 409 for (unsigned k = 0; k < num_pnames; ++k) 410 { 411 GLint get_value = ~0; 412 413 gl.framebufferParameteri(target, pnames[k], valid_values[k]); 414 GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glFramebufferParameteri() " 415 "should not set GL error"); 416 417 gl.getFramebufferParameteriv(target, pnames[k], &get_value); 418 GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() " 419 "should not set GL error"); 420 421 TCU_CHECK_MSG(get_value == valid_values[k], 422 "glGetFramebufferParameteriv() " 423 "should have returned the value set with glFramebufferParameteri()"); 424 } 425 426 // After valid set, check FBO status of user FBO 427 expect_fbo_status(target, GL_FRAMEBUFFER_COMPLETE, 428 "Framebuffer should be complete after setting valid valid"); 429 } 430 end_fbo(target); 431 432 // Negative or too large values - GL_INVALID_VALUE 433 // Also check for correct default values 434 begin_fbo(target, j); 435 for (unsigned k = 0; k < num_pnames; ++k) 436 { 437 GLint get_value = ~0; 438 GLenum pname = pnames[k]; 439 440 if (min_values[k] >= 0) 441 { 442 gl.framebufferParameteri(target, pname, min_values[k] - 1); 443 GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_VALUE, 444 "Calling glFramebufferParameteri() with negative value " 445 "should set GL_INVALID_VALUE"); 446 } 447 448 gl.getFramebufferParameteriv(target, pname, &get_value); 449 GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() " 450 "should not set GL error"); 451 452 TCU_CHECK_MSG(get_value == default_values[k], "glGetFramebufferParameteriv() " 453 "did not return a valid default value"); 454 455 get_value = ~0; 456 if (max_values[k] >= 0) 457 { 458 gl.framebufferParameteri(target, pname, max_values[k] + 1); 459 GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_VALUE, 460 "Calling glFramebufferParameteri() too large value " 461 "should set GL_INVALID_VALUE"); 462 } 463 464 gl.getFramebufferParameteriv(target, pname, &get_value); 465 GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() " 466 "should not set GL error"); 467 468 TCU_CHECK_MSG(get_value == default_values[k], "glGetFramebufferParameteriv() " 469 "did not return a valid default value"); 470 } 471 end_fbo(target); 472 } 473 } 474 475 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail"); 476 return STOP; 477} 478 479// Draw with imageStore, validate that framebuffer 480// default width and height is respected. 481class FramebufferNoAttachmentsRenderCase : public FramebufferNoAttachmentsBaseCase 482{ 483public: 484 FramebufferNoAttachmentsRenderCase(Context& context, const char* name, const char* description); 485 486 IterateResult iterate(); 487 void deinit(void); 488 489private: 490 GLuint m_program; 491 GLuint m_vertex_shader; 492 GLuint m_fragment_shader; 493 GLuint m_vao; 494 GLuint m_framebuffer; 495 GLuint m_texture; 496}; 497 498FramebufferNoAttachmentsRenderCase::FramebufferNoAttachmentsRenderCase(Context& context, const char* name, 499 const char* description) 500 : FramebufferNoAttachmentsBaseCase(context, name, description) 501 , m_program(0) 502 , m_vertex_shader(0) 503 , m_fragment_shader(0) 504 , m_vao(0) 505 , m_framebuffer(0) 506 , m_texture(0) 507{ 508} 509 510void FramebufferNoAttachmentsRenderCase::deinit(void) 511{ 512 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 513 gl.deleteShader(m_vertex_shader); 514 gl.deleteShader(m_fragment_shader); 515 gl.deleteProgram(m_program); 516 gl.deleteVertexArrays(1, &m_vao); 517 gl.deleteTextures(1, &m_texture); 518 gl.deleteFramebuffers(1, &m_framebuffer); 519} 520 521FramebufferNoAttachmentsRenderCase::IterateResult FramebufferNoAttachmentsRenderCase::iterate() 522{ 523 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 524 int max_fragment_image_uniforms; 525 bool isOk = true; 526 527 // Check GL_MAX_FRAGMENT_IMAGE_UNIFORMS, we need at least one 528 glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &max_fragment_image_uniforms); 529 GLU_EXPECT_NO_ERROR(gl.getError(), "Querying GL_MAX_FRAGMENT_IMAGE_UNIFORMS"); 530 531 if (max_fragment_image_uniforms < 1) 532 { 533 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_MAX_FRAGMENT_IMAGE_UNIFORMS<1"); 534 return STOP; 535 } 536 537 // Create program and VAO 538 { 539 const char* vs_source = "#version 310 es\n" 540 "void main()\n" 541 "{\n" 542 " if (gl_VertexID == 0) gl_Position = vec4(-1, -1, 0, 1);\n" 543 " else if (gl_VertexID == 1) gl_Position = vec4(-1, 1, 0, 1);\n" 544 " else if (gl_VertexID == 2) gl_Position = vec4( 1, 1, 0, 1);\n" 545 " else gl_Position = vec4( 1, -1, 0, 1);\n" 546 "}\n"; 547 548 const char* fs_source = "#version 310 es\n" 549 "precision highp uimage2D;\n" 550 "layout(r32ui) uniform uimage2D data;\n" 551 "void main()\n" 552 "{\n" 553 " ivec2 image_info = ivec2(gl_FragCoord.xy);\n" 554 " imageStore(data, image_info, uvec4(1, 2, 3, 4));\n" 555 "}\n"; 556 557 m_program = gl.createProgram(); 558 m_vertex_shader = gl.createShader(GL_VERTEX_SHADER); 559 m_fragment_shader = gl.createShader(GL_FRAGMENT_SHADER); 560 gl.shaderSource(m_vertex_shader, 1, &vs_source, NULL); 561 gl.compileShader(m_vertex_shader); 562 gl.attachShader(m_program, m_vertex_shader); 563 gl.shaderSource(m_fragment_shader, 1, &fs_source, NULL); 564 gl.compileShader(m_fragment_shader); 565 gl.attachShader(m_program, m_fragment_shader); 566 gl.linkProgram(m_program); 567 gl.useProgram(m_program); 568 gl.genVertexArrays(1, &m_vao); 569 gl.bindVertexArray(m_vao); 570 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating program and VAO"); 571 } 572 573 // Create framebuffer with no attachments 574 gl.genFramebuffers(1, &m_framebuffer); 575 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer); 576 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 32); 577 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 32); 578 expect_fbo_status(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_COMPLETE, "Creating framebuffer with no attachments"); 579 580 // Create texture and clear it, temporarily attaching to FBO 581 { 582 GLuint zero = 0; 583 gl.genTextures(1, &m_texture); 584 gl.bindTexture(GL_TEXTURE_2D, m_texture); 585 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 64, 64); 586 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 587 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 588 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0); 589 gl.viewport(0, 0, 64, 64); 590 gl.clearBufferuiv(GL_COLOR, 0, &zero); 591 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 592 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating and clearing texture"); 593 } 594 595 // Draw using storeImage 596 gl.drawBuffers(0, NULL); 597 gl.viewport(0, 0, 64, 64); 598 gl.bindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI); 599 gl.drawArrays(GL_TRIANGLE_FAN, 0, 4); 600 gl.memoryBarrier(GL_ALL_BARRIER_BITS); 601 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw with imageStore"); 602 603 // Read and validate texture contents 604 { 605 GLuint pixels[64 * 64 * 4]; 606 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 607 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer); 608 gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0); 609 expect_fbo_status(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_COMPLETE, "ReadPixels to texture for validation"); 610 gl.readPixels(0, 0, 64, 64, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 611 GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels"); 612 613 for (unsigned y = 0; y < 64; ++y) 614 { 615 for (unsigned x = 0; x < 64; ++x) 616 { 617 GLuint expected_value = (x < 32) && (y < 32) ? 1 : 0; 618 GLuint value = pixels[(y * 64 + x) * 4]; 619 TCU_CHECK_MSG(value == expected_value, "Validating draw with imageStore"); 620 } 621 } 622 } 623 624 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail"); 625 return STOP; 626} 627 628FramebufferNoAttachmentsTests::FramebufferNoAttachmentsTests(Context& context) 629 : TestCaseGroup(context, "framebuffer_no_attachments", "Framebuffer no attachments tests") 630{ 631} 632 633FramebufferNoAttachmentsTests::~FramebufferNoAttachmentsTests(void) 634{ 635} 636 637void FramebufferNoAttachmentsTests::init(void) 638{ 639 addChild(new FramebufferNoAttachmentsApiCase(m_context, "api", "Basic API verification")); 640 641 addChild(new FramebufferNoAttachmentsRenderCase(m_context, "render", "Rendering with imageStore")); 642} 643 644} // glcts 645