1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2015-2016 The Khronos Group Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ /*! 20 * \file 21 * \brief 22 */ /*-------------------------------------------------------------------*/ 23 24 /** 25 */ /*! 26 * \file gl4cSparseBufferTests.cpp 27 * \brief Conformance tests for the GL_ARB_sparse_buffer functionality. 28 */ /*-------------------------------------------------------------------*/ 29 30 #include "gl4cSparseBufferTests.hpp" 31 #include "gluContextInfo.hpp" 32 #include "gluDefs.hpp" 33 #include "glwEnums.hpp" 34 #include "glwFunctions.hpp" 35 #include "tcuTestLog.hpp" 36 37 #include <string.h> 38 #include <vector> 39 40 #ifndef GL_SPARSE_BUFFER_PAGE_SIZE_ARB 41 #define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8 42 #endif 43 #ifndef GL_SPARSE_STORAGE_BIT_ARB 44 #define GL_SPARSE_STORAGE_BIT_ARB 0x0400 45 #endif 46 47 namespace gl4cts 48 { 49 /** Rounds up the provided offset so that it is aligned to the specified value (eg. page size). 50 * In other words, the result value meets the following requirements: 51 * 52 * 1) result value % input value = 0 53 * 2) result value >= offset 54 * 3) (result value - offset) < input value 55 * 56 * @param offset Offset to be used for the rounding operation. 57 * @param value Value to align the offset to. 58 * 59 * @return Result value. 60 **/ 61 unsigned int SparseBufferTestUtilities::alignOffset(const unsigned int& offset, const unsigned int& value) 62 { 63 return offset + (value - offset % value) % value; 64 } 65 66 /** Builds a compute program object, using the user-specified CS code snippets. 67 * 68 * @param gl DEQP CTS GL functions container. 69 * @param cs_body_parts Code snippets to use for the compute shader. Must hold exactly 70 * @param n_cs_body_parts null-terminated text strings. 71 * @param n_cs_body_parts Number of code snippets accessible via @param cs_body_parts. 72 * 73 * @return Result PO id if program has been linked successfully, 0 otherwise. 74 **/ 75 glw::GLuint SparseBufferTestUtilities::createComputeProgram(const glw::Functions& gl, const char** cs_body_parts, 76 unsigned int n_cs_body_parts) 77 { 78 glw::GLint compile_status = GL_FALSE; 79 glw::GLuint cs_id = 0; 80 glw::GLint link_status = GL_FALSE; 81 glw::GLuint po_id = 0; 82 bool result = true; 83 84 if (n_cs_body_parts > 0) 85 { 86 cs_id = gl.createShader(GL_COMPUTE_SHADER); 87 } 88 89 po_id = gl.createProgram(); 90 91 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed."); 92 93 if (n_cs_body_parts > 0) 94 { 95 gl.attachShader(po_id, cs_id); 96 } 97 98 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed."); 99 100 if (n_cs_body_parts > 0) 101 { 102 gl.shaderSource(cs_id, n_cs_body_parts, cs_body_parts, NULL); /* length */ 103 } 104 105 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed."); 106 107 gl.compileShader(cs_id); 108 109 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); 110 111 gl.getShaderiv(cs_id, GL_COMPILE_STATUS, &compile_status); 112 113 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed"); 114 115 char temp[1024]; 116 gl.getShaderInfoLog(cs_id, 1024, NULL, temp); 117 118 if (GL_TRUE != compile_status) 119 { 120 result = false; 121 122 goto end; 123 } 124 125 gl.linkProgram(po_id); 126 127 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); 128 129 gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status); 130 131 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); 132 133 if (GL_TRUE != link_status) 134 { 135 result = false; 136 137 goto end; 138 } 139 140 end: 141 if (cs_id != 0) 142 { 143 gl.deleteShader(cs_id); 144 145 cs_id = 0; 146 } 147 148 if (!result) 149 { 150 if (po_id != 0) 151 { 152 gl.deleteProgram(po_id); 153 154 po_id = 0; 155 } 156 } /* if (!result) */ 157 158 return po_id; 159 } 160 161 /** Builds a program object, using the user-specified code snippets. Can optionally configure 162 * the PO to use pre-defined attribute locations & transform feed-back varyings. 163 * 164 * @param gl DEQP CTS GL functions container. 165 * @param fs_body_parts Code snippets to use for the fragment shader. Must hold exactly 166 * @param n_fs_body_parts null-terminated text strings. May only 167 * be NULL if @param n_fs_body_parts is 0. 168 * @param n_fs_body_parts See @param fs_body_parts definitions. 169 * @param vs_body_parts Code snippets to use for the vertex shader. Must hold exactly 170 * @param n_vs_body_parts null-terminated text strings. May only 171 * be NULL if @param n_vs_body_parts is 0. 172 * @param n_vs_body_parts See @param vs_body_parts definitions. 173 * @param attribute_names Null-terminated attribute names to pass to the 174 * glBindAttribLocation() call. 175 * May only be NULL if @param n_attribute_properties is 0. 176 * @param attribute_locations Attribute locations to pass to the glBindAttribLocation() call. 177 * May only be NULL if @param n_attribute_properties is 0. 178 * @param n_attribute_properties See @param attribute_names and @param attribute_locations definitions. 179 * @param tf_varyings Transform-feedback varying names to use for the 180 * glTransformFeedbackVaryings() call. May only be NULL if 181 * @param n_tf_varyings is 0. 182 * @param n_tf_varyings See @param tf_varyings definition. 183 * @param tf_varying_mode Transform feedback mode to use for the 184 * glTransformFeedbackVaryings() call. Only used if @param n_tf_varyings 185 * is 0. 186 * 187 * @return Result PO id if program has been linked successfully, 0 otherwise. 188 **/ 189 glw::GLuint SparseBufferTestUtilities::createProgram(const glw::Functions& gl, const char** fs_body_parts, 190 unsigned int n_fs_body_parts, const char** vs_body_parts, 191 unsigned int n_vs_body_parts, const char** attribute_names, 192 const unsigned int* attribute_locations, 193 unsigned int n_attribute_properties, 194 const glw::GLchar* const* tf_varyings, unsigned int n_tf_varyings, 195 glw::GLenum tf_varying_mode) 196 { 197 glw::GLint compile_status = GL_FALSE; 198 glw::GLuint fs_id = 0; 199 glw::GLint link_status = GL_FALSE; 200 glw::GLuint po_id = 0; 201 bool result = true; 202 glw::GLuint vs_id = 0; 203 204 if (n_fs_body_parts > 0) 205 { 206 fs_id = gl.createShader(GL_FRAGMENT_SHADER); 207 } 208 209 po_id = gl.createProgram(); 210 211 if (n_vs_body_parts > 0) 212 { 213 vs_id = gl.createShader(GL_VERTEX_SHADER); 214 } 215 216 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed."); 217 218 if (n_fs_body_parts > 0) 219 { 220 gl.attachShader(po_id, fs_id); 221 } 222 223 if (n_vs_body_parts > 0) 224 { 225 gl.attachShader(po_id, vs_id); 226 } 227 228 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed."); 229 230 if (n_fs_body_parts > 0) 231 { 232 gl.shaderSource(fs_id, n_fs_body_parts, fs_body_parts, NULL); /* length */ 233 } 234 235 if (n_vs_body_parts > 0) 236 { 237 gl.shaderSource(vs_id, n_vs_body_parts, vs_body_parts, NULL); /* length */ 238 } 239 240 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed."); 241 242 const glw::GLuint so_ids[] = { fs_id, vs_id }; 243 const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]); 244 245 for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id) 246 { 247 if (so_ids[n_so_id] != 0) 248 { 249 gl.compileShader(so_ids[n_so_id]); 250 251 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); 252 253 gl.getShaderiv(so_ids[n_so_id], GL_COMPILE_STATUS, &compile_status); 254 255 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed"); 256 257 char temp[1024]; 258 gl.getShaderInfoLog(so_ids[n_so_id], 1024, NULL, temp); 259 260 if (GL_TRUE != compile_status) 261 { 262 result = false; 263 264 goto end; 265 } 266 } /* if (so_ids[n_so_id] != 0) */ 267 } /* for (all shader object IDs) */ 268 269 for (unsigned int n_attribute = 0; n_attribute < n_attribute_properties; ++n_attribute) 270 { 271 gl.bindAttribLocation(po_id, attribute_locations[n_attribute], attribute_names[n_attribute]); 272 273 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindAttribLocation() call failed."); 274 } /* for (all attributes to configure) */ 275 276 if (n_tf_varyings != 0) 277 { 278 gl.transformFeedbackVaryings(po_id, n_tf_varyings, tf_varyings, tf_varying_mode); 279 280 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed."); 281 } /* if (n_tf_varyings != 0) */ 282 283 gl.linkProgram(po_id); 284 285 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); 286 287 gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status); 288 289 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); 290 291 if (GL_TRUE != link_status) 292 { 293 result = false; 294 295 goto end; 296 } 297 298 end: 299 if (fs_id != 0) 300 { 301 gl.deleteShader(fs_id); 302 303 fs_id = 0; 304 } 305 306 if (vs_id != 0) 307 { 308 gl.deleteShader(vs_id); 309 310 vs_id = 0; 311 } 312 313 if (!result) 314 { 315 316 if (po_id != 0) 317 { 318 gl.deleteProgram(po_id); 319 320 po_id = 0; 321 } 322 } /* if (!result) */ 323 324 return po_id; 325 } 326 327 /** Returns a string with textual representation of the @param flags bitfield 328 * holding bits applicable to the @param flags argument of glBufferStorage() 329 * calls. 330 * 331 * @param flags Flags argument, as supported by the @param flags argument of 332 * glBufferStorage() entry-point. 333 * 334 * @return Described string. 335 **/ 336 std::string SparseBufferTestUtilities::getSparseBOFlagsString(glw::GLenum flags) 337 { 338 unsigned int n_flags_added = 0; 339 std::stringstream result_sstream; 340 341 if ((flags & GL_CLIENT_STORAGE_BIT) != 0) 342 { 343 result_sstream << "GL_CLIENT_STORAGE_BIT"; 344 345 ++n_flags_added; 346 } 347 348 if ((flags & GL_DYNAMIC_STORAGE_BIT) != 0) 349 { 350 result_sstream << ((n_flags_added) ? " | " : "") << "GL_DYNAMIC_STORAGE_BIT"; 351 352 ++n_flags_added; 353 } 354 355 if ((flags & GL_MAP_COHERENT_BIT) != 0) 356 { 357 result_sstream << ((n_flags_added) ? " | " : "") << "GL_MAP_COHERENT_BIT"; 358 359 ++n_flags_added; 360 } 361 362 if ((flags & GL_MAP_PERSISTENT_BIT) != 0) 363 { 364 result_sstream << ((n_flags_added) ? " | " : "") << "GL_MAP_PERSISTENT_BIT"; 365 366 ++n_flags_added; 367 } 368 369 if ((flags & GL_SPARSE_STORAGE_BIT_ARB) != 0) 370 { 371 result_sstream << ((n_flags_added) ? " | " : "") << "GL_SPARSE_STORAGE_BIT"; 372 373 ++n_flags_added; 374 } 375 376 return result_sstream.str(); 377 } 378 379 /** Constructor. 380 * 381 * @param context Rendering context 382 * @param name Test name 383 * @param description Test description 384 */ 385 NegativeTests::NegativeTests(deqp::Context& context) 386 : TestCase(context, "NegativeTests", "Implements all negative tests described in CTS_ARB_sparse_buffer") 387 , m_helper_bo_id(0) 388 , m_immutable_bo_id(0) 389 , m_immutable_bo_size(1024768) 390 , m_sparse_bo_id(0) 391 { 392 /* Left blank intentionally */ 393 } 394 395 /** Stub deinit method. */ 396 void NegativeTests::deinit() 397 { 398 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 399 400 if (m_helper_bo_id != 0) 401 { 402 gl.deleteBuffers(1, &m_helper_bo_id); 403 404 m_helper_bo_id = 0; 405 } 406 407 if (m_immutable_bo_id != 0) 408 { 409 gl.deleteBuffers(1, &m_immutable_bo_id); 410 411 m_immutable_bo_id = 0; 412 } 413 414 if (m_sparse_bo_id != 0) 415 { 416 gl.deleteBuffers(1, &m_sparse_bo_id); 417 418 m_sparse_bo_id = 0; 419 } 420 } 421 422 /** Stub init method */ 423 void NegativeTests::init() 424 { 425 /* Nothing to do here */ 426 } 427 428 /** Executes test iteration. 429 * 430 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. 431 */ 432 tcu::TestNode::IterateResult NegativeTests::iterate() 433 { 434 glw::GLvoid* data_ptr = DE_NULL; 435 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 436 glw::GLint page_size = 0; 437 bool result = true; 438 439 /* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */ 440 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer")) 441 { 442 throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported"); 443 } 444 445 /* Set up */ 446 gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size); 447 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed."); 448 449 gl.genBuffers(1, &m_helper_bo_id); 450 gl.genBuffers(1, &m_immutable_bo_id); 451 gl.genBuffers(1, &m_sparse_bo_id); 452 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed."); 453 454 gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo_id); 455 gl.bindBuffer(GL_COPY_READ_BUFFER, m_immutable_bo_id); 456 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_helper_bo_id); 457 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); 458 459 gl.bufferStorage(GL_ARRAY_BUFFER, page_size * 3, /* size as per test spec */ 460 DE_NULL, /* data */ 461 GL_SPARSE_STORAGE_BIT_ARB); 462 gl.bufferStorage(GL_COPY_READ_BUFFER, m_immutable_bo_size, /* size */ 463 DE_NULL, /* data */ 464 0); 465 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call(s) failed."); 466 467 /** * Verify glBufferPageCommitmentARB() returns GL_INVALID_ENUM if <target> is 468 * set to GL_INTERLEAVED_ATTRIBS. */ 469 glw::GLint error_code = GL_NO_ERROR; 470 471 gl.bufferPageCommitmentARB(GL_INTERLEAVED_ATTRIBS, 0, /* offset */ 472 page_size, GL_TRUE); /* commit */ 473 474 error_code = gl.getError(); 475 if (error_code != GL_INVALID_ENUM) 476 { 477 m_testCtx.getLog() << tcu::TestLog::Message 478 << "Invalid <target> value passed to a glBufferPageCommitmentARB() call" 479 " did not generate a GL_INVALID_ENUM error." 480 << tcu::TestLog::EndMessage; 481 482 result = false; 483 } 484 485 /* * Verify glBufferStorage() throws a GL_INVALID_VALUE error if <flags> is 486 * set to (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT) or 487 * (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT). */ 488 gl.bufferStorage(GL_ELEMENT_ARRAY_BUFFER, page_size * 3, /* size */ 489 DE_NULL, /* data */ 490 GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT); 491 492 error_code = gl.getError(); 493 if (error_code != GL_INVALID_VALUE) 494 { 495 m_testCtx.getLog() << tcu::TestLog::Message 496 << "Invalid <flags> value set to GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT " 497 "did not generate a GL_INVALID_VALUE error." 498 << tcu::TestLog::EndMessage; 499 500 result = false; 501 } 502 503 gl.bufferStorage(GL_ELEMENT_ARRAY_BUFFER, page_size * 3, /* size */ 504 DE_NULL, /* data */ 505 GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT); 506 507 error_code = gl.getError(); 508 if (error_code != GL_INVALID_VALUE) 509 { 510 m_testCtx.getLog() << tcu::TestLog::Message 511 << "Invalid <flags> value set to GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT " 512 "did not generate a GL_INVALID_VALUE error." 513 << tcu::TestLog::EndMessage; 514 515 result = false; 516 } 517 518 /* * Verify glBufferPageCommitmentARB() generates a GL_INVALID_OPERATION error if 519 * it is called for an immutable BO, which has not been initialized with the 520 * GL_SPARSE_STORAGE_BIT_ARB flag. */ 521 gl.bufferPageCommitmentARB(GL_COPY_READ_BUFFER, 0, /* offset */ 522 page_size, GL_TRUE); /* commit */ 523 524 error_code = gl.getError(); 525 if (error_code != GL_INVALID_OPERATION) 526 { 527 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() " 528 " issued against an immutable, non-sparse buffer object." 529 << tcu::TestLog::EndMessage; 530 531 result = false; 532 } 533 534 /* * Verify glBufferPageCommitmentARB() issues a GL_INVALID_VALUE error if <offset> 535 * is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value 536 * is equal to 1. */ 537 if (page_size != 1) 538 { 539 gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, page_size / 2, /* offset */ 540 page_size, GL_TRUE); /* commit */ 541 542 error_code = gl.getError(); 543 if (error_code != GL_INVALID_VALUE) 544 { 545 m_testCtx.getLog() << tcu::TestLog::Message 546 << "Invalid error code generated by glBufferPageCommitmentARB() " 547 "whose <offset> value was set to (page size / 2)." 548 << tcu::TestLog::EndMessage; 549 550 result = false; 551 } 552 } /* if (page_size != 1) */ 553 554 /* * Verify glBufferPageCommitmentARB() emits a GL_INVALID_VALUE error if <size> 555 * is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value 556 * is equal to 1. */ 557 if (page_size != 1) 558 { 559 gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 560 page_size / 2, GL_TRUE); /* commit */ 561 562 error_code = gl.getError(); 563 if (error_code != GL_INVALID_VALUE) 564 { 565 m_testCtx.getLog() << tcu::TestLog::Message 566 << "Invalid error code generated by glBufferPageCommitmentARB() " 567 "whose <size> value was set to (page size / 2)." 568 << tcu::TestLog::EndMessage; 569 570 result = false; 571 } 572 } /* if (page_size != 1) */ 573 574 /* * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <offset> is 575 * set to -1, but all other arguments are valid. */ 576 gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, -1, /* offset */ 577 page_size, GL_TRUE); /* commit */ 578 579 error_code = gl.getError(); 580 if (error_code != GL_INVALID_VALUE) 581 { 582 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() " 583 "whose <offset> argument was set to -1." 584 << tcu::TestLog::EndMessage; 585 586 result = false; 587 } 588 589 /* * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <size> is 590 * set to -1, but all other arguments are valid. */ 591 gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 592 -1, /* size */ 593 GL_TRUE); /* commit */ 594 595 error_code = gl.getError(); 596 if (error_code != GL_INVALID_VALUE) 597 { 598 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() " 599 "whose <size> argument was set to -1." 600 << tcu::TestLog::EndMessage; 601 602 result = false; 603 } 604 605 /* * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is 606 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to 0 and <size> 607 * argument used for the call is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 4. */ 608 gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 609 page_size * 4, /* size */ 610 GL_TRUE); 611 612 error_code = gl.getError(); 613 if (error_code != GL_INVALID_VALUE) 614 { 615 m_testCtx.getLog() << tcu::TestLog::Message 616 << "Invalid error code generated by glBufferPageCommitmentARB() " 617 "whose <offset> was set to 0 and <size> was set to (page size * 4), " 618 "when the buffer storage size had been configured to be (page size * 3)." 619 << tcu::TestLog::EndMessage; 620 621 result = false; 622 } 623 624 /* * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is 625 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to 626 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 1 and <size> argument used for the call 627 * is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3. */ 628 gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, page_size * 1, /* offset */ 629 page_size * 3, /* size */ 630 GL_TRUE); 631 632 error_code = gl.getError(); 633 if (error_code != GL_INVALID_VALUE) 634 { 635 m_testCtx.getLog() << tcu::TestLog::Message 636 << "Invalid error code generated by glBufferPageCommitmentARB() " 637 "whose <offset> was set to (page size) and <size> was set to (page size * 3), " 638 "when the buffer storage size had been configured to be (page size * 3)." 639 << tcu::TestLog::EndMessage; 640 641 result = false; 642 } 643 644 /* * Verify that calling glMapBuffer() or glMapBufferRange() against a sparse 645 * buffer generates a GL_INVALID_OPERATION error. */ 646 data_ptr = gl.mapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); 647 648 if (data_ptr != DE_NULL) 649 { 650 m_testCtx.getLog() << tcu::TestLog::Message 651 << "Non-NULL pointer returned by an invalid glMapBuffer() call, issued " 652 "against a sparse buffer object" 653 << tcu::TestLog::EndMessage; 654 655 result = false; 656 } 657 658 error_code = gl.getError(); 659 660 if (error_code != GL_INVALID_OPERATION) 661 { 662 m_testCtx.getLog() << tcu::TestLog::Message 663 << "Invalid error code generated by glMapBuffer() call, issued against " 664 "a sparse buffer object" 665 << tcu::TestLog::EndMessage; 666 667 result = false; 668 } 669 670 data_ptr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, /* offset */ 671 page_size, /* length */ 672 GL_MAP_READ_BIT); 673 674 if (data_ptr != DE_NULL) 675 { 676 m_testCtx.getLog() << tcu::TestLog::Message 677 << "Non-NULL pointer returned by an invalid glMapBufferRange() call, issued " 678 "against a sparse buffer object" 679 << tcu::TestLog::EndMessage; 680 681 result = false; 682 } 683 684 error_code = gl.getError(); 685 686 if (error_code != GL_INVALID_OPERATION) 687 { 688 m_testCtx.getLog() << tcu::TestLog::Message 689 << "Invalid error code generated by glMapBufferRange() call, issued against " 690 "a sparse buffer object" 691 << tcu::TestLog::EndMessage; 692 693 result = false; 694 } 695 696 m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); 697 698 return STOP; 699 } 700 701 /** Constructor. 702 * 703 * @param context Rendering context 704 * @param name Test name 705 * @param description Test description 706 */ 707 PageSizeGetterTest::PageSizeGetterTest(deqp::Context& context) 708 : TestCase(context, "PageSizeGetterTest", 709 "Verifies GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname is recognized by the getter functions") 710 { 711 /* Left blank intentionally */ 712 } 713 714 /** Stub deinit method. */ 715 void PageSizeGetterTest::deinit() 716 { 717 /* Nothing to be done here */ 718 } 719 720 /** Stub init method */ 721 void PageSizeGetterTest::init() 722 { 723 /* Nothing to do here */ 724 } 725 726 /** Executes test iteration. 727 * 728 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. 729 */ 730 tcu::TestNode::IterateResult PageSizeGetterTest::iterate() 731 { 732 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 733 glw::GLboolean page_size_bool = false; 734 glw::GLdouble page_size_double = 0.0; 735 glw::GLfloat page_size_float = 0.0f; 736 glw::GLint page_size_int = 0; 737 glw::GLint64 page_size_int64 = 0; 738 bool result = true; 739 740 /* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */ 741 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer")) 742 { 743 throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported"); 744 } 745 746 /* glGetIntegerv() */ 747 gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_int); 748 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed"); 749 750 if (page_size_int < 1 || page_size_int > 65536) 751 { 752 m_testCtx.getLog() << tcu::TestLog::Message << "Page size reported by the implementation (" << page_size_int 753 << ")" 754 " by glGetIntegerv() is out of the allowed range." 755 << tcu::TestLog::EndMessage; 756 757 result = false; 758 } 759 760 /* glGetBooleanv() */ 761 gl.getBooleanv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_bool); 762 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed"); 763 764 if (!page_size_bool) 765 { 766 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetBooleanv()" 767 << tcu::TestLog::EndMessage; 768 769 result = false; 770 } 771 772 /* glGetDoublev() */ 773 gl.getDoublev(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_double); 774 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed"); 775 776 if (de::abs(page_size_double - page_size_int) > 1e-5) 777 { 778 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetDoublev()" 779 " (reported value: " 780 << page_size_double << ", expected value: " << page_size_int << ")" 781 << tcu::TestLog::EndMessage; 782 783 result = false; 784 } 785 786 /* glGetFloatv() */ 787 gl.getFloatv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_float); 788 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed"); 789 790 if (de::abs(page_size_float - static_cast<float>(page_size_int)) > 1e-5f) 791 { 792 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetFloatv()" 793 " (reported value: " 794 << page_size_float << ", expected value: " << page_size_int << ")" 795 << tcu::TestLog::EndMessage; 796 797 result = false; 798 } 799 800 /* glGetInteger64v() */ 801 gl.getInteger64v(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_int64); 802 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed"); 803 804 if (page_size_int64 != page_size_int) 805 { 806 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetInteger64v()" 807 " (reported value: " 808 << page_size_int64 << ", expected value: " << page_size_int << ")" 809 << tcu::TestLog::EndMessage; 810 811 result = false; 812 } 813 814 m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); 815 816 return STOP; 817 } 818 819 /** Constructor. 820 * 821 * @param gl GL entry-points container 822 * @param testContext CTS test context 823 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 824 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 825 * @param all_pages_committed true to run the test with all data memory pages committed, 826 * false to leave some of them without an actual memory backing. 827 */ 828 AtomicCounterBufferStorageTestCase::AtomicCounterBufferStorageTestCase(const glw::Functions& gl, 829 tcu::TestContext& testContext, 830 glw::GLint page_size, bool all_pages_committed) 831 : m_all_pages_committed(all_pages_committed) 832 , m_gl(gl) 833 , m_gl_atomic_counter_uniform_array_stride(0) 834 , m_gl_max_vertex_atomic_counters_value(0) 835 , m_helper_bo(0) 836 , m_helper_bo_size(0) 837 , m_helper_bo_size_rounded(0) 838 , m_n_draw_calls(3) /* as per test spec */ 839 , m_page_size(page_size) 840 , m_po(0) 841 , m_sparse_bo(0) 842 , m_sparse_bo_data_size(0) 843 , m_sparse_bo_data_size_rounded(0) 844 , m_sparse_bo_data_start_offset(0) 845 , m_sparse_bo_data_start_offset_rounded(0) 846 , m_testCtx(testContext) 847 , m_vao(0) 848 { 849 /* Left blank intentionally */ 850 } 851 852 /** Releases all GL objects used across all test case iterations. 853 * 854 * Called once during BufferStorage test run-time. 855 */ 856 void AtomicCounterBufferStorageTestCase::deinitTestCaseGlobal() 857 { 858 if (m_helper_bo != 0) 859 { 860 m_gl.deleteBuffers(1, &m_helper_bo); 861 862 m_helper_bo = 0; 863 } 864 865 if (m_po != 0) 866 { 867 m_gl.deleteProgram(m_po); 868 869 m_po = 0; 870 } 871 872 if (m_vao != 0) 873 { 874 m_gl.deleteVertexArrays(1, &m_vao); 875 876 m_vao = 0; 877 } 878 } 879 880 /** Releases temporary GL objects, created specifically for one test case iteration. */ 881 void AtomicCounterBufferStorageTestCase::deinitTestCaseIteration() 882 { 883 if (m_sparse_bo != 0) 884 { 885 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 886 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 887 888 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 889 m_helper_bo_size_rounded, GL_FALSE); /* commit */ 890 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 891 892 m_sparse_bo = 0; 893 } 894 } 895 896 /** Executes a single test iteration. The BufferStorage test will call this method 897 * numerously during its life-time, testing various valid flag combinations applied 898 * to the tested sparse buffer object at glBufferStorage() call time. 899 * 900 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 901 * call to set up the sparse buffer's storage. 902 * 903 * @return true if the test case executed correctly, false otherwise. 904 */ 905 bool AtomicCounterBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 906 { 907 (void)sparse_bo_storage_flags; 908 static const unsigned char data_zero = 0; 909 bool result = true; 910 911 /* Only execute if GL_MAX_VERTEX_ATOMIC_COUNTERS is > 0 */ 912 if (m_gl_max_vertex_atomic_counters_value == 0) 913 { 914 m_testCtx.getLog() << tcu::TestLog::Message << "G_MAX_VERTEX_ATOMIC_COUNTERS is 0. Skipping the test." 915 << tcu::TestLog::EndMessage; 916 917 goto end; 918 } 919 920 /* Bind the test program object */ 921 m_gl.useProgram(m_po); 922 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 923 924 m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_sparse_bo); 925 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 926 927 /* Try using both ranged and non-ranged AC bindings. 928 * 929 * NOTE: It only makes sense to perform glBindBufferBase() test if all AC pages are 930 * committed 931 */ 932 for (unsigned int n_binding_type = (m_all_pages_committed) ? 0 : 1; 933 n_binding_type < 2; /* glBindBufferBase(), glBindBufferRange() */ 934 ++n_binding_type) 935 { 936 bool result_local = true; 937 938 if (n_binding_type == 0) 939 { 940 m_gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */ 941 m_sparse_bo); 942 943 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed."); 944 } 945 else 946 { 947 m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */ 948 m_sparse_bo, m_sparse_bo_data_start_offset, m_helper_bo_size); 949 950 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed."); 951 } 952 953 /* Zero out the sparse buffer's contents */ 954 m_gl.clearBufferData(GL_ATOMIC_COUNTER_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero); 955 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed."); 956 957 /* Run the test */ 958 m_gl.drawArraysInstanced(GL_POINTS, 0, /* first */ 959 m_gl_max_vertex_atomic_counters_value, /* count */ 960 m_n_draw_calls); 961 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed"); 962 963 /* Retrieve the atomic counter values */ 964 const glw::GLuint* ac_data = NULL; 965 const unsigned int n_expected_written_values = 966 (m_all_pages_committed) ? m_gl_max_vertex_atomic_counters_value : m_gl_max_vertex_atomic_counters_value / 2; 967 968 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo); 969 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo); 970 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffeR() call failed"); 971 972 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 973 (n_binding_type == 0) ? 0 : m_sparse_bo_data_start_offset, 0, /* writeOffset */ 974 m_sparse_bo_data_size); 975 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 976 977 ac_data = (const glw::GLuint*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */ 978 m_sparse_bo_data_size, GL_MAP_READ_BIT); 979 980 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed."); 981 982 for (unsigned int n_counter = 0; n_counter < n_expected_written_values && result_local; ++n_counter) 983 { 984 const unsigned int expected_value = m_n_draw_calls; 985 const unsigned int retrieved_value = 986 *((unsigned int*)((unsigned char*)ac_data + m_gl_atomic_counter_uniform_array_stride * n_counter)); 987 988 if (expected_value != retrieved_value) 989 { 990 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value " 991 "[" 992 << retrieved_value << "]" 993 " instead of the expected value " 994 "[" 995 << expected_value << "]" 996 " at index " 997 << n_counter << " when using " 998 << ((n_binding_type == 0) ? "glBindBufferBase()" : "glBindBufferRange()") 999 << " for AC binding configuration" << tcu::TestLog::EndMessage; 1000 1001 result_local = false; 1002 } /* if (expected_value != retrieved_value) */ 1003 } /* for (all draw calls that need to be executed) */ 1004 1005 m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER); 1006 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 1007 1008 result &= result_local; 1009 } /* for (both binding types) */ 1010 1011 end: 1012 return result; 1013 } 1014 1015 /** Initializes GL objects used across all test case iterations. 1016 * 1017 * Called once during BufferStorage test run-time. 1018 */ 1019 bool AtomicCounterBufferStorageTestCase::initTestCaseGlobal() 1020 { 1021 const glw::GLuint ac_uniform_index = 0; /* only one uniform is defined in the VS below */ 1022 std::stringstream n_counters_sstream; 1023 std::string n_counters_string; 1024 bool result = true; 1025 1026 static const char* vs_body_preamble = "#version 430 core\n" 1027 "\n"; 1028 1029 static const char* vs_body_core = "layout(binding = 0) uniform atomic_uint counters[N_COUNTERS];\n" 1030 "\n" 1031 "void main()\n" 1032 "{\n" 1033 " for (uint n = 0; n < N_COUNTERS; ++n)\n" 1034 " {\n" 1035 " if (n == gl_VertexID)\n" 1036 " {\n" 1037 " atomicCounterIncrement(counters[n]);\n" 1038 " }\n" 1039 " }\n" 1040 "\n" 1041 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" 1042 "}\n"; 1043 const char* vs_body_parts[] = { vs_body_preamble, DE_NULL, /* will be set to n_counters_string.c_str() */ 1044 vs_body_core }; 1045 const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]); 1046 1047 /* Retrieve GL_MAX_VERTEX_ATOMIC_COUNTERS value. The test will only be executed if it's >= 1 */ 1048 m_gl.getIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &m_gl_max_vertex_atomic_counters_value); 1049 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call failed."); 1050 1051 if (m_gl_max_vertex_atomic_counters_value == 0) 1052 { 1053 goto end; 1054 } 1055 1056 /* Form the N_COUNTERS declaration string */ 1057 n_counters_sstream << "#define N_COUNTERS " << m_gl_max_vertex_atomic_counters_value << "\n"; 1058 n_counters_string = n_counters_sstream.str(); 1059 1060 vs_body_parts[1] = n_counters_string.c_str(); 1061 1062 /* Set up the program object */ 1063 DE_ASSERT(m_po == 0); 1064 1065 m_po = 1066 SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */ 1067 0, /* n_fs_body_parts */ 1068 vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names */ 1069 DE_NULL, /* attribute_locations */ 1070 0); /* n_attribute_properties */ 1071 1072 if (m_po == 0) 1073 { 1074 result = false; 1075 1076 goto end; 1077 } 1078 1079 /* Helper BO will be used to hold the atomic counter buffer data. 1080 * Determine how much space will be needed. 1081 * 1082 * Min max for the GL constant value is 0. Bail out if that's the 1083 * value we are returned - it is pointless to execute the test in 1084 * such environment. 1085 */ 1086 m_gl.getActiveUniformsiv(m_po, 1, /* uniformCount */ 1087 &ac_uniform_index, GL_UNIFORM_ARRAY_STRIDE, &m_gl_atomic_counter_uniform_array_stride); 1088 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetActiveUniformsiv() call failed."); 1089 1090 DE_ASSERT(m_gl_atomic_counter_uniform_array_stride >= (int)sizeof(unsigned int)); 1091 1092 m_helper_bo_size = m_gl_atomic_counter_uniform_array_stride * m_gl_max_vertex_atomic_counters_value; 1093 m_helper_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_helper_bo_size, m_page_size); 1094 1095 /* Set up the helper BO */ 1096 DE_ASSERT(m_helper_bo == 0); 1097 1098 m_gl.genBuffers(1, &m_helper_bo); 1099 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 1100 1101 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 1102 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1103 1104 m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_helper_bo_size_rounded, DE_NULL, GL_MAP_READ_BIT); /* flags */ 1105 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 1106 1107 /* Set up the vertex array object */ 1108 DE_ASSERT(m_vao == 0); 1109 1110 m_gl.genVertexArrays(1, &m_vao); 1111 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed."); 1112 1113 m_gl.bindVertexArray(m_vao); 1114 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed."); 1115 1116 end: 1117 return result; 1118 } 1119 1120 /** Initializes GL objects which are needed for a single test case iteration. 1121 * 1122 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 1123 * to release these objects. 1124 **/ 1125 bool AtomicCounterBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 1126 { 1127 bool result = true; 1128 1129 /* Cache the BO id, if not cached already */ 1130 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 1131 1132 m_sparse_bo = sparse_bo; 1133 1134 /* Set up the sparse bufffer. */ 1135 int sparse_bo_data_size = 0; 1136 1137 DE_ASSERT(m_helper_bo_size_rounded != 0); 1138 1139 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 1140 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1141 1142 if (m_all_pages_committed) 1143 { 1144 /* Commit all required pages */ 1145 sparse_bo_data_size = m_helper_bo_size_rounded; 1146 } 1147 else 1148 { 1149 /* Only commit the first half of the required pages */ 1150 DE_ASSERT((m_helper_bo_size_rounded % m_page_size) == 0); 1151 1152 sparse_bo_data_size = (m_helper_bo_size_rounded / m_page_size) * m_page_size / 2; 1153 } 1154 1155 /* NOTE: We need to ensure that the memory region assigned to the atomic counter buffer spans 1156 * at least through two separate pages. 1157 * 1158 * Since we align up, we need to move one page backward and then apply the alignment function 1159 * to determine the start page index. 1160 */ 1161 const int sparse_bo_data_start_offset = m_page_size - m_helper_bo_size_rounded / 2; 1162 int sparse_bo_data_start_offset_minus_page = sparse_bo_data_start_offset - m_page_size; 1163 1164 if (sparse_bo_data_start_offset_minus_page < 0) 1165 { 1166 sparse_bo_data_start_offset_minus_page = 0; 1167 } 1168 1169 m_sparse_bo_data_start_offset = sparse_bo_data_start_offset; 1170 m_sparse_bo_data_start_offset_rounded = 1171 SparseBufferTestUtilities::alignOffset(sparse_bo_data_start_offset_minus_page, m_page_size); 1172 m_sparse_bo_data_size = sparse_bo_data_size; 1173 m_sparse_bo_data_size_rounded = 1174 SparseBufferTestUtilities::alignOffset(m_sparse_bo_data_start_offset + sparse_bo_data_size, m_page_size); 1175 1176 DE_ASSERT((m_sparse_bo_data_size_rounded % m_page_size) == 0); 1177 DE_ASSERT((m_sparse_bo_data_start_offset_rounded % m_page_size) == 0); 1178 1179 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_data_start_offset_rounded, m_sparse_bo_data_size_rounded, 1180 GL_TRUE); /* commit */ 1181 1182 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 1183 1184 return result; 1185 } 1186 1187 /** Constructor. 1188 * 1189 * @param gl GL entry-points container 1190 * @param context CTS rendering context 1191 * @param testContext CTS test context 1192 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 1193 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 1194 */ 1195 BufferTextureStorageTestCase::BufferTextureStorageTestCase(const glw::Functions& gl, deqp::Context& context, 1196 tcu::TestContext& testContext, glw::GLint page_size) 1197 : m_gl(gl) 1198 , m_helper_bo(0) 1199 , m_helper_bo_data(DE_NULL) 1200 , m_helper_bo_data_size(0) 1201 , m_is_texture_buffer_range_supported(false) 1202 , m_page_size(page_size) 1203 , m_po(0) 1204 , m_po_local_wg_size(1024) 1205 , m_sparse_bo(0) 1206 , m_sparse_bo_size(0) 1207 , m_sparse_bo_size_rounded(0) 1208 , m_ssbo(0) 1209 , m_ssbo_zero_data(DE_NULL) 1210 , m_ssbo_zero_data_size(0) 1211 , m_testCtx(testContext) 1212 , m_to(0) 1213 , m_to_width(65536) /* min max for GL_MAX_TEXTURE_BUFFER_SIZE_ARB */ 1214 { 1215 const glu::ContextInfo& context_info = context.getContextInfo(); 1216 glu::RenderContext& render_context = context.getRenderContext(); 1217 1218 if (glu::contextSupports(render_context.getType(), glu::ApiType::core(4, 3)) || 1219 context_info.isExtensionSupported("GL_ARB_texture_buffer_range")) 1220 { 1221 m_is_texture_buffer_range_supported = true; 1222 } 1223 } 1224 1225 /** Releases all GL objects used across all test case iterations. 1226 * 1227 * Called once during BufferStorage test run-time. 1228 */ 1229 void BufferTextureStorageTestCase::deinitTestCaseGlobal() 1230 { 1231 if (m_helper_bo != 0) 1232 { 1233 m_gl.deleteBuffers(1, &m_helper_bo); 1234 1235 m_helper_bo = 0; 1236 } 1237 1238 if (m_helper_bo_data != DE_NULL) 1239 { 1240 delete[] m_helper_bo_data; 1241 1242 m_helper_bo_data = DE_NULL; 1243 } 1244 1245 if (m_po != 0) 1246 { 1247 m_gl.deleteProgram(m_po); 1248 1249 m_po = 0; 1250 } 1251 1252 if (m_ssbo != 0) 1253 { 1254 m_gl.deleteBuffers(1, &m_ssbo); 1255 1256 m_ssbo = 0; 1257 } 1258 1259 if (m_ssbo_zero_data != DE_NULL) 1260 { 1261 delete[] m_ssbo_zero_data; 1262 1263 m_ssbo_zero_data = DE_NULL; 1264 } 1265 1266 if (m_to != 0) 1267 { 1268 m_gl.deleteTextures(1, &m_to); 1269 1270 m_to = 0; 1271 } 1272 } 1273 1274 /** Releases temporary GL objects, created specifically for one test case iteration. */ 1275 void BufferTextureStorageTestCase::deinitTestCaseIteration() 1276 { 1277 if (m_sparse_bo != 0) 1278 { 1279 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 1280 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1281 1282 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 1283 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 1284 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 1285 1286 m_sparse_bo = 0; 1287 } 1288 } 1289 1290 /** Executes a single test iteration. The BufferStorage test will call this method 1291 * numerously during its life-time, testing various valid flag combinations applied 1292 * to the tested sparse buffer object at glBufferStorage() call time. 1293 * 1294 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 1295 * call to set up the sparse buffer's storage. 1296 * 1297 * @return true if the test case executed correctly, false otherwise. 1298 */ 1299 bool BufferTextureStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 1300 { 1301 (void)sparse_bo_storage_flags; 1302 bool result = true; 1303 1304 /* Bind the program object */ 1305 m_gl.useProgram(m_po); 1306 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 1307 1308 m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo); 1309 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1310 1311 m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */ 1312 m_ssbo); 1313 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed."); 1314 1315 /* Set up bindings for the copy ops */ 1316 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 1317 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo); 1318 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 1319 1320 /* Run the test in two iterations: 1321 * 1322 * a) All required pages are committed. 1323 * b) Only half of the pages are committed. */ 1324 for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration) 1325 { 1326 1327 /* Test glTexBuffer() and glTexBufferRange() separately. */ 1328 for (int n_entry_point = 0; n_entry_point < (m_is_texture_buffer_range_supported ? 2 : 1); ++n_entry_point) 1329 { 1330 bool result_local = true; 1331 1332 /* Set up the sparse buffer's memory backing. */ 1333 const unsigned int tbo_commit_start_offset = (n_iteration == 0) ? 0 : m_sparse_bo_size_rounded / 2; 1334 const unsigned int tbo_commit_size = 1335 (n_iteration == 0) ? m_sparse_bo_size_rounded : m_sparse_bo_size_rounded / 2; 1336 1337 m_gl.bindBuffer(GL_TEXTURE_BUFFER, m_sparse_bo); 1338 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1339 1340 m_gl.bufferPageCommitmentARB(GL_TEXTURE_BUFFER, tbo_commit_start_offset, tbo_commit_size, 1341 GL_TRUE); /* commit */ 1342 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 1343 1344 /* Set up the buffer texture's backing */ 1345 if (n_entry_point == 0) 1346 { 1347 m_gl.texBuffer(GL_TEXTURE_BUFFER, GL_RGBA8, m_sparse_bo); 1348 1349 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexBuffer() call failed."); 1350 } 1351 else 1352 { 1353 m_gl.texBufferRange(GL_TEXTURE_BUFFER, GL_RGBA8, m_sparse_bo, 0, /* offset */ 1354 m_sparse_bo_size); 1355 1356 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexBufferRange() call failed."); 1357 } 1358 1359 /* Set up the sparse buffer's data storage */ 1360 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 1361 0, /* writeOffset */ 1362 m_helper_bo_data_size); 1363 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 1364 1365 /* Run the compute program */ 1366 DE_ASSERT((m_to_width % m_po_local_wg_size) == 0); 1367 1368 m_gl.dispatchCompute(m_to_width / m_po_local_wg_size, 1, /* num_groups_y */ 1369 1); /* num_groups_z */ 1370 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed."); 1371 1372 /* Flush the caches */ 1373 m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); 1374 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed."); 1375 1376 /* Map the SSBO into process space, so we can check if the texture buffer's 1377 * contents was found valid by the compute shader */ 1378 unsigned int current_tb_offset = 0; 1379 const unsigned int* ssbo_data_ptr = 1380 (const unsigned int*)m_gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); 1381 1382 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed."); 1383 1384 for (unsigned int n_texel = 0; n_texel < m_to_width && result_local; 1385 ++n_texel, current_tb_offset += 4 /* rgba */) 1386 { 1387 /* NOTE: Since the CS uses std140 layout, we need to move by 4 ints for 1388 * each result value */ 1389 if (current_tb_offset >= tbo_commit_start_offset && 1390 current_tb_offset < (tbo_commit_start_offset + tbo_commit_size) && ssbo_data_ptr[n_texel * 4] != 1) 1391 { 1392 m_testCtx.getLog() << tcu::TestLog::Message << "A texel read from the texture buffer at index " 1393 "[" 1394 << n_texel << "]" 1395 " was marked as invalid by the CS invocation." 1396 << tcu::TestLog::EndMessage; 1397 1398 result_local = false; 1399 } /* if (ssbo_data_ptr[n_texel] != 1) */ 1400 } /* for (all result values) */ 1401 1402 result &= result_local; 1403 1404 m_gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 1405 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 1406 1407 /* Remove the physical backing from the sparse buffer */ 1408 m_gl.bufferPageCommitmentARB(GL_TEXTURE_BUFFER, 0, /* offset */ 1409 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 1410 1411 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 1412 1413 /* Reset SSBO's contents */ 1414 m_gl.bufferSubData(GL_SHADER_STORAGE_BUFFER, 0, /* offset */ 1415 m_ssbo_zero_data_size, m_ssbo_zero_data); 1416 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed."); 1417 } /* for (both entry-points) */ 1418 } /* for (both iterations) */ 1419 1420 return result; 1421 } 1422 1423 /** Initializes GL objects used across all test case iterations. 1424 * 1425 * Called once during BufferStorage test run-time. 1426 */ 1427 bool BufferTextureStorageTestCase::initTestCaseGlobal() 1428 { 1429 /* Set up the test program */ 1430 static const char* cs_body = 1431 "#version 430 core\n" 1432 "\n" 1433 "layout(local_size_x = 1024) in;\n" 1434 "\n" 1435 "layout(std140, binding = 0) buffer data\n" 1436 "{\n" 1437 " restrict writeonly int result[];\n" 1438 "};\n" 1439 "\n" 1440 "uniform samplerBuffer input_texture;\n" 1441 "\n" 1442 "void main()\n" 1443 "{\n" 1444 " uint texel_index = gl_GlobalInvocationID.x;\n" 1445 "\n" 1446 " if (texel_index < 65536)\n" 1447 " {\n" 1448 " vec4 expected_texel_data = vec4 (float((texel_index) % 255) / 255.0,\n" 1449 " float((texel_index + 35) % 255) / 255.0,\n" 1450 " float((texel_index + 78) % 255) / 255.0,\n" 1451 " float((texel_index + 131) % 255) / 255.0);\n" 1452 " vec4 texel_data = texelFetch(input_texture, int(texel_index) );\n" 1453 "\n" 1454 " if (abs(texel_data.r - expected_texel_data.r) > 1.0 / 255.0 ||\n" 1455 " abs(texel_data.g - expected_texel_data.g) > 1.0 / 255.0 ||\n" 1456 " abs(texel_data.b - expected_texel_data.b) > 1.0 / 255.0 ||\n" 1457 " abs(texel_data.a - expected_texel_data.a) > 1.0 / 255.0)\n" 1458 " {\n" 1459 " result[texel_index] = 0;\n" 1460 " }\n" 1461 " else\n" 1462 " {\n" 1463 " result[texel_index] = 1;\n" 1464 " }\n" 1465 " }\n" 1466 "}\n"; 1467 1468 m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */ 1469 1470 /* Set up a data buffer we will use to initialize the SSBO with default data. 1471 * 1472 * CS uses a std140 layout for the SSBO, so we need to add the additional padding. 1473 */ 1474 m_ssbo_zero_data_size = static_cast<unsigned int>(4 * sizeof(int) * m_to_width); 1475 m_ssbo_zero_data = new unsigned char[m_ssbo_zero_data_size]; 1476 1477 memset(m_ssbo_zero_data, 0, m_ssbo_zero_data_size); 1478 1479 /* Set up the SSBO */ 1480 m_gl.genBuffers(1, &m_ssbo); 1481 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 1482 1483 m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo); 1484 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1485 1486 m_gl.bufferData(GL_SHADER_STORAGE_BUFFER, m_ssbo_zero_data_size, m_ssbo_zero_data, GL_STATIC_DRAW); 1487 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed."); 1488 1489 /* During execution, we will need to use a helper buffer object. The BO will hold 1490 * data we will be copying into the sparse buffer object for each iteration. 1491 * 1492 * Create an array to hold the helper buffer's data and fill it with info that 1493 * the compute shader is going to be expecting */ 1494 unsigned char* helper_bo_data_traveller_ptr = NULL; 1495 1496 m_helper_bo_data_size = m_to_width * 4; /* rgba */ 1497 m_helper_bo_data = new unsigned char[m_helper_bo_data_size]; 1498 1499 helper_bo_data_traveller_ptr = m_helper_bo_data; 1500 1501 for (unsigned int n_texel = 0; n_texel < m_to_width; ++n_texel) 1502 { 1503 /* Red */ 1504 *helper_bo_data_traveller_ptr = static_cast<unsigned char>(n_texel % 255); 1505 ++helper_bo_data_traveller_ptr; 1506 1507 /* Green */ 1508 *helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 35) % 255); 1509 ++helper_bo_data_traveller_ptr; 1510 1511 /* Blue */ 1512 *helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 78) % 255); 1513 ++helper_bo_data_traveller_ptr; 1514 1515 /* Alpha */ 1516 *helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 131) % 255); 1517 ++helper_bo_data_traveller_ptr; 1518 } /* for (all texels to be accessible via the buffer texture) */ 1519 1520 /* Set up the helper buffer object which we are going to use to copy data into 1521 * the sparse buffer object. */ 1522 m_gl.genBuffers(1, &m_helper_bo); 1523 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 1524 1525 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 1526 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1527 1528 m_gl.bufferData(GL_COPY_READ_BUFFER, m_helper_bo_data_size, m_helper_bo_data, GL_STATIC_DRAW); 1529 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed."); 1530 1531 /* Set up the texture buffer object. We will attach the actual buffer storage 1532 * in execute() */ 1533 m_gl.genTextures(1, &m_to); 1534 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed."); 1535 1536 m_gl.bindTexture(GL_TEXTURE_BUFFER, m_to); 1537 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed."); 1538 1539 /* Determine the number of bytes both the helper and the sparse buffer 1540 * object need to be able to hold, at maximum */ 1541 m_sparse_bo_size = static_cast<unsigned int>(m_to_width * sizeof(int)); 1542 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size); 1543 1544 return true; 1545 } 1546 1547 /** Initializes GL objects which are needed for a single test case iteration. 1548 * 1549 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 1550 * to release these objects. 1551 **/ 1552 bool BufferTextureStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 1553 { 1554 bool result = true; 1555 1556 /* Cache the BO id, if not cached already */ 1557 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 1558 1559 m_sparse_bo = sparse_bo; 1560 1561 return result; 1562 } 1563 1564 /** Constructor. 1565 * 1566 * @param gl GL entry-points container 1567 * @param testContext CTS test context 1568 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 1569 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 1570 */ 1571 ClearOpsBufferStorageTestCase::ClearOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, 1572 glw::GLint page_size) 1573 : m_gl(gl) 1574 , m_helper_bo(0) 1575 , m_initial_data(DE_NULL) 1576 , m_n_pages_to_use(16) 1577 , m_page_size(page_size) 1578 , m_sparse_bo(0) 1579 , m_sparse_bo_size_rounded(0) 1580 , m_testCtx(testContext) 1581 { 1582 /* Left blank intentionally */ 1583 } 1584 1585 /** Releases all GL objects used across all test case iterations. 1586 * 1587 * Called once during BufferStorage test run-time. 1588 */ 1589 void ClearOpsBufferStorageTestCase::deinitTestCaseGlobal() 1590 { 1591 if (m_helper_bo != 0) 1592 { 1593 m_gl.deleteBuffers(1, &m_helper_bo); 1594 1595 m_helper_bo = 0; 1596 } 1597 1598 if (m_initial_data != DE_NULL) 1599 { 1600 delete[] m_initial_data; 1601 1602 m_initial_data = DE_NULL; 1603 } 1604 } 1605 1606 /** Releases temporary GL objects, created specifically for one test case iteration. */ 1607 void ClearOpsBufferStorageTestCase::deinitTestCaseIteration() 1608 { 1609 if (m_sparse_bo != 0) 1610 { 1611 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 1612 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1613 1614 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 1615 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 1616 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 1617 1618 m_sparse_bo = 0; 1619 } 1620 } 1621 1622 /** Executes a single test iteration. The BufferStorage test will call this method 1623 * numerously during its life-time, testing various valid flag combinations applied 1624 * to the tested sparse buffer object at glBufferStorage() call time. 1625 * 1626 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 1627 * call to set up the sparse buffer's storage. 1628 * 1629 * @return true if the test case executed correctly, false otherwise. 1630 */ 1631 bool ClearOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 1632 { 1633 (void)sparse_bo_storage_flags; 1634 bool result = true; 1635 const unsigned int data_rgba8 = 0x12345678; 1636 1637 for (unsigned int n_clear_op_type = 0; n_clear_op_type < 2; /* glClearBufferData(), glClearBufferSubData() */ 1638 ++n_clear_op_type) 1639 { 1640 const bool use_clear_buffer_data_call = (n_clear_op_type == 0); 1641 1642 /* We will run the test case in two iterations: 1643 * 1644 * 1) All pages will have a physical backing. 1645 * 2) Half of the pages will have a physical backing. 1646 */ 1647 for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration) 1648 { 1649 /* By default, for each iteration all sparse buffer pages are commited. 1650 * 1651 * For the last iteration, we need to de-commit the latter half before 1652 * proceeding with the test. 1653 */ 1654 const bool all_pages_committed = (n_iteration == 0); 1655 1656 if (!all_pages_committed) 1657 { 1658 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 1659 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1660 1661 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded / 2, /* offset */ 1662 m_sparse_bo_size_rounded / 2, /* size */ 1663 GL_TRUE); /* commit */ 1664 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 1665 } 1666 1667 /* Set up the sparse buffer contents */ 1668 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo); 1669 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1670 1671 m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */ 1672 m_sparse_bo_size_rounded, m_initial_data); 1673 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed."); 1674 1675 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 1676 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo); 1677 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 1678 1679 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, /* readTarget */ 1680 GL_COPY_WRITE_BUFFER, /* writeTarget */ 1681 0, /* readOffset */ 1682 0, /* writeOffset */ 1683 m_sparse_bo_size_rounded); 1684 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 1685 1686 /* Issue the clear call */ 1687 unsigned int clear_region_size = 0; 1688 unsigned int clear_region_start_offset = 0; 1689 1690 if (use_clear_buffer_data_call) 1691 { 1692 DE_ASSERT((m_sparse_bo_size_rounded % sizeof(unsigned int)) == 0); 1693 1694 clear_region_size = m_sparse_bo_size_rounded; 1695 clear_region_start_offset = 0; 1696 1697 m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &data_rgba8); 1698 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed."); 1699 } 1700 else 1701 { 1702 DE_ASSERT(((m_sparse_bo_size_rounded / 2) % sizeof(unsigned int)) == 0); 1703 DE_ASSERT(((m_sparse_bo_size_rounded) % sizeof(unsigned int)) == 0); 1704 1705 clear_region_size = m_sparse_bo_size_rounded / 2; 1706 clear_region_start_offset = m_sparse_bo_size_rounded / 2; 1707 1708 m_gl.clearBufferSubData(GL_COPY_WRITE_BUFFER, GL_RGBA8, clear_region_start_offset, clear_region_size, 1709 GL_RGBA, GL_UNSIGNED_BYTE, &data_rgba8); 1710 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferSubData() call failed."); 1711 } 1712 1713 /* Retrieve the modified buffer's contents */ 1714 const unsigned char* result_data = NULL; 1715 1716 m_gl.copyBufferSubData(GL_COPY_WRITE_BUFFER, /* readTarget */ 1717 GL_COPY_READ_BUFFER, /* writeTarget */ 1718 0, /* readOffset */ 1719 0, /* writeOffset */ 1720 m_sparse_bo_size_rounded); 1721 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 1722 1723 result_data = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */ 1724 m_sparse_bo_size_rounded, GL_MAP_READ_BIT); 1725 1726 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed."); 1727 1728 /* Verify the result data: unmodified region */ 1729 bool result_local = true; 1730 const unsigned int unmodified_region_size = (use_clear_buffer_data_call) ? 0 : clear_region_start_offset; 1731 const unsigned int unmodified_region_start_offset = 0; 1732 1733 for (unsigned int n_current_byte = unmodified_region_start_offset; 1734 (n_current_byte < unmodified_region_start_offset + unmodified_region_size) && result_local; 1735 ++n_current_byte) 1736 { 1737 const unsigned int current_initial_data_offset = n_current_byte - unmodified_region_start_offset; 1738 const unsigned char expected_value = m_initial_data[current_initial_data_offset]; 1739 const unsigned char found_value = result_data[n_current_byte]; 1740 1741 if (expected_value != found_value) 1742 { 1743 m_testCtx.getLog() << tcu::TestLog::Message 1744 << "Unmodified buffer object region has invalid contents. Expected byte " 1745 << "[" << (int)expected_value << "]" 1746 ", found byte:" 1747 "[" 1748 << (int)found_value << "]" 1749 " at index " 1750 "[" 1751 << n_current_byte << "]; " 1752 "call type:" 1753 "[" 1754 << ((use_clear_buffer_data_call) ? "glClearBufferData()" : 1755 "glClearBufferSubData()") 1756 << "]" 1757 ", all required pages committed?:" 1758 "[" 1759 << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage; 1760 1761 result_local = false; 1762 break; 1763 } 1764 } 1765 1766 result &= result_local; 1767 result_local = true; 1768 1769 /* Verify the result data: modified region (clamped to the memory region 1770 * with actual physical backing) */ 1771 const unsigned int modified_region_size = (all_pages_committed) ? clear_region_size : 0; 1772 const unsigned int modified_region_start_offset = clear_region_start_offset; 1773 1774 for (unsigned int n_current_byte = modified_region_start_offset; 1775 (n_current_byte < modified_region_start_offset + modified_region_size) && result_local; 1776 ++n_current_byte) 1777 { 1778 const unsigned char expected_value = 1779 static_cast<unsigned char>((data_rgba8 & (0xFF << (n_current_byte * 8))) >> (n_current_byte * 8)); 1780 const unsigned char found_value = result_data[n_current_byte]; 1781 1782 if (expected_value != found_value) 1783 { 1784 m_testCtx.getLog() << tcu::TestLog::Message 1785 << "Unmodified buffer object region has invalid contents. Expected byte " 1786 << "[" << (int)expected_value << "]" 1787 ", found byte:" 1788 "[" 1789 << (int)found_value << "]" 1790 " at index " 1791 "[" 1792 << n_current_byte << "]; " 1793 "call type:" 1794 "[" 1795 << ((use_clear_buffer_data_call) ? "glClearBufferData()" : 1796 "glClearBufferSubData()") 1797 << "]" 1798 ", all required pages committed?:" 1799 "[" 1800 << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage; 1801 1802 result_local = false; 1803 break; 1804 } 1805 } 1806 1807 result &= result_local; 1808 1809 /* Unmap the storage before proceeding */ 1810 m_gl.unmapBuffer(GL_COPY_READ_BUFFER); 1811 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 1812 } /* for (both iterations) */ 1813 } /* for (both clear types) */ 1814 1815 return result; 1816 } 1817 1818 /** Initializes GL objects used across all test case iterations. 1819 * 1820 * Called once during BufferStorage test run-time. 1821 */ 1822 bool ClearOpsBufferStorageTestCase::initTestCaseGlobal() 1823 { 1824 unsigned int n_bytes_filled = 0; 1825 const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size; 1826 1827 /* Determine the number of bytes both the helper and the sparse buffer 1828 * object need to be able to hold, at maximum */ 1829 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size); 1830 1831 /* Set up the helper BO */ 1832 DE_ASSERT(m_helper_bo == 0); 1833 1834 m_gl.genBuffers(1, &m_helper_bo); 1835 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 1836 1837 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 1838 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1839 1840 m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_size_rounded, DE_NULL, 1841 GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT); /* flags */ 1842 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 1843 1844 /* Set up a client-side data buffer we will use to fill the sparse BO with data, 1845 * to be later cleared with the clear ops */ 1846 DE_ASSERT(m_initial_data == DE_NULL); 1847 1848 m_initial_data = new unsigned char[m_sparse_bo_size_rounded]; 1849 1850 while (n_bytes_filled < m_sparse_bo_size_rounded) 1851 { 1852 m_initial_data[n_bytes_filled] = static_cast<unsigned char>(n_bytes_filled % 256); 1853 1854 ++n_bytes_filled; 1855 } 1856 1857 return true; 1858 } 1859 1860 /** Initializes GL objects which are needed for a single test case iteration. 1861 * 1862 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 1863 * to release these objects. 1864 **/ 1865 bool ClearOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 1866 { 1867 bool result = true; 1868 1869 /* Cache the BO id, if not cached already */ 1870 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 1871 1872 m_sparse_bo = sparse_bo; 1873 1874 /* Set up the sparse bufffer. */ 1875 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 1876 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1877 1878 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 1879 m_sparse_bo_size_rounded, GL_TRUE); /* commit */ 1880 1881 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 1882 1883 return result; 1884 } 1885 1886 /** Constructor. 1887 * 1888 * @param gl GL entry-points container 1889 * @param testContext CTS test context 1890 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 1891 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 1892 */ 1893 CopyOpsBufferStorageTestCase::CopyOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, 1894 glw::GLint page_size) 1895 : m_gl(gl) 1896 , m_helper_bo(0) 1897 , m_immutable_bo(0) 1898 , m_page_size(page_size) 1899 , m_sparse_bo_size(0) 1900 , m_sparse_bo_size_rounded(0) 1901 , m_testCtx(testContext) 1902 { 1903 m_ref_data[0] = DE_NULL; 1904 m_ref_data[1] = DE_NULL; 1905 m_ref_data[2] = DE_NULL; 1906 m_sparse_bos[0] = 0; 1907 m_sparse_bos[1] = 0; 1908 } 1909 1910 /** Releases all GL objects used across all test case iterations. 1911 * 1912 * Called once during BufferStorage test run-time. 1913 */ 1914 1915 void CopyOpsBufferStorageTestCase::deinitTestCaseGlobal() 1916 { 1917 if (m_helper_bo != 0) 1918 { 1919 m_gl.deleteBuffers(1, &m_helper_bo); 1920 1921 m_helper_bo = 0; 1922 } 1923 1924 if (m_immutable_bo != 0) 1925 { 1926 m_gl.deleteBuffers(1, &m_immutable_bo); 1927 1928 m_immutable_bo = 0; 1929 } 1930 1931 for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]); 1932 ++n_ref_data_buffer) 1933 { 1934 if (m_ref_data[n_ref_data_buffer] != DE_NULL) 1935 { 1936 delete[] m_ref_data[n_ref_data_buffer]; 1937 1938 m_ref_data[n_ref_data_buffer] = DE_NULL; 1939 } 1940 } 1941 1942 /* Only release the test case-owned BO */ 1943 if (m_sparse_bos[1] != 0) 1944 { 1945 m_gl.deleteBuffers(1, m_sparse_bos + 1); 1946 1947 m_sparse_bos[1] = 0; 1948 } 1949 } 1950 1951 /** Releases temporary GL objects, created specifically for one test case iteration. */ 1952 void CopyOpsBufferStorageTestCase::deinitTestCaseIteration() 1953 { 1954 for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo) 1955 { 1956 const glw::GLuint sparse_bo_id = m_sparse_bos[n_sparse_bo]; 1957 1958 if (sparse_bo_id != 0) 1959 { 1960 m_gl.bindBuffer(GL_ARRAY_BUFFER, sparse_bo_id); 1961 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 1962 1963 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 1964 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 1965 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 1966 } /* if (sparse_bo_id != 0) */ 1967 } /* for (both BOs) */ 1968 } 1969 1970 /** Executes a single test iteration. The BufferStorage test will call this method 1971 * numerously during its life-time, testing various valid flag combinations applied 1972 * to the tested sparse buffer object at glBufferStorage() call time. 1973 * 1974 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 1975 * call to set up the sparse buffer's storage. 1976 * 1977 * @return true if the test case executed correctly, false otherwise. 1978 */ 1979 bool CopyOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 1980 { 1981 (void)sparse_bo_storage_flags; 1982 bool result = true; 1983 1984 /* Iterate over all test cases */ 1985 DE_ASSERT(m_immutable_bo != 0); 1986 DE_ASSERT(m_sparse_bos[0] != 0); 1987 DE_ASSERT(m_sparse_bos[1] != 0); 1988 1989 for (_test_cases_const_iterator test_iterator = m_test_cases.begin(); test_iterator != m_test_cases.end(); 1990 ++test_iterator) 1991 { 1992 bool result_local = true; 1993 const _test_case& test_case = *test_iterator; 1994 const glw::GLuint dst_bo_id = 1995 test_case.dst_bo_is_sparse ? m_sparse_bos[test_case.dst_bo_sparse_id] : m_immutable_bo; 1996 const glw::GLuint src_bo_id = 1997 test_case.src_bo_is_sparse ? m_sparse_bos[test_case.src_bo_sparse_id] : m_immutable_bo; 1998 1999 /* Initialize immutable BO data (if used) */ 2000 if (dst_bo_id == m_immutable_bo || src_bo_id == m_immutable_bo) 2001 { 2002 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_immutable_bo); 2003 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2004 2005 m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */ 2006 m_sparse_bo_size_rounded, m_ref_data[0]); 2007 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed."); 2008 } 2009 2010 /* Initialize sparse BO data storage */ 2011 for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo) 2012 { 2013 const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]); 2014 const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]); 2015 2016 if (!is_dst_bo && !is_src_bo) 2017 continue; 2018 2019 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 2020 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bos[n_sparse_bo]); 2021 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 2022 2023 if (is_dst_bo) 2024 { 2025 m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.dst_bo_commit_start_offset, 2026 test_case.dst_bo_commit_size, GL_TRUE); /* commit */ 2027 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 2028 } 2029 2030 if (is_src_bo) 2031 { 2032 m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.src_bo_commit_start_offset, 2033 test_case.src_bo_commit_size, GL_TRUE); /* commit */ 2034 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 2035 } 2036 2037 m_gl.bufferSubData(GL_COPY_READ_BUFFER, 0, /* offset */ 2038 m_sparse_bo_size_rounded, m_ref_data[1 + n_sparse_bo]); 2039 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed."); 2040 2041 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 2042 0, /* writeOffset */ 2043 m_sparse_bo_size_rounded); 2044 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 2045 } /* for (both sparse BOs) */ 2046 2047 /* Set up the bindings */ 2048 m_gl.bindBuffer(GL_COPY_READ_BUFFER, src_bo_id); 2049 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, dst_bo_id); 2050 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2051 2052 /* Issue the copy op */ 2053 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, test_case.src_bo_start_offset, 2054 test_case.dst_bo_start_offset, test_case.n_bytes_to_copy); 2055 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 2056 2057 /* Retrieve the destination buffer's contents. The BO used for the previous copy op might have 2058 * been a sparse BO, so copy its storage to a helper immutable BO */ 2059 const unsigned short* dst_bo_data_ptr = NULL; 2060 2061 m_gl.bindBuffer(GL_COPY_READ_BUFFER, dst_bo_id); 2062 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo); 2063 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2064 2065 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 2066 0, /* writeOffset */ 2067 m_sparse_bo_size_rounded); 2068 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 2069 2070 dst_bo_data_ptr = (const unsigned short*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */ 2071 m_sparse_bo_size_rounded, GL_MAP_READ_BIT); 2072 2073 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed."); 2074 2075 /* Verify the retrieved data: 2076 * 2077 * 1. Check the bytes which precede the copy op dst offset. These should be equal to 2078 * the destination buffer's reference data within the committed memory region. 2079 **/ 2080 if (test_case.dst_bo_start_offset != 0 && test_case.dst_bo_commit_start_offset < test_case.dst_bo_start_offset) 2081 { 2082 DE_ASSERT(((test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) % sizeof(short)) == 0); 2083 2084 const unsigned int n_valid_values = static_cast<unsigned int>( 2085 (test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) / sizeof(short)); 2086 2087 for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value) 2088 { 2089 const int dst_data_offset = static_cast<int>(sizeof(short) * n_value); 2090 2091 if (dst_data_offset >= test_case.dst_bo_commit_start_offset && 2092 dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size) 2093 { 2094 const unsigned short expected_short_value = 2095 *(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset); 2096 const unsigned short found_short_value = 2097 *(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset); 2098 2099 if (expected_short_value != found_short_value) 2100 { 2101 m_testCtx.getLog() 2102 << tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, " 2103 "preceding the region modified by the copy op. " 2104 << "Destination BO id:" << dst_bo_id << " (" 2105 << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)") 2106 << ", commited region: " << test_case.dst_bo_commit_start_offset << ":" 2107 << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size) 2108 << ", copy region: " << test_case.dst_bo_start_offset << ":" 2109 << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy) 2110 << ". Source BO id:" << src_bo_id << " (" 2111 << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)") 2112 << ", commited region: " << test_case.src_bo_commit_start_offset << ":" 2113 << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size) 2114 << ", copy region: " << test_case.src_bo_start_offset << ":" 2115 << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of " 2116 << expected_short_value << ", found value of " << found_short_value 2117 << " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage; 2118 2119 result_local = false; 2120 } 2121 } 2122 } /* for (all preceding values which should not have been affected by the copy op) */ 2123 } /* if (copy op did not modify the beginning of the destination buffer storage) */ 2124 2125 /* 2. Check if the data written to the destination buffer object is correct. */ 2126 for (unsigned int n_copied_short_value = 0; 2127 n_copied_short_value < test_case.n_bytes_to_copy / sizeof(short) && result_local; ++n_copied_short_value) 2128 { 2129 const int src_data_offset = 2130 static_cast<unsigned int>(test_case.src_bo_start_offset + sizeof(short) * n_copied_short_value); 2131 const int dst_data_offset = 2132 static_cast<unsigned int>(test_case.dst_bo_start_offset + sizeof(short) * n_copied_short_value); 2133 2134 if (dst_data_offset >= test_case.dst_bo_commit_start_offset && 2135 dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size && 2136 src_data_offset >= test_case.src_bo_commit_start_offset && 2137 src_data_offset < test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size) 2138 { 2139 const unsigned short expected_short_value = 2140 *(unsigned short*)((unsigned char*)test_case.src_bo_ref_data + src_data_offset); 2141 const unsigned short found_short_value = 2142 *(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset); 2143 2144 if (expected_short_value != found_short_value) 2145 { 2146 m_testCtx.getLog() << tcu::TestLog::Message 2147 << "Malformed data found in the copy op's destination BO. " 2148 << "Destination BO id:" << dst_bo_id << " (" 2149 << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)") 2150 << ", commited region: " << test_case.dst_bo_commit_start_offset << ":" 2151 << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size) 2152 << ", copy region: " << test_case.dst_bo_start_offset << ":" 2153 << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy) 2154 << ". Source BO id:" << src_bo_id << " (" 2155 << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)") 2156 << ", commited region: " << test_case.src_bo_commit_start_offset << ":" 2157 << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size) 2158 << ", copy region: " << test_case.src_bo_start_offset << ":" 2159 << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) 2160 << ". Expected value of " << expected_short_value << ", found value of " 2161 << found_short_value << " at dst data offset of " << dst_data_offset << "." 2162 << tcu::TestLog::EndMessage; 2163 2164 result_local = false; 2165 } 2166 } 2167 } 2168 2169 /* 3. Verify the remaining data in the committed part of the destination buffer object is left intact. */ 2170 const unsigned int commit_region_end_offset = 2171 test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size; 2172 const unsigned int copy_region_end_offset = test_case.dst_bo_start_offset + test_case.n_bytes_to_copy; 2173 2174 if (commit_region_end_offset > copy_region_end_offset) 2175 { 2176 DE_ASSERT(((commit_region_end_offset - copy_region_end_offset) % sizeof(short)) == 0); 2177 2178 const unsigned int n_valid_values = 2179 static_cast<unsigned int>((commit_region_end_offset - copy_region_end_offset) / sizeof(short)); 2180 2181 for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value) 2182 { 2183 const int dst_data_offset = static_cast<int>(copy_region_end_offset + sizeof(short) * n_value); 2184 2185 if (dst_data_offset >= test_case.dst_bo_commit_start_offset && 2186 dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size) 2187 { 2188 const unsigned short expected_short_value = 2189 *(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset); 2190 const unsigned short found_short_value = 2191 *(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset); 2192 2193 if (expected_short_value != found_short_value) 2194 { 2195 m_testCtx.getLog() 2196 << tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, " 2197 "following the region modified by the copy op. " 2198 << "Destination BO id:" << dst_bo_id << " (" 2199 << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)") 2200 << ", commited region: " << test_case.dst_bo_commit_start_offset << ":" 2201 << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size) 2202 << ", copy region: " << test_case.dst_bo_start_offset << ":" 2203 << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy) 2204 << ". Source BO id:" << src_bo_id << " (" 2205 << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)") 2206 << ", commited region: " << test_case.src_bo_commit_start_offset << ":" 2207 << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size) 2208 << ", copy region: " << test_case.src_bo_start_offset << ":" 2209 << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of " 2210 << expected_short_value << ", found value of " << found_short_value 2211 << " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage; 2212 2213 result_local = false; 2214 } 2215 } 2216 } /* for (all preceding values which should not have been affected by the copy op) */ 2217 } /* if (copy op did not modify the beginning of the destination buffer storage) */ 2218 2219 /* Unmap the buffer storage */ 2220 m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER); 2221 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 2222 2223 /* Clean up */ 2224 for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo) 2225 { 2226 const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]); 2227 const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]); 2228 2229 if (is_dst_bo || is_src_bo) 2230 { 2231 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[n_sparse_bo]); 2232 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2233 2234 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 2235 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 2236 } 2237 } 2238 2239 result &= result_local; 2240 } /* for (all test cases) */ 2241 2242 return result; 2243 } 2244 2245 /** Allocates reference buffers, fills them with data and updates the m_ref_data array. */ 2246 void CopyOpsBufferStorageTestCase::initReferenceData() 2247 { 2248 DE_ASSERT(m_sparse_bo_size_rounded != 0); 2249 DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0); 2250 DE_ASSERT(sizeof(short) == 2); 2251 2252 for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]); 2253 ++n_ref_data_buffer) 2254 { 2255 DE_ASSERT(m_ref_data[n_ref_data_buffer] == DE_NULL); 2256 2257 m_ref_data[n_ref_data_buffer] = new unsigned short[m_sparse_bo_size_rounded / 2]; 2258 2259 /* Write reference values. */ 2260 for (unsigned int n_short_value = 0; n_short_value < m_sparse_bo_size_rounded / 2; ++n_short_value) 2261 { 2262 m_ref_data[n_ref_data_buffer][n_short_value] = 2263 (unsigned short)((n_ref_data_buffer + 1) * (n_short_value + 1)); 2264 } 2265 } /* for (all reference data buffers) */ 2266 } 2267 2268 /** Initializes GL objects used across all test case iterations. 2269 * 2270 * Called once during BufferStorage test run-time. 2271 */ 2272 bool CopyOpsBufferStorageTestCase::initTestCaseGlobal() 2273 { 2274 m_sparse_bo_size = 2 * 3 * 4 * m_page_size; 2275 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size); 2276 2277 initReferenceData(); 2278 2279 /* Initialize the sparse buffer object */ 2280 m_gl.genBuffers(1, m_sparse_bos + 1); 2281 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 2282 2283 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[1]); 2284 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2285 2286 m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, DE_NULL, /* data */ 2287 GL_SPARSE_STORAGE_BIT_ARB); 2288 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 2289 2290 /* Initialize the immutable buffer objects used by the test */ 2291 for (unsigned int n_bo = 0; n_bo < 2; /* helper + immutable BO used for the copy ops */ 2292 ++n_bo) 2293 { 2294 glw::GLuint* bo_id_ptr = (n_bo == 0) ? &m_helper_bo : &m_immutable_bo; 2295 glw::GLenum flags = GL_DYNAMIC_STORAGE_BIT; 2296 2297 if (n_bo == 0) 2298 { 2299 flags |= GL_MAP_READ_BIT; 2300 } 2301 2302 /* Initialize the immutable buffer object */ 2303 m_gl.genBuffers(1, bo_id_ptr); 2304 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 2305 2306 m_gl.bindBuffer(GL_ARRAY_BUFFER, *bo_id_ptr); 2307 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2308 2309 m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, m_ref_data[0], flags); 2310 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 2311 } 2312 2313 return true; 2314 } 2315 2316 /** Initializes GL objects which are needed for a single test case iteration. 2317 * 2318 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 2319 * to release these objects. 2320 **/ 2321 bool CopyOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 2322 { 2323 bool result = true; 2324 2325 /* Remember the BO id */ 2326 m_sparse_bos[0] = sparse_bo; 2327 2328 /* Initialize test cases, if this is the first call to initTestCaseIteration() */ 2329 if (m_test_cases.size() == 0) 2330 { 2331 initTestCases(); 2332 } 2333 2334 /* Make sure all pages of the provided sparse BO are de-committed before 2335 * ::execute() is called. */ 2336 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[0]); 2337 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2338 2339 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 2340 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 2341 2342 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 2343 2344 return result; 2345 } 2346 2347 /** Fills m_test_cases with test case descriptors. Each such descriptor defines 2348 * a single copy op use case. 2349 * 2350 * The descriptors are then iterated over in ::execute(), defining the testing 2351 * behavior of the test copy ops buffer storage test case. 2352 */ 2353 void CopyOpsBufferStorageTestCase::initTestCases() 2354 { 2355 /* We need to use the following destination & source BO configurations: 2356 * 2357 * Dst: sparse BO 1; Src: sparse BO 2 2358 * Dst: sparse BO 1; Src: immutable BO 2359 * Dst: immutable BO; Src: sparse BO 1 2360 * Dst: sparse BO 1; Src: sparse BO 1 2361 */ 2362 unsigned int n_test_case = 0; 2363 2364 for (unsigned int n_bo_configuration = 0; n_bo_configuration < 4; /* as per the comment */ 2365 ++n_bo_configuration, ++n_test_case) 2366 { 2367 glw::GLuint dst_bo_sparse_id = 0; 2368 bool dst_bo_is_sparse = false; 2369 unsigned short* dst_bo_ref_data = DE_NULL; 2370 glw::GLuint src_bo_sparse_id = 0; 2371 bool src_bo_is_sparse = false; 2372 unsigned short* src_bo_ref_data = DE_NULL; 2373 2374 switch (n_bo_configuration) 2375 { 2376 case 0: 2377 { 2378 dst_bo_sparse_id = 0; 2379 dst_bo_is_sparse = true; 2380 dst_bo_ref_data = m_ref_data[1]; 2381 src_bo_sparse_id = 1; 2382 src_bo_is_sparse = true; 2383 src_bo_ref_data = m_ref_data[2]; 2384 2385 break; 2386 } 2387 2388 case 1: 2389 { 2390 dst_bo_sparse_id = 0; 2391 dst_bo_is_sparse = true; 2392 dst_bo_ref_data = m_ref_data[1]; 2393 src_bo_is_sparse = false; 2394 src_bo_ref_data = m_ref_data[0]; 2395 2396 break; 2397 } 2398 2399 case 2: 2400 { 2401 dst_bo_is_sparse = false; 2402 dst_bo_ref_data = m_ref_data[0]; 2403 src_bo_sparse_id = 0; 2404 src_bo_is_sparse = true; 2405 src_bo_ref_data = m_ref_data[1]; 2406 2407 break; 2408 } 2409 2410 case 3: 2411 { 2412 dst_bo_sparse_id = 0; 2413 dst_bo_is_sparse = true; 2414 dst_bo_ref_data = m_ref_data[1]; 2415 src_bo_sparse_id = 0; 2416 src_bo_is_sparse = true; 2417 src_bo_ref_data = m_ref_data[1]; 2418 2419 break; 2420 } 2421 2422 default: 2423 { 2424 TCU_FAIL("Invalid BO configuration index"); 2425 } 2426 } /* switch (n_bo_configuration) */ 2427 2428 /* Need to test the copy operation in three different scenarios, 2429 * in regard to the destination buffer: 2430 * 2431 * a) All pages of the destination region are committed. 2432 * b) Half of the pages of the destination region are committed. 2433 * c) None of the pages of the destination region are committed. 2434 * 2435 * Destination region spans from 0 to half of the memory we use 2436 * for the testing purposes. 2437 */ 2438 DE_ASSERT((m_sparse_bo_size_rounded % m_page_size) == 0); 2439 DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0); 2440 DE_ASSERT((m_sparse_bo_size_rounded % 4) == 0); 2441 2442 for (unsigned int n_dst_region = 0; n_dst_region < 3; /* as per the comment */ 2443 ++n_dst_region) 2444 { 2445 glw::GLuint dst_bo_commit_size = 0; 2446 glw::GLuint dst_bo_commit_start_offset = 0; 2447 2448 switch (n_dst_region) 2449 { 2450 case 0: 2451 { 2452 dst_bo_commit_start_offset = 0; 2453 dst_bo_commit_size = m_sparse_bo_size_rounded / 2; 2454 2455 break; 2456 } 2457 2458 case 1: 2459 { 2460 dst_bo_commit_start_offset = m_sparse_bo_size_rounded / 4; 2461 dst_bo_commit_size = m_sparse_bo_size_rounded / 4; 2462 2463 break; 2464 } 2465 2466 case 2: 2467 { 2468 dst_bo_commit_start_offset = 0; 2469 dst_bo_commit_size = 0; 2470 2471 break; 2472 } 2473 2474 default: 2475 { 2476 TCU_FAIL("Invalid destination region configuration index"); 2477 } 2478 } /* switch (n_dst_region) */ 2479 2480 /* Same goes for the source region. 2481 * 2482 * Source region spans from m_sparse_bo_size_rounded / 2 to 2483 * m_sparse_bo_size_rounded. 2484 * 2485 **/ 2486 for (unsigned int n_src_region = 0; n_src_region < 3; /* as per the comment */ 2487 ++n_src_region) 2488 { 2489 glw::GLuint src_bo_commit_size = 0; 2490 glw::GLuint src_bo_commit_start_offset = 0; 2491 2492 switch (n_src_region) 2493 { 2494 case 0: 2495 { 2496 src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2; 2497 src_bo_commit_size = m_sparse_bo_size_rounded / 2; 2498 2499 break; 2500 } 2501 2502 case 1: 2503 { 2504 src_bo_commit_start_offset = 3 * m_sparse_bo_size_rounded / 4; 2505 src_bo_commit_size = m_sparse_bo_size_rounded / 4; 2506 2507 break; 2508 } 2509 2510 case 2: 2511 { 2512 src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2; 2513 src_bo_commit_size = 0; 2514 2515 break; 2516 } 2517 2518 default: 2519 { 2520 TCU_FAIL("Invalid source region configuration index"); 2521 } 2522 } /* switch (n_src_region) */ 2523 2524 /* Initialize the test case descriptor */ 2525 _test_case test_case; 2526 2527 test_case.dst_bo_commit_size = dst_bo_commit_size; 2528 test_case.dst_bo_commit_start_offset = dst_bo_commit_start_offset; 2529 test_case.dst_bo_sparse_id = dst_bo_sparse_id; 2530 test_case.dst_bo_is_sparse = dst_bo_is_sparse; 2531 test_case.dst_bo_ref_data = dst_bo_ref_data; 2532 test_case.dst_bo_start_offset = static_cast<glw::GLint>(sizeof(short) * n_test_case); 2533 test_case.n_bytes_to_copy = static_cast<glw::GLint>( 2534 m_sparse_bo_size_rounded / 2 - test_case.dst_bo_start_offset - sizeof(short) * n_test_case); 2535 test_case.src_bo_commit_size = src_bo_commit_size; 2536 test_case.src_bo_commit_start_offset = src_bo_commit_start_offset; 2537 test_case.src_bo_sparse_id = src_bo_sparse_id; 2538 test_case.src_bo_is_sparse = src_bo_is_sparse; 2539 test_case.src_bo_ref_data = src_bo_ref_data; 2540 test_case.src_bo_start_offset = m_sparse_bo_size_rounded / 2; 2541 2542 DE_ASSERT(test_case.dst_bo_commit_size >= 0); 2543 DE_ASSERT(test_case.dst_bo_commit_start_offset >= 0); 2544 DE_ASSERT(test_case.dst_bo_ref_data != DE_NULL); 2545 DE_ASSERT(test_case.dst_bo_start_offset >= 0); 2546 DE_ASSERT(test_case.n_bytes_to_copy >= 0); 2547 DE_ASSERT(test_case.src_bo_commit_size >= 0); 2548 DE_ASSERT(test_case.src_bo_commit_start_offset >= 0); 2549 DE_ASSERT(test_case.src_bo_ref_data != DE_NULL); 2550 DE_ASSERT(test_case.src_bo_start_offset >= 0); 2551 2552 m_test_cases.push_back(test_case); 2553 } /* for (all source region commit configurations) */ 2554 } /* for (all destination region commit configurations) */ 2555 } /* for (all BO configurations which need to be tested) */ 2556 } 2557 2558 /** Constructor. 2559 * 2560 * @param gl GL entry-points container 2561 * @param testContext CTS test context 2562 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 2563 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 2564 */ 2565 IndirectDispatchBufferStorageTestCase::IndirectDispatchBufferStorageTestCase(const glw::Functions& gl, 2566 tcu::TestContext& testContext, 2567 glw::GLint page_size) 2568 : m_dispatch_draw_call_args_start_offset(-1) 2569 , m_expected_ac_value(0) 2570 , m_gl(gl) 2571 , m_global_wg_size_x(2048) 2572 , m_helper_bo(0) 2573 , m_local_wg_size_x(1023) /* must stay in sync with the local work-groups's size hardcoded in m_po's body! */ 2574 , m_page_size(page_size) 2575 , m_po(0) 2576 , m_sparse_bo(0) 2577 , m_sparse_bo_size(0) 2578 , m_sparse_bo_size_rounded(0) 2579 , m_testCtx(testContext) 2580 { 2581 /* Left blank intentionally */ 2582 } 2583 2584 /** Releases all GL objects used across all test case iterations. 2585 * 2586 * Called once during BufferStorage test run-time. 2587 */ 2588 void IndirectDispatchBufferStorageTestCase::deinitTestCaseGlobal() 2589 { 2590 if (m_helper_bo != 0) 2591 { 2592 m_gl.deleteBuffers(1, &m_helper_bo); 2593 2594 m_helper_bo = 0; 2595 } 2596 2597 if (m_po != 0) 2598 { 2599 m_gl.deleteProgram(m_po); 2600 2601 m_po = 0; 2602 } 2603 } 2604 2605 /** Releases temporary GL objects, created specifically for one test case iteration. */ 2606 void IndirectDispatchBufferStorageTestCase::deinitTestCaseIteration() 2607 { 2608 if (m_sparse_bo != 0) 2609 { 2610 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 2611 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2612 2613 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 2614 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 2615 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 2616 2617 m_sparse_bo = 0; 2618 } 2619 } 2620 2621 /** Executes a single test iteration. The BufferStorage test will call this method 2622 * numerously during its life-time, testing various valid flag combinations applied 2623 * to the tested sparse buffer object at glBufferStorage() call time. 2624 * 2625 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 2626 * call to set up the sparse buffer's storage. 2627 * 2628 * @return true if the test case executed correctly, false otherwise. 2629 */ 2630 bool IndirectDispatchBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 2631 { 2632 (void)sparse_bo_storage_flags; 2633 bool result = true; 2634 2635 /* Set up the buffer bindings */ 2636 m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_helper_bo); 2637 m_gl.bindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_sparse_bo); 2638 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed"); 2639 2640 m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */ 2641 m_helper_bo, 12, /* offset */ 2642 4); /* size */ 2643 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed."); 2644 2645 /* Bind the compute program */ 2646 m_gl.useProgram(m_po); 2647 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 2648 2649 /* Zero out atomic counter value. */ 2650 const unsigned int zero_ac_value = 0; 2651 2652 m_gl.bufferSubData(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */ 2653 4, /* size */ 2654 &zero_ac_value); 2655 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed."); 2656 2657 m_expected_ac_value = zero_ac_value; 2658 2659 /* Run the test only in a configuration where all arguments are local in 2660 * committed memory page(s): reading arguments from uncommitted pages means 2661 * reading undefined data, which can result in huge dispatches that 2662 * effectively hang the test. 2663 */ 2664 m_gl.bufferPageCommitmentARB(GL_DISPATCH_INDIRECT_BUFFER, 0, /* offset */ 2665 m_sparse_bo_size_rounded, GL_TRUE); /* commit */ 2666 2667 m_expected_ac_value += m_global_wg_size_x * m_local_wg_size_x; 2668 2669 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed."); 2670 2671 /* Copy the indirect dispatch call args data from the helper BO to the sparse BO */ 2672 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 2673 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo); 2674 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2675 2676 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 2677 m_dispatch_draw_call_args_start_offset, sizeof(unsigned int) * 3); 2678 2679 /* Run the program */ 2680 m_gl.dispatchComputeIndirect(m_dispatch_draw_call_args_start_offset); 2681 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchComputeIndirect() call failed."); 2682 2683 /* Extract the AC value and verify it */ 2684 const unsigned int* ac_data_ptr = 2685 (const unsigned int*)m_gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */ 2686 4, /* length */ 2687 GL_MAP_READ_BIT); 2688 2689 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed."); 2690 2691 if (*ac_data_ptr != m_expected_ac_value && result) 2692 { 2693 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value encountered. " 2694 "Expected value: [" 2695 << m_expected_ac_value << "]" 2696 ", found:" 2697 "[" 2698 << *ac_data_ptr << "]." << tcu::TestLog::EndMessage; 2699 2700 result = false; 2701 } 2702 2703 /* Unmap the buffer before we move on with the next iteration */ 2704 m_gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); 2705 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 2706 2707 return result; 2708 } 2709 2710 /** Initializes GL objects used across all test case iterations. 2711 * 2712 * Called once during BufferStorage test run-time. 2713 */ 2714 bool IndirectDispatchBufferStorageTestCase::initTestCaseGlobal() 2715 { 2716 bool result = true; 2717 2718 /* One of the cases the test case implementation needs to support is the scenario 2719 * where the indirect call arguments are located on the boundary of two (or more) memory pages, 2720 * and some of the pages are not committed. 2721 * 2722 * There are two scenarios which can happen: 2723 * 2724 * a) page size >= sizeof(uint) * 3: Allocate two pages, arg start offset: (page_size - 4) aligned to 4. 2725 * The alignment is a must, since we'll be feeding the offset to an indirect dispatch call. 2726 * b) page size < sizeof(uint) * 3: Allocate as many pages as needed, disable some of the pages. 2727 * 2728 * For code clarity, the two cases are handled by separate branches, although they could be easily 2729 * merged. 2730 */ 2731 const int n_indirect_dispatch_call_arg_bytes = sizeof(unsigned int) * 3; 2732 2733 if (m_page_size >= n_indirect_dispatch_call_arg_bytes) 2734 { 2735 /* Indirect dispatch call args must be aligned to 4 */ 2736 DE_ASSERT(m_page_size >= 4); 2737 2738 m_dispatch_draw_call_args_start_offset = SparseBufferTestUtilities::alignOffset(m_page_size - 4, 4); 2739 m_sparse_bo_size = m_dispatch_draw_call_args_start_offset + n_indirect_dispatch_call_arg_bytes; 2740 } 2741 else 2742 { 2743 m_dispatch_draw_call_args_start_offset = 0; 2744 m_sparse_bo_size = n_indirect_dispatch_call_arg_bytes; 2745 } 2746 2747 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size); 2748 2749 /* Set up the helper buffer object. Its structure is as follows: 2750 * 2751 * [ 0-11]: Indirect dispatch call args 2752 * [12-15]: Atomic counter value storage 2753 */ 2754 unsigned int helper_bo_data[4] = { 0 }; 2755 const unsigned int n_helper_bo_bytes = sizeof(helper_bo_data); 2756 2757 helper_bo_data[0] = m_global_wg_size_x; /* num_groups_x */ 2758 helper_bo_data[1] = 1; /* num_groups_y */ 2759 helper_bo_data[2] = 1; /* num_groups_z */ 2760 helper_bo_data[3] = 0; /* default atomic counter value */ 2761 2762 m_gl.genBuffers(1, &m_helper_bo); 2763 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 2764 2765 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo); 2766 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2767 2768 m_gl.bufferData(GL_ARRAY_BUFFER, n_helper_bo_bytes, helper_bo_data, GL_STATIC_DRAW); 2769 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed."); 2770 2771 /* Set up the test compute program object */ 2772 static const char* cs_body = "#version 430 core\n" 2773 "\n" 2774 "layout(local_size_x = 1023) in;\n" 2775 "layout(binding = 0, offset = 0) uniform atomic_uint ac;\n" 2776 "\n" 2777 "void main()\n" 2778 "{\n" 2779 " atomicCounterIncrement(ac);\n" 2780 "}\n"; 2781 2782 m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */ 2783 2784 result = (m_po != 0); 2785 2786 return result; 2787 } 2788 2789 /** Initializes GL objects which are needed for a single test case iteration. 2790 * 2791 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 2792 * to release these objects. 2793 **/ 2794 bool IndirectDispatchBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 2795 { 2796 bool result = true; 2797 2798 /* Cache the BO id, if not cached already */ 2799 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 2800 2801 m_sparse_bo = sparse_bo; 2802 2803 /* Set up the sparse bufffer. */ 2804 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 2805 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2806 2807 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 2808 m_sparse_bo_size_rounded, GL_TRUE); /* commit */ 2809 2810 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 2811 2812 return result; 2813 } 2814 2815 /** Constructor. 2816 * 2817 * @param gl GL entry-points container 2818 * @param testContext CTS test context 2819 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 2820 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 2821 */ 2822 InvalidateBufferStorageTestCase::InvalidateBufferStorageTestCase(const glw::Functions& gl, 2823 tcu::TestContext& testContext, glw::GLint page_size) 2824 : m_gl(gl) 2825 , m_n_pages_to_use(4) 2826 , m_page_size(page_size) 2827 , m_sparse_bo(0) 2828 , m_sparse_bo_size(0) 2829 , m_sparse_bo_size_rounded(0) 2830 { 2831 (void)testContext; 2832 DE_ASSERT((m_n_pages_to_use % 2) == 0); 2833 } 2834 2835 /** Releases all GL objects used across all test case iterations. 2836 * 2837 * Called once during BufferStorage test run-time. 2838 */ 2839 void InvalidateBufferStorageTestCase::deinitTestCaseGlobal() 2840 { 2841 /* Stub */ 2842 } 2843 2844 /** Releases temporary GL objects, created specifically for one test case iteration. */ 2845 void InvalidateBufferStorageTestCase::deinitTestCaseIteration() 2846 { 2847 if (m_sparse_bo != 0) 2848 { 2849 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 2850 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2851 2852 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 2853 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 2854 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 2855 2856 m_sparse_bo = 0; 2857 } 2858 } 2859 2860 /** Executes a single test iteration. The BufferStorage test will call this method 2861 * numerously during its life-time, testing various valid flag combinations applied 2862 * to the tested sparse buffer object at glBufferStorage() call time. 2863 * 2864 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 2865 * call to set up the sparse buffer's storage. 2866 * 2867 * @return true if the test case executed correctly, false otherwise. 2868 */ 2869 bool InvalidateBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 2870 { 2871 (void)sparse_bo_storage_flags; 2872 bool result = true; 2873 2874 /* Since we cannot really perform any validation related to whether buffer 2875 * storage invalidation works corectly, all this test can really do is to verify 2876 * if the implementation does not crash when both entry-points are used against 2877 * a sparse buffer object. 2878 */ 2879 for (unsigned int n_entry_point = 0; n_entry_point < 2; /* glInvalidateBuffer(), glInvalidateBufferSubData() */ 2880 ++n_entry_point) 2881 { 2882 const bool should_test_invalidate_buffer = (n_entry_point == 0); 2883 2884 /* For glInvalidateBufferSubData(), we need to test two different ranges. */ 2885 for (int n_iteration = 0; n_iteration < ((should_test_invalidate_buffer) ? 1 : 2); ++n_iteration) 2886 { 2887 if (should_test_invalidate_buffer) 2888 { 2889 m_gl.invalidateBufferData(m_sparse_bo); 2890 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferData() call failed."); 2891 } 2892 else 2893 { 2894 m_gl.invalidateBufferSubData(m_sparse_bo, 0, /* offset */ 2895 m_sparse_bo_size_rounded * ((n_iteration == 0) ? 1 : 2)); 2896 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferSubData() call failed."); 2897 } 2898 } /* for (all iterations) */ 2899 } /* for (both entry-points) */ 2900 2901 return result; 2902 } 2903 2904 /** Initializes GL objects used across all test case iterations. 2905 * 2906 * Called once during BufferStorage test run-time. 2907 */ 2908 bool InvalidateBufferStorageTestCase::initTestCaseGlobal() 2909 { 2910 const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size; 2911 2912 /* Determine the number of bytes both the helper and the sparse buffer 2913 * object need to be able to hold, at maximum */ 2914 m_sparse_bo_size = n_bytes_needed; 2915 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size); 2916 2917 return true; 2918 } 2919 2920 /** Initializes GL objects which are needed for a single test case iteration. 2921 * 2922 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 2923 * to release these objects. 2924 **/ 2925 bool InvalidateBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 2926 { 2927 bool result = true; 2928 2929 /* Cache the BO id, if not cached already */ 2930 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 2931 2932 m_sparse_bo = sparse_bo; 2933 2934 /* Set up the sparse bufffer. */ 2935 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 2936 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 2937 2938 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 2939 m_sparse_bo_size_rounded, GL_TRUE); /* commit */ 2940 2941 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 2942 2943 return result; 2944 } 2945 2946 /** Constructor. 2947 * 2948 * @param gl GL entry-points container 2949 * @param testContext CTS test context 2950 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 2951 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 2952 */ 2953 PixelPackBufferStorageTestCase::PixelPackBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, 2954 glw::GLint page_size) 2955 : m_color_rb(0) 2956 , m_color_rb_height(1024) 2957 , m_color_rb_width(1024) 2958 , m_fbo(0) 2959 , m_gl(gl) 2960 , m_helper_bo(0) 2961 , m_page_size(page_size) 2962 , m_po(0) 2963 , m_ref_data_ptr(DE_NULL) 2964 , m_ref_data_size(0) 2965 , m_sparse_bo(0) 2966 , m_sparse_bo_size(0) 2967 , m_sparse_bo_size_rounded(0) 2968 , m_testCtx(testContext) 2969 , m_vao(0) 2970 { 2971 m_ref_data_size = m_color_rb_width * m_color_rb_height * 4; /* rgba */ 2972 } 2973 2974 /** Releases all GL objects used across all test case iterations. 2975 * 2976 * Called once during BufferStorage test run-time. 2977 */ 2978 void PixelPackBufferStorageTestCase::deinitTestCaseGlobal() 2979 { 2980 if (m_color_rb != 0) 2981 { 2982 m_gl.deleteRenderbuffers(1, &m_color_rb); 2983 2984 m_color_rb = 0; 2985 } 2986 2987 if (m_fbo != 0) 2988 { 2989 m_gl.deleteFramebuffers(1, &m_fbo); 2990 2991 m_fbo = 0; 2992 } 2993 2994 if (m_helper_bo != 0) 2995 { 2996 m_gl.deleteBuffers(1, &m_helper_bo); 2997 2998 m_helper_bo = 0; 2999 } 3000 3001 if (m_ref_data_ptr != DE_NULL) 3002 { 3003 delete[] m_ref_data_ptr; 3004 3005 m_ref_data_ptr = DE_NULL; 3006 } 3007 3008 if (m_po != 0) 3009 { 3010 m_gl.deleteProgram(m_po); 3011 3012 m_po = 0; 3013 } 3014 3015 if (m_vao != 0) 3016 { 3017 m_gl.deleteVertexArrays(1, &m_vao); 3018 3019 m_vao = 0; 3020 } 3021 } 3022 3023 /** Releases temporary GL objects, created specifically for one test case iteration. */ 3024 void PixelPackBufferStorageTestCase::deinitTestCaseIteration() 3025 { 3026 if (m_sparse_bo != 0) 3027 { 3028 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 3029 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3030 3031 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 3032 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 3033 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3034 3035 m_sparse_bo = 0; 3036 } 3037 } 3038 3039 /** Executes a single test iteration. The BufferStorage test will call this method 3040 * numerously during its life-time, testing various valid flag combinations applied 3041 * to the tested sparse buffer object at glBufferStorage() call time. 3042 * 3043 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 3044 * call to set up the sparse buffer's storage. 3045 * 3046 * @return true if the test case executed correctly, false otherwise. 3047 */ 3048 bool PixelPackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 3049 { 3050 (void)sparse_bo_storage_flags; 3051 bool result = true; 3052 3053 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 3054 m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, m_sparse_bo); 3055 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 3056 3057 /* Run three separate iterations: 3058 * 3059 * a) All pages that are going to hold the texture data are committed. 3060 * b) Use a zig-zag memory page commitment layout patern. 3061 * b) No pages are committed. 3062 */ 3063 for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration) 3064 { 3065 bool result_local = true; 3066 3067 /* Set up the memory page commitment & the storage contents*/ 3068 switch (n_iteration) 3069 { 3070 case 0: 3071 { 3072 m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0, /* offset */ 3073 m_sparse_bo_size_rounded, GL_TRUE); /* commit */ 3074 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3075 3076 break; 3077 } 3078 3079 case 1: 3080 { 3081 const unsigned int n_pages = 1 + m_ref_data_size / m_page_size; 3082 3083 DE_ASSERT((m_ref_data_size % m_page_size) == 0); 3084 3085 for (unsigned int n_page = 0; n_page < n_pages; ++n_page) 3086 { 3087 const bool should_commit = ((n_page % 2) == 0); 3088 3089 m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, m_page_size * n_page, m_page_size, 3090 should_commit ? GL_TRUE : GL_FALSE); 3091 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3092 } /* for (all relevant memory pages) */ 3093 3094 break; 3095 } 3096 3097 case 2: 3098 { 3099 /* Do nothing - all pages already de-committed */ 3100 break; 3101 } 3102 3103 default: 3104 { 3105 TCU_FAIL("Invalid iteration index"); 3106 } 3107 } /* switch (n_iteration) */ 3108 3109 /* Draw full screen quad to generate the black-to-white gradient */ 3110 const unsigned char* read_data_ptr = NULL; 3111 3112 m_gl.useProgram(m_po); 3113 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 3114 3115 m_gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */); 3116 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed."); 3117 3118 /* Read a framebuffer pixel data */ 3119 m_gl.readPixels(0, /* x */ 3120 0, /* y */ 3121 m_color_rb_width, m_color_rb_height, GL_RGBA, GL_UNSIGNED_BYTE, 0); /* pixels */ 3122 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed."); 3123 3124 m_gl.copyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_COPY_READ_BUFFER, 0, /* readOffset */ 3125 0, /* writeOffset */ 3126 m_ref_data_size); 3127 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 3128 3129 read_data_ptr = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */ 3130 m_ref_data_size, GL_MAP_READ_BIT); 3131 3132 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed."); 3133 3134 /* Verify the data */ 3135 unsigned int n_current_tex_data_byte = 0; 3136 const unsigned char* read_data_traveller_ptr = (const unsigned char*)read_data_ptr; 3137 const unsigned char* reference_data_traveller_ptr = (const unsigned char*)m_ref_data_ptr; 3138 3139 for (unsigned int y = 0; y < m_color_rb_height && result_local; ++y) 3140 { 3141 for (unsigned int x = 0; x < m_color_rb_width && result_local; ++x) 3142 { 3143 for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component) 3144 { 3145 unsigned char expected_value = 0; 3146 bool is_from_committed_page = true; 3147 3148 if (n_iteration == 1) /* zig-zag */ 3149 { 3150 is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0; 3151 } 3152 else if (n_iteration == 2) /* no pages committed */ 3153 { 3154 is_from_committed_page = false; 3155 } 3156 3157 if (is_from_committed_page) 3158 { 3159 expected_value = *reference_data_traveller_ptr; 3160 } 3161 3162 if (is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) > 1) 3163 { 3164 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component 3165 << ")" 3166 " found at X:" 3167 << x << ", " 3168 "Y:" 3169 << y << ")." 3170 " Expected value:" 3171 << expected_value << "," 3172 " found value:" 3173 << *reference_data_traveller_ptr << tcu::TestLog::EndMessage; 3174 3175 result_local = false; 3176 } 3177 3178 n_current_tex_data_byte++; 3179 read_data_traveller_ptr++; 3180 reference_data_traveller_ptr++; 3181 } /* for (all components) */ 3182 } /* for (all columns) */ 3183 } /* for (all rows) */ 3184 3185 m_gl.unmapBuffer(GL_COPY_READ_BUFFER); 3186 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 3187 3188 read_data_ptr = DE_NULL; 3189 result &= result_local; 3190 3191 /* Clean up */ 3192 m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0, /* offset */ 3193 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 3194 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3195 } /* for (three iterations) */ 3196 3197 m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0); 3198 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3199 3200 return result; 3201 } 3202 3203 /** Initializes GL objects used across all test case iterations. 3204 * 3205 * Called once during BufferStorage test run-time. 3206 */ 3207 bool PixelPackBufferStorageTestCase::initTestCaseGlobal() 3208 { 3209 /* Determine dummy vertex shader and fragment shader that will generate black-to-white gradient. */ 3210 const char* gradient_fs_code = "#version 330 core\n" 3211 "\n" 3212 "out vec4 result;\n" 3213 "\n" 3214 "void main()\n" 3215 "{\n" 3216 " float c = 1.0 - (gl_FragCoord.y - 0.5) / 1023.0;\n" 3217 " result = vec4(c);\n" 3218 "}\n"; 3219 3220 const char* gradient_vs_code = "#version 330\n" 3221 "\n" 3222 "void main()\n" 3223 "{\n" 3224 " switch (gl_VertexID)\n" 3225 " {\n" 3226 " case 0: gl_Position = vec4(-1.0, -1.0, 0.0, 1.0); break;\n" 3227 " case 1: gl_Position = vec4( 1.0, -1.0, 0.0, 1.0); break;\n" 3228 " case 2: gl_Position = vec4(-1.0, 1.0, 0.0, 1.0); break;\n" 3229 " case 3: gl_Position = vec4( 1.0, 1.0, 0.0, 1.0); break;\n" 3230 " }\n" 3231 "}\n"; 3232 3233 m_po = SparseBufferTestUtilities::createProgram(m_gl, &gradient_fs_code, 1, /* n_fs_body_parts */ 3234 &gradient_vs_code, 1, /* n_vs_body_parts*/ 3235 NULL, /* attribute_names */ 3236 NULL, /* attribute_locations */ 3237 GL_NONE, /* attribute_properties */ 3238 0, /* tf_varyings */ 3239 0, /* n_tf_varyings */ 3240 0); /* tf_varying_mode */ 3241 if (m_po == 0) 3242 { 3243 TCU_FAIL("Failed to link the test program"); 3244 } 3245 3246 /* Generate and bind VAO */ 3247 m_gl.genVertexArrays(1, &m_vao); 3248 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed."); 3249 3250 m_gl.bindVertexArray(m_vao); 3251 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed."); 3252 3253 /* Generate and bind FBO */ 3254 m_gl.genFramebuffers(1, &m_fbo); 3255 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed."); 3256 3257 m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 3258 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed."); 3259 3260 m_gl.readBuffer(GL_COLOR_ATTACHMENT0); 3261 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadBuffer() call failed."); 3262 3263 /* Generate and bind RBO and attach it to FBO as a color attachment */ 3264 m_gl.genRenderbuffers(1, &m_color_rb); 3265 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenRenderbuffers() call failed."); 3266 3267 m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_color_rb); 3268 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindRenderbuffer() call failed."); 3269 3270 m_gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_color_rb_width, m_color_rb_height); 3271 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glRenderbufferStorage() call failed."); 3272 3273 m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_color_rb); 3274 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferRenderbuffer() call failed."); 3275 3276 if (m_gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 3277 { 3278 throw tcu::NotSupportedError("Cannot execute the test - driver does not support rendering" 3279 "to a GL_RGBA8 renderbuffer-based color attachment"); 3280 } 3281 3282 m_gl.viewport(0, /* x */ 3283 0, /* y */ 3284 m_color_rb_width, m_color_rb_height); 3285 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glViewport() call failed."); 3286 3287 /* Determine what sparse buffer storage size we are going to need*/ 3288 m_sparse_bo_size = m_ref_data_size; 3289 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size); 3290 3291 /* Prepare the texture data */ 3292 unsigned char* ref_data_traveller_ptr = DE_NULL; 3293 3294 m_ref_data_ptr = new unsigned char[m_ref_data_size]; 3295 ref_data_traveller_ptr = m_ref_data_ptr; 3296 3297 for (unsigned int y = 0; y < m_color_rb_height; ++y) 3298 { 3299 const unsigned char color = (unsigned char)((1.0f - float(y) / float(m_color_rb_height - 1)) * 255.0f); 3300 3301 for (unsigned int x = 0; x < m_color_rb_width; ++x) 3302 { 3303 memset(ref_data_traveller_ptr, color, 4); /* rgba */ 3304 3305 ref_data_traveller_ptr += 4; /* rgba */ 3306 } /* for (all columns) */ 3307 } /* for (all rows) */ 3308 3309 /* Set up the helper buffer object. */ 3310 m_gl.genBuffers(1, &m_helper_bo); 3311 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 3312 3313 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 3314 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3315 3316 m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_ref_data_size, m_ref_data_ptr, GL_MAP_READ_BIT); 3317 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 3318 3319 return true; 3320 } 3321 3322 /** Initializes GL objects which are needed for a single test case iteration. 3323 * 3324 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 3325 * to release these objects. 3326 **/ 3327 bool PixelPackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 3328 { 3329 bool result = true; 3330 3331 /* Cache the BO id, if not cached already */ 3332 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 3333 3334 m_sparse_bo = sparse_bo; 3335 3336 return result; 3337 } 3338 3339 /** Constructor. 3340 * 3341 * @param gl GL entry-points container 3342 * @param testContext CTS test context 3343 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 3344 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 3345 */ 3346 PixelUnpackBufferStorageTestCase::PixelUnpackBufferStorageTestCase(const glw::Functions& gl, 3347 tcu::TestContext& testContext, glw::GLint page_size) 3348 : m_gl(gl) 3349 , m_helper_bo(0) 3350 , m_page_size(page_size) 3351 , m_read_data_ptr(DE_NULL) 3352 , m_sparse_bo(0) 3353 , m_sparse_bo_size(0) 3354 , m_sparse_bo_size_rounded(0) 3355 , m_testCtx(testContext) 3356 , m_texture_data_ptr(DE_NULL) 3357 , m_texture_data_size(0) 3358 , m_to(0) 3359 , m_to_data_zero(DE_NULL) 3360 , m_to_height(1024) 3361 , m_to_width(1024) 3362 { 3363 m_texture_data_size = m_to_width * m_to_height * 4; /* rgba */ 3364 } 3365 3366 /** Releases all GL objects used across all test case iterations. 3367 * 3368 * Called once during BufferStorage test run-time. 3369 */ 3370 void PixelUnpackBufferStorageTestCase::deinitTestCaseGlobal() 3371 { 3372 if (m_helper_bo != 0) 3373 { 3374 m_gl.deleteBuffers(1, &m_helper_bo); 3375 3376 m_helper_bo = 0; 3377 } 3378 3379 if (m_read_data_ptr != DE_NULL) 3380 { 3381 delete[] m_read_data_ptr; 3382 3383 m_read_data_ptr = DE_NULL; 3384 } 3385 3386 if (m_texture_data_ptr != DE_NULL) 3387 { 3388 delete[] m_texture_data_ptr; 3389 3390 m_texture_data_ptr = DE_NULL; 3391 } 3392 3393 if (m_to != 0) 3394 { 3395 m_gl.deleteTextures(1, &m_to); 3396 3397 m_to = 0; 3398 } 3399 3400 if (m_to_data_zero != DE_NULL) 3401 { 3402 delete[] m_to_data_zero; 3403 3404 m_to_data_zero = DE_NULL; 3405 } 3406 } 3407 3408 /** Releases temporary GL objects, created specifically for one test case iteration. */ 3409 void PixelUnpackBufferStorageTestCase::deinitTestCaseIteration() 3410 { 3411 if (m_sparse_bo != 0) 3412 { 3413 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 3414 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3415 3416 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 3417 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 3418 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3419 3420 m_sparse_bo = 0; 3421 } 3422 } 3423 3424 /** Executes a single test iteration. The BufferStorage test will call this method 3425 * numerously during its life-time, testing various valid flag combinations applied 3426 * to the tested sparse buffer object at glBufferStorage() call time. 3427 * 3428 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 3429 * call to set up the sparse buffer's storage. 3430 * 3431 * @return true if the test case executed correctly, false otherwise. 3432 */ 3433 bool PixelUnpackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 3434 { 3435 (void)sparse_bo_storage_flags; 3436 bool result = true; 3437 3438 m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo); 3439 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3440 3441 m_gl.bindTexture(GL_TEXTURE_2D, m_to); 3442 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed."); 3443 3444 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 3445 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed."); 3446 3447 /* Run three separate iterations: 3448 * 3449 * a) All pages holding the source texture data are committed. 3450 * b) Use a zig-zag memory page commitment layout patern. 3451 * b) No pages are committed. 3452 */ 3453 for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration) 3454 { 3455 bool result_local = true; 3456 3457 /* Set up the memory page commitment & the storage contents*/ 3458 switch (n_iteration) 3459 { 3460 case 0: 3461 { 3462 m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0, /* offset */ 3463 m_sparse_bo_size_rounded, GL_TRUE); /* commit */ 3464 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3465 3466 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, /* readOffset */ 3467 0, /* writeOffset */ 3468 m_texture_data_size); 3469 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 3470 3471 break; 3472 } 3473 3474 case 1: 3475 { 3476 const unsigned int n_pages = m_texture_data_size / m_page_size; 3477 3478 for (unsigned int n_page = 0; n_page < n_pages; ++n_page) 3479 { 3480 const bool should_commit = ((n_page % 2) == 0); 3481 3482 m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, m_page_size * n_page, m_page_size, 3483 should_commit ? GL_TRUE : GL_FALSE); 3484 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3485 3486 if (should_commit) 3487 { 3488 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER, 3489 m_page_size * n_page, /* readOffset */ 3490 m_page_size * n_page, /* writeOffset */ 3491 m_page_size); 3492 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 3493 } 3494 } /* for (all relevant memory pages) */ 3495 3496 break; 3497 } 3498 3499 case 2: 3500 { 3501 /* Do nothing */ 3502 break; 3503 } 3504 3505 default: 3506 { 3507 TCU_FAIL("Invalid iteration index"); 3508 } 3509 } /* switch (n_iteration) */ 3510 3511 /* Clean up the base mip-map's contents before we proceeding with updating it 3512 * with data downloaded from the BO, in order to avoid situation where silently 3513 * failing glTexSubImage2D() calls slip past unnoticed */ 3514 m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 3515 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3516 3517 m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */ 3518 0, /* xoffset */ 3519 0, /* yoffset */ 3520 m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, m_to_data_zero); 3521 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed."); 3522 3523 m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo); 3524 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3525 3526 /* Update the base mip-map's contents */ 3527 m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */ 3528 0, /* xoffset */ 3529 0, /* yoffset */ 3530 m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, (const glw::GLvoid*)0); 3531 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed."); 3532 3533 /* Read back the stored mip-map data */ 3534 memset(m_read_data_ptr, 0xFF, m_texture_data_size); 3535 3536 m_gl.getTexImage(GL_TEXTURE_2D, 0, /* level */ 3537 GL_RGBA, GL_UNSIGNED_BYTE, m_read_data_ptr); 3538 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetTexImage() call failed."); 3539 3540 /* Verify the data */ 3541 unsigned int n_current_tex_data_byte = 0; 3542 const char* read_data_traveller_ptr = (const char*)m_read_data_ptr; 3543 const char* texture_data_traveller_ptr = (const char*)m_texture_data_ptr; 3544 3545 for (unsigned int y = 0; y < m_to_height && result_local; ++y) 3546 { 3547 for (unsigned int x = 0; x < m_to_width && result_local; ++x) 3548 { 3549 for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component) 3550 { 3551 char expected_value = 0; 3552 bool is_from_committed_page = true; 3553 3554 if (n_iteration == 1) /* zig-zag */ 3555 { 3556 is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0; 3557 } 3558 else if (n_iteration == 2) /* no pages committed */ 3559 { 3560 is_from_committed_page = false; 3561 } 3562 3563 if (is_from_committed_page) 3564 { 3565 expected_value = *texture_data_traveller_ptr; 3566 } 3567 3568 if ((is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) >= 1) || 3569 (!is_from_committed_page && *read_data_traveller_ptr != expected_value)) 3570 { 3571 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component 3572 << ")" 3573 " found at X:" 3574 << x << ", " 3575 "Y:" 3576 << y << ")." 3577 " Expected value:" 3578 << expected_value << "," 3579 " found value:" 3580 << *texture_data_traveller_ptr << tcu::TestLog::EndMessage; 3581 3582 result_local = false; 3583 } 3584 3585 n_current_tex_data_byte++; 3586 read_data_traveller_ptr++; 3587 texture_data_traveller_ptr++; 3588 } /* for (all components) */ 3589 } /* for (all columns) */ 3590 } /* for (all rows) */ 3591 3592 result &= result_local; 3593 3594 /* Clean up */ 3595 m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0, /* offset */ 3596 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 3597 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3598 } /* for (three iterations) */ 3599 3600 m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 3601 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3602 3603 return result; 3604 } 3605 3606 /** Initializes GL objects used across all test case iterations. 3607 * 3608 * Called once during BufferStorage test run-time. 3609 */ 3610 bool PixelUnpackBufferStorageTestCase::initTestCaseGlobal() 3611 { 3612 /* Determine sparse buffer storage size */ 3613 m_sparse_bo_size = m_texture_data_size; 3614 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size); 3615 3616 /* Prepare the texture data */ 3617 unsigned char* texture_data_traveller_ptr = DE_NULL; 3618 3619 m_read_data_ptr = new unsigned char[m_texture_data_size]; 3620 m_texture_data_ptr = new unsigned char[m_texture_data_size]; 3621 texture_data_traveller_ptr = m_texture_data_ptr; 3622 3623 for (unsigned int y = 0; y < m_to_height; ++y) 3624 { 3625 for (unsigned int x = 0; x < m_to_width; ++x) 3626 { 3627 const unsigned char color = (unsigned char)(float(x) / float(m_to_width - 1) * 255.0f); 3628 3629 memset(texture_data_traveller_ptr, color, 4); /* rgba */ 3630 3631 texture_data_traveller_ptr += 4; /* rgba */ 3632 } /* for (all columns) */ 3633 } /* for (all rows) */ 3634 3635 m_to_data_zero = new unsigned char[m_texture_data_size]; 3636 3637 memset(m_to_data_zero, 0, m_texture_data_size); 3638 3639 /* Set up the helper buffer object */ 3640 m_gl.genBuffers(1, &m_helper_bo); 3641 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 3642 3643 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 3644 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3645 3646 m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_texture_data_size, m_texture_data_ptr, GL_MAP_READ_BIT); 3647 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 3648 3649 /* Set up texture object storage */ 3650 m_gl.genTextures(1, &m_to); 3651 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed."); 3652 3653 m_gl.bindTexture(GL_TEXTURE_2D, m_to); 3654 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed."); 3655 3656 m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */ 3657 GL_RGBA8, m_to_width, m_to_height); 3658 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed."); 3659 3660 return true; 3661 } 3662 3663 /** Initializes GL objects which are needed for a single test case iteration. 3664 * 3665 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 3666 * to release these objects. 3667 **/ 3668 bool PixelUnpackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 3669 { 3670 bool result = true; 3671 3672 /* Cache the BO id, if not cached already */ 3673 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 3674 3675 m_sparse_bo = sparse_bo; 3676 3677 /* Set up the sparse buffer. */ 3678 m_gl.bindBuffer(GL_QUERY_BUFFER, m_sparse_bo); 3679 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3680 3681 return result; 3682 } 3683 3684 /** Constructor. 3685 * 3686 * @param gl GL entry-points container 3687 * @param testContext CTS test context 3688 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 3689 * @param ibo_usage Specifies if an indexed draw call should be used by the test. For more details, 3690 * please see documentation for _ibo_usage. 3691 * @param use_color_data true to use the color data for the tested draw call; 3692 * false to omit usage of attribute data. 3693 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 3694 */ 3695 QuadsBufferStorageTestCase::QuadsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, 3696 glw::GLint page_size, _ibo_usage ibo_usage, bool use_color_data) 3697 : m_attribute_color_location(0) /* predefined attribute locations */ 3698 , m_attribute_position_location(1) /* predefined attribute locations */ 3699 , m_color_data_offset(0) 3700 , m_data(DE_NULL) 3701 , m_data_size(0) 3702 , m_data_size_rounded(0) 3703 , m_fbo(0) 3704 , m_gl(gl) 3705 , m_helper_bo(0) 3706 , m_ibo_data_offset(-1) 3707 , m_ibo_usage(ibo_usage) 3708 , m_n_quad_delta_x(5) 3709 , m_n_quad_delta_y(5) 3710 , m_n_quad_height(5) 3711 , m_n_quad_width(5) 3712 , m_n_quads_x(100) /* as per spec */ 3713 , m_n_quads_y(100) /* as per spec */ 3714 , m_n_vertices_to_draw(0) 3715 , m_pages_committed(false) 3716 , m_po(0) 3717 , m_sparse_bo(0) 3718 , m_testCtx(testContext) 3719 , m_to(0) 3720 , m_to_height(1024) /* as per spec */ 3721 , m_to_width(1024) /* as per spec */ 3722 , m_use_color_data(use_color_data) 3723 , m_vao(0) 3724 , m_vbo_data_offset(-1) 3725 { 3726 /* 3727 * Each quad = 2 triangles, 1 triangle = 3 vertices, 1 vertex = 4 components. 3728 * The inefficient representation has been used on purpose - we want the data to take 3729 * more than 64KB so that it is guaranteed that it will span over more than 1 page. 3730 */ 3731 m_data_size = 0; 3732 3733 m_n_vertices_to_draw = m_n_quads_x * /* quads in X */ 3734 m_n_quads_y * /* quads in Y */ 3735 2 * /* triangles */ 3736 3; /* vertices per triangle */ 3737 3738 m_data_size = static_cast<glw::GLuint>(m_n_vertices_to_draw * 4 /* components */ * sizeof(float)); 3739 3740 if (m_ibo_usage != IBO_USAGE_NONE) 3741 { 3742 DE_ASSERT(m_n_vertices_to_draw < 65536); 3743 3744 m_data_size = static_cast<glw::GLuint>(m_data_size + (m_n_vertices_to_draw * sizeof(unsigned short))); 3745 } 3746 3747 if (m_use_color_data) 3748 { 3749 m_data_size = static_cast<glw::GLuint>(m_data_size + 3750 (m_n_vertices_to_draw * sizeof(unsigned char) * 4 * /* rgba components */ 3751 2 * /* triangles */ 3752 3)); /* vertices per triangle */ 3753 } 3754 3755 m_data_size_rounded = SparseBufferTestUtilities::alignOffset(m_data_size, page_size); 3756 } 3757 3758 /** Allocates a data buffer and fills it with vertex/index/color data. Vertex data is always stored, 3759 * index data only if m_ibo_usage is different from IBO_USAGE_NONE. Color data is only saved if 3760 * m_use_color_data is true. 3761 * 3762 * @param out_data Deref will be used to store a pointer to the allocated data buffer. 3763 * Ownership is transferred to the caller. Must not be NULL. 3764 * @param out_vbo_data_offset Deref will be used to store an offset, from which VBO data starts, 3765 * relative to the beginning of *out_data. Must not be NULL. 3766 * @param out_ibo_data_offset Deref will be used to store an offset, from which IBO data starts, 3767 * relative to the beginning of *out_data. May be NULL if m_ibo_usage 3768 * is IBO_USAGE_NONE. 3769 * @param out_color_data_offset Deref will be used to store na offset, from which color data starts, 3770 * relative to the beginning of *out_data. May be NULL if m_use_color_data 3771 * is false. 3772 * 3773 */ 3774 void QuadsBufferStorageTestCase::createTestData(unsigned char** out_data, unsigned int* out_vbo_data_offset, 3775 unsigned int* out_ibo_data_offset, 3776 unsigned int* out_color_data_offset) const 3777 { 3778 unsigned char* data_traveller_ptr = NULL; 3779 3780 *out_data = new unsigned char[m_data_size]; 3781 *out_vbo_data_offset = 0; 3782 3783 data_traveller_ptr = *out_data; 3784 3785 for (unsigned int n_quad_y = 0; n_quad_y < m_n_quads_y; ++n_quad_y) 3786 { 3787 for (unsigned int n_quad_x = 0; n_quad_x < m_n_quads_x; ++n_quad_x) 3788 { 3789 const unsigned int quad_start_x_px = n_quad_x * (m_n_quad_delta_x + m_n_quad_width); 3790 const unsigned int quad_start_y_px = n_quad_y * (m_n_quad_delta_y + m_n_quad_height); 3791 const unsigned int quad_end_x_px = quad_start_x_px + m_n_quad_width; 3792 const unsigned int quad_end_y_px = quad_start_y_px + m_n_quad_height; 3793 3794 const float quad_end_x_ss = float(quad_end_x_px) / float(m_to_width) * 2.0f - 1.0f; 3795 const float quad_end_y_ss = float(quad_end_y_px) / float(m_to_height) * 2.0f - 1.0f; 3796 const float quad_start_x_ss = float(quad_start_x_px) / float(m_to_width) * 2.0f - 1.0f; 3797 const float quad_start_y_ss = float(quad_start_y_px) / float(m_to_height) * 2.0f - 1.0f; 3798 3799 /* 1,4--5 3800 * |\ | 3801 * | \ | 3802 * 2----3,6 3803 */ 3804 const float v1_4[] = { 3805 quad_start_x_ss, quad_start_y_ss, 0.0f, /* z */ 3806 1.0f, /* w */ 3807 }; 3808 const float v2[] = { 3809 quad_start_x_ss, quad_end_y_ss, 0.0f, /* z */ 3810 1.0f /* w */ 3811 }; 3812 const float v3_6[] = { 3813 quad_end_x_ss, quad_end_y_ss, 0.0f, /* z */ 3814 1.0f /* w */ 3815 }; 3816 const float v5[] = { 3817 quad_end_x_ss, quad_start_y_ss, 0.0f, /* z */ 3818 1.0f /* w */ 3819 }; 3820 3821 memcpy(data_traveller_ptr, v1_4, sizeof(v1_4)); 3822 data_traveller_ptr += sizeof(v1_4); 3823 3824 memcpy(data_traveller_ptr, v2, sizeof(v2)); 3825 data_traveller_ptr += sizeof(v2); 3826 3827 memcpy(data_traveller_ptr, v3_6, sizeof(v3_6)); 3828 data_traveller_ptr += sizeof(v3_6); 3829 3830 memcpy(data_traveller_ptr, v1_4, sizeof(v1_4)); 3831 data_traveller_ptr += sizeof(v1_4); 3832 3833 memcpy(data_traveller_ptr, v5, sizeof(v5)); 3834 data_traveller_ptr += sizeof(v5); 3835 3836 memcpy(data_traveller_ptr, v3_6, sizeof(v3_6)); 3837 data_traveller_ptr += sizeof(v3_6); 3838 } /* for (all quads in X) */ 3839 } /* for (all quads in Y) */ 3840 3841 /* Set up index data if needed */ 3842 if (m_ibo_usage != IBO_USAGE_NONE) 3843 { 3844 *out_ibo_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data); 3845 3846 for (int index = m_n_vertices_to_draw - 1; index >= 0; --index) 3847 { 3848 *(unsigned short*)data_traveller_ptr = (unsigned short)index; 3849 data_traveller_ptr += sizeof(unsigned short); 3850 } /* for (all index values) */ 3851 } /* if (m_use_ibo) */ 3852 else 3853 { 3854 *out_ibo_data_offset = 0; 3855 } 3856 3857 /* Set up color data if needed */ 3858 if (m_use_color_data) 3859 { 3860 *out_color_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data); 3861 3862 for (unsigned int n_quad = 0; n_quad < m_n_quads_x * m_n_quads_y; ++n_quad) 3863 { 3864 /* Use magic formulas to generate a color data set for the quads. The data 3865 * needs to be duplicated for 6 vertices forming a single quad. */ 3866 for (unsigned int n_vertex = 0; n_vertex < 6; ++n_vertex) 3867 { 3868 /* Red */ 3869 *data_traveller_ptr = static_cast<unsigned char>(n_quad % 256); //((n_quad + 15) * 14) % 256; 3870 data_traveller_ptr++; 3871 3872 /* Green */ 3873 *data_traveller_ptr = static_cast<unsigned char>(((n_quad + 32) * 7) % 255); 3874 data_traveller_ptr++; 3875 3876 /* Blue */ 3877 *data_traveller_ptr = static_cast<unsigned char>(((n_quad + 7) * 53) % 255); 3878 data_traveller_ptr++; 3879 3880 /* Alpha */ 3881 *data_traveller_ptr = static_cast<unsigned char>(((n_quad + 13) * 3) % 255); 3882 data_traveller_ptr++; 3883 } 3884 } /* for (all quads) */ 3885 } 3886 else 3887 { 3888 *out_color_data_offset = 0; 3889 } 3890 } 3891 3892 /** Releases all GL objects used across all test case iterations. 3893 * 3894 * Called once during BufferStorage test run-time. 3895 */ 3896 void QuadsBufferStorageTestCase::deinitTestCaseGlobal() 3897 { 3898 if (m_data != DE_NULL) 3899 { 3900 delete[] m_data; 3901 3902 m_data = DE_NULL; 3903 } 3904 3905 if (m_fbo != 0) 3906 { 3907 m_gl.deleteFramebuffers(1, &m_fbo); 3908 3909 m_fbo = 0; 3910 } 3911 3912 if (m_helper_bo != 0) 3913 { 3914 m_gl.deleteBuffers(1, &m_helper_bo); 3915 3916 m_helper_bo = 0; 3917 } 3918 3919 if (m_po != 0) 3920 { 3921 m_gl.deleteProgram(m_po); 3922 3923 m_po = 0; 3924 } 3925 3926 if (m_to != 0) 3927 { 3928 m_gl.deleteTextures(1, &m_to); 3929 3930 m_to = 0; 3931 } 3932 3933 if (m_vao != 0) 3934 { 3935 m_gl.deleteVertexArrays(1, &m_vao); 3936 3937 m_vao = 0; 3938 } 3939 } 3940 3941 /** Releases temporary GL objects, created specifically for one test case iteration. */ 3942 void QuadsBufferStorageTestCase::deinitTestCaseIteration() 3943 { 3944 /* If the test executed successfully, all pages should've been released by now. 3945 * However, if it failed, it's a good idea to de-commit them at this point. 3946 * Redundant calls are fine spec-wise, too. */ 3947 if (m_sparse_bo != 0) 3948 { 3949 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 3950 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 3951 3952 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 3953 m_data_size_rounded, GL_FALSE); /* commit */ 3954 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 3955 3956 m_sparse_bo = 0; 3957 } 3958 } 3959 3960 /** Executes a single test iteration. The BufferStorage test will call this method 3961 * numerously during its life-time, testing various valid flag combinations applied 3962 * to the tested sparse buffer object at glBufferStorage() call time. 3963 * 3964 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 3965 * call to set up the sparse buffer's storage. 3966 * 3967 * @return true if the test case executed correctly, false otherwise. 3968 */ 3969 bool QuadsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 3970 { 3971 bool result = true; 3972 3973 m_gl.viewport(0, /* x */ 3974 0, /* y */ 3975 m_to_width, m_to_height); 3976 3977 m_gl.useProgram(m_po); 3978 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 3979 3980 m_gl.clearColor(0.0f, /* red */ 3981 0.0f, /* green */ 3982 0.0f, /* blue */ 3983 0.0f); /* alpha */ 3984 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor() call failed."); 3985 3986 /* Render the quads. 3987 * 3988 * Run in two iterations: 3989 * 3990 * a) Iteration 1 performs the draw call with the VBO & IBO pages committed 3991 * b) Iteration 2 performs the draw call with the VBO & IBO pages without any 3992 * physical backing. 3993 **/ 3994 for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration) 3995 { 3996 initSparseBO((n_iteration == 0), /* decommit pages after upload */ 3997 (sparse_bo_storage_flags & GL_DYNAMIC_STORAGE_BIT) != 0); 3998 3999 m_gl.clear(GL_COLOR_BUFFER_BIT); 4000 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear() call failed."); 4001 4002 switch (m_ibo_usage) 4003 { 4004 case IBO_USAGE_NONE: 4005 { 4006 m_gl.drawArrays(GL_TRIANGLES, 0, /* first */ 4007 m_n_vertices_to_draw); 4008 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed."); 4009 4010 break; 4011 } 4012 4013 case IBO_USAGE_INDEXED_DRAW_CALL: 4014 { 4015 m_gl.drawElements(GL_TRIANGLES, m_n_vertices_to_draw, GL_UNSIGNED_SHORT, 4016 (glw::GLvoid*)(intptr_t)m_ibo_data_offset); 4017 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed."); 4018 4019 break; 4020 } 4021 4022 case IBO_USAGE_INDEXED_RANGED_DRAW_CALL: 4023 { 4024 m_gl.drawRangeElements(GL_TRIANGLES, 0, /* start */ 4025 m_n_vertices_to_draw, /* end */ 4026 m_n_vertices_to_draw, /* count */ 4027 GL_UNSIGNED_SHORT, (glw::GLvoid*)(intptr_t)m_ibo_data_offset); 4028 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawRangeElements() call failed."); 4029 4030 break; 4031 } 4032 4033 default: 4034 { 4035 TCU_FAIL("Unrecognized IBO usage value"); 4036 } 4037 } /* switch (m_ibo_usage) */ 4038 4039 /* Retrieve the rendered output */ 4040 unsigned char* read_data = new unsigned char[m_to_width * m_to_height * sizeof(char) * 4 /* rgba */]; 4041 4042 m_gl.readPixels(0, /* x */ 4043 0, /* y */ 4044 m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, read_data); 4045 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed."); 4046 4047 /* IF the data pages have been committed by the time the draw call was made, validate the data. 4048 * 4049 * For each quad region (be it filled or not), check the center and make sure the retrieved 4050 * color corresponds to the expected value. 4051 */ 4052 if (m_pages_committed) 4053 { 4054 for (unsigned int n_quad_region_y = 0; n_quad_region_y < m_n_quads_y * 2; /* quad + empty "delta" region */ 4055 ++n_quad_region_y) 4056 { 4057 for (unsigned int n_quad_region_x = 0; n_quad_region_x < m_n_quads_x * 2; ++n_quad_region_x) 4058 { 4059 /* Determine the expected texel color */ 4060 unsigned char expected_color[4]; 4061 unsigned char found_color[4]; 4062 bool is_delta_region = (n_quad_region_x % 2) != 0 || (n_quad_region_y % 2) != 0; 4063 4064 if (is_delta_region) 4065 { 4066 memset(expected_color, 0, sizeof(expected_color)); 4067 } /* if (is_delta_region) */ 4068 else 4069 { 4070 if (m_use_color_data) 4071 { 4072 const unsigned int n_quad_x = n_quad_region_x / 2; 4073 const unsigned int n_quad_y = n_quad_region_y / 2; 4074 const unsigned char* data_ptr = 4075 m_data + m_color_data_offset + 4076 (n_quad_y * m_n_quads_x + n_quad_x) * 4 /* rgba */ * 6; /* vertices */ 4077 4078 memcpy(expected_color, data_ptr, sizeof(expected_color)); 4079 } /* if (m_use_color_data) */ 4080 else 4081 { 4082 memset(expected_color, 255, sizeof(expected_color)); 4083 } 4084 } 4085 4086 /* Do we have a match? */ 4087 DE_ASSERT(m_n_quad_height == m_n_quad_delta_y); 4088 DE_ASSERT(m_n_quad_width == m_n_quad_delta_x); 4089 4090 const unsigned int sample_texel_x = m_n_quad_delta_x * n_quad_region_x; 4091 const unsigned int sample_texel_y = m_n_quad_delta_y * n_quad_region_y; 4092 4093 memcpy(found_color, read_data + (sample_texel_y * m_to_width + sample_texel_x) * 4, /* rgba */ 4094 sizeof(found_color)); 4095 4096 if (memcmp(expected_color, found_color, sizeof(expected_color)) != 0) 4097 { 4098 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid color found at " 4099 "(" 4100 << sample_texel_x << ", " << sample_texel_y << "): " 4101 "Expected color:" 4102 "(" 4103 << (int)expected_color[0] << ", " << (int)expected_color[1] << ", " 4104 << (int)expected_color[2] << ", " << (int)expected_color[3] << "), " 4105 "Found:" 4106 "(" 4107 << (int)found_color[0] << ", " << (int)found_color[1] << ", " 4108 << (int)found_color[2] << ", " << (int)found_color[3] << "), " 4109 << tcu::TestLog::EndMessage; 4110 4111 result = false; 4112 goto end; 4113 } 4114 } /* for (all quads in X) */ 4115 } /* for (all quads in Y) */ 4116 } /* if (m_pages_committed) */ 4117 4118 delete[] read_data; 4119 read_data = DE_NULL; 4120 } /* for (both iterations) */ 4121 4122 end: 4123 return result; 4124 } 4125 4126 /** Creates test data and fills the result buffer object (whose ID is stored under m_helper_bo) 4127 * with the data. 4128 */ 4129 void QuadsBufferStorageTestCase::initHelperBO() 4130 { 4131 DE_ASSERT(m_data == DE_NULL); 4132 DE_ASSERT(m_helper_bo == 0); 4133 4134 createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset); 4135 4136 m_gl.genBuffers(1, &m_helper_bo); 4137 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 4138 4139 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 4140 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4141 4142 m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_data_size, m_data, 0); /* flags */ 4143 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 4144 } 4145 4146 /** Creates test data (if necessary), configures sparse buffer's memory page commitment 4147 * and uploads the test data to the buffer object. Finally, the method configures the 4148 * vertex array object, used by ::execute() at the draw call time. 4149 * 4150 * @param decommit_data_pages_after_upload true to de-commit memory pages requested before 4151 * uploading the vertex/index/color data. 4152 * @param is_dynamic_storage true to upload the data via glBufferSubData() call. 4153 * false to use a copy op for the operation. 4154 **/ 4155 void QuadsBufferStorageTestCase::initSparseBO(bool decommit_data_pages_after_upload, bool is_dynamic_storage) 4156 { 4157 /* Set up the vertex buffer object. */ 4158 if (m_data == DE_NULL) 4159 { 4160 createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset); 4161 } 4162 else 4163 { 4164 /* Sanity checks */ 4165 if (m_ibo_usage != IBO_USAGE_NONE) 4166 { 4167 DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset); 4168 } 4169 4170 if (m_use_color_data) 4171 { 4172 DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset); 4173 DE_ASSERT(m_ibo_data_offset != m_color_data_offset); 4174 } 4175 } 4176 4177 /* Commit as many pages as we need to upload the data */ 4178 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 4179 m_data_size_rounded, GL_TRUE); /* commit */ 4180 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 4181 4182 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 4183 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4184 4185 m_pages_committed = true; 4186 4187 /* Upload the data */ 4188 if (is_dynamic_storage) 4189 { 4190 m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */ 4191 m_data_size, m_data); 4192 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed."); 4193 } 4194 else 4195 { 4196 /* Sparse BO cannot be directly uploaded data to. Copy the data from a helper BO */ 4197 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, /* readOffset */ 4198 0, /* writeOffset */ 4199 m_data_size); 4200 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 4201 } 4202 4203 /* Set the VAO up */ 4204 m_gl.vertexAttribPointer(m_attribute_position_location, 4, /* size */ 4205 GL_FLOAT, GL_FALSE, /* normalized */ 4206 0, /* stride */ 4207 (glw::GLvoid*)(intptr_t)m_vbo_data_offset); 4208 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed."); 4209 4210 m_gl.enableVertexAttribArray(m_attribute_position_location); /* index */ 4211 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed."); 4212 4213 if (m_use_color_data) 4214 { 4215 m_gl.vertexAttribPointer(m_attribute_color_location, 4, /* size */ 4216 GL_UNSIGNED_BYTE, GL_TRUE, /* normalized */ 4217 0, /* stride */ 4218 (glw::GLvoid*)(intptr_t)m_color_data_offset); 4219 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed."); 4220 4221 m_gl.enableVertexAttribArray(m_attribute_color_location); /* index */ 4222 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed."); 4223 } 4224 else 4225 { 4226 m_gl.vertexAttrib4f(m_attribute_color_location, 1.0f, 1.0f, 1.0f, 1.0f); 4227 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttrib4f() call failed."); 4228 4229 m_gl.disableVertexAttribArray(m_attribute_color_location); 4230 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisableVertexAttribArray() call failed."); 4231 } 4232 4233 if (m_ibo_usage != IBO_USAGE_NONE) 4234 { 4235 m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sparse_bo); 4236 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4237 } /* if (m_use_ibo) */ 4238 4239 /* If we were requested to do so, decommit the pages we have just uploaded 4240 * the data to. 4241 */ 4242 if (decommit_data_pages_after_upload) 4243 { 4244 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 4245 m_data_size_rounded, GL_FALSE); /* commit */ 4246 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 4247 4248 m_pages_committed = false; 4249 } /* if (decommit_data_pages_after_upload) */ 4250 } 4251 4252 /** Initializes GL objects used across all test case iterations. 4253 * 4254 * Called once during BufferStorage test run-time. 4255 */ 4256 bool QuadsBufferStorageTestCase::initTestCaseGlobal() 4257 { 4258 bool result = true; 4259 4260 /* Set up the texture object */ 4261 DE_ASSERT(m_to == 0); 4262 4263 m_gl.genTextures(1, &m_to); 4264 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed."); 4265 4266 m_gl.bindTexture(GL_TEXTURE_2D, m_to); 4267 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed."); 4268 4269 m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */ 4270 GL_RGBA8, m_to_width, m_to_height); 4271 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed."); 4272 4273 /* Set up the framebuffer object */ 4274 DE_ASSERT(m_fbo == 0); 4275 4276 m_gl.genFramebuffers(1, &m_fbo); 4277 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed."); 4278 4279 m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 4280 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed."); 4281 4282 m_gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to, 0); /* level */ 4283 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferTexture2D() call failed."); 4284 4285 /* Set up the vertex array object */ 4286 DE_ASSERT(m_vao == 0); 4287 4288 m_gl.genVertexArrays(1, &m_vao); 4289 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed."); 4290 4291 m_gl.bindVertexArray(m_vao); 4292 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed."); 4293 4294 /* Init a helper BO */ 4295 initHelperBO(); 4296 4297 /* Set up the program object */ 4298 const char* fs_body = "#version 430 core\n" 4299 "\n" 4300 "flat in vec4 fs_color;\n" 4301 " out vec4 color;\n" 4302 "\n" 4303 "void main()\n" 4304 "{\n" 4305 " color = fs_color;\n" 4306 "}\n"; 4307 4308 const char* vs_body = "#version 430 core\n" 4309 "\n" 4310 "in vec4 color;\n" 4311 "in vec4 position;\n" 4312 "\n" 4313 "flat out vec4 fs_color;\n" 4314 "\n" 4315 "void main()\n" 4316 "{\n" 4317 " fs_color = color;\n" 4318 " gl_Position = position;\n" 4319 "}\n"; 4320 4321 const unsigned int attribute_locations[] = { m_attribute_color_location, m_attribute_position_location }; 4322 const char* attribute_names[] = { "color", "position" }; 4323 const unsigned int n_attributes = sizeof(attribute_locations) / sizeof(attribute_locations[0]); 4324 4325 DE_ASSERT(m_po == 0); 4326 4327 m_po = SparseBufferTestUtilities::createProgram(m_gl, &fs_body, 1, /* n_fs_body_parts */ 4328 &vs_body, 1, attribute_names, attribute_locations, 4329 n_attributes); /* n_vs_body_parts */ 4330 4331 if (m_po == 0) 4332 { 4333 result = false; 4334 4335 goto end; 4336 } 4337 4338 end: 4339 return result; 4340 } 4341 4342 /** Initializes GL objects which are needed for a single test case iteration. 4343 * 4344 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 4345 * to release these objects. 4346 **/ 4347 bool QuadsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 4348 { 4349 bool result = true; 4350 4351 /* Cache the BO id, if not cached already */ 4352 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 4353 4354 m_sparse_bo = sparse_bo; 4355 4356 return result; 4357 } 4358 4359 /** Constructor. 4360 * 4361 * @param gl GL entry-points container 4362 * @param testContext CTS test context 4363 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 4364 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 4365 */ 4366 QueryBufferStorageTestCase::QueryBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, 4367 glw::GLint page_size) 4368 : m_gl(gl) 4369 , m_helper_bo(0) 4370 , m_n_triangles(15) 4371 , m_page_size(page_size) 4372 , m_po(0) 4373 , m_qo(0) 4374 , m_sparse_bo(0) 4375 , m_sparse_bo_size(0) 4376 , m_sparse_bo_size_rounded(0) 4377 , m_testCtx(testContext) 4378 , m_vao(0) 4379 { 4380 /* Left blank on purpose */ 4381 } 4382 4383 /** Releases all GL objects used across all test case iterations. 4384 * 4385 * Called once during BufferStorage test run-time. 4386 */ 4387 void QueryBufferStorageTestCase::deinitTestCaseGlobal() 4388 { 4389 if (m_helper_bo != 0) 4390 { 4391 m_gl.deleteBuffers(1, &m_helper_bo); 4392 4393 m_helper_bo = 0; 4394 } 4395 4396 if (m_po != 0) 4397 { 4398 m_gl.deleteProgram(m_po); 4399 4400 m_po = 0; 4401 } 4402 4403 if (m_qo != 0) 4404 { 4405 m_gl.deleteQueries(1, &m_qo); 4406 4407 m_qo = 0; 4408 } 4409 4410 if (m_vao != 0) 4411 { 4412 m_gl.deleteVertexArrays(1, &m_vao); 4413 4414 m_vao = 0; 4415 } 4416 } 4417 4418 /** Releases temporary GL objects, created specifically for one test case iteration. */ 4419 void QueryBufferStorageTestCase::deinitTestCaseIteration() 4420 { 4421 if (m_sparse_bo != 0) 4422 { 4423 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 4424 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4425 4426 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 4427 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 4428 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 4429 4430 m_sparse_bo = 0; 4431 } 4432 } 4433 4434 /** Executes a single test iteration. The BufferStorage test will call this method 4435 * numerously during its life-time, testing various valid flag combinations applied 4436 * to the tested sparse buffer object at glBufferStorage() call time. 4437 * 4438 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 4439 * call to set up the sparse buffer's storage. 4440 * 4441 * @return true if the test case executed correctly, false otherwise. 4442 */ 4443 bool QueryBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 4444 { 4445 (void)sparse_bo_storage_flags; 4446 static const unsigned char data_r8_zero = 0; 4447 bool result = true; 4448 4449 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo); 4450 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4451 4452 m_gl.useProgram(m_po); 4453 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 4454 4455 /* Run two separate iterations: 4456 * 4457 * a) The page holding the query result value is committed. 4458 * b) The page is not committed. 4459 */ 4460 for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration) 4461 { 4462 const bool should_commit_page = (n_iteration == 0); 4463 4464 /* Set up the memory page commitment */ 4465 m_gl.bufferPageCommitmentARB(GL_QUERY_BUFFER, 0, /* offset */ 4466 m_sparse_bo_size_rounded, should_commit_page ? GL_TRUE : GL_FALSE); 4467 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 4468 4469 /* Run the draw call */ 4470 m_gl.beginQuery(GL_PRIMITIVES_GENERATED, m_qo); 4471 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginQuery() call failed."); 4472 4473 m_gl.drawArrays(GL_TRIANGLES, 0, /* first */ 4474 m_n_triangles * 3); 4475 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed."); 4476 4477 m_gl.endQuery(GL_PRIMITIVES_GENERATED); 4478 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndQuery() call failed."); 4479 4480 /* Copy the query result to the sparse buffer */ 4481 for (unsigned int n_getter_call = 0; n_getter_call < 4; ++n_getter_call) 4482 { 4483 glw::GLsizei result_n_bytes; 4484 4485 switch (n_getter_call) 4486 { 4487 case 0: 4488 { 4489 result_n_bytes = sizeof(glw::GLint); 4490 m_gl.getQueryObjectiv(m_qo, GL_QUERY_RESULT, (glw::GLint*)0); /* params */ 4491 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectiv() call failed."); 4492 4493 break; 4494 } 4495 4496 case 1: 4497 { 4498 result_n_bytes = sizeof(glw::GLint); 4499 m_gl.getQueryObjectuiv(m_qo, GL_QUERY_RESULT, (glw::GLuint*)0); /* params */ 4500 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectuiv() call failed."); 4501 4502 break; 4503 } 4504 4505 case 2: 4506 { 4507 result_n_bytes = sizeof(glw::GLint64); 4508 m_gl.getQueryObjecti64v(m_qo, GL_QUERY_RESULT, (glw::GLint64*)0); 4509 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjecti64v() call failed."); 4510 4511 break; 4512 } 4513 4514 case 3: 4515 { 4516 result_n_bytes = sizeof(glw::GLint64); 4517 m_gl.getQueryObjectui64v(m_qo, GL_QUERY_RESULT, (glw::GLuint64*)0); 4518 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectui64v() call failed."); 4519 4520 break; 4521 } 4522 4523 default: 4524 { 4525 TCU_FAIL("Invalid getter call type"); 4526 } 4527 } /* switch (n_getter_call) */ 4528 4529 /* Verify the query result */ 4530 if (should_commit_page) 4531 { 4532 const glw::GLint64* result_ptr = NULL; 4533 4534 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo); 4535 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4536 4537 m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_r8_zero); 4538 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed."); 4539 4540 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 4541 0, /* writeOffset */ 4542 result_n_bytes); 4543 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 4544 4545 result_ptr = (const glw::GLint64*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY); 4546 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed."); 4547 4548 if (*result_ptr != m_n_triangles) 4549 { 4550 m_testCtx.getLog() << tcu::TestLog::Message 4551 << "Invalid query result stored in a sparse buffer. Found: " 4552 "[" 4553 << *result_ptr << "]" 4554 ", expected: " 4555 "[" 4556 << m_n_triangles << "]" << tcu::TestLog::EndMessage; 4557 4558 result = false; 4559 } 4560 4561 m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER); 4562 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 4563 } /* for (all query getter call types) */ 4564 } /* if (should_commit_page) */ 4565 } /* for (both iterations) */ 4566 4567 return result; 4568 } 4569 4570 /** Initializes GL objects used across all test case iterations. 4571 * 4572 * Called once during BufferStorage test run-time. 4573 */ 4574 bool QueryBufferStorageTestCase::initTestCaseGlobal() 4575 { 4576 /* Determine sparse buffer storage size */ 4577 m_sparse_bo_size = sizeof(glw::GLuint64); 4578 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size); 4579 4580 /* Set up the test program object */ 4581 static const char* vs_body = "#version 140\n" 4582 "\n" 4583 "void main()\n" 4584 "{\n" 4585 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" 4586 "}\n"; 4587 4588 m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */ 4589 0, /* n_fs_body_parts */ 4590 &vs_body, 1, /* n_vs_body_parts */ 4591 DE_NULL, /* attribute_names */ 4592 DE_NULL, /* attribute_locations */ 4593 0); /* n_attribute_locations */ 4594 4595 if (m_po == 0) 4596 { 4597 TCU_FAIL("Test program linking failure"); 4598 } 4599 4600 /* Set up the helper buffer object */ 4601 m_gl.genBuffers(1, &m_helper_bo); 4602 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 4603 4604 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo); 4605 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4606 4607 m_gl.bufferStorage(GL_COPY_WRITE_BUFFER, sizeof(glw::GLint64), DE_NULL, /* data */ 4608 GL_MAP_READ_BIT); 4609 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 4610 4611 /* Set up the test query object */ 4612 m_gl.genQueries(1, &m_qo); 4613 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenQueries() call failed."); 4614 4615 /* Set up the VAO */ 4616 m_gl.genVertexArrays(1, &m_vao); 4617 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed."); 4618 4619 m_gl.bindVertexArray(m_vao); 4620 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed."); 4621 4622 return true; 4623 } 4624 4625 /** Initializes GL objects which are needed for a single test case iteration. 4626 * 4627 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 4628 * to release these objects. 4629 **/ 4630 bool QueryBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 4631 { 4632 bool result = true; 4633 4634 /* Cache the BO id, if not cached already */ 4635 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 4636 4637 m_sparse_bo = sparse_bo; 4638 4639 /* Set up the sparse buffer. */ 4640 m_gl.bindBuffer(GL_QUERY_BUFFER, m_sparse_bo); 4641 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4642 4643 return result; 4644 } 4645 4646 /** Constructor. 4647 * 4648 * @param gl GL entry-points container 4649 * @param testContext CTS test context 4650 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 4651 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 4652 */ 4653 SSBOStorageTestCase::SSBOStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size) 4654 : m_gl(gl) 4655 , m_helper_bo(0) 4656 , m_page_size(page_size) 4657 , m_po(0) 4658 , m_po_local_wg_size(1024) 4659 , m_result_bo(0) 4660 , m_sparse_bo(0) 4661 , m_sparse_bo_size(0) 4662 , m_sparse_bo_size_rounded(0) 4663 , m_ssbo_data(DE_NULL) 4664 , m_testCtx(testContext) 4665 { 4666 /* min max for SSBO size from GL_ARB_shader_storage_buffer_object is 16mb; 4667 * 4668 * The specified amount of space lets the test write as many 4669 * ints as it's possible, with an assertion that our CS 4670 * uses a std140 layout and the SSBO only contains an unsized array. 4671 * 4672 * NOTE: 16777216 % 1024 = 0, which is awesome because we can hardcode the 4673 * local workgroup size directly in the CS. 4674 */ 4675 m_sparse_bo_size = (16777216 / (sizeof(int) * 4) /* std140 */) * (sizeof(int) * 4); 4676 m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size); 4677 } 4678 4679 /** Releases all GL objects used across all test case iterations. 4680 * 4681 * Called once during BufferStorage test run-time. 4682 */ 4683 void SSBOStorageTestCase::deinitTestCaseGlobal() 4684 { 4685 if (m_helper_bo != 0) 4686 { 4687 m_gl.deleteBuffers(1, &m_helper_bo); 4688 4689 m_helper_bo = 0; 4690 } 4691 4692 if (m_po != 0) 4693 { 4694 m_gl.deleteProgram(m_po); 4695 4696 m_po = 0; 4697 } 4698 4699 if (m_result_bo != 0) 4700 { 4701 m_gl.deleteBuffers(1, &m_result_bo); 4702 4703 m_result_bo = 0; 4704 } 4705 4706 if (m_ssbo_data != DE_NULL) 4707 { 4708 delete[] m_ssbo_data; 4709 4710 m_ssbo_data = DE_NULL; 4711 } 4712 } 4713 4714 /** Releases temporary GL objects, created specifically for one test case iteration. */ 4715 void SSBOStorageTestCase::deinitTestCaseIteration() 4716 { 4717 if (m_sparse_bo != 0) 4718 { 4719 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 4720 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4721 4722 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 4723 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 4724 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 4725 4726 m_sparse_bo = 0; 4727 } 4728 } 4729 4730 /** Executes a single test iteration. The BufferStorage test will call this method 4731 * numerously during its life-time, testing various valid flag combinations applied 4732 * to the tested sparse buffer object at glBufferStorage() call time. 4733 * 4734 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 4735 * call to set up the sparse buffer's storage. 4736 * 4737 * @return true if the test case executed correctly, false otherwise. 4738 */ 4739 bool SSBOStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 4740 { 4741 (void)sparse_bo_storage_flags; 4742 bool result = true; 4743 4744 /* Bind the program object */ 4745 m_gl.useProgram(m_po); 4746 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 4747 4748 /* Set up shader storage buffer bindings */ 4749 m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_sparse_bo); 4750 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4751 4752 m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */ 4753 m_sparse_bo); 4754 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed."); 4755 4756 /* Run the test in three iterations: 4757 * 4758 * a) All required pages are committed. 4759 * b) Only half of the pages are committed (in a zig-zag layout) 4760 * c) None of the pages are committed. 4761 */ 4762 for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration) 4763 { 4764 bool result_local = true; 4765 4766 /* Set up the shader storage buffer object's memory backing */ 4767 const bool is_zigzag_ssbo = (n_iteration == 1); 4768 unsigned int ssbo_commit_size = 0; 4769 unsigned int ssbo_commit_start_offset = 0; 4770 4771 switch (n_iteration) 4772 { 4773 case 0: 4774 case 1: 4775 { 4776 ssbo_commit_size = m_sparse_bo_size_rounded; 4777 ssbo_commit_start_offset = 0; 4778 4779 if (is_zigzag_ssbo) 4780 { 4781 const unsigned int n_pages = ssbo_commit_size / m_page_size; 4782 4783 for (unsigned int n_page = 0; n_page < n_pages; n_page += 2) 4784 { 4785 m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, m_page_size * n_page, /* offset */ 4786 m_page_size, /* size */ 4787 GL_TRUE); /* commit */ 4788 } /* for (all memory pages) */ 4789 } 4790 else 4791 { 4792 m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0, /* offset */ 4793 ssbo_commit_size, GL_TRUE); /* commit */ 4794 } 4795 4796 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed."); 4797 4798 break; 4799 } 4800 4801 case 2: 4802 { 4803 /* Use no physical memory backing */ 4804 break; 4805 } 4806 4807 default: 4808 { 4809 TCU_FAIL("Unrecognized iteration index"); 4810 } 4811 } /* switch (n_iteration) */ 4812 4813 /* Set up bindings for the copy op */ 4814 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 4815 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo); 4816 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 4817 4818 /* Set up the sparse buffer's data storage */ 4819 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 4820 0, /* writeOffset */ 4821 m_sparse_bo_size); 4822 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 4823 4824 /* Run the compute program */ 4825 DE_ASSERT((m_sparse_bo_size % m_po_local_wg_size) == 0); 4826 4827 m_gl.dispatchCompute(m_sparse_bo_size / m_po_local_wg_size, 1, /* num_groups_y */ 4828 1); /* num_groups_z */ 4829 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed."); 4830 4831 /* Flush the caches */ 4832 m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); 4833 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed."); 4834 4835 /* Copy SSBO's storage to a mappable result BO */ 4836 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo); 4837 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_result_bo); 4838 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 4839 4840 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 4841 0, /* writeOffset */ 4842 m_sparse_bo_size); 4843 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 4844 4845 /* Map the result BO to the process space */ 4846 unsigned int current_ssbo_offset = 0; 4847 const unsigned int* ssbo_data_ptr = (const unsigned int*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY); 4848 4849 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed."); 4850 4851 for (unsigned int n_invocation = 0; current_ssbo_offset < m_sparse_bo_size && result_local; ++n_invocation, 4852 current_ssbo_offset = static_cast<unsigned int>(current_ssbo_offset + 4853 (sizeof(int) * 4 /* std140 */))) 4854 { 4855 const unsigned int n_page = current_ssbo_offset / m_page_size; 4856 4857 if ((is_zigzag_ssbo && (n_page % 2) == 0) || 4858 (!is_zigzag_ssbo && (current_ssbo_offset >= ssbo_commit_start_offset && 4859 current_ssbo_offset < (ssbo_commit_start_offset + ssbo_commit_size)))) 4860 { 4861 if (ssbo_data_ptr[n_invocation * 4] != (n_invocation + 1)) 4862 { 4863 m_testCtx.getLog() << tcu::TestLog::Message << "Value written to the SSBO at byte " 4864 "[" 4865 << (sizeof(int) * n_invocation) << "]" 4866 " is invalid. Found:" 4867 << "[" << ssbo_data_ptr[n_invocation * 4] << "]" 4868 ", expected:" 4869 << "[" << (n_invocation + 1) << "]" << tcu::TestLog::EndMessage; 4870 4871 result_local = false; 4872 } 4873 } /* if (ssbo_data_ptr[n_texel] != 1) */ 4874 } /* for (all result values) */ 4875 4876 result &= result_local; 4877 4878 m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER); 4879 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 4880 4881 /* Remove the physical backing from the sparse buffer */ 4882 m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0, /* offset */ 4883 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 4884 4885 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 4886 } /* for (three iterations) */ 4887 4888 return result; 4889 } 4890 4891 /** Initializes GL objects used across all test case iterations. 4892 * 4893 * Called once during BufferStorage test run-time. 4894 */ 4895 bool SSBOStorageTestCase::initTestCaseGlobal() 4896 { 4897 /* Set up the test program */ 4898 static const char* cs_body = 4899 "#version 430 core\n" 4900 "\n" 4901 "layout(local_size_x = 1024) in;\n" 4902 "\n" 4903 "layout(std140, binding = 0) buffer data\n" 4904 "{\n" 4905 " restrict uint io_values[];\n" 4906 "};\n" 4907 "\n" 4908 "void main()\n" 4909 "{\n" 4910 " uint value_index = gl_GlobalInvocationID.x;\n" 4911 " uint new_value = (io_values[value_index] == value_index) ? (value_index + 1u) : value_index;\n" 4912 "\n" 4913 " io_values[value_index] = new_value;\n" 4914 "}\n"; 4915 4916 m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */ 4917 4918 /* Set up a data buffer we will use to initialize the SSBO with default data. 4919 * 4920 * CS uses a std140 layout for the SSBO, so we need to add the additional padding. 4921 */ 4922 DE_ASSERT((m_sparse_bo_size) != 0); 4923 DE_ASSERT((m_sparse_bo_size % (sizeof(int) * 4)) == 0); 4924 DE_ASSERT((m_sparse_bo_size % 1024) == 0); 4925 4926 m_ssbo_data = new unsigned int[m_sparse_bo_size / sizeof(int)]; 4927 4928 memset(m_ssbo_data, 0, m_sparse_bo_size); 4929 4930 for (unsigned int index = 0; index < m_sparse_bo_size / sizeof(int) / 4; ++index) 4931 { 4932 /* Mind the std140 rules for arrays of ints */ 4933 m_ssbo_data[4 * index] = index; 4934 } 4935 4936 /* During execution, we will need to use a helper buffer object. The BO will hold 4937 * data we will be copying into the sparse buffer object for each iteration. 4938 */ 4939 m_gl.genBuffers(1, &m_helper_bo); 4940 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 4941 4942 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 4943 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4944 4945 m_gl.bufferData(GL_COPY_READ_BUFFER, m_sparse_bo_size, m_ssbo_data, GL_STATIC_DRAW); 4946 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed."); 4947 4948 /* To retrieve the data written to a sparse SSBO, we need to use another 4949 * non-sparse helper BO. 4950 */ 4951 m_gl.genBuffers(1, &m_result_bo); 4952 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 4953 4954 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_result_bo); 4955 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 4956 4957 m_gl.bufferData(GL_ARRAY_BUFFER, m_sparse_bo_size, DE_NULL, /* data */ 4958 GL_STATIC_DRAW); 4959 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed."); 4960 4961 return true; 4962 } 4963 4964 /** Initializes GL objects which are needed for a single test case iteration. 4965 * 4966 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 4967 * to release these objects. 4968 **/ 4969 bool SSBOStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 4970 { 4971 bool result = true; 4972 4973 /* Cache the BO id, if not cached already */ 4974 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 4975 4976 m_sparse_bo = sparse_bo; 4977 4978 return result; 4979 } 4980 4981 /** Constructor. 4982 * 4983 * @param gl GL entry-points container 4984 * @param testContext CTS test context 4985 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 4986 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 4987 * @param all_pages_committed true to provide memory backing for all memory pages holding data used by the test. 4988 * false to leave some of them uncommitted. 4989 */ 4990 TransformFeedbackBufferStorageTestCase::TransformFeedbackBufferStorageTestCase(const glw::Functions& gl, 4991 tcu::TestContext& testContext, 4992 glw::GLint page_size, 4993 bool all_pages_committed) 4994 : m_all_pages_committed(all_pages_committed) 4995 , m_data_bo(0) 4996 , m_data_bo_index_data_offset(0) 4997 , m_data_bo_indexed_indirect_arg_offset(0) 4998 , m_data_bo_indexed_mdi_arg_offset(0) 4999 , m_data_bo_regular_indirect_arg_offset(0) 5000 , m_data_bo_regular_mdi_arg_offset(0) 5001 , m_data_bo_size(0) 5002 , m_draw_call_baseInstance(1231) 5003 , m_draw_call_baseVertex(65537) 5004 , m_draw_call_first(913) 5005 , m_draw_call_firstIndex(4) 5006 , m_gl(gl) 5007 , m_helper_bo(0) 5008 , m_index_data(DE_NULL) 5009 , m_index_data_size(0) 5010 , m_indirect_arg_data(DE_NULL) 5011 , m_indirect_arg_data_size(0) 5012 , m_min_memory_page_span(4) /* as per test spec */ 5013 , m_multidrawcall_drawcount(-1) 5014 , m_multidrawcall_primcount(-1) 5015 , m_n_instances_to_test(4) 5016 , m_n_vertices_per_instance(0) 5017 , m_page_size(page_size) 5018 , m_po_ia(0) 5019 , m_po_sa(0) 5020 , m_result_bo(0) 5021 , m_result_bo_size(0) 5022 , m_result_bo_size_rounded(0) 5023 , m_testCtx(testContext) 5024 , m_vao(0) 5025 { 5026 /* Left blank on purpose */ 5027 } 5028 5029 /** Releases all GL objects used across all test case iterations. 5030 * 5031 * Called once during BufferStorage test run-time. 5032 */ 5033 void TransformFeedbackBufferStorageTestCase::deinitTestCaseGlobal() 5034 { 5035 if (m_data_bo != 0) 5036 { 5037 m_gl.deleteBuffers(1, &m_data_bo); 5038 5039 m_data_bo = 0; 5040 } 5041 5042 if (m_helper_bo != 0) 5043 { 5044 m_gl.deleteBuffers(1, &m_helper_bo); 5045 5046 m_helper_bo = 0; 5047 } 5048 5049 if (m_index_data != DE_NULL) 5050 { 5051 delete[] m_index_data; 5052 5053 m_index_data = DE_NULL; 5054 } 5055 5056 if (m_indirect_arg_data != DE_NULL) 5057 { 5058 delete[] m_indirect_arg_data; 5059 5060 m_indirect_arg_data = DE_NULL; 5061 } 5062 5063 if (m_po_ia != 0) 5064 { 5065 m_gl.deleteProgram(m_po_ia); 5066 5067 m_po_ia = 0; 5068 } 5069 5070 if (m_po_sa != 0) 5071 { 5072 m_gl.deleteProgram(m_po_sa); 5073 5074 m_po_sa = 0; 5075 } 5076 5077 if (m_result_bo != 0) 5078 { 5079 m_gl.deleteBuffers(1, &m_result_bo); 5080 5081 m_result_bo = 0; 5082 } 5083 5084 if (m_vao != 0) 5085 { 5086 m_gl.deleteVertexArrays(1, &m_vao); 5087 5088 m_vao = 0; 5089 } 5090 } 5091 5092 /** Executes a single test iteration. The BufferStorage test will call this method 5093 * numerously during its life-time, testing various valid flag combinations applied 5094 * to the tested sparse buffer object at glBufferStorage() call time. 5095 * 5096 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 5097 * call to set up the sparse buffer's storage. 5098 * 5099 * @return true if the test case executed correctly, false otherwise. 5100 */ 5101 bool TransformFeedbackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 5102 { 5103 bool result = true; 5104 5105 /* Iterate through two different transform feedback modes we need to test */ 5106 for (unsigned int n_tf_type = 0; n_tf_type < 2; /* interleaved & separate attribs */ 5107 ++n_tf_type) 5108 { 5109 const bool is_ia_iteration = (n_tf_type == 0); 5110 5111 /* Bind the test PO to the context */ 5112 m_gl.useProgram(is_ia_iteration ? m_po_ia : m_po_sa); 5113 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 5114 5115 /* Set up TF general binding, which is needed for a glClearBufferData() call 5116 * we'll be firing shortly. 5117 */ 5118 m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, /* needed for the subsequent glClearBufferData() call */ 5119 m_result_bo); 5120 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 5121 5122 /* Iterate through all draw call types */ 5123 for (unsigned int n_draw_call_type = 0; n_draw_call_type < DRAW_CALL_COUNT; ++n_draw_call_type) 5124 { 5125 int draw_call_count = 0; /* != 1 for multi-draw calls only */ 5126 int draw_call_first_instance_id[2] = { -1 }; 5127 int draw_call_first_vertex_id[2] = { -1 }; 5128 int draw_call_n_instances[2] = { 0 }; 5129 int draw_call_n_vertices[2] = { 0 }; 5130 bool draw_call_is_vertex_id_ascending = false; 5131 const _draw_call draw_call_type = (_draw_call)n_draw_call_type; 5132 unsigned int n_result_bytes_per_instance[2] = { 0 }; 5133 const unsigned int n_result_bytes_per_vertex = sizeof(unsigned int) * 2; 5134 unsigned int n_result_bytes_total = 0; 5135 glw::GLuint* result_ptr = DE_NULL; 5136 5137 m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_data_bo); 5138 m_gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_data_bo); 5139 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 5140 5141 /* Commit pages needed to execute transform feed-back */ 5142 if (m_all_pages_committed) 5143 { 5144 m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */ 5145 m_result_bo_size_rounded, GL_TRUE); /* commit */ 5146 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 5147 } 5148 else 5149 { 5150 for (unsigned int n_page = 0; n_page < m_result_bo_size_rounded / m_page_size; ++n_page) 5151 { 5152 m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, n_page * m_page_size, /* offset */ 5153 m_page_size, /* size */ 5154 (n_page % 2 == 0) ? GL_TRUE : GL_FALSE); /* commit */ 5155 } 5156 5157 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 5158 } 5159 5160 /* Zero out the target BO before we begin the TF */ 5161 static const unsigned char data_zero = 0; 5162 5163 m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero); 5164 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed."); 5165 5166 /* Set up transform feed-back buffer bindings */ 5167 DE_ASSERT(m_result_bo_size != 0); 5168 5169 if (is_ia_iteration) 5170 { 5171 DE_ASSERT(m_result_bo != 0); 5172 5173 m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */ 5174 m_result_bo, 0, /* offset */ 5175 m_result_bo_size); 5176 5177 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed."); 5178 } 5179 else 5180 { 5181 DE_ASSERT(m_result_bo_size % 2 == 0); 5182 5183 m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */ 5184 m_result_bo, 0, /* offset */ 5185 m_result_bo_size / 2); 5186 m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, /* index */ 5187 m_result_bo, m_result_bo_size / 2, m_result_bo_size / 2); 5188 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call(s) failed."); 5189 } 5190 5191 m_gl.beginTransformFeedback(GL_POINTS); 5192 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed."); 5193 5194 /* NOTE: Some discussion about the expected "vertex id" value: 5195 * 5196 * In GL 4.5 core spec (Feb2/2015 version), we have: 5197 * 5198 * >> 5199 * The index of any element transferred to the GL by DrawElementsOneInstance 5200 * is referred to as its vertex ID, and may be read by a vertex shader as 5201 * gl_VertexID. The vertex ID of the ith element transferred is the sum of 5202 * basevertex and the value stored in the currently bound element array buffer at 5203 * offset indices +i. 5204 * << 5205 * 5206 * So for glDrawElements*() derivatives, we will be expecting gl_VertexID to be set to 5207 * (basevertex + index[i] + i) 5208 * 5209 * DrawArrays does not support the "base vertex" concept at all: 5210 * 5211 * >> 5212 * The index of any element transferred to the GL by DrawArraysOneInstance 5213 * is referred to as its vertex ID, and may be read by a vertex shader as gl_VertexID. 5214 * The vertex ID of the ith element transferred is first + i. 5215 * << 5216 * 5217 * For regular draw calls, gl_VertexID should be of form: 5218 * 5219 * (first + i) 5220 * 5221 * In both cases, gl_InstanceID does NOT include the baseinstance value, as per: 5222 * 5223 * >> 5224 * If an enabled vertex attribute array is instanced (it has a non-zero divisor as 5225 * specified by VertexAttribDivisor), the element index that is transferred to the GL, 5226 * for all vertices, is given by 5227 * 5228 * floor(instance / divisor) + baseinstance 5229 * 5230 * The value of instance may be read by a vertex shader as gl_InstanceID, as 5231 * described in section 11.1.3.9 5232 * << 5233 */ 5234 switch (draw_call_type) 5235 { 5236 case DRAW_CALL_INDEXED: 5237 { 5238 m_gl.drawElements(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT, 5239 (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset); 5240 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed."); 5241 5242 draw_call_count = 1; 5243 draw_call_first_instance_id[0] = 0; 5244 draw_call_first_vertex_id[0] = m_n_vertices_per_instance; 5245 draw_call_is_vertex_id_ascending = false; 5246 draw_call_n_instances[0] = 1; 5247 draw_call_n_vertices[0] = m_n_vertices_per_instance; 5248 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_n_vertices_per_instance; 5249 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5250 5251 break; 5252 } 5253 5254 case DRAW_CALL_INDEXED_BASE_VERTEX: 5255 { 5256 m_gl.drawElementsBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT, 5257 (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset, 5258 m_draw_call_baseVertex); 5259 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsBaseVertex() call failed."); 5260 5261 draw_call_count = 1; 5262 draw_call_first_instance_id[0] = 0; 5263 draw_call_first_vertex_id[0] = m_draw_call_baseVertex + m_n_vertices_per_instance; 5264 draw_call_is_vertex_id_ascending = false; 5265 draw_call_n_instances[0] = 1; 5266 draw_call_n_vertices[0] = m_n_vertices_per_instance; 5267 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_n_vertices_per_instance; 5268 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5269 5270 break; 5271 } 5272 5273 case DRAW_CALL_INDEXED_INDIRECT: 5274 { 5275 m_gl.drawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT, 5276 (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_indirect_arg_offset); 5277 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsIndirect() call failed."); 5278 5279 draw_call_count = 1; 5280 draw_call_first_instance_id[0] = 0; 5281 draw_call_first_vertex_id[0] = 5282 m_draw_call_baseVertex + 5283 m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) / 5284 sizeof(unsigned int)]; 5285 draw_call_is_vertex_id_ascending = false; 5286 draw_call_n_instances[0] = m_n_instances_to_test; 5287 draw_call_n_vertices[0] = m_multidrawcall_count[1]; 5288 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * draw_call_n_vertices[0]; 5289 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5290 5291 break; 5292 } 5293 5294 case DRAW_CALL_INDEXED_INDIRECT_MULTI: 5295 { 5296 m_gl.multiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT, 5297 (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_mdi_arg_offset, 5298 m_multidrawcall_drawcount, 0); /* stride */ 5299 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsIndirect() call failed."); 5300 5301 draw_call_count = m_multidrawcall_drawcount; 5302 draw_call_first_instance_id[0] = 0; 5303 draw_call_first_instance_id[1] = 0; 5304 draw_call_first_vertex_id[0] = 5305 m_draw_call_baseVertex + 5306 m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) / 5307 sizeof(unsigned int)]; 5308 draw_call_first_vertex_id[1] = 5309 m_draw_call_baseVertex + 5310 m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) / 5311 sizeof(unsigned int)]; 5312 draw_call_is_vertex_id_ascending = false; 5313 draw_call_n_instances[0] = 1; 5314 draw_call_n_instances[1] = m_n_instances_to_test; 5315 draw_call_n_vertices[0] = m_multidrawcall_count[0]; 5316 draw_call_n_vertices[1] = m_multidrawcall_count[1]; 5317 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * draw_call_n_vertices[0]; 5318 n_result_bytes_per_instance[1] = n_result_bytes_per_vertex * draw_call_n_vertices[1]; 5319 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0] + 5320 n_result_bytes_per_instance[1] * draw_call_n_instances[1]; 5321 5322 break; 5323 } 5324 5325 case DRAW_CALL_INDEXED_MULTI: 5326 { 5327 m_gl.multiDrawElements(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT, m_multidrawcall_index, 5328 m_multidrawcall_drawcount); 5329 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElements() call failed"); 5330 5331 draw_call_count = m_multidrawcall_drawcount; 5332 draw_call_first_instance_id[0] = 0; 5333 draw_call_first_instance_id[1] = 0; 5334 draw_call_first_vertex_id[0] = 5335 m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) / 5336 sizeof(unsigned int)]; 5337 draw_call_first_vertex_id[1] = 5338 m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) / 5339 sizeof(unsigned int)]; 5340 draw_call_is_vertex_id_ascending = false; 5341 draw_call_n_instances[0] = 1; 5342 draw_call_n_instances[1] = 1; 5343 draw_call_n_vertices[0] = m_multidrawcall_count[0]; 5344 draw_call_n_vertices[1] = m_multidrawcall_count[1]; 5345 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_multidrawcall_count[0]; 5346 n_result_bytes_per_instance[1] = n_result_bytes_per_vertex * m_multidrawcall_count[1]; 5347 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0] + 5348 n_result_bytes_per_instance[1] * draw_call_n_instances[1]; 5349 5350 break; 5351 } 5352 5353 case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX: 5354 { 5355 m_gl.multiDrawElementsBaseVertex(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT, 5356 m_multidrawcall_index, m_multidrawcall_drawcount, 5357 m_multidrawcall_basevertex); 5358 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsBaseVertex() call failed."); 5359 5360 draw_call_count = m_multidrawcall_drawcount; 5361 draw_call_first_instance_id[0] = 0; 5362 draw_call_first_instance_id[1] = 0; 5363 draw_call_first_vertex_id[0] = 5364 m_multidrawcall_basevertex[0] + 5365 m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) / 5366 sizeof(unsigned int)]; 5367 draw_call_first_vertex_id[1] = 5368 m_multidrawcall_basevertex[1] + 5369 m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) / 5370 sizeof(unsigned int)]; 5371 draw_call_is_vertex_id_ascending = false; 5372 draw_call_n_instances[0] = 1; 5373 draw_call_n_instances[1] = 1; 5374 draw_call_n_vertices[0] = m_multidrawcall_count[0]; 5375 draw_call_n_vertices[1] = m_multidrawcall_count[1]; 5376 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_multidrawcall_count[0]; 5377 n_result_bytes_per_instance[1] = n_result_bytes_per_vertex * m_multidrawcall_count[1]; 5378 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0] + 5379 n_result_bytes_per_instance[1] * draw_call_n_instances[1]; 5380 5381 break; 5382 } 5383 5384 case DRAW_CALL_INSTANCED_INDEXED: 5385 { 5386 m_gl.drawElementsInstanced(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT, 5387 (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset, 5388 m_n_instances_to_test); 5389 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstanced() call failed."); 5390 5391 draw_call_count = 1; 5392 draw_call_first_instance_id[0] = 0; 5393 draw_call_first_vertex_id[0] = m_index_data[0]; 5394 draw_call_is_vertex_id_ascending = false; 5395 draw_call_n_instances[0] = m_n_instances_to_test; 5396 draw_call_n_vertices[0] = m_n_vertices_per_instance; 5397 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_n_vertices_per_instance; 5398 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5399 5400 break; 5401 } 5402 5403 case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX: 5404 { 5405 m_gl.drawElementsInstancedBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT, 5406 (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset, 5407 m_n_instances_to_test, m_draw_call_baseVertex); 5408 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertex() call failed."); 5409 5410 draw_call_count = 1; 5411 draw_call_first_instance_id[0] = 0; 5412 draw_call_first_vertex_id[0] = m_draw_call_baseVertex + m_index_data[0]; 5413 draw_call_is_vertex_id_ascending = false; 5414 draw_call_n_instances[0] = m_n_instances_to_test; 5415 draw_call_n_vertices[0] = m_n_vertices_per_instance; 5416 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_n_vertices_per_instance; 5417 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5418 5419 break; 5420 } 5421 5422 case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE: 5423 { 5424 m_gl.drawElementsInstancedBaseVertexBaseInstance( 5425 GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT, 5426 (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset, m_n_instances_to_test, 5427 m_draw_call_baseVertex, m_draw_call_baseInstance); 5428 5429 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertexBaseInstance() call failed."); 5430 5431 draw_call_count = 1; 5432 draw_call_first_instance_id[0] = 0; 5433 draw_call_first_vertex_id[0] = m_draw_call_baseVertex + m_index_data[0]; 5434 draw_call_is_vertex_id_ascending = false; 5435 draw_call_n_instances[0] = m_n_instances_to_test; 5436 draw_call_n_vertices[0] = m_n_vertices_per_instance; 5437 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_n_vertices_per_instance; 5438 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5439 5440 break; 5441 } 5442 5443 case DRAW_CALL_REGULAR: 5444 { 5445 m_gl.drawArrays(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance); 5446 5447 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed"); 5448 5449 draw_call_count = 1; 5450 draw_call_first_instance_id[0] = 0; 5451 draw_call_first_vertex_id[0] = m_draw_call_first; 5452 draw_call_is_vertex_id_ascending = true; 5453 draw_call_n_instances[0] = 1; 5454 draw_call_n_vertices[0] = m_n_vertices_per_instance; 5455 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_n_vertices_per_instance; 5456 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5457 5458 break; 5459 } 5460 5461 case DRAW_CALL_REGULAR_INDIRECT: 5462 { 5463 m_gl.drawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_indirect_arg_offset); 5464 5465 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysIndirect() call failed."); 5466 5467 draw_call_count = 1; 5468 draw_call_first_instance_id[0] = 0; 5469 draw_call_first_vertex_id[0] = m_draw_call_first; 5470 draw_call_is_vertex_id_ascending = true; 5471 draw_call_n_instances[0] = m_n_instances_to_test; 5472 draw_call_n_vertices[0] = m_multidrawcall_count[1]; 5473 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * draw_call_n_vertices[0]; 5474 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5475 5476 break; 5477 } 5478 5479 case DRAW_CALL_REGULAR_INDIRECT_MULTI: 5480 { 5481 m_gl.multiDrawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_mdi_arg_offset, 5482 m_multidrawcall_drawcount, 0); /* stride */ 5483 5484 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArraysIndirect() call failed."); 5485 5486 draw_call_count = 2; 5487 draw_call_first_instance_id[0] = 0; 5488 draw_call_first_instance_id[1] = 0; 5489 draw_call_first_vertex_id[0] = m_draw_call_first; 5490 draw_call_first_vertex_id[1] = m_draw_call_first; 5491 draw_call_is_vertex_id_ascending = true; 5492 draw_call_n_instances[0] = 1; 5493 draw_call_n_instances[1] = m_n_instances_to_test; 5494 draw_call_n_vertices[0] = m_multidrawcall_count[0]; 5495 draw_call_n_vertices[1] = m_multidrawcall_count[1]; 5496 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * draw_call_n_vertices[0]; 5497 n_result_bytes_per_instance[1] = n_result_bytes_per_vertex * draw_call_n_vertices[1]; 5498 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0] + 5499 n_result_bytes_per_instance[1] * draw_call_n_instances[1]; 5500 5501 break; 5502 } 5503 5504 case DRAW_CALL_REGULAR_INSTANCED: 5505 { 5506 m_gl.drawArraysInstanced(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance, 5507 m_n_instances_to_test); 5508 5509 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed."); 5510 5511 draw_call_count = 1; 5512 draw_call_first_instance_id[0] = 0; 5513 draw_call_first_vertex_id[0] = m_draw_call_first; 5514 draw_call_is_vertex_id_ascending = true; 5515 draw_call_n_instances[0] = m_n_instances_to_test; 5516 draw_call_n_vertices[0] = m_n_vertices_per_instance; 5517 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * draw_call_n_vertices[0]; 5518 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5519 5520 break; 5521 } 5522 5523 case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE: 5524 { 5525 m_gl.drawArraysInstancedBaseInstance(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance, 5526 m_n_instances_to_test, m_draw_call_baseInstance); 5527 5528 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstancedBaseInstance() call failed."); 5529 5530 draw_call_count = 1; 5531 draw_call_first_instance_id[0] = 0; 5532 draw_call_first_vertex_id[0] = m_draw_call_first; 5533 draw_call_is_vertex_id_ascending = true; 5534 draw_call_n_instances[0] = m_n_instances_to_test; 5535 draw_call_n_vertices[0] = m_n_vertices_per_instance; 5536 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * draw_call_n_vertices[0]; 5537 n_result_bytes_total = n_result_bytes_per_instance[0] * draw_call_n_instances[0]; 5538 5539 break; 5540 } 5541 5542 case DRAW_CALL_REGULAR_MULTI: 5543 { 5544 m_gl.multiDrawArrays(GL_POINTS, m_multidrawcall_first, m_multidrawcall_count, 5545 m_multidrawcall_drawcount); 5546 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArrays() call failed."); 5547 5548 draw_call_count = m_multidrawcall_drawcount; 5549 draw_call_first_instance_id[0] = 0; 5550 draw_call_first_instance_id[1] = 0; 5551 draw_call_first_vertex_id[0] = m_multidrawcall_first[0]; 5552 draw_call_first_vertex_id[1] = m_multidrawcall_first[1]; 5553 draw_call_is_vertex_id_ascending = true; 5554 draw_call_n_instances[0] = 1; 5555 draw_call_n_instances[1] = 1; 5556 draw_call_n_vertices[0] = m_multidrawcall_count[0]; 5557 draw_call_n_vertices[1] = m_multidrawcall_count[1]; 5558 n_result_bytes_per_instance[0] = n_result_bytes_per_vertex * m_multidrawcall_count[0]; 5559 n_result_bytes_per_instance[1] = n_result_bytes_per_vertex * m_multidrawcall_count[1]; 5560 n_result_bytes_total = n_result_bytes_per_instance[0] + n_result_bytes_per_instance[1]; 5561 5562 break; 5563 } 5564 5565 default: 5566 { 5567 TCU_FAIL("Unrecognized draw call type"); 5568 } 5569 } /* switch (draw_call_type) */ 5570 5571 DE_ASSERT(n_result_bytes_total <= m_result_bo_size); 5572 5573 m_gl.endTransformFeedback(); 5574 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed."); 5575 5576 /* Retrieve the captured data */ 5577 glw::GLuint mappable_bo_id = m_helper_bo; 5578 unsigned int mappable_bo_start_offset = 0; 5579 5580 /* We cannot map the result BO storage directly into process space, since 5581 * it's a sparse buffer. Copy the generated data to a helper BO and map 5582 * that BO instead. */ 5583 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_result_bo); 5584 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo); 5585 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 5586 5587 if (is_ia_iteration) 5588 { 5589 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 5590 0, /* writeOffset */ 5591 n_result_bytes_total); 5592 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 5593 } 5594 else 5595 { 5596 DE_ASSERT((n_result_bytes_total % 2) == 0); 5597 5598 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 5599 0, /* writeOffset */ 5600 n_result_bytes_total / 2); 5601 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 5602 m_result_bo_size / 2, /* readOffset */ 5603 m_result_bo_size / 2, /* writeOffset */ 5604 n_result_bytes_total / 2); /* size */ 5605 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 5606 } 5607 5608 m_gl.bindBuffer(GL_ARRAY_BUFFER, mappable_bo_id); 5609 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 5610 5611 result_ptr = (unsigned int*)m_gl.mapBufferRange(GL_ARRAY_BUFFER, mappable_bo_start_offset, m_result_bo_size, 5612 GL_MAP_READ_BIT); 5613 5614 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed."); 5615 5616 /* Verify the generated output */ 5617 bool continue_checking = true; 5618 glw::GLuint result_instance_id_stride = 0; 5619 glw::GLuint result_vertex_id_stride = 0; 5620 5621 if (is_ia_iteration) 5622 { 5623 result_instance_id_stride = 2; 5624 result_vertex_id_stride = 2; 5625 } 5626 else 5627 { 5628 result_instance_id_stride = 1; 5629 result_vertex_id_stride = 1; 5630 } 5631 5632 /* For all draw calls.. */ 5633 for (int n_draw_call = 0; n_draw_call < draw_call_count && continue_checking; ++n_draw_call) 5634 { 5635 /* ..and resulting draw call instances.. */ 5636 for (int n_instance = 0; n_instance < draw_call_n_instances[n_draw_call] && continue_checking; 5637 ++n_instance) 5638 { 5639 DE_ASSERT((n_result_bytes_per_instance[n_draw_call] % sizeof(unsigned int)) == 0); 5640 5641 /* Determine where the result TF data start from */ 5642 const glw::GLuint expected_instance_id = draw_call_first_instance_id[n_draw_call] + n_instance; 5643 glw::GLuint* result_instance_id_traveller_ptr = DE_NULL; 5644 glw::GLuint* result_vertex_id_traveller_ptr = DE_NULL; 5645 5646 if (is_ia_iteration) 5647 { 5648 result_instance_id_traveller_ptr = result_ptr; 5649 5650 for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call) 5651 { 5652 result_instance_id_traveller_ptr += draw_call_n_instances[n_prev_draw_call] * 5653 n_result_bytes_per_instance[n_prev_draw_call] / 5654 sizeof(unsigned int); 5655 } 5656 5657 result_instance_id_traveller_ptr += 5658 n_instance * n_result_bytes_per_instance[n_draw_call] / sizeof(unsigned int); 5659 result_vertex_id_traveller_ptr = result_instance_id_traveller_ptr + 1; 5660 } /* if (is_ia_iteration) */ 5661 else 5662 { 5663 DE_ASSERT((m_result_bo_size % 2) == 0); 5664 5665 result_instance_id_traveller_ptr = result_ptr; 5666 5667 for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call) 5668 { 5669 result_instance_id_traveller_ptr += 5670 draw_call_n_instances[n_prev_draw_call] * 5671 n_result_bytes_per_instance[n_prev_draw_call] / 5672 2 / /* instance id..instance id data | vertex id..vertex id data */ 5673 sizeof(unsigned int); 5674 } 5675 5676 result_instance_id_traveller_ptr += 5677 n_instance * n_result_bytes_per_instance[n_draw_call] / 2 / sizeof(unsigned int); 5678 result_vertex_id_traveller_ptr = 5679 result_instance_id_traveller_ptr + (m_result_bo_size / 2) / sizeof(unsigned int); 5680 } 5681 5682 /* Start checking the generated output */ 5683 for (int n_point = 0; n_point < draw_call_n_vertices[n_draw_call] && continue_checking; ++n_point) 5684 { 5685 glw::GLuint expected_vertex_id = 1; 5686 glw::GLuint retrieved_instance_id = 2; 5687 glw::GLuint retrieved_vertex_id = 3; 5688 5689 if (draw_call_is_vertex_id_ascending) 5690 { 5691 expected_vertex_id = draw_call_first_vertex_id[n_draw_call] + n_point; 5692 } /* if (draw_call_is_vertex_id_ascending) */ 5693 else 5694 { 5695 if (draw_call_first_vertex_id[n_draw_call] >= n_point) 5696 { 5697 expected_vertex_id = draw_call_first_vertex_id[n_draw_call] - n_point; 5698 } 5699 else 5700 { 5701 expected_vertex_id = 0; 5702 } 5703 } 5704 5705 /* Only perform the check if the offsets refer to pages with physical backing. 5706 * 5707 * Note that, on platforms, whose page size % 4 != 0, the values can land partially in the no-man's land, 5708 * and partially in the safe zone. In such cases, skip the verification. */ 5709 const bool result_instance_id_page_has_physical_backing = 5710 (((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) == 5711 0) && 5712 ((((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) - 5713 1) / 5714 m_page_size) % 5715 2) == 0); 5716 const bool result_vertex_id_page_has_physical_backing = 5717 (((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) == 0) && 5718 ((((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) - 5719 1) / 5720 m_page_size) % 5721 2) == 0); 5722 5723 retrieved_instance_id = *result_instance_id_traveller_ptr; 5724 result_instance_id_traveller_ptr += result_instance_id_stride; 5725 5726 retrieved_vertex_id = *result_vertex_id_traveller_ptr; 5727 result_vertex_id_traveller_ptr += result_vertex_id_stride; 5728 5729 if ((result_instance_id_page_has_physical_backing && 5730 retrieved_instance_id != expected_instance_id) || 5731 (result_vertex_id_page_has_physical_backing && retrieved_vertex_id != expected_vertex_id)) 5732 { 5733 m_testCtx.getLog() 5734 << tcu::TestLog::Message << "For " 5735 "[" 5736 << getName() << "]" 5737 ", sparse BO flags " 5738 "[" 5739 << SparseBufferTestUtilities::getSparseBOFlagsString(sparse_bo_storage_flags) 5740 << "]" 5741 ", draw call type " 5742 << getDrawCallTypeString(draw_call_type) << " at index " 5743 "[" 5744 << n_draw_call << " / " << (draw_call_count - 1) << "]" 5745 ", TF mode " 5746 "[" 5747 << ((is_ia_iteration) ? "interleaved attribs" : "separate attribs") << "]" 5748 << ", instance " 5749 "[" 5750 << n_instance << " / " << (draw_call_n_instances[n_draw_call] - 1) << "]" 5751 << ", point at index " 5752 "[" 5753 << n_point << " / " << (draw_call_n_vertices[n_draw_call] - 1) << "]" 5754 << ", VS-level gl_VertexID was equal to " 5755 "[" 5756 << retrieved_vertex_id << "]" 5757 " and gl_InstanceID was set to " 5758 "[" 5759 << retrieved_instance_id << "]" 5760 ", whereas gl_VertexID of value " 5761 "[" 5762 << expected_vertex_id << "]" 5763 " and gl_InstanceID of value " 5764 "[" 5765 << expected_instance_id << "]" 5766 " were anticipated." 5767 << tcu::TestLog::EndMessage; 5768 5769 continue_checking = false; 5770 result = false; 5771 5772 break; 5773 } /* if (reported gl_InstanceID / gl_VertexID values are wrong) */ 5774 } /* for (all drawn points) */ 5775 } /* for (all instances) */ 5776 5777 /* Release memory pages we have allocated for the transform feed-back. 5778 * 5779 * NOTE: For some iterations, this call will attempt to de-commit pages which 5780 * have not been assigned physical backing. This is a valid behavior, 5781 * as per spec. 5782 */ 5783 m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */ 5784 m_result_bo_size_rounded, GL_FALSE); /* commit */ 5785 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 5786 } /* for (all draw call) */ 5787 5788 m_gl.unmapBuffer(GL_ARRAY_BUFFER); 5789 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 5790 } /* for (all draw call types) */ 5791 } /* for (both TF modes) */ 5792 5793 return result; 5794 } 5795 5796 /** Converts the internal enum to a null-terminated text string. 5797 * 5798 * @param draw_call Draw call type to return a string for. 5799 * 5800 * @return The requested string or "[?!]", if the enum was not recognized. 5801 **/ 5802 const char* TransformFeedbackBufferStorageTestCase::getDrawCallTypeString(_draw_call draw_call) 5803 { 5804 const char* result = "[?!]"; 5805 5806 switch (draw_call) 5807 { 5808 case DRAW_CALL_INDEXED: 5809 result = "glDrawElements()"; 5810 break; 5811 case DRAW_CALL_INDEXED_BASE_VERTEX: 5812 result = "glDrawElementsBaseVertex()"; 5813 break; 5814 case DRAW_CALL_INDEXED_INDIRECT: 5815 result = "glDrawElementsIndirect()"; 5816 break; 5817 case DRAW_CALL_INDEXED_INDIRECT_MULTI: 5818 result = "glMultiDrawElementIndirect()"; 5819 break; 5820 case DRAW_CALL_INDEXED_MULTI: 5821 result = "glMultiDrawElements()"; 5822 break; 5823 case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX: 5824 result = "glMultiDrawElementsBaseVertex()"; 5825 break; 5826 case DRAW_CALL_INSTANCED_INDEXED: 5827 result = "glDrawElementsInstanced()"; 5828 break; 5829 case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX: 5830 result = "glDrawElementsInstancedBaseVertex()"; 5831 break; 5832 case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE: 5833 result = "glDrawElementsInstancedBaseVertexBaseInstance()"; 5834 break; 5835 case DRAW_CALL_REGULAR: 5836 result = "glDrawArrays()"; 5837 break; 5838 case DRAW_CALL_REGULAR_INDIRECT: 5839 result = "glDrawArraysIndirect()"; 5840 break; 5841 case DRAW_CALL_REGULAR_INDIRECT_MULTI: 5842 result = "glMultiDrawArraysIndirect()"; 5843 break; 5844 case DRAW_CALL_REGULAR_INSTANCED: 5845 result = "glDrawArraysInstanced()"; 5846 break; 5847 case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE: 5848 result = "glDrawArraysInstancedBaseInstance()"; 5849 break; 5850 case DRAW_CALL_REGULAR_MULTI: 5851 result = "glMultiDrawArrays()"; 5852 break; 5853 5854 default: 5855 break; 5856 } /* switch (draw_call) */ 5857 5858 return result; 5859 } 5860 5861 /** Initializes test data buffer, and then sets up: 5862 * 5863 * - an immutable buffer object (id stored in m_data_bo), to which the test data 5864 * is copied. 5865 * - a mappable immutable buffer object (id stored in m_helper_bo) 5866 **/ 5867 void TransformFeedbackBufferStorageTestCase::initDataBO() 5868 { 5869 initTestData(); 5870 5871 /* Initialize data BO (the BO which holds index + indirect draw call args */ 5872 DE_ASSERT(m_data_bo == 0); 5873 5874 m_gl.genBuffers(1, &m_data_bo); 5875 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 5876 5877 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_data_bo); 5878 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 5879 5880 m_gl.bufferStorage(GL_ARRAY_BUFFER, m_data_bo_size, DE_NULL, GL_DYNAMIC_STORAGE_BIT); 5881 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 5882 5883 m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_indexed_indirect_arg_offset, m_indirect_arg_data_size, 5884 m_indirect_arg_data); 5885 m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_index_data_offset, m_index_data_size, m_index_data); 5886 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call(s) failed."); 5887 5888 /* Generate & bind a helper BO we need to copy the data to from the sparse BO 5889 * if direct mapping is not possible. 5890 */ 5891 DE_ASSERT(m_result_bo_size != 0); 5892 DE_ASSERT(m_result_bo == 0); 5893 DE_ASSERT(m_helper_bo == 0); 5894 5895 m_gl.genBuffers(1, &m_helper_bo); 5896 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 5897 5898 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo); 5899 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 5900 5901 m_gl.bufferStorage(GL_ARRAY_BUFFER, m_result_bo_size, DE_NULL, /* data */ 5902 GL_MAP_READ_BIT); 5903 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 5904 } 5905 5906 /** Initializes GL objects used across all test case iterations. 5907 * 5908 * Called once during BufferStorage test run-time. 5909 */ 5910 bool TransformFeedbackBufferStorageTestCase::initTestCaseGlobal() 5911 { 5912 bool result = true; 5913 5914 /* Initialize test program object */ 5915 static const char* tf_varyings[] = { "instance_id", "vertex_id" }; 5916 static const unsigned int n_tf_varyings = sizeof(tf_varyings) / sizeof(tf_varyings[0]); 5917 static const char* vs_body = "#version 420 core\n" 5918 "\n" 5919 "out uint instance_id;\n" 5920 "out uint vertex_id;\n" 5921 "\n" 5922 "void main()\n" 5923 "{\n" 5924 " instance_id = gl_InstanceID;\n" 5925 " vertex_id = gl_VertexID;\n" 5926 "}\n"; 5927 5928 m_po_ia = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */ 5929 0, /* n_fs_body_parts */ 5930 &vs_body, 1, /* n_vs_body_parts */ 5931 DE_NULL, /* attribute_names */ 5932 DE_NULL, /* attribute_locations */ 5933 0, /* n_attribute_properties */ 5934 tf_varyings, n_tf_varyings, GL_INTERLEAVED_ATTRIBS); 5935 5936 m_po_sa = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */ 5937 0, /* n_fs_body_parts */ 5938 &vs_body, 1, /* n_vs_body_parts */ 5939 DE_NULL, /* attribute_names */ 5940 DE_NULL, /* attribute_locations */ 5941 0, /* n_attribute_properties */ 5942 tf_varyings, n_tf_varyings, GL_SEPARATE_ATTRIBS); 5943 5944 if (m_po_ia == 0 || m_po_sa == 0) 5945 { 5946 result = false; 5947 5948 goto end; 5949 } 5950 5951 /* Generate & bind a VAO */ 5952 m_gl.genVertexArrays(1, &m_vao); 5953 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed."); 5954 5955 m_gl.bindVertexArray(m_vao); 5956 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed."); 5957 5958 initDataBO(); 5959 5960 end: 5961 return result; 5962 } 5963 5964 /** Initializes GL objects which are needed for a single test case iteration. 5965 * 5966 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 5967 * to release these objects. 5968 **/ 5969 bool TransformFeedbackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 5970 { 5971 bool result = true; 5972 5973 /* Initialize buffer objects used by the test case */ 5974 m_result_bo = sparse_bo; 5975 5976 /* Sanity check */ 5977 DE_ASSERT(m_data_bo != 0); 5978 5979 return result; 5980 } 5981 5982 /** Sets up client-side data arrays, later uploaded to the test buffer object, used as a source for: 5983 * 5984 * - index data 5985 * - indirect draw call arguments 5986 * - multi draw call arguments 5987 **/ 5988 void TransformFeedbackBufferStorageTestCase::initTestData() 5989 { 5990 /* We need the result data to span across at least m_min_memory_page_span memory pages. 5991 * Each vertex outputs 2 * sizeof(int) = 8 bytes of data. 5992 * 5993 * For simplicity, we assume the number of bytes we calculate here is per instance. */ 5994 m_n_vertices_per_instance = static_cast<unsigned int>((m_page_size * m_min_memory_page_span / (sizeof(int) * 2))); 5995 5996 /* Let: 5997 * 5998 * index_data_size = (n of vertices per a single instance) * sizeof(unsigned int) 5999 * indexed_indirect_size = sizeof(glDrawElementsIndirect() indirect arguments) 6000 * indexed_mdi_size = sizeof(glMultiDrawElementsIndirect() indirect arguments) * 2 (single instance & multiple instances case) 6001 * regular_indirect_size = sizeof(glDrawArraysIndirect() indirect arguments) 6002 * regular_mdi_size = sizeof(glMultiDrawArraysIndirect() indirect arguments) * 2 (single instance & multiple instances case) 6003 * 6004 * 6005 * The layout we will use for the data buffer is: 6006 * 6007 * [indexed indirect arg data // Size: indexed_indirect_size bytes] 6008 * [indexed MDI arg data // Size: indexed_mdi_size bytes] 6009 * [regular indirect arg data // Size: regular_indirect_size bytes] 6010 * [regular MDI arg data // Size: regular_mdi_size bytes] 6011 * [index data // Size: index_data_size bytes] 6012 */ 6013 const unsigned int indexed_indirect_size = sizeof(unsigned int) * 5 /* as per GL spec */; 6014 const unsigned int indexed_mdi_size = sizeof(unsigned int) * 5 /* as per GL spec */ * 2; /* draw calls */ 6015 const unsigned int regular_indirect_size = sizeof(unsigned int) * 4; /* as per GL spec */ 6016 const unsigned int regular_mdi_size = sizeof(unsigned int) * 4 /* as per GL spec */ * 2; /* draw calls */ 6017 6018 m_data_bo_indexed_indirect_arg_offset = 0; 6019 m_data_bo_indexed_mdi_arg_offset = m_data_bo_indexed_indirect_arg_offset + indexed_indirect_size; 6020 m_data_bo_regular_indirect_arg_offset = m_data_bo_indexed_mdi_arg_offset + indexed_mdi_size; 6021 m_data_bo_regular_mdi_arg_offset = m_data_bo_regular_indirect_arg_offset + regular_indirect_size; 6022 m_data_bo_index_data_offset = m_data_bo_regular_mdi_arg_offset + regular_mdi_size; 6023 6024 /* Form the index data */ 6025 DE_ASSERT(m_index_data == DE_NULL); 6026 DE_ASSERT(m_draw_call_firstIndex == sizeof(unsigned int)); 6027 6028 m_index_data_size = static_cast<glw::GLuint>( 6029 (1 /* extra index, as per m_draw_call_firstIndex */ + m_n_vertices_per_instance) * sizeof(unsigned int)); 6030 m_index_data = (unsigned int*)new unsigned char[m_index_data_size]; 6031 6032 for (unsigned int n_index = 0; n_index < m_n_vertices_per_instance + 1; ++n_index) 6033 { 6034 m_index_data[n_index] = m_n_vertices_per_instance - n_index; 6035 } /* for (all available indices) */ 6036 6037 /* Set multi draw-call arguments */ 6038 m_multidrawcall_basevertex[0] = m_draw_call_baseVertex; 6039 m_multidrawcall_basevertex[1] = 257; 6040 m_multidrawcall_count[0] = m_n_vertices_per_instance; 6041 m_multidrawcall_count[1] = m_n_vertices_per_instance - 16; 6042 m_multidrawcall_drawcount = 2; 6043 m_multidrawcall_first[0] = 0; 6044 m_multidrawcall_first[1] = m_draw_call_first; 6045 m_multidrawcall_index[0] = (glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset; 6046 m_multidrawcall_index[1] = (glw::GLvoid*)(intptr_t)(m_data_bo_index_data_offset + m_draw_call_firstIndex); 6047 m_multidrawcall_primcount = m_n_instances_to_test; 6048 6049 /* Form the indirect data */ 6050 DE_ASSERT(m_indirect_arg_data == DE_NULL); 6051 6052 m_indirect_arg_data_size = m_data_bo_index_data_offset - m_data_bo_indexed_indirect_arg_offset; 6053 m_indirect_arg_data = (unsigned int*)new unsigned char[m_indirect_arg_data_size]; 6054 6055 unsigned int* indirect_arg_data_traveller_ptr = m_indirect_arg_data; 6056 6057 /* 1. Indexed indirect arg data */ 6058 DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[1]) % sizeof(unsigned int)) == 0); 6059 6060 *indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */ 6061 indirect_arg_data_traveller_ptr++; 6062 6063 *indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */ 6064 indirect_arg_data_traveller_ptr++; 6065 6066 *indirect_arg_data_traveller_ptr = static_cast<unsigned int>((unsigned int)(intptr_t)(m_multidrawcall_index[1]) / 6067 sizeof(unsigned int)); /* firstIndex */ 6068 indirect_arg_data_traveller_ptr++; 6069 6070 *indirect_arg_data_traveller_ptr = m_draw_call_baseVertex; /* baseVertex */ 6071 indirect_arg_data_traveller_ptr++; 6072 6073 *indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */ 6074 indirect_arg_data_traveller_ptr++; 6075 6076 /* 2. Indexed MDI arg data */ 6077 for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call) 6078 { 6079 DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) % sizeof(unsigned int)) == 0); 6080 6081 *indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */ 6082 indirect_arg_data_traveller_ptr++; 6083 6084 *indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* primCount */ 6085 indirect_arg_data_traveller_ptr++; 6086 6087 *indirect_arg_data_traveller_ptr = static_cast<unsigned int>( 6088 (unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) / sizeof(unsigned int)); /* firstIndex */ 6089 indirect_arg_data_traveller_ptr++; 6090 6091 *indirect_arg_data_traveller_ptr = m_draw_call_baseVertex; 6092 indirect_arg_data_traveller_ptr++; 6093 6094 *indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; 6095 indirect_arg_data_traveller_ptr++; 6096 } /* for (both single-instanced and multi-instanced cases) */ 6097 6098 /* 3. Regular indirect arg data */ 6099 *indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */ 6100 indirect_arg_data_traveller_ptr++; 6101 6102 *indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */ 6103 indirect_arg_data_traveller_ptr++; 6104 6105 *indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */ 6106 indirect_arg_data_traveller_ptr++; 6107 6108 *indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */ 6109 indirect_arg_data_traveller_ptr++; 6110 6111 /* 4. Regular MDI arg data */ 6112 for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call) 6113 { 6114 *indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */ 6115 indirect_arg_data_traveller_ptr++; 6116 6117 *indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* instanceCount */ 6118 indirect_arg_data_traveller_ptr++; 6119 6120 *indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */ 6121 indirect_arg_data_traveller_ptr++; 6122 6123 *indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */ 6124 indirect_arg_data_traveller_ptr++; 6125 } /* for (both single-instanced and multi-instanced cases) */ 6126 6127 /* Store the number of bytes we will need to allocate for the data BO */ 6128 m_data_bo_size = m_index_data_size + m_indirect_arg_data_size; 6129 6130 /* Determine the number of bytes we will need to have at hand to hold all the captured TF varyings. 6131 * The equation below takes into account the heaviest draw call the test will ever issue. 6132 */ 6133 m_result_bo_size = 6134 static_cast<glw::GLuint>(sizeof(unsigned int) * 2 /* TF varyings per vertex */ * 6135 (m_multidrawcall_count[0] + m_multidrawcall_count[1]) * m_multidrawcall_primcount); 6136 m_result_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_result_bo_size, m_page_size); 6137 6138 /* Sanity checks */ 6139 DE_ASSERT(m_min_memory_page_span > 0); 6140 DE_ASSERT(m_page_size > 0); 6141 DE_ASSERT(m_result_bo_size >= (m_min_memory_page_span * m_page_size)); 6142 } 6143 6144 /** Constructor. 6145 * 6146 * @param gl GL entry-points container 6147 * @param testContext CTS test context 6148 * @param page_size Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query. 6149 * @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point. 6150 */ 6151 UniformBufferStorageTestCase::UniformBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, 6152 glw::GLint page_size) 6153 : m_gl(gl) 6154 , m_gl_uniform_buffer_offset_alignment_value(0) 6155 , m_helper_bo(0) 6156 , m_n_pages_to_use(4) 6157 , m_n_ubo_uints(0) 6158 , m_page_size(page_size) 6159 , m_po(0) 6160 , m_sparse_bo(0) 6161 , m_sparse_bo_data_size(0) 6162 , m_sparse_bo_data_start_offset(0) 6163 , m_sparse_bo_size(0) 6164 , m_sparse_bo_size_rounded(0) 6165 , m_testCtx(testContext) 6166 , m_tf_bo(0) 6167 , m_ubo_data(DE_NULL) 6168 , m_vao(0) 6169 { 6170 if ((m_n_pages_to_use % 2) != 0) 6171 { 6172 DE_ASSERT(DE_FALSE); 6173 } 6174 } 6175 6176 /** Releases all GL objects used across all test case iterations. 6177 * 6178 * Called once during BufferStorage test run-time. 6179 */ 6180 void UniformBufferStorageTestCase::deinitTestCaseGlobal() 6181 { 6182 if (m_helper_bo != 0) 6183 { 6184 m_gl.deleteBuffers(1, &m_helper_bo); 6185 6186 m_helper_bo = 0; 6187 } 6188 6189 if (m_po != 0) 6190 { 6191 m_gl.deleteProgram(m_po); 6192 6193 m_po = 0; 6194 } 6195 6196 if (m_tf_bo != 0) 6197 { 6198 m_gl.deleteBuffers(1, &m_tf_bo); 6199 6200 m_tf_bo = 0; 6201 } 6202 6203 if (m_ubo_data != DE_NULL) 6204 { 6205 delete[] m_ubo_data; 6206 6207 m_ubo_data = DE_NULL; 6208 } 6209 6210 if (m_vao != 0) 6211 { 6212 m_gl.deleteVertexArrays(1, &m_vao); 6213 6214 m_vao = 0; 6215 } 6216 } 6217 6218 /** Releases temporary GL objects, created specifically for one test case iteration. */ 6219 void UniformBufferStorageTestCase::deinitTestCaseIteration() 6220 { 6221 if (m_sparse_bo != 0) 6222 { 6223 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 6224 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 6225 6226 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */ 6227 m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 6228 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 6229 6230 m_sparse_bo = 0; 6231 } 6232 } 6233 6234 /** Executes a single test iteration. The BufferStorage test will call this method 6235 * numerously during its life-time, testing various valid flag combinations applied 6236 * to the tested sparse buffer object at glBufferStorage() call time. 6237 * 6238 * @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage() 6239 * call to set up the sparse buffer's storage. 6240 * 6241 * @return true if the test case executed correctly, false otherwise. 6242 */ 6243 bool UniformBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags) 6244 { 6245 (void)sparse_bo_storage_flags; 6246 bool result = true; 6247 6248 m_gl.bindBufferRange(GL_UNIFORM_BUFFER, 0, /* index */ 6249 m_sparse_bo, m_sparse_bo_data_start_offset, m_sparse_bo_data_size); 6250 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed."); 6251 6252 /* Run the test in three iterations: 6253 * 6254 * 1) Whole UBO storage is backed by physical backing. 6255 * 2) Half the UBO storage is backed by physical backing. 6256 * 3) None of the UBO storage is backed by physical backing. 6257 */ 6258 for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration) 6259 { 6260 bool result_local = true; 6261 unsigned int ubo_commit_size = 0; 6262 unsigned int ubo_commit_start_offset = 0; 6263 6264 switch (n_iteration) 6265 { 6266 case 0: 6267 { 6268 ubo_commit_size = m_sparse_bo_data_size; 6269 ubo_commit_start_offset = m_sparse_bo_data_start_offset; 6270 6271 break; 6272 } 6273 6274 case 1: 6275 { 6276 DE_ASSERT((m_sparse_bo_data_size % 2) == 0); 6277 DE_ASSERT((m_sparse_bo_data_size % m_page_size) == 0); 6278 6279 ubo_commit_size = m_sparse_bo_data_size / 2; 6280 ubo_commit_start_offset = m_sparse_bo_data_start_offset; 6281 6282 break; 6283 } 6284 6285 case 2: 6286 { 6287 /* The default values do just fine */ 6288 6289 break; 6290 } 6291 6292 default: 6293 { 6294 TCU_FAIL("Invalid iteration index"); 6295 } 6296 } /* switch (n_iteration) */ 6297 6298 m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, ubo_commit_start_offset, ubo_commit_size, GL_TRUE); /* commit */ 6299 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 6300 6301 /* Copy the UBO data */ 6302 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */ 6303 ubo_commit_start_offset, ubo_commit_size); 6304 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed."); 6305 6306 /* Issue the draw call to execute the test */ 6307 m_gl.useProgram(m_po); 6308 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed."); 6309 6310 m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo); 6311 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 6312 6313 m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */ 6314 m_tf_bo); 6315 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed."); 6316 6317 m_gl.beginTransformFeedback(GL_POINTS); 6318 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed."); 6319 6320 m_gl.drawArrays(GL_POINTS, 0, /* first */ 6321 m_n_ubo_uints); 6322 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed."); 6323 6324 m_gl.endTransformFeedback(); 6325 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed."); 6326 6327 /* Retrieve the data, verify the output */ 6328 const unsigned int* result_data_ptr = 6329 (const unsigned int*)m_gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); 6330 unsigned int ubo_data_offset = m_sparse_bo_data_start_offset; 6331 6332 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed."); 6333 6334 for (unsigned int n_vertex = 0; n_vertex < m_n_ubo_uints && result_local; 6335 ++n_vertex, ubo_data_offset = static_cast<unsigned int>(ubo_data_offset + 4 * sizeof(unsigned int))) 6336 { 6337 const bool is_ub_data_physically_backed = (ubo_data_offset >= ubo_commit_start_offset && 6338 ubo_data_offset < (ubo_commit_start_offset + ubo_commit_size)) ? 6339 1 : 6340 0; 6341 unsigned int expected_value = -1; 6342 const unsigned int retrieved_value = result_data_ptr[n_vertex]; 6343 6344 if (is_ub_data_physically_backed) 6345 { 6346 expected_value = 1; 6347 } 6348 else 6349 { 6350 /* Read ops applied against non-committed sparse buffers return an undefined value. 6351 */ 6352 continue; 6353 } 6354 6355 if (expected_value != retrieved_value) 6356 { 6357 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value " 6358 "(" 6359 << retrieved_value << ") " 6360 "found at index " 6361 "(" 6362 << n_vertex << ")" 6363 ", instead of the expected value " 6364 "(" 6365 << expected_value << ")" 6366 ". Iteration index:" 6367 "(" 6368 << n_iteration << ")" << tcu::TestLog::EndMessage; 6369 6370 result_local = false; 6371 } 6372 } 6373 6374 result &= result_local; 6375 6376 /* Clean up in anticipation for the next iteration */ 6377 static const unsigned char data_zero_r8 = 0; 6378 6379 m_gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); 6380 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed."); 6381 6382 m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero_r8); 6383 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed."); 6384 6385 m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */ 6386 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed."); 6387 } /* for (all three iterations) */ 6388 6389 return result; 6390 } 6391 6392 /** Initializes GL objects used across all test case iterations. 6393 * 6394 * Called once during BufferStorage test run-time. 6395 */ 6396 bool UniformBufferStorageTestCase::initTestCaseGlobal() 6397 { 6398 /* Cache GL constant values */ 6399 glw::GLint gl_max_uniform_block_size_value = 0; 6400 6401 m_gl.getIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gl_max_uniform_block_size_value); 6402 m_gl.getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_gl_uniform_buffer_offset_alignment_value); 6403 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call(s) failed."); 6404 6405 /* Determine the number of uints we can access at once from a single VS invocation */ 6406 DE_ASSERT(gl_max_uniform_block_size_value >= 1); 6407 6408 /* Account for the fact that in std140 layout, array elements will be rounded up 6409 * to the size of a vec4, i.e. 16 bytes. */ 6410 m_n_ubo_uints = static_cast<unsigned int>(gl_max_uniform_block_size_value / (4 * sizeof(unsigned int))); 6411 6412 /* Prepare the test program */ 6413 std::stringstream vs_body_define_sstream; 6414 std::string vs_body_define_string; 6415 6416 const char* tf_varying = "result"; 6417 const char* vs_body_preamble = "#version 140\n" 6418 "\n"; 6419 6420 const char* vs_body_main = "\n" 6421 "layout(std140) uniform data\n" 6422 "{\n" 6423 " uint data_input[N_UBO_UINTS];" 6424 "};\n" 6425 "\n" 6426 "out uint result;\n" 6427 "\n" 6428 "void main()\n" 6429 "{\n" 6430 " result = (data_input[gl_VertexID] == uint(gl_VertexID) ) ? 1u : 0u;\n" 6431 "}"; 6432 6433 vs_body_define_sstream << "#define N_UBO_UINTS (" << m_n_ubo_uints << ")\n"; 6434 vs_body_define_string = vs_body_define_sstream.str(); 6435 6436 const char* vs_body_parts[] = { vs_body_preamble, vs_body_define_string.c_str(), vs_body_main }; 6437 const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]); 6438 6439 m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */ 6440 0, /* n_fs_body_parts */ 6441 vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names */ 6442 DE_NULL, /* attribute_locations */ 6443 0, /* n_attribute_properties */ 6444 &tf_varying, 1, /* n_tf_varyings */ 6445 GL_INTERLEAVED_ATTRIBS); 6446 6447 if (m_po == 0) 6448 { 6449 TCU_FAIL("The test program failed to link"); 6450 } 6451 6452 /* Determine the number of bytes the sparse buffer needs to be able to have 6453 * a physical backing or. 6454 * 6455 * We will provide physical backing for twice the required size and then use 6456 * a region in the centered of the allocated memory block. 6457 * 6458 * NOTE: We need to be able to use an offset which is aligned to both the page size, 6459 * and the UB offset alignment. 6460 * */ 6461 m_sparse_bo_data_size = static_cast<unsigned int>(sizeof(unsigned int) * m_page_size); 6462 m_sparse_bo_size = (m_page_size * m_gl_uniform_buffer_offset_alignment_value) * 2; 6463 6464 if (m_sparse_bo_size < m_sparse_bo_data_size * 2) 6465 { 6466 m_sparse_bo_size = m_sparse_bo_data_size * 2; 6467 } 6468 6469 m_sparse_bo_size_rounded = m_sparse_bo_size; /* rounded to the page size by default */ 6470 m_sparse_bo_data_start_offset = (m_sparse_bo_size - m_sparse_bo_data_size) / 2; 6471 6472 /* Set up the TFBO storage */ 6473 const unsigned tfbo_size = static_cast<unsigned int>(sizeof(unsigned int) * m_n_ubo_uints); 6474 6475 m_gl.genBuffers(1, &m_tf_bo); 6476 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 6477 6478 m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo); 6479 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 6480 6481 m_gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, tfbo_size, DE_NULL, /* data */ 6482 GL_MAP_READ_BIT); 6483 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 6484 6485 /* Set up the UBO contents. We're actually setting up an immutable BO here, 6486 * but we'll use its contents for a copy op, executed at the beginning of 6487 * each iteration. 6488 */ 6489 unsigned int* ubo_data_traveller_ptr = DE_NULL; 6490 6491 DE_ASSERT((m_sparse_bo_data_size % sizeof(unsigned int)) == 0); 6492 6493 m_ubo_data = new (std::nothrow) unsigned char[m_sparse_bo_data_size]; 6494 ubo_data_traveller_ptr = (unsigned int*)m_ubo_data; 6495 6496 for (unsigned int n_vertex = 0; n_vertex < m_sparse_bo_data_size / (4 * sizeof(unsigned int)); ++n_vertex) 6497 { 6498 *ubo_data_traveller_ptr = n_vertex; 6499 ubo_data_traveller_ptr += 4; 6500 } 6501 6502 m_gl.genBuffers(1, &m_helper_bo); 6503 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed."); 6504 6505 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 6506 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 6507 6508 /* Set up helper BO storage */ 6509 m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_data_size, m_ubo_data, 0); /* flags */ 6510 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed."); 6511 6512 /* Set up the VAO */ 6513 m_gl.genVertexArrays(1, &m_vao); 6514 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed."); 6515 6516 m_gl.bindVertexArray(m_vao); 6517 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed."); 6518 6519 return true; 6520 } 6521 6522 /** Initializes GL objects which are needed for a single test case iteration. 6523 * 6524 * deinitTestCaseIteration() will be called after the test case is executed in ::execute() 6525 * to release these objects. 6526 **/ 6527 bool UniformBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo) 6528 { 6529 bool result = true; 6530 6531 /* Cache the BO id, if not cached already */ 6532 DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo); 6533 6534 m_sparse_bo = sparse_bo; 6535 6536 /* Set up the sparse buffer bindings. */ 6537 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo); 6538 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed."); 6539 6540 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo); 6541 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 6542 6543 m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo); 6544 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed."); 6545 6546 return result; 6547 } 6548 6549 /** Constructor. 6550 * 6551 * @param context Rendering context 6552 * @param name Test name 6553 * @param description Test description 6554 */ 6555 BufferStorageTest::BufferStorageTest(deqp::Context& context) 6556 : TestCase(context, "BufferStorageTest", "Tests various interactions between sparse buffers and other API areas") 6557 , m_sparse_bo(0) 6558 { 6559 /* Left blank intentionally */ 6560 } 6561 6562 /** Tears down any GL objects set up to run the test. */ 6563 void BufferStorageTest::deinit() 6564 { 6565 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 6566 6567 /* De-initialize all test the test cases */ 6568 for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase) 6569 { 6570 (*itTestCase)->deinitTestCaseGlobal(); 6571 6572 delete (*itTestCase); 6573 } /* for (all registered test case objects) */ 6574 6575 m_testCases.clear(); 6576 6577 if (m_sparse_bo != 0) 6578 { 6579 gl.deleteBuffers(1, &m_sparse_bo); 6580 6581 m_sparse_bo = 0; 6582 } 6583 } 6584 6585 /** Stub init method */ 6586 void BufferStorageTest::init() 6587 { 6588 /* We cannot initialize the test case objects here as there are cases where there 6589 * is no rendering context bound to the thread, when this method is called. */ 6590 } 6591 6592 /** Fills m_testCases with BufferStorageTestCase instances which implement the sub-cases 6593 * for the second test described in the CTS_ARB_sparse_buffer test specification 6594 **/ 6595 void BufferStorageTest::initTestCases() 6596 { 6597 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 6598 glw::GLint page_size = 0; 6599 6600 /* Retrieve "sparse buffer" GL constant values and entry-point func ptrs */ 6601 gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size); 6602 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname"); 6603 6604 /* Initialize all test case objects: 6605 * 6606 * Test cases a1-a6 */ 6607 m_testCases.push_back(new QuadsBufferStorageTestCase( 6608 gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_NONE, false)); /* use_color_data */ 6609 m_testCases.push_back(new QuadsBufferStorageTestCase( 6610 gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, false)); /* use_color_data */ 6611 m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size, 6612 QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL, 6613 false)); /* use_color_data */ 6614 m_testCases.push_back(new QuadsBufferStorageTestCase( 6615 gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, true)); /* use_color_data */ 6616 m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size, 6617 QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL, 6618 true)); /* use_color_data */ 6619 6620 /* Test case b1 */ 6621 m_testCases.push_back( 6622 new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_tf_pages_committed */ 6623 6624 /* Test case b2 */ 6625 m_testCases.push_back( 6626 new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_tf_pages_committed */ 6627 6628 /* Test case c */ 6629 m_testCases.push_back(new ClearOpsBufferStorageTestCase(gl, m_testCtx, page_size)); 6630 6631 /* Test case d */ 6632 m_testCases.push_back(new InvalidateBufferStorageTestCase(gl, m_testCtx, page_size)); 6633 6634 /* Test case e */ 6635 m_testCases.push_back( 6636 new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_pages_committed */ 6637 m_testCases.push_back( 6638 new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_pages_committed */ 6639 6640 /* Test case f */ 6641 m_testCases.push_back(new BufferTextureStorageTestCase(gl, m_context, m_testCtx, page_size)); 6642 6643 /* Test case g */ 6644 m_testCases.push_back(new CopyOpsBufferStorageTestCase(gl, m_testCtx, page_size)); 6645 6646 /* Test case h */ 6647 m_testCases.push_back(new IndirectDispatchBufferStorageTestCase(gl, m_testCtx, page_size)); 6648 6649 /* Test case i */ 6650 m_testCases.push_back(new SSBOStorageTestCase(gl, m_testCtx, page_size)); 6651 6652 /* Test case j */ 6653 m_testCases.push_back(new UniformBufferStorageTestCase(gl, m_testCtx, page_size)); 6654 6655 /* Test case k */ 6656 m_testCases.push_back(new PixelPackBufferStorageTestCase(gl, m_testCtx, page_size)); 6657 6658 /* Test case l */ 6659 m_testCases.push_back(new PixelUnpackBufferStorageTestCase(gl, m_testCtx, page_size)); 6660 6661 /* Test case m */ 6662 m_testCases.push_back(new QueryBufferStorageTestCase(gl, m_testCtx, page_size)); 6663 6664 /* Initialize all test cases */ 6665 for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase) 6666 { 6667 (*itTestCase)->initTestCaseGlobal(); 6668 } 6669 } 6670 6671 /** Executes test iteration. 6672 * 6673 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. 6674 */ 6675 tcu::TestNode::IterateResult BufferStorageTest::iterate() 6676 { 6677 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 6678 bool result = true; 6679 6680 /* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */ 6681 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer")) 6682 { 6683 throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported"); 6684 } 6685 6686 /* The buffer storage test cases require OpenGL 4.3 feature-set. */ 6687 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3))) 6688 { 6689 throw tcu::NotSupportedError("GL_ARB_sparse_buffer conformance tests require OpenGL 4.3 core feature-set"); 6690 } 6691 6692 /* Register & initialize the test case objects */ 6693 initTestCases(); 6694 6695 /* Iterate over all sparse BO flag combinations. We need to consider a total of 4 flags: 6696 * 6697 * - GL_CLIENT_STORAGE_BIT (bit 0) 6698 * - GL_DYNAMIC_STORAGE_BIT (bit 1) 6699 * - GL_MAP_COHERENT_BIT (bit 2) 6700 * - GL_MAP_PERSISTENT_BIT (bit 3) 6701 * 6702 * GL_MAP_READ_BIT and GL_MAP_WRITE_BIT are excluded, since they are incompatible 6703 * with sparse buffers by definition. 6704 * 6705 * GL_SPARSE_STORAGE_BIT_ARB is assumed to be always defined. Some of the combinations are invalid. 6706 * Such loop iterations will be skipped. 6707 * */ 6708 6709 for (unsigned int n_flag_combination = 0; n_flag_combination < (1 << 4); ++n_flag_combination) 6710 { 6711 const glw::GLint flags = ((n_flag_combination & (1 << 0)) ? GL_CLIENT_STORAGE_BIT : 0) | 6712 ((n_flag_combination & (1 << 1)) ? GL_DYNAMIC_STORAGE_BIT : 0) | 6713 ((n_flag_combination & (1 << 2)) ? GL_MAP_COHERENT_BIT : 0) | 6714 ((n_flag_combination & (1 << 3)) ? GL_MAP_PERSISTENT_BIT : 0) | 6715 GL_SPARSE_STORAGE_BIT_ARB; 6716 6717 if ((flags & GL_MAP_PERSISTENT_BIT) != 0) 6718 { 6719 if ((flags & GL_MAP_READ_BIT) == 0 && (flags & GL_MAP_WRITE_BIT) == 0) 6720 { 6721 continue; 6722 } 6723 } 6724 6725 if (((flags & GL_MAP_COHERENT_BIT) != 0) && ((flags & GL_MAP_PERSISTENT_BIT) == 0)) 6726 { 6727 continue; 6728 } 6729 6730 /* Set up the sparse BO */ 6731 gl.genBuffers(1, &m_sparse_bo); 6732 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); 6733 6734 gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 6735 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); 6736 6737 gl.bufferStorage(GL_ARRAY_BUFFER, 1024768 * 1024, /* as per test spec */ 6738 DE_NULL, /* data */ 6739 flags); 6740 6741 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call failed."); 6742 6743 for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase) 6744 { 6745 gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo); 6746 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); 6747 6748 if (!(*itTestCase)->initTestCaseIteration(m_sparse_bo)) 6749 { 6750 m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName() 6751 << "] " 6752 "has failed to initialize." 6753 << tcu::TestLog::EndMessage; 6754 6755 result = false; 6756 goto end; 6757 } 6758 6759 if (!(*itTestCase)->execute(flags)) 6760 { 6761 m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName() 6762 << "] " 6763 "has failed to execute correctly." 6764 << tcu::TestLog::EndMessage; 6765 6766 result = false; 6767 } /* if (!testCaseResult) */ 6768 6769 (*itTestCase)->deinitTestCaseIteration(); 6770 } /* for (all added test cases) */ 6771 6772 /* Release the sparse BO */ 6773 gl.deleteBuffers(1, &m_sparse_bo); 6774 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() call failed."); 6775 6776 m_sparse_bo = 0; 6777 } 6778 6779 end: 6780 m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); 6781 6782 return STOP; 6783 } 6784 6785 /** Constructor. 6786 * 6787 * @param context Rendering context. 6788 */ 6789 SparseBufferTests::SparseBufferTests(deqp::Context& context) 6790 : TestCaseGroup(context, "sparse_buffer_tests", "Verify conformance of CTS_ARB_sparse_buffer implementation") 6791 { 6792 } 6793 6794 /** Initializes the test group contents. */ 6795 void SparseBufferTests::init() 6796 { 6797 addChild(new BufferStorageTest(m_context)); 6798 addChild(new NegativeTests(m_context)); 6799 addChild(new PageSizeGetterTest(m_context)); 6800 } 6801 6802 } /* gl4cts namespace */ 6803