1 #ifndef _GL4CSPARSEBUFFERTESTS_HPP 2 #define _GL4CSPARSEBUFFERTESTS_HPP 3 /*------------------------------------------------------------------------- 4 * OpenGL Conformance Test Suite 5 * ----------------------------- 6 * 7 * Copyright (c) 2015-2016 The Khronos Group Inc. 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 */ /*! 22 * \file 23 * \brief 24 */ /*-------------------------------------------------------------------*/ 25 26 /** 27 */ /*! 28 * \file gl4cSparseBufferTests.hpp 29 * \brief Conformance tests for the GL_ARB_sparse_buffer functionality. 30 */ /*-------------------------------------------------------------------*/ 31 #include "glcTestCase.hpp" 32 #include "glwDefs.hpp" 33 #include "glwEnums.hpp" 34 #include "tcuDefs.hpp" 35 #include <vector> 36 37 namespace gl4cts 38 { 39 /** Utility functions, used across many sparse buffer conformance test classes. */ 40 class SparseBufferTestUtilities 41 { 42 public: 43 /* Public methods */ 44 static unsigned int alignOffset(const unsigned int& offset, const unsigned int& value); 45 46 static glw::GLuint createComputeProgram(const glw::Functions& gl, const char** cs_body_parts, 47 unsigned int n_cs_body_parts); 48 49 static glw::GLuint createProgram(const glw::Functions& gl, const char** fs_body_parts, unsigned int n_fs_body_parts, 50 const char** vs_body_parts, unsigned int n_vs_body_parts, 51 const char** attribute_names, const unsigned int* attribute_locations, 52 unsigned int n_attribute_properties, 53 const glw::GLchar* const* tf_varyings = DE_NULL, unsigned int n_tf_varyings = 0, 54 glw::GLenum tf_varying_mode = GL_NONE); 55 56 static std::string getSparseBOFlagsString(glw::GLenum flags); 57 }; 58 59 /** * Verify glBufferPageCommitmentARB() returns GL_INVALID_ENUM if <target> is 60 * set to GL_INTERLEAVED_ATTRIBS. 61 * 62 * * Verify glBufferStorage() throws a GL_INVALID_VALUE error if <flags> is 63 * set to (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT) or 64 * (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT). 65 * 66 * * Verify glBufferPageCommitmentARB() generates a GL_INVALID_OPERATION error if 67 * it is called for an immutable BO, which has not been initialized with the 68 * GL_SPARSE_STORAGE_BIT_ARB flag. 69 * 70 * * Verify glBufferPageCommitmentARB() issues a GL_INVALID_VALUE error if <offset> 71 * is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value 72 * is equal to 1. 73 * 74 * * Verify glBufferPageCommitmentARB() emits a GL_INVALID_VALUE error if <size> 75 * is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value 76 * is equal to 1. 77 * 78 * * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <offset> is 79 * set to -1, but all other arguments are valid. 80 * 81 * * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <size> is 82 * set to -1, but all other arguments are valid. 83 * 84 * * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is 85 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to 0 and <size> 86 * argument used for the call is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 4. 87 * 88 * * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is 89 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to 90 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 1 and <size> argument used for the call 91 * is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3. 92 * 93 * * Verify that calling glMapBuffer() or glMapBufferRange() against a sparse 94 * buffer generates a GL_INVALID_OPERATION error. 95 **/ 96 class NegativeTests : public deqp::TestCase 97 { 98 public: 99 /* Public methods */ 100 NegativeTests(deqp::Context& context); 101 102 void deinit(); 103 void init(); 104 tcu::TestNode::IterateResult iterate(); 105 106 private: 107 /* Private methods */ 108 109 /* Private members */ 110 glw::GLuint m_helper_bo_id; /* never allocated actual storage; bound to GL_ELEMENT_ARRAY_BUFFER */ 111 glw::GLuint m_immutable_bo_id; /* bound to GL_COPY_READ_BUFFER */ 112 const unsigned int m_immutable_bo_size; 113 114 glw::GLuint m_sparse_bo_id; /* bound to GL_ARRAY_BUFFER */ 115 }; 116 117 /** 1. Make sure glGetBooleanv(), glGetDoublev(), glGetFloatv(), glGetIntegerv() 118 * and glGetInteger64v() recognize the new GL_SPARSE_BUFFER_PAGE_SIZE_ARB 119 * pname and return a value equal to or larger than 1, but no bigger than 65536 120 */ 121 class PageSizeGetterTest : public deqp::TestCase 122 { 123 public: 124 /* Public methods */ 125 PageSizeGetterTest(deqp::Context& context); 126 127 void deinit(); 128 void init(); 129 tcu::TestNode::IterateResult iterate(); 130 }; 131 132 /** Interface class for test case implementation for the functional test 2. */ 133 class BufferStorageTestCase 134 { 135 public: ~BufferStorageTestCase()136 virtual ~BufferStorageTestCase() 137 { 138 } 139 140 /* Public methods */ 141 virtual void deinitTestCaseGlobal() = 0; 142 virtual bool execute(glw::GLuint sparse_bo_storage_flags) = 0; 143 virtual const char* getName() = 0; 144 virtual bool initTestCaseGlobal() = 0; 145 virtual bool initTestCaseIteration(glw::GLuint sparse_bo) = 0; 146 deinitTestCaseIteration()147 virtual void deinitTestCaseIteration() 148 { 149 /* Stub by default */ 150 } 151 }; 152 153 /** Implements the test case e for the test 2: 154 * 155 * e. Use the committed sparse buffer storage to store atomic counter values. 156 * The vertex shader used for the test case should define as many ACs as 157 * supported by the platform (GL_MAX_VERTEX_ATOMIC_COUNTERS). The condition, 158 * under which each of the ACs should be incremented, can be based on 159 * gl_VertexID's value (eg. increment AC0 if gl_VertexID % 2 == 0, increment 160 * AC1 if gl_VertexID % 3 == 0, and so on). 161 * 162 * Use regular draw calls, issued consecutively for three times, for the 163 * test. 164 * Verify that both atomic counter buffer binding commands (glBindBufferBase() 165 * and glBindBufferRange() ) work correctly. 166 * 167 * The test passes if the result values are correct. 168 * 169 * The test should run in two iterations: 170 * a) All required pages are committed. 171 * b) Only half of the pages are committed. If only a single page is needed, 172 * de-commit that page before issuing the draw call. 173 */ 174 class AtomicCounterBufferStorageTestCase : public BufferStorageTestCase 175 { 176 public: 177 /* Public methods */ 178 AtomicCounterBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size, 179 bool all_pages_committed); 180 181 /* BufferStorageTestCase implementation */ 182 void deinitTestCaseGlobal(); 183 void deinitTestCaseIteration(); 184 185 bool execute(glw::GLuint sparse_bo_storage_flags); 186 bool initTestCaseGlobal(); 187 bool initTestCaseIteration(glw::GLuint sparse_bo); 188 getName()189 const char* getName() 190 { 191 return "case e"; 192 } 193 194 private: 195 /* Private fields */ 196 bool m_all_pages_committed; 197 const glw::Functions& m_gl; 198 glw::GLint m_gl_atomic_counter_uniform_array_stride; 199 glw::GLint m_gl_max_vertex_atomic_counters_value; 200 glw::GLuint m_helper_bo; 201 unsigned int m_helper_bo_size; 202 unsigned int m_helper_bo_size_rounded; 203 const unsigned int m_n_draw_calls; 204 glw::GLint m_page_size; 205 glw::GLuint m_po; 206 glw::GLuint m_sparse_bo; 207 unsigned int m_sparse_bo_data_size; 208 unsigned int m_sparse_bo_data_size_rounded; /* aligned to page size */ 209 unsigned int m_sparse_bo_data_start_offset; 210 unsigned int m_sparse_bo_data_start_offset_rounded; /* <= m_sparse_bo_data_start_offset, aligned to page size */ 211 tcu::TestContext& m_testCtx; 212 glw::GLuint m_vao; 213 }; 214 215 /** Implements the test case f for the test 2: 216 * 217 * f. Use the committed sparse buffer storage as a backing for a buffer texture 218 * object. A compute shader should inspect the contents of the texture and, 219 * for invocation-specific texels, write out 1 to a SSBO if the fetched texel 220 * was correct. Otherwise, it should write out 0. 221 * 222 * The shader storage block needs not be backed by a sparse buffer. 223 * 224 * As with previous cases, make sure both of the following scenarios are 225 * tested: 226 * 227 * a) All required pages are committed. 228 * b) Only half of the pages are committed. If only a single page is needed, 229 * de-commit that page before issuing the dispatch call. 230 * 231 * Both glTexBuffer() and glTexBufferRange() should be tested. 232 * 233 */ 234 class BufferTextureStorageTestCase : public BufferStorageTestCase 235 { 236 public: 237 /* Public methods */ 238 BufferTextureStorageTestCase(const glw::Functions& gl, deqp::Context& context, tcu::TestContext& testContext, 239 glw::GLint page_size); 240 241 /* BufferStorageTestCase implementation */ 242 void deinitTestCaseGlobal(); 243 void deinitTestCaseIteration(); 244 bool execute(glw::GLuint sparse_bo_storage_flags); 245 bool initTestCaseGlobal(); 246 bool initTestCaseIteration(glw::GLuint sparse_bo); 247 getName()248 const char* getName() 249 { 250 return "case f"; 251 } 252 253 private: 254 /* Private fields */ 255 const glw::Functions& m_gl; 256 glw::GLuint m_helper_bo; 257 unsigned char* m_helper_bo_data; 258 unsigned int m_helper_bo_data_size; 259 bool m_is_texture_buffer_range_supported; 260 glw::GLint m_page_size; 261 glw::GLuint m_po; 262 const unsigned int m_po_local_wg_size; 263 glw::GLuint m_sparse_bo; 264 unsigned int m_sparse_bo_size; 265 unsigned int m_sparse_bo_size_rounded; 266 glw::GLuint m_ssbo; 267 unsigned char* m_ssbo_zero_data; 268 unsigned int m_ssbo_zero_data_size; 269 tcu::TestContext& m_testCtx; 270 glw::GLuint m_to; 271 const unsigned int m_to_width; 272 }; 273 274 /** Implements the test case c for the test 2: 275 * 276 * c. Issue glClearBufferData() and glClearBufferSubData() calls 277 * over a sparse buffer. Make sure that all committed pages, which should 278 * have been affected by the calls, have been reset to the requested 279 * values. 280 * Try issuing glClearNamedBufferSubData() over a region, for which one 281 * of the halves is committed, and the other is not. Make sure the former 282 * has been touched, and that no crash has occurred. 283 * 284 */ 285 class ClearOpsBufferStorageTestCase : public BufferStorageTestCase 286 { 287 public: 288 /* Public methods */ 289 ClearOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size); 290 291 /* BufferStorageTestCase implementation */ 292 void deinitTestCaseGlobal(); 293 void deinitTestCaseIteration(); 294 bool execute(glw::GLuint sparse_bo_storage_flags); 295 bool initTestCaseGlobal(); 296 bool initTestCaseIteration(glw::GLuint sparse_bo); 297 getName()298 const char* getName() 299 { 300 return "case c"; 301 } 302 303 private: 304 /* Private fields */ 305 const glw::Functions& m_gl; 306 glw::GLuint m_helper_bo; /* holds m_sparse_bo_size_rounded bytes */ 307 unsigned char* m_initial_data; /* holds m_sparse_bo_size_rounded bytes */ 308 unsigned int m_n_pages_to_use; 309 glw::GLint m_page_size; 310 glw::GLuint m_sparse_bo; 311 unsigned int m_sparse_bo_size_rounded; 312 tcu::TestContext& m_testCtx; 313 }; 314 315 /** Implements the test case g for the test 2: 316 * 317 * g. Verify copy operations work correctly for cases where: 318 * 319 * I) Destination and source are different sparse BOs. 320 * II) Destination is a sparse buffer object, source is an immutable BO. 321 * III) Destination is an immutable BO, source is a sparse BO. 322 * IV) Destination and source are the same sparse BO, but refer to 323 * different, non-overlapping memory regions. 324 * 325 * and 326 * 327 * *) All pages of the source region are not committed 328 * **) Half of the pages of the source region is not committed 329 * ***) None of the pages of the source region are committed. 330 * 331 * and 332 * 333 * +) All pages of the destination region are not committed 334 * ++) Half of the pages of the destination region is not committed 335 * +++) None of the pages of the destination region are committed. 336 * 337 * Test all combinations of I-IV, *-***, and +-+++ bearing in mind that: 338 * 339 * a) reads executed on non-committed memory regions return meaningless 340 * values but MUST NOT crash GL 341 * b) writes performed on non-committed memory regions are silently 342 * ignored. 343 */ 344 class CopyOpsBufferStorageTestCase : public BufferStorageTestCase 345 { 346 public: 347 /* Public methods */ 348 CopyOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size); 349 350 /* BufferStorageTestCase implementation */ 351 void deinitTestCaseGlobal(); 352 void deinitTestCaseIteration(); 353 bool execute(glw::GLuint sparse_bo_storage_flags); 354 bool initTestCaseGlobal(); 355 bool initTestCaseIteration(glw::GLuint sparse_bo); 356 getName()357 const char* getName() 358 { 359 return "case g"; 360 } 361 362 private: 363 /* Private type definitions */ 364 typedef struct _test_case 365 { 366 glw::GLint dst_bo_commit_size; 367 glw::GLint dst_bo_commit_start_offset; 368 glw::GLuint dst_bo_sparse_id; 369 bool dst_bo_is_sparse; 370 unsigned short* dst_bo_ref_data; 371 glw::GLint dst_bo_start_offset; 372 373 glw::GLint n_bytes_to_copy; 374 375 glw::GLint src_bo_commit_size; 376 glw::GLint src_bo_commit_start_offset; 377 glw::GLuint src_bo_sparse_id; 378 bool src_bo_is_sparse; 379 unsigned short* src_bo_ref_data; 380 glw::GLint src_bo_start_offset; 381 } _test_case; 382 383 typedef std::vector<_test_case> _test_cases; 384 typedef _test_cases::const_iterator _test_cases_const_iterator; 385 typedef _test_cases::iterator _test_cases_iterator; 386 387 /* Private methods */ 388 void initReferenceData(); 389 void initTestCases(); 390 391 /* Private fields */ 392 const glw::Functions& m_gl; 393 glw::GLuint m_helper_bo; 394 glw::GLuint m_immutable_bo; 395 glw::GLint m_page_size; 396 unsigned short* m_ref_data[3]; /* [0] - immutable bo data, [1] - sparse bo[0] data, [2] - sparse bo[1] data. 397 * 398 * Each data buffer holds m_sparse_bo_size_rounded bytes. 399 */ 400 glw::GLuint m_sparse_bos[2]; /* [0] - provided by BufferStorageTest[0], [1] - managed by the test case */ 401 unsigned int m_sparse_bo_size; 402 unsigned int m_sparse_bo_size_rounded; 403 _test_cases m_test_cases; 404 tcu::TestContext& m_testCtx; 405 }; 406 407 /** Implements the test case h for the test 2: 408 * 409 * h. Verify indirect dispatch calls work correctly for the following cases: 410 * 411 * a) The arguments are taken from a committed memory page. 412 * b) The arguments are taken from a de-committed memory page. We expect 413 * the dispatch request to be silently ignored in this case. 414 * c) Half of the arguments are taken from a committed memory page, 415 * and the other half come from a de-committed memory page. Anticipated 416 * result is as per b). 417 * 418 * Each spawned compute shader invocation should increment an atomic 419 * counter. 420 * 421 */ 422 class IndirectDispatchBufferStorageTestCase : public BufferStorageTestCase 423 { 424 public: 425 /* Public methods */ 426 IndirectDispatchBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, 427 glw::GLint page_size); 428 429 /* BufferStorageTestCase implementation */ 430 void deinitTestCaseGlobal(); 431 void deinitTestCaseIteration(); 432 bool execute(glw::GLuint sparse_bo_storage_flags); 433 bool initTestCaseGlobal(); 434 bool initTestCaseIteration(glw::GLuint sparse_bo); 435 getName()436 const char* getName() 437 { 438 return "case h"; 439 } 440 441 private: 442 /* Private fields */ 443 unsigned int m_dispatch_draw_call_args_start_offset; 444 unsigned int m_expected_ac_value; 445 const glw::Functions& m_gl; 446 const unsigned int m_global_wg_size_x; 447 glw::GLuint m_helper_bo; /* stores AC value + indirect dispatch call args */ 448 const unsigned int m_local_wg_size_x; 449 glw::GLint m_page_size; 450 glw::GLuint m_po; 451 glw::GLuint m_sparse_bo; 452 unsigned int m_sparse_bo_size; 453 unsigned int m_sparse_bo_size_rounded; 454 tcu::TestContext& m_testCtx; 455 }; 456 457 /** Implements the test case d for the test 2: 458 * 459 * d. Issue glInvalidateBufferData() and glInvalidateBufferSubData() calls for 460 * sparse buffers. For the *SubData() case, make sure you test both of 461 * cases: 462 * 463 * * the whole touched region has been committed 464 * * only half of the pages have physical backing. 465 */ 466 class InvalidateBufferStorageTestCase : public BufferStorageTestCase 467 { 468 public: 469 /* Public methods */ 470 InvalidateBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size); 471 472 /* BufferStorageTestCase implementation */ 473 void deinitTestCaseGlobal(); 474 void deinitTestCaseIteration(); 475 bool execute(glw::GLuint sparse_bo_storage_flags); 476 bool initTestCaseGlobal(); 477 bool initTestCaseIteration(glw::GLuint sparse_bo); 478 getName()479 const char* getName() 480 { 481 return "case d"; 482 } 483 484 private: 485 /* Private fields */ 486 const glw::Functions& m_gl; 487 unsigned int m_n_pages_to_use; 488 const glw::GLint m_page_size; 489 glw::GLuint m_sparse_bo; 490 unsigned int m_sparse_bo_size; 491 unsigned int m_sparse_bo_size_rounded; 492 }; 493 494 /** Implement the test case k from CTS_ARB_sparse_buffer: 495 * 496 * k. Verify pixel pack functionality works correctly, when a sparse buffer 497 * is bound to the pixel pack buffer binding point. Render a black-to-white 498 * RGBA8 gradient and use glReadPixels() to read & verify the rendered 499 * data. The color attachment should be of 1024x1024 resolution. 500 * 501 * Consider three scenarios: 502 * 503 * a) All pages, to which the data is to be written to, have been committed. 504 * b) Use the same memory page commitment layout as proposed in b2. The 505 * committed pages should contain correct data. Contents the pages 506 * without the physical backing should not be verified. 507 * c) No pages have been committed. The draw & read call should not crash 508 * the driver, but the actual contents is of no relevance. 509 * 510 **/ 511 class PixelPackBufferStorageTestCase : public BufferStorageTestCase 512 { 513 public: 514 /* Public methods */ 515 PixelPackBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size); 516 517 /* BufferStorageTestCase implementation */ 518 void deinitTestCaseGlobal(); 519 void deinitTestCaseIteration(); 520 bool execute(glw::GLuint sparse_bo_storage_flags); 521 bool initTestCaseGlobal(); 522 bool initTestCaseIteration(glw::GLuint sparse_bo); 523 getName()524 const char* getName() 525 { 526 return "case k"; 527 } 528 529 private: 530 /* Private fields */ 531 glw::GLuint m_color_rb; 532 const unsigned int m_color_rb_height; 533 const unsigned int m_color_rb_width; 534 glw::GLuint m_fbo; 535 const glw::Functions& m_gl; 536 glw::GLuint m_helper_bo; 537 glw::GLint m_page_size; 538 glw::GLuint m_po; 539 unsigned char* m_ref_data_ptr; 540 unsigned int m_ref_data_size; 541 glw::GLuint m_sparse_bo; 542 unsigned int m_sparse_bo_size; 543 unsigned int m_sparse_bo_size_rounded; 544 tcu::TestContext& m_testCtx; 545 glw::GLuint m_vao; 546 }; 547 548 /** Implements the test case l for the test 2: 549 * 550 * l. Verify pixel unpack functionality works correctly, when a sparse buffer 551 * is bound to the pixel unpack buffer binding point. Use a black-to-white 552 * gradient texture data for a glTexSubImage2D() call applied against an 553 * immutable texture object's base mip-map. Read back the data with 554 * a glGetTexImage() call and verify the contents is valid. 555 * 556 * Consider three scenarios: 557 * 558 * a) All pages, from which the texture data were read from, have been 559 * committed at the glTexSubImage2D() call time. 560 * b) Use the same memory page commitment layout as proposed in b2. The 561 * test should only check contents of the committed memory pages. 562 * c) No pages have been committed at the glTexSubImage2D() call time. 563 * The upload & getter calls should not crash, but the returned 564 * contents are irrelevant in this case. 565 */ 566 class PixelUnpackBufferStorageTestCase : public BufferStorageTestCase 567 { 568 public: 569 /* Public methods */ 570 PixelUnpackBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size); 571 572 /* BufferStorageTestCase implementation */ 573 void deinitTestCaseGlobal(); 574 void deinitTestCaseIteration(); 575 bool execute(glw::GLuint sparse_bo_storage_flags); 576 bool initTestCaseGlobal(); 577 bool initTestCaseIteration(glw::GLuint sparse_bo); 578 getName()579 const char* getName() 580 { 581 return "case l"; 582 } 583 584 private: 585 /* Private fields */ 586 const glw::Functions& m_gl; 587 glw::GLuint m_helper_bo; 588 glw::GLint m_page_size; 589 unsigned char* m_read_data_ptr; 590 glw::GLuint m_sparse_bo; 591 unsigned int m_sparse_bo_size; 592 unsigned int m_sparse_bo_size_rounded; 593 tcu::TestContext& m_testCtx; 594 unsigned char* m_texture_data_ptr; 595 unsigned int m_texture_data_size; 596 glw::GLuint m_to; 597 unsigned char* m_to_data_zero; 598 const unsigned int m_to_height; 599 const unsigned int m_to_width; 600 }; 601 602 /** Implements test cases a1-a6 for the test 2: 603 * 604 * a1. Use the sparse buffer as a VBO. 605 * 606 * The render-target should be drawn a total of 100 x 100 green quads 607 * (built of triangles). Fill the buffer with vertex data (use four 608 * components, even though we need the rectangles to be rendered in 609 * screen space, in order to assure that the data-set spans across 610 * multiple pages by exceeding the maximum permitted page size of 64KB). 611 * 612 * The quads should be 5px in width & height, and be separated from each 613 * other by a delta of 5px. 614 * 615 * Render the quads to a render-target of 1024x1024 resolution. 616 * 617 * All the pages, to which the vertex data has been submitted, should 618 * be committed. The test case passes if the rendered data is correct. 619 * 620 * a2. Follow the same approach as described for a1. However, this time, 621 * after the vertex data is uploaded, the test should de-commit all the 622 * pages and attempt to do the draw call. 623 * 624 * The test passes if the GL implementation does not crash. Do not 625 * validate the rendered data. 626 * 627 * a3. Follow the same approach as described for a1. However, this time, 628 * make sure to also provide an IBO and issue an indexed draw call 629 * (both ranged and non-ranged). All required VBO and IBO pages should 630 * be committed. 631 * 632 * The pass condition described in a1 is not changed. 633 * 634 * a4. Follow the same approach as described for a2. However, this time, 635 * after the vertex and index data is uploaded, the test should de-commit 636 * pages storing both IBO and VBO data. Both draw calls should be issued 637 * then. 638 * 639 * The pass condition described in a2 is not changed. 640 * 641 * a5. Follow the same approach as described for a1. Apply the following 642 * change: 643 * 644 * - Each rectangle should now be assigned a color, exposed to the VS 645 * via a Vertex Attribute Array. The color data should come from committed 646 * sparse buffer pages. 647 * 648 * a6. Follow the same approach as described for a5. Apply the following 649 * change: 650 * 651 * - De-commit color data, after it has been uploaded. Try to execute the 652 * draw call. 653 * 654 * The test passes if the GL implementation does not crash. Do not 655 * validate the rendered data. 656 */ 657 class QuadsBufferStorageTestCase : public BufferStorageTestCase 658 { 659 public: 660 /* Type definitions */ 661 enum _ibo_usage 662 { 663 /* Use glDrawArrays() for the draw call */ 664 IBO_USAGE_NONE, 665 /* Use glDrawElements() for the draw call */ 666 IBO_USAGE_INDEXED_DRAW_CALL, 667 /* Use glDrawRangeElements() for the draw call */ 668 IBO_USAGE_INDEXED_RANGED_DRAW_CALL 669 }; 670 671 /* Public methods */ 672 QuadsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size, 673 _ibo_usage ibo_usage, bool use_color_data); 674 675 /* BufferStorageTestCase implementation */ 676 void deinitTestCaseGlobal(); 677 void deinitTestCaseIteration(); 678 bool execute(glw::GLuint sparse_bo_storage_flags); 679 bool initTestCaseGlobal(); 680 bool initTestCaseIteration(glw::GLuint sparse_bo); 681 getName()682 const char* getName() 683 { 684 return (!m_use_color_data && m_ibo_usage == IBO_USAGE_NONE) ? 685 "cases a1-a2" : 686 (!m_use_color_data && m_ibo_usage != IBO_USAGE_NONE) ? 687 "cases a3-a4" : 688 (m_use_color_data && m_ibo_usage != IBO_USAGE_NONE) ? "casea a5-a6" : "?!"; 689 } 690 691 private: 692 /* Private methods */ 693 void createTestData(unsigned char** out_data, unsigned int* out_vbo_data_offset, unsigned int* out_ibo_data_offset, 694 unsigned int* out_color_data_offset) const; 695 696 void initHelperBO(); 697 698 void initSparseBO(bool decommit_data_pages_after_upload, bool is_dynamic_storage); 699 700 /* Private fields */ 701 glw::GLuint m_attribute_color_location; 702 glw::GLuint m_attribute_position_location; 703 glw::GLuint m_color_data_offset; 704 unsigned char* m_data; 705 glw::GLuint m_data_size; /* ibo, vbo, color data */ 706 glw::GLuint m_data_size_rounded; /* rounded up to page size */ 707 glw::GLuint m_fbo; 708 const glw::Functions& m_gl; 709 glw::GLuint m_helper_bo; 710 glw::GLuint m_ibo_data_offset; 711 _ibo_usage m_ibo_usage; 712 const unsigned int m_n_quad_delta_x; 713 const unsigned int m_n_quad_delta_y; 714 const unsigned int m_n_quad_height; 715 const unsigned int m_n_quad_width; 716 const unsigned int m_n_quads_x; 717 const unsigned int m_n_quads_y; 718 unsigned int m_n_vertices_to_draw; 719 bool m_pages_committed; 720 glw::GLuint m_po; 721 glw::GLuint m_sparse_bo; 722 tcu::TestContext& m_testCtx; 723 glw::GLuint m_to; 724 const unsigned int m_to_height; 725 const unsigned int m_to_width; 726 bool m_use_color_data; 727 glw::GLuint m_vao; 728 glw::GLuint m_vbo_data_offset; 729 }; 730 731 /** Implements test case m for the test 2: 732 * 733 * m. Verify query functionality works correctly, when a sparse buffer is bound 734 * to the query buffer binding point. Render a number of triangles while 735 * a GL_PRIMITIVES_GENERATED query is enabled and the BO is bound to the 736 * GL_QUERY_BUFFER binding point. Read back the value of the query from 737 * the BO and verify it is correct using glGetQueryObjectiv(), 738 * glGetQueryObjectuiv(), glGetQueryObjecti64v() and glGetQueryObjectui64v() 739 * functions. 740 * 741 * Consider two scenarios: 742 * 743 * a) The page holding the result value is committed. 744 * b) The page holding the result value is NOT committed. In this case, 745 * the draw call glGetQueryObjectuiv() and all the getter functions should 746 * not crash, but the reported values are irrelevant. 747 */ 748 class QueryBufferStorageTestCase : public BufferStorageTestCase 749 { 750 public: 751 /* Public methods */ 752 QueryBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size); 753 754 /* BufferStorageTestCase implementation */ 755 void deinitTestCaseGlobal(); 756 void deinitTestCaseIteration(); 757 bool execute(glw::GLuint sparse_bo_storage_flags); 758 bool initTestCaseGlobal(); 759 bool initTestCaseIteration(glw::GLuint sparse_bo); 760 getName()761 const char* getName() 762 { 763 return "case m"; 764 } 765 766 private: 767 /* Private fields */ 768 const glw::Functions& m_gl; 769 glw::GLuint m_helper_bo; 770 const unsigned int m_n_triangles; 771 glw::GLint m_page_size; 772 glw::GLuint m_po; 773 glw::GLuint m_qo; 774 glw::GLuint m_sparse_bo; 775 unsigned int m_sparse_bo_size; 776 unsigned int m_sparse_bo_size_rounded; 777 tcu::TestContext& m_testCtx; 778 glw::GLuint m_vao; 779 }; 780 781 /** Implements test case i for the test 2: 782 * 783 * i. Verify a SSBO, holding an unsized array, accessed from a compute shader, 784 * contains anticipated values. Each CS invocation should only fetch 785 * a single invocation-specific value. If the value is found correct, it 786 * should increment it. 787 * 788 * The test passes if all values accessed by the CS invocations are found 789 * valid after the dispatch call. 790 * 791 * Make sure to test three scenarios: 792 * 793 * a) All values come from the committed memory pages. 794 * b) Use the same memory page commitment layout as proposed in b2. Verify 795 * only those values, which were available to the compute shader. 796 * c) None of the value exposed via SSBO are backed by physical memory. 797 * In this case, we do not really care about the outputs of the CS. 798 * We only need to ensure that GL (or the GPU) does not crash. 799 */ 800 class SSBOStorageTestCase : public BufferStorageTestCase 801 { 802 public: 803 /* Public methods */ 804 SSBOStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size); 805 806 /* BufferStorageTestCase implementation */ 807 void deinitTestCaseGlobal(); 808 void deinitTestCaseIteration(); 809 bool execute(glw::GLuint sparse_bo_storage_flags); 810 bool initTestCaseGlobal(); 811 bool initTestCaseIteration(glw::GLuint sparse_bo); 812 getName()813 const char* getName() 814 { 815 return "case i"; 816 } 817 818 private: 819 /* Private fields */ 820 const glw::Functions& m_gl; 821 glw::GLuint m_helper_bo; /* holds m_sparse_bo_size bytes */ 822 glw::GLint m_page_size; 823 glw::GLuint m_po; 824 const unsigned int m_po_local_wg_size; 825 glw::GLuint m_result_bo; 826 glw::GLuint m_sparse_bo; 827 unsigned int m_sparse_bo_size; 828 unsigned int m_sparse_bo_size_rounded; 829 unsigned int* m_ssbo_data; /* holds m_sparse_bo_size bytes */ 830 tcu::TestContext& m_testCtx; 831 }; 832 833 /** Implements test cases b1-b2 for the test 2: 834 * 835 * b1. Use a sparse buffer as a target for separate & interleaved transform 836 * feed-back (in separate iterations). A sufficient number of pages should 837 * have been committed prior to issuing any draw call. 838 * 839 * The vertex shader should output vertex ID & instance ID data to two 840 * different output variables captured by the TF. 841 * 842 * The test should only pass if the generated output is correct. 843 * 844 * For the purpose of this test, use the following draw call types: 845 * 846 * * regular 847 * * regular indirect 848 * * regular indirect multi 849 * * regular instanced 850 * * regular instanced + base instance 851 * * regular multi 852 * * indexed 853 * * indexed indirect 854 * * indexed indirect multi 855 * * indexed multi 856 * * indexed multi + base vertex 857 * * indexed + base vertex 858 * * indexed + base vertex + base instance 859 * * instanced indexed 860 * * instanced indexed + base vertex 861 * * instanced indexed + base vertex + base instance 862 * 863 * 864 * b2. Follow the same approach as described for b1. However, the commitment 865 * state of memory pages used for the TF process should be laid out in 866 * the following order: 867 * 868 * 1st page: committed 869 * 2nd page: NOT committed 870 * ... 871 * (2N) -th page: committed 872 * (2N+1)-th page: NOT committed 873 * 874 * Make sure to use at least 4 memory pages in this test case. 875 * 876 * Execute the test as described in b1, and make sure the results stored 877 * in the committed pages used by the TF process holds valid result data. 878 */ 879 class TransformFeedbackBufferStorageTestCase : public BufferStorageTestCase 880 { 881 public: 882 /* Type definitions */ 883 enum _draw_call 884 { 885 /* glDrawElements() */ 886 DRAW_CALL_INDEXED, 887 /* glDrawElementsBaseVertex() */ 888 DRAW_CALL_INDEXED_BASE_VERTEX, 889 /* glDrawElementsIndirect() */ 890 DRAW_CALL_INDEXED_INDIRECT, 891 /* glMultiDrawElementIndirect() */ 892 DRAW_CALL_INDEXED_INDIRECT_MULTI, 893 /* glMultiDrawElements() */ 894 DRAW_CALL_INDEXED_MULTI, 895 /* glMultiDrawElementsBaseVertex() */ 896 DRAW_CALL_INDEXED_MULTI_BASE_VERTEX, 897 /* glDrawElementsInstanced() */ 898 DRAW_CALL_INSTANCED_INDEXED, 899 /* glDrawElementsInstancedBaseVertex() */ 900 DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX, 901 /* glDrawElementsInstancedBaseVertexBaseInstance() */ 902 DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE, 903 /* glDrawArrays() */ 904 DRAW_CALL_REGULAR, 905 /* glDrawArraysIndirect() */ 906 DRAW_CALL_REGULAR_INDIRECT, 907 /* glMultiDrawArraysIndirect() */ 908 DRAW_CALL_REGULAR_INDIRECT_MULTI, 909 /* glDrawArraysInstanced() */ 910 DRAW_CALL_REGULAR_INSTANCED, 911 /* glDrawArraysInstancedBaseInstance() */ 912 DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE, 913 /* glMultiDrawArrays() */ 914 DRAW_CALL_REGULAR_MULTI, 915 916 /* Always last */ 917 DRAW_CALL_COUNT 918 }; 919 920 /* Public methods */ 921 TransformFeedbackBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, 922 glw::GLint page_size, bool all_pages_committed); 923 924 /* BufferStorageTestCase implementation */ 925 void deinitTestCaseGlobal(); 926 bool execute(glw::GLuint sparse_bo_storage_flags); 927 bool initTestCaseGlobal(); 928 bool initTestCaseIteration(glw::GLuint sparse_bo); 929 getName()930 const char* getName() 931 { 932 return (m_all_pages_committed) ? "case b1" : "case b2"; 933 } 934 935 private: 936 /* Private methods */ 937 const char* getDrawCallTypeString(_draw_call draw_call); 938 void initDataBO(); 939 void initTestData(); 940 941 /* Private fields */ 942 bool m_all_pages_committed; 943 glw::GLuint m_data_bo; 944 unsigned int m_data_bo_index_data_offset; 945 unsigned int m_data_bo_indexed_indirect_arg_offset; 946 unsigned int m_data_bo_indexed_mdi_arg_offset; 947 unsigned int m_data_bo_regular_indirect_arg_offset; 948 unsigned int m_data_bo_regular_mdi_arg_offset; 949 glw::GLuint m_data_bo_size; 950 const unsigned int m_draw_call_baseInstance; 951 const unsigned int m_draw_call_baseVertex; 952 const unsigned int m_draw_call_first; 953 const unsigned int m_draw_call_firstIndex; 954 const glw::Functions& m_gl; 955 glw::GLuint m_helper_bo; /* of m_result_bo_size size */ 956 glw::GLuint* m_index_data; 957 glw::GLuint m_index_data_size; 958 glw::GLuint* m_indirect_arg_data; 959 glw::GLuint m_indirect_arg_data_size; 960 const unsigned int m_min_memory_page_span; 961 glw::GLint m_multidrawcall_basevertex[2]; 962 glw::GLsizei m_multidrawcall_count[2]; 963 unsigned int m_multidrawcall_drawcount; 964 glw::GLint m_multidrawcall_first[2]; 965 glw::GLvoid* m_multidrawcall_index[2]; 966 unsigned int m_multidrawcall_primcount; 967 const unsigned int m_n_instances_to_test; 968 unsigned int m_n_vertices_per_instance; 969 glw::GLint m_page_size; 970 glw::GLuint m_po_ia; /* interleave attribs TF */ 971 glw::GLuint m_po_sa; /* separate attribs TF */ 972 glw::GLuint m_result_bo; 973 glw::GLuint m_result_bo_size; 974 glw::GLuint m_result_bo_size_rounded; 975 tcu::TestContext& m_testCtx; 976 glw::GLuint m_vao; 977 }; 978 979 /** Implements test case j for the test 2: 980 * 981 * j. Verify an UBO, backed by a sparse buffer, accessed from a vertex shader, 982 * holds values as expected. Each VS invocation should only check 983 * an invocation-specific arrayed member item and set gl_Position to 984 * vec4(1.0), if the retrieved value is valid. 985 * 986 * Make sure to test three scenarios as described for case i). 987 */ 988 class UniformBufferStorageTestCase : public BufferStorageTestCase 989 { 990 public: 991 /* Public methods */ 992 UniformBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size); 993 994 /* BufferStorageTestCase implementation */ 995 void deinitTestCaseGlobal(); 996 void deinitTestCaseIteration(); 997 bool execute(glw::GLuint sparse_bo_storage_flags); 998 bool initTestCaseGlobal(); 999 bool initTestCaseIteration(glw::GLuint sparse_bo); 1000 getName()1001 const char* getName() 1002 { 1003 return "case j"; 1004 } 1005 1006 private: 1007 /* Private fields */ 1008 const glw::Functions& m_gl; 1009 glw::GLint m_gl_uniform_buffer_offset_alignment_value; 1010 glw::GLuint m_helper_bo; 1011 const unsigned int m_n_pages_to_use; 1012 unsigned int m_n_ubo_uints; 1013 glw::GLint m_page_size; 1014 glw::GLuint m_po; 1015 glw::GLuint m_sparse_bo; 1016 unsigned int m_sparse_bo_data_size; 1017 unsigned int m_sparse_bo_data_start_offset; 1018 unsigned int m_sparse_bo_size; 1019 unsigned int m_sparse_bo_size_rounded; 1020 tcu::TestContext& m_testCtx; 1021 glw::GLuint m_tf_bo; 1022 unsigned char* m_ubo_data; 1023 glw::GLuint m_vao; 1024 }; 1025 1026 /** Implements conformance test 2 from the test specification: 1027 * 1028 * 2. Make sure glBufferStorage() accepts the new GL_SPARSE_STORAGE_BIT_ARB flag 1029 * in all valid flag combinations. For each such combination, allocate 1030 * a sparse buffer of 1GB size and verify the following test cases work as 1031 * expected. After all tests have been run for a particular flag combination, 1032 * the sparse buffer should be deleted, and a new sparse buffer should be 1033 * created, if there are any outstanding flag combinations. 1034 * 1035 * Test cases, whose verification behavior is incompatible with 1036 * the requested flag combination should skip the validation part: 1037 * 1038 * (for test case descriptions, please check test case class prototypes) 1039 */ 1040 class BufferStorageTest : public deqp::TestCase 1041 { 1042 public: 1043 /* Public methods */ 1044 BufferStorageTest(deqp::Context& context); 1045 1046 void deinit(); 1047 void init(); 1048 tcu::TestNode::IterateResult iterate(); 1049 1050 private: 1051 /* Private type definitions */ 1052 typedef std::vector<BufferStorageTestCase*> TestCasesVector; 1053 typedef TestCasesVector::const_iterator TestCasesVectorConstIterator; 1054 typedef TestCasesVector::iterator TestCasesVectorIterator; 1055 1056 /* Private methods */ 1057 void initTestCases(); 1058 1059 /* Private members */ 1060 glw::GLuint m_sparse_bo; 1061 TestCasesVector m_testCases; 1062 }; 1063 1064 /** Test group which encapsulates all sparse buffer conformance tests */ 1065 class SparseBufferTests : public deqp::TestCaseGroup 1066 { 1067 public: 1068 /* Public methods */ 1069 SparseBufferTests(deqp::Context& context); 1070 1071 void init(); 1072 1073 private: 1074 SparseBufferTests(const SparseBufferTests& other); 1075 SparseBufferTests& operator=(const SparseBufferTests& other); 1076 }; 1077 1078 } /* glcts namespace */ 1079 1080 #endif // _GL4CSPARSEBUFFERTESTS_HPP 1081