Home | History | Annotate | Download | only in gl
      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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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