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