xref: /aosp_15_r20/external/deqp/external/openglcts/modules/gl/gl4cSparseBufferTests.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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