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) ? "cases a1-a2" : 685 (!m_use_color_data && m_ibo_usage != IBO_USAGE_NONE) ? "cases a3-a4" : 686 (m_use_color_data && m_ibo_usage != IBO_USAGE_NONE) ? "casea a5-a6" : 687 "?!"; 688 } 689 690 private: 691 /* Private methods */ 692 void createTestData(unsigned char **out_data, unsigned int *out_vbo_data_offset, unsigned int *out_ibo_data_offset, 693 unsigned int *out_color_data_offset) const; 694 695 void initHelperBO(); 696 697 void initSparseBO(bool decommit_data_pages_after_upload, bool is_dynamic_storage); 698 699 /* Private fields */ 700 glw::GLuint m_attribute_color_location; 701 glw::GLuint m_attribute_position_location; 702 glw::GLuint m_color_data_offset; 703 unsigned char *m_data; 704 glw::GLuint m_data_size; /* ibo, vbo, color data */ 705 glw::GLuint m_data_size_rounded; /* rounded up to page size */ 706 glw::GLuint m_fbo; 707 const glw::Functions &m_gl; 708 glw::GLuint m_helper_bo; 709 glw::GLuint m_ibo_data_offset; 710 _ibo_usage m_ibo_usage; 711 const unsigned int m_n_quad_delta_x; 712 const unsigned int m_n_quad_delta_y; 713 const unsigned int m_n_quad_height; 714 const unsigned int m_n_quad_width; 715 const unsigned int m_n_quads_x; 716 const unsigned int m_n_quads_y; 717 unsigned int m_n_vertices_to_draw; 718 bool m_pages_committed; 719 glw::GLuint m_po; 720 glw::GLuint m_sparse_bo; 721 tcu::TestContext &m_testCtx; 722 glw::GLuint m_to; 723 const unsigned int m_to_height; 724 const unsigned int m_to_width; 725 bool m_use_color_data; 726 glw::GLuint m_vao; 727 glw::GLuint m_vbo_data_offset; 728 }; 729 730 /** Implements test case m for the test 2: 731 * 732 * m. Verify query functionality works correctly, when a sparse buffer is bound 733 * to the query buffer binding point. Render a number of triangles while 734 * a GL_PRIMITIVES_GENERATED query is enabled and the BO is bound to the 735 * GL_QUERY_BUFFER binding point. Read back the value of the query from 736 * the BO and verify it is correct using glGetQueryObjectiv(), 737 * glGetQueryObjectuiv(), glGetQueryObjecti64v() and glGetQueryObjectui64v() 738 * functions. 739 * 740 * Consider two scenarios: 741 * 742 * a) The page holding the result value is committed. 743 * b) The page holding the result value is NOT committed. In this case, 744 * the draw call glGetQueryObjectuiv() and all the getter functions should 745 * not crash, but the reported values are irrelevant. 746 */ 747 class QueryBufferStorageTestCase : public BufferStorageTestCase 748 { 749 public: 750 /* Public methods */ 751 QueryBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext, glw::GLint page_size); 752 753 /* BufferStorageTestCase implementation */ 754 void deinitTestCaseGlobal(); 755 void deinitTestCaseIteration(); 756 bool execute(glw::GLuint sparse_bo_storage_flags); 757 bool initTestCaseGlobal(); 758 bool initTestCaseIteration(glw::GLuint sparse_bo); 759 getName()760 const char *getName() 761 { 762 return "case m"; 763 } 764 765 private: 766 /* Private fields */ 767 const glw::Functions &m_gl; 768 glw::GLuint m_helper_bo; 769 const unsigned int m_n_triangles; 770 glw::GLint m_page_size; 771 glw::GLuint m_po; 772 glw::GLuint m_qo; 773 glw::GLuint m_sparse_bo; 774 unsigned int m_sparse_bo_size; 775 unsigned int m_sparse_bo_size_rounded; 776 tcu::TestContext &m_testCtx; 777 glw::GLuint m_vao; 778 }; 779 780 /** Implements test case i for the test 2: 781 * 782 * i. Verify a SSBO, holding an unsized array, accessed from a compute shader, 783 * contains anticipated values. Each CS invocation should only fetch 784 * a single invocation-specific value. If the value is found correct, it 785 * should increment it. 786 * 787 * The test passes if all values accessed by the CS invocations are found 788 * valid after the dispatch call. 789 * 790 * Make sure to test three scenarios: 791 * 792 * a) All values come from the committed memory pages. 793 * b) Use the same memory page commitment layout as proposed in b2. Verify 794 * only those values, which were available to the compute shader. 795 * c) None of the value exposed via SSBO are backed by physical memory. 796 * In this case, we do not really care about the outputs of the CS. 797 * We only need to ensure that GL (or the GPU) does not crash. 798 */ 799 class SSBOStorageTestCase : public BufferStorageTestCase 800 { 801 public: 802 /* Public methods */ 803 SSBOStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext, glw::GLint page_size); 804 805 /* BufferStorageTestCase implementation */ 806 void deinitTestCaseGlobal(); 807 void deinitTestCaseIteration(); 808 bool execute(glw::GLuint sparse_bo_storage_flags); 809 bool initTestCaseGlobal(); 810 bool initTestCaseIteration(glw::GLuint sparse_bo); 811 getName()812 const char *getName() 813 { 814 return "case i"; 815 } 816 817 private: 818 /* Private fields */ 819 const glw::Functions &m_gl; 820 glw::GLuint m_helper_bo; /* holds m_sparse_bo_size bytes */ 821 glw::GLint m_page_size; 822 glw::GLuint m_po; 823 const unsigned int m_po_local_wg_size; 824 glw::GLuint m_result_bo; 825 glw::GLuint m_sparse_bo; 826 unsigned int m_sparse_bo_size; 827 unsigned int m_sparse_bo_size_rounded; 828 unsigned int *m_ssbo_data; /* holds m_sparse_bo_size bytes */ 829 tcu::TestContext &m_testCtx; 830 }; 831 832 /** Implements test cases b1-b2 for the test 2: 833 * 834 * b1. Use a sparse buffer as a target for separate & interleaved transform 835 * feed-back (in separate iterations). A sufficient number of pages should 836 * have been committed prior to issuing any draw call. 837 * 838 * The vertex shader should output vertex ID & instance ID data to two 839 * different output variables captured by the TF. 840 * 841 * The test should only pass if the generated output is correct. 842 * 843 * For the purpose of this test, use the following draw call types: 844 * 845 * * regular 846 * * regular indirect 847 * * regular indirect multi 848 * * regular instanced 849 * * regular instanced + base instance 850 * * regular multi 851 * * indexed 852 * * indexed indirect 853 * * indexed indirect multi 854 * * indexed multi 855 * * indexed multi + base vertex 856 * * indexed + base vertex 857 * * indexed + base vertex + base instance 858 * * instanced indexed 859 * * instanced indexed + base vertex 860 * * instanced indexed + base vertex + base instance 861 * 862 * 863 * b2. Follow the same approach as described for b1. However, the commitment 864 * state of memory pages used for the TF process should be laid out in 865 * the following order: 866 * 867 * 1st page: committed 868 * 2nd page: NOT committed 869 * ... 870 * (2N) -th page: committed 871 * (2N+1)-th page: NOT committed 872 * 873 * Make sure to use at least 4 memory pages in this test case. 874 * 875 * Execute the test as described in b1, and make sure the results stored 876 * in the committed pages used by the TF process holds valid result data. 877 */ 878 class TransformFeedbackBufferStorageTestCase : public BufferStorageTestCase 879 { 880 public: 881 /* Type definitions */ 882 enum _draw_call 883 { 884 /* glDrawElements() */ 885 DRAW_CALL_INDEXED, 886 /* glDrawElementsBaseVertex() */ 887 DRAW_CALL_INDEXED_BASE_VERTEX, 888 /* glDrawElementsIndirect() */ 889 DRAW_CALL_INDEXED_INDIRECT, 890 /* glMultiDrawElementIndirect() */ 891 DRAW_CALL_INDEXED_INDIRECT_MULTI, 892 /* glMultiDrawElements() */ 893 DRAW_CALL_INDEXED_MULTI, 894 /* glMultiDrawElementsBaseVertex() */ 895 DRAW_CALL_INDEXED_MULTI_BASE_VERTEX, 896 /* glDrawElementsInstanced() */ 897 DRAW_CALL_INSTANCED_INDEXED, 898 /* glDrawElementsInstancedBaseVertex() */ 899 DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX, 900 /* glDrawElementsInstancedBaseVertexBaseInstance() */ 901 DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE, 902 /* glDrawArrays() */ 903 DRAW_CALL_REGULAR, 904 /* glDrawArraysIndirect() */ 905 DRAW_CALL_REGULAR_INDIRECT, 906 /* glMultiDrawArraysIndirect() */ 907 DRAW_CALL_REGULAR_INDIRECT_MULTI, 908 /* glDrawArraysInstanced() */ 909 DRAW_CALL_REGULAR_INSTANCED, 910 /* glDrawArraysInstancedBaseInstance() */ 911 DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE, 912 /* glMultiDrawArrays() */ 913 DRAW_CALL_REGULAR_MULTI, 914 915 /* Always last */ 916 DRAW_CALL_COUNT 917 }; 918 919 /* Public methods */ 920 TransformFeedbackBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext, 921 glw::GLint page_size, bool all_pages_committed); 922 923 /* BufferStorageTestCase implementation */ 924 void deinitTestCaseGlobal(); 925 bool execute(glw::GLuint sparse_bo_storage_flags); 926 bool initTestCaseGlobal(); 927 bool initTestCaseIteration(glw::GLuint sparse_bo); 928 getName()929 const char *getName() 930 { 931 return (m_all_pages_committed) ? "case b1" : "case b2"; 932 } 933 934 private: 935 /* Private methods */ 936 const char *getDrawCallTypeString(_draw_call draw_call); 937 void initDataBO(); 938 void initTestData(); 939 940 /* Private fields */ 941 bool m_all_pages_committed; 942 glw::GLuint m_data_bo; 943 unsigned int m_data_bo_index_data_offset; 944 unsigned int m_data_bo_indexed_indirect_arg_offset; 945 unsigned int m_data_bo_indexed_mdi_arg_offset; 946 unsigned int m_data_bo_regular_indirect_arg_offset; 947 unsigned int m_data_bo_regular_mdi_arg_offset; 948 glw::GLuint m_data_bo_size; 949 const unsigned int m_draw_call_baseInstance; 950 const unsigned int m_draw_call_baseVertex; 951 const unsigned int m_draw_call_first; 952 const unsigned int m_draw_call_firstIndex; 953 const glw::Functions &m_gl; 954 glw::GLuint m_helper_bo; /* of m_result_bo_size size */ 955 glw::GLuint *m_index_data; 956 glw::GLuint m_index_data_size; 957 glw::GLuint *m_indirect_arg_data; 958 glw::GLuint m_indirect_arg_data_size; 959 const unsigned int m_min_memory_page_span; 960 glw::GLint m_multidrawcall_basevertex[2]; 961 glw::GLsizei m_multidrawcall_count[2]; 962 unsigned int m_multidrawcall_drawcount; 963 glw::GLint m_multidrawcall_first[2]; 964 glw::GLvoid *m_multidrawcall_index[2]; 965 unsigned int m_multidrawcall_primcount; 966 const unsigned int m_n_instances_to_test; 967 unsigned int m_n_vertices_per_instance; 968 glw::GLint m_page_size; 969 glw::GLuint m_po_ia; /* interleave attribs TF */ 970 glw::GLuint m_po_sa; /* separate attribs TF */ 971 glw::GLuint m_result_bo; 972 glw::GLuint m_result_bo_size; 973 glw::GLuint m_result_bo_size_rounded; 974 tcu::TestContext &m_testCtx; 975 glw::GLuint m_vao; 976 }; 977 978 /** Implements test case j for the test 2: 979 * 980 * j. Verify an UBO, backed by a sparse buffer, accessed from a vertex shader, 981 * holds values as expected. Each VS invocation should only check 982 * an invocation-specific arrayed member item and set gl_Position to 983 * vec4(1.0), if the retrieved value is valid. 984 * 985 * Make sure to test three scenarios as described for case i). 986 */ 987 class UniformBufferStorageTestCase : public BufferStorageTestCase 988 { 989 public: 990 /* Public methods */ 991 UniformBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext, glw::GLint page_size); 992 993 /* BufferStorageTestCase implementation */ 994 void deinitTestCaseGlobal(); 995 void deinitTestCaseIteration(); 996 bool execute(glw::GLuint sparse_bo_storage_flags); 997 bool initTestCaseGlobal(); 998 bool initTestCaseIteration(glw::GLuint sparse_bo); 999 getName()1000 const char *getName() 1001 { 1002 return "case j"; 1003 } 1004 1005 private: 1006 /* Private fields */ 1007 const glw::Functions &m_gl; 1008 glw::GLint m_gl_uniform_buffer_offset_alignment_value; 1009 glw::GLuint m_helper_bo; 1010 const unsigned int m_n_pages_to_use; 1011 unsigned int m_n_ubo_uints; 1012 glw::GLint m_page_size; 1013 glw::GLuint m_po; 1014 glw::GLuint m_sparse_bo; 1015 unsigned int m_sparse_bo_data_size; 1016 unsigned int m_sparse_bo_data_start_offset; 1017 unsigned int m_sparse_bo_size; 1018 unsigned int m_sparse_bo_size_rounded; 1019 tcu::TestContext &m_testCtx; 1020 glw::GLuint m_tf_bo; 1021 unsigned char *m_ubo_data; 1022 glw::GLuint m_vao; 1023 }; 1024 1025 /** Implements conformance test 2 from the test specification: 1026 * 1027 * 2. Make sure glBufferStorage() accepts the new GL_SPARSE_STORAGE_BIT_ARB flag 1028 * in all valid flag combinations. For each such combination, allocate 1029 * a sparse buffer of 1GB size and verify the following test cases work as 1030 * expected. After all tests have been run for a particular flag combination, 1031 * the sparse buffer should be deleted, and a new sparse buffer should be 1032 * created, if there are any outstanding flag combinations. 1033 * 1034 * Test cases, whose verification behavior is incompatible with 1035 * the requested flag combination should skip the validation part: 1036 * 1037 * (for test case descriptions, please check test case class prototypes) 1038 */ 1039 class BufferStorageTest : public deqp::TestCase 1040 { 1041 public: 1042 /* Public methods */ 1043 BufferStorageTest(deqp::Context &context); 1044 1045 void deinit(); 1046 void init(); 1047 tcu::TestNode::IterateResult iterate(); 1048 1049 private: 1050 /* Private type definitions */ 1051 typedef std::vector<BufferStorageTestCase *> TestCasesVector; 1052 typedef TestCasesVector::const_iterator TestCasesVectorConstIterator; 1053 typedef TestCasesVector::iterator TestCasesVectorIterator; 1054 1055 /* Private methods */ 1056 void initTestCases(); 1057 1058 /* Private members */ 1059 glw::GLuint m_sparse_bo; 1060 TestCasesVector m_testCases; 1061 }; 1062 1063 /** Test group which encapsulates all sparse buffer conformance tests */ 1064 class SparseBufferTests : public deqp::TestCaseGroup 1065 { 1066 public: 1067 /* Public methods */ 1068 SparseBufferTests(deqp::Context &context); 1069 1070 void init(); 1071 1072 private: 1073 SparseBufferTests(const SparseBufferTests &other); 1074 SparseBufferTests &operator=(const SparseBufferTests &other); 1075 }; 1076 1077 } // namespace gl4cts 1078 1079 #endif // _GL4CSPARSEBUFFERTESTS_HPP 1080