• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = nullptr, 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,
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 (m_all_pages_committed ? "case_e_all_pages" : "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 
240     /* BufferStorageTestCase implementation */
241     void deinitTestCaseGlobal();
242     void deinitTestCaseIteration();
243     bool execute(glw::GLuint sparse_bo_storage_flags);
244     bool initTestCaseGlobal();
245     bool initTestCaseIteration(glw::GLuint sparse_bo);
246 
getName()247     const char *getName()
248     {
249         return "case_f";
250     }
251 
252 private:
253     /* Private fields */
254     const glw::Functions &m_gl;
255     glw::GLuint m_helper_bo;
256     unsigned char *m_helper_bo_data;
257     unsigned int m_helper_bo_data_size;
258     bool m_is_texture_buffer_range_supported;
259     glw::GLint m_page_size;
260     glw::GLuint m_po;
261     const unsigned int m_po_local_wg_size;
262     glw::GLuint m_sparse_bo;
263     unsigned int m_sparse_bo_size;
264     unsigned int m_sparse_bo_size_rounded;
265     glw::GLuint m_ssbo;
266     unsigned char *m_ssbo_zero_data;
267     unsigned int m_ssbo_zero_data_size;
268     tcu::TestContext &m_testCtx;
269     glw::GLuint m_to;
270     const unsigned int m_to_width;
271 };
272 
273 /** Implements the test case c for the test 2:
274  *
275  * c.  Issue glClearBufferData() and glClearBufferSubData() calls
276  *     over a sparse buffer. Make sure that all committed pages, which should
277  *     have been affected by the calls, have been reset to the requested
278  *     values.
279  *     Try issuing glClearNamedBufferSubData() over a region, for which one
280  *     of the halves is committed, and the other is not. Make sure the former
281  *     has been touched, and that no crash has occurred.
282  *
283  */
284 class ClearOpsBufferStorageTestCase : public BufferStorageTestCase
285 {
286 public:
287     /* Public methods */
288     ClearOpsBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext, unsigned int clear_op_type,
289                                   unsigned int iteration);
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     unsigned int m_clear_op_type;
314     unsigned int m_iteration;
315 };
316 
317 /** Implements the test case g for the test 2:
318  *
319  * g.  Verify copy operations work correctly for cases where:
320  *
321  *     I)   Destination and source are different sparse BOs.
322  *     II)  Destination is a sparse buffer object, source is an immutable BO.
323  *     III) Destination is an immutable BO, source is a sparse BO.
324  *     IV)  Destination and source are the same sparse BO, but refer to
325  *          different, non-overlapping memory regions.
326  *
327  *     and
328  *
329  *     *)   All pages of the source region are not committed
330  *     **)  Half of the pages of the source region is not committed
331  *     ***) None of the pages of the source region are committed.
332  *
333  *     and
334  *
335  *     +)   All pages of the destination region are not committed
336  *     ++)  Half of the pages of the destination region is not committed
337  *     +++) None of the pages of the destination region are committed.
338  *
339  *     Test all combinations of I-IV, *-***, and +-+++ bearing in mind that:
340  *
341  *     a) reads executed on non-committed memory regions return meaningless
342  *        values but MUST NOT crash GL
343  *     b) writes performed on non-committed memory regions are silently
344  *        ignored.
345  */
346 class CopyOpsBufferStorageTestCase : public BufferStorageTestCase
347 {
348 public:
349     /* Public methods */
350     CopyOpsBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext);
351 
352     /* BufferStorageTestCase implementation */
353     void deinitTestCaseGlobal();
354     void deinitTestCaseIteration();
355     bool execute(glw::GLuint sparse_bo_storage_flags);
356     bool initTestCaseGlobal();
357     bool initTestCaseIteration(glw::GLuint sparse_bo);
358 
getName()359     const char *getName()
360     {
361         return "case_g";
362     }
363 
364 private:
365     /* Private type definitions */
366     typedef struct _test_case
367     {
368         glw::GLint dst_bo_commit_size;
369         glw::GLint dst_bo_commit_start_offset;
370         glw::GLuint dst_bo_sparse_id;
371         bool dst_bo_is_sparse;
372         unsigned short *dst_bo_ref_data;
373         glw::GLint dst_bo_start_offset;
374 
375         glw::GLint n_bytes_to_copy;
376 
377         glw::GLint src_bo_commit_size;
378         glw::GLint src_bo_commit_start_offset;
379         glw::GLuint src_bo_sparse_id;
380         bool src_bo_is_sparse;
381         unsigned short *src_bo_ref_data;
382         glw::GLint src_bo_start_offset;
383     } _test_case;
384 
385     typedef std::vector<_test_case> _test_cases;
386     typedef _test_cases::const_iterator _test_cases_const_iterator;
387     typedef _test_cases::iterator _test_cases_iterator;
388 
389     /* Private methods */
390     void initReferenceData();
391     void initTestCases();
392 
393     /* Private fields */
394     const glw::Functions &m_gl;
395     glw::GLuint m_helper_bo;
396     glw::GLuint m_immutable_bo;
397     glw::GLint m_page_size;
398     unsigned short *m_ref_data[3]; /* [0] - immutable bo data, [1] - sparse bo[0] data, [2] - sparse bo[1] data.
399                                     *
400                                     * Each data buffer holds m_sparse_bo_size_rounded bytes.
401                                     */
402     glw::GLuint m_sparse_bos[2];   /* [0] - provided by BufferStorageTest[0], [1] - managed by the test case */
403     unsigned int m_sparse_bo_size;
404     unsigned int m_sparse_bo_size_rounded;
405     _test_cases m_test_cases;
406     tcu::TestContext &m_testCtx;
407 };
408 
409 /** Implements the test case h for the test 2:
410  *
411  *  h.  Verify indirect dispatch calls work correctly for the following cases:
412  *
413  *  a) The arguments are taken from a committed memory page.
414  *  b) The arguments are taken from a de-committed memory page. We expect
415  *     the dispatch request to be silently ignored in this case.
416  *  c) Half of the arguments are taken from a committed memory page,
417  *     and the other half come from a de-committed memory page. Anticipated
418  *     result is as per b).
419  *
420  *  Each spawned compute shader invocation should increment an atomic
421  *  counter.
422  *
423  */
424 class IndirectDispatchBufferStorageTestCase : public BufferStorageTestCase
425 {
426 public:
427     /* Public methods */
428     IndirectDispatchBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext);
429 
430     /* BufferStorageTestCase implementation */
431     void deinitTestCaseGlobal();
432     void deinitTestCaseIteration();
433     bool execute(glw::GLuint sparse_bo_storage_flags);
434     bool initTestCaseGlobal();
435     bool initTestCaseIteration(glw::GLuint sparse_bo);
436 
getName()437     const char *getName()
438     {
439         return "case_h";
440     }
441 
442 private:
443     /* Private fields */
444     unsigned int m_dispatch_draw_call_args_start_offset;
445     unsigned int m_expected_ac_value;
446     const glw::Functions &m_gl;
447     const unsigned int m_global_wg_size_x;
448     glw::GLuint m_helper_bo; /* stores AC value + indirect dispatch call args */
449     const unsigned int m_local_wg_size_x;
450     glw::GLint m_page_size;
451     glw::GLuint m_po;
452     glw::GLuint m_sparse_bo;
453     unsigned int m_sparse_bo_size;
454     unsigned int m_sparse_bo_size_rounded;
455     tcu::TestContext &m_testCtx;
456 };
457 
458 /** Implements the test case d for the test 2:
459  *
460  * d.  Issue glInvalidateBufferData() and glInvalidateBufferSubData() calls for
461  *     sparse buffers. For the *SubData() case, make sure you test both of
462  *     cases:
463  *
464  *     * the whole touched region has been committed
465  *     * only half of the pages have physical backing.
466  */
467 class InvalidateBufferStorageTestCase : public BufferStorageTestCase
468 {
469 public:
470     /* Public methods */
471     InvalidateBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext);
472 
473     /* BufferStorageTestCase implementation */
474     void deinitTestCaseGlobal();
475     void deinitTestCaseIteration();
476     bool execute(glw::GLuint sparse_bo_storage_flags);
477     bool initTestCaseGlobal();
478     bool initTestCaseIteration(glw::GLuint sparse_bo);
479 
getName()480     const char *getName()
481     {
482         return "case_d";
483     }
484 
485 private:
486     /* Private fields */
487     const glw::Functions &m_gl;
488     unsigned int m_n_pages_to_use;
489     glw::GLint m_page_size;
490     glw::GLuint m_sparse_bo;
491     unsigned int m_sparse_bo_size;
492     unsigned int m_sparse_bo_size_rounded;
493 };
494 
495 /** Implement the test case k from CTS_ARB_sparse_buffer:
496  *
497  *  k. Verify pixel pack functionality works correctly, when a sparse buffer
498  *     is bound to the pixel pack buffer binding point. Render a black-to-white
499  *     RGBA8 gradient and use glReadPixels() to read & verify the rendered
500  *     data. The color attachment should be of 1024x1024 resolution.
501  *
502  *     Consider three scenarios:
503  *
504  *     a) All pages, to which the data is to be written to, have been committed.
505  *     b) Use the same memory page commitment layout as proposed in b2. The
506  *        committed pages should contain correct data. Contents the pages
507  *        without the physical backing should not be verified.
508  *     c) No pages have been committed. The draw & read call should not crash
509  *        the driver, but the actual contents is of no relevance.
510  *
511  **/
512 class PixelPackBufferStorageTestCase : public BufferStorageTestCase
513 {
514 public:
515     /* Public methods */
516     PixelPackBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext);
517 
518     /* BufferStorageTestCase implementation */
519     void deinitTestCaseGlobal();
520     void deinitTestCaseIteration();
521     bool execute(glw::GLuint sparse_bo_storage_flags);
522     bool initTestCaseGlobal();
523     bool initTestCaseIteration(glw::GLuint sparse_bo);
524 
getName()525     const char *getName()
526     {
527         return "case_k";
528     }
529 
530 private:
531     /* Private fields */
532     glw::GLuint m_color_rb;
533     const unsigned int m_color_rb_height;
534     const unsigned int m_color_rb_width;
535     glw::GLuint m_fbo;
536     const glw::Functions &m_gl;
537     glw::GLuint m_helper_bo;
538     glw::GLint m_page_size;
539     glw::GLuint m_po;
540     unsigned char *m_ref_data_ptr;
541     unsigned int m_ref_data_size;
542     glw::GLuint m_sparse_bo;
543     unsigned int m_sparse_bo_size;
544     unsigned int m_sparse_bo_size_rounded;
545     tcu::TestContext &m_testCtx;
546     glw::GLuint m_vao;
547 };
548 
549 /** Implements the test case l for the test 2:
550  *
551  * l. Verify pixel unpack functionality works correctly, when a sparse buffer
552  *     is bound to the pixel unpack buffer binding point. Use a black-to-white
553  *     gradient texture data for a glTexSubImage2D() call applied against an
554  *     immutable texture object's base mip-map. Read back the data with
555  *     a glGetTexImage() call and verify the contents is valid.
556  *
557  *     Consider three scenarios:
558  *
559  *     a) All pages, from which the texture data were read from, have been
560  *        committed at the glTexSubImage2D() call time.
561  *     b) Use the same memory page commitment layout as proposed in b2. The
562  *        test should only check contents of the committed memory pages.
563  *     c) No pages have been committed at the glTexSubImage2D() call time.
564  *        The upload & getter calls should not crash, but the returned
565  *        contents are irrelevant in this case.
566  */
567 class PixelUnpackBufferStorageTestCase : public BufferStorageTestCase
568 {
569 public:
570     /* Public methods */
571     PixelUnpackBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext);
572 
573     /* BufferStorageTestCase implementation */
574     void deinitTestCaseGlobal();
575     void deinitTestCaseIteration();
576     bool execute(glw::GLuint sparse_bo_storage_flags);
577     bool initTestCaseGlobal();
578     bool initTestCaseIteration(glw::GLuint sparse_bo);
579 
getName()580     const char *getName()
581     {
582         return "case_l";
583     }
584 
585 private:
586     /* Private fields */
587     const glw::Functions &m_gl;
588     glw::GLuint m_helper_bo;
589     glw::GLint m_page_size;
590     unsigned char *m_read_data_ptr;
591     glw::GLuint m_sparse_bo;
592     unsigned int m_sparse_bo_size;
593     unsigned int m_sparse_bo_size_rounded;
594     tcu::TestContext &m_testCtx;
595     unsigned char *m_texture_data_ptr;
596     unsigned int m_texture_data_size;
597     glw::GLuint m_to;
598     unsigned char *m_to_data_zero;
599     const unsigned int m_to_height;
600     const unsigned int m_to_width;
601 };
602 
603 /** Implements test cases a1-a6 for the test 2:
604  *
605  * a1. Use the sparse buffer as a VBO.
606  *
607  *     The render-target should be drawn a total of 100 x 100 green quads
608  *     (built of triangles). Fill the buffer with vertex data (use four
609  *     components, even though we need the rectangles to be rendered in
610  *     screen space, in order to assure that the data-set spans across
611  *     multiple pages by exceeding the maximum permitted page size of 64KB).
612  *
613  *     The quads should be 5px in width & height, and be separated from each
614  *     other by a delta of 5px.
615  *
616  *     Render the quads to a render-target of 1024x1024 resolution.
617  *
618  *     All the pages, to which the vertex data has been submitted, should
619  *     be committed. The test case passes if the rendered data is correct.
620  *
621  * a2. Follow the same approach as described for a1. However, this time,
622  *     after the vertex data is uploaded, the test should de-commit all the
623  *     pages and attempt to do the draw call.
624  *
625  *     The test passes if the GL implementation does not crash. Do not
626  *     validate the rendered data.
627  *
628  * a3. Follow the same approach as described for a1. However, this time,
629  *     make sure to also provide an IBO and issue an indexed draw call
630  *     (both ranged and non-ranged). All required VBO and IBO pages should
631  *     be committed.
632  *
633  *     The pass condition described in a1 is not changed.
634  *
635  * a4. Follow the same approach as described for a2. However, this time,
636  *     after the vertex and index data is uploaded, the test should de-commit
637  *     pages storing both IBO and VBO data. Both draw calls should be issued
638  *     then.
639  *
640  *     The pass condition described in a2 is not changed.
641  *
642  * a5. Follow the same approach as described for a1. Apply the following
643  *     change:
644  *
645  *     - Each rectangle should now be assigned a color, exposed to the VS
646  *       via a Vertex Attribute Array. The color data should come from committed
647  *       sparse buffer pages.
648  *
649  * a6. Follow the same approach as described for a5. Apply the following
650  *     change:
651  *
652  *     - De-commit color data, after it has been uploaded. Try to execute the
653  *       draw call.
654  *
655  *     The test passes if the GL implementation does not crash. Do not
656  *     validate the rendered data.
657  */
658 class QuadsBufferStorageTestCase : public BufferStorageTestCase
659 {
660 public:
661     /* Type definitions */
662     enum _ibo_usage
663     {
664         /* Use glDrawArrays() for the draw call */
665         IBO_USAGE_NONE,
666         /* Use glDrawElements() for the draw call */
667         IBO_USAGE_INDEXED_DRAW_CALL,
668         /* Use glDrawRangeElements() for the draw call */
669         IBO_USAGE_INDEXED_RANGED_DRAW_CALL
670     };
671 
672     /* Public methods */
673     QuadsBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext, _ibo_usage ibo_usage,
674                                bool use_color_data);
675 
676     /* BufferStorageTestCase implementation */
677     void deinitTestCaseGlobal();
678     void deinitTestCaseIteration();
679     bool execute(glw::GLuint sparse_bo_storage_flags);
680     bool initTestCaseGlobal();
681     bool initTestCaseIteration(glw::GLuint sparse_bo);
682 
getName()683     const char *getName()
684     {
685         return (!m_use_color_data && m_ibo_usage == IBO_USAGE_NONE) ? "cases_a1-a2" :
686                (!m_use_color_data && m_ibo_usage != IBO_USAGE_NONE) ? "cases_a3-a4" :
687                (m_use_color_data && m_ibo_usage != IBO_USAGE_NONE)  ? "cases_a5-a6" :
688                                                                       "?!";
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);
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);
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                                            bool all_pages_committed, unsigned int tf_type, unsigned int draw_call_type);
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     const char *drawCallTypeEnumToString(unsigned int draw_call);
936 
937 private:
938     /* Private methods */
939     const char *getDrawCallTypeString(_draw_call draw_call);
940     void initDataBO();
941     void initTestData();
942 
943     /* Private fields */
944     bool m_all_pages_committed;
945     glw::GLuint m_data_bo;
946     unsigned int m_data_bo_index_data_offset;
947     unsigned int m_data_bo_indexed_indirect_arg_offset;
948     unsigned int m_data_bo_indexed_mdi_arg_offset;
949     unsigned int m_data_bo_regular_indirect_arg_offset;
950     unsigned int m_data_bo_regular_mdi_arg_offset;
951     glw::GLuint m_data_bo_size;
952     const unsigned int m_draw_call_baseInstance;
953     const unsigned int m_draw_call_baseVertex;
954     const unsigned int m_draw_call_first;
955     const unsigned int m_draw_call_firstIndex;
956     const glw::Functions &m_gl;
957     glw::GLuint m_helper_bo; /* of m_result_bo_size size */
958     glw::GLuint *m_index_data;
959     glw::GLuint m_index_data_size;
960     glw::GLuint *m_indirect_arg_data;
961     glw::GLuint m_indirect_arg_data_size;
962     const unsigned int m_min_memory_page_span;
963     glw::GLint m_multidrawcall_basevertex[2];
964     glw::GLsizei m_multidrawcall_count[2];
965     unsigned int m_multidrawcall_drawcount;
966     glw::GLint m_multidrawcall_first[2];
967     glw::GLvoid *m_multidrawcall_index[2];
968     unsigned int m_multidrawcall_primcount;
969     const unsigned int m_n_instances_to_test;
970     unsigned int m_n_vertices_per_instance;
971     glw::GLint m_page_size;
972     glw::GLuint m_po_ia; /* interleave attribs TF */
973     glw::GLuint m_po_sa; /* separate attribs TF */
974     glw::GLuint m_result_bo;
975     glw::GLuint m_result_bo_size;
976     glw::GLuint m_result_bo_size_rounded;
977     tcu::TestContext &m_testCtx;
978     glw::GLuint m_vao;
979     unsigned int m_tf_type;
980     unsigned int m_draw_call_type;
981 };
982 
983 /** Implements test case j for the test 2:
984  *
985  * j. Verify an UBO, backed by a sparse buffer, accessed from a vertex shader,
986  *    holds values as expected. Each VS invocation should only check
987  *    an invocation-specific arrayed member item and set gl_Position to
988  *    vec4(1.0), if the retrieved value is valid.
989  *
990  *    Make sure to test three scenarios as described for case i).
991  */
992 class UniformBufferStorageTestCase : public BufferStorageTestCase
993 {
994 public:
995     /* Public methods */
996     UniformBufferStorageTestCase(const glw::Functions &gl, tcu::TestContext &testContext);
997 
998     /* BufferStorageTestCase implementation */
999     void deinitTestCaseGlobal();
1000     void deinitTestCaseIteration();
1001     bool execute(glw::GLuint sparse_bo_storage_flags);
1002     bool initTestCaseGlobal();
1003     bool initTestCaseIteration(glw::GLuint sparse_bo);
1004 
getName()1005     const char *getName()
1006     {
1007         return "case_j";
1008     }
1009 
1010 private:
1011     /* Private fields */
1012     const glw::Functions &m_gl;
1013     glw::GLint m_gl_uniform_buffer_offset_alignment_value;
1014     glw::GLuint m_helper_bo;
1015     const unsigned int m_n_pages_to_use;
1016     unsigned int m_n_ubo_uints;
1017     glw::GLint m_page_size;
1018     glw::GLuint m_po;
1019     glw::GLuint m_sparse_bo;
1020     unsigned int m_sparse_bo_data_size;
1021     unsigned int m_sparse_bo_data_start_offset;
1022     unsigned int m_sparse_bo_size;
1023     unsigned int m_sparse_bo_size_rounded;
1024     tcu::TestContext &m_testCtx;
1025     glw::GLuint m_tf_bo;
1026     unsigned char *m_ubo_data;
1027     glw::GLuint m_vao;
1028 };
1029 
1030 /** Implements conformance test 2 from the test specification:
1031  *
1032  * 2. Make sure glBufferStorage() accepts the new GL_SPARSE_STORAGE_BIT_ARB flag
1033  *    in all valid flag combinations. For each such combination, allocate
1034  *    a sparse buffer of 1GB size and verify the following test cases work as
1035  *    expected. After all tests have been run for a particular flag combination,
1036  *    the sparse buffer should be deleted, and a new sparse buffer should be
1037  *    created, if there are any outstanding flag combinations.
1038  *
1039  *    Test cases, whose verification behavior is incompatible with
1040  *    the requested flag combination should skip the validation part:
1041  *
1042  *    (for test case descriptions, please check test case class prototypes)
1043  */
1044 class BufferStorageTest : public deqp::TestCase
1045 {
1046 public:
1047     /* Public methods */
1048     BufferStorageTest(deqp::Context &context, BufferStorageTestCase *testCase, const char *name);
1049 
1050     void deinit();
1051     void init();
1052     tcu::TestNode::IterateResult iterate();
1053 
1054 private:
1055     /* Private type definitions */
1056     typedef std::vector<BufferStorageTestCase *> TestCasesVector;
1057     typedef TestCasesVector::const_iterator TestCasesVectorConstIterator;
1058     typedef TestCasesVector::iterator TestCasesVectorIterator;
1059 
1060     /* Private members */
1061     glw::GLuint m_sparse_bo;
1062     BufferStorageTestCase *mTestCase;
1063 };
1064 
1065 /** Test group which encapsulates all sparse buffer conformance tests */
1066 class SparseBufferTests : public deqp::TestCaseGroup
1067 {
1068 public:
1069     /* Public methods */
1070     SparseBufferTests(deqp::Context &context);
1071 
1072     void init();
1073 
1074 private:
1075     SparseBufferTests(const SparseBufferTests &other);
1076     SparseBufferTests &operator=(const SparseBufferTests &other);
1077 
1078     void addBufferStorageTests();
1079 };
1080 
1081 } // namespace gl4cts
1082 
1083 #endif // _GL4CSPARSEBUFFERTESTS_HPP
1084