Home | History | Annotate | Download | only in gl
      1 /*-------------------------------------------------------------------------
      2  * OpenGL Conformance Test Suite
      3  * -----------------------------
      4  *
      5  * Copyright (c) 2015-2016 The Khronos Group Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  */ /*!
     20  * \file
     21  * \brief
     22  */ /*-------------------------------------------------------------------*/
     23 
     24 /**
     25  */ /*!
     26  * \file  gl4cSparseBufferTests.cpp
     27  * \brief Conformance tests for the GL_ARB_sparse_buffer functionality.
     28  */ /*-------------------------------------------------------------------*/
     29 
     30 #include "gl4cSparseBufferTests.hpp"
     31 #include "gluContextInfo.hpp"
     32 #include "gluDefs.hpp"
     33 #include "glwEnums.hpp"
     34 #include "glwFunctions.hpp"
     35 #include "tcuTestLog.hpp"
     36 
     37 #include <string.h>
     38 #include <vector>
     39 
     40 #ifndef GL_SPARSE_BUFFER_PAGE_SIZE_ARB
     41 #define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8
     42 #endif
     43 #ifndef GL_SPARSE_STORAGE_BIT_ARB
     44 #define GL_SPARSE_STORAGE_BIT_ARB 0x0400
     45 #endif
     46 
     47 namespace gl4cts
     48 {
     49 /** Rounds up the provided offset so that it is aligned to the specified value (eg. page size).
     50  *  In other words, the result value meets the following requirements:
     51  *
     52  *  1)  result value % input value  = 0
     53  *  2)  result value               >= offset
     54  *  3) (result value - offset)     <  input value
     55  *
     56  *  @param offset Offset to be used for the rounding operation.
     57  *  @param value  Value to align the offset to.
     58  *
     59  *  @return Result value.
     60  **/
     61 unsigned int SparseBufferTestUtilities::alignOffset(const unsigned int& offset, const unsigned int& value)
     62 {
     63 	return offset + (value - offset % value) % value;
     64 }
     65 
     66 /** Builds a compute program object, using the user-specified CS code snippets.
     67  *
     68  *  @param gl                     DEQP CTS GL functions container.
     69  *  @param cs_body_parts          Code snippets to use for the compute shader. Must hold exactly
     70  *                                @param n_cs_body_parts null-terminated text strings.
     71  *  @param n_cs_body_parts        Number of code snippets accessible via @param cs_body_parts.
     72  *
     73  *  @return Result PO id if program has been linked successfully, 0 otherwise.
     74  **/
     75 glw::GLuint SparseBufferTestUtilities::createComputeProgram(const glw::Functions& gl, const char** cs_body_parts,
     76 															unsigned int n_cs_body_parts)
     77 {
     78 	glw::GLint  compile_status = GL_FALSE;
     79 	glw::GLuint cs_id		   = 0;
     80 	glw::GLint  link_status	= GL_FALSE;
     81 	glw::GLuint po_id		   = 0;
     82 	bool		result		   = true;
     83 
     84 	if (n_cs_body_parts > 0)
     85 	{
     86 		cs_id = gl.createShader(GL_COMPUTE_SHADER);
     87 	}
     88 
     89 	po_id = gl.createProgram();
     90 
     91 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed.");
     92 
     93 	if (n_cs_body_parts > 0)
     94 	{
     95 		gl.attachShader(po_id, cs_id);
     96 	}
     97 
     98 	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
     99 
    100 	if (n_cs_body_parts > 0)
    101 	{
    102 		gl.shaderSource(cs_id, n_cs_body_parts, cs_body_parts, NULL); /* length */
    103 	}
    104 
    105 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
    106 
    107 	gl.compileShader(cs_id);
    108 
    109 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
    110 
    111 	gl.getShaderiv(cs_id, GL_COMPILE_STATUS, &compile_status);
    112 
    113 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
    114 
    115 	char temp[1024];
    116 	gl.getShaderInfoLog(cs_id, 1024, NULL, temp);
    117 
    118 	if (GL_TRUE != compile_status)
    119 	{
    120 		result = false;
    121 
    122 		goto end;
    123 	}
    124 
    125 	gl.linkProgram(po_id);
    126 
    127 	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
    128 
    129 	gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
    130 
    131 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
    132 
    133 	if (GL_TRUE != link_status)
    134 	{
    135 		result = false;
    136 
    137 		goto end;
    138 	}
    139 
    140 end:
    141 	if (cs_id != 0)
    142 	{
    143 		gl.deleteShader(cs_id);
    144 
    145 		cs_id = 0;
    146 	}
    147 
    148 	if (!result)
    149 	{
    150 		if (po_id != 0)
    151 		{
    152 			gl.deleteProgram(po_id);
    153 
    154 			po_id = 0;
    155 		}
    156 	} /* if (!result) */
    157 
    158 	return po_id;
    159 }
    160 
    161 /** Builds a program object, using the user-specified code snippets. Can optionally configure
    162  *  the PO to use pre-defined attribute locations & transform feed-back varyings.
    163  *
    164  *  @param gl                     DEQP CTS GL functions container.
    165  *  @param fs_body_parts          Code snippets to use for the fragment shader. Must hold exactly
    166  *                                @param n_fs_body_parts null-terminated text strings. May only
    167  *                                be NULL if @param n_fs_body_parts is 0.
    168  *  @param n_fs_body_parts        See @param fs_body_parts definitions.
    169  *  @param vs_body_parts          Code snippets to use for the vertex shader. Must hold exactly
    170  *                                @param n_vs_body_parts null-terminated text strings. May only
    171  *                                be NULL if @param n_vs_body_parts is 0.
    172  *  @param n_vs_body_parts        See @param vs_body_parts definitions.
    173  *  @param attribute_names        Null-terminated attribute names to pass to the
    174  *                                glBindAttribLocation() call.
    175  *                                May only be NULL if @param n_attribute_properties is 0.
    176  *  @param attribute_locations    Attribute locations to pass to the glBindAttribLocation() call.
    177  *                                May only be NULL if @param n_attribute_properties is 0.
    178  *  @param n_attribute_properties See @param attribute_names and @param attribute_locations definitions.
    179  *  @param tf_varyings            Transform-feedback varying names to use for the
    180  *                                glTransformFeedbackVaryings() call. May only be NULL if
    181  *                                @param n_tf_varyings is 0.
    182  *  @param n_tf_varyings          See @param tf_varyings definition.
    183  *  @param tf_varying_mode        Transform feedback mode to use for the
    184  *                                glTransformFeedbackVaryings() call. Only used if @param n_tf_varyings
    185  *                                is 0.
    186  *
    187  *  @return Result PO id if program has been linked successfully, 0 otherwise.
    188  **/
    189 glw::GLuint SparseBufferTestUtilities::createProgram(const glw::Functions& gl, const char** fs_body_parts,
    190 													 unsigned int n_fs_body_parts, const char** vs_body_parts,
    191 													 unsigned int n_vs_body_parts, const char** attribute_names,
    192 													 const unsigned int*	   attribute_locations,
    193 													 unsigned int			   n_attribute_properties,
    194 													 const glw::GLchar* const* tf_varyings, unsigned int n_tf_varyings,
    195 													 glw::GLenum tf_varying_mode)
    196 {
    197 	glw::GLint  compile_status = GL_FALSE;
    198 	glw::GLuint fs_id		   = 0;
    199 	glw::GLint  link_status	= GL_FALSE;
    200 	glw::GLuint po_id		   = 0;
    201 	bool		result		   = true;
    202 	glw::GLuint vs_id		   = 0;
    203 
    204 	if (n_fs_body_parts > 0)
    205 	{
    206 		fs_id = gl.createShader(GL_FRAGMENT_SHADER);
    207 	}
    208 
    209 	po_id = gl.createProgram();
    210 
    211 	if (n_vs_body_parts > 0)
    212 	{
    213 		vs_id = gl.createShader(GL_VERTEX_SHADER);
    214 	}
    215 
    216 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed.");
    217 
    218 	if (n_fs_body_parts > 0)
    219 	{
    220 		gl.attachShader(po_id, fs_id);
    221 	}
    222 
    223 	if (n_vs_body_parts > 0)
    224 	{
    225 		gl.attachShader(po_id, vs_id);
    226 	}
    227 
    228 	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
    229 
    230 	if (n_fs_body_parts > 0)
    231 	{
    232 		gl.shaderSource(fs_id, n_fs_body_parts, fs_body_parts, NULL); /* length */
    233 	}
    234 
    235 	if (n_vs_body_parts > 0)
    236 	{
    237 		gl.shaderSource(vs_id, n_vs_body_parts, vs_body_parts, NULL); /* length */
    238 	}
    239 
    240 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
    241 
    242 	const glw::GLuint  so_ids[] = { fs_id, vs_id };
    243 	const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
    244 
    245 	for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
    246 	{
    247 		if (so_ids[n_so_id] != 0)
    248 		{
    249 			gl.compileShader(so_ids[n_so_id]);
    250 
    251 			GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
    252 
    253 			gl.getShaderiv(so_ids[n_so_id], GL_COMPILE_STATUS, &compile_status);
    254 
    255 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
    256 
    257 			char temp[1024];
    258 			gl.getShaderInfoLog(so_ids[n_so_id], 1024, NULL, temp);
    259 
    260 			if (GL_TRUE != compile_status)
    261 			{
    262 				result = false;
    263 
    264 				goto end;
    265 			}
    266 		} /* if (so_ids[n_so_id] != 0) */
    267 	}	 /* for (all shader object IDs) */
    268 
    269 	for (unsigned int n_attribute = 0; n_attribute < n_attribute_properties; ++n_attribute)
    270 	{
    271 		gl.bindAttribLocation(po_id, attribute_locations[n_attribute], attribute_names[n_attribute]);
    272 
    273 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindAttribLocation() call failed.");
    274 	} /* for (all attributes to configure) */
    275 
    276 	if (n_tf_varyings != 0)
    277 	{
    278 		gl.transformFeedbackVaryings(po_id, n_tf_varyings, tf_varyings, tf_varying_mode);
    279 
    280 		GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
    281 	} /* if (n_tf_varyings != 0) */
    282 
    283 	gl.linkProgram(po_id);
    284 
    285 	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
    286 
    287 	gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
    288 
    289 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
    290 
    291 	if (GL_TRUE != link_status)
    292 	{
    293 		result = false;
    294 
    295 		goto end;
    296 	}
    297 
    298 end:
    299 	if (fs_id != 0)
    300 	{
    301 		gl.deleteShader(fs_id);
    302 
    303 		fs_id = 0;
    304 	}
    305 
    306 	if (vs_id != 0)
    307 	{
    308 		gl.deleteShader(vs_id);
    309 
    310 		vs_id = 0;
    311 	}
    312 
    313 	if (!result)
    314 	{
    315 
    316 		if (po_id != 0)
    317 		{
    318 			gl.deleteProgram(po_id);
    319 
    320 			po_id = 0;
    321 		}
    322 	} /* if (!result) */
    323 
    324 	return po_id;
    325 }
    326 
    327 /** Returns a string with textual representation of the @param flags bitfield
    328  *  holding bits applicable to the @param flags argument of glBufferStorage()
    329  *  calls.
    330  *
    331  *  @param flags Flags argument, as supported by the @param flags argument of
    332  *               glBufferStorage() entry-point.
    333  *
    334  *  @return Described string.
    335  **/
    336 std::string SparseBufferTestUtilities::getSparseBOFlagsString(glw::GLenum flags)
    337 {
    338 	unsigned int	  n_flags_added = 0;
    339 	std::stringstream result_sstream;
    340 
    341 	if ((flags & GL_CLIENT_STORAGE_BIT) != 0)
    342 	{
    343 		result_sstream << "GL_CLIENT_STORAGE_BIT";
    344 
    345 		++n_flags_added;
    346 	}
    347 
    348 	if ((flags & GL_DYNAMIC_STORAGE_BIT) != 0)
    349 	{
    350 		result_sstream << ((n_flags_added) ? " | " : "") << "GL_DYNAMIC_STORAGE_BIT";
    351 
    352 		++n_flags_added;
    353 	}
    354 
    355 	if ((flags & GL_MAP_COHERENT_BIT) != 0)
    356 	{
    357 		result_sstream << ((n_flags_added) ? " | " : "") << "GL_MAP_COHERENT_BIT";
    358 
    359 		++n_flags_added;
    360 	}
    361 
    362 	if ((flags & GL_MAP_PERSISTENT_BIT) != 0)
    363 	{
    364 		result_sstream << ((n_flags_added) ? " | " : "") << "GL_MAP_PERSISTENT_BIT";
    365 
    366 		++n_flags_added;
    367 	}
    368 
    369 	if ((flags & GL_SPARSE_STORAGE_BIT_ARB) != 0)
    370 	{
    371 		result_sstream << ((n_flags_added) ? " | " : "") << "GL_SPARSE_STORAGE_BIT";
    372 
    373 		++n_flags_added;
    374 	}
    375 
    376 	return result_sstream.str();
    377 }
    378 
    379 /** Constructor.
    380  *
    381  *  @param context     Rendering context
    382  *  @param name        Test name
    383  *  @param description Test description
    384  */
    385 NegativeTests::NegativeTests(deqp::Context& context)
    386 	: TestCase(context, "NegativeTests", "Implements all negative tests described in CTS_ARB_sparse_buffer")
    387 	, m_helper_bo_id(0)
    388 	, m_immutable_bo_id(0)
    389 	, m_immutable_bo_size(1024768)
    390 	, m_sparse_bo_id(0)
    391 {
    392 	/* Left blank intentionally */
    393 }
    394 
    395 /** Stub deinit method. */
    396 void NegativeTests::deinit()
    397 {
    398 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    399 
    400 	if (m_helper_bo_id != 0)
    401 	{
    402 		gl.deleteBuffers(1, &m_helper_bo_id);
    403 
    404 		m_helper_bo_id = 0;
    405 	}
    406 
    407 	if (m_immutable_bo_id != 0)
    408 	{
    409 		gl.deleteBuffers(1, &m_immutable_bo_id);
    410 
    411 		m_immutable_bo_id = 0;
    412 	}
    413 
    414 	if (m_sparse_bo_id != 0)
    415 	{
    416 		gl.deleteBuffers(1, &m_sparse_bo_id);
    417 
    418 		m_sparse_bo_id = 0;
    419 	}
    420 }
    421 
    422 /** Stub init method */
    423 void NegativeTests::init()
    424 {
    425 	/* Nothing to do here */
    426 }
    427 
    428 /** Executes test iteration.
    429  *
    430  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
    431  */
    432 tcu::TestNode::IterateResult NegativeTests::iterate()
    433 {
    434 	glw::GLvoid*		  data_ptr  = DE_NULL;
    435 	const glw::Functions& gl		= m_context.getRenderContext().getFunctions();
    436 	glw::GLint			  page_size = 0;
    437 	bool				  result	= true;
    438 
    439 	/* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
    440 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
    441 	{
    442 		throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
    443 	}
    444 
    445 	/* Set up */
    446 	gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size);
    447 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
    448 
    449 	gl.genBuffers(1, &m_helper_bo_id);
    450 	gl.genBuffers(1, &m_immutable_bo_id);
    451 	gl.genBuffers(1, &m_sparse_bo_id);
    452 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed.");
    453 
    454 	gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo_id);
    455 	gl.bindBuffer(GL_COPY_READ_BUFFER, m_immutable_bo_id);
    456 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_helper_bo_id);
    457 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
    458 
    459 	gl.bufferStorage(GL_ARRAY_BUFFER, page_size * 3, /* size as per test spec */
    460 					 DE_NULL,						 /* data */
    461 					 GL_SPARSE_STORAGE_BIT_ARB);
    462 	gl.bufferStorage(GL_COPY_READ_BUFFER, m_immutable_bo_size, /* size */
    463 					 DE_NULL,								   /* data */
    464 					 0);
    465 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call(s) failed.");
    466 
    467 	/** * Verify glBufferPageCommitmentARB() returns GL_INVALID_ENUM if <target> is
    468 	 *    set to GL_INTERLEAVED_ATTRIBS. */
    469 	glw::GLint error_code = GL_NO_ERROR;
    470 
    471 	gl.bufferPageCommitmentARB(GL_INTERLEAVED_ATTRIBS, 0, /* offset */
    472 							   page_size, GL_TRUE);		  /* commit */
    473 
    474 	error_code = gl.getError();
    475 	if (error_code != GL_INVALID_ENUM)
    476 	{
    477 		m_testCtx.getLog() << tcu::TestLog::Message
    478 						   << "Invalid <target> value passed to a glBufferPageCommitmentARB() call"
    479 							  " did not generate a GL_INVALID_ENUM error."
    480 						   << tcu::TestLog::EndMessage;
    481 
    482 		result = false;
    483 	}
    484 
    485 	/*  * Verify glBufferStorage() throws a GL_INVALID_VALUE error if <flags> is
    486 	 *    set to (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT) or
    487 	 *    (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT). */
    488 	gl.bufferStorage(GL_ELEMENT_ARRAY_BUFFER, page_size * 3, /* size */
    489 					 DE_NULL,								 /* data */
    490 					 GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT);
    491 
    492 	error_code = gl.getError();
    493 	if (error_code != GL_INVALID_VALUE)
    494 	{
    495 		m_testCtx.getLog() << tcu::TestLog::Message
    496 						   << "Invalid <flags> value set to GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT "
    497 							  "did not generate a GL_INVALID_VALUE error."
    498 						   << tcu::TestLog::EndMessage;
    499 
    500 		result = false;
    501 	}
    502 
    503 	gl.bufferStorage(GL_ELEMENT_ARRAY_BUFFER, page_size * 3, /* size */
    504 					 DE_NULL,								 /* data */
    505 					 GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT);
    506 
    507 	error_code = gl.getError();
    508 	if (error_code != GL_INVALID_VALUE)
    509 	{
    510 		m_testCtx.getLog() << tcu::TestLog::Message
    511 						   << "Invalid <flags> value set to GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT "
    512 							  "did not generate a GL_INVALID_VALUE error."
    513 						   << tcu::TestLog::EndMessage;
    514 
    515 		result = false;
    516 	}
    517 
    518 	/*  * Verify glBufferPageCommitmentARB() generates a GL_INVALID_OPERATION error if
    519 	 *    it is called for an immutable BO, which has not been initialized with the
    520 	 *    GL_SPARSE_STORAGE_BIT_ARB flag. */
    521 	gl.bufferPageCommitmentARB(GL_COPY_READ_BUFFER, 0, /* offset */
    522 							   page_size, GL_TRUE);	/* commit */
    523 
    524 	error_code = gl.getError();
    525 	if (error_code != GL_INVALID_OPERATION)
    526 	{
    527 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
    528 													   " issued against an immutable, non-sparse buffer object."
    529 						   << tcu::TestLog::EndMessage;
    530 
    531 		result = false;
    532 	}
    533 
    534 	/*  * Verify glBufferPageCommitmentARB() issues a GL_INVALID_VALUE error if <offset>
    535 	 *    is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value
    536 	 *    is equal to 1. */
    537 	if (page_size != 1)
    538 	{
    539 		gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, page_size / 2, /* offset */
    540 								   page_size, GL_TRUE);			   /* commit */
    541 
    542 		error_code = gl.getError();
    543 		if (error_code != GL_INVALID_VALUE)
    544 		{
    545 			m_testCtx.getLog() << tcu::TestLog::Message
    546 							   << "Invalid error code generated by glBufferPageCommitmentARB() "
    547 								  "whose <offset> value was set to (page size / 2)."
    548 							   << tcu::TestLog::EndMessage;
    549 
    550 			result = false;
    551 		}
    552 	} /* if (page_size != 1) */
    553 
    554 	/*  * Verify glBufferPageCommitmentARB() emits a GL_INVALID_VALUE error if <size>
    555 	 *    is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value
    556 	 *    is equal to 1. */
    557 	if (page_size != 1)
    558 	{
    559 		gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,		/* offset */
    560 								   page_size / 2, GL_TRUE); /* commit */
    561 
    562 		error_code = gl.getError();
    563 		if (error_code != GL_INVALID_VALUE)
    564 		{
    565 			m_testCtx.getLog() << tcu::TestLog::Message
    566 							   << "Invalid error code generated by glBufferPageCommitmentARB() "
    567 								  "whose <size> value was set to (page size / 2)."
    568 							   << tcu::TestLog::EndMessage;
    569 
    570 			result = false;
    571 		}
    572 	} /* if (page_size != 1) */
    573 
    574 	/*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <offset> is
    575 	 *    set to -1, but all other arguments are valid. */
    576 	gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, -1, /* offset */
    577 							   page_size, GL_TRUE); /* commit */
    578 
    579 	error_code = gl.getError();
    580 	if (error_code != GL_INVALID_VALUE)
    581 	{
    582 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
    583 													   "whose <offset> argument was set to -1."
    584 						   << tcu::TestLog::EndMessage;
    585 
    586 		result = false;
    587 	}
    588 
    589 	/*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <size> is
    590 	 *    set to -1, but all other arguments are valid. */
    591 	gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */
    592 							   -1,				   /* size */
    593 							   GL_TRUE);		   /* commit */
    594 
    595 	error_code = gl.getError();
    596 	if (error_code != GL_INVALID_VALUE)
    597 	{
    598 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
    599 													   "whose <size> argument was set to -1."
    600 						   << tcu::TestLog::EndMessage;
    601 
    602 		result = false;
    603 	}
    604 
    605 	/*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is
    606 	 *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to 0 and <size>
    607 	 *    argument used for the call is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 4. */
    608 	gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */
    609 							   page_size * 4,	  /* size */
    610 							   GL_TRUE);
    611 
    612 	error_code = gl.getError();
    613 	if (error_code != GL_INVALID_VALUE)
    614 	{
    615 		m_testCtx.getLog() << tcu::TestLog::Message
    616 						   << "Invalid error code generated by glBufferPageCommitmentARB() "
    617 							  "whose <offset> was set to 0 and <size> was set to (page size * 4), "
    618 							  "when the buffer storage size had been configured to be (page size * 3)."
    619 						   << tcu::TestLog::EndMessage;
    620 
    621 		result = false;
    622 	}
    623 
    624 	/*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is
    625 	 *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to
    626 	 *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 1 and <size> argument used for the call
    627 	 *    is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3. */
    628 	gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, page_size * 1, /* offset */
    629 							   page_size * 3,				   /* size */
    630 							   GL_TRUE);
    631 
    632 	error_code = gl.getError();
    633 	if (error_code != GL_INVALID_VALUE)
    634 	{
    635 		m_testCtx.getLog() << tcu::TestLog::Message
    636 						   << "Invalid error code generated by glBufferPageCommitmentARB() "
    637 							  "whose <offset> was set to (page size) and <size> was set to (page size * 3), "
    638 							  "when the buffer storage size had been configured to be (page size * 3)."
    639 						   << tcu::TestLog::EndMessage;
    640 
    641 		result = false;
    642 	}
    643 
    644 	/*  * Verify that calling glMapBuffer() or glMapBufferRange() against a sparse
    645 	 *    buffer generates a GL_INVALID_OPERATION error. */
    646 	data_ptr = gl.mapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
    647 
    648 	if (data_ptr != DE_NULL)
    649 	{
    650 		m_testCtx.getLog() << tcu::TestLog::Message
    651 						   << "Non-NULL pointer returned by an invalid glMapBuffer() call, issued "
    652 							  "against a sparse buffer object"
    653 						   << tcu::TestLog::EndMessage;
    654 
    655 		result = false;
    656 	}
    657 
    658 	error_code = gl.getError();
    659 
    660 	if (error_code != GL_INVALID_OPERATION)
    661 	{
    662 		m_testCtx.getLog() << tcu::TestLog::Message
    663 						   << "Invalid error code generated by glMapBuffer() call, issued against "
    664 							  "a sparse buffer object"
    665 						   << tcu::TestLog::EndMessage;
    666 
    667 		result = false;
    668 	}
    669 
    670 	data_ptr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, /* offset */
    671 								 page_size,			 /* length */
    672 								 GL_MAP_READ_BIT);
    673 
    674 	if (data_ptr != DE_NULL)
    675 	{
    676 		m_testCtx.getLog() << tcu::TestLog::Message
    677 						   << "Non-NULL pointer returned by an invalid glMapBufferRange() call, issued "
    678 							  "against a sparse buffer object"
    679 						   << tcu::TestLog::EndMessage;
    680 
    681 		result = false;
    682 	}
    683 
    684 	error_code = gl.getError();
    685 
    686 	if (error_code != GL_INVALID_OPERATION)
    687 	{
    688 		m_testCtx.getLog() << tcu::TestLog::Message
    689 						   << "Invalid error code generated by glMapBufferRange() call, issued against "
    690 							  "a sparse buffer object"
    691 						   << tcu::TestLog::EndMessage;
    692 
    693 		result = false;
    694 	}
    695 
    696 	m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
    697 
    698 	return STOP;
    699 }
    700 
    701 /** Constructor.
    702  *
    703  *  @param context     Rendering context
    704  *  @param name        Test name
    705  *  @param description Test description
    706  */
    707 PageSizeGetterTest::PageSizeGetterTest(deqp::Context& context)
    708 	: TestCase(context, "PageSizeGetterTest",
    709 			   "Verifies GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname is recognized by the getter functions")
    710 {
    711 	/* Left blank intentionally */
    712 }
    713 
    714 /** Stub deinit method. */
    715 void PageSizeGetterTest::deinit()
    716 {
    717 	/* Nothing to be done here */
    718 }
    719 
    720 /** Stub init method */
    721 void PageSizeGetterTest::init()
    722 {
    723 	/* Nothing to do here */
    724 }
    725 
    726 /** Executes test iteration.
    727  *
    728  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
    729  */
    730 tcu::TestNode::IterateResult PageSizeGetterTest::iterate()
    731 {
    732 	const glw::Functions& gl			   = m_context.getRenderContext().getFunctions();
    733 	glw::GLboolean		  page_size_bool   = false;
    734 	glw::GLdouble		  page_size_double = 0.0;
    735 	glw::GLfloat		  page_size_float  = 0.0f;
    736 	glw::GLint			  page_size_int	= 0;
    737 	glw::GLint64		  page_size_int64  = 0;
    738 	bool				  result		   = true;
    739 
    740 	/* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
    741 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
    742 	{
    743 		throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
    744 	}
    745 
    746 	/* glGetIntegerv() */
    747 	gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_int);
    748 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed");
    749 
    750 	if (page_size_int < 1 || page_size_int > 65536)
    751 	{
    752 		m_testCtx.getLog() << tcu::TestLog::Message << "Page size reported by the implementation (" << page_size_int
    753 						   << ")"
    754 							  " by glGetIntegerv() is out of the allowed range."
    755 						   << tcu::TestLog::EndMessage;
    756 
    757 		result = false;
    758 	}
    759 
    760 	/* glGetBooleanv() */
    761 	gl.getBooleanv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_bool);
    762 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed");
    763 
    764 	if (!page_size_bool)
    765 	{
    766 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetBooleanv()"
    767 						   << tcu::TestLog::EndMessage;
    768 
    769 		result = false;
    770 	}
    771 
    772 	/* glGetDoublev() */
    773 	gl.getDoublev(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_double);
    774 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed");
    775 
    776 	if (de::abs(page_size_double - page_size_int) > 1e-5)
    777 	{
    778 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetDoublev()"
    779 													   " (reported value: "
    780 						   << page_size_double << ", expected value: " << page_size_int << ")"
    781 						   << tcu::TestLog::EndMessage;
    782 
    783 		result = false;
    784 	}
    785 
    786 	/* glGetFloatv() */
    787 	gl.getFloatv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_float);
    788 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed");
    789 
    790 	if (de::abs(page_size_float - static_cast<float>(page_size_int)) > 1e-5f)
    791 	{
    792 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetFloatv()"
    793 													   " (reported value: "
    794 						   << page_size_float << ", expected value: " << page_size_int << ")"
    795 						   << tcu::TestLog::EndMessage;
    796 
    797 		result = false;
    798 	}
    799 
    800 	/* glGetInteger64v() */
    801 	gl.getInteger64v(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_int64);
    802 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed");
    803 
    804 	if (page_size_int64 != page_size_int)
    805 	{
    806 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetInteger64v()"
    807 													   " (reported value: "
    808 						   << page_size_int64 << ", expected value: " << page_size_int << ")"
    809 						   << tcu::TestLog::EndMessage;
    810 
    811 		result = false;
    812 	}
    813 
    814 	m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
    815 
    816 	return STOP;
    817 }
    818 
    819 /** Constructor.
    820  *
    821  *  @param gl                         GL entry-points container
    822  *  @param testContext                CTS test context
    823  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
    824  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
    825  *  @param all_pages_committed        true to run the test with all data memory pages committed,
    826  *                                    false to leave some of them without an actual memory backing.
    827  */
    828 AtomicCounterBufferStorageTestCase::AtomicCounterBufferStorageTestCase(const glw::Functions& gl,
    829 																	   tcu::TestContext&	 testContext,
    830 																	   glw::GLint page_size, bool all_pages_committed)
    831 	: m_all_pages_committed(all_pages_committed)
    832 	, m_gl(gl)
    833 	, m_gl_atomic_counter_uniform_array_stride(0)
    834 	, m_gl_max_vertex_atomic_counters_value(0)
    835 	, m_helper_bo(0)
    836 	, m_helper_bo_size(0)
    837 	, m_helper_bo_size_rounded(0)
    838 	, m_n_draw_calls(3) /* as per test spec */
    839 	, m_page_size(page_size)
    840 	, m_po(0)
    841 	, m_sparse_bo(0)
    842 	, m_sparse_bo_data_size(0)
    843 	, m_sparse_bo_data_size_rounded(0)
    844 	, m_sparse_bo_data_start_offset(0)
    845 	, m_sparse_bo_data_start_offset_rounded(0)
    846 	, m_testCtx(testContext)
    847 	, m_vao(0)
    848 {
    849 	/* Left blank intentionally */
    850 }
    851 
    852 /** Releases all GL objects used across all test case iterations.
    853  *
    854  *  Called once during BufferStorage test run-time.
    855  */
    856 void AtomicCounterBufferStorageTestCase::deinitTestCaseGlobal()
    857 {
    858 	if (m_helper_bo != 0)
    859 	{
    860 		m_gl.deleteBuffers(1, &m_helper_bo);
    861 
    862 		m_helper_bo = 0;
    863 	}
    864 
    865 	if (m_po != 0)
    866 	{
    867 		m_gl.deleteProgram(m_po);
    868 
    869 		m_po = 0;
    870 	}
    871 
    872 	if (m_vao != 0)
    873 	{
    874 		m_gl.deleteVertexArrays(1, &m_vao);
    875 
    876 		m_vao = 0;
    877 	}
    878 }
    879 
    880 /** Releases temporary GL objects, created specifically for one test case iteration. */
    881 void AtomicCounterBufferStorageTestCase::deinitTestCaseIteration()
    882 {
    883 	if (m_sparse_bo != 0)
    884 	{
    885 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
    886 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
    887 
    888 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
    889 									 m_helper_bo_size_rounded, GL_FALSE); /* commit */
    890 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
    891 
    892 		m_sparse_bo = 0;
    893 	}
    894 }
    895 
    896 /** Executes a single test iteration. The BufferStorage test will call this method
    897  *  numerously during its life-time, testing various valid flag combinations applied
    898  *  to the tested sparse buffer object at glBufferStorage() call time.
    899  *
    900  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
    901  *                                 call to set up the sparse buffer's storage.
    902  *
    903  *  @return true if the test case executed correctly, false otherwise.
    904  */
    905 bool AtomicCounterBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
    906 {
    907 	(void)sparse_bo_storage_flags;
    908 	static const unsigned char data_zero = 0;
    909 	bool					   result	= true;
    910 
    911 	/* Only execute if GL_MAX_VERTEX_ATOMIC_COUNTERS is > 0 */
    912 	if (m_gl_max_vertex_atomic_counters_value == 0)
    913 	{
    914 		m_testCtx.getLog() << tcu::TestLog::Message << "G_MAX_VERTEX_ATOMIC_COUNTERS is 0. Skipping the test."
    915 						   << tcu::TestLog::EndMessage;
    916 
    917 		goto end;
    918 	}
    919 
    920 	/* Bind the test program object */
    921 	m_gl.useProgram(m_po);
    922 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
    923 
    924 	m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_sparse_bo);
    925 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
    926 
    927 	/* Try using both ranged and non-ranged AC bindings.
    928 	 *
    929 	 * NOTE: It only makes sense to perform glBindBufferBase() test if all AC pages are
    930 	 *       committed
    931 	 */
    932 	for (unsigned int n_binding_type = (m_all_pages_committed) ? 0 : 1;
    933 		 n_binding_type < 2; /* glBindBufferBase(), glBindBufferRange() */
    934 		 ++n_binding_type)
    935 	{
    936 		bool result_local = true;
    937 
    938 		if (n_binding_type == 0)
    939 		{
    940 			m_gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
    941 								m_sparse_bo);
    942 
    943 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
    944 		}
    945 		else
    946 		{
    947 			m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
    948 								 m_sparse_bo, m_sparse_bo_data_start_offset, m_helper_bo_size);
    949 
    950 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
    951 		}
    952 
    953 		/* Zero out the sparse buffer's contents */
    954 		m_gl.clearBufferData(GL_ATOMIC_COUNTER_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero);
    955 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
    956 
    957 		/* Run the test */
    958 		m_gl.drawArraysInstanced(GL_POINTS, 0,							/* first */
    959 								 m_gl_max_vertex_atomic_counters_value, /* count */
    960 								 m_n_draw_calls);
    961 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed");
    962 
    963 		/* Retrieve the atomic counter values */
    964 		const glw::GLuint* ac_data = NULL;
    965 		const unsigned int n_expected_written_values =
    966 			(m_all_pages_committed) ? m_gl_max_vertex_atomic_counters_value : m_gl_max_vertex_atomic_counters_value / 2;
    967 
    968 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
    969 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
    970 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffeR() call failed");
    971 
    972 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
    973 							   (n_binding_type == 0) ? 0 : m_sparse_bo_data_start_offset, 0, /* writeOffset */
    974 							   m_sparse_bo_data_size);
    975 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
    976 
    977 		ac_data = (const glw::GLuint*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */
    978 														  m_sparse_bo_data_size, GL_MAP_READ_BIT);
    979 
    980 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
    981 
    982 		for (unsigned int n_counter = 0; n_counter < n_expected_written_values && result_local; ++n_counter)
    983 		{
    984 			const unsigned int expected_value = m_n_draw_calls;
    985 			const unsigned int retrieved_value =
    986 				*((unsigned int*)((unsigned char*)ac_data + m_gl_atomic_counter_uniform_array_stride * n_counter));
    987 
    988 			if (expected_value != retrieved_value)
    989 			{
    990 				m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value "
    991 															   "["
    992 								   << retrieved_value << "]"
    993 														 " instead of the expected value "
    994 														 "["
    995 								   << expected_value << "]"
    996 														" at index "
    997 								   << n_counter << " when using "
    998 								   << ((n_binding_type == 0) ? "glBindBufferBase()" : "glBindBufferRange()")
    999 								   << " for AC binding configuration" << tcu::TestLog::EndMessage;
   1000 
   1001 				result_local = false;
   1002 			} /* if (expected_value != retrieved_value) */
   1003 		}	 /* for (all draw calls that need to be executed) */
   1004 
   1005 		m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
   1006 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   1007 
   1008 		result &= result_local;
   1009 	} /* for (both binding types) */
   1010 
   1011 end:
   1012 	return result;
   1013 }
   1014 
   1015 /** Initializes GL objects used across all test case iterations.
   1016  *
   1017  *  Called once during BufferStorage test run-time.
   1018  */
   1019 bool AtomicCounterBufferStorageTestCase::initTestCaseGlobal()
   1020 {
   1021 	const glw::GLuint ac_uniform_index = 0; /* only one uniform is defined in the VS below */
   1022 	std::stringstream n_counters_sstream;
   1023 	std::string		  n_counters_string;
   1024 	bool			  result = true;
   1025 
   1026 	static const char* vs_body_preamble = "#version 430 core\n"
   1027 										  "\n";
   1028 
   1029 	static const char* vs_body_core = "layout(binding = 0) uniform atomic_uint counters[N_COUNTERS];\n"
   1030 									  "\n"
   1031 									  "void main()\n"
   1032 									  "{\n"
   1033 									  "    for (uint n = 0; n < N_COUNTERS; ++n)\n"
   1034 									  "    {\n"
   1035 									  "        if (n == gl_VertexID)\n"
   1036 									  "        {\n"
   1037 									  "            atomicCounterIncrement(counters[n]);\n"
   1038 									  "        }\n"
   1039 									  "    }\n"
   1040 									  "\n"
   1041 									  "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
   1042 									  "}\n";
   1043 	const char* vs_body_parts[] = { vs_body_preamble, DE_NULL, /* will be set to n_counters_string.c_str() */
   1044 									vs_body_core };
   1045 	const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]);
   1046 
   1047 	/* Retrieve GL_MAX_VERTEX_ATOMIC_COUNTERS value. The test will only be executed if it's >= 1 */
   1048 	m_gl.getIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &m_gl_max_vertex_atomic_counters_value);
   1049 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call failed.");
   1050 
   1051 	if (m_gl_max_vertex_atomic_counters_value == 0)
   1052 	{
   1053 		goto end;
   1054 	}
   1055 
   1056 	/* Form the N_COUNTERS declaration string */
   1057 	n_counters_sstream << "#define N_COUNTERS " << m_gl_max_vertex_atomic_counters_value << "\n";
   1058 	n_counters_string = n_counters_sstream.str();
   1059 
   1060 	vs_body_parts[1] = n_counters_string.c_str();
   1061 
   1062 	/* Set up the program object */
   1063 	DE_ASSERT(m_po == 0);
   1064 
   1065 	m_po =
   1066 		SparseBufferTestUtilities::createProgram(m_gl, DE_NULL,							  /* fs_body_parts   */
   1067 												 0,										  /* n_fs_body_parts */
   1068 												 vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names        */
   1069 												 DE_NULL,								  /* attribute_locations    */
   1070 												 0);									  /* n_attribute_properties */
   1071 
   1072 	if (m_po == 0)
   1073 	{
   1074 		result = false;
   1075 
   1076 		goto end;
   1077 	}
   1078 
   1079 	/* Helper BO will be used to hold the atomic counter buffer data.
   1080 	 * Determine how much space will be needed.
   1081 	 *
   1082 	 * Min max for the GL constant value is 0. Bail out if that's the
   1083 	 * value we are returned - it is pointless to execute the test in
   1084 	 * such environment.
   1085 	 */
   1086 	m_gl.getActiveUniformsiv(m_po, 1, /* uniformCount */
   1087 							 &ac_uniform_index, GL_UNIFORM_ARRAY_STRIDE, &m_gl_atomic_counter_uniform_array_stride);
   1088 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetActiveUniformsiv() call failed.");
   1089 
   1090 	DE_ASSERT(m_gl_atomic_counter_uniform_array_stride >= (int)sizeof(unsigned int));
   1091 
   1092 	m_helper_bo_size		 = m_gl_atomic_counter_uniform_array_stride * m_gl_max_vertex_atomic_counters_value;
   1093 	m_helper_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_helper_bo_size, m_page_size);
   1094 
   1095 	/* Set up the helper BO */
   1096 	DE_ASSERT(m_helper_bo == 0);
   1097 
   1098 	m_gl.genBuffers(1, &m_helper_bo);
   1099 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   1100 
   1101 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   1102 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1103 
   1104 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_helper_bo_size_rounded, DE_NULL, GL_MAP_READ_BIT); /* flags */
   1105 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   1106 
   1107 	/* Set up the vertex array object */
   1108 	DE_ASSERT(m_vao == 0);
   1109 
   1110 	m_gl.genVertexArrays(1, &m_vao);
   1111 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
   1112 
   1113 	m_gl.bindVertexArray(m_vao);
   1114 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
   1115 
   1116 end:
   1117 	return result;
   1118 }
   1119 
   1120 /** Initializes GL objects which are needed for a single test case iteration.
   1121  *
   1122  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   1123  *  to release these objects.
   1124  **/
   1125 bool AtomicCounterBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   1126 {
   1127 	bool result = true;
   1128 
   1129 	/* Cache the BO id, if not cached already */
   1130 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   1131 
   1132 	m_sparse_bo = sparse_bo;
   1133 
   1134 	/* Set up the sparse bufffer. */
   1135 	int sparse_bo_data_size = 0;
   1136 
   1137 	DE_ASSERT(m_helper_bo_size_rounded != 0);
   1138 
   1139 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   1140 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1141 
   1142 	if (m_all_pages_committed)
   1143 	{
   1144 		/* Commit all required pages */
   1145 		sparse_bo_data_size = m_helper_bo_size_rounded;
   1146 	}
   1147 	else
   1148 	{
   1149 		/* Only commit the first half of the required pages */
   1150 		DE_ASSERT((m_helper_bo_size_rounded % m_page_size) == 0);
   1151 
   1152 		sparse_bo_data_size = (m_helper_bo_size_rounded / m_page_size) * m_page_size / 2;
   1153 	}
   1154 
   1155 	/* NOTE: We need to ensure that the memory region assigned to the atomic counter buffer spans
   1156 	 *       at least through two separate pages.
   1157 	 *
   1158 	 * Since we align up, we need to move one page backward and then apply the alignment function
   1159 	 * to determine the start page index.
   1160 	 */
   1161 	const int sparse_bo_data_start_offset			 = m_page_size - m_helper_bo_size_rounded / 2;
   1162 	int		  sparse_bo_data_start_offset_minus_page = sparse_bo_data_start_offset - m_page_size;
   1163 
   1164 	if (sparse_bo_data_start_offset_minus_page < 0)
   1165 	{
   1166 		sparse_bo_data_start_offset_minus_page = 0;
   1167 	}
   1168 
   1169 	m_sparse_bo_data_start_offset = sparse_bo_data_start_offset;
   1170 	m_sparse_bo_data_start_offset_rounded =
   1171 		SparseBufferTestUtilities::alignOffset(sparse_bo_data_start_offset_minus_page, m_page_size);
   1172 	m_sparse_bo_data_size = sparse_bo_data_size;
   1173 	m_sparse_bo_data_size_rounded =
   1174 		SparseBufferTestUtilities::alignOffset(m_sparse_bo_data_start_offset + sparse_bo_data_size, m_page_size);
   1175 
   1176 	DE_ASSERT((m_sparse_bo_data_size_rounded % m_page_size) == 0);
   1177 	DE_ASSERT((m_sparse_bo_data_start_offset_rounded % m_page_size) == 0);
   1178 
   1179 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_data_start_offset_rounded, m_sparse_bo_data_size_rounded,
   1180 								 GL_TRUE); /* commit */
   1181 
   1182 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   1183 
   1184 	return result;
   1185 }
   1186 
   1187 /** Constructor.
   1188  *
   1189  *  @param gl                         GL entry-points container
   1190  *  @param context                    CTS rendering context
   1191  *  @param testContext                CTS test context
   1192  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   1193  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   1194  */
   1195 BufferTextureStorageTestCase::BufferTextureStorageTestCase(const glw::Functions& gl, deqp::Context& context,
   1196 														   tcu::TestContext& testContext, glw::GLint page_size)
   1197 	: m_gl(gl)
   1198 	, m_helper_bo(0)
   1199 	, m_helper_bo_data(DE_NULL)
   1200 	, m_helper_bo_data_size(0)
   1201 	, m_is_texture_buffer_range_supported(false)
   1202 	, m_page_size(page_size)
   1203 	, m_po(0)
   1204 	, m_po_local_wg_size(1024)
   1205 	, m_sparse_bo(0)
   1206 	, m_sparse_bo_size(0)
   1207 	, m_sparse_bo_size_rounded(0)
   1208 	, m_ssbo(0)
   1209 	, m_ssbo_zero_data(DE_NULL)
   1210 	, m_ssbo_zero_data_size(0)
   1211 	, m_testCtx(testContext)
   1212 	, m_to(0)
   1213 	, m_to_width(65536) /* min max for GL_MAX_TEXTURE_BUFFER_SIZE_ARB */
   1214 {
   1215 	const glu::ContextInfo& context_info   = context.getContextInfo();
   1216 	glu::RenderContext&		render_context = context.getRenderContext();
   1217 
   1218 	if (glu::contextSupports(render_context.getType(), glu::ApiType::core(4, 3)) ||
   1219 		context_info.isExtensionSupported("GL_ARB_texture_buffer_range"))
   1220 	{
   1221 		m_is_texture_buffer_range_supported = true;
   1222 	}
   1223 }
   1224 
   1225 /** Releases all GL objects used across all test case iterations.
   1226  *
   1227  *  Called once during BufferStorage test run-time.
   1228  */
   1229 void BufferTextureStorageTestCase::deinitTestCaseGlobal()
   1230 {
   1231 	if (m_helper_bo != 0)
   1232 	{
   1233 		m_gl.deleteBuffers(1, &m_helper_bo);
   1234 
   1235 		m_helper_bo = 0;
   1236 	}
   1237 
   1238 	if (m_helper_bo_data != DE_NULL)
   1239 	{
   1240 		delete[] m_helper_bo_data;
   1241 
   1242 		m_helper_bo_data = DE_NULL;
   1243 	}
   1244 
   1245 	if (m_po != 0)
   1246 	{
   1247 		m_gl.deleteProgram(m_po);
   1248 
   1249 		m_po = 0;
   1250 	}
   1251 
   1252 	if (m_ssbo != 0)
   1253 	{
   1254 		m_gl.deleteBuffers(1, &m_ssbo);
   1255 
   1256 		m_ssbo = 0;
   1257 	}
   1258 
   1259 	if (m_ssbo_zero_data != DE_NULL)
   1260 	{
   1261 		delete[] m_ssbo_zero_data;
   1262 
   1263 		m_ssbo_zero_data = DE_NULL;
   1264 	}
   1265 
   1266 	if (m_to != 0)
   1267 	{
   1268 		m_gl.deleteTextures(1, &m_to);
   1269 
   1270 		m_to = 0;
   1271 	}
   1272 }
   1273 
   1274 /** Releases temporary GL objects, created specifically for one test case iteration. */
   1275 void BufferTextureStorageTestCase::deinitTestCaseIteration()
   1276 {
   1277 	if (m_sparse_bo != 0)
   1278 	{
   1279 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   1280 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1281 
   1282 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   1283 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   1284 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   1285 
   1286 		m_sparse_bo = 0;
   1287 	}
   1288 }
   1289 
   1290 /** Executes a single test iteration. The BufferStorage test will call this method
   1291  *  numerously during its life-time, testing various valid flag combinations applied
   1292  *  to the tested sparse buffer object at glBufferStorage() call time.
   1293  *
   1294  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   1295  *                                 call to set up the sparse buffer's storage.
   1296  *
   1297  *  @return true if the test case executed correctly, false otherwise.
   1298  */
   1299 bool BufferTextureStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   1300 {
   1301 	(void)sparse_bo_storage_flags;
   1302 	bool result = true;
   1303 
   1304 	/* Bind the program object */
   1305 	m_gl.useProgram(m_po);
   1306 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
   1307 
   1308 	m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
   1309 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1310 
   1311 	m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */
   1312 						m_ssbo);
   1313 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
   1314 
   1315 	/* Set up bindings for the copy ops */
   1316 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   1317 	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
   1318 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   1319 
   1320 	/* Run the test in two iterations:
   1321 	 *
   1322 	 * a) All required pages are committed.
   1323 	 * b) Only half of the pages are committed. */
   1324 	for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
   1325 	{
   1326 
   1327 		/* Test glTexBuffer() and glTexBufferRange() separately. */
   1328 		for (int n_entry_point = 0; n_entry_point < (m_is_texture_buffer_range_supported ? 2 : 1); ++n_entry_point)
   1329 		{
   1330 			bool result_local = true;
   1331 
   1332 			/* Set up the sparse buffer's memory backing. */
   1333 			const unsigned int tbo_commit_start_offset = (n_iteration == 0) ? 0 : m_sparse_bo_size_rounded / 2;
   1334 			const unsigned int tbo_commit_size =
   1335 				(n_iteration == 0) ? m_sparse_bo_size_rounded : m_sparse_bo_size_rounded / 2;
   1336 
   1337 			m_gl.bindBuffer(GL_TEXTURE_BUFFER, m_sparse_bo);
   1338 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1339 
   1340 			m_gl.bufferPageCommitmentARB(GL_TEXTURE_BUFFER, tbo_commit_start_offset, tbo_commit_size,
   1341 										 GL_TRUE); /* commit */
   1342 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   1343 
   1344 			/* Set up the buffer texture's backing */
   1345 			if (n_entry_point == 0)
   1346 			{
   1347 				m_gl.texBuffer(GL_TEXTURE_BUFFER, GL_RGBA8, m_sparse_bo);
   1348 
   1349 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexBuffer() call failed.");
   1350 			}
   1351 			else
   1352 			{
   1353 				m_gl.texBufferRange(GL_TEXTURE_BUFFER, GL_RGBA8, m_sparse_bo, 0, /* offset */
   1354 									m_sparse_bo_size);
   1355 
   1356 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexBufferRange() call failed.");
   1357 			}
   1358 
   1359 			/* Set up the sparse buffer's data storage */
   1360 			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   1361 								   0,											 /* writeOffset */
   1362 								   m_helper_bo_data_size);
   1363 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   1364 
   1365 			/* Run the compute program */
   1366 			DE_ASSERT((m_to_width % m_po_local_wg_size) == 0);
   1367 
   1368 			m_gl.dispatchCompute(m_to_width / m_po_local_wg_size, 1, /* num_groups_y */
   1369 								 1);								 /* num_groups_z */
   1370 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed.");
   1371 
   1372 			/* Flush the caches */
   1373 			m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
   1374 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed.");
   1375 
   1376 			/* Map the SSBO into process space, so we can check if the texture buffer's
   1377 			 * contents was found valid by the compute shader */
   1378 			unsigned int		current_tb_offset = 0;
   1379 			const unsigned int* ssbo_data_ptr =
   1380 				(const unsigned int*)m_gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
   1381 
   1382 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
   1383 
   1384 			for (unsigned int n_texel = 0; n_texel < m_to_width && result_local;
   1385 				 ++n_texel, current_tb_offset += 4 /* rgba */)
   1386 			{
   1387 				/* NOTE: Since the CS uses std140 layout, we need to move by 4 ints for
   1388 				 *       each result value */
   1389 				if (current_tb_offset >= tbo_commit_start_offset &&
   1390 					current_tb_offset < (tbo_commit_start_offset + tbo_commit_size) && ssbo_data_ptr[n_texel * 4] != 1)
   1391 				{
   1392 					m_testCtx.getLog() << tcu::TestLog::Message << "A texel read from the texture buffer at index "
   1393 																   "["
   1394 									   << n_texel << "]"
   1395 													 " was marked as invalid by the CS invocation."
   1396 									   << tcu::TestLog::EndMessage;
   1397 
   1398 					result_local = false;
   1399 				} /* if (ssbo_data_ptr[n_texel] != 1) */
   1400 			}	 /* for (all result values) */
   1401 
   1402 			result &= result_local;
   1403 
   1404 			m_gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
   1405 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   1406 
   1407 			/* Remove the physical backing from the sparse buffer  */
   1408 			m_gl.bufferPageCommitmentARB(GL_TEXTURE_BUFFER, 0,				  /* offset */
   1409 										 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   1410 
   1411 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   1412 
   1413 			/* Reset SSBO's contents */
   1414 			m_gl.bufferSubData(GL_SHADER_STORAGE_BUFFER, 0, /* offset */
   1415 							   m_ssbo_zero_data_size, m_ssbo_zero_data);
   1416 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
   1417 		} /* for (both entry-points) */
   1418 	}	 /* for (both iterations) */
   1419 
   1420 	return result;
   1421 }
   1422 
   1423 /** Initializes GL objects used across all test case iterations.
   1424  *
   1425  *  Called once during BufferStorage test run-time.
   1426  */
   1427 bool BufferTextureStorageTestCase::initTestCaseGlobal()
   1428 {
   1429 	/* Set up the test program */
   1430 	static const char* cs_body =
   1431 		"#version 430 core\n"
   1432 		"\n"
   1433 		"layout(local_size_x = 1024) in;\n"
   1434 		"\n"
   1435 		"layout(std140, binding = 0) buffer data\n"
   1436 		"{\n"
   1437 		"    restrict writeonly int result[];\n"
   1438 		"};\n"
   1439 		"\n"
   1440 		"uniform samplerBuffer input_texture;\n"
   1441 		"\n"
   1442 		"void main()\n"
   1443 		"{\n"
   1444 		"    uint texel_index = gl_GlobalInvocationID.x;\n"
   1445 		"\n"
   1446 		"    if (texel_index < 65536)\n"
   1447 		"    {\n"
   1448 		"        vec4 expected_texel_data = vec4       (float((texel_index)       % 255) / 255.0,\n"
   1449 		"                                               float((texel_index + 35)  % 255) / 255.0,\n"
   1450 		"                                               float((texel_index + 78)  % 255) / 255.0,\n"
   1451 		"                                               float((texel_index + 131) % 255) / 255.0);\n"
   1452 		"        vec4 texel_data          = texelFetch(input_texture, int(texel_index) );\n"
   1453 		"\n"
   1454 		"        if (abs(texel_data.r - expected_texel_data.r) > 1.0 / 255.0 ||\n"
   1455 		"            abs(texel_data.g - expected_texel_data.g) > 1.0 / 255.0 ||\n"
   1456 		"            abs(texel_data.b - expected_texel_data.b) > 1.0 / 255.0 ||\n"
   1457 		"            abs(texel_data.a - expected_texel_data.a) > 1.0 / 255.0)\n"
   1458 		"        {\n"
   1459 		"            result[texel_index] = 0;\n"
   1460 		"        }\n"
   1461 		"        else\n"
   1462 		"        {\n"
   1463 		"            result[texel_index] = 1;\n"
   1464 		"        }\n"
   1465 		"    }\n"
   1466 		"}\n";
   1467 
   1468 	m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
   1469 
   1470 	/* Set up a data buffer we will use to initialize the SSBO with default data.
   1471 	 *
   1472 	 * CS uses a std140 layout for the SSBO, so we need to add the additional padding.
   1473 	 */
   1474 	m_ssbo_zero_data_size = static_cast<unsigned int>(4 * sizeof(int) * m_to_width);
   1475 	m_ssbo_zero_data	  = new unsigned char[m_ssbo_zero_data_size];
   1476 
   1477 	memset(m_ssbo_zero_data, 0, m_ssbo_zero_data_size);
   1478 
   1479 	/* Set up the SSBO */
   1480 	m_gl.genBuffers(1, &m_ssbo);
   1481 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   1482 
   1483 	m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
   1484 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1485 
   1486 	m_gl.bufferData(GL_SHADER_STORAGE_BUFFER, m_ssbo_zero_data_size, m_ssbo_zero_data, GL_STATIC_DRAW);
   1487 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
   1488 
   1489 	/* During execution, we will need to use a helper buffer object. The BO will hold
   1490 	 * data we will be copying into the sparse buffer object for each iteration.
   1491 	 *
   1492 	 * Create an array to hold the helper buffer's data and fill it with info that
   1493 	 * the compute shader is going to be expecting */
   1494 	unsigned char* helper_bo_data_traveller_ptr = NULL;
   1495 
   1496 	m_helper_bo_data_size = m_to_width * 4; /* rgba */
   1497 	m_helper_bo_data	  = new unsigned char[m_helper_bo_data_size];
   1498 
   1499 	helper_bo_data_traveller_ptr = m_helper_bo_data;
   1500 
   1501 	for (unsigned int n_texel = 0; n_texel < m_to_width; ++n_texel)
   1502 	{
   1503 		/* Red */
   1504 		*helper_bo_data_traveller_ptr = static_cast<unsigned char>(n_texel % 255);
   1505 		++helper_bo_data_traveller_ptr;
   1506 
   1507 		/* Green */
   1508 		*helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 35) % 255);
   1509 		++helper_bo_data_traveller_ptr;
   1510 
   1511 		/* Blue */
   1512 		*helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 78) % 255);
   1513 		++helper_bo_data_traveller_ptr;
   1514 
   1515 		/* Alpha */
   1516 		*helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 131) % 255);
   1517 		++helper_bo_data_traveller_ptr;
   1518 	} /* for (all texels to be accessible via the buffer texture) */
   1519 
   1520 	/* Set up the helper buffer object which we are going to use to copy data into
   1521 	 * the sparse buffer object. */
   1522 	m_gl.genBuffers(1, &m_helper_bo);
   1523 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   1524 
   1525 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   1526 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1527 
   1528 	m_gl.bufferData(GL_COPY_READ_BUFFER, m_helper_bo_data_size, m_helper_bo_data, GL_STATIC_DRAW);
   1529 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
   1530 
   1531 	/* Set up the texture buffer object. We will attach the actual buffer storage
   1532 	 * in execute() */
   1533 	m_gl.genTextures(1, &m_to);
   1534 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
   1535 
   1536 	m_gl.bindTexture(GL_TEXTURE_BUFFER, m_to);
   1537 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
   1538 
   1539 	/* Determine the number of bytes both the helper and the sparse buffer
   1540 	 * object need to be able to hold, at maximum */
   1541 	m_sparse_bo_size		 = static_cast<unsigned int>(m_to_width * sizeof(int));
   1542 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
   1543 
   1544 	return true;
   1545 }
   1546 
   1547 /** Initializes GL objects which are needed for a single test case iteration.
   1548  *
   1549  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   1550  *  to release these objects.
   1551  **/
   1552 bool BufferTextureStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   1553 {
   1554 	bool result = true;
   1555 
   1556 	/* Cache the BO id, if not cached already */
   1557 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   1558 
   1559 	m_sparse_bo = sparse_bo;
   1560 
   1561 	return result;
   1562 }
   1563 
   1564 /** Constructor.
   1565  *
   1566  *  @param gl                         GL entry-points container
   1567  *  @param testContext                CTS test context
   1568  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   1569  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   1570  */
   1571 ClearOpsBufferStorageTestCase::ClearOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
   1572 															 glw::GLint page_size)
   1573 	: m_gl(gl)
   1574 	, m_helper_bo(0)
   1575 	, m_initial_data(DE_NULL)
   1576 	, m_n_pages_to_use(16)
   1577 	, m_page_size(page_size)
   1578 	, m_sparse_bo(0)
   1579 	, m_sparse_bo_size_rounded(0)
   1580 	, m_testCtx(testContext)
   1581 {
   1582 	/* Left blank intentionally */
   1583 }
   1584 
   1585 /** Releases all GL objects used across all test case iterations.
   1586  *
   1587  *  Called once during BufferStorage test run-time.
   1588  */
   1589 void ClearOpsBufferStorageTestCase::deinitTestCaseGlobal()
   1590 {
   1591 	if (m_helper_bo != 0)
   1592 	{
   1593 		m_gl.deleteBuffers(1, &m_helper_bo);
   1594 
   1595 		m_helper_bo = 0;
   1596 	}
   1597 
   1598 	if (m_initial_data != DE_NULL)
   1599 	{
   1600 		delete[] m_initial_data;
   1601 
   1602 		m_initial_data = DE_NULL;
   1603 	}
   1604 }
   1605 
   1606 /** Releases temporary GL objects, created specifically for one test case iteration. */
   1607 void ClearOpsBufferStorageTestCase::deinitTestCaseIteration()
   1608 {
   1609 	if (m_sparse_bo != 0)
   1610 	{
   1611 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   1612 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1613 
   1614 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   1615 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   1616 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   1617 
   1618 		m_sparse_bo = 0;
   1619 	}
   1620 }
   1621 
   1622 /** Executes a single test iteration. The BufferStorage test will call this method
   1623  *  numerously during its life-time, testing various valid flag combinations applied
   1624  *  to the tested sparse buffer object at glBufferStorage() call time.
   1625  *
   1626  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   1627  *                                 call to set up the sparse buffer's storage.
   1628  *
   1629  *  @return true if the test case executed correctly, false otherwise.
   1630  */
   1631 bool ClearOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   1632 {
   1633 	(void)sparse_bo_storage_flags;
   1634 	bool			   result	 = true;
   1635 	const unsigned int data_rgba8 = 0x12345678;
   1636 
   1637 	for (unsigned int n_clear_op_type = 0; n_clear_op_type < 2; /* glClearBufferData(), glClearBufferSubData() */
   1638 		 ++n_clear_op_type)
   1639 	{
   1640 		const bool use_clear_buffer_data_call = (n_clear_op_type == 0);
   1641 
   1642 		/* We will run the test case in two iterations:
   1643 		 *
   1644 		 * 1) All pages will have a physical backing.
   1645 		 * 2) Half of the pages will have a physical backing.
   1646 		 */
   1647 		for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
   1648 		{
   1649 			/* By default, for each iteration all sparse buffer pages are commited.
   1650 			 *
   1651 			 * For the last iteration, we need to de-commit the latter half before
   1652 			 * proceeding with the test.
   1653 			 */
   1654 			const bool all_pages_committed = (n_iteration == 0);
   1655 
   1656 			if (!all_pages_committed)
   1657 			{
   1658 				m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   1659 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1660 
   1661 				m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded / 2, /* offset */
   1662 											 m_sparse_bo_size_rounded / 2,					/* size   */
   1663 											 GL_TRUE);										/* commit */
   1664 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   1665 			}
   1666 
   1667 			/* Set up the sparse buffer contents */
   1668 			m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
   1669 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1670 
   1671 			m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
   1672 							   m_sparse_bo_size_rounded, m_initial_data);
   1673 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
   1674 
   1675 			m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   1676 			m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
   1677 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   1678 
   1679 			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER,  /* readTarget  */
   1680 								   GL_COPY_WRITE_BUFFER, /* writeTarget */
   1681 								   0,					 /* readOffset */
   1682 								   0,					 /* writeOffset */
   1683 								   m_sparse_bo_size_rounded);
   1684 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   1685 
   1686 			/* Issue the clear call */
   1687 			unsigned int clear_region_size		   = 0;
   1688 			unsigned int clear_region_start_offset = 0;
   1689 
   1690 			if (use_clear_buffer_data_call)
   1691 			{
   1692 				DE_ASSERT((m_sparse_bo_size_rounded % sizeof(unsigned int)) == 0);
   1693 
   1694 				clear_region_size		  = m_sparse_bo_size_rounded;
   1695 				clear_region_start_offset = 0;
   1696 
   1697 				m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &data_rgba8);
   1698 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
   1699 			}
   1700 			else
   1701 			{
   1702 				DE_ASSERT(((m_sparse_bo_size_rounded / 2) % sizeof(unsigned int)) == 0);
   1703 				DE_ASSERT(((m_sparse_bo_size_rounded) % sizeof(unsigned int)) == 0);
   1704 
   1705 				clear_region_size		  = m_sparse_bo_size_rounded / 2;
   1706 				clear_region_start_offset = m_sparse_bo_size_rounded / 2;
   1707 
   1708 				m_gl.clearBufferSubData(GL_COPY_WRITE_BUFFER, GL_RGBA8, clear_region_start_offset, clear_region_size,
   1709 										GL_RGBA, GL_UNSIGNED_BYTE, &data_rgba8);
   1710 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferSubData() call failed.");
   1711 			}
   1712 
   1713 			/* Retrieve the modified buffer's contents */
   1714 			const unsigned char* result_data = NULL;
   1715 
   1716 			m_gl.copyBufferSubData(GL_COPY_WRITE_BUFFER, /* readTarget  */
   1717 								   GL_COPY_READ_BUFFER,  /* writeTarget */
   1718 								   0,					 /* readOffset  */
   1719 								   0,					 /* writeOffset */
   1720 								   m_sparse_bo_size_rounded);
   1721 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   1722 
   1723 			result_data = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */
   1724 															  m_sparse_bo_size_rounded, GL_MAP_READ_BIT);
   1725 
   1726 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
   1727 
   1728 			/* Verify the result data: unmodified region */
   1729 			bool			   result_local			  = true;
   1730 			const unsigned int unmodified_region_size = (use_clear_buffer_data_call) ? 0 : clear_region_start_offset;
   1731 			const unsigned int unmodified_region_start_offset = 0;
   1732 
   1733 			for (unsigned int n_current_byte = unmodified_region_start_offset;
   1734 				 (n_current_byte < unmodified_region_start_offset + unmodified_region_size) && result_local;
   1735 				 ++n_current_byte)
   1736 			{
   1737 				const unsigned int  current_initial_data_offset = n_current_byte - unmodified_region_start_offset;
   1738 				const unsigned char expected_value				= m_initial_data[current_initial_data_offset];
   1739 				const unsigned char found_value					= result_data[n_current_byte];
   1740 
   1741 				if (expected_value != found_value)
   1742 				{
   1743 					m_testCtx.getLog() << tcu::TestLog::Message
   1744 									   << "Unmodified buffer object region has invalid contents. Expected byte "
   1745 									   << "[" << (int)expected_value << "]"
   1746 																		", found byte:"
   1747 																		"["
   1748 									   << (int)found_value << "]"
   1749 															  " at index "
   1750 															  "["
   1751 									   << n_current_byte << "]; "
   1752 															"call type:"
   1753 															"["
   1754 									   << ((use_clear_buffer_data_call) ? "glClearBufferData()" :
   1755 																		  "glClearBufferSubData()")
   1756 									   << "]"
   1757 										  ", all required pages committed?:"
   1758 										  "["
   1759 									   << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage;
   1760 
   1761 					result_local = false;
   1762 					break;
   1763 				}
   1764 			}
   1765 
   1766 			result &= result_local;
   1767 			result_local = true;
   1768 
   1769 			/* Verify the result data: modified region (clamped to the memory region
   1770 			 * with actual physical backing) */
   1771 			const unsigned int modified_region_size			= (all_pages_committed) ? clear_region_size : 0;
   1772 			const unsigned int modified_region_start_offset = clear_region_start_offset;
   1773 
   1774 			for (unsigned int n_current_byte = modified_region_start_offset;
   1775 				 (n_current_byte < modified_region_start_offset + modified_region_size) && result_local;
   1776 				 ++n_current_byte)
   1777 			{
   1778 				const unsigned char expected_value =
   1779 					static_cast<unsigned char>((data_rgba8 & (0xFF << (n_current_byte * 8))) >> (n_current_byte * 8));
   1780 				const unsigned char found_value = result_data[n_current_byte];
   1781 
   1782 				if (expected_value != found_value)
   1783 				{
   1784 					m_testCtx.getLog() << tcu::TestLog::Message
   1785 									   << "Unmodified buffer object region has invalid contents. Expected byte "
   1786 									   << "[" << (int)expected_value << "]"
   1787 																		", found byte:"
   1788 																		"["
   1789 									   << (int)found_value << "]"
   1790 															  " at index "
   1791 															  "["
   1792 									   << n_current_byte << "]; "
   1793 															"call type:"
   1794 															"["
   1795 									   << ((use_clear_buffer_data_call) ? "glClearBufferData()" :
   1796 																		  "glClearBufferSubData()")
   1797 									   << "]"
   1798 										  ", all required pages committed?:"
   1799 										  "["
   1800 									   << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage;
   1801 
   1802 					result_local = false;
   1803 					break;
   1804 				}
   1805 			}
   1806 
   1807 			result &= result_local;
   1808 
   1809 			/* Unmap the storage before proceeding */
   1810 			m_gl.unmapBuffer(GL_COPY_READ_BUFFER);
   1811 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   1812 		} /* for (both iterations) */
   1813 	}	 /* for (both clear types) */
   1814 
   1815 	return result;
   1816 }
   1817 
   1818 /** Initializes GL objects used across all test case iterations.
   1819  *
   1820  *  Called once during BufferStorage test run-time.
   1821  */
   1822 bool ClearOpsBufferStorageTestCase::initTestCaseGlobal()
   1823 {
   1824 	unsigned int	   n_bytes_filled = 0;
   1825 	const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size;
   1826 
   1827 	/* Determine the number of bytes both the helper and the sparse buffer
   1828 	 * object need to be able to hold, at maximum */
   1829 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size);
   1830 
   1831 	/* Set up the helper BO */
   1832 	DE_ASSERT(m_helper_bo == 0);
   1833 
   1834 	m_gl.genBuffers(1, &m_helper_bo);
   1835 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   1836 
   1837 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   1838 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1839 
   1840 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_size_rounded, DE_NULL,
   1841 					   GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT); /* flags */
   1842 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   1843 
   1844 	/* Set up a client-side data buffer we will use to fill the sparse BO with data,
   1845 	 * to be later cleared with the clear ops */
   1846 	DE_ASSERT(m_initial_data == DE_NULL);
   1847 
   1848 	m_initial_data = new unsigned char[m_sparse_bo_size_rounded];
   1849 
   1850 	while (n_bytes_filled < m_sparse_bo_size_rounded)
   1851 	{
   1852 		m_initial_data[n_bytes_filled] = static_cast<unsigned char>(n_bytes_filled % 256);
   1853 
   1854 		++n_bytes_filled;
   1855 	}
   1856 
   1857 	return true;
   1858 }
   1859 
   1860 /** Initializes GL objects which are needed for a single test case iteration.
   1861  *
   1862  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   1863  *  to release these objects.
   1864  **/
   1865 bool ClearOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   1866 {
   1867 	bool result = true;
   1868 
   1869 	/* Cache the BO id, if not cached already */
   1870 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   1871 
   1872 	m_sparse_bo = sparse_bo;
   1873 
   1874 	/* Set up the sparse bufffer. */
   1875 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   1876 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1877 
   1878 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
   1879 								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
   1880 
   1881 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   1882 
   1883 	return result;
   1884 }
   1885 
   1886 /** Constructor.
   1887  *
   1888  *  @param gl                         GL entry-points container
   1889  *  @param testContext                CTS test context
   1890  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   1891  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   1892  */
   1893 CopyOpsBufferStorageTestCase::CopyOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
   1894 														   glw::GLint page_size)
   1895 	: m_gl(gl)
   1896 	, m_helper_bo(0)
   1897 	, m_immutable_bo(0)
   1898 	, m_page_size(page_size)
   1899 	, m_sparse_bo_size(0)
   1900 	, m_sparse_bo_size_rounded(0)
   1901 	, m_testCtx(testContext)
   1902 {
   1903 	m_ref_data[0]   = DE_NULL;
   1904 	m_ref_data[1]   = DE_NULL;
   1905 	m_ref_data[2]   = DE_NULL;
   1906 	m_sparse_bos[0] = 0;
   1907 	m_sparse_bos[1] = 0;
   1908 }
   1909 
   1910 /** Releases all GL objects used across all test case iterations.
   1911  *
   1912  *  Called once during BufferStorage test run-time.
   1913  */
   1914 
   1915 void CopyOpsBufferStorageTestCase::deinitTestCaseGlobal()
   1916 {
   1917 	if (m_helper_bo != 0)
   1918 	{
   1919 		m_gl.deleteBuffers(1, &m_helper_bo);
   1920 
   1921 		m_helper_bo = 0;
   1922 	}
   1923 
   1924 	if (m_immutable_bo != 0)
   1925 	{
   1926 		m_gl.deleteBuffers(1, &m_immutable_bo);
   1927 
   1928 		m_immutable_bo = 0;
   1929 	}
   1930 
   1931 	for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]);
   1932 		 ++n_ref_data_buffer)
   1933 	{
   1934 		if (m_ref_data[n_ref_data_buffer] != DE_NULL)
   1935 		{
   1936 			delete[] m_ref_data[n_ref_data_buffer];
   1937 
   1938 			m_ref_data[n_ref_data_buffer] = DE_NULL;
   1939 		}
   1940 	}
   1941 
   1942 	/* Only release the test case-owned BO */
   1943 	if (m_sparse_bos[1] != 0)
   1944 	{
   1945 		m_gl.deleteBuffers(1, m_sparse_bos + 1);
   1946 
   1947 		m_sparse_bos[1] = 0;
   1948 	}
   1949 }
   1950 
   1951 /** Releases temporary GL objects, created specifically for one test case iteration. */
   1952 void CopyOpsBufferStorageTestCase::deinitTestCaseIteration()
   1953 {
   1954 	for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
   1955 	{
   1956 		const glw::GLuint sparse_bo_id = m_sparse_bos[n_sparse_bo];
   1957 
   1958 		if (sparse_bo_id != 0)
   1959 		{
   1960 			m_gl.bindBuffer(GL_ARRAY_BUFFER, sparse_bo_id);
   1961 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   1962 
   1963 			m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   1964 										 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   1965 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   1966 		} /* if (sparse_bo_id != 0) */
   1967 	}	 /* for (both BOs) */
   1968 }
   1969 
   1970 /** Executes a single test iteration. The BufferStorage test will call this method
   1971  *  numerously during its life-time, testing various valid flag combinations applied
   1972  *  to the tested sparse buffer object at glBufferStorage() call time.
   1973  *
   1974  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   1975  *                                 call to set up the sparse buffer's storage.
   1976  *
   1977  *  @return true if the test case executed correctly, false otherwise.
   1978  */
   1979 bool CopyOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   1980 {
   1981 	(void)sparse_bo_storage_flags;
   1982 	bool result = true;
   1983 
   1984 	/* Iterate over all test cases */
   1985 	DE_ASSERT(m_immutable_bo != 0);
   1986 	DE_ASSERT(m_sparse_bos[0] != 0);
   1987 	DE_ASSERT(m_sparse_bos[1] != 0);
   1988 
   1989 	for (_test_cases_const_iterator test_iterator = m_test_cases.begin(); test_iterator != m_test_cases.end();
   1990 		 ++test_iterator)
   1991 	{
   1992 		bool			  result_local = true;
   1993 		const _test_case& test_case	= *test_iterator;
   1994 		const glw::GLuint dst_bo_id =
   1995 			test_case.dst_bo_is_sparse ? m_sparse_bos[test_case.dst_bo_sparse_id] : m_immutable_bo;
   1996 		const glw::GLuint src_bo_id =
   1997 			test_case.src_bo_is_sparse ? m_sparse_bos[test_case.src_bo_sparse_id] : m_immutable_bo;
   1998 
   1999 		/* Initialize immutable BO data (if used) */
   2000 		if (dst_bo_id == m_immutable_bo || src_bo_id == m_immutable_bo)
   2001 		{
   2002 			m_gl.bindBuffer(GL_ARRAY_BUFFER, m_immutable_bo);
   2003 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2004 
   2005 			m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
   2006 							   m_sparse_bo_size_rounded, m_ref_data[0]);
   2007 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
   2008 		}
   2009 
   2010 		/* Initialize sparse BO data storage */
   2011 		for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
   2012 		{
   2013 			const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]);
   2014 			const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]);
   2015 
   2016 			if (!is_dst_bo && !is_src_bo)
   2017 				continue;
   2018 
   2019 			m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   2020 			m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bos[n_sparse_bo]);
   2021 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   2022 
   2023 			if (is_dst_bo)
   2024 			{
   2025 				m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.dst_bo_commit_start_offset,
   2026 											 test_case.dst_bo_commit_size, GL_TRUE); /* commit */
   2027 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   2028 			}
   2029 
   2030 			if (is_src_bo)
   2031 			{
   2032 				m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.src_bo_commit_start_offset,
   2033 											 test_case.src_bo_commit_size, GL_TRUE); /* commit */
   2034 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   2035 			}
   2036 
   2037 			m_gl.bufferSubData(GL_COPY_READ_BUFFER, 0, /* offset */
   2038 							   m_sparse_bo_size_rounded, m_ref_data[1 + n_sparse_bo]);
   2039 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
   2040 
   2041 			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   2042 								   0,											 /* writeOffset */
   2043 								   m_sparse_bo_size_rounded);
   2044 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   2045 		} /* for (both sparse BOs) */
   2046 
   2047 		/* Set up the bindings */
   2048 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, src_bo_id);
   2049 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, dst_bo_id);
   2050 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2051 
   2052 		/* Issue the copy op */
   2053 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, test_case.src_bo_start_offset,
   2054 							   test_case.dst_bo_start_offset, test_case.n_bytes_to_copy);
   2055 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   2056 
   2057 		/* Retrieve the destination buffer's contents. The BO used for the previous copy op might have
   2058 		 * been a sparse BO, so copy its storage to a helper immutable BO */
   2059 		const unsigned short* dst_bo_data_ptr = NULL;
   2060 
   2061 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, dst_bo_id);
   2062 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
   2063 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2064 
   2065 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   2066 							   0,											 /* writeOffset */
   2067 							   m_sparse_bo_size_rounded);
   2068 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   2069 
   2070 		dst_bo_data_ptr = (const unsigned short*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */
   2071 																	 m_sparse_bo_size_rounded, GL_MAP_READ_BIT);
   2072 
   2073 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
   2074 
   2075 		/* Verify the retrieved data:
   2076 		 *
   2077 		 * 1. Check the bytes which precede the copy op dst offset. These should be equal to
   2078 		 *    the destination buffer's reference data within the committed memory region.
   2079 		 **/
   2080 		if (test_case.dst_bo_start_offset != 0 && test_case.dst_bo_commit_start_offset < test_case.dst_bo_start_offset)
   2081 		{
   2082 			DE_ASSERT(((test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) % sizeof(short)) == 0);
   2083 
   2084 			const unsigned int n_valid_values = static_cast<unsigned int>(
   2085 				(test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) / sizeof(short));
   2086 
   2087 			for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value)
   2088 			{
   2089 				const int dst_data_offset = static_cast<int>(sizeof(short) * n_value);
   2090 
   2091 				if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
   2092 					dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
   2093 				{
   2094 					const unsigned short expected_short_value =
   2095 						*(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset);
   2096 					const unsigned short found_short_value =
   2097 						*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
   2098 
   2099 					if (expected_short_value != found_short_value)
   2100 					{
   2101 						m_testCtx.getLog()
   2102 							<< tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, "
   2103 														"preceding the region modified by the copy op. "
   2104 							<< "Destination BO id:" << dst_bo_id << " ("
   2105 							<< ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
   2106 							<< ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
   2107 							<< (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
   2108 							<< ", copy region: " << test_case.dst_bo_start_offset << ":"
   2109 							<< (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
   2110 							<< ". Source BO id:" << src_bo_id << " ("
   2111 							<< ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
   2112 							<< ", commited region: " << test_case.src_bo_commit_start_offset << ":"
   2113 							<< (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
   2114 							<< ", copy region: " << test_case.src_bo_start_offset << ":"
   2115 							<< (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of "
   2116 							<< expected_short_value << ", found value of " << found_short_value
   2117 							<< " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage;
   2118 
   2119 						result_local = false;
   2120 					}
   2121 				}
   2122 			} /* for (all preceding values which should not have been affected by the copy op) */
   2123 		}	 /* if (copy op did not modify the beginning of the destination buffer storage) */
   2124 
   2125 		/* 2. Check if the data written to the destination buffer object is correct. */
   2126 		for (unsigned int n_copied_short_value = 0;
   2127 			 n_copied_short_value < test_case.n_bytes_to_copy / sizeof(short) && result_local; ++n_copied_short_value)
   2128 		{
   2129 			const int src_data_offset =
   2130 				static_cast<unsigned int>(test_case.src_bo_start_offset + sizeof(short) * n_copied_short_value);
   2131 			const int dst_data_offset =
   2132 				static_cast<unsigned int>(test_case.dst_bo_start_offset + sizeof(short) * n_copied_short_value);
   2133 
   2134 			if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
   2135 				dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size &&
   2136 				src_data_offset >= test_case.src_bo_commit_start_offset &&
   2137 				src_data_offset < test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
   2138 			{
   2139 				const unsigned short expected_short_value =
   2140 					*(unsigned short*)((unsigned char*)test_case.src_bo_ref_data + src_data_offset);
   2141 				const unsigned short found_short_value =
   2142 					*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
   2143 
   2144 				if (expected_short_value != found_short_value)
   2145 				{
   2146 					m_testCtx.getLog() << tcu::TestLog::Message
   2147 									   << "Malformed data found in the copy op's destination BO. "
   2148 									   << "Destination BO id:" << dst_bo_id << " ("
   2149 									   << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
   2150 									   << ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
   2151 									   << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
   2152 									   << ", copy region: " << test_case.dst_bo_start_offset << ":"
   2153 									   << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
   2154 									   << ". Source BO id:" << src_bo_id << " ("
   2155 									   << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
   2156 									   << ", commited region: " << test_case.src_bo_commit_start_offset << ":"
   2157 									   << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
   2158 									   << ", copy region: " << test_case.src_bo_start_offset << ":"
   2159 									   << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy)
   2160 									   << ". Expected value of " << expected_short_value << ", found value of "
   2161 									   << found_short_value << " at dst data offset of " << dst_data_offset << "."
   2162 									   << tcu::TestLog::EndMessage;
   2163 
   2164 					result_local = false;
   2165 				}
   2166 			}
   2167 		}
   2168 
   2169 		/* 3. Verify the remaining data in the committed part of the destination buffer object is left intact. */
   2170 		const unsigned int commit_region_end_offset =
   2171 			test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size;
   2172 		const unsigned int copy_region_end_offset = test_case.dst_bo_start_offset + test_case.n_bytes_to_copy;
   2173 
   2174 		if (commit_region_end_offset > copy_region_end_offset)
   2175 		{
   2176 			DE_ASSERT(((commit_region_end_offset - copy_region_end_offset) % sizeof(short)) == 0);
   2177 
   2178 			const unsigned int n_valid_values =
   2179 				static_cast<unsigned int>((commit_region_end_offset - copy_region_end_offset) / sizeof(short));
   2180 
   2181 			for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value)
   2182 			{
   2183 				const int dst_data_offset = static_cast<int>(copy_region_end_offset + sizeof(short) * n_value);
   2184 
   2185 				if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
   2186 					dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
   2187 				{
   2188 					const unsigned short expected_short_value =
   2189 						*(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset);
   2190 					const unsigned short found_short_value =
   2191 						*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
   2192 
   2193 					if (expected_short_value != found_short_value)
   2194 					{
   2195 						m_testCtx.getLog()
   2196 							<< tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, "
   2197 														"following the region modified by the copy op. "
   2198 							<< "Destination BO id:" << dst_bo_id << " ("
   2199 							<< ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
   2200 							<< ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
   2201 							<< (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
   2202 							<< ", copy region: " << test_case.dst_bo_start_offset << ":"
   2203 							<< (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
   2204 							<< ". Source BO id:" << src_bo_id << " ("
   2205 							<< ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
   2206 							<< ", commited region: " << test_case.src_bo_commit_start_offset << ":"
   2207 							<< (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
   2208 							<< ", copy region: " << test_case.src_bo_start_offset << ":"
   2209 							<< (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of "
   2210 							<< expected_short_value << ", found value of " << found_short_value
   2211 							<< " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage;
   2212 
   2213 						result_local = false;
   2214 					}
   2215 				}
   2216 			} /* for (all preceding values which should not have been affected by the copy op) */
   2217 		}	 /* if (copy op did not modify the beginning of the destination buffer storage) */
   2218 
   2219 		/* Unmap the buffer storage */
   2220 		m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
   2221 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   2222 
   2223 		/* Clean up */
   2224 		for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
   2225 		{
   2226 			const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]);
   2227 			const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]);
   2228 
   2229 			if (is_dst_bo || is_src_bo)
   2230 			{
   2231 				m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[n_sparse_bo]);
   2232 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2233 
   2234 				m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   2235 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   2236 			}
   2237 		}
   2238 
   2239 		result &= result_local;
   2240 	} /* for (all test cases) */
   2241 
   2242 	return result;
   2243 }
   2244 
   2245 /** Allocates reference buffers, fills them with data and updates the m_ref_data array. */
   2246 void CopyOpsBufferStorageTestCase::initReferenceData()
   2247 {
   2248 	DE_ASSERT(m_sparse_bo_size_rounded != 0);
   2249 	DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0);
   2250 	DE_ASSERT(sizeof(short) == 2);
   2251 
   2252 	for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]);
   2253 		 ++n_ref_data_buffer)
   2254 	{
   2255 		DE_ASSERT(m_ref_data[n_ref_data_buffer] == DE_NULL);
   2256 
   2257 		m_ref_data[n_ref_data_buffer] = new unsigned short[m_sparse_bo_size_rounded / 2];
   2258 
   2259 		/* Write reference values. */
   2260 		for (unsigned int n_short_value = 0; n_short_value < m_sparse_bo_size_rounded / 2; ++n_short_value)
   2261 		{
   2262 			m_ref_data[n_ref_data_buffer][n_short_value] =
   2263 				(unsigned short)((n_ref_data_buffer + 1) * (n_short_value + 1));
   2264 		}
   2265 	} /* for (all reference data buffers) */
   2266 }
   2267 
   2268 /** Initializes GL objects used across all test case iterations.
   2269  *
   2270  *  Called once during BufferStorage test run-time.
   2271  */
   2272 bool CopyOpsBufferStorageTestCase::initTestCaseGlobal()
   2273 {
   2274 	m_sparse_bo_size		 = 2 * 3 * 4 * m_page_size;
   2275 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
   2276 
   2277 	initReferenceData();
   2278 
   2279 	/* Initialize the sparse buffer object */
   2280 	m_gl.genBuffers(1, m_sparse_bos + 1);
   2281 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   2282 
   2283 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[1]);
   2284 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2285 
   2286 	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, DE_NULL, /* data */
   2287 					   GL_SPARSE_STORAGE_BIT_ARB);
   2288 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   2289 
   2290 	/* Initialize the immutable buffer objects used by the test */
   2291 	for (unsigned int n_bo = 0; n_bo < 2; /* helper + immutable BO used for the copy ops */
   2292 		 ++n_bo)
   2293 	{
   2294 		glw::GLuint* bo_id_ptr = (n_bo == 0) ? &m_helper_bo : &m_immutable_bo;
   2295 		glw::GLenum  flags	 = GL_DYNAMIC_STORAGE_BIT;
   2296 
   2297 		if (n_bo == 0)
   2298 		{
   2299 			flags |= GL_MAP_READ_BIT;
   2300 		}
   2301 
   2302 		/* Initialize the immutable buffer object */
   2303 		m_gl.genBuffers(1, bo_id_ptr);
   2304 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   2305 
   2306 		m_gl.bindBuffer(GL_ARRAY_BUFFER, *bo_id_ptr);
   2307 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2308 
   2309 		m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, m_ref_data[0], flags);
   2310 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   2311 	}
   2312 
   2313 	return true;
   2314 }
   2315 
   2316 /** Initializes GL objects which are needed for a single test case iteration.
   2317  *
   2318  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   2319  *  to release these objects.
   2320  **/
   2321 bool CopyOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   2322 {
   2323 	bool result = true;
   2324 
   2325 	/* Remember the BO id */
   2326 	m_sparse_bos[0] = sparse_bo;
   2327 
   2328 	/* Initialize test cases, if this is the first call to initTestCaseIteration() */
   2329 	if (m_test_cases.size() == 0)
   2330 	{
   2331 		initTestCases();
   2332 	}
   2333 
   2334 	/* Make sure all pages of the provided sparse BO are de-committed before
   2335 	 * ::execute() is called. */
   2336 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[0]);
   2337 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2338 
   2339 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   2340 								 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   2341 
   2342 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   2343 
   2344 	return result;
   2345 }
   2346 
   2347 /** Fills m_test_cases with test case descriptors. Each such descriptor defines
   2348  *  a single copy op use case.
   2349  *
   2350  * The descriptors are then iterated over in ::execute(), defining the testing
   2351  * behavior of the test copy ops buffer storage test case.
   2352  */
   2353 void CopyOpsBufferStorageTestCase::initTestCases()
   2354 {
   2355 	/* We need to use the following destination & source BO configurations:
   2356 	 *
   2357 	 * Dst: sparse    BO 1;  Src: sparse    BO 2
   2358 	 * Dst: sparse    BO 1;  Src: immutable BO
   2359 	 * Dst: immutable BO;    Src: sparse    BO 1
   2360 	 * Dst: sparse    BO 1;  Src: sparse    BO 1
   2361 	 */
   2362 	unsigned int n_test_case = 0;
   2363 
   2364 	for (unsigned int n_bo_configuration = 0; n_bo_configuration < 4; /* as per the comment */
   2365 		 ++n_bo_configuration, ++n_test_case)
   2366 	{
   2367 		glw::GLuint		dst_bo_sparse_id = 0;
   2368 		bool			dst_bo_is_sparse = false;
   2369 		unsigned short* dst_bo_ref_data  = DE_NULL;
   2370 		glw::GLuint		src_bo_sparse_id = 0;
   2371 		bool			src_bo_is_sparse = false;
   2372 		unsigned short* src_bo_ref_data  = DE_NULL;
   2373 
   2374 		switch (n_bo_configuration)
   2375 		{
   2376 		case 0:
   2377 		{
   2378 			dst_bo_sparse_id = 0;
   2379 			dst_bo_is_sparse = true;
   2380 			dst_bo_ref_data  = m_ref_data[1];
   2381 			src_bo_sparse_id = 1;
   2382 			src_bo_is_sparse = true;
   2383 			src_bo_ref_data  = m_ref_data[2];
   2384 
   2385 			break;
   2386 		}
   2387 
   2388 		case 1:
   2389 		{
   2390 			dst_bo_sparse_id = 0;
   2391 			dst_bo_is_sparse = true;
   2392 			dst_bo_ref_data  = m_ref_data[1];
   2393 			src_bo_is_sparse = false;
   2394 			src_bo_ref_data  = m_ref_data[0];
   2395 
   2396 			break;
   2397 		}
   2398 
   2399 		case 2:
   2400 		{
   2401 			dst_bo_is_sparse = false;
   2402 			dst_bo_ref_data  = m_ref_data[0];
   2403 			src_bo_sparse_id = 0;
   2404 			src_bo_is_sparse = true;
   2405 			src_bo_ref_data  = m_ref_data[1];
   2406 
   2407 			break;
   2408 		}
   2409 
   2410 		case 3:
   2411 		{
   2412 			dst_bo_sparse_id = 0;
   2413 			dst_bo_is_sparse = true;
   2414 			dst_bo_ref_data  = m_ref_data[1];
   2415 			src_bo_sparse_id = 0;
   2416 			src_bo_is_sparse = true;
   2417 			src_bo_ref_data  = m_ref_data[1];
   2418 
   2419 			break;
   2420 		}
   2421 
   2422 		default:
   2423 		{
   2424 			TCU_FAIL("Invalid BO configuration index");
   2425 		}
   2426 		} /* switch (n_bo_configuration) */
   2427 
   2428 		/* Need to test the copy operation in three different scenarios,
   2429 		 * in regard to the destination buffer:
   2430 		 *
   2431 		 * a) All pages of the destination region are committed.
   2432 		 * b) Half of the pages of the destination region are committed.
   2433 		 * c) None of the pages of the destination region are committed.
   2434 		 *
   2435 		 * Destination region spans from 0 to half of the memory we use
   2436 		 * for the testing purposes.
   2437 		 */
   2438 		DE_ASSERT((m_sparse_bo_size_rounded % m_page_size) == 0);
   2439 		DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0);
   2440 		DE_ASSERT((m_sparse_bo_size_rounded % 4) == 0);
   2441 
   2442 		for (unsigned int n_dst_region = 0; n_dst_region < 3; /* as per the comment */
   2443 			 ++n_dst_region)
   2444 		{
   2445 			glw::GLuint dst_bo_commit_size		   = 0;
   2446 			glw::GLuint dst_bo_commit_start_offset = 0;
   2447 
   2448 			switch (n_dst_region)
   2449 			{
   2450 			case 0:
   2451 			{
   2452 				dst_bo_commit_start_offset = 0;
   2453 				dst_bo_commit_size		   = m_sparse_bo_size_rounded / 2;
   2454 
   2455 				break;
   2456 			}
   2457 
   2458 			case 1:
   2459 			{
   2460 				dst_bo_commit_start_offset = m_sparse_bo_size_rounded / 4;
   2461 				dst_bo_commit_size		   = m_sparse_bo_size_rounded / 4;
   2462 
   2463 				break;
   2464 			}
   2465 
   2466 			case 2:
   2467 			{
   2468 				dst_bo_commit_start_offset = 0;
   2469 				dst_bo_commit_size		   = 0;
   2470 
   2471 				break;
   2472 			}
   2473 
   2474 			default:
   2475 			{
   2476 				TCU_FAIL("Invalid destination region configuration index");
   2477 			}
   2478 			} /* switch (n_dst_region) */
   2479 
   2480 			/* Same goes for the source region.
   2481 			 *
   2482 			 * Source region spans from m_sparse_bo_size_rounded / 2 to
   2483 			 * m_sparse_bo_size_rounded.
   2484 			 *
   2485 			 **/
   2486 			for (unsigned int n_src_region = 0; n_src_region < 3; /* as per the comment */
   2487 				 ++n_src_region)
   2488 			{
   2489 				glw::GLuint src_bo_commit_size		   = 0;
   2490 				glw::GLuint src_bo_commit_start_offset = 0;
   2491 
   2492 				switch (n_src_region)
   2493 				{
   2494 				case 0:
   2495 				{
   2496 					src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2;
   2497 					src_bo_commit_size		   = m_sparse_bo_size_rounded / 2;
   2498 
   2499 					break;
   2500 				}
   2501 
   2502 				case 1:
   2503 				{
   2504 					src_bo_commit_start_offset = 3 * m_sparse_bo_size_rounded / 4;
   2505 					src_bo_commit_size		   = m_sparse_bo_size_rounded / 4;
   2506 
   2507 					break;
   2508 				}
   2509 
   2510 				case 2:
   2511 				{
   2512 					src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2;
   2513 					src_bo_commit_size		   = 0;
   2514 
   2515 					break;
   2516 				}
   2517 
   2518 				default:
   2519 				{
   2520 					TCU_FAIL("Invalid source region configuration index");
   2521 				}
   2522 				} /* switch (n_src_region) */
   2523 
   2524 				/* Initialize the test case descriptor */
   2525 				_test_case test_case;
   2526 
   2527 				test_case.dst_bo_commit_size		 = dst_bo_commit_size;
   2528 				test_case.dst_bo_commit_start_offset = dst_bo_commit_start_offset;
   2529 				test_case.dst_bo_sparse_id			 = dst_bo_sparse_id;
   2530 				test_case.dst_bo_is_sparse			 = dst_bo_is_sparse;
   2531 				test_case.dst_bo_ref_data			 = dst_bo_ref_data;
   2532 				test_case.dst_bo_start_offset		 = static_cast<glw::GLint>(sizeof(short) * n_test_case);
   2533 				test_case.n_bytes_to_copy			 = static_cast<glw::GLint>(
   2534 					m_sparse_bo_size_rounded / 2 - test_case.dst_bo_start_offset - sizeof(short) * n_test_case);
   2535 				test_case.src_bo_commit_size		 = src_bo_commit_size;
   2536 				test_case.src_bo_commit_start_offset = src_bo_commit_start_offset;
   2537 				test_case.src_bo_sparse_id			 = src_bo_sparse_id;
   2538 				test_case.src_bo_is_sparse			 = src_bo_is_sparse;
   2539 				test_case.src_bo_ref_data			 = src_bo_ref_data;
   2540 				test_case.src_bo_start_offset		 = m_sparse_bo_size_rounded / 2;
   2541 
   2542 				DE_ASSERT(test_case.dst_bo_commit_size >= 0);
   2543 				DE_ASSERT(test_case.dst_bo_commit_start_offset >= 0);
   2544 				DE_ASSERT(test_case.dst_bo_ref_data != DE_NULL);
   2545 				DE_ASSERT(test_case.dst_bo_start_offset >= 0);
   2546 				DE_ASSERT(test_case.n_bytes_to_copy >= 0);
   2547 				DE_ASSERT(test_case.src_bo_commit_size >= 0);
   2548 				DE_ASSERT(test_case.src_bo_commit_start_offset >= 0);
   2549 				DE_ASSERT(test_case.src_bo_ref_data != DE_NULL);
   2550 				DE_ASSERT(test_case.src_bo_start_offset >= 0);
   2551 
   2552 				m_test_cases.push_back(test_case);
   2553 			} /* for (all source region commit configurations) */
   2554 		}	 /* for (all destination region commit configurations) */
   2555 	}		  /* for (all BO configurations which need to be tested) */
   2556 }
   2557 
   2558 /** Constructor.
   2559  *
   2560  *  @param gl                         GL entry-points container
   2561  *  @param testContext                CTS test context
   2562  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   2563  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   2564  */
   2565 IndirectDispatchBufferStorageTestCase::IndirectDispatchBufferStorageTestCase(const glw::Functions& gl,
   2566 																			 tcu::TestContext&	 testContext,
   2567 																			 glw::GLint			   page_size)
   2568 	: m_dispatch_draw_call_args_start_offset(-1)
   2569 	, m_expected_ac_value(0)
   2570 	, m_gl(gl)
   2571 	, m_global_wg_size_x(2048)
   2572 	, m_helper_bo(0)
   2573 	, m_local_wg_size_x(1023) /* must stay in sync with the local work-groups's size hardcoded in m_po's body! */
   2574 	, m_page_size(page_size)
   2575 	, m_po(0)
   2576 	, m_sparse_bo(0)
   2577 	, m_sparse_bo_size(0)
   2578 	, m_sparse_bo_size_rounded(0)
   2579 	, m_testCtx(testContext)
   2580 {
   2581 	/* Left blank intentionally */
   2582 }
   2583 
   2584 /** Releases all GL objects used across all test case iterations.
   2585  *
   2586  *  Called once during BufferStorage test run-time.
   2587  */
   2588 void IndirectDispatchBufferStorageTestCase::deinitTestCaseGlobal()
   2589 {
   2590 	if (m_helper_bo != 0)
   2591 	{
   2592 		m_gl.deleteBuffers(1, &m_helper_bo);
   2593 
   2594 		m_helper_bo = 0;
   2595 	}
   2596 
   2597 	if (m_po != 0)
   2598 	{
   2599 		m_gl.deleteProgram(m_po);
   2600 
   2601 		m_po = 0;
   2602 	}
   2603 }
   2604 
   2605 /** Releases temporary GL objects, created specifically for one test case iteration. */
   2606 void IndirectDispatchBufferStorageTestCase::deinitTestCaseIteration()
   2607 {
   2608 	if (m_sparse_bo != 0)
   2609 	{
   2610 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   2611 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2612 
   2613 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   2614 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   2615 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   2616 
   2617 		m_sparse_bo = 0;
   2618 	}
   2619 }
   2620 
   2621 /** Executes a single test iteration. The BufferStorage test will call this method
   2622  *  numerously during its life-time, testing various valid flag combinations applied
   2623  *  to the tested sparse buffer object at glBufferStorage() call time.
   2624  *
   2625  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   2626  *                                 call to set up the sparse buffer's storage.
   2627  *
   2628  *  @return true if the test case executed correctly, false otherwise.
   2629  */
   2630 bool IndirectDispatchBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   2631 {
   2632 	(void)sparse_bo_storage_flags;
   2633 	bool result = true;
   2634 
   2635 	/* Set up the buffer bindings */
   2636 	m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_helper_bo);
   2637 	m_gl.bindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_sparse_bo);
   2638 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed");
   2639 
   2640 	m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
   2641 						 m_helper_bo, 12,			  /* offset */
   2642 						 4);						  /* size */
   2643 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
   2644 
   2645 	/* Bind the compute program */
   2646 	m_gl.useProgram(m_po);
   2647 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
   2648 
   2649 	/* Zero out atomic counter value. */
   2650 	const unsigned int zero_ac_value = 0;
   2651 
   2652 	m_gl.bufferSubData(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */
   2653 					   4,							 /* size */
   2654 					   &zero_ac_value);
   2655 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
   2656 
   2657 	m_expected_ac_value = zero_ac_value;
   2658 
   2659 	/* Run the test only in a configuration where all arguments are local in
   2660 	 * committed memory page(s): reading arguments from uncommitted pages means
   2661 	 * reading undefined data, which can result in huge dispatches that
   2662 	 * effectively hang the test.
   2663 	 */
   2664 	m_gl.bufferPageCommitmentARB(GL_DISPATCH_INDIRECT_BUFFER, 0,	 /* offset */
   2665 								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
   2666 
   2667 	m_expected_ac_value += m_global_wg_size_x * m_local_wg_size_x;
   2668 
   2669 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed.");
   2670 
   2671 	/* Copy the indirect dispatch call args data from the helper BO to the sparse BO */
   2672 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   2673 	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
   2674 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2675 
   2676 	m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   2677 						   m_dispatch_draw_call_args_start_offset, sizeof(unsigned int) * 3);
   2678 
   2679 	/* Run the program */
   2680 	m_gl.dispatchComputeIndirect(m_dispatch_draw_call_args_start_offset);
   2681 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchComputeIndirect() call failed.");
   2682 
   2683 	/* Extract the AC value and verify it */
   2684 	const unsigned int* ac_data_ptr =
   2685 		(const unsigned int*)m_gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */
   2686 												 4,							   /* length */
   2687 												 GL_MAP_READ_BIT);
   2688 
   2689 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
   2690 
   2691 	if (*ac_data_ptr != m_expected_ac_value && result)
   2692 	{
   2693 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value encountered. "
   2694 													   "Expected value: ["
   2695 						   << m_expected_ac_value << "]"
   2696 													 ", found:"
   2697 													 "["
   2698 						   << *ac_data_ptr << "]." << tcu::TestLog::EndMessage;
   2699 
   2700 		result = false;
   2701 	}
   2702 
   2703 	/* Unmap the buffer before we move on with the next iteration */
   2704 	m_gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
   2705 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   2706 
   2707 	return result;
   2708 }
   2709 
   2710 /** Initializes GL objects used across all test case iterations.
   2711  *
   2712  *  Called once during BufferStorage test run-time.
   2713  */
   2714 bool IndirectDispatchBufferStorageTestCase::initTestCaseGlobal()
   2715 {
   2716 	bool result = true;
   2717 
   2718 	/* One of the cases the test case implementation needs to support is the scenario
   2719 	 * where the indirect call arguments are located on the boundary of two (or more) memory pages,
   2720 	 * and some of the pages are not committed.
   2721 	 *
   2722 	 * There are two scenarios which can happen:
   2723 	 *
   2724 	 * a) page size >= sizeof(uint) * 3: Allocate two pages, arg start offset: (page_size - 4) aligned to 4.
   2725 	 *                                   The alignment is a must, since we'll be feeding the offset to an indirect dispatch call.
   2726 	 * b) page size <  sizeof(uint) * 3: Allocate as many pages as needed, disable some of the pages.
   2727 	 *
   2728 	 * For code clarity, the two cases are handled by separate branches, although they could be easily
   2729 	 * merged.
   2730 	 */
   2731 	const int n_indirect_dispatch_call_arg_bytes = sizeof(unsigned int) * 3;
   2732 
   2733 	if (m_page_size >= n_indirect_dispatch_call_arg_bytes)
   2734 	{
   2735 		/* Indirect dispatch call args must be aligned to 4 */
   2736 		DE_ASSERT(m_page_size >= 4);
   2737 
   2738 		m_dispatch_draw_call_args_start_offset = SparseBufferTestUtilities::alignOffset(m_page_size - 4, 4);
   2739 		m_sparse_bo_size = m_dispatch_draw_call_args_start_offset + n_indirect_dispatch_call_arg_bytes;
   2740 	}
   2741 	else
   2742 	{
   2743 		m_dispatch_draw_call_args_start_offset = 0;
   2744 		m_sparse_bo_size					   = n_indirect_dispatch_call_arg_bytes;
   2745 	}
   2746 
   2747 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
   2748 
   2749 	/* Set up the helper buffer object. Its structure is as follows:
   2750 	 *
   2751 	 * [ 0-11]: Indirect dispatch call args
   2752 	 * [12-15]: Atomic counter value storage
   2753 	 */
   2754 	unsigned int	   helper_bo_data[4] = { 0 };
   2755 	const unsigned int n_helper_bo_bytes = sizeof(helper_bo_data);
   2756 
   2757 	helper_bo_data[0] = m_global_wg_size_x; /* num_groups_x */
   2758 	helper_bo_data[1] = 1;					/* num_groups_y */
   2759 	helper_bo_data[2] = 1;					/* num_groups_z */
   2760 	helper_bo_data[3] = 0;					/* default atomic counter value */
   2761 
   2762 	m_gl.genBuffers(1, &m_helper_bo);
   2763 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   2764 
   2765 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
   2766 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2767 
   2768 	m_gl.bufferData(GL_ARRAY_BUFFER, n_helper_bo_bytes, helper_bo_data, GL_STATIC_DRAW);
   2769 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
   2770 
   2771 	/* Set up the test compute program object */
   2772 	static const char* cs_body = "#version 430 core\n"
   2773 								 "\n"
   2774 								 "layout(local_size_x = 1023)          in;\n"
   2775 								 "layout(binding      = 0, offset = 0) uniform atomic_uint ac;\n"
   2776 								 "\n"
   2777 								 "void main()\n"
   2778 								 "{\n"
   2779 								 "    atomicCounterIncrement(ac);\n"
   2780 								 "}\n";
   2781 
   2782 	m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
   2783 
   2784 	result = (m_po != 0);
   2785 
   2786 	return result;
   2787 }
   2788 
   2789 /** Initializes GL objects which are needed for a single test case iteration.
   2790  *
   2791  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   2792  *  to release these objects.
   2793  **/
   2794 bool IndirectDispatchBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   2795 {
   2796 	bool result = true;
   2797 
   2798 	/* Cache the BO id, if not cached already */
   2799 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   2800 
   2801 	m_sparse_bo = sparse_bo;
   2802 
   2803 	/* Set up the sparse bufffer. */
   2804 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   2805 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2806 
   2807 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
   2808 								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
   2809 
   2810 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   2811 
   2812 	return result;
   2813 }
   2814 
   2815 /** Constructor.
   2816  *
   2817  *  @param gl                         GL entry-points container
   2818  *  @param testContext                CTS test context
   2819  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   2820  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   2821  */
   2822 InvalidateBufferStorageTestCase::InvalidateBufferStorageTestCase(const glw::Functions& gl,
   2823 																 tcu::TestContext& testContext, glw::GLint page_size)
   2824 	: m_gl(gl)
   2825 	, m_n_pages_to_use(4)
   2826 	, m_page_size(page_size)
   2827 	, m_sparse_bo(0)
   2828 	, m_sparse_bo_size(0)
   2829 	, m_sparse_bo_size_rounded(0)
   2830 {
   2831 	(void)testContext;
   2832 	DE_ASSERT((m_n_pages_to_use % 2) == 0);
   2833 }
   2834 
   2835 /** Releases all GL objects used across all test case iterations.
   2836  *
   2837  *  Called once during BufferStorage test run-time.
   2838  */
   2839 void InvalidateBufferStorageTestCase::deinitTestCaseGlobal()
   2840 {
   2841 	/* Stub */
   2842 }
   2843 
   2844 /** Releases temporary GL objects, created specifically for one test case iteration. */
   2845 void InvalidateBufferStorageTestCase::deinitTestCaseIteration()
   2846 {
   2847 	if (m_sparse_bo != 0)
   2848 	{
   2849 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   2850 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2851 
   2852 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   2853 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   2854 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   2855 
   2856 		m_sparse_bo = 0;
   2857 	}
   2858 }
   2859 
   2860 /** Executes a single test iteration. The BufferStorage test will call this method
   2861  *  numerously during its life-time, testing various valid flag combinations applied
   2862  *  to the tested sparse buffer object at glBufferStorage() call time.
   2863  *
   2864  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   2865  *                                 call to set up the sparse buffer's storage.
   2866  *
   2867  *  @return true if the test case executed correctly, false otherwise.
   2868  */
   2869 bool InvalidateBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   2870 {
   2871 	(void)sparse_bo_storage_flags;
   2872 	bool result = true;
   2873 
   2874 	/* Since we cannot really perform any validation related to whether buffer
   2875 	 * storage invalidation works corectly, all this test can really do is to verify
   2876 	 * if the implementation does not crash when both entry-points are used against
   2877 	 * a sparse buffer object.
   2878 	 */
   2879 	for (unsigned int n_entry_point = 0; n_entry_point < 2; /* glInvalidateBuffer(), glInvalidateBufferSubData() */
   2880 		 ++n_entry_point)
   2881 	{
   2882 		const bool should_test_invalidate_buffer = (n_entry_point == 0);
   2883 
   2884 		/* For glInvalidateBufferSubData(), we need to test two different ranges. */
   2885 		for (int n_iteration = 0; n_iteration < ((should_test_invalidate_buffer) ? 1 : 2); ++n_iteration)
   2886 		{
   2887 			if (should_test_invalidate_buffer)
   2888 			{
   2889 				m_gl.invalidateBufferData(m_sparse_bo);
   2890 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferData() call failed.");
   2891 			}
   2892 			else
   2893 			{
   2894 				m_gl.invalidateBufferSubData(m_sparse_bo, 0, /* offset */
   2895 											 m_sparse_bo_size_rounded * ((n_iteration == 0) ? 1 : 2));
   2896 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferSubData() call failed.");
   2897 			}
   2898 		} /* for (all iterations) */
   2899 	}	 /* for (both entry-points) */
   2900 
   2901 	return result;
   2902 }
   2903 
   2904 /** Initializes GL objects used across all test case iterations.
   2905  *
   2906  *  Called once during BufferStorage test run-time.
   2907  */
   2908 bool InvalidateBufferStorageTestCase::initTestCaseGlobal()
   2909 {
   2910 	const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size;
   2911 
   2912 	/* Determine the number of bytes both the helper and the sparse buffer
   2913 	 * object need to be able to hold, at maximum */
   2914 	m_sparse_bo_size		 = n_bytes_needed;
   2915 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size);
   2916 
   2917 	return true;
   2918 }
   2919 
   2920 /** Initializes GL objects which are needed for a single test case iteration.
   2921  *
   2922  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   2923  *  to release these objects.
   2924  **/
   2925 bool InvalidateBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   2926 {
   2927 	bool result = true;
   2928 
   2929 	/* Cache the BO id, if not cached already */
   2930 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   2931 
   2932 	m_sparse_bo = sparse_bo;
   2933 
   2934 	/* Set up the sparse bufffer. */
   2935 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   2936 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   2937 
   2938 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
   2939 								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
   2940 
   2941 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   2942 
   2943 	return result;
   2944 }
   2945 
   2946 /** Constructor.
   2947  *
   2948  *  @param gl                         GL entry-points container
   2949  *  @param testContext                CTS test context
   2950  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   2951  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   2952  */
   2953 PixelPackBufferStorageTestCase::PixelPackBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
   2954 															   glw::GLint page_size)
   2955 	: m_color_rb(0)
   2956 	, m_color_rb_height(1024)
   2957 	, m_color_rb_width(1024)
   2958 	, m_fbo(0)
   2959 	, m_gl(gl)
   2960 	, m_helper_bo(0)
   2961 	, m_page_size(page_size)
   2962 	, m_po(0)
   2963 	, m_ref_data_ptr(DE_NULL)
   2964 	, m_ref_data_size(0)
   2965 	, m_sparse_bo(0)
   2966 	, m_sparse_bo_size(0)
   2967 	, m_sparse_bo_size_rounded(0)
   2968 	, m_testCtx(testContext)
   2969 	, m_vao(0)
   2970 {
   2971 	m_ref_data_size = m_color_rb_width * m_color_rb_height * 4; /* rgba */
   2972 }
   2973 
   2974 /** Releases all GL objects used across all test case iterations.
   2975  *
   2976  *  Called once during BufferStorage test run-time.
   2977  */
   2978 void PixelPackBufferStorageTestCase::deinitTestCaseGlobal()
   2979 {
   2980 	if (m_color_rb != 0)
   2981 	{
   2982 		m_gl.deleteRenderbuffers(1, &m_color_rb);
   2983 
   2984 		m_color_rb = 0;
   2985 	}
   2986 
   2987 	if (m_fbo != 0)
   2988 	{
   2989 		m_gl.deleteFramebuffers(1, &m_fbo);
   2990 
   2991 		m_fbo = 0;
   2992 	}
   2993 
   2994 	if (m_helper_bo != 0)
   2995 	{
   2996 		m_gl.deleteBuffers(1, &m_helper_bo);
   2997 
   2998 		m_helper_bo = 0;
   2999 	}
   3000 
   3001 	if (m_ref_data_ptr != DE_NULL)
   3002 	{
   3003 		delete[] m_ref_data_ptr;
   3004 
   3005 		m_ref_data_ptr = DE_NULL;
   3006 	}
   3007 
   3008 	if (m_po != 0)
   3009 	{
   3010 		m_gl.deleteProgram(m_po);
   3011 
   3012 		m_po = 0;
   3013 	}
   3014 
   3015 	if (m_vao != 0)
   3016 	{
   3017 		m_gl.deleteVertexArrays(1, &m_vao);
   3018 
   3019 		m_vao = 0;
   3020 	}
   3021 }
   3022 
   3023 /** Releases temporary GL objects, created specifically for one test case iteration. */
   3024 void PixelPackBufferStorageTestCase::deinitTestCaseIteration()
   3025 {
   3026 	if (m_sparse_bo != 0)
   3027 	{
   3028 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   3029 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3030 
   3031 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   3032 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   3033 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3034 
   3035 		m_sparse_bo = 0;
   3036 	}
   3037 }
   3038 
   3039 /** Executes a single test iteration. The BufferStorage test will call this method
   3040  *  numerously during its life-time, testing various valid flag combinations applied
   3041  *  to the tested sparse buffer object at glBufferStorage() call time.
   3042  *
   3043  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   3044  *                                 call to set up the sparse buffer's storage.
   3045  *
   3046  *  @return true if the test case executed correctly, false otherwise.
   3047  */
   3048 bool PixelPackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   3049 {
   3050 	(void)sparse_bo_storage_flags;
   3051 	bool result = true;
   3052 
   3053 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   3054 	m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, m_sparse_bo);
   3055 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   3056 
   3057 	/* Run three separate iterations:
   3058 	 *
   3059 	 * a) All pages that are going to hold the texture data are committed.
   3060 	 * b) Use a zig-zag memory page commitment layout patern.
   3061 	 * b) No pages are committed.
   3062 	 */
   3063 	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
   3064 	{
   3065 		bool result_local = true;
   3066 
   3067 		/* Set up the memory page commitment & the storage contents*/
   3068 		switch (n_iteration)
   3069 		{
   3070 		case 0:
   3071 		{
   3072 			m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0,			 /* offset */
   3073 										 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
   3074 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3075 
   3076 			break;
   3077 		}
   3078 
   3079 		case 1:
   3080 		{
   3081 			const unsigned int n_pages = 1 + m_ref_data_size / m_page_size;
   3082 
   3083 			DE_ASSERT((m_ref_data_size % m_page_size) == 0);
   3084 
   3085 			for (unsigned int n_page = 0; n_page < n_pages; ++n_page)
   3086 			{
   3087 				const bool should_commit = ((n_page % 2) == 0);
   3088 
   3089 				m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, m_page_size * n_page, m_page_size,
   3090 											 should_commit ? GL_TRUE : GL_FALSE);
   3091 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3092 			} /* for (all relevant memory pages) */
   3093 
   3094 			break;
   3095 		}
   3096 
   3097 		case 2:
   3098 		{
   3099 			/* Do nothing - all pages already de-committed  */
   3100 			break;
   3101 		}
   3102 
   3103 		default:
   3104 		{
   3105 			TCU_FAIL("Invalid iteration index");
   3106 		}
   3107 		} /* switch (n_iteration) */
   3108 
   3109 		/* Draw full screen quad to generate the black-to-white gradient */
   3110 		const unsigned char* read_data_ptr = NULL;
   3111 
   3112 		m_gl.useProgram(m_po);
   3113 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
   3114 
   3115 		m_gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */);
   3116 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
   3117 
   3118 		/* Read a framebuffer pixel data */
   3119 		m_gl.readPixels(0,																	/* x */
   3120 						0,																	/* y */
   3121 						m_color_rb_width, m_color_rb_height, GL_RGBA, GL_UNSIGNED_BYTE, 0); /* pixels */
   3122 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed.");
   3123 
   3124 		m_gl.copyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_COPY_READ_BUFFER, 0, /* readOffset */
   3125 							   0,											 /* writeOffset */
   3126 							   m_ref_data_size);
   3127 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   3128 
   3129 		read_data_ptr = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */
   3130 															m_ref_data_size, GL_MAP_READ_BIT);
   3131 
   3132 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
   3133 
   3134 		/* Verify the data */
   3135 		unsigned int		 n_current_tex_data_byte	  = 0;
   3136 		const unsigned char* read_data_traveller_ptr	  = (const unsigned char*)read_data_ptr;
   3137 		const unsigned char* reference_data_traveller_ptr = (const unsigned char*)m_ref_data_ptr;
   3138 
   3139 		for (unsigned int y = 0; y < m_color_rb_height && result_local; ++y)
   3140 		{
   3141 			for (unsigned int x = 0; x < m_color_rb_width && result_local; ++x)
   3142 			{
   3143 				for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component)
   3144 				{
   3145 					unsigned char expected_value		 = 0;
   3146 					bool		  is_from_committed_page = true;
   3147 
   3148 					if (n_iteration == 1) /* zig-zag */
   3149 					{
   3150 						is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0;
   3151 					}
   3152 					else if (n_iteration == 2) /* no pages committed */
   3153 					{
   3154 						is_from_committed_page = false;
   3155 					}
   3156 
   3157 					if (is_from_committed_page)
   3158 					{
   3159 						expected_value = *reference_data_traveller_ptr;
   3160 					}
   3161 
   3162 					if (is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) > 1)
   3163 					{
   3164 						m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component
   3165 										   << ")"
   3166 											  " found at X:"
   3167 										   << x << ", "
   3168 												   "Y:"
   3169 										   << y << ")."
   3170 												   " Expected value:"
   3171 										   << expected_value << ","
   3172 																" found value:"
   3173 										   << *reference_data_traveller_ptr << tcu::TestLog::EndMessage;
   3174 
   3175 						result_local = false;
   3176 					}
   3177 
   3178 					n_current_tex_data_byte++;
   3179 					read_data_traveller_ptr++;
   3180 					reference_data_traveller_ptr++;
   3181 				} /* for (all components) */
   3182 			}	 /* for (all columns) */
   3183 		}		  /* for (all rows) */
   3184 
   3185 		m_gl.unmapBuffer(GL_COPY_READ_BUFFER);
   3186 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   3187 
   3188 		read_data_ptr = DE_NULL;
   3189 		result &= result_local;
   3190 
   3191 		/* Clean up */
   3192 		m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0,			  /* offset */
   3193 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   3194 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3195 	} /* for (three iterations) */
   3196 
   3197 	m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
   3198 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3199 
   3200 	return result;
   3201 }
   3202 
   3203 /** Initializes GL objects used across all test case iterations.
   3204  *
   3205  *  Called once during BufferStorage test run-time.
   3206  */
   3207 bool PixelPackBufferStorageTestCase::initTestCaseGlobal()
   3208 {
   3209 	/* Determine dummy vertex shader and fragment shader that will generate black-to-white gradient. */
   3210 	const char* gradient_fs_code = "#version 330 core\n"
   3211 								   "\n"
   3212 								   "out vec4 result;\n"
   3213 								   "\n"
   3214 								   "void main()\n"
   3215 								   "{\n"
   3216 								   "    float c = 1.0 - (gl_FragCoord.y - 0.5) / 1023.0;\n"
   3217 								   "    result  = vec4(c);\n"
   3218 								   "}\n";
   3219 
   3220 	const char* gradient_vs_code = "#version 330\n"
   3221 								   "\n"
   3222 								   "void main()\n"
   3223 								   "{\n"
   3224 								   "    switch (gl_VertexID)\n"
   3225 								   "    {\n"
   3226 								   "        case 0: gl_Position = vec4(-1.0, -1.0, 0.0, 1.0); break;\n"
   3227 								   "        case 1: gl_Position = vec4( 1.0, -1.0, 0.0, 1.0); break;\n"
   3228 								   "        case 2: gl_Position = vec4(-1.0,  1.0, 0.0, 1.0); break;\n"
   3229 								   "        case 3: gl_Position = vec4( 1.0,  1.0, 0.0, 1.0); break;\n"
   3230 								   "    }\n"
   3231 								   "}\n";
   3232 
   3233 	m_po = SparseBufferTestUtilities::createProgram(m_gl, &gradient_fs_code, 1, /* n_fs_body_parts */
   3234 													&gradient_vs_code, 1,		/* n_vs_body_parts*/
   3235 													NULL,						/* attribute_names */
   3236 													NULL,						/* attribute_locations */
   3237 													GL_NONE,					/* attribute_properties */
   3238 													0,							/* tf_varyings */
   3239 													0,							/* n_tf_varyings */
   3240 													0);							/* tf_varying_mode */
   3241 	if (m_po == 0)
   3242 	{
   3243 		TCU_FAIL("Failed to link the test program");
   3244 	}
   3245 
   3246 	/* Generate and bind VAO */
   3247 	m_gl.genVertexArrays(1, &m_vao);
   3248 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
   3249 
   3250 	m_gl.bindVertexArray(m_vao);
   3251 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
   3252 
   3253 	/* Generate and bind FBO */
   3254 	m_gl.genFramebuffers(1, &m_fbo);
   3255 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed.");
   3256 
   3257 	m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
   3258 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed.");
   3259 
   3260 	m_gl.readBuffer(GL_COLOR_ATTACHMENT0);
   3261 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadBuffer() call failed.");
   3262 
   3263 	/* Generate and bind RBO and attach it to FBO as a color attachment */
   3264 	m_gl.genRenderbuffers(1, &m_color_rb);
   3265 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenRenderbuffers() call failed.");
   3266 
   3267 	m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_color_rb);
   3268 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindRenderbuffer() call failed.");
   3269 
   3270 	m_gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_color_rb_width, m_color_rb_height);
   3271 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glRenderbufferStorage() call failed.");
   3272 
   3273 	m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_color_rb);
   3274 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferRenderbuffer() call failed.");
   3275 
   3276 	if (m_gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
   3277 	{
   3278 		throw tcu::NotSupportedError("Cannot execute the test - driver does not support rendering"
   3279 									 "to a GL_RGBA8 renderbuffer-based color attachment");
   3280 	}
   3281 
   3282 	m_gl.viewport(0, /* x */
   3283 				  0, /* y */
   3284 				  m_color_rb_width, m_color_rb_height);
   3285 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glViewport() call failed.");
   3286 
   3287 	/* Determine what sparse buffer storage size we are going to need*/
   3288 	m_sparse_bo_size		 = m_ref_data_size;
   3289 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
   3290 
   3291 	/* Prepare the texture data */
   3292 	unsigned char* ref_data_traveller_ptr = DE_NULL;
   3293 
   3294 	m_ref_data_ptr		   = new unsigned char[m_ref_data_size];
   3295 	ref_data_traveller_ptr = m_ref_data_ptr;
   3296 
   3297 	for (unsigned int y = 0; y < m_color_rb_height; ++y)
   3298 	{
   3299 		const unsigned char color = (unsigned char)((1.0f - float(y) / float(m_color_rb_height - 1)) * 255.0f);
   3300 
   3301 		for (unsigned int x = 0; x < m_color_rb_width; ++x)
   3302 		{
   3303 			memset(ref_data_traveller_ptr, color, 4); /* rgba */
   3304 
   3305 			ref_data_traveller_ptr += 4; /* rgba */
   3306 		}								 /* for (all columns) */
   3307 	}									 /* for (all rows) */
   3308 
   3309 	/* Set up the helper buffer object. */
   3310 	m_gl.genBuffers(1, &m_helper_bo);
   3311 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   3312 
   3313 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   3314 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3315 
   3316 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_ref_data_size, m_ref_data_ptr, GL_MAP_READ_BIT);
   3317 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   3318 
   3319 	return true;
   3320 }
   3321 
   3322 /** Initializes GL objects which are needed for a single test case iteration.
   3323  *
   3324  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   3325  *  to release these objects.
   3326  **/
   3327 bool PixelPackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   3328 {
   3329 	bool result = true;
   3330 
   3331 	/* Cache the BO id, if not cached already */
   3332 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   3333 
   3334 	m_sparse_bo = sparse_bo;
   3335 
   3336 	return result;
   3337 }
   3338 
   3339 /** Constructor.
   3340  *
   3341  *  @param gl                         GL entry-points container
   3342  *  @param testContext                CTS test context
   3343  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   3344  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   3345  */
   3346 PixelUnpackBufferStorageTestCase::PixelUnpackBufferStorageTestCase(const glw::Functions& gl,
   3347 																   tcu::TestContext& testContext, glw::GLint page_size)
   3348 	: m_gl(gl)
   3349 	, m_helper_bo(0)
   3350 	, m_page_size(page_size)
   3351 	, m_read_data_ptr(DE_NULL)
   3352 	, m_sparse_bo(0)
   3353 	, m_sparse_bo_size(0)
   3354 	, m_sparse_bo_size_rounded(0)
   3355 	, m_testCtx(testContext)
   3356 	, m_texture_data_ptr(DE_NULL)
   3357 	, m_texture_data_size(0)
   3358 	, m_to(0)
   3359 	, m_to_data_zero(DE_NULL)
   3360 	, m_to_height(1024)
   3361 	, m_to_width(1024)
   3362 {
   3363 	m_texture_data_size = m_to_width * m_to_height * 4; /* rgba */
   3364 }
   3365 
   3366 /** Releases all GL objects used across all test case iterations.
   3367  *
   3368  *  Called once during BufferStorage test run-time.
   3369  */
   3370 void PixelUnpackBufferStorageTestCase::deinitTestCaseGlobal()
   3371 {
   3372 	if (m_helper_bo != 0)
   3373 	{
   3374 		m_gl.deleteBuffers(1, &m_helper_bo);
   3375 
   3376 		m_helper_bo = 0;
   3377 	}
   3378 
   3379 	if (m_read_data_ptr != DE_NULL)
   3380 	{
   3381 		delete[] m_read_data_ptr;
   3382 
   3383 		m_read_data_ptr = DE_NULL;
   3384 	}
   3385 
   3386 	if (m_texture_data_ptr != DE_NULL)
   3387 	{
   3388 		delete[] m_texture_data_ptr;
   3389 
   3390 		m_texture_data_ptr = DE_NULL;
   3391 	}
   3392 
   3393 	if (m_to != 0)
   3394 	{
   3395 		m_gl.deleteTextures(1, &m_to);
   3396 
   3397 		m_to = 0;
   3398 	}
   3399 
   3400 	if (m_to_data_zero != DE_NULL)
   3401 	{
   3402 		delete[] m_to_data_zero;
   3403 
   3404 		m_to_data_zero = DE_NULL;
   3405 	}
   3406 }
   3407 
   3408 /** Releases temporary GL objects, created specifically for one test case iteration. */
   3409 void PixelUnpackBufferStorageTestCase::deinitTestCaseIteration()
   3410 {
   3411 	if (m_sparse_bo != 0)
   3412 	{
   3413 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   3414 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3415 
   3416 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   3417 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   3418 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3419 
   3420 		m_sparse_bo = 0;
   3421 	}
   3422 }
   3423 
   3424 /** Executes a single test iteration. The BufferStorage test will call this method
   3425  *  numerously during its life-time, testing various valid flag combinations applied
   3426  *  to the tested sparse buffer object at glBufferStorage() call time.
   3427  *
   3428  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   3429  *                                 call to set up the sparse buffer's storage.
   3430  *
   3431  *  @return true if the test case executed correctly, false otherwise.
   3432  */
   3433 bool PixelUnpackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   3434 {
   3435 	(void)sparse_bo_storage_flags;
   3436 	bool result = true;
   3437 
   3438 	m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo);
   3439 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3440 
   3441 	m_gl.bindTexture(GL_TEXTURE_2D, m_to);
   3442 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
   3443 
   3444 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   3445 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
   3446 
   3447 	/* Run three separate iterations:
   3448 	 *
   3449 	 * a) All pages holding the source texture data are committed.
   3450 	 * b) Use a zig-zag memory page commitment layout patern.
   3451 	 * b) No pages are committed.
   3452 	 */
   3453 	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
   3454 	{
   3455 		bool result_local = true;
   3456 
   3457 		/* Set up the memory page commitment & the storage contents*/
   3458 		switch (n_iteration)
   3459 		{
   3460 		case 0:
   3461 		{
   3462 			m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0,			 /* offset */
   3463 										 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
   3464 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3465 
   3466 			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, /* readOffset */
   3467 								   0,											   /* writeOffset */
   3468 								   m_texture_data_size);
   3469 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   3470 
   3471 			break;
   3472 		}
   3473 
   3474 		case 1:
   3475 		{
   3476 			const unsigned int n_pages = m_texture_data_size / m_page_size;
   3477 
   3478 			for (unsigned int n_page = 0; n_page < n_pages; ++n_page)
   3479 			{
   3480 				const bool should_commit = ((n_page % 2) == 0);
   3481 
   3482 				m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, m_page_size * n_page, m_page_size,
   3483 											 should_commit ? GL_TRUE : GL_FALSE);
   3484 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3485 
   3486 				if (should_commit)
   3487 				{
   3488 					m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER,
   3489 										   m_page_size * n_page, /* readOffset */
   3490 										   m_page_size * n_page, /* writeOffset */
   3491 										   m_page_size);
   3492 					GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   3493 				}
   3494 			} /* for (all relevant memory pages) */
   3495 
   3496 			break;
   3497 		}
   3498 
   3499 		case 2:
   3500 		{
   3501 			/* Do nothing */
   3502 			break;
   3503 		}
   3504 
   3505 		default:
   3506 		{
   3507 			TCU_FAIL("Invalid iteration index");
   3508 		}
   3509 		} /* switch (n_iteration) */
   3510 
   3511 		/* Clean up the base mip-map's contents before we proceeding with updating it
   3512 		 * with data downloaded from the BO, in order to avoid situation where silently
   3513 		 * failing glTexSubImage2D() calls slip past unnoticed */
   3514 		m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
   3515 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3516 
   3517 		m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
   3518 						   0,				 /* xoffset */
   3519 						   0,				 /* yoffset */
   3520 						   m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, m_to_data_zero);
   3521 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed.");
   3522 
   3523 		m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo);
   3524 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3525 
   3526 		/* Update the base mip-map's contents */
   3527 		m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
   3528 						   0,				 /* xoffset */
   3529 						   0,				 /* yoffset */
   3530 						   m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, (const glw::GLvoid*)0);
   3531 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed.");
   3532 
   3533 		/* Read back the stored mip-map data */
   3534 		memset(m_read_data_ptr, 0xFF, m_texture_data_size);
   3535 
   3536 		m_gl.getTexImage(GL_TEXTURE_2D, 0, /* level */
   3537 						 GL_RGBA, GL_UNSIGNED_BYTE, m_read_data_ptr);
   3538 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetTexImage() call failed.");
   3539 
   3540 		/* Verify the data */
   3541 		unsigned int n_current_tex_data_byte	= 0;
   3542 		const char*  read_data_traveller_ptr	= (const char*)m_read_data_ptr;
   3543 		const char*  texture_data_traveller_ptr = (const char*)m_texture_data_ptr;
   3544 
   3545 		for (unsigned int y = 0; y < m_to_height && result_local; ++y)
   3546 		{
   3547 			for (unsigned int x = 0; x < m_to_width && result_local; ++x)
   3548 			{
   3549 				for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component)
   3550 				{
   3551 					char expected_value			= 0;
   3552 					bool is_from_committed_page = true;
   3553 
   3554 					if (n_iteration == 1) /* zig-zag */
   3555 					{
   3556 						is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0;
   3557 					}
   3558 					else if (n_iteration == 2) /* no pages committed */
   3559 					{
   3560 						is_from_committed_page = false;
   3561 					}
   3562 
   3563 					if (is_from_committed_page)
   3564 					{
   3565 						expected_value = *texture_data_traveller_ptr;
   3566 					}
   3567 
   3568 					if ((is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) >= 1) ||
   3569 						(!is_from_committed_page && *read_data_traveller_ptr != expected_value))
   3570 					{
   3571 						m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component
   3572 										   << ")"
   3573 											  " found at X:"
   3574 										   << x << ", "
   3575 												   "Y:"
   3576 										   << y << ")."
   3577 												   " Expected value:"
   3578 										   << expected_value << ","
   3579 																" found value:"
   3580 										   << *texture_data_traveller_ptr << tcu::TestLog::EndMessage;
   3581 
   3582 						result_local = false;
   3583 					}
   3584 
   3585 					n_current_tex_data_byte++;
   3586 					read_data_traveller_ptr++;
   3587 					texture_data_traveller_ptr++;
   3588 				} /* for (all components) */
   3589 			}	 /* for (all columns) */
   3590 		}		  /* for (all rows) */
   3591 
   3592 		result &= result_local;
   3593 
   3594 		/* Clean up */
   3595 		m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0,			  /* offset */
   3596 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   3597 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3598 	} /* for (three iterations) */
   3599 
   3600 	m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
   3601 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3602 
   3603 	return result;
   3604 }
   3605 
   3606 /** Initializes GL objects used across all test case iterations.
   3607  *
   3608  *  Called once during BufferStorage test run-time.
   3609  */
   3610 bool PixelUnpackBufferStorageTestCase::initTestCaseGlobal()
   3611 {
   3612 	/* Determine sparse buffer storage size */
   3613 	m_sparse_bo_size		 = m_texture_data_size;
   3614 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
   3615 
   3616 	/* Prepare the texture data */
   3617 	unsigned char* texture_data_traveller_ptr = DE_NULL;
   3618 
   3619 	m_read_data_ptr			   = new unsigned char[m_texture_data_size];
   3620 	m_texture_data_ptr		   = new unsigned char[m_texture_data_size];
   3621 	texture_data_traveller_ptr = m_texture_data_ptr;
   3622 
   3623 	for (unsigned int y = 0; y < m_to_height; ++y)
   3624 	{
   3625 		for (unsigned int x = 0; x < m_to_width; ++x)
   3626 		{
   3627 			const unsigned char color = (unsigned char)(float(x) / float(m_to_width - 1) * 255.0f);
   3628 
   3629 			memset(texture_data_traveller_ptr, color, 4); /* rgba */
   3630 
   3631 			texture_data_traveller_ptr += 4; /* rgba */
   3632 		}									 /* for (all columns) */
   3633 	}										 /* for (all rows) */
   3634 
   3635 	m_to_data_zero = new unsigned char[m_texture_data_size];
   3636 
   3637 	memset(m_to_data_zero, 0, m_texture_data_size);
   3638 
   3639 	/* Set up the helper buffer object */
   3640 	m_gl.genBuffers(1, &m_helper_bo);
   3641 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   3642 
   3643 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   3644 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3645 
   3646 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_texture_data_size, m_texture_data_ptr, GL_MAP_READ_BIT);
   3647 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   3648 
   3649 	/* Set up texture object storage */
   3650 	m_gl.genTextures(1, &m_to);
   3651 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
   3652 
   3653 	m_gl.bindTexture(GL_TEXTURE_2D, m_to);
   3654 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
   3655 
   3656 	m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
   3657 					  GL_RGBA8, m_to_width, m_to_height);
   3658 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed.");
   3659 
   3660 	return true;
   3661 }
   3662 
   3663 /** Initializes GL objects which are needed for a single test case iteration.
   3664  *
   3665  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   3666  *  to release these objects.
   3667  **/
   3668 bool PixelUnpackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   3669 {
   3670 	bool result = true;
   3671 
   3672 	/* Cache the BO id, if not cached already */
   3673 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   3674 
   3675 	m_sparse_bo = sparse_bo;
   3676 
   3677 	/* Set up the sparse buffer. */
   3678 	m_gl.bindBuffer(GL_QUERY_BUFFER, m_sparse_bo);
   3679 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3680 
   3681 	return result;
   3682 }
   3683 
   3684 /** Constructor.
   3685  *
   3686  *  @param gl                         GL entry-points container
   3687  *  @param testContext                CTS test context
   3688  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   3689  *  @param ibo_usage                  Specifies if an indexed draw call should be used by the test. For more details,
   3690  *                                    please see documentation for _ibo_usage.
   3691  *  @param use_color_data             true to use the color data for the tested draw call;
   3692  *                                    false to omit usage of attribute data.
   3693  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   3694  */
   3695 QuadsBufferStorageTestCase::QuadsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
   3696 													   glw::GLint page_size, _ibo_usage ibo_usage, bool use_color_data)
   3697 	: m_attribute_color_location(0)	/* predefined attribute locations */
   3698 	, m_attribute_position_location(1) /* predefined attribute locations */
   3699 	, m_color_data_offset(0)
   3700 	, m_data(DE_NULL)
   3701 	, m_data_size(0)
   3702 	, m_data_size_rounded(0)
   3703 	, m_fbo(0)
   3704 	, m_gl(gl)
   3705 	, m_helper_bo(0)
   3706 	, m_ibo_data_offset(-1)
   3707 	, m_ibo_usage(ibo_usage)
   3708 	, m_n_quad_delta_x(5)
   3709 	, m_n_quad_delta_y(5)
   3710 	, m_n_quad_height(5)
   3711 	, m_n_quad_width(5)
   3712 	, m_n_quads_x(100) /* as per spec */
   3713 	, m_n_quads_y(100) /* as per spec */
   3714 	, m_n_vertices_to_draw(0)
   3715 	, m_pages_committed(false)
   3716 	, m_po(0)
   3717 	, m_sparse_bo(0)
   3718 	, m_testCtx(testContext)
   3719 	, m_to(0)
   3720 	, m_to_height(1024) /* as per spec */
   3721 	, m_to_width(1024)  /* as per spec */
   3722 	, m_use_color_data(use_color_data)
   3723 	, m_vao(0)
   3724 	, m_vbo_data_offset(-1)
   3725 {
   3726 	/*
   3727 	 * Each quad = 2 triangles, 1 triangle = 3 vertices, 1 vertex = 4 components.
   3728 	 * The inefficient representation has been used on purpose - we want the data to take
   3729 	 * more than 64KB so that it is guaranteed that it will span over more than 1 page.
   3730 	 */
   3731 	m_data_size = 0;
   3732 
   3733 	m_n_vertices_to_draw = m_n_quads_x * /* quads in X */
   3734 						   m_n_quads_y * /* quads in Y */
   3735 						   2 *			 /* triangles */
   3736 						   3;			 /* vertices per triangle */
   3737 
   3738 	m_data_size = static_cast<glw::GLuint>(m_n_vertices_to_draw * 4 /* components */ * sizeof(float));
   3739 
   3740 	if (m_ibo_usage != IBO_USAGE_NONE)
   3741 	{
   3742 		DE_ASSERT(m_n_vertices_to_draw < 65536);
   3743 
   3744 		m_data_size = static_cast<glw::GLuint>(m_data_size + (m_n_vertices_to_draw * sizeof(unsigned short)));
   3745 	}
   3746 
   3747 	if (m_use_color_data)
   3748 	{
   3749 		m_data_size = static_cast<glw::GLuint>(m_data_size +
   3750 											   (m_n_vertices_to_draw * sizeof(unsigned char) * 4 * /* rgba components */
   3751 												2 *												   /* triangles */
   3752 												3)); /* vertices per triangle */
   3753 	}
   3754 
   3755 	m_data_size_rounded = SparseBufferTestUtilities::alignOffset(m_data_size, page_size);
   3756 }
   3757 
   3758 /** Allocates a data buffer and fills it with vertex/index/color data. Vertex data is always stored,
   3759  *  index data only if m_ibo_usage is different from IBO_USAGE_NONE. Color data is only saved if
   3760  *  m_use_color_data is true.
   3761  *
   3762  *  @param out_data              Deref will be used to store a pointer to the allocated data buffer.
   3763  *                               Ownership is transferred to the caller. Must not be NULL.
   3764  *  @param out_vbo_data_offset   Deref will be used to store an offset, from which VBO data starts,
   3765  *                               relative to the beginning of *out_data. Must not be NULL.
   3766  *  @param out_ibo_data_offset   Deref will be used to store an offset, from which IBO data starts,
   3767  *                               relative to the beginning of *out_data. May be NULL if m_ibo_usage
   3768  *                               is IBO_USAGE_NONE.
   3769  *  @param out_color_data_offset Deref will be used to store na offset, from which color data starts,
   3770  *                               relative to the beginning of *out_data. May be NULL if m_use_color_data
   3771  *                               is false.
   3772  *
   3773  */
   3774 void QuadsBufferStorageTestCase::createTestData(unsigned char** out_data, unsigned int* out_vbo_data_offset,
   3775 												unsigned int* out_ibo_data_offset,
   3776 												unsigned int* out_color_data_offset) const
   3777 {
   3778 	unsigned char* data_traveller_ptr = NULL;
   3779 
   3780 	*out_data			 = new unsigned char[m_data_size];
   3781 	*out_vbo_data_offset = 0;
   3782 
   3783 	data_traveller_ptr = *out_data;
   3784 
   3785 	for (unsigned int n_quad_y = 0; n_quad_y < m_n_quads_y; ++n_quad_y)
   3786 	{
   3787 		for (unsigned int n_quad_x = 0; n_quad_x < m_n_quads_x; ++n_quad_x)
   3788 		{
   3789 			const unsigned int quad_start_x_px = n_quad_x * (m_n_quad_delta_x + m_n_quad_width);
   3790 			const unsigned int quad_start_y_px = n_quad_y * (m_n_quad_delta_y + m_n_quad_height);
   3791 			const unsigned int quad_end_x_px   = quad_start_x_px + m_n_quad_width;
   3792 			const unsigned int quad_end_y_px   = quad_start_y_px + m_n_quad_height;
   3793 
   3794 			const float quad_end_x_ss   = float(quad_end_x_px) / float(m_to_width) * 2.0f - 1.0f;
   3795 			const float quad_end_y_ss   = float(quad_end_y_px) / float(m_to_height) * 2.0f - 1.0f;
   3796 			const float quad_start_x_ss = float(quad_start_x_px) / float(m_to_width) * 2.0f - 1.0f;
   3797 			const float quad_start_y_ss = float(quad_start_y_px) / float(m_to_height) * 2.0f - 1.0f;
   3798 
   3799 			/*  1,4--5
   3800 			 *  |\   |
   3801 			 *  | \  |
   3802 			 *  2----3,6
   3803 			 */
   3804 			const float v1_4[] = {
   3805 				quad_start_x_ss, quad_start_y_ss, 0.0f, /* z */
   3806 				1.0f,									/* w */
   3807 			};
   3808 			const float v2[] = {
   3809 				quad_start_x_ss, quad_end_y_ss, 0.0f, /* z */
   3810 				1.0f								  /* w */
   3811 			};
   3812 			const float v3_6[] = {
   3813 				quad_end_x_ss, quad_end_y_ss, 0.0f, /* z */
   3814 				1.0f								/* w */
   3815 			};
   3816 			const float v5[] = {
   3817 				quad_end_x_ss, quad_start_y_ss, 0.0f, /* z */
   3818 				1.0f								  /* w */
   3819 			};
   3820 
   3821 			memcpy(data_traveller_ptr, v1_4, sizeof(v1_4));
   3822 			data_traveller_ptr += sizeof(v1_4);
   3823 
   3824 			memcpy(data_traveller_ptr, v2, sizeof(v2));
   3825 			data_traveller_ptr += sizeof(v2);
   3826 
   3827 			memcpy(data_traveller_ptr, v3_6, sizeof(v3_6));
   3828 			data_traveller_ptr += sizeof(v3_6);
   3829 
   3830 			memcpy(data_traveller_ptr, v1_4, sizeof(v1_4));
   3831 			data_traveller_ptr += sizeof(v1_4);
   3832 
   3833 			memcpy(data_traveller_ptr, v5, sizeof(v5));
   3834 			data_traveller_ptr += sizeof(v5);
   3835 
   3836 			memcpy(data_traveller_ptr, v3_6, sizeof(v3_6));
   3837 			data_traveller_ptr += sizeof(v3_6);
   3838 		} /* for (all quads in X) */
   3839 	}	 /* for (all quads in Y) */
   3840 
   3841 	/* Set up index data if needed */
   3842 	if (m_ibo_usage != IBO_USAGE_NONE)
   3843 	{
   3844 		*out_ibo_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data);
   3845 
   3846 		for (int index = m_n_vertices_to_draw - 1; index >= 0; --index)
   3847 		{
   3848 			*(unsigned short*)data_traveller_ptr = (unsigned short)index;
   3849 			data_traveller_ptr += sizeof(unsigned short);
   3850 		} /* for (all index values) */
   3851 	}	 /* if (m_use_ibo) */
   3852 	else
   3853 	{
   3854 		*out_ibo_data_offset = 0;
   3855 	}
   3856 
   3857 	/* Set up color data if needed */
   3858 	if (m_use_color_data)
   3859 	{
   3860 		*out_color_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data);
   3861 
   3862 		for (unsigned int n_quad = 0; n_quad < m_n_quads_x * m_n_quads_y; ++n_quad)
   3863 		{
   3864 			/* Use magic formulas to generate a color data set for the quads. The data
   3865 			 * needs to be duplicated for 6 vertices forming a single quad. */
   3866 			for (unsigned int n_vertex = 0; n_vertex < 6; ++n_vertex)
   3867 			{
   3868 				/* Red */
   3869 				*data_traveller_ptr = static_cast<unsigned char>(n_quad % 256); //((n_quad + 15) * 14) % 256;
   3870 				data_traveller_ptr++;
   3871 
   3872 				/* Green */
   3873 				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 32) * 7) % 255);
   3874 				data_traveller_ptr++;
   3875 
   3876 				/* Blue */
   3877 				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 7) * 53) % 255);
   3878 				data_traveller_ptr++;
   3879 
   3880 				/* Alpha */
   3881 				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 13) * 3) % 255);
   3882 				data_traveller_ptr++;
   3883 			}
   3884 		} /* for (all quads) */
   3885 	}
   3886 	else
   3887 	{
   3888 		*out_color_data_offset = 0;
   3889 	}
   3890 }
   3891 
   3892 /** Releases all GL objects used across all test case iterations.
   3893  *
   3894  *  Called once during BufferStorage test run-time.
   3895  */
   3896 void QuadsBufferStorageTestCase::deinitTestCaseGlobal()
   3897 {
   3898 	if (m_data != DE_NULL)
   3899 	{
   3900 		delete[] m_data;
   3901 
   3902 		m_data = DE_NULL;
   3903 	}
   3904 
   3905 	if (m_fbo != 0)
   3906 	{
   3907 		m_gl.deleteFramebuffers(1, &m_fbo);
   3908 
   3909 		m_fbo = 0;
   3910 	}
   3911 
   3912 	if (m_helper_bo != 0)
   3913 	{
   3914 		m_gl.deleteBuffers(1, &m_helper_bo);
   3915 
   3916 		m_helper_bo = 0;
   3917 	}
   3918 
   3919 	if (m_po != 0)
   3920 	{
   3921 		m_gl.deleteProgram(m_po);
   3922 
   3923 		m_po = 0;
   3924 	}
   3925 
   3926 	if (m_to != 0)
   3927 	{
   3928 		m_gl.deleteTextures(1, &m_to);
   3929 
   3930 		m_to = 0;
   3931 	}
   3932 
   3933 	if (m_vao != 0)
   3934 	{
   3935 		m_gl.deleteVertexArrays(1, &m_vao);
   3936 
   3937 		m_vao = 0;
   3938 	}
   3939 }
   3940 
   3941 /** Releases temporary GL objects, created specifically for one test case iteration. */
   3942 void QuadsBufferStorageTestCase::deinitTestCaseIteration()
   3943 {
   3944 	/* If the test executed successfully, all pages should've been released by now.
   3945 	 * However, if it failed, it's a good idea to de-commit them at this point.
   3946 	 * Redundant calls are fine spec-wise, too. */
   3947 	if (m_sparse_bo != 0)
   3948 	{
   3949 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   3950 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   3951 
   3952 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			 /* offset */
   3953 									 m_data_size_rounded, GL_FALSE); /* commit */
   3954 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   3955 
   3956 		m_sparse_bo = 0;
   3957 	}
   3958 }
   3959 
   3960 /** Executes a single test iteration. The BufferStorage test will call this method
   3961  *  numerously during its life-time, testing various valid flag combinations applied
   3962  *  to the tested sparse buffer object at glBufferStorage() call time.
   3963  *
   3964  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   3965  *                                 call to set up the sparse buffer's storage.
   3966  *
   3967  *  @return true if the test case executed correctly, false otherwise.
   3968  */
   3969 bool QuadsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   3970 {
   3971 	bool result = true;
   3972 
   3973 	m_gl.viewport(0, /* x */
   3974 				  0, /* y */
   3975 				  m_to_width, m_to_height);
   3976 
   3977 	m_gl.useProgram(m_po);
   3978 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
   3979 
   3980 	m_gl.clearColor(0.0f,  /* red */
   3981 					0.0f,  /* green */
   3982 					0.0f,  /* blue */
   3983 					0.0f); /* alpha */
   3984 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor() call failed.");
   3985 
   3986 	/* Render the quads.
   3987 	 *
   3988 	 * Run in two iterations:
   3989 	 *
   3990 	 * a) Iteration 1 performs the draw call with the VBO & IBO pages committed
   3991 	 * b) Iteration 2 performs the draw call with the VBO & IBO pages without any
   3992 	 *    physical backing.
   3993 	 **/
   3994 	for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
   3995 	{
   3996 		initSparseBO((n_iteration == 0), /* decommit pages after upload */
   3997 					 (sparse_bo_storage_flags & GL_DYNAMIC_STORAGE_BIT) != 0);
   3998 
   3999 		m_gl.clear(GL_COLOR_BUFFER_BIT);
   4000 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear() call failed.");
   4001 
   4002 		switch (m_ibo_usage)
   4003 		{
   4004 		case IBO_USAGE_NONE:
   4005 		{
   4006 			m_gl.drawArrays(GL_TRIANGLES, 0, /* first */
   4007 							m_n_vertices_to_draw);
   4008 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
   4009 
   4010 			break;
   4011 		}
   4012 
   4013 		case IBO_USAGE_INDEXED_DRAW_CALL:
   4014 		{
   4015 			m_gl.drawElements(GL_TRIANGLES, m_n_vertices_to_draw, GL_UNSIGNED_SHORT,
   4016 							  (glw::GLvoid*)(intptr_t)m_ibo_data_offset);
   4017 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed.");
   4018 
   4019 			break;
   4020 		}
   4021 
   4022 		case IBO_USAGE_INDEXED_RANGED_DRAW_CALL:
   4023 		{
   4024 			m_gl.drawRangeElements(GL_TRIANGLES, 0,		 /* start */
   4025 								   m_n_vertices_to_draw, /* end */
   4026 								   m_n_vertices_to_draw, /* count */
   4027 								   GL_UNSIGNED_SHORT, (glw::GLvoid*)(intptr_t)m_ibo_data_offset);
   4028 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawRangeElements() call failed.");
   4029 
   4030 			break;
   4031 		}
   4032 
   4033 		default:
   4034 		{
   4035 			TCU_FAIL("Unrecognized IBO usage value");
   4036 		}
   4037 		} /* switch (m_ibo_usage) */
   4038 
   4039 		/* Retrieve the rendered output */
   4040 		unsigned char* read_data = new unsigned char[m_to_width * m_to_height * sizeof(char) * 4 /* rgba */];
   4041 
   4042 		m_gl.readPixels(0, /* x */
   4043 						0, /* y */
   4044 						m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, read_data);
   4045 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed.");
   4046 
   4047 		/* IF the data pages have been committed by the time the draw call was made, validate the data.
   4048 		 *
   4049 		 * For each quad region (be it filled or not), check the center and make sure the retrieved
   4050 		 * color corresponds to the expected value.
   4051 		 */
   4052 		if (m_pages_committed)
   4053 		{
   4054 			for (unsigned int n_quad_region_y = 0; n_quad_region_y < m_n_quads_y * 2; /* quad + empty "delta" region */
   4055 				 ++n_quad_region_y)
   4056 			{
   4057 				for (unsigned int n_quad_region_x = 0; n_quad_region_x < m_n_quads_x * 2; ++n_quad_region_x)
   4058 				{
   4059 					/* Determine the expected texel color */
   4060 					unsigned char expected_color[4];
   4061 					unsigned char found_color[4];
   4062 					bool		  is_delta_region = (n_quad_region_x % 2) != 0 || (n_quad_region_y % 2) != 0;
   4063 
   4064 					if (is_delta_region)
   4065 					{
   4066 						memset(expected_color, 0, sizeof(expected_color));
   4067 					} /* if (is_delta_region) */
   4068 					else
   4069 					{
   4070 						if (m_use_color_data)
   4071 						{
   4072 							const unsigned int   n_quad_x = n_quad_region_x / 2;
   4073 							const unsigned int   n_quad_y = n_quad_region_y / 2;
   4074 							const unsigned char* data_ptr =
   4075 								m_data + m_color_data_offset +
   4076 								(n_quad_y * m_n_quads_x + n_quad_x) * 4 /* rgba */ * 6; /* vertices */
   4077 
   4078 							memcpy(expected_color, data_ptr, sizeof(expected_color));
   4079 						} /* if (m_use_color_data) */
   4080 						else
   4081 						{
   4082 							memset(expected_color, 255, sizeof(expected_color));
   4083 						}
   4084 					}
   4085 
   4086 					/* Do we have a match? */
   4087 					DE_ASSERT(m_n_quad_height == m_n_quad_delta_y);
   4088 					DE_ASSERT(m_n_quad_width == m_n_quad_delta_x);
   4089 
   4090 					const unsigned int sample_texel_x = m_n_quad_delta_x * n_quad_region_x;
   4091 					const unsigned int sample_texel_y = m_n_quad_delta_y * n_quad_region_y;
   4092 
   4093 					memcpy(found_color, read_data + (sample_texel_y * m_to_width + sample_texel_x) * 4, /* rgba */
   4094 						   sizeof(found_color));
   4095 
   4096 					if (memcmp(expected_color, found_color, sizeof(expected_color)) != 0)
   4097 					{
   4098 						m_testCtx.getLog() << tcu::TestLog::Message << "Invalid color found at "
   4099 																	   "("
   4100 										   << sample_texel_x << ", " << sample_texel_y << "): "
   4101 																						  "Expected color:"
   4102 																						  "("
   4103 										   << (int)expected_color[0] << ", " << (int)expected_color[1] << ", "
   4104 										   << (int)expected_color[2] << ", " << (int)expected_color[3] << "), "
   4105 																										  "Found:"
   4106 																										  "("
   4107 										   << (int)found_color[0] << ", " << (int)found_color[1] << ", "
   4108 										   << (int)found_color[2] << ", " << (int)found_color[3] << "), "
   4109 										   << tcu::TestLog::EndMessage;
   4110 
   4111 						result = false;
   4112 						goto end;
   4113 					}
   4114 				} /* for (all quads in X) */
   4115 			}	 /* for (all quads in Y) */
   4116 		}		  /* if (m_pages_committed) */
   4117 
   4118 		delete[] read_data;
   4119 		read_data = DE_NULL;
   4120 	} /* for (both iterations) */
   4121 
   4122 end:
   4123 	return result;
   4124 }
   4125 
   4126 /** Creates test data and fills the result buffer object (whose ID is stored under m_helper_bo)
   4127  *  with the data.
   4128  */
   4129 void QuadsBufferStorageTestCase::initHelperBO()
   4130 {
   4131 	DE_ASSERT(m_data == DE_NULL);
   4132 	DE_ASSERT(m_helper_bo == 0);
   4133 
   4134 	createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset);
   4135 
   4136 	m_gl.genBuffers(1, &m_helper_bo);
   4137 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   4138 
   4139 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   4140 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4141 
   4142 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_data_size, m_data, 0); /* flags */
   4143 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   4144 }
   4145 
   4146 /** Creates test data (if necessary), configures sparse buffer's memory page commitment
   4147  *  and uploads the test data to the buffer object. Finally, the method configures the
   4148  *  vertex array object, used by ::execute() at the draw call time.
   4149  *
   4150  *  @param decommit_data_pages_after_upload true to de-commit memory pages requested before
   4151  *                                          uploading the vertex/index/color data.
   4152  *  @param is_dynamic_storage               true to upload the data via glBufferSubData() call.
   4153  *                                          false to use a copy op for the operation.
   4154  **/
   4155 void QuadsBufferStorageTestCase::initSparseBO(bool decommit_data_pages_after_upload, bool is_dynamic_storage)
   4156 {
   4157 	/* Set up the vertex buffer object. */
   4158 	if (m_data == DE_NULL)
   4159 	{
   4160 		createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset);
   4161 	}
   4162 	else
   4163 	{
   4164 		/* Sanity checks */
   4165 		if (m_ibo_usage != IBO_USAGE_NONE)
   4166 		{
   4167 			DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset);
   4168 		}
   4169 
   4170 		if (m_use_color_data)
   4171 		{
   4172 			DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset);
   4173 			DE_ASSERT(m_ibo_data_offset != m_color_data_offset);
   4174 		}
   4175 	}
   4176 
   4177 	/* Commit as many pages as we need to upload the data */
   4178 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			/* offset */
   4179 								 m_data_size_rounded, GL_TRUE); /* commit */
   4180 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   4181 
   4182 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   4183 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4184 
   4185 	m_pages_committed = true;
   4186 
   4187 	/* Upload the data */
   4188 	if (is_dynamic_storage)
   4189 	{
   4190 		m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
   4191 						   m_data_size, m_data);
   4192 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
   4193 	}
   4194 	else
   4195 	{
   4196 		/* Sparse BO cannot be directly uploaded data to. Copy the data from a helper BO */
   4197 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, /* readOffset */
   4198 							   0,										/* writeOffset */
   4199 							   m_data_size);
   4200 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   4201 	}
   4202 
   4203 	/* Set the VAO up */
   4204 	m_gl.vertexAttribPointer(m_attribute_position_location, 4, /* size */
   4205 							 GL_FLOAT, GL_FALSE,			   /* normalized */
   4206 							 0,								   /* stride */
   4207 							 (glw::GLvoid*)(intptr_t)m_vbo_data_offset);
   4208 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed.");
   4209 
   4210 	m_gl.enableVertexAttribArray(m_attribute_position_location); /* index */
   4211 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed.");
   4212 
   4213 	if (m_use_color_data)
   4214 	{
   4215 		m_gl.vertexAttribPointer(m_attribute_color_location, 4, /* size */
   4216 								 GL_UNSIGNED_BYTE, GL_TRUE,		/* normalized */
   4217 								 0,								/* stride */
   4218 								 (glw::GLvoid*)(intptr_t)m_color_data_offset);
   4219 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed.");
   4220 
   4221 		m_gl.enableVertexAttribArray(m_attribute_color_location); /* index */
   4222 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed.");
   4223 	}
   4224 	else
   4225 	{
   4226 		m_gl.vertexAttrib4f(m_attribute_color_location, 1.0f, 1.0f, 1.0f, 1.0f);
   4227 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttrib4f() call failed.");
   4228 
   4229 		m_gl.disableVertexAttribArray(m_attribute_color_location);
   4230 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisableVertexAttribArray() call failed.");
   4231 	}
   4232 
   4233 	if (m_ibo_usage != IBO_USAGE_NONE)
   4234 	{
   4235 		m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sparse_bo);
   4236 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4237 	} /* if (m_use_ibo) */
   4238 
   4239 	/* If we were requested to do so, decommit the pages we have just uploaded
   4240 	 * the data to.
   4241 	 */
   4242 	if (decommit_data_pages_after_upload)
   4243 	{
   4244 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			 /* offset */
   4245 									 m_data_size_rounded, GL_FALSE); /* commit */
   4246 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   4247 
   4248 		m_pages_committed = false;
   4249 	} /* if (decommit_data_pages_after_upload) */
   4250 }
   4251 
   4252 /** Initializes GL objects used across all test case iterations.
   4253  *
   4254  *  Called once during BufferStorage test run-time.
   4255  */
   4256 bool QuadsBufferStorageTestCase::initTestCaseGlobal()
   4257 {
   4258 	bool result = true;
   4259 
   4260 	/* Set up the texture object */
   4261 	DE_ASSERT(m_to == 0);
   4262 
   4263 	m_gl.genTextures(1, &m_to);
   4264 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
   4265 
   4266 	m_gl.bindTexture(GL_TEXTURE_2D, m_to);
   4267 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
   4268 
   4269 	m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
   4270 					  GL_RGBA8, m_to_width, m_to_height);
   4271 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed.");
   4272 
   4273 	/* Set up the framebuffer object */
   4274 	DE_ASSERT(m_fbo == 0);
   4275 
   4276 	m_gl.genFramebuffers(1, &m_fbo);
   4277 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed.");
   4278 
   4279 	m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
   4280 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed.");
   4281 
   4282 	m_gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to, 0); /* level */
   4283 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferTexture2D() call failed.");
   4284 
   4285 	/* Set up the vertex array object */
   4286 	DE_ASSERT(m_vao == 0);
   4287 
   4288 	m_gl.genVertexArrays(1, &m_vao);
   4289 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
   4290 
   4291 	m_gl.bindVertexArray(m_vao);
   4292 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
   4293 
   4294 	/* Init a helper BO */
   4295 	initHelperBO();
   4296 
   4297 	/* Set up the program object */
   4298 	const char* fs_body = "#version 430 core\n"
   4299 						  "\n"
   4300 						  "flat in  vec4 fs_color;\n"
   4301 						  "     out vec4 color;\n"
   4302 						  "\n"
   4303 						  "void main()\n"
   4304 						  "{\n"
   4305 						  "    color = fs_color;\n"
   4306 						  "}\n";
   4307 
   4308 	const char* vs_body = "#version 430 core\n"
   4309 						  "\n"
   4310 						  "in vec4 color;\n"
   4311 						  "in vec4 position;\n"
   4312 						  "\n"
   4313 						  "flat out vec4 fs_color;\n"
   4314 						  "\n"
   4315 						  "void main()\n"
   4316 						  "{\n"
   4317 						  "    fs_color    = color;\n"
   4318 						  "    gl_Position = position;\n"
   4319 						  "}\n";
   4320 
   4321 	const unsigned int attribute_locations[] = { m_attribute_color_location, m_attribute_position_location };
   4322 	const char*		   attribute_names[]	 = { "color", "position" };
   4323 	const unsigned int n_attributes			 = sizeof(attribute_locations) / sizeof(attribute_locations[0]);
   4324 
   4325 	DE_ASSERT(m_po == 0);
   4326 
   4327 	m_po = SparseBufferTestUtilities::createProgram(m_gl, &fs_body, 1, /* n_fs_body_parts */
   4328 													&vs_body, 1, attribute_names, attribute_locations,
   4329 													n_attributes); /* n_vs_body_parts */
   4330 
   4331 	if (m_po == 0)
   4332 	{
   4333 		result = false;
   4334 
   4335 		goto end;
   4336 	}
   4337 
   4338 end:
   4339 	return result;
   4340 }
   4341 
   4342 /** Initializes GL objects which are needed for a single test case iteration.
   4343  *
   4344  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   4345  *  to release these objects.
   4346  **/
   4347 bool QuadsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   4348 {
   4349 	bool result = true;
   4350 
   4351 	/* Cache the BO id, if not cached already */
   4352 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   4353 
   4354 	m_sparse_bo = sparse_bo;
   4355 
   4356 	return result;
   4357 }
   4358 
   4359 /** Constructor.
   4360  *
   4361  *  @param gl                         GL entry-points container
   4362  *  @param testContext                CTS test context
   4363  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   4364  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   4365  */
   4366 QueryBufferStorageTestCase::QueryBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
   4367 													   glw::GLint page_size)
   4368 	: m_gl(gl)
   4369 	, m_helper_bo(0)
   4370 	, m_n_triangles(15)
   4371 	, m_page_size(page_size)
   4372 	, m_po(0)
   4373 	, m_qo(0)
   4374 	, m_sparse_bo(0)
   4375 	, m_sparse_bo_size(0)
   4376 	, m_sparse_bo_size_rounded(0)
   4377 	, m_testCtx(testContext)
   4378 	, m_vao(0)
   4379 {
   4380 	/* Left blank on purpose */
   4381 }
   4382 
   4383 /** Releases all GL objects used across all test case iterations.
   4384  *
   4385  *  Called once during BufferStorage test run-time.
   4386  */
   4387 void QueryBufferStorageTestCase::deinitTestCaseGlobal()
   4388 {
   4389 	if (m_helper_bo != 0)
   4390 	{
   4391 		m_gl.deleteBuffers(1, &m_helper_bo);
   4392 
   4393 		m_helper_bo = 0;
   4394 	}
   4395 
   4396 	if (m_po != 0)
   4397 	{
   4398 		m_gl.deleteProgram(m_po);
   4399 
   4400 		m_po = 0;
   4401 	}
   4402 
   4403 	if (m_qo != 0)
   4404 	{
   4405 		m_gl.deleteQueries(1, &m_qo);
   4406 
   4407 		m_qo = 0;
   4408 	}
   4409 
   4410 	if (m_vao != 0)
   4411 	{
   4412 		m_gl.deleteVertexArrays(1, &m_vao);
   4413 
   4414 		m_vao = 0;
   4415 	}
   4416 }
   4417 
   4418 /** Releases temporary GL objects, created specifically for one test case iteration. */
   4419 void QueryBufferStorageTestCase::deinitTestCaseIteration()
   4420 {
   4421 	if (m_sparse_bo != 0)
   4422 	{
   4423 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   4424 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4425 
   4426 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   4427 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   4428 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   4429 
   4430 		m_sparse_bo = 0;
   4431 	}
   4432 }
   4433 
   4434 /** Executes a single test iteration. The BufferStorage test will call this method
   4435  *  numerously during its life-time, testing various valid flag combinations applied
   4436  *  to the tested sparse buffer object at glBufferStorage() call time.
   4437  *
   4438  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   4439  *                                 call to set up the sparse buffer's storage.
   4440  *
   4441  *  @return true if the test case executed correctly, false otherwise.
   4442  */
   4443 bool QueryBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   4444 {
   4445 	(void)sparse_bo_storage_flags;
   4446 	static const unsigned char data_r8_zero = 0;
   4447 	bool					   result		= true;
   4448 
   4449 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
   4450 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4451 
   4452 	m_gl.useProgram(m_po);
   4453 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
   4454 
   4455 	/* Run two separate iterations:
   4456 	 *
   4457 	 * a) The page holding the query result value is committed.
   4458 	 * b) The page is not committed.
   4459 	 */
   4460 	for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
   4461 	{
   4462 		const bool should_commit_page = (n_iteration == 0);
   4463 
   4464 		/* Set up the memory page commitment */
   4465 		m_gl.bufferPageCommitmentARB(GL_QUERY_BUFFER, 0, /* offset */
   4466 									 m_sparse_bo_size_rounded, should_commit_page ? GL_TRUE : GL_FALSE);
   4467 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   4468 
   4469 		/* Run the draw call */
   4470 		m_gl.beginQuery(GL_PRIMITIVES_GENERATED, m_qo);
   4471 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginQuery() call failed.");
   4472 
   4473 		m_gl.drawArrays(GL_TRIANGLES, 0, /* first */
   4474 						m_n_triangles * 3);
   4475 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
   4476 
   4477 		m_gl.endQuery(GL_PRIMITIVES_GENERATED);
   4478 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndQuery() call failed.");
   4479 
   4480 		/* Copy the query result to the sparse buffer */
   4481 		for (unsigned int n_getter_call = 0; n_getter_call < 4; ++n_getter_call)
   4482 		{
   4483 			glw::GLsizei result_n_bytes;
   4484 
   4485 			switch (n_getter_call)
   4486 			{
   4487 			case 0:
   4488 			{
   4489 				result_n_bytes = sizeof(glw::GLint);
   4490 				m_gl.getQueryObjectiv(m_qo, GL_QUERY_RESULT, (glw::GLint*)0); /* params */
   4491 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectiv() call failed.");
   4492 
   4493 				break;
   4494 			}
   4495 
   4496 			case 1:
   4497 			{
   4498 				result_n_bytes = sizeof(glw::GLint);
   4499 				m_gl.getQueryObjectuiv(m_qo, GL_QUERY_RESULT, (glw::GLuint*)0); /* params */
   4500 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectuiv() call failed.");
   4501 
   4502 				break;
   4503 			}
   4504 
   4505 			case 2:
   4506 			{
   4507 				result_n_bytes = sizeof(glw::GLint64);
   4508 				m_gl.getQueryObjecti64v(m_qo, GL_QUERY_RESULT, (glw::GLint64*)0);
   4509 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjecti64v() call failed.");
   4510 
   4511 				break;
   4512 			}
   4513 
   4514 			case 3:
   4515 			{
   4516 				result_n_bytes = sizeof(glw::GLint64);
   4517 				m_gl.getQueryObjectui64v(m_qo, GL_QUERY_RESULT, (glw::GLuint64*)0);
   4518 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectui64v() call failed.");
   4519 
   4520 				break;
   4521 			}
   4522 
   4523 			default:
   4524 			{
   4525 				TCU_FAIL("Invalid getter call type");
   4526 			}
   4527 			} /* switch (n_getter_call) */
   4528 
   4529 			/* Verify the query result */
   4530 			if (should_commit_page)
   4531 			{
   4532 				const glw::GLint64* result_ptr = NULL;
   4533 
   4534 				m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
   4535 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4536 
   4537 				m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_r8_zero);
   4538 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
   4539 
   4540 				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   4541 									   0,											 /* writeOffset */
   4542 									   result_n_bytes);
   4543 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   4544 
   4545 				result_ptr = (const glw::GLint64*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY);
   4546 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
   4547 
   4548 				if (*result_ptr != m_n_triangles)
   4549 				{
   4550 					m_testCtx.getLog() << tcu::TestLog::Message
   4551 									   << "Invalid query result stored in a sparse buffer. Found: "
   4552 										  "["
   4553 									   << *result_ptr << "]"
   4554 														 ", expected: "
   4555 														 "["
   4556 									   << m_n_triangles << "]" << tcu::TestLog::EndMessage;
   4557 
   4558 					result = false;
   4559 				}
   4560 
   4561 				m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
   4562 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   4563 			} /* for (all query getter call types) */
   4564 		}	 /* if (should_commit_page) */
   4565 	}		  /* for (both iterations) */
   4566 
   4567 	return result;
   4568 }
   4569 
   4570 /** Initializes GL objects used across all test case iterations.
   4571  *
   4572  *  Called once during BufferStorage test run-time.
   4573  */
   4574 bool QueryBufferStorageTestCase::initTestCaseGlobal()
   4575 {
   4576 	/* Determine sparse buffer storage size */
   4577 	m_sparse_bo_size		 = sizeof(glw::GLuint64);
   4578 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
   4579 
   4580 	/* Set up the test program object */
   4581 	static const char* vs_body = "#version 140\n"
   4582 								 "\n"
   4583 								 "void main()\n"
   4584 								 "{\n"
   4585 								 "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
   4586 								 "}\n";
   4587 
   4588 	m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
   4589 													0,			   /* n_fs_body_parts */
   4590 													&vs_body, 1,   /* n_vs_body_parts */
   4591 													DE_NULL,	   /* attribute_names */
   4592 													DE_NULL,	   /* attribute_locations */
   4593 													0);			   /* n_attribute_locations */
   4594 
   4595 	if (m_po == 0)
   4596 	{
   4597 		TCU_FAIL("Test program linking failure");
   4598 	}
   4599 
   4600 	/* Set up the helper buffer object */
   4601 	m_gl.genBuffers(1, &m_helper_bo);
   4602 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   4603 
   4604 	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
   4605 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4606 
   4607 	m_gl.bufferStorage(GL_COPY_WRITE_BUFFER, sizeof(glw::GLint64), DE_NULL, /* data */
   4608 					   GL_MAP_READ_BIT);
   4609 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   4610 
   4611 	/* Set up the test query object */
   4612 	m_gl.genQueries(1, &m_qo);
   4613 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenQueries() call failed.");
   4614 
   4615 	/* Set up the VAO */
   4616 	m_gl.genVertexArrays(1, &m_vao);
   4617 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
   4618 
   4619 	m_gl.bindVertexArray(m_vao);
   4620 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
   4621 
   4622 	return true;
   4623 }
   4624 
   4625 /** Initializes GL objects which are needed for a single test case iteration.
   4626  *
   4627  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   4628  *  to release these objects.
   4629  **/
   4630 bool QueryBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   4631 {
   4632 	bool result = true;
   4633 
   4634 	/* Cache the BO id, if not cached already */
   4635 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   4636 
   4637 	m_sparse_bo = sparse_bo;
   4638 
   4639 	/* Set up the sparse buffer. */
   4640 	m_gl.bindBuffer(GL_QUERY_BUFFER, m_sparse_bo);
   4641 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4642 
   4643 	return result;
   4644 }
   4645 
   4646 /** Constructor.
   4647  *
   4648  *  @param gl                         GL entry-points container
   4649  *  @param testContext                CTS test context
   4650  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   4651  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   4652  */
   4653 SSBOStorageTestCase::SSBOStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size)
   4654 	: m_gl(gl)
   4655 	, m_helper_bo(0)
   4656 	, m_page_size(page_size)
   4657 	, m_po(0)
   4658 	, m_po_local_wg_size(1024)
   4659 	, m_result_bo(0)
   4660 	, m_sparse_bo(0)
   4661 	, m_sparse_bo_size(0)
   4662 	, m_sparse_bo_size_rounded(0)
   4663 	, m_ssbo_data(DE_NULL)
   4664 	, m_testCtx(testContext)
   4665 {
   4666 	/* min max for SSBO size from GL_ARB_shader_storage_buffer_object is 16mb;
   4667 	 *
   4668 	 * The specified amount of space lets the test write as many
   4669 	 * ints as it's possible, with an assertion that our CS
   4670 	 * uses a std140 layout and the SSBO only contains an unsized array.
   4671 	 *
   4672 	 * NOTE: 16777216 % 1024 = 0, which is awesome because we can hardcode the
   4673 	 *       local workgroup size directly in the CS.
   4674 	 */
   4675 	m_sparse_bo_size		 = (16777216 / (sizeof(int) * 4) /* std140 */) * (sizeof(int) * 4);
   4676 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
   4677 }
   4678 
   4679 /** Releases all GL objects used across all test case iterations.
   4680  *
   4681  *  Called once during BufferStorage test run-time.
   4682  */
   4683 void SSBOStorageTestCase::deinitTestCaseGlobal()
   4684 {
   4685 	if (m_helper_bo != 0)
   4686 	{
   4687 		m_gl.deleteBuffers(1, &m_helper_bo);
   4688 
   4689 		m_helper_bo = 0;
   4690 	}
   4691 
   4692 	if (m_po != 0)
   4693 	{
   4694 		m_gl.deleteProgram(m_po);
   4695 
   4696 		m_po = 0;
   4697 	}
   4698 
   4699 	if (m_result_bo != 0)
   4700 	{
   4701 		m_gl.deleteBuffers(1, &m_result_bo);
   4702 
   4703 		m_result_bo = 0;
   4704 	}
   4705 
   4706 	if (m_ssbo_data != DE_NULL)
   4707 	{
   4708 		delete[] m_ssbo_data;
   4709 
   4710 		m_ssbo_data = DE_NULL;
   4711 	}
   4712 }
   4713 
   4714 /** Releases temporary GL objects, created specifically for one test case iteration. */
   4715 void SSBOStorageTestCase::deinitTestCaseIteration()
   4716 {
   4717 	if (m_sparse_bo != 0)
   4718 	{
   4719 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   4720 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4721 
   4722 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   4723 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   4724 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   4725 
   4726 		m_sparse_bo = 0;
   4727 	}
   4728 }
   4729 
   4730 /** Executes a single test iteration. The BufferStorage test will call this method
   4731  *  numerously during its life-time, testing various valid flag combinations applied
   4732  *  to the tested sparse buffer object at glBufferStorage() call time.
   4733  *
   4734  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   4735  *                                 call to set up the sparse buffer's storage.
   4736  *
   4737  *  @return true if the test case executed correctly, false otherwise.
   4738  */
   4739 bool SSBOStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   4740 {
   4741 	(void)sparse_bo_storage_flags;
   4742 	bool result = true;
   4743 
   4744 	/* Bind the program object */
   4745 	m_gl.useProgram(m_po);
   4746 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
   4747 
   4748 	/* Set up shader storage buffer bindings */
   4749 	m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_sparse_bo);
   4750 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4751 
   4752 	m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */
   4753 						m_sparse_bo);
   4754 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
   4755 
   4756 	/* Run the test in three iterations:
   4757 	 *
   4758 	 * a) All required pages are committed.
   4759 	 * b) Only half of the pages are committed (in a zig-zag layout)
   4760 	 * c) None of the pages are committed.
   4761 	 */
   4762 	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
   4763 	{
   4764 		bool result_local = true;
   4765 
   4766 		/* Set up the shader storage buffer object's memory backing */
   4767 		const bool   is_zigzag_ssbo			  = (n_iteration == 1);
   4768 		unsigned int ssbo_commit_size		  = 0;
   4769 		unsigned int ssbo_commit_start_offset = 0;
   4770 
   4771 		switch (n_iteration)
   4772 		{
   4773 		case 0:
   4774 		case 1:
   4775 		{
   4776 			ssbo_commit_size		 = m_sparse_bo_size_rounded;
   4777 			ssbo_commit_start_offset = 0;
   4778 
   4779 			if (is_zigzag_ssbo)
   4780 			{
   4781 				const unsigned int n_pages = ssbo_commit_size / m_page_size;
   4782 
   4783 				for (unsigned int n_page = 0; n_page < n_pages; n_page += 2)
   4784 				{
   4785 					m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, m_page_size * n_page, /* offset */
   4786 												 m_page_size,									 /* size */
   4787 												 GL_TRUE);										 /* commit */
   4788 				} /* for (all memory pages) */
   4789 			}
   4790 			else
   4791 			{
   4792 				m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0, /* offset */
   4793 											 ssbo_commit_size, GL_TRUE);  /* commit */
   4794 			}
   4795 
   4796 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed.");
   4797 
   4798 			break;
   4799 		}
   4800 
   4801 		case 2:
   4802 		{
   4803 			/* Use no physical memory backing */
   4804 			break;
   4805 		}
   4806 
   4807 		default:
   4808 		{
   4809 			TCU_FAIL("Unrecognized iteration index");
   4810 		}
   4811 		} /* switch (n_iteration) */
   4812 
   4813 		/* Set up bindings for the copy op */
   4814 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   4815 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
   4816 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   4817 
   4818 		/* Set up the sparse buffer's data storage */
   4819 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   4820 							   0,											 /* writeOffset */
   4821 							   m_sparse_bo_size);
   4822 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   4823 
   4824 		/* Run the compute program */
   4825 		DE_ASSERT((m_sparse_bo_size % m_po_local_wg_size) == 0);
   4826 
   4827 		m_gl.dispatchCompute(m_sparse_bo_size / m_po_local_wg_size, 1, /* num_groups_y */
   4828 							 1);									   /* num_groups_z */
   4829 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed.");
   4830 
   4831 		/* Flush the caches */
   4832 		m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
   4833 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed.");
   4834 
   4835 		/* Copy SSBO's storage to a mappable result BO */
   4836 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
   4837 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_result_bo);
   4838 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   4839 
   4840 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   4841 							   0,											 /* writeOffset */
   4842 							   m_sparse_bo_size);
   4843 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   4844 
   4845 		/* Map the result BO to the process space */
   4846 		unsigned int		current_ssbo_offset = 0;
   4847 		const unsigned int* ssbo_data_ptr = (const unsigned int*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY);
   4848 
   4849 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
   4850 
   4851 		for (unsigned int n_invocation = 0; current_ssbo_offset < m_sparse_bo_size && result_local; ++n_invocation,
   4852 						  current_ssbo_offset = static_cast<unsigned int>(current_ssbo_offset +
   4853 																		  (sizeof(int) * 4 /* std140 */)))
   4854 		{
   4855 			const unsigned int n_page = current_ssbo_offset / m_page_size;
   4856 
   4857 			if ((is_zigzag_ssbo && (n_page % 2) == 0) ||
   4858 				(!is_zigzag_ssbo && (current_ssbo_offset >= ssbo_commit_start_offset &&
   4859 									 current_ssbo_offset < (ssbo_commit_start_offset + ssbo_commit_size))))
   4860 			{
   4861 				if (ssbo_data_ptr[n_invocation * 4] != (n_invocation + 1))
   4862 				{
   4863 					m_testCtx.getLog() << tcu::TestLog::Message << "Value written to the SSBO at byte "
   4864 																   "["
   4865 									   << (sizeof(int) * n_invocation) << "]"
   4866 																		  " is invalid. Found:"
   4867 									   << "[" << ssbo_data_ptr[n_invocation * 4] << "]"
   4868 																					", expected:"
   4869 									   << "[" << (n_invocation + 1) << "]" << tcu::TestLog::EndMessage;
   4870 
   4871 					result_local = false;
   4872 				}
   4873 			} /* if (ssbo_data_ptr[n_texel] != 1) */
   4874 		}	 /* for (all result values) */
   4875 
   4876 		result &= result_local;
   4877 
   4878 		m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
   4879 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   4880 
   4881 		/* Remove the physical backing from the sparse buffer  */
   4882 		m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0,		  /* offset */
   4883 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   4884 
   4885 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   4886 	} /* for (three iterations) */
   4887 
   4888 	return result;
   4889 }
   4890 
   4891 /** Initializes GL objects used across all test case iterations.
   4892  *
   4893  *  Called once during BufferStorage test run-time.
   4894  */
   4895 bool SSBOStorageTestCase::initTestCaseGlobal()
   4896 {
   4897 	/* Set up the test program */
   4898 	static const char* cs_body =
   4899 		"#version 430 core\n"
   4900 		"\n"
   4901 		"layout(local_size_x = 1024) in;\n"
   4902 		"\n"
   4903 		"layout(std140, binding = 0) buffer data\n"
   4904 		"{\n"
   4905 		"    restrict uint io_values[];\n"
   4906 		"};\n"
   4907 		"\n"
   4908 		"void main()\n"
   4909 		"{\n"
   4910 		"    uint value_index = gl_GlobalInvocationID.x;\n"
   4911 		"    uint new_value   = (io_values[value_index] == value_index) ? (value_index + 1u) : value_index;\n"
   4912 		"\n"
   4913 		"    io_values[value_index] = new_value;\n"
   4914 		"}\n";
   4915 
   4916 	m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
   4917 
   4918 	/* Set up a data buffer we will use to initialize the SSBO with default data.
   4919 	 *
   4920 	 * CS uses a std140 layout for the SSBO, so we need to add the additional padding.
   4921 	 */
   4922 	DE_ASSERT((m_sparse_bo_size) != 0);
   4923 	DE_ASSERT((m_sparse_bo_size % (sizeof(int) * 4)) == 0);
   4924 	DE_ASSERT((m_sparse_bo_size % 1024) == 0);
   4925 
   4926 	m_ssbo_data = new unsigned int[m_sparse_bo_size / sizeof(int)];
   4927 
   4928 	memset(m_ssbo_data, 0, m_sparse_bo_size);
   4929 
   4930 	for (unsigned int index = 0; index < m_sparse_bo_size / sizeof(int) / 4; ++index)
   4931 	{
   4932 		/* Mind the std140 rules for arrays of ints */
   4933 		m_ssbo_data[4 * index] = index;
   4934 	}
   4935 
   4936 	/* During execution, we will need to use a helper buffer object. The BO will hold
   4937 	 * data we will be copying into the sparse buffer object for each iteration.
   4938 	 */
   4939 	m_gl.genBuffers(1, &m_helper_bo);
   4940 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   4941 
   4942 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   4943 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4944 
   4945 	m_gl.bufferData(GL_COPY_READ_BUFFER, m_sparse_bo_size, m_ssbo_data, GL_STATIC_DRAW);
   4946 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
   4947 
   4948 	/* To retrieve the data written to a sparse SSBO, we need to use another
   4949 	 * non-sparse helper BO.
   4950 	 */
   4951 	m_gl.genBuffers(1, &m_result_bo);
   4952 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   4953 
   4954 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_result_bo);
   4955 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   4956 
   4957 	m_gl.bufferData(GL_ARRAY_BUFFER, m_sparse_bo_size, DE_NULL, /* data */
   4958 					GL_STATIC_DRAW);
   4959 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
   4960 
   4961 	return true;
   4962 }
   4963 
   4964 /** Initializes GL objects which are needed for a single test case iteration.
   4965  *
   4966  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   4967  *  to release these objects.
   4968  **/
   4969 bool SSBOStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   4970 {
   4971 	bool result = true;
   4972 
   4973 	/* Cache the BO id, if not cached already */
   4974 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   4975 
   4976 	m_sparse_bo = sparse_bo;
   4977 
   4978 	return result;
   4979 }
   4980 
   4981 /** Constructor.
   4982  *
   4983  *  @param gl                         GL entry-points container
   4984  *  @param testContext                CTS test context
   4985  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   4986  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   4987  *  @param all_pages_committed        true to provide memory backing for all memory pages holding data used by the test.
   4988  *                                    false to leave some of them uncommitted.
   4989  */
   4990 TransformFeedbackBufferStorageTestCase::TransformFeedbackBufferStorageTestCase(const glw::Functions& gl,
   4991 																			   tcu::TestContext&	 testContext,
   4992 																			   glw::GLint			 page_size,
   4993 																			   bool all_pages_committed)
   4994 	: m_all_pages_committed(all_pages_committed)
   4995 	, m_data_bo(0)
   4996 	, m_data_bo_index_data_offset(0)
   4997 	, m_data_bo_indexed_indirect_arg_offset(0)
   4998 	, m_data_bo_indexed_mdi_arg_offset(0)
   4999 	, m_data_bo_regular_indirect_arg_offset(0)
   5000 	, m_data_bo_regular_mdi_arg_offset(0)
   5001 	, m_data_bo_size(0)
   5002 	, m_draw_call_baseInstance(1231)
   5003 	, m_draw_call_baseVertex(65537)
   5004 	, m_draw_call_first(913)
   5005 	, m_draw_call_firstIndex(4)
   5006 	, m_gl(gl)
   5007 	, m_helper_bo(0)
   5008 	, m_index_data(DE_NULL)
   5009 	, m_index_data_size(0)
   5010 	, m_indirect_arg_data(DE_NULL)
   5011 	, m_indirect_arg_data_size(0)
   5012 	, m_min_memory_page_span(4) /* as per test spec */
   5013 	, m_multidrawcall_drawcount(-1)
   5014 	, m_multidrawcall_primcount(-1)
   5015 	, m_n_instances_to_test(4)
   5016 	, m_n_vertices_per_instance(0)
   5017 	, m_page_size(page_size)
   5018 	, m_po_ia(0)
   5019 	, m_po_sa(0)
   5020 	, m_result_bo(0)
   5021 	, m_result_bo_size(0)
   5022 	, m_result_bo_size_rounded(0)
   5023 	, m_testCtx(testContext)
   5024 	, m_vao(0)
   5025 {
   5026 	/* Left blank on purpose */
   5027 }
   5028 
   5029 /** Releases all GL objects used across all test case iterations.
   5030  *
   5031  *  Called once during BufferStorage test run-time.
   5032  */
   5033 void TransformFeedbackBufferStorageTestCase::deinitTestCaseGlobal()
   5034 {
   5035 	if (m_data_bo != 0)
   5036 	{
   5037 		m_gl.deleteBuffers(1, &m_data_bo);
   5038 
   5039 		m_data_bo = 0;
   5040 	}
   5041 
   5042 	if (m_helper_bo != 0)
   5043 	{
   5044 		m_gl.deleteBuffers(1, &m_helper_bo);
   5045 
   5046 		m_helper_bo = 0;
   5047 	}
   5048 
   5049 	if (m_index_data != DE_NULL)
   5050 	{
   5051 		delete[] m_index_data;
   5052 
   5053 		m_index_data = DE_NULL;
   5054 	}
   5055 
   5056 	if (m_indirect_arg_data != DE_NULL)
   5057 	{
   5058 		delete[] m_indirect_arg_data;
   5059 
   5060 		m_indirect_arg_data = DE_NULL;
   5061 	}
   5062 
   5063 	if (m_po_ia != 0)
   5064 	{
   5065 		m_gl.deleteProgram(m_po_ia);
   5066 
   5067 		m_po_ia = 0;
   5068 	}
   5069 
   5070 	if (m_po_sa != 0)
   5071 	{
   5072 		m_gl.deleteProgram(m_po_sa);
   5073 
   5074 		m_po_sa = 0;
   5075 	}
   5076 
   5077 	if (m_result_bo != 0)
   5078 	{
   5079 		m_gl.deleteBuffers(1, &m_result_bo);
   5080 
   5081 		m_result_bo = 0;
   5082 	}
   5083 
   5084 	if (m_vao != 0)
   5085 	{
   5086 		m_gl.deleteVertexArrays(1, &m_vao);
   5087 
   5088 		m_vao = 0;
   5089 	}
   5090 }
   5091 
   5092 /** Executes a single test iteration. The BufferStorage test will call this method
   5093  *  numerously during its life-time, testing various valid flag combinations applied
   5094  *  to the tested sparse buffer object at glBufferStorage() call time.
   5095  *
   5096  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   5097  *                                 call to set up the sparse buffer's storage.
   5098  *
   5099  *  @return true if the test case executed correctly, false otherwise.
   5100  */
   5101 bool TransformFeedbackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   5102 {
   5103 	bool result = true;
   5104 
   5105 	/* Iterate through two different transform feedback modes we need to test */
   5106 	for (unsigned int n_tf_type = 0; n_tf_type < 2; /* interleaved & separate attribs */
   5107 		 ++n_tf_type)
   5108 	{
   5109 		const bool is_ia_iteration = (n_tf_type == 0);
   5110 
   5111 		/* Bind the test PO to the context */
   5112 		m_gl.useProgram(is_ia_iteration ? m_po_ia : m_po_sa);
   5113 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
   5114 
   5115 		/* Set up TF general binding, which is needed for a glClearBufferData() call
   5116 		 * we'll be firing shortly.
   5117 		 */
   5118 		m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, /* needed for the subsequent glClearBufferData() call */
   5119 						m_result_bo);
   5120 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   5121 
   5122 		/* Iterate through all draw call types */
   5123 		for (unsigned int n_draw_call_type = 0; n_draw_call_type < DRAW_CALL_COUNT; ++n_draw_call_type)
   5124 		{
   5125 			int				   draw_call_count					= 0; /* != 1 for multi-draw calls only */
   5126 			int				   draw_call_first_instance_id[2]   = { -1 };
   5127 			int				   draw_call_first_vertex_id[2]		= { -1 };
   5128 			int				   draw_call_n_instances[2]			= { 0 };
   5129 			int				   draw_call_n_vertices[2]			= { 0 };
   5130 			bool			   draw_call_is_vertex_id_ascending = false;
   5131 			const _draw_call   draw_call_type					= (_draw_call)n_draw_call_type;
   5132 			unsigned int	   n_result_bytes_per_instance[2]   = { 0 };
   5133 			const unsigned int n_result_bytes_per_vertex		= sizeof(unsigned int) * 2;
   5134 			unsigned int	   n_result_bytes_total				= 0;
   5135 			glw::GLuint*	   result_ptr						= DE_NULL;
   5136 
   5137 			m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_data_bo);
   5138 			m_gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_data_bo);
   5139 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   5140 
   5141 			/* Commit pages needed to execute transform feed-back */
   5142 			if (m_all_pages_committed)
   5143 			{
   5144 				m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0,	/* offset */
   5145 											 m_result_bo_size_rounded, GL_TRUE); /* commit */
   5146 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   5147 			}
   5148 			else
   5149 			{
   5150 				for (unsigned int n_page = 0; n_page < m_result_bo_size_rounded / m_page_size; ++n_page)
   5151 				{
   5152 					m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, n_page * m_page_size, /* offset */
   5153 												 m_page_size,										 /* size   */
   5154 												 (n_page % 2 == 0) ? GL_TRUE : GL_FALSE);			 /* commit */
   5155 				}
   5156 
   5157 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   5158 			}
   5159 
   5160 			/* Zero out the target BO before we begin the TF */
   5161 			static const unsigned char data_zero = 0;
   5162 
   5163 			m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero);
   5164 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
   5165 
   5166 			/* Set up transform feed-back buffer bindings */
   5167 			DE_ASSERT(m_result_bo_size != 0);
   5168 
   5169 			if (is_ia_iteration)
   5170 			{
   5171 				DE_ASSERT(m_result_bo != 0);
   5172 
   5173 				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
   5174 									 m_result_bo, 0,				  /* offset */
   5175 									 m_result_bo_size);
   5176 
   5177 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
   5178 			}
   5179 			else
   5180 			{
   5181 				DE_ASSERT(m_result_bo_size % 2 == 0);
   5182 
   5183 				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
   5184 									 m_result_bo, 0,				  /* offset */
   5185 									 m_result_bo_size / 2);
   5186 				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, /* index */
   5187 									 m_result_bo, m_result_bo_size / 2, m_result_bo_size / 2);
   5188 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call(s) failed.");
   5189 			}
   5190 
   5191 			m_gl.beginTransformFeedback(GL_POINTS);
   5192 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed.");
   5193 
   5194 			/* NOTE: Some discussion about the expected "vertex id" value:
   5195 			 *
   5196 			 * In GL 4.5 core spec (Feb2/2015 version), we have:
   5197 			 *
   5198 			 * >>
   5199 			 * The index of any element transferred to the GL by DrawElementsOneInstance
   5200 			 * is referred to as its vertex ID, and may be read by a vertex shader as
   5201 			 * gl_VertexID. The vertex ID of the ith element transferred is the sum of
   5202 			 * basevertex and the value stored in the currently bound element array buffer at
   5203 			 * offset indices +i.
   5204 			 * <<
   5205 			 *
   5206 			 * So for glDrawElements*() derivatives, we will be expecting gl_VertexID to be set to
   5207 			 * (basevertex + index[i] + i)
   5208 			 *
   5209 			 * DrawArrays does not support the "base vertex" concept at all:
   5210 			 *
   5211 			 * >>
   5212 			 * The index of any element transferred to the GL by DrawArraysOneInstance
   5213 			 * is referred to as its vertex ID, and may be read by a vertex shader as gl_VertexID.
   5214 			 * The vertex ID of the ith element transferred is first + i.
   5215 			 * <<
   5216 			 *
   5217 			 * For regular draw calls, gl_VertexID should be of form:
   5218 			 *
   5219 			 * (first + i)
   5220 			 *
   5221 			 * In both cases, gl_InstanceID does NOT include the baseinstance value, as per:
   5222 			 *
   5223 			 * >>
   5224 			 * If an enabled vertex attribute array is instanced (it has a non-zero divisor as
   5225 			 * specified by VertexAttribDivisor), the element index that is transferred to the GL,
   5226 			 * for all vertices, is given by
   5227 			 *
   5228 			 * floor(instance / divisor) + baseinstance
   5229 			 *
   5230 			 * The value of instance may be read by a vertex shader as gl_InstanceID, as
   5231 			 * described in section 11.1.3.9
   5232 			 * <<
   5233 			 */
   5234 			switch (draw_call_type)
   5235 			{
   5236 			case DRAW_CALL_INDEXED:
   5237 			{
   5238 				m_gl.drawElements(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
   5239 								  (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset);
   5240 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed.");
   5241 
   5242 				draw_call_count					 = 1;
   5243 				draw_call_first_instance_id[0]   = 0;
   5244 				draw_call_first_vertex_id[0]	 = m_n_vertices_per_instance;
   5245 				draw_call_is_vertex_id_ascending = false;
   5246 				draw_call_n_instances[0]		 = 1;
   5247 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
   5248 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
   5249 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5250 
   5251 				break;
   5252 			}
   5253 
   5254 			case DRAW_CALL_INDEXED_BASE_VERTEX:
   5255 			{
   5256 				m_gl.drawElementsBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
   5257 											(const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
   5258 											m_draw_call_baseVertex);
   5259 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsBaseVertex() call failed.");
   5260 
   5261 				draw_call_count					 = 1;
   5262 				draw_call_first_instance_id[0]   = 0;
   5263 				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_n_vertices_per_instance;
   5264 				draw_call_is_vertex_id_ascending = false;
   5265 				draw_call_n_instances[0]		 = 1;
   5266 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
   5267 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
   5268 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5269 
   5270 				break;
   5271 			}
   5272 
   5273 			case DRAW_CALL_INDEXED_INDIRECT:
   5274 			{
   5275 				m_gl.drawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT,
   5276 										  (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_indirect_arg_offset);
   5277 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsIndirect() call failed.");
   5278 
   5279 				draw_call_count				   = 1;
   5280 				draw_call_first_instance_id[0] = 0;
   5281 				draw_call_first_vertex_id[0] =
   5282 					m_draw_call_baseVertex +
   5283 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
   5284 								 sizeof(unsigned int)];
   5285 				draw_call_is_vertex_id_ascending = false;
   5286 				draw_call_n_instances[0]		 = m_n_instances_to_test;
   5287 				draw_call_n_vertices[0]			 = m_multidrawcall_count[1];
   5288 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
   5289 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5290 
   5291 				break;
   5292 			}
   5293 
   5294 			case DRAW_CALL_INDEXED_INDIRECT_MULTI:
   5295 			{
   5296 				m_gl.multiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT,
   5297 											   (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_mdi_arg_offset,
   5298 											   m_multidrawcall_drawcount, 0); /* stride */
   5299 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsIndirect() call failed.");
   5300 
   5301 				draw_call_count				   = m_multidrawcall_drawcount;
   5302 				draw_call_first_instance_id[0] = 0;
   5303 				draw_call_first_instance_id[1] = 0;
   5304 				draw_call_first_vertex_id[0] =
   5305 					m_draw_call_baseVertex +
   5306 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
   5307 								 sizeof(unsigned int)];
   5308 				draw_call_first_vertex_id[1] =
   5309 					m_draw_call_baseVertex +
   5310 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
   5311 								 sizeof(unsigned int)];
   5312 				draw_call_is_vertex_id_ascending = false;
   5313 				draw_call_n_instances[0]		 = 1;
   5314 				draw_call_n_instances[1]		 = m_n_instances_to_test;
   5315 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
   5316 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
   5317 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
   5318 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * draw_call_n_vertices[1];
   5319 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
   5320 									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
   5321 
   5322 				break;
   5323 			}
   5324 
   5325 			case DRAW_CALL_INDEXED_MULTI:
   5326 			{
   5327 				m_gl.multiDrawElements(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT, m_multidrawcall_index,
   5328 									   m_multidrawcall_drawcount);
   5329 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElements() call failed");
   5330 
   5331 				draw_call_count				   = m_multidrawcall_drawcount;
   5332 				draw_call_first_instance_id[0] = 0;
   5333 				draw_call_first_instance_id[1] = 0;
   5334 				draw_call_first_vertex_id[0] =
   5335 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
   5336 								 sizeof(unsigned int)];
   5337 				draw_call_first_vertex_id[1] =
   5338 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
   5339 								 sizeof(unsigned int)];
   5340 				draw_call_is_vertex_id_ascending = false;
   5341 				draw_call_n_instances[0]		 = 1;
   5342 				draw_call_n_instances[1]		 = 1;
   5343 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
   5344 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
   5345 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
   5346 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
   5347 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
   5348 									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
   5349 
   5350 				break;
   5351 			}
   5352 
   5353 			case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX:
   5354 			{
   5355 				m_gl.multiDrawElementsBaseVertex(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT,
   5356 												 m_multidrawcall_index, m_multidrawcall_drawcount,
   5357 												 m_multidrawcall_basevertex);
   5358 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsBaseVertex() call failed.");
   5359 
   5360 				draw_call_count				   = m_multidrawcall_drawcount;
   5361 				draw_call_first_instance_id[0] = 0;
   5362 				draw_call_first_instance_id[1] = 0;
   5363 				draw_call_first_vertex_id[0] =
   5364 					m_multidrawcall_basevertex[0] +
   5365 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
   5366 								 sizeof(unsigned int)];
   5367 				draw_call_first_vertex_id[1] =
   5368 					m_multidrawcall_basevertex[1] +
   5369 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
   5370 								 sizeof(unsigned int)];
   5371 				draw_call_is_vertex_id_ascending = false;
   5372 				draw_call_n_instances[0]		 = 1;
   5373 				draw_call_n_instances[1]		 = 1;
   5374 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
   5375 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
   5376 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
   5377 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
   5378 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
   5379 									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
   5380 
   5381 				break;
   5382 			}
   5383 
   5384 			case DRAW_CALL_INSTANCED_INDEXED:
   5385 			{
   5386 				m_gl.drawElementsInstanced(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
   5387 										   (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
   5388 										   m_n_instances_to_test);
   5389 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstanced() call failed.");
   5390 
   5391 				draw_call_count					 = 1;
   5392 				draw_call_first_instance_id[0]   = 0;
   5393 				draw_call_first_vertex_id[0]	 = m_index_data[0];
   5394 				draw_call_is_vertex_id_ascending = false;
   5395 				draw_call_n_instances[0]		 = m_n_instances_to_test;
   5396 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
   5397 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
   5398 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5399 
   5400 				break;
   5401 			}
   5402 
   5403 			case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX:
   5404 			{
   5405 				m_gl.drawElementsInstancedBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
   5406 													 (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
   5407 													 m_n_instances_to_test, m_draw_call_baseVertex);
   5408 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertex() call failed.");
   5409 
   5410 				draw_call_count					 = 1;
   5411 				draw_call_first_instance_id[0]   = 0;
   5412 				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_index_data[0];
   5413 				draw_call_is_vertex_id_ascending = false;
   5414 				draw_call_n_instances[0]		 = m_n_instances_to_test;
   5415 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
   5416 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
   5417 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5418 
   5419 				break;
   5420 			}
   5421 
   5422 			case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE:
   5423 			{
   5424 				m_gl.drawElementsInstancedBaseVertexBaseInstance(
   5425 					GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
   5426 					(const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset, m_n_instances_to_test,
   5427 					m_draw_call_baseVertex, m_draw_call_baseInstance);
   5428 
   5429 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertexBaseInstance() call failed.");
   5430 
   5431 				draw_call_count					 = 1;
   5432 				draw_call_first_instance_id[0]   = 0;
   5433 				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_index_data[0];
   5434 				draw_call_is_vertex_id_ascending = false;
   5435 				draw_call_n_instances[0]		 = m_n_instances_to_test;
   5436 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
   5437 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
   5438 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5439 
   5440 				break;
   5441 			}
   5442 
   5443 			case DRAW_CALL_REGULAR:
   5444 			{
   5445 				m_gl.drawArrays(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance);
   5446 
   5447 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed");
   5448 
   5449 				draw_call_count					 = 1;
   5450 				draw_call_first_instance_id[0]   = 0;
   5451 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
   5452 				draw_call_is_vertex_id_ascending = true;
   5453 				draw_call_n_instances[0]		 = 1;
   5454 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
   5455 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
   5456 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5457 
   5458 				break;
   5459 			}
   5460 
   5461 			case DRAW_CALL_REGULAR_INDIRECT:
   5462 			{
   5463 				m_gl.drawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_indirect_arg_offset);
   5464 
   5465 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysIndirect() call failed.");
   5466 
   5467 				draw_call_count					 = 1;
   5468 				draw_call_first_instance_id[0]   = 0;
   5469 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
   5470 				draw_call_is_vertex_id_ascending = true;
   5471 				draw_call_n_instances[0]		 = m_n_instances_to_test;
   5472 				draw_call_n_vertices[0]			 = m_multidrawcall_count[1];
   5473 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
   5474 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5475 
   5476 				break;
   5477 			}
   5478 
   5479 			case DRAW_CALL_REGULAR_INDIRECT_MULTI:
   5480 			{
   5481 				m_gl.multiDrawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_mdi_arg_offset,
   5482 											 m_multidrawcall_drawcount, 0); /* stride */
   5483 
   5484 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArraysIndirect() call failed.");
   5485 
   5486 				draw_call_count					 = 2;
   5487 				draw_call_first_instance_id[0]   = 0;
   5488 				draw_call_first_instance_id[1]   = 0;
   5489 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
   5490 				draw_call_first_vertex_id[1]	 = m_draw_call_first;
   5491 				draw_call_is_vertex_id_ascending = true;
   5492 				draw_call_n_instances[0]		 = 1;
   5493 				draw_call_n_instances[1]		 = m_n_instances_to_test;
   5494 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
   5495 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
   5496 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
   5497 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * draw_call_n_vertices[1];
   5498 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
   5499 									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
   5500 
   5501 				break;
   5502 			}
   5503 
   5504 			case DRAW_CALL_REGULAR_INSTANCED:
   5505 			{
   5506 				m_gl.drawArraysInstanced(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance,
   5507 										 m_n_instances_to_test);
   5508 
   5509 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed.");
   5510 
   5511 				draw_call_count					 = 1;
   5512 				draw_call_first_instance_id[0]   = 0;
   5513 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
   5514 				draw_call_is_vertex_id_ascending = true;
   5515 				draw_call_n_instances[0]		 = m_n_instances_to_test;
   5516 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
   5517 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
   5518 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5519 
   5520 				break;
   5521 			}
   5522 
   5523 			case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE:
   5524 			{
   5525 				m_gl.drawArraysInstancedBaseInstance(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance,
   5526 													 m_n_instances_to_test, m_draw_call_baseInstance);
   5527 
   5528 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstancedBaseInstance() call failed.");
   5529 
   5530 				draw_call_count					 = 1;
   5531 				draw_call_first_instance_id[0]   = 0;
   5532 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
   5533 				draw_call_is_vertex_id_ascending = true;
   5534 				draw_call_n_instances[0]		 = m_n_instances_to_test;
   5535 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
   5536 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
   5537 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
   5538 
   5539 				break;
   5540 			}
   5541 
   5542 			case DRAW_CALL_REGULAR_MULTI:
   5543 			{
   5544 				m_gl.multiDrawArrays(GL_POINTS, m_multidrawcall_first, m_multidrawcall_count,
   5545 									 m_multidrawcall_drawcount);
   5546 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArrays() call failed.");
   5547 
   5548 				draw_call_count					 = m_multidrawcall_drawcount;
   5549 				draw_call_first_instance_id[0]   = 0;
   5550 				draw_call_first_instance_id[1]   = 0;
   5551 				draw_call_first_vertex_id[0]	 = m_multidrawcall_first[0];
   5552 				draw_call_first_vertex_id[1]	 = m_multidrawcall_first[1];
   5553 				draw_call_is_vertex_id_ascending = true;
   5554 				draw_call_n_instances[0]		 = 1;
   5555 				draw_call_n_instances[1]		 = 1;
   5556 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
   5557 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
   5558 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
   5559 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
   5560 				n_result_bytes_total			 = n_result_bytes_per_instance[0] + n_result_bytes_per_instance[1];
   5561 
   5562 				break;
   5563 			}
   5564 
   5565 			default:
   5566 			{
   5567 				TCU_FAIL("Unrecognized draw call type");
   5568 			}
   5569 			} /* switch (draw_call_type) */
   5570 
   5571 			DE_ASSERT(n_result_bytes_total <= m_result_bo_size);
   5572 
   5573 			m_gl.endTransformFeedback();
   5574 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed.");
   5575 
   5576 			/* Retrieve the captured data */
   5577 			glw::GLuint  mappable_bo_id			  = m_helper_bo;
   5578 			unsigned int mappable_bo_start_offset = 0;
   5579 
   5580 			/* We cannot map the result BO storage directly into process space, since
   5581 			 * it's a sparse buffer. Copy the generated data to a helper BO and map
   5582 			 * that BO instead. */
   5583 			m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_result_bo);
   5584 			m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
   5585 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   5586 
   5587 			if (is_ia_iteration)
   5588 			{
   5589 				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   5590 									   0,											 /* writeOffset */
   5591 									   n_result_bytes_total);
   5592 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   5593 			}
   5594 			else
   5595 			{
   5596 				DE_ASSERT((n_result_bytes_total % 2) == 0);
   5597 
   5598 				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   5599 									   0,											 /* writeOffset */
   5600 									   n_result_bytes_total / 2);
   5601 				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
   5602 									   m_result_bo_size / 2,	  /* readOffset  */
   5603 									   m_result_bo_size / 2,	  /* writeOffset */
   5604 									   n_result_bytes_total / 2); /* size        */
   5605 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   5606 			}
   5607 
   5608 			m_gl.bindBuffer(GL_ARRAY_BUFFER, mappable_bo_id);
   5609 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   5610 
   5611 			result_ptr = (unsigned int*)m_gl.mapBufferRange(GL_ARRAY_BUFFER, mappable_bo_start_offset, m_result_bo_size,
   5612 															GL_MAP_READ_BIT);
   5613 
   5614 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
   5615 
   5616 			/* Verify the generated output */
   5617 			bool		continue_checking		  = true;
   5618 			glw::GLuint result_instance_id_stride = 0;
   5619 			glw::GLuint result_vertex_id_stride   = 0;
   5620 
   5621 			if (is_ia_iteration)
   5622 			{
   5623 				result_instance_id_stride = 2;
   5624 				result_vertex_id_stride   = 2;
   5625 			}
   5626 			else
   5627 			{
   5628 				result_instance_id_stride = 1;
   5629 				result_vertex_id_stride   = 1;
   5630 			}
   5631 
   5632 			/* For all draw calls.. */
   5633 			for (int n_draw_call = 0; n_draw_call < draw_call_count && continue_checking; ++n_draw_call)
   5634 			{
   5635 				/* ..and resulting draw call instances.. */
   5636 				for (int n_instance = 0; n_instance < draw_call_n_instances[n_draw_call] && continue_checking;
   5637 					 ++n_instance)
   5638 				{
   5639 					DE_ASSERT((n_result_bytes_per_instance[n_draw_call] % sizeof(unsigned int)) == 0);
   5640 
   5641 					/* Determine where the result TF data start from */
   5642 					const glw::GLuint expected_instance_id = draw_call_first_instance_id[n_draw_call] + n_instance;
   5643 					glw::GLuint*	  result_instance_id_traveller_ptr = DE_NULL;
   5644 					glw::GLuint*	  result_vertex_id_traveller_ptr   = DE_NULL;
   5645 
   5646 					if (is_ia_iteration)
   5647 					{
   5648 						result_instance_id_traveller_ptr = result_ptr;
   5649 
   5650 						for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call)
   5651 						{
   5652 							result_instance_id_traveller_ptr += draw_call_n_instances[n_prev_draw_call] *
   5653 																n_result_bytes_per_instance[n_prev_draw_call] /
   5654 																sizeof(unsigned int);
   5655 						}
   5656 
   5657 						result_instance_id_traveller_ptr +=
   5658 							n_instance * n_result_bytes_per_instance[n_draw_call] / sizeof(unsigned int);
   5659 						result_vertex_id_traveller_ptr = result_instance_id_traveller_ptr + 1;
   5660 					} /* if (is_ia_iteration) */
   5661 					else
   5662 					{
   5663 						DE_ASSERT((m_result_bo_size % 2) == 0);
   5664 
   5665 						result_instance_id_traveller_ptr = result_ptr;
   5666 
   5667 						for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call)
   5668 						{
   5669 							result_instance_id_traveller_ptr +=
   5670 								draw_call_n_instances[n_prev_draw_call] *
   5671 								n_result_bytes_per_instance[n_prev_draw_call] /
   5672 								2 / /* instance id..instance id data | vertex id..vertex id data */
   5673 								sizeof(unsigned int);
   5674 						}
   5675 
   5676 						result_instance_id_traveller_ptr +=
   5677 							n_instance * n_result_bytes_per_instance[n_draw_call] / 2 / sizeof(unsigned int);
   5678 						result_vertex_id_traveller_ptr =
   5679 							result_instance_id_traveller_ptr + (m_result_bo_size / 2) / sizeof(unsigned int);
   5680 					}
   5681 
   5682 					/* Start checking the generated output */
   5683 					for (int n_point = 0; n_point < draw_call_n_vertices[n_draw_call] && continue_checking; ++n_point)
   5684 					{
   5685 						glw::GLuint expected_vertex_id	= 1;
   5686 						glw::GLuint retrieved_instance_id = 2;
   5687 						glw::GLuint retrieved_vertex_id   = 3;
   5688 
   5689 						if (draw_call_is_vertex_id_ascending)
   5690 						{
   5691 							expected_vertex_id = draw_call_first_vertex_id[n_draw_call] + n_point;
   5692 						} /* if (draw_call_is_vertex_id_ascending) */
   5693 						else
   5694 						{
   5695 							if (draw_call_first_vertex_id[n_draw_call] >= n_point)
   5696 							{
   5697 								expected_vertex_id = draw_call_first_vertex_id[n_draw_call] - n_point;
   5698 							}
   5699 							else
   5700 							{
   5701 								expected_vertex_id = 0;
   5702 							}
   5703 						}
   5704 
   5705 						/* Only perform the check if the offsets refer to pages with physical backing.
   5706 						 *
   5707 						 * Note that, on platforms, whose page size % 4 != 0, the values can land partially in the no-man's land,
   5708 						 * and partially in the safe zone. In such cases, skip the verification. */
   5709 						const bool result_instance_id_page_has_physical_backing =
   5710 							(((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) ==
   5711 							 0) &&
   5712 							((((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) -
   5713 								1) /
   5714 							   m_page_size) %
   5715 							  2) == 0);
   5716 						const bool result_vertex_id_page_has_physical_backing =
   5717 							(((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) == 0) &&
   5718 							((((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) -
   5719 								1) /
   5720 							   m_page_size) %
   5721 							  2) == 0);
   5722 
   5723 						retrieved_instance_id = *result_instance_id_traveller_ptr;
   5724 						result_instance_id_traveller_ptr += result_instance_id_stride;
   5725 
   5726 						retrieved_vertex_id = *result_vertex_id_traveller_ptr;
   5727 						result_vertex_id_traveller_ptr += result_vertex_id_stride;
   5728 
   5729 						if ((result_instance_id_page_has_physical_backing &&
   5730 							 retrieved_instance_id != expected_instance_id) ||
   5731 							(result_vertex_id_page_has_physical_backing && retrieved_vertex_id != expected_vertex_id))
   5732 						{
   5733 							m_testCtx.getLog()
   5734 								<< tcu::TestLog::Message << "For "
   5735 															"["
   5736 								<< getName() << "]"
   5737 												", sparse BO flags "
   5738 												"["
   5739 								<< SparseBufferTestUtilities::getSparseBOFlagsString(sparse_bo_storage_flags)
   5740 								<< "]"
   5741 								   ", draw call type "
   5742 								<< getDrawCallTypeString(draw_call_type) << " at index "
   5743 																			"["
   5744 								<< n_draw_call << " / " << (draw_call_count - 1) << "]"
   5745 																					", TF mode "
   5746 																					"["
   5747 								<< ((is_ia_iteration) ? "interleaved attribs" : "separate attribs") << "]"
   5748 								<< ", instance "
   5749 								   "["
   5750 								<< n_instance << " / " << (draw_call_n_instances[n_draw_call] - 1) << "]"
   5751 								<< ", point at index "
   5752 								   "["
   5753 								<< n_point << " / " << (draw_call_n_vertices[n_draw_call] - 1) << "]"
   5754 								<< ", VS-level gl_VertexID was equal to "
   5755 								   "["
   5756 								<< retrieved_vertex_id << "]"
   5757 														  " and gl_InstanceID was set to "
   5758 														  "["
   5759 								<< retrieved_instance_id << "]"
   5760 															", whereas gl_VertexID of value "
   5761 															"["
   5762 								<< expected_vertex_id << "]"
   5763 														 " and gl_InstanceID of value "
   5764 														 "["
   5765 								<< expected_instance_id << "]"
   5766 														   " were anticipated."
   5767 								<< tcu::TestLog::EndMessage;
   5768 
   5769 							continue_checking = false;
   5770 							result			  = false;
   5771 
   5772 							break;
   5773 						} /* if (reported gl_InstanceID / gl_VertexID values are wrong) */
   5774 					}	 /* for (all drawn points) */
   5775 				}		  /* for (all instances) */
   5776 
   5777 				/* Release memory pages we have allocated for the transform feed-back.
   5778 				 *
   5779 				 * NOTE: For some iterations, this call will attempt to de-commit pages which
   5780 				 *       have not been assigned physical backing. This is a valid behavior,
   5781 				 *       as per spec.
   5782 				 */
   5783 				m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0,	 /* offset */
   5784 											 m_result_bo_size_rounded, GL_FALSE); /* commit */
   5785 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   5786 			} /* for (all draw call) */
   5787 
   5788 			m_gl.unmapBuffer(GL_ARRAY_BUFFER);
   5789 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   5790 		} /* for (all draw call types) */
   5791 	}	 /* for (both TF modes) */
   5792 
   5793 	return result;
   5794 }
   5795 
   5796 /** Converts the internal enum to a null-terminated text string.
   5797  *
   5798  *  @param draw_call Draw call type to return a string for.
   5799  *
   5800  *  @return The requested string or "[?!]", if the enum was not recognized.
   5801  **/
   5802 const char* TransformFeedbackBufferStorageTestCase::getDrawCallTypeString(_draw_call draw_call)
   5803 {
   5804 	const char* result = "[?!]";
   5805 
   5806 	switch (draw_call)
   5807 	{
   5808 	case DRAW_CALL_INDEXED:
   5809 		result = "glDrawElements()";
   5810 		break;
   5811 	case DRAW_CALL_INDEXED_BASE_VERTEX:
   5812 		result = "glDrawElementsBaseVertex()";
   5813 		break;
   5814 	case DRAW_CALL_INDEXED_INDIRECT:
   5815 		result = "glDrawElementsIndirect()";
   5816 		break;
   5817 	case DRAW_CALL_INDEXED_INDIRECT_MULTI:
   5818 		result = "glMultiDrawElementIndirect()";
   5819 		break;
   5820 	case DRAW_CALL_INDEXED_MULTI:
   5821 		result = "glMultiDrawElements()";
   5822 		break;
   5823 	case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX:
   5824 		result = "glMultiDrawElementsBaseVertex()";
   5825 		break;
   5826 	case DRAW_CALL_INSTANCED_INDEXED:
   5827 		result = "glDrawElementsInstanced()";
   5828 		break;
   5829 	case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX:
   5830 		result = "glDrawElementsInstancedBaseVertex()";
   5831 		break;
   5832 	case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE:
   5833 		result = "glDrawElementsInstancedBaseVertexBaseInstance()";
   5834 		break;
   5835 	case DRAW_CALL_REGULAR:
   5836 		result = "glDrawArrays()";
   5837 		break;
   5838 	case DRAW_CALL_REGULAR_INDIRECT:
   5839 		result = "glDrawArraysIndirect()";
   5840 		break;
   5841 	case DRAW_CALL_REGULAR_INDIRECT_MULTI:
   5842 		result = "glMultiDrawArraysIndirect()";
   5843 		break;
   5844 	case DRAW_CALL_REGULAR_INSTANCED:
   5845 		result = "glDrawArraysInstanced()";
   5846 		break;
   5847 	case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE:
   5848 		result = "glDrawArraysInstancedBaseInstance()";
   5849 		break;
   5850 	case DRAW_CALL_REGULAR_MULTI:
   5851 		result = "glMultiDrawArrays()";
   5852 		break;
   5853 
   5854 	default:
   5855 		break;
   5856 	} /* switch (draw_call) */
   5857 
   5858 	return result;
   5859 }
   5860 
   5861 /** Initializes test data buffer, and then sets up:
   5862  *
   5863  *  - an immutable buffer object (id stored in m_data_bo), to which the test data
   5864  *    is copied.
   5865  *  - a mappable immutable buffer object (id stored in m_helper_bo)
   5866  **/
   5867 void TransformFeedbackBufferStorageTestCase::initDataBO()
   5868 {
   5869 	initTestData();
   5870 
   5871 	/* Initialize data BO (the BO which holds index + indirect draw call args */
   5872 	DE_ASSERT(m_data_bo == 0);
   5873 
   5874 	m_gl.genBuffers(1, &m_data_bo);
   5875 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   5876 
   5877 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_data_bo);
   5878 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   5879 
   5880 	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_data_bo_size, DE_NULL, GL_DYNAMIC_STORAGE_BIT);
   5881 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   5882 
   5883 	m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_indexed_indirect_arg_offset, m_indirect_arg_data_size,
   5884 					   m_indirect_arg_data);
   5885 	m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_index_data_offset, m_index_data_size, m_index_data);
   5886 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call(s) failed.");
   5887 
   5888 	/* Generate & bind a helper BO we need to copy the data to from the sparse BO
   5889 	 * if direct mapping is not possible.
   5890 	 */
   5891 	DE_ASSERT(m_result_bo_size != 0);
   5892 	DE_ASSERT(m_result_bo == 0);
   5893 	DE_ASSERT(m_helper_bo == 0);
   5894 
   5895 	m_gl.genBuffers(1, &m_helper_bo);
   5896 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   5897 
   5898 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
   5899 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   5900 
   5901 	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_result_bo_size, DE_NULL, /* data */
   5902 					   GL_MAP_READ_BIT);
   5903 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   5904 }
   5905 
   5906 /** Initializes GL objects used across all test case iterations.
   5907  *
   5908  *  Called once during BufferStorage test run-time.
   5909  */
   5910 bool TransformFeedbackBufferStorageTestCase::initTestCaseGlobal()
   5911 {
   5912 	bool result = true;
   5913 
   5914 	/* Initialize test program object */
   5915 	static const char*		  tf_varyings[] = { "instance_id", "vertex_id" };
   5916 	static const unsigned int n_tf_varyings = sizeof(tf_varyings) / sizeof(tf_varyings[0]);
   5917 	static const char*		  vs_body		= "#version 420 core\n"
   5918 								 "\n"
   5919 								 "out uint instance_id;\n"
   5920 								 "out uint vertex_id;\n"
   5921 								 "\n"
   5922 								 "void main()\n"
   5923 								 "{\n"
   5924 								 "    instance_id = gl_InstanceID;\n"
   5925 								 "    vertex_id   = gl_VertexID;\n"
   5926 								 "}\n";
   5927 
   5928 	m_po_ia = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
   5929 													   0,			  /* n_fs_body_parts */
   5930 													   &vs_body, 1,   /* n_vs_body_parts */
   5931 													   DE_NULL,		  /* attribute_names */
   5932 													   DE_NULL,		  /* attribute_locations */
   5933 													   0,			  /* n_attribute_properties */
   5934 													   tf_varyings, n_tf_varyings, GL_INTERLEAVED_ATTRIBS);
   5935 
   5936 	m_po_sa = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
   5937 													   0,			  /* n_fs_body_parts */
   5938 													   &vs_body, 1,   /* n_vs_body_parts */
   5939 													   DE_NULL,		  /* attribute_names */
   5940 													   DE_NULL,		  /* attribute_locations */
   5941 													   0,			  /* n_attribute_properties */
   5942 													   tf_varyings, n_tf_varyings, GL_SEPARATE_ATTRIBS);
   5943 
   5944 	if (m_po_ia == 0 || m_po_sa == 0)
   5945 	{
   5946 		result = false;
   5947 
   5948 		goto end;
   5949 	}
   5950 
   5951 	/* Generate & bind a VAO */
   5952 	m_gl.genVertexArrays(1, &m_vao);
   5953 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
   5954 
   5955 	m_gl.bindVertexArray(m_vao);
   5956 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
   5957 
   5958 	initDataBO();
   5959 
   5960 end:
   5961 	return result;
   5962 }
   5963 
   5964 /** Initializes GL objects which are needed for a single test case iteration.
   5965  *
   5966  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   5967  *  to release these objects.
   5968  **/
   5969 bool TransformFeedbackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   5970 {
   5971 	bool result = true;
   5972 
   5973 	/* Initialize buffer objects used by the test case */
   5974 	m_result_bo = sparse_bo;
   5975 
   5976 	/* Sanity check */
   5977 	DE_ASSERT(m_data_bo != 0);
   5978 
   5979 	return result;
   5980 }
   5981 
   5982 /** Sets up client-side data arrays, later uploaded to the test buffer object, used as a source for:
   5983  *
   5984  *  - index data
   5985  *  - indirect draw call arguments
   5986  *  - multi draw call arguments
   5987  **/
   5988 void TransformFeedbackBufferStorageTestCase::initTestData()
   5989 {
   5990 	/* We need the result data to span across at least m_min_memory_page_span memory pages.
   5991 	 * Each vertex outputs 2 * sizeof(int) = 8 bytes of data.
   5992 	 *
   5993 	 * For simplicity, we assume the number of bytes we calculate here is per instance. */
   5994 	m_n_vertices_per_instance = static_cast<unsigned int>((m_page_size * m_min_memory_page_span / (sizeof(int) * 2)));
   5995 
   5996 	/* Let:
   5997 	 *
   5998 	 *     index_data_size       = (n of vertices per a single instance) * sizeof(unsigned int)
   5999 	 *     indexed_indirect_size = sizeof(glDrawElementsIndirect()      indirect arguments)
   6000 	 *     indexed_mdi_size      = sizeof(glMultiDrawElementsIndirect() indirect arguments) * 2 (single instance & multiple instances case)
   6001 	 *     regular_indirect_size = sizeof(glDrawArraysIndirect()        indirect arguments)
   6002 	 *     regular_mdi_size      = sizeof(glMultiDrawArraysIndirect()   indirect arguments) * 2 (single instance & multiple instances case)
   6003 	 *
   6004 	 *
   6005 	 * The layout we will use for the data buffer is:
   6006 	 *
   6007 	 * [indexed indirect arg data // Size: indexed_indirect_size bytes]
   6008 	 * [indexed MDI arg data      // Size: indexed_mdi_size      bytes]
   6009 	 * [regular indirect arg data // Size: regular_indirect_size bytes]
   6010 	 * [regular MDI arg data      // Size: regular_mdi_size      bytes]
   6011 	 * [index data                // Size: index_data_size       bytes]
   6012 	 */
   6013 	const unsigned int indexed_indirect_size = sizeof(unsigned int) * 5 /* as per GL spec */;
   6014 	const unsigned int indexed_mdi_size		 = sizeof(unsigned int) * 5 /* as per GL spec */ * 2; /* draw calls */
   6015 	const unsigned int regular_indirect_size = sizeof(unsigned int) * 4;						  /* as per GL spec */
   6016 	const unsigned int regular_mdi_size		 = sizeof(unsigned int) * 4 /* as per GL spec */ * 2; /* draw calls */
   6017 
   6018 	m_data_bo_indexed_indirect_arg_offset = 0;
   6019 	m_data_bo_indexed_mdi_arg_offset	  = m_data_bo_indexed_indirect_arg_offset + indexed_indirect_size;
   6020 	m_data_bo_regular_indirect_arg_offset = m_data_bo_indexed_mdi_arg_offset + indexed_mdi_size;
   6021 	m_data_bo_regular_mdi_arg_offset	  = m_data_bo_regular_indirect_arg_offset + regular_indirect_size;
   6022 	m_data_bo_index_data_offset			  = m_data_bo_regular_mdi_arg_offset + regular_mdi_size;
   6023 
   6024 	/* Form the index data */
   6025 	DE_ASSERT(m_index_data == DE_NULL);
   6026 	DE_ASSERT(m_draw_call_firstIndex == sizeof(unsigned int));
   6027 
   6028 	m_index_data_size = static_cast<glw::GLuint>(
   6029 		(1 /* extra index, as per m_draw_call_firstIndex */ + m_n_vertices_per_instance) * sizeof(unsigned int));
   6030 	m_index_data = (unsigned int*)new unsigned char[m_index_data_size];
   6031 
   6032 	for (unsigned int n_index = 0; n_index < m_n_vertices_per_instance + 1; ++n_index)
   6033 	{
   6034 		m_index_data[n_index] = m_n_vertices_per_instance - n_index;
   6035 	} /* for (all available indices) */
   6036 
   6037 	/* Set multi draw-call arguments */
   6038 	m_multidrawcall_basevertex[0] = m_draw_call_baseVertex;
   6039 	m_multidrawcall_basevertex[1] = 257;
   6040 	m_multidrawcall_count[0]	  = m_n_vertices_per_instance;
   6041 	m_multidrawcall_count[1]	  = m_n_vertices_per_instance - 16;
   6042 	m_multidrawcall_drawcount	 = 2;
   6043 	m_multidrawcall_first[0]	  = 0;
   6044 	m_multidrawcall_first[1]	  = m_draw_call_first;
   6045 	m_multidrawcall_index[0]	  = (glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset;
   6046 	m_multidrawcall_index[1]	  = (glw::GLvoid*)(intptr_t)(m_data_bo_index_data_offset + m_draw_call_firstIndex);
   6047 	m_multidrawcall_primcount	 = m_n_instances_to_test;
   6048 
   6049 	/* Form the indirect data */
   6050 	DE_ASSERT(m_indirect_arg_data == DE_NULL);
   6051 
   6052 	m_indirect_arg_data_size = m_data_bo_index_data_offset - m_data_bo_indexed_indirect_arg_offset;
   6053 	m_indirect_arg_data		 = (unsigned int*)new unsigned char[m_indirect_arg_data_size];
   6054 
   6055 	unsigned int* indirect_arg_data_traveller_ptr = m_indirect_arg_data;
   6056 
   6057 	/* 1. Indexed indirect arg data */
   6058 	DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[1]) % sizeof(unsigned int)) == 0);
   6059 
   6060 	*indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */
   6061 	indirect_arg_data_traveller_ptr++;
   6062 
   6063 	*indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */
   6064 	indirect_arg_data_traveller_ptr++;
   6065 
   6066 	*indirect_arg_data_traveller_ptr = static_cast<unsigned int>((unsigned int)(intptr_t)(m_multidrawcall_index[1]) /
   6067 																 sizeof(unsigned int)); /* firstIndex */
   6068 	indirect_arg_data_traveller_ptr++;
   6069 
   6070 	*indirect_arg_data_traveller_ptr = m_draw_call_baseVertex; /* baseVertex */
   6071 	indirect_arg_data_traveller_ptr++;
   6072 
   6073 	*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
   6074 	indirect_arg_data_traveller_ptr++;
   6075 
   6076 	/* 2. Indexed MDI arg data */
   6077 	for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call)
   6078 	{
   6079 		DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) % sizeof(unsigned int)) == 0);
   6080 
   6081 		*indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */
   6082 		indirect_arg_data_traveller_ptr++;
   6083 
   6084 		*indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* primCount */
   6085 		indirect_arg_data_traveller_ptr++;
   6086 
   6087 		*indirect_arg_data_traveller_ptr = static_cast<unsigned int>(
   6088 			(unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) / sizeof(unsigned int)); /* firstIndex */
   6089 		indirect_arg_data_traveller_ptr++;
   6090 
   6091 		*indirect_arg_data_traveller_ptr = m_draw_call_baseVertex;
   6092 		indirect_arg_data_traveller_ptr++;
   6093 
   6094 		*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance;
   6095 		indirect_arg_data_traveller_ptr++;
   6096 	} /* for (both single-instanced and multi-instanced cases) */
   6097 
   6098 	/* 3. Regular indirect arg data */
   6099 	*indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */
   6100 	indirect_arg_data_traveller_ptr++;
   6101 
   6102 	*indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */
   6103 	indirect_arg_data_traveller_ptr++;
   6104 
   6105 	*indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */
   6106 	indirect_arg_data_traveller_ptr++;
   6107 
   6108 	*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
   6109 	indirect_arg_data_traveller_ptr++;
   6110 
   6111 	/* 4. Regular MDI arg data */
   6112 	for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call)
   6113 	{
   6114 		*indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */
   6115 		indirect_arg_data_traveller_ptr++;
   6116 
   6117 		*indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* instanceCount */
   6118 		indirect_arg_data_traveller_ptr++;
   6119 
   6120 		*indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */
   6121 		indirect_arg_data_traveller_ptr++;
   6122 
   6123 		*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
   6124 		indirect_arg_data_traveller_ptr++;
   6125 	} /* for (both single-instanced and multi-instanced cases) */
   6126 
   6127 	/* Store the number of bytes we will need to allocate for the data BO */
   6128 	m_data_bo_size = m_index_data_size + m_indirect_arg_data_size;
   6129 
   6130 	/* Determine the number of bytes we will need to have at hand to hold all the captured TF varyings.
   6131 	 * The equation below takes into account the heaviest draw call the test will ever issue.
   6132 	 */
   6133 	m_result_bo_size =
   6134 		static_cast<glw::GLuint>(sizeof(unsigned int) * 2 /* TF varyings per vertex */ *
   6135 								 (m_multidrawcall_count[0] + m_multidrawcall_count[1]) * m_multidrawcall_primcount);
   6136 	m_result_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_result_bo_size, m_page_size);
   6137 
   6138 	/* Sanity checks */
   6139 	DE_ASSERT(m_min_memory_page_span > 0);
   6140 	DE_ASSERT(m_page_size > 0);
   6141 	DE_ASSERT(m_result_bo_size >= (m_min_memory_page_span * m_page_size));
   6142 }
   6143 
   6144 /** Constructor.
   6145  *
   6146  *  @param gl                         GL entry-points container
   6147  *  @param testContext                CTS test context
   6148  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
   6149  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
   6150  */
   6151 UniformBufferStorageTestCase::UniformBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
   6152 														   glw::GLint page_size)
   6153 	: m_gl(gl)
   6154 	, m_gl_uniform_buffer_offset_alignment_value(0)
   6155 	, m_helper_bo(0)
   6156 	, m_n_pages_to_use(4)
   6157 	, m_n_ubo_uints(0)
   6158 	, m_page_size(page_size)
   6159 	, m_po(0)
   6160 	, m_sparse_bo(0)
   6161 	, m_sparse_bo_data_size(0)
   6162 	, m_sparse_bo_data_start_offset(0)
   6163 	, m_sparse_bo_size(0)
   6164 	, m_sparse_bo_size_rounded(0)
   6165 	, m_testCtx(testContext)
   6166 	, m_tf_bo(0)
   6167 	, m_ubo_data(DE_NULL)
   6168 	, m_vao(0)
   6169 {
   6170 	if ((m_n_pages_to_use % 2) != 0)
   6171 	{
   6172 		DE_ASSERT(DE_FALSE);
   6173 	}
   6174 }
   6175 
   6176 /** Releases all GL objects used across all test case iterations.
   6177  *
   6178  *  Called once during BufferStorage test run-time.
   6179  */
   6180 void UniformBufferStorageTestCase::deinitTestCaseGlobal()
   6181 {
   6182 	if (m_helper_bo != 0)
   6183 	{
   6184 		m_gl.deleteBuffers(1, &m_helper_bo);
   6185 
   6186 		m_helper_bo = 0;
   6187 	}
   6188 
   6189 	if (m_po != 0)
   6190 	{
   6191 		m_gl.deleteProgram(m_po);
   6192 
   6193 		m_po = 0;
   6194 	}
   6195 
   6196 	if (m_tf_bo != 0)
   6197 	{
   6198 		m_gl.deleteBuffers(1, &m_tf_bo);
   6199 
   6200 		m_tf_bo = 0;
   6201 	}
   6202 
   6203 	if (m_ubo_data != DE_NULL)
   6204 	{
   6205 		delete[] m_ubo_data;
   6206 
   6207 		m_ubo_data = DE_NULL;
   6208 	}
   6209 
   6210 	if (m_vao != 0)
   6211 	{
   6212 		m_gl.deleteVertexArrays(1, &m_vao);
   6213 
   6214 		m_vao = 0;
   6215 	}
   6216 }
   6217 
   6218 /** Releases temporary GL objects, created specifically for one test case iteration. */
   6219 void UniformBufferStorageTestCase::deinitTestCaseIteration()
   6220 {
   6221 	if (m_sparse_bo != 0)
   6222 	{
   6223 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   6224 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   6225 
   6226 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
   6227 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   6228 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   6229 
   6230 		m_sparse_bo = 0;
   6231 	}
   6232 }
   6233 
   6234 /** Executes a single test iteration. The BufferStorage test will call this method
   6235  *  numerously during its life-time, testing various valid flag combinations applied
   6236  *  to the tested sparse buffer object at glBufferStorage() call time.
   6237  *
   6238  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
   6239  *                                 call to set up the sparse buffer's storage.
   6240  *
   6241  *  @return true if the test case executed correctly, false otherwise.
   6242  */
   6243 bool UniformBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
   6244 {
   6245 	(void)sparse_bo_storage_flags;
   6246 	bool result = true;
   6247 
   6248 	m_gl.bindBufferRange(GL_UNIFORM_BUFFER, 0, /* index */
   6249 						 m_sparse_bo, m_sparse_bo_data_start_offset, m_sparse_bo_data_size);
   6250 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
   6251 
   6252 	/* Run the test in three iterations:
   6253 	 *
   6254 	 * 1) Whole UBO storage is backed by physical backing.
   6255 	 * 2) Half the UBO storage is backed by physical backing.
   6256 	 * 3) None of the UBO storage is backed by physical backing.
   6257 	 */
   6258 	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
   6259 	{
   6260 		bool		 result_local			 = true;
   6261 		unsigned int ubo_commit_size		 = 0;
   6262 		unsigned int ubo_commit_start_offset = 0;
   6263 
   6264 		switch (n_iteration)
   6265 		{
   6266 		case 0:
   6267 		{
   6268 			ubo_commit_size			= m_sparse_bo_data_size;
   6269 			ubo_commit_start_offset = m_sparse_bo_data_start_offset;
   6270 
   6271 			break;
   6272 		}
   6273 
   6274 		case 1:
   6275 		{
   6276 			DE_ASSERT((m_sparse_bo_data_size % 2) == 0);
   6277 			DE_ASSERT((m_sparse_bo_data_size % m_page_size) == 0);
   6278 
   6279 			ubo_commit_size			= m_sparse_bo_data_size / 2;
   6280 			ubo_commit_start_offset = m_sparse_bo_data_start_offset;
   6281 
   6282 			break;
   6283 		}
   6284 
   6285 		case 2:
   6286 		{
   6287 			/* The default values do just fine */
   6288 
   6289 			break;
   6290 		}
   6291 
   6292 		default:
   6293 		{
   6294 			TCU_FAIL("Invalid iteration index");
   6295 		}
   6296 		} /* switch (n_iteration) */
   6297 
   6298 		m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, ubo_commit_start_offset, ubo_commit_size, GL_TRUE); /* commit */
   6299 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   6300 
   6301 		/* Copy the UBO data */
   6302 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
   6303 							   ubo_commit_start_offset, ubo_commit_size);
   6304 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
   6305 
   6306 		/* Issue the draw call to execute the test */
   6307 		m_gl.useProgram(m_po);
   6308 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
   6309 
   6310 		m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
   6311 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   6312 
   6313 		m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
   6314 							m_tf_bo);
   6315 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
   6316 
   6317 		m_gl.beginTransformFeedback(GL_POINTS);
   6318 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed.");
   6319 
   6320 		m_gl.drawArrays(GL_POINTS, 0, /* first */
   6321 						m_n_ubo_uints);
   6322 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
   6323 
   6324 		m_gl.endTransformFeedback();
   6325 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed.");
   6326 
   6327 		/* Retrieve the data, verify the output */
   6328 		const unsigned int* result_data_ptr =
   6329 			(const unsigned int*)m_gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
   6330 		unsigned int ubo_data_offset = m_sparse_bo_data_start_offset;
   6331 
   6332 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
   6333 
   6334 		for (unsigned int n_vertex = 0; n_vertex < m_n_ubo_uints && result_local;
   6335 			 ++n_vertex, ubo_data_offset = static_cast<unsigned int>(ubo_data_offset + 4 * sizeof(unsigned int)))
   6336 		{
   6337 			const bool is_ub_data_physically_backed = (ubo_data_offset >= ubo_commit_start_offset &&
   6338 													   ubo_data_offset < (ubo_commit_start_offset + ubo_commit_size)) ?
   6339 														  1 :
   6340 														  0;
   6341 			unsigned int	   expected_value  = -1;
   6342 			const unsigned int retrieved_value = result_data_ptr[n_vertex];
   6343 
   6344 			if (is_ub_data_physically_backed)
   6345 			{
   6346 				expected_value = 1;
   6347 			}
   6348 			else
   6349 			{
   6350 				/* Read ops applied against non-committed sparse buffers return an undefined value.
   6351 				 */
   6352 				continue;
   6353 			}
   6354 
   6355 			if (expected_value != retrieved_value)
   6356 			{
   6357 				m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value "
   6358 															   "("
   6359 								   << retrieved_value << ") "
   6360 														 "found at index "
   6361 														 "("
   6362 								   << n_vertex << ")"
   6363 												  ", instead of the expected value "
   6364 												  "("
   6365 								   << expected_value << ")"
   6366 														". Iteration index:"
   6367 														"("
   6368 								   << n_iteration << ")" << tcu::TestLog::EndMessage;
   6369 
   6370 				result_local = false;
   6371 			}
   6372 		}
   6373 
   6374 		result &= result_local;
   6375 
   6376 		/* Clean up in anticipation for the next iteration */
   6377 		static const unsigned char data_zero_r8 = 0;
   6378 
   6379 		m_gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
   6380 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
   6381 
   6382 		m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero_r8);
   6383 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
   6384 
   6385 		m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */
   6386 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
   6387 	} /* for (all three iterations) */
   6388 
   6389 	return result;
   6390 }
   6391 
   6392 /** Initializes GL objects used across all test case iterations.
   6393  *
   6394  *  Called once during BufferStorage test run-time.
   6395  */
   6396 bool UniformBufferStorageTestCase::initTestCaseGlobal()
   6397 {
   6398 	/* Cache GL constant values */
   6399 	glw::GLint gl_max_uniform_block_size_value = 0;
   6400 
   6401 	m_gl.getIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gl_max_uniform_block_size_value);
   6402 	m_gl.getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_gl_uniform_buffer_offset_alignment_value);
   6403 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call(s) failed.");
   6404 
   6405 	/* Determine the number of uints we can access at once from a single VS invocation */
   6406 	DE_ASSERT(gl_max_uniform_block_size_value >= 1);
   6407 
   6408 	/* Account for the fact that in std140 layout, array elements will be rounded up
   6409 	 * to the size of a vec4, i.e. 16 bytes. */
   6410 	m_n_ubo_uints = static_cast<unsigned int>(gl_max_uniform_block_size_value / (4 * sizeof(unsigned int)));
   6411 
   6412 	/* Prepare the test program */
   6413 	std::stringstream vs_body_define_sstream;
   6414 	std::string		  vs_body_define_string;
   6415 
   6416 	const char* tf_varying		 = "result";
   6417 	const char* vs_body_preamble = "#version 140\n"
   6418 								   "\n";
   6419 
   6420 	const char* vs_body_main = "\n"
   6421 							   "layout(std140) uniform data\n"
   6422 							   "{\n"
   6423 							   "    uint data_input[N_UBO_UINTS];"
   6424 							   "};\n"
   6425 							   "\n"
   6426 							   "out uint result;\n"
   6427 							   "\n"
   6428 							   "void main()\n"
   6429 							   "{\n"
   6430 							   "    result = (data_input[gl_VertexID] == uint(gl_VertexID) ) ? 1u : 0u;\n"
   6431 							   "}";
   6432 
   6433 	vs_body_define_sstream << "#define N_UBO_UINTS (" << m_n_ubo_uints << ")\n";
   6434 	vs_body_define_string = vs_body_define_sstream.str();
   6435 
   6436 	const char*		   vs_body_parts[] = { vs_body_preamble, vs_body_define_string.c_str(), vs_body_main };
   6437 	const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]);
   6438 
   6439 	m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL,							 /* fs_body_parts */
   6440 													0,										 /* n_fs_body_parts */
   6441 													vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names */
   6442 													DE_NULL,								 /* attribute_locations */
   6443 													0,				/* n_attribute_properties */
   6444 													&tf_varying, 1, /* n_tf_varyings */
   6445 													GL_INTERLEAVED_ATTRIBS);
   6446 
   6447 	if (m_po == 0)
   6448 	{
   6449 		TCU_FAIL("The test program failed to link");
   6450 	}
   6451 
   6452 	/* Determine the number of bytes the sparse buffer needs to be able to have
   6453 	 * a physical backing or.
   6454 	 *
   6455 	 * We will provide physical backing for twice the required size and then use
   6456 	 * a region in the centered of the allocated memory block.
   6457 	 *
   6458 	 * NOTE: We need to be able to use an offset which is aligned to both the page size,
   6459 	 *       and the UB offset alignment.
   6460 	 * */
   6461 	m_sparse_bo_data_size = static_cast<unsigned int>(sizeof(unsigned int) * m_page_size);
   6462 	m_sparse_bo_size	  = (m_page_size * m_gl_uniform_buffer_offset_alignment_value) * 2;
   6463 
   6464 	if (m_sparse_bo_size < m_sparse_bo_data_size * 2)
   6465 	{
   6466 		m_sparse_bo_size = m_sparse_bo_data_size * 2;
   6467 	}
   6468 
   6469 	m_sparse_bo_size_rounded	  = m_sparse_bo_size; /* rounded to the page size by default */
   6470 	m_sparse_bo_data_start_offset = (m_sparse_bo_size - m_sparse_bo_data_size) / 2;
   6471 
   6472 	/* Set up the TFBO storage */
   6473 	const unsigned tfbo_size = static_cast<unsigned int>(sizeof(unsigned int) * m_n_ubo_uints);
   6474 
   6475 	m_gl.genBuffers(1, &m_tf_bo);
   6476 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   6477 
   6478 	m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
   6479 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   6480 
   6481 	m_gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, tfbo_size, DE_NULL, /* data */
   6482 					   GL_MAP_READ_BIT);
   6483 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   6484 
   6485 	/* Set up the UBO contents. We're actually setting up an immutable BO here,
   6486 	 * but we'll use its contents for a copy op, executed at the beginning of
   6487 	 * each iteration.
   6488 	 */
   6489 	unsigned int* ubo_data_traveller_ptr = DE_NULL;
   6490 
   6491 	DE_ASSERT((m_sparse_bo_data_size % sizeof(unsigned int)) == 0);
   6492 
   6493 	m_ubo_data			   = new (std::nothrow) unsigned char[m_sparse_bo_data_size];
   6494 	ubo_data_traveller_ptr = (unsigned int*)m_ubo_data;
   6495 
   6496 	for (unsigned int n_vertex = 0; n_vertex < m_sparse_bo_data_size / (4 * sizeof(unsigned int)); ++n_vertex)
   6497 	{
   6498 		*ubo_data_traveller_ptr = n_vertex;
   6499 		ubo_data_traveller_ptr += 4;
   6500 	}
   6501 
   6502 	m_gl.genBuffers(1, &m_helper_bo);
   6503 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
   6504 
   6505 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   6506 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   6507 
   6508 	/* Set up helper BO storage */
   6509 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_data_size, m_ubo_data, 0); /* flags */
   6510 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
   6511 
   6512 	/* Set up the VAO */
   6513 	m_gl.genVertexArrays(1, &m_vao);
   6514 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
   6515 
   6516 	m_gl.bindVertexArray(m_vao);
   6517 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
   6518 
   6519 	return true;
   6520 }
   6521 
   6522 /** Initializes GL objects which are needed for a single test case iteration.
   6523  *
   6524  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
   6525  *  to release these objects.
   6526  **/
   6527 bool UniformBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
   6528 {
   6529 	bool result = true;
   6530 
   6531 	/* Cache the BO id, if not cached already */
   6532 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
   6533 
   6534 	m_sparse_bo = sparse_bo;
   6535 
   6536 	/* Set up the sparse buffer bindings. */
   6537 	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
   6538 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
   6539 
   6540 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
   6541 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   6542 
   6543 	m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
   6544 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
   6545 
   6546 	return result;
   6547 }
   6548 
   6549 /** Constructor.
   6550  *
   6551  *  @param context     Rendering context
   6552  *  @param name        Test name
   6553  *  @param description Test description
   6554  */
   6555 BufferStorageTest::BufferStorageTest(deqp::Context& context)
   6556 	: TestCase(context, "BufferStorageTest", "Tests various interactions between sparse buffers and other API areas")
   6557 	, m_sparse_bo(0)
   6558 {
   6559 	/* Left blank intentionally */
   6560 }
   6561 
   6562 /** Tears down any GL objects set up to run the test. */
   6563 void BufferStorageTest::deinit()
   6564 {
   6565 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   6566 
   6567 	/* De-initialize all test the test cases */
   6568 	for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
   6569 	{
   6570 		(*itTestCase)->deinitTestCaseGlobal();
   6571 
   6572 		delete (*itTestCase);
   6573 	} /* for (all registered test case objects) */
   6574 
   6575 	m_testCases.clear();
   6576 
   6577 	if (m_sparse_bo != 0)
   6578 	{
   6579 		gl.deleteBuffers(1, &m_sparse_bo);
   6580 
   6581 		m_sparse_bo = 0;
   6582 	}
   6583 }
   6584 
   6585 /** Stub init method */
   6586 void BufferStorageTest::init()
   6587 {
   6588 	/* We cannot initialize the test case objects here as there are cases where there
   6589 	 * is no rendering context bound to the thread, when this method is called. */
   6590 }
   6591 
   6592 /** Fills m_testCases with BufferStorageTestCase instances which implement the sub-cases
   6593  *  for the second test described in the CTS_ARB_sparse_buffer test specification
   6594  **/
   6595 void BufferStorageTest::initTestCases()
   6596 {
   6597 	const glw::Functions& gl		= m_context.getRenderContext().getFunctions();
   6598 	glw::GLint			  page_size = 0;
   6599 
   6600 	/* Retrieve "sparse buffer" GL constant values and entry-point func ptrs */
   6601 	gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size);
   6602 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname");
   6603 
   6604 	/* Initialize all test case objects:
   6605 	 *
   6606 	 * Test cases a1-a6 */
   6607 	m_testCases.push_back(new QuadsBufferStorageTestCase(
   6608 		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_NONE, false)); /* use_color_data */
   6609 	m_testCases.push_back(new QuadsBufferStorageTestCase(
   6610 		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, false)); /* use_color_data */
   6611 	m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size,
   6612 														 QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL,
   6613 														 false)); /* use_color_data */
   6614 	m_testCases.push_back(new QuadsBufferStorageTestCase(
   6615 		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, true)); /* use_color_data */
   6616 	m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size,
   6617 														 QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL,
   6618 														 true)); /* use_color_data */
   6619 
   6620 	/* Test case b1 */
   6621 	m_testCases.push_back(
   6622 		new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_tf_pages_committed */
   6623 
   6624 	/* Test case b2 */
   6625 	m_testCases.push_back(
   6626 		new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_tf_pages_committed */
   6627 
   6628 	/* Test case c */
   6629 	m_testCases.push_back(new ClearOpsBufferStorageTestCase(gl, m_testCtx, page_size));
   6630 
   6631 	/* Test case d */
   6632 	m_testCases.push_back(new InvalidateBufferStorageTestCase(gl, m_testCtx, page_size));
   6633 
   6634 	/* Test case e */
   6635 	m_testCases.push_back(
   6636 		new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_pages_committed */
   6637 	m_testCases.push_back(
   6638 		new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_pages_committed */
   6639 
   6640 	/* Test case f */
   6641 	m_testCases.push_back(new BufferTextureStorageTestCase(gl, m_context, m_testCtx, page_size));
   6642 
   6643 	/* Test case g */
   6644 	m_testCases.push_back(new CopyOpsBufferStorageTestCase(gl, m_testCtx, page_size));
   6645 
   6646 	/* Test case h */
   6647 	m_testCases.push_back(new IndirectDispatchBufferStorageTestCase(gl, m_testCtx, page_size));
   6648 
   6649 	/* Test case i */
   6650 	m_testCases.push_back(new SSBOStorageTestCase(gl, m_testCtx, page_size));
   6651 
   6652 	/* Test case j */
   6653 	m_testCases.push_back(new UniformBufferStorageTestCase(gl, m_testCtx, page_size));
   6654 
   6655 	/* Test case k */
   6656 	m_testCases.push_back(new PixelPackBufferStorageTestCase(gl, m_testCtx, page_size));
   6657 
   6658 	/* Test case l */
   6659 	m_testCases.push_back(new PixelUnpackBufferStorageTestCase(gl, m_testCtx, page_size));
   6660 
   6661 	/* Test case m */
   6662 	m_testCases.push_back(new QueryBufferStorageTestCase(gl, m_testCtx, page_size));
   6663 
   6664 	/* Initialize all test cases */
   6665 	for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
   6666 	{
   6667 		(*itTestCase)->initTestCaseGlobal();
   6668 	}
   6669 }
   6670 
   6671 /** Executes test iteration.
   6672  *
   6673  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
   6674  */
   6675 tcu::TestNode::IterateResult BufferStorageTest::iterate()
   6676 {
   6677 	const glw::Functions& gl	 = m_context.getRenderContext().getFunctions();
   6678 	bool				  result = true;
   6679 
   6680 	/* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
   6681 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
   6682 	{
   6683 		throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
   6684 	}
   6685 
   6686 	/* The buffer storage test cases require OpenGL 4.3 feature-set. */
   6687 	if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)))
   6688 	{
   6689 		throw tcu::NotSupportedError("GL_ARB_sparse_buffer conformance tests require OpenGL 4.3 core feature-set");
   6690 	}
   6691 
   6692 	/* Register & initialize the test case objects */
   6693 	initTestCases();
   6694 
   6695 	/* Iterate over all sparse BO flag combinations. We need to consider a total of 4 flags:
   6696 	 *
   6697 	 * - GL_CLIENT_STORAGE_BIT  (bit 0)
   6698 	 * - GL_DYNAMIC_STORAGE_BIT (bit 1)
   6699 	 * - GL_MAP_COHERENT_BIT    (bit 2)
   6700 	 * - GL_MAP_PERSISTENT_BIT  (bit 3)
   6701 	 *
   6702 	 *  GL_MAP_READ_BIT and GL_MAP_WRITE_BIT are excluded, since they are incompatible
   6703 	 *  with sparse buffers by definition.
   6704 	 *
   6705 	 *  GL_SPARSE_STORAGE_BIT_ARB is assumed to be always defined. Some of the combinations are invalid.
   6706 	 *  Such loop iterations will be skipped.
   6707 	 * */
   6708 
   6709 	for (unsigned int n_flag_combination = 0; n_flag_combination < (1 << 4); ++n_flag_combination)
   6710 	{
   6711 		const glw::GLint flags = ((n_flag_combination & (1 << 0)) ? GL_CLIENT_STORAGE_BIT : 0) |
   6712 								 ((n_flag_combination & (1 << 1)) ? GL_DYNAMIC_STORAGE_BIT : 0) |
   6713 								 ((n_flag_combination & (1 << 2)) ? GL_MAP_COHERENT_BIT : 0) |
   6714 								 ((n_flag_combination & (1 << 3)) ? GL_MAP_PERSISTENT_BIT : 0) |
   6715 								 GL_SPARSE_STORAGE_BIT_ARB;
   6716 
   6717 		if ((flags & GL_MAP_PERSISTENT_BIT) != 0)
   6718 		{
   6719 			if ((flags & GL_MAP_READ_BIT) == 0 && (flags & GL_MAP_WRITE_BIT) == 0)
   6720 			{
   6721 				continue;
   6722 			}
   6723 		}
   6724 
   6725 		if (((flags & GL_MAP_COHERENT_BIT) != 0) && ((flags & GL_MAP_PERSISTENT_BIT) == 0))
   6726 		{
   6727 			continue;
   6728 		}
   6729 
   6730 		/* Set up the sparse BO */
   6731 		gl.genBuffers(1, &m_sparse_bo);
   6732 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
   6733 
   6734 		gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   6735 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
   6736 
   6737 		gl.bufferStorage(GL_ARRAY_BUFFER, 1024768 * 1024, /* as per test spec */
   6738 						 DE_NULL,						  /* data */
   6739 						 flags);
   6740 
   6741 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call failed.");
   6742 
   6743 		for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
   6744 		{
   6745 			gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
   6746 			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
   6747 
   6748 			if (!(*itTestCase)->initTestCaseIteration(m_sparse_bo))
   6749 			{
   6750 				m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName()
   6751 								   << "] "
   6752 									  "has failed to initialize."
   6753 								   << tcu::TestLog::EndMessage;
   6754 
   6755 				result = false;
   6756 				goto end;
   6757 			}
   6758 
   6759 			if (!(*itTestCase)->execute(flags))
   6760 			{
   6761 				m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName()
   6762 								   << "] "
   6763 									  "has failed to execute correctly."
   6764 								   << tcu::TestLog::EndMessage;
   6765 
   6766 				result = false;
   6767 			} /* if (!testCaseResult) */
   6768 
   6769 			(*itTestCase)->deinitTestCaseIteration();
   6770 		} /* for (all added test cases) */
   6771 
   6772 		/* Release the sparse BO */
   6773 		gl.deleteBuffers(1, &m_sparse_bo);
   6774 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() call failed.");
   6775 
   6776 		m_sparse_bo = 0;
   6777 	}
   6778 
   6779 end:
   6780 	m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
   6781 
   6782 	return STOP;
   6783 }
   6784 
   6785 /** Constructor.
   6786  *
   6787  *  @param context Rendering context.
   6788  */
   6789 SparseBufferTests::SparseBufferTests(deqp::Context& context)
   6790 	: TestCaseGroup(context, "sparse_buffer_tests", "Verify conformance of CTS_ARB_sparse_buffer implementation")
   6791 {
   6792 }
   6793 
   6794 /** Initializes the test group contents. */
   6795 void SparseBufferTests::init()
   6796 {
   6797 	addChild(new BufferStorageTest(m_context));
   6798 	addChild(new NegativeTests(m_context));
   6799 	addChild(new PageSizeGetterTest(m_context));
   6800 }
   6801 
   6802 } /* gl4cts namespace */
   6803