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  **/
alignOffset(const unsigned int & offset,const unsigned int & value)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  **/
createComputeProgram(const glw::Functions & gl,const char ** cs_body_parts,unsigned int n_cs_body_parts)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  **/
createProgram(const glw::Functions & gl,const char ** fs_body_parts,unsigned int n_fs_body_parts,const char ** vs_body_parts,unsigned int n_vs_body_parts,const char ** attribute_names,const unsigned int * attribute_locations,unsigned int n_attribute_properties,const glw::GLchar * const * tf_varyings,unsigned int n_tf_varyings,glw::GLenum tf_varying_mode)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  **/
getSparseBOFlagsString(glw::GLenum flags)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  */
NegativeTests(deqp::Context & context)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. */
deinit()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 */
init()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  */
iterate()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  */
PageSizeGetterTest(deqp::Context & context)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. */
deinit()715 void PageSizeGetterTest::deinit()
716 {
717 	/* Nothing to be done here */
718 }
719 
720 /** Stub init method */
init()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  */
iterate()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  */
AtomicCounterBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size,bool all_pages_committed)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  */
deinitTestCaseGlobal()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. */
deinitTestCaseIteration()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  */
execute(glw::GLuint sparse_bo_storage_flags)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  */
initTestCaseGlobal()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  **/
initTestCaseIteration(glw::GLuint sparse_bo)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  */
BufferTextureStorageTestCase(const glw::Functions & gl,deqp::Context & context,tcu::TestContext & testContext,glw::GLint page_size)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  */
deinitTestCaseGlobal()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. */
deinitTestCaseIteration()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  */
execute(glw::GLuint sparse_bo_storage_flags)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  */
initTestCaseGlobal()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  **/
initTestCaseIteration(glw::GLuint sparse_bo)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  */
ClearOpsBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)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  */
deinitTestCaseGlobal()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. */
deinitTestCaseIteration()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  */
execute(glw::GLuint sparse_bo_storage_flags)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 component_offset = n_current_byte % 4;
1779 				const unsigned char expected_value =
1780 					static_cast<unsigned char>((data_rgba8 & (0xFFu << (component_offset * 8))) >> (component_offset * 8));
1781 				const unsigned char found_value = result_data[n_current_byte];
1782 
1783 				if (expected_value != found_value)
1784 				{
1785 					m_testCtx.getLog() << tcu::TestLog::Message
1786 									   << "Modified buffer object region has invalid contents. Expected byte "
1787 									   << "[" << (int)expected_value << "]"
1788 																		", found byte:"
1789 																		"["
1790 									   << (int)found_value << "]"
1791 															  " at index "
1792 															  "["
1793 									   << n_current_byte << "]; "
1794 															"call type:"
1795 															"["
1796 									   << ((use_clear_buffer_data_call) ? "glClearBufferData()" :
1797 																		  "glClearBufferSubData()")
1798 									   << "]"
1799 										  ", all required pages committed?:"
1800 										  "["
1801 									   << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage;
1802 
1803 					result_local = false;
1804 					break;
1805 				}
1806 			}
1807 
1808 			result &= result_local;
1809 
1810 			/* Unmap the storage before proceeding */
1811 			m_gl.unmapBuffer(GL_COPY_READ_BUFFER);
1812 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
1813 		} /* for (both iterations) */
1814 	}	 /* for (both clear types) */
1815 
1816 	return result;
1817 }
1818 
1819 /** Initializes GL objects used across all test case iterations.
1820  *
1821  *  Called once during BufferStorage test run-time.
1822  */
initTestCaseGlobal()1823 bool ClearOpsBufferStorageTestCase::initTestCaseGlobal()
1824 {
1825 	unsigned int	   n_bytes_filled = 0;
1826 	const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size;
1827 
1828 	/* Determine the number of bytes both the helper and the sparse buffer
1829 	 * object need to be able to hold, at maximum */
1830 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size);
1831 
1832 	/* Set up the helper BO */
1833 	DE_ASSERT(m_helper_bo == 0);
1834 
1835 	m_gl.genBuffers(1, &m_helper_bo);
1836 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1837 
1838 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1839 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1840 
1841 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_size_rounded, DE_NULL,
1842 					   GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT); /* flags */
1843 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
1844 
1845 	/* Set up a client-side data buffer we will use to fill the sparse BO with data,
1846 	 * to be later cleared with the clear ops */
1847 	DE_ASSERT(m_initial_data == DE_NULL);
1848 
1849 	m_initial_data = new unsigned char[m_sparse_bo_size_rounded];
1850 
1851 	while (n_bytes_filled < m_sparse_bo_size_rounded)
1852 	{
1853 		m_initial_data[n_bytes_filled] = static_cast<unsigned char>(n_bytes_filled % 256);
1854 
1855 		++n_bytes_filled;
1856 	}
1857 
1858 	return true;
1859 }
1860 
1861 /** Initializes GL objects which are needed for a single test case iteration.
1862  *
1863  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
1864  *  to release these objects.
1865  **/
initTestCaseIteration(glw::GLuint sparse_bo)1866 bool ClearOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
1867 {
1868 	bool result = true;
1869 
1870 	/* Cache the BO id, if not cached already */
1871 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
1872 
1873 	m_sparse_bo = sparse_bo;
1874 
1875 	/* Set up the sparse bufffer. */
1876 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1877 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1878 
1879 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
1880 								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
1881 
1882 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1883 
1884 	return result;
1885 }
1886 
1887 /** Constructor.
1888  *
1889  *  @param gl                         GL entry-points container
1890  *  @param testContext                CTS test context
1891  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
1892  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
1893  */
CopyOpsBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)1894 CopyOpsBufferStorageTestCase::CopyOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
1895 														   glw::GLint page_size)
1896 	: m_gl(gl)
1897 	, m_helper_bo(0)
1898 	, m_immutable_bo(0)
1899 	, m_page_size(page_size)
1900 	, m_sparse_bo_size(0)
1901 	, m_sparse_bo_size_rounded(0)
1902 	, m_testCtx(testContext)
1903 {
1904 	m_ref_data[0]   = DE_NULL;
1905 	m_ref_data[1]   = DE_NULL;
1906 	m_ref_data[2]   = DE_NULL;
1907 	m_sparse_bos[0] = 0;
1908 	m_sparse_bos[1] = 0;
1909 }
1910 
1911 /** Releases all GL objects used across all test case iterations.
1912  *
1913  *  Called once during BufferStorage test run-time.
1914  */
1915 
deinitTestCaseGlobal()1916 void CopyOpsBufferStorageTestCase::deinitTestCaseGlobal()
1917 {
1918 	if (m_helper_bo != 0)
1919 	{
1920 		m_gl.deleteBuffers(1, &m_helper_bo);
1921 
1922 		m_helper_bo = 0;
1923 	}
1924 
1925 	if (m_immutable_bo != 0)
1926 	{
1927 		m_gl.deleteBuffers(1, &m_immutable_bo);
1928 
1929 		m_immutable_bo = 0;
1930 	}
1931 
1932 	for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]);
1933 		 ++n_ref_data_buffer)
1934 	{
1935 		if (m_ref_data[n_ref_data_buffer] != DE_NULL)
1936 		{
1937 			delete[] m_ref_data[n_ref_data_buffer];
1938 
1939 			m_ref_data[n_ref_data_buffer] = DE_NULL;
1940 		}
1941 	}
1942 
1943 	/* Only release the test case-owned BO */
1944 	if (m_sparse_bos[1] != 0)
1945 	{
1946 		m_gl.deleteBuffers(1, m_sparse_bos + 1);
1947 
1948 		m_sparse_bos[1] = 0;
1949 	}
1950 }
1951 
1952 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()1953 void CopyOpsBufferStorageTestCase::deinitTestCaseIteration()
1954 {
1955 	for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
1956 	{
1957 		const glw::GLuint sparse_bo_id = m_sparse_bos[n_sparse_bo];
1958 
1959 		if (sparse_bo_id != 0)
1960 		{
1961 			m_gl.bindBuffer(GL_ARRAY_BUFFER, sparse_bo_id);
1962 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1963 
1964 			m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
1965 										 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1966 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1967 		} /* if (sparse_bo_id != 0) */
1968 	}	 /* for (both BOs) */
1969 }
1970 
1971 /** Executes a single test iteration. The BufferStorage test will call this method
1972  *  numerously during its life-time, testing various valid flag combinations applied
1973  *  to the tested sparse buffer object at glBufferStorage() call time.
1974  *
1975  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
1976  *                                 call to set up the sparse buffer's storage.
1977  *
1978  *  @return true if the test case executed correctly, false otherwise.
1979  */
execute(glw::GLuint sparse_bo_storage_flags)1980 bool CopyOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
1981 {
1982 	(void)sparse_bo_storage_flags;
1983 	bool result = true;
1984 
1985 	/* Iterate over all test cases */
1986 	DE_ASSERT(m_immutable_bo != 0);
1987 	DE_ASSERT(m_sparse_bos[0] != 0);
1988 	DE_ASSERT(m_sparse_bos[1] != 0);
1989 
1990 	for (_test_cases_const_iterator test_iterator = m_test_cases.begin(); test_iterator != m_test_cases.end();
1991 		 ++test_iterator)
1992 	{
1993 		bool			  result_local = true;
1994 		const _test_case& test_case	= *test_iterator;
1995 		const glw::GLuint dst_bo_id =
1996 			test_case.dst_bo_is_sparse ? m_sparse_bos[test_case.dst_bo_sparse_id] : m_immutable_bo;
1997 		const glw::GLuint src_bo_id =
1998 			test_case.src_bo_is_sparse ? m_sparse_bos[test_case.src_bo_sparse_id] : m_immutable_bo;
1999 
2000 		/* Initialize immutable BO data (if used) */
2001 		if (dst_bo_id == m_immutable_bo || src_bo_id == m_immutable_bo)
2002 		{
2003 			m_gl.bindBuffer(GL_ARRAY_BUFFER, m_immutable_bo);
2004 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2005 
2006 			m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
2007 							   m_sparse_bo_size_rounded, m_ref_data[0]);
2008 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2009 		}
2010 
2011 		/* Initialize sparse BO data storage */
2012 		for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
2013 		{
2014 			const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]);
2015 			const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]);
2016 
2017 			if (!is_dst_bo && !is_src_bo)
2018 				continue;
2019 
2020 			m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
2021 			m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bos[n_sparse_bo]);
2022 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
2023 
2024 			if (is_dst_bo)
2025 			{
2026 				m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.dst_bo_commit_start_offset,
2027 											 test_case.dst_bo_commit_size, GL_TRUE); /* commit */
2028 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2029 			}
2030 
2031 			if (is_src_bo)
2032 			{
2033 				m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.src_bo_commit_start_offset,
2034 											 test_case.src_bo_commit_size, GL_TRUE); /* commit */
2035 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2036 			}
2037 
2038 			m_gl.bufferSubData(GL_COPY_READ_BUFFER, 0, /* offset */
2039 							   m_sparse_bo_size_rounded, m_ref_data[1 + n_sparse_bo]);
2040 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2041 
2042 			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2043 								   0,											 /* writeOffset */
2044 								   m_sparse_bo_size_rounded);
2045 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2046 		} /* for (both sparse BOs) */
2047 
2048 		/* Set up the bindings */
2049 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, src_bo_id);
2050 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, dst_bo_id);
2051 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2052 
2053 		/* Issue the copy op */
2054 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, test_case.src_bo_start_offset,
2055 							   test_case.dst_bo_start_offset, test_case.n_bytes_to_copy);
2056 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2057 
2058 		/* Retrieve the destination buffer's contents. The BO used for the previous copy op might have
2059 		 * been a sparse BO, so copy its storage to a helper immutable BO */
2060 		const unsigned short* dst_bo_data_ptr = NULL;
2061 
2062 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, dst_bo_id);
2063 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
2064 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2065 
2066 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2067 							   0,											 /* writeOffset */
2068 							   m_sparse_bo_size_rounded);
2069 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2070 
2071 		dst_bo_data_ptr = (const unsigned short*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */
2072 																	 m_sparse_bo_size_rounded, GL_MAP_READ_BIT);
2073 
2074 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
2075 
2076 		/* Verify the retrieved data:
2077 		 *
2078 		 * 1. Check the bytes which precede the copy op dst offset. These should be equal to
2079 		 *    the destination buffer's reference data within the committed memory region.
2080 		 **/
2081 		if (test_case.dst_bo_start_offset != 0 && test_case.dst_bo_commit_start_offset < test_case.dst_bo_start_offset)
2082 		{
2083 			DE_ASSERT(((test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) % sizeof(short)) == 0);
2084 
2085 			const unsigned int n_valid_values = static_cast<unsigned int>(
2086 				(test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) / sizeof(short));
2087 
2088 			for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value)
2089 			{
2090 				const int dst_data_offset = static_cast<int>(sizeof(short) * n_value);
2091 
2092 				if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2093 					dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2094 				{
2095 					const unsigned short expected_short_value =
2096 						*(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset);
2097 					const unsigned short found_short_value =
2098 						*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2099 
2100 					if (expected_short_value != found_short_value)
2101 					{
2102 						m_testCtx.getLog()
2103 							<< tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, "
2104 														"preceding the region modified by the copy op. "
2105 							<< "Destination BO id:" << dst_bo_id << " ("
2106 							<< ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2107 							<< ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2108 							<< (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2109 							<< ", copy region: " << test_case.dst_bo_start_offset << ":"
2110 							<< (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2111 							<< ". Source BO id:" << src_bo_id << " ("
2112 							<< ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2113 							<< ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2114 							<< (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2115 							<< ", copy region: " << test_case.src_bo_start_offset << ":"
2116 							<< (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of "
2117 							<< expected_short_value << ", found value of " << found_short_value
2118 							<< " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage;
2119 
2120 						result_local = false;
2121 					}
2122 				}
2123 			} /* for (all preceding values which should not have been affected by the copy op) */
2124 		}	 /* if (copy op did not modify the beginning of the destination buffer storage) */
2125 
2126 		/* 2. Check if the data written to the destination buffer object is correct. */
2127 		for (unsigned int n_copied_short_value = 0;
2128 			 n_copied_short_value < test_case.n_bytes_to_copy / sizeof(short) && result_local; ++n_copied_short_value)
2129 		{
2130 			const int src_data_offset =
2131 				static_cast<unsigned int>(test_case.src_bo_start_offset + sizeof(short) * n_copied_short_value);
2132 			const int dst_data_offset =
2133 				static_cast<unsigned int>(test_case.dst_bo_start_offset + sizeof(short) * n_copied_short_value);
2134 
2135 			if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2136 				dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size &&
2137 				src_data_offset >= test_case.src_bo_commit_start_offset &&
2138 				src_data_offset < test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2139 			{
2140 				const unsigned short expected_short_value =
2141 					*(unsigned short*)((unsigned char*)test_case.src_bo_ref_data + src_data_offset);
2142 				const unsigned short found_short_value =
2143 					*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2144 
2145 				if (expected_short_value != found_short_value)
2146 				{
2147 					m_testCtx.getLog() << tcu::TestLog::Message
2148 									   << "Malformed data found in the copy op's destination BO. "
2149 									   << "Destination BO id:" << dst_bo_id << " ("
2150 									   << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2151 									   << ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2152 									   << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2153 									   << ", copy region: " << test_case.dst_bo_start_offset << ":"
2154 									   << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2155 									   << ". Source BO id:" << src_bo_id << " ("
2156 									   << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2157 									   << ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2158 									   << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2159 									   << ", copy region: " << test_case.src_bo_start_offset << ":"
2160 									   << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy)
2161 									   << ". Expected value of " << expected_short_value << ", found value of "
2162 									   << found_short_value << " at dst data offset of " << dst_data_offset << "."
2163 									   << tcu::TestLog::EndMessage;
2164 
2165 					result_local = false;
2166 				}
2167 			}
2168 		}
2169 
2170 		/* 3. Verify the remaining data in the committed part of the destination buffer object is left intact. */
2171 		const unsigned int commit_region_end_offset =
2172 			test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size;
2173 		const unsigned int copy_region_end_offset = test_case.dst_bo_start_offset + test_case.n_bytes_to_copy;
2174 
2175 		if (commit_region_end_offset > copy_region_end_offset)
2176 		{
2177 			DE_ASSERT(((commit_region_end_offset - copy_region_end_offset) % sizeof(short)) == 0);
2178 
2179 			const unsigned int n_valid_values =
2180 				static_cast<unsigned int>((commit_region_end_offset - copy_region_end_offset) / sizeof(short));
2181 
2182 			for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value)
2183 			{
2184 				const int dst_data_offset = static_cast<int>(copy_region_end_offset + sizeof(short) * n_value);
2185 
2186 				if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2187 					dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2188 				{
2189 					const unsigned short expected_short_value =
2190 						*(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset);
2191 					const unsigned short found_short_value =
2192 						*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2193 
2194 					if (expected_short_value != found_short_value)
2195 					{
2196 						m_testCtx.getLog()
2197 							<< tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, "
2198 														"following the region modified by the copy op. "
2199 							<< "Destination BO id:" << dst_bo_id << " ("
2200 							<< ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2201 							<< ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2202 							<< (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2203 							<< ", copy region: " << test_case.dst_bo_start_offset << ":"
2204 							<< (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2205 							<< ". Source BO id:" << src_bo_id << " ("
2206 							<< ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2207 							<< ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2208 							<< (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2209 							<< ", copy region: " << test_case.src_bo_start_offset << ":"
2210 							<< (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of "
2211 							<< expected_short_value << ", found value of " << found_short_value
2212 							<< " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage;
2213 
2214 						result_local = false;
2215 					}
2216 				}
2217 			} /* for (all preceding values which should not have been affected by the copy op) */
2218 		}	 /* if (copy op did not modify the beginning of the destination buffer storage) */
2219 
2220 		/* Unmap the buffer storage */
2221 		m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
2222 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
2223 
2224 		/* Clean up */
2225 		for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
2226 		{
2227 			const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]);
2228 			const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]);
2229 
2230 			if (is_dst_bo || is_src_bo)
2231 			{
2232 				m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[n_sparse_bo]);
2233 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2234 
2235 				m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2236 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2237 			}
2238 		}
2239 
2240 		result &= result_local;
2241 	} /* for (all test cases) */
2242 
2243 	return result;
2244 }
2245 
2246 /** Allocates reference buffers, fills them with data and updates the m_ref_data array. */
initReferenceData()2247 void CopyOpsBufferStorageTestCase::initReferenceData()
2248 {
2249 	DE_ASSERT(m_sparse_bo_size_rounded != 0);
2250 	DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0);
2251 	DE_ASSERT(sizeof(short) == 2);
2252 
2253 	for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]);
2254 		 ++n_ref_data_buffer)
2255 	{
2256 		DE_ASSERT(m_ref_data[n_ref_data_buffer] == DE_NULL);
2257 
2258 		m_ref_data[n_ref_data_buffer] = new unsigned short[m_sparse_bo_size_rounded / 2];
2259 
2260 		/* Write reference values. */
2261 		for (unsigned int n_short_value = 0; n_short_value < m_sparse_bo_size_rounded / 2; ++n_short_value)
2262 		{
2263 			m_ref_data[n_ref_data_buffer][n_short_value] =
2264 				(unsigned short)((n_ref_data_buffer + 1) * (n_short_value + 1));
2265 		}
2266 	} /* for (all reference data buffers) */
2267 }
2268 
2269 /** Initializes GL objects used across all test case iterations.
2270  *
2271  *  Called once during BufferStorage test run-time.
2272  */
initTestCaseGlobal()2273 bool CopyOpsBufferStorageTestCase::initTestCaseGlobal()
2274 {
2275 	m_sparse_bo_size		 = 2 * 3 * 4 * m_page_size;
2276 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
2277 
2278 	initReferenceData();
2279 
2280 	/* Initialize the sparse buffer object */
2281 	m_gl.genBuffers(1, m_sparse_bos + 1);
2282 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2283 
2284 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[1]);
2285 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2286 
2287 	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, DE_NULL, /* data */
2288 					   GL_SPARSE_STORAGE_BIT_ARB);
2289 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
2290 
2291 	/* Initialize the immutable buffer objects used by the test */
2292 	for (unsigned int n_bo = 0; n_bo < 2; /* helper + immutable BO used for the copy ops */
2293 		 ++n_bo)
2294 	{
2295 		glw::GLuint* bo_id_ptr = (n_bo == 0) ? &m_helper_bo : &m_immutable_bo;
2296 		glw::GLenum  flags	 = GL_DYNAMIC_STORAGE_BIT;
2297 
2298 		if (n_bo == 0)
2299 		{
2300 			flags |= GL_MAP_READ_BIT;
2301 		}
2302 
2303 		/* Initialize the immutable buffer object */
2304 		m_gl.genBuffers(1, bo_id_ptr);
2305 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2306 
2307 		m_gl.bindBuffer(GL_ARRAY_BUFFER, *bo_id_ptr);
2308 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2309 
2310 		m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, m_ref_data[0], flags);
2311 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
2312 	}
2313 
2314 	return true;
2315 }
2316 
2317 /** Initializes GL objects which are needed for a single test case iteration.
2318  *
2319  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2320  *  to release these objects.
2321  **/
initTestCaseIteration(glw::GLuint sparse_bo)2322 bool CopyOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2323 {
2324 	bool result = true;
2325 
2326 	/* Remember the BO id */
2327 	m_sparse_bos[0] = sparse_bo;
2328 
2329 	/* Initialize test cases, if this is the first call to initTestCaseIteration() */
2330 	if (m_test_cases.size() == 0)
2331 	{
2332 		initTestCases();
2333 	}
2334 
2335 	/* Make sure all pages of the provided sparse BO are de-committed before
2336 	 * ::execute() is called. */
2337 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[0]);
2338 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2339 
2340 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
2341 								 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2342 
2343 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2344 
2345 	return result;
2346 }
2347 
2348 /** Fills m_test_cases with test case descriptors. Each such descriptor defines
2349  *  a single copy op use case.
2350  *
2351  * The descriptors are then iterated over in ::execute(), defining the testing
2352  * behavior of the test copy ops buffer storage test case.
2353  */
initTestCases()2354 void CopyOpsBufferStorageTestCase::initTestCases()
2355 {
2356 	/* We need to use the following destination & source BO configurations:
2357 	 *
2358 	 * Dst: sparse    BO 1;  Src: sparse    BO 2
2359 	 * Dst: sparse    BO 1;  Src: immutable BO
2360 	 * Dst: immutable BO;    Src: sparse    BO 1
2361 	 * Dst: sparse    BO 1;  Src: sparse    BO 1
2362 	 */
2363 	unsigned int n_test_case = 0;
2364 
2365 	for (unsigned int n_bo_configuration = 0; n_bo_configuration < 4; /* as per the comment */
2366 		 ++n_bo_configuration, ++n_test_case)
2367 	{
2368 		glw::GLuint		dst_bo_sparse_id = 0;
2369 		bool			dst_bo_is_sparse = false;
2370 		unsigned short* dst_bo_ref_data  = DE_NULL;
2371 		glw::GLuint		src_bo_sparse_id = 0;
2372 		bool			src_bo_is_sparse = false;
2373 		unsigned short* src_bo_ref_data  = DE_NULL;
2374 
2375 		switch (n_bo_configuration)
2376 		{
2377 		case 0:
2378 		{
2379 			dst_bo_sparse_id = 0;
2380 			dst_bo_is_sparse = true;
2381 			dst_bo_ref_data  = m_ref_data[1];
2382 			src_bo_sparse_id = 1;
2383 			src_bo_is_sparse = true;
2384 			src_bo_ref_data  = m_ref_data[2];
2385 
2386 			break;
2387 		}
2388 
2389 		case 1:
2390 		{
2391 			dst_bo_sparse_id = 0;
2392 			dst_bo_is_sparse = true;
2393 			dst_bo_ref_data  = m_ref_data[1];
2394 			src_bo_is_sparse = false;
2395 			src_bo_ref_data  = m_ref_data[0];
2396 
2397 			break;
2398 		}
2399 
2400 		case 2:
2401 		{
2402 			dst_bo_is_sparse = false;
2403 			dst_bo_ref_data  = m_ref_data[0];
2404 			src_bo_sparse_id = 0;
2405 			src_bo_is_sparse = true;
2406 			src_bo_ref_data  = m_ref_data[1];
2407 
2408 			break;
2409 		}
2410 
2411 		case 3:
2412 		{
2413 			dst_bo_sparse_id = 0;
2414 			dst_bo_is_sparse = true;
2415 			dst_bo_ref_data  = m_ref_data[1];
2416 			src_bo_sparse_id = 0;
2417 			src_bo_is_sparse = true;
2418 			src_bo_ref_data  = m_ref_data[1];
2419 
2420 			break;
2421 		}
2422 
2423 		default:
2424 		{
2425 			TCU_FAIL("Invalid BO configuration index");
2426 		}
2427 		} /* switch (n_bo_configuration) */
2428 
2429 		/* Need to test the copy operation in three different scenarios,
2430 		 * in regard to the destination buffer:
2431 		 *
2432 		 * a) All pages of the destination region are committed.
2433 		 * b) Half of the pages of the destination region are committed.
2434 		 * c) None of the pages of the destination region are committed.
2435 		 *
2436 		 * Destination region spans from 0 to half of the memory we use
2437 		 * for the testing purposes.
2438 		 */
2439 		DE_ASSERT((m_sparse_bo_size_rounded % m_page_size) == 0);
2440 		DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0);
2441 		DE_ASSERT((m_sparse_bo_size_rounded % 4) == 0);
2442 
2443 		for (unsigned int n_dst_region = 0; n_dst_region < 3; /* as per the comment */
2444 			 ++n_dst_region)
2445 		{
2446 			glw::GLuint dst_bo_commit_size		   = 0;
2447 			glw::GLuint dst_bo_commit_start_offset = 0;
2448 
2449 			switch (n_dst_region)
2450 			{
2451 			case 0:
2452 			{
2453 				dst_bo_commit_start_offset = 0;
2454 				dst_bo_commit_size		   = m_sparse_bo_size_rounded / 2;
2455 
2456 				break;
2457 			}
2458 
2459 			case 1:
2460 			{
2461 				dst_bo_commit_start_offset = m_sparse_bo_size_rounded / 4;
2462 				dst_bo_commit_size		   = m_sparse_bo_size_rounded / 4;
2463 
2464 				break;
2465 			}
2466 
2467 			case 2:
2468 			{
2469 				dst_bo_commit_start_offset = 0;
2470 				dst_bo_commit_size		   = 0;
2471 
2472 				break;
2473 			}
2474 
2475 			default:
2476 			{
2477 				TCU_FAIL("Invalid destination region configuration index");
2478 			}
2479 			} /* switch (n_dst_region) */
2480 
2481 			/* Same goes for the source region.
2482 			 *
2483 			 * Source region spans from m_sparse_bo_size_rounded / 2 to
2484 			 * m_sparse_bo_size_rounded.
2485 			 *
2486 			 **/
2487 			for (unsigned int n_src_region = 0; n_src_region < 3; /* as per the comment */
2488 				 ++n_src_region)
2489 			{
2490 				glw::GLuint src_bo_commit_size		   = 0;
2491 				glw::GLuint src_bo_commit_start_offset = 0;
2492 
2493 				switch (n_src_region)
2494 				{
2495 				case 0:
2496 				{
2497 					src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2;
2498 					src_bo_commit_size		   = m_sparse_bo_size_rounded / 2;
2499 
2500 					break;
2501 				}
2502 
2503 				case 1:
2504 				{
2505 					src_bo_commit_start_offset = 3 * m_sparse_bo_size_rounded / 4;
2506 					src_bo_commit_size		   = m_sparse_bo_size_rounded / 4;
2507 
2508 					break;
2509 				}
2510 
2511 				case 2:
2512 				{
2513 					src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2;
2514 					src_bo_commit_size		   = 0;
2515 
2516 					break;
2517 				}
2518 
2519 				default:
2520 				{
2521 					TCU_FAIL("Invalid source region configuration index");
2522 				}
2523 				} /* switch (n_src_region) */
2524 
2525 				/* Initialize the test case descriptor */
2526 				_test_case test_case;
2527 
2528 				test_case.dst_bo_commit_size		 = dst_bo_commit_size;
2529 				test_case.dst_bo_commit_start_offset = dst_bo_commit_start_offset;
2530 				test_case.dst_bo_sparse_id			 = dst_bo_sparse_id;
2531 				test_case.dst_bo_is_sparse			 = dst_bo_is_sparse;
2532 				test_case.dst_bo_ref_data			 = dst_bo_ref_data;
2533 				test_case.dst_bo_start_offset		 = static_cast<glw::GLint>(sizeof(short) * n_test_case);
2534 				test_case.n_bytes_to_copy			 = static_cast<glw::GLint>(
2535 					m_sparse_bo_size_rounded / 2 - test_case.dst_bo_start_offset - sizeof(short) * n_test_case);
2536 				test_case.src_bo_commit_size		 = src_bo_commit_size;
2537 				test_case.src_bo_commit_start_offset = src_bo_commit_start_offset;
2538 				test_case.src_bo_sparse_id			 = src_bo_sparse_id;
2539 				test_case.src_bo_is_sparse			 = src_bo_is_sparse;
2540 				test_case.src_bo_ref_data			 = src_bo_ref_data;
2541 				test_case.src_bo_start_offset		 = m_sparse_bo_size_rounded / 2;
2542 
2543 				DE_ASSERT(test_case.dst_bo_commit_size >= 0);
2544 				DE_ASSERT(test_case.dst_bo_commit_start_offset >= 0);
2545 				DE_ASSERT(test_case.dst_bo_ref_data != DE_NULL);
2546 				DE_ASSERT(test_case.dst_bo_start_offset >= 0);
2547 				DE_ASSERT(test_case.n_bytes_to_copy >= 0);
2548 				DE_ASSERT(test_case.src_bo_commit_size >= 0);
2549 				DE_ASSERT(test_case.src_bo_commit_start_offset >= 0);
2550 				DE_ASSERT(test_case.src_bo_ref_data != DE_NULL);
2551 				DE_ASSERT(test_case.src_bo_start_offset >= 0);
2552 
2553 				m_test_cases.push_back(test_case);
2554 			} /* for (all source region commit configurations) */
2555 		}	 /* for (all destination region commit configurations) */
2556 	}		  /* for (all BO configurations which need to be tested) */
2557 }
2558 
2559 /** Constructor.
2560  *
2561  *  @param gl                         GL entry-points container
2562  *  @param testContext                CTS test context
2563  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2564  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2565  */
IndirectDispatchBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)2566 IndirectDispatchBufferStorageTestCase::IndirectDispatchBufferStorageTestCase(const glw::Functions& gl,
2567 																			 tcu::TestContext&	 testContext,
2568 																			 glw::GLint			   page_size)
2569 	: m_dispatch_draw_call_args_start_offset(-1)
2570 	, m_expected_ac_value(0)
2571 	, m_gl(gl)
2572 	, m_global_wg_size_x(2048)
2573 	, m_helper_bo(0)
2574 	, m_local_wg_size_x(1023) /* must stay in sync with the local work-groups's size hardcoded in m_po's body! */
2575 	, m_page_size(page_size)
2576 	, m_po(0)
2577 	, m_sparse_bo(0)
2578 	, m_sparse_bo_size(0)
2579 	, m_sparse_bo_size_rounded(0)
2580 	, m_testCtx(testContext)
2581 {
2582 	/* Left blank intentionally */
2583 }
2584 
2585 /** Releases all GL objects used across all test case iterations.
2586  *
2587  *  Called once during BufferStorage test run-time.
2588  */
deinitTestCaseGlobal()2589 void IndirectDispatchBufferStorageTestCase::deinitTestCaseGlobal()
2590 {
2591 	if (m_helper_bo != 0)
2592 	{
2593 		m_gl.deleteBuffers(1, &m_helper_bo);
2594 
2595 		m_helper_bo = 0;
2596 	}
2597 
2598 	if (m_po != 0)
2599 	{
2600 		m_gl.deleteProgram(m_po);
2601 
2602 		m_po = 0;
2603 	}
2604 }
2605 
2606 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()2607 void IndirectDispatchBufferStorageTestCase::deinitTestCaseIteration()
2608 {
2609 	if (m_sparse_bo != 0)
2610 	{
2611 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2612 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2613 
2614 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
2615 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2616 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2617 
2618 		m_sparse_bo = 0;
2619 	}
2620 }
2621 
2622 /** Executes a single test iteration. The BufferStorage test will call this method
2623  *  numerously during its life-time, testing various valid flag combinations applied
2624  *  to the tested sparse buffer object at glBufferStorage() call time.
2625  *
2626  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
2627  *                                 call to set up the sparse buffer's storage.
2628  *
2629  *  @return true if the test case executed correctly, false otherwise.
2630  */
execute(glw::GLuint sparse_bo_storage_flags)2631 bool IndirectDispatchBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
2632 {
2633 	(void)sparse_bo_storage_flags;
2634 	bool result = true;
2635 
2636 	/* Set up the buffer bindings */
2637 	m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_helper_bo);
2638 	m_gl.bindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_sparse_bo);
2639 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed");
2640 
2641 	m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
2642 						 m_helper_bo, 12,			  /* offset */
2643 						 4);						  /* size */
2644 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
2645 
2646 	/* Bind the compute program */
2647 	m_gl.useProgram(m_po);
2648 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
2649 
2650 	/* Zero out atomic counter value. */
2651 	const unsigned int zero_ac_value = 0;
2652 
2653 	m_gl.bufferSubData(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */
2654 					   4,							 /* size */
2655 					   &zero_ac_value);
2656 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2657 
2658 	m_expected_ac_value = zero_ac_value;
2659 
2660 	/* Run the test only in a configuration where all arguments are local in
2661 	 * committed memory page(s): reading arguments from uncommitted pages means
2662 	 * reading undefined data, which can result in huge dispatches that
2663 	 * effectively hang the test.
2664 	 */
2665 	m_gl.bufferPageCommitmentARB(GL_DISPATCH_INDIRECT_BUFFER, 0,	 /* offset */
2666 								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2667 
2668 	m_expected_ac_value += m_global_wg_size_x * m_local_wg_size_x;
2669 
2670 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed.");
2671 
2672 	/* Copy the indirect dispatch call args data from the helper BO to the sparse BO */
2673 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
2674 	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
2675 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2676 
2677 	m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2678 						   m_dispatch_draw_call_args_start_offset, sizeof(unsigned int) * 3);
2679 
2680 	/* Run the program */
2681 	m_gl.dispatchComputeIndirect(m_dispatch_draw_call_args_start_offset);
2682 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchComputeIndirect() call failed.");
2683 
2684 	/* Extract the AC value and verify it */
2685 	const unsigned int* ac_data_ptr =
2686 		(const unsigned int*)m_gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */
2687 												 4,							   /* length */
2688 												 GL_MAP_READ_BIT);
2689 
2690 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
2691 
2692 	if (*ac_data_ptr != m_expected_ac_value && result)
2693 	{
2694 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value encountered. "
2695 													   "Expected value: ["
2696 						   << m_expected_ac_value << "]"
2697 													 ", found:"
2698 													 "["
2699 						   << *ac_data_ptr << "]." << tcu::TestLog::EndMessage;
2700 
2701 		result = false;
2702 	}
2703 
2704 	/* Unmap the buffer before we move on with the next iteration */
2705 	m_gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2706 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
2707 
2708 	return result;
2709 }
2710 
2711 /** Initializes GL objects used across all test case iterations.
2712  *
2713  *  Called once during BufferStorage test run-time.
2714  */
initTestCaseGlobal()2715 bool IndirectDispatchBufferStorageTestCase::initTestCaseGlobal()
2716 {
2717 	bool result = true;
2718 
2719 	/* One of the cases the test case implementation needs to support is the scenario
2720 	 * where the indirect call arguments are located on the boundary of two (or more) memory pages,
2721 	 * and some of the pages are not committed.
2722 	 *
2723 	 * There are two scenarios which can happen:
2724 	 *
2725 	 * a) page size >= sizeof(uint) * 3: Allocate two pages, arg start offset: (page_size - 4) aligned to 4.
2726 	 *                                   The alignment is a must, since we'll be feeding the offset to an indirect dispatch call.
2727 	 * b) page size <  sizeof(uint) * 3: Allocate as many pages as needed, disable some of the pages.
2728 	 *
2729 	 * For code clarity, the two cases are handled by separate branches, although they could be easily
2730 	 * merged.
2731 	 */
2732 	const int n_indirect_dispatch_call_arg_bytes = sizeof(unsigned int) * 3;
2733 
2734 	if (m_page_size >= n_indirect_dispatch_call_arg_bytes)
2735 	{
2736 		/* Indirect dispatch call args must be aligned to 4 */
2737 		DE_ASSERT(m_page_size >= 4);
2738 
2739 		m_dispatch_draw_call_args_start_offset = SparseBufferTestUtilities::alignOffset(m_page_size - 4, 4);
2740 		m_sparse_bo_size = m_dispatch_draw_call_args_start_offset + n_indirect_dispatch_call_arg_bytes;
2741 	}
2742 	else
2743 	{
2744 		m_dispatch_draw_call_args_start_offset = 0;
2745 		m_sparse_bo_size					   = n_indirect_dispatch_call_arg_bytes;
2746 	}
2747 
2748 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
2749 
2750 	/* Set up the helper buffer object. Its structure is as follows:
2751 	 *
2752 	 * [ 0-11]: Indirect dispatch call args
2753 	 * [12-15]: Atomic counter value storage
2754 	 */
2755 	unsigned int	   helper_bo_data[4] = { 0 };
2756 	const unsigned int n_helper_bo_bytes = sizeof(helper_bo_data);
2757 
2758 	helper_bo_data[0] = m_global_wg_size_x; /* num_groups_x */
2759 	helper_bo_data[1] = 1;					/* num_groups_y */
2760 	helper_bo_data[2] = 1;					/* num_groups_z */
2761 	helper_bo_data[3] = 0;					/* default atomic counter value */
2762 
2763 	m_gl.genBuffers(1, &m_helper_bo);
2764 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2765 
2766 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
2767 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2768 
2769 	m_gl.bufferData(GL_ARRAY_BUFFER, n_helper_bo_bytes, helper_bo_data, GL_STATIC_DRAW);
2770 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
2771 
2772 	/* Set up the test compute program object */
2773 	static const char* cs_body = "#version 430 core\n"
2774 								 "\n"
2775 								 "layout(local_size_x = 1023)          in;\n"
2776 								 "layout(binding      = 0, offset = 0) uniform atomic_uint ac;\n"
2777 								 "\n"
2778 								 "void main()\n"
2779 								 "{\n"
2780 								 "    atomicCounterIncrement(ac);\n"
2781 								 "}\n";
2782 
2783 	m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
2784 
2785 	result = (m_po != 0);
2786 
2787 	return result;
2788 }
2789 
2790 /** Initializes GL objects which are needed for a single test case iteration.
2791  *
2792  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2793  *  to release these objects.
2794  **/
initTestCaseIteration(glw::GLuint sparse_bo)2795 bool IndirectDispatchBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2796 {
2797 	bool result = true;
2798 
2799 	/* Cache the BO id, if not cached already */
2800 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
2801 
2802 	m_sparse_bo = sparse_bo;
2803 
2804 	/* Set up the sparse bufffer. */
2805 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2806 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2807 
2808 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
2809 								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2810 
2811 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2812 
2813 	return result;
2814 }
2815 
2816 /** Constructor.
2817  *
2818  *  @param gl                         GL entry-points container
2819  *  @param testContext                CTS test context
2820  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2821  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2822  */
InvalidateBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)2823 InvalidateBufferStorageTestCase::InvalidateBufferStorageTestCase(const glw::Functions& gl,
2824 																 tcu::TestContext& testContext, glw::GLint page_size)
2825 	: m_gl(gl)
2826 	, m_n_pages_to_use(4)
2827 	, m_page_size(page_size)
2828 	, m_sparse_bo(0)
2829 	, m_sparse_bo_size(0)
2830 	, m_sparse_bo_size_rounded(0)
2831 {
2832 	(void)testContext;
2833 	DE_ASSERT((m_n_pages_to_use % 2) == 0);
2834 }
2835 
2836 /** Releases all GL objects used across all test case iterations.
2837  *
2838  *  Called once during BufferStorage test run-time.
2839  */
deinitTestCaseGlobal()2840 void InvalidateBufferStorageTestCase::deinitTestCaseGlobal()
2841 {
2842 	/* Stub */
2843 }
2844 
2845 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()2846 void InvalidateBufferStorageTestCase::deinitTestCaseIteration()
2847 {
2848 	if (m_sparse_bo != 0)
2849 	{
2850 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2851 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2852 
2853 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
2854 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2855 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2856 
2857 		m_sparse_bo = 0;
2858 	}
2859 }
2860 
2861 /** Executes a single test iteration. The BufferStorage test will call this method
2862  *  numerously during its life-time, testing various valid flag combinations applied
2863  *  to the tested sparse buffer object at glBufferStorage() call time.
2864  *
2865  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
2866  *                                 call to set up the sparse buffer's storage.
2867  *
2868  *  @return true if the test case executed correctly, false otherwise.
2869  */
execute(glw::GLuint sparse_bo_storage_flags)2870 bool InvalidateBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
2871 {
2872 	(void)sparse_bo_storage_flags;
2873 	bool result = true;
2874 
2875 	/* Since we cannot really perform any validation related to whether buffer
2876 	 * storage invalidation works corectly, all this test can really do is to verify
2877 	 * if the implementation does not crash when both entry-points are used against
2878 	 * a sparse buffer object.
2879 	 */
2880 	for (unsigned int n_entry_point = 0; n_entry_point < 2; /* glInvalidateBuffer(), glInvalidateBufferSubData() */
2881 		 ++n_entry_point)
2882 	{
2883 		const bool should_test_invalidate_buffer = (n_entry_point == 0);
2884 
2885 		/* For glInvalidateBufferSubData(), we need to test two different ranges. */
2886 		for (int n_iteration = 0; n_iteration < ((should_test_invalidate_buffer) ? 1 : 2); ++n_iteration)
2887 		{
2888 			if (should_test_invalidate_buffer)
2889 			{
2890 				m_gl.invalidateBufferData(m_sparse_bo);
2891 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferData() call failed.");
2892 			}
2893 			else
2894 			{
2895 				m_gl.invalidateBufferSubData(m_sparse_bo, 0, /* offset */
2896 											 m_sparse_bo_size_rounded * ((n_iteration == 0) ? 1 : 2));
2897 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferSubData() call failed.");
2898 			}
2899 		} /* for (all iterations) */
2900 	}	 /* for (both entry-points) */
2901 
2902 	return result;
2903 }
2904 
2905 /** Initializes GL objects used across all test case iterations.
2906  *
2907  *  Called once during BufferStorage test run-time.
2908  */
initTestCaseGlobal()2909 bool InvalidateBufferStorageTestCase::initTestCaseGlobal()
2910 {
2911 	const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size;
2912 
2913 	/* Determine the number of bytes both the helper and the sparse buffer
2914 	 * object need to be able to hold, at maximum */
2915 	m_sparse_bo_size		 = n_bytes_needed;
2916 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size);
2917 
2918 	return true;
2919 }
2920 
2921 /** Initializes GL objects which are needed for a single test case iteration.
2922  *
2923  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2924  *  to release these objects.
2925  **/
initTestCaseIteration(glw::GLuint sparse_bo)2926 bool InvalidateBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2927 {
2928 	bool result = true;
2929 
2930 	/* Cache the BO id, if not cached already */
2931 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
2932 
2933 	m_sparse_bo = sparse_bo;
2934 
2935 	/* Set up the sparse bufffer. */
2936 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2937 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2938 
2939 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
2940 								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2941 
2942 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2943 
2944 	return result;
2945 }
2946 
2947 /** Constructor.
2948  *
2949  *  @param gl                         GL entry-points container
2950  *  @param testContext                CTS test context
2951  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2952  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2953  */
PixelPackBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)2954 PixelPackBufferStorageTestCase::PixelPackBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
2955 															   glw::GLint page_size)
2956 	: m_color_rb(0)
2957 	, m_color_rb_height(1024)
2958 	, m_color_rb_width(1024)
2959 	, m_fbo(0)
2960 	, m_gl(gl)
2961 	, m_helper_bo(0)
2962 	, m_page_size(page_size)
2963 	, m_po(0)
2964 	, m_ref_data_ptr(DE_NULL)
2965 	, m_ref_data_size(0)
2966 	, m_sparse_bo(0)
2967 	, m_sparse_bo_size(0)
2968 	, m_sparse_bo_size_rounded(0)
2969 	, m_testCtx(testContext)
2970 	, m_vao(0)
2971 {
2972 	m_ref_data_size = m_color_rb_width * m_color_rb_height * 4; /* rgba */
2973 }
2974 
2975 /** Releases all GL objects used across all test case iterations.
2976  *
2977  *  Called once during BufferStorage test run-time.
2978  */
deinitTestCaseGlobal()2979 void PixelPackBufferStorageTestCase::deinitTestCaseGlobal()
2980 {
2981 	if (m_color_rb != 0)
2982 	{
2983 		m_gl.deleteRenderbuffers(1, &m_color_rb);
2984 
2985 		m_color_rb = 0;
2986 	}
2987 
2988 	if (m_fbo != 0)
2989 	{
2990 		m_gl.deleteFramebuffers(1, &m_fbo);
2991 
2992 		m_fbo = 0;
2993 	}
2994 
2995 	if (m_helper_bo != 0)
2996 	{
2997 		m_gl.deleteBuffers(1, &m_helper_bo);
2998 
2999 		m_helper_bo = 0;
3000 	}
3001 
3002 	if (m_ref_data_ptr != DE_NULL)
3003 	{
3004 		delete[] m_ref_data_ptr;
3005 
3006 		m_ref_data_ptr = DE_NULL;
3007 	}
3008 
3009 	if (m_po != 0)
3010 	{
3011 		m_gl.deleteProgram(m_po);
3012 
3013 		m_po = 0;
3014 	}
3015 
3016 	if (m_vao != 0)
3017 	{
3018 		m_gl.deleteVertexArrays(1, &m_vao);
3019 
3020 		m_vao = 0;
3021 	}
3022 }
3023 
3024 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()3025 void PixelPackBufferStorageTestCase::deinitTestCaseIteration()
3026 {
3027 	if (m_sparse_bo != 0)
3028 	{
3029 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3030 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3031 
3032 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
3033 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3034 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3035 
3036 		m_sparse_bo = 0;
3037 	}
3038 }
3039 
3040 /** Executes a single test iteration. The BufferStorage test will call this method
3041  *  numerously during its life-time, testing various valid flag combinations applied
3042  *  to the tested sparse buffer object at glBufferStorage() call time.
3043  *
3044  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3045  *                                 call to set up the sparse buffer's storage.
3046  *
3047  *  @return true if the test case executed correctly, false otherwise.
3048  */
execute(glw::GLuint sparse_bo_storage_flags)3049 bool PixelPackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3050 {
3051 	(void)sparse_bo_storage_flags;
3052 	bool result = true;
3053 
3054 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3055 	m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, m_sparse_bo);
3056 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
3057 
3058 	/* Run three separate iterations:
3059 	 *
3060 	 * a) All pages that are going to hold the texture data are committed.
3061 	 * b) Use a zig-zag memory page commitment layout patern.
3062 	 * b) No pages are committed.
3063 	 */
3064 	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
3065 	{
3066 		bool result_local = true;
3067 
3068 		/* Set up the memory page commitment & the storage contents*/
3069 		switch (n_iteration)
3070 		{
3071 		case 0:
3072 		{
3073 			m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0,			 /* offset */
3074 										 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
3075 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3076 
3077 			break;
3078 		}
3079 
3080 		case 1:
3081 		{
3082 			const unsigned int n_pages = 1 + m_ref_data_size / m_page_size;
3083 
3084 			DE_ASSERT((m_ref_data_size % m_page_size) == 0);
3085 
3086 			for (unsigned int n_page = 0; n_page < n_pages; ++n_page)
3087 			{
3088 				const bool should_commit = ((n_page % 2) == 0);
3089 
3090 				m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, m_page_size * n_page, m_page_size,
3091 											 should_commit ? GL_TRUE : GL_FALSE);
3092 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3093 			} /* for (all relevant memory pages) */
3094 
3095 			break;
3096 		}
3097 
3098 		case 2:
3099 		{
3100 			/* Do nothing - all pages already de-committed  */
3101 			break;
3102 		}
3103 
3104 		default:
3105 		{
3106 			TCU_FAIL("Invalid iteration index");
3107 		}
3108 		} /* switch (n_iteration) */
3109 
3110 		/* Draw full screen quad to generate the black-to-white gradient */
3111 		const unsigned char* read_data_ptr = NULL;
3112 
3113 		m_gl.useProgram(m_po);
3114 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
3115 
3116 		m_gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */);
3117 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
3118 
3119 		/* Read a framebuffer pixel data */
3120 		m_gl.readPixels(0,																	/* x */
3121 						0,																	/* y */
3122 						m_color_rb_width, m_color_rb_height, GL_RGBA, GL_UNSIGNED_BYTE, 0); /* pixels */
3123 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed.");
3124 
3125 		m_gl.copyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_COPY_READ_BUFFER, 0, /* readOffset */
3126 							   0,											 /* writeOffset */
3127 							   m_ref_data_size);
3128 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3129 
3130 		read_data_ptr = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */
3131 															m_ref_data_size, GL_MAP_READ_BIT);
3132 
3133 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
3134 
3135 		/* Verify the data */
3136 		unsigned int		 n_current_tex_data_byte	  = 0;
3137 		const unsigned char* read_data_traveller_ptr	  = (const unsigned char*)read_data_ptr;
3138 		const unsigned char* reference_data_traveller_ptr = (const unsigned char*)m_ref_data_ptr;
3139 
3140 		for (unsigned int y = 0; y < m_color_rb_height && result_local; ++y)
3141 		{
3142 			for (unsigned int x = 0; x < m_color_rb_width && result_local; ++x)
3143 			{
3144 				for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component)
3145 				{
3146 					unsigned char expected_value		 = 0;
3147 					bool		  is_from_committed_page = true;
3148 
3149 					if (n_iteration == 1) /* zig-zag */
3150 					{
3151 						is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0;
3152 					}
3153 					else if (n_iteration == 2) /* no pages committed */
3154 					{
3155 						is_from_committed_page = false;
3156 					}
3157 
3158 					if (is_from_committed_page)
3159 					{
3160 						expected_value = *reference_data_traveller_ptr;
3161 					}
3162 
3163 					if (is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) > 1)
3164 					{
3165 						m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component
3166 										   << ")"
3167 											  " found at X:"
3168 										   << x << ", "
3169 												   "Y:"
3170 										   << y << ")."
3171 												   " Expected value:"
3172 										   << expected_value << ","
3173 																" found value:"
3174 										   << *reference_data_traveller_ptr << tcu::TestLog::EndMessage;
3175 
3176 						result_local = false;
3177 					}
3178 
3179 					n_current_tex_data_byte++;
3180 					read_data_traveller_ptr++;
3181 					reference_data_traveller_ptr++;
3182 				} /* for (all components) */
3183 			}	 /* for (all columns) */
3184 		}		  /* for (all rows) */
3185 
3186 		m_gl.unmapBuffer(GL_COPY_READ_BUFFER);
3187 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
3188 
3189 		read_data_ptr = DE_NULL;
3190 		result &= result_local;
3191 
3192 		/* Clean up */
3193 		m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0,			  /* offset */
3194 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3195 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3196 	} /* for (three iterations) */
3197 
3198 	m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
3199 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3200 
3201 	return result;
3202 }
3203 
3204 /** Initializes GL objects used across all test case iterations.
3205  *
3206  *  Called once during BufferStorage test run-time.
3207  */
initTestCaseGlobal()3208 bool PixelPackBufferStorageTestCase::initTestCaseGlobal()
3209 {
3210 	/* Determine dummy vertex shader and fragment shader that will generate black-to-white gradient. */
3211 	const char* gradient_fs_code = "#version 330 core\n"
3212 								   "\n"
3213 								   "out vec4 result;\n"
3214 								   "\n"
3215 								   "void main()\n"
3216 								   "{\n"
3217 								   "    float c = 1.0 - (gl_FragCoord.y - 0.5) / 1023.0;\n"
3218 								   "    result  = vec4(c);\n"
3219 								   "}\n";
3220 
3221 	const char* gradient_vs_code = "#version 330\n"
3222 								   "\n"
3223 								   "void main()\n"
3224 								   "{\n"
3225 								   "    switch (gl_VertexID)\n"
3226 								   "    {\n"
3227 								   "        case 0: gl_Position = vec4(-1.0, -1.0, 0.0, 1.0); break;\n"
3228 								   "        case 1: gl_Position = vec4( 1.0, -1.0, 0.0, 1.0); break;\n"
3229 								   "        case 2: gl_Position = vec4(-1.0,  1.0, 0.0, 1.0); break;\n"
3230 								   "        case 3: gl_Position = vec4( 1.0,  1.0, 0.0, 1.0); break;\n"
3231 								   "    }\n"
3232 								   "}\n";
3233 
3234 	m_po = SparseBufferTestUtilities::createProgram(m_gl, &gradient_fs_code, 1, /* n_fs_body_parts */
3235 													&gradient_vs_code, 1,		/* n_vs_body_parts*/
3236 													NULL,						/* attribute_names */
3237 													NULL,						/* attribute_locations */
3238 													GL_NONE,					/* attribute_properties */
3239 													0,							/* tf_varyings */
3240 													0,							/* n_tf_varyings */
3241 													0);							/* tf_varying_mode */
3242 	if (m_po == 0)
3243 	{
3244 		TCU_FAIL("Failed to link the test program");
3245 	}
3246 
3247 	/* Generate and bind VAO */
3248 	m_gl.genVertexArrays(1, &m_vao);
3249 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
3250 
3251 	m_gl.bindVertexArray(m_vao);
3252 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
3253 
3254 	/* Generate and bind FBO */
3255 	m_gl.genFramebuffers(1, &m_fbo);
3256 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed.");
3257 
3258 	m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3259 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed.");
3260 
3261 	m_gl.readBuffer(GL_COLOR_ATTACHMENT0);
3262 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadBuffer() call failed.");
3263 
3264 	/* Generate and bind RBO and attach it to FBO as a color attachment */
3265 	m_gl.genRenderbuffers(1, &m_color_rb);
3266 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenRenderbuffers() call failed.");
3267 
3268 	m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_color_rb);
3269 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindRenderbuffer() call failed.");
3270 
3271 	m_gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_color_rb_width, m_color_rb_height);
3272 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glRenderbufferStorage() call failed.");
3273 
3274 	m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_color_rb);
3275 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferRenderbuffer() call failed.");
3276 
3277 	if (m_gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
3278 	{
3279 		throw tcu::NotSupportedError("Cannot execute the test - driver does not support rendering"
3280 									 "to a GL_RGBA8 renderbuffer-based color attachment");
3281 	}
3282 
3283 	m_gl.viewport(0, /* x */
3284 				  0, /* y */
3285 				  m_color_rb_width, m_color_rb_height);
3286 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glViewport() call failed.");
3287 
3288 	/* Determine what sparse buffer storage size we are going to need*/
3289 	m_sparse_bo_size		 = m_ref_data_size;
3290 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
3291 
3292 	/* Prepare the texture data */
3293 	unsigned char* ref_data_traveller_ptr = DE_NULL;
3294 
3295 	m_ref_data_ptr		   = new unsigned char[m_ref_data_size];
3296 	ref_data_traveller_ptr = m_ref_data_ptr;
3297 
3298 	for (unsigned int y = 0; y < m_color_rb_height; ++y)
3299 	{
3300 		const unsigned char color = (unsigned char)((1.0f - float(y) / float(m_color_rb_height - 1)) * 255.0f);
3301 
3302 		for (unsigned int x = 0; x < m_color_rb_width; ++x)
3303 		{
3304 			memset(ref_data_traveller_ptr, color, 4); /* rgba */
3305 
3306 			ref_data_traveller_ptr += 4; /* rgba */
3307 		}								 /* for (all columns) */
3308 	}									 /* for (all rows) */
3309 
3310 	/* Set up the helper buffer object. */
3311 	m_gl.genBuffers(1, &m_helper_bo);
3312 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
3313 
3314 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3315 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3316 
3317 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_ref_data_size, m_ref_data_ptr, GL_MAP_READ_BIT);
3318 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
3319 
3320 	return true;
3321 }
3322 
3323 /** Initializes GL objects which are needed for a single test case iteration.
3324  *
3325  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
3326  *  to release these objects.
3327  **/
initTestCaseIteration(glw::GLuint sparse_bo)3328 bool PixelPackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
3329 {
3330 	bool result = true;
3331 
3332 	/* Cache the BO id, if not cached already */
3333 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
3334 
3335 	m_sparse_bo = sparse_bo;
3336 
3337 	return result;
3338 }
3339 
3340 /** Constructor.
3341  *
3342  *  @param gl                         GL entry-points container
3343  *  @param testContext                CTS test context
3344  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
3345  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
3346  */
PixelUnpackBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)3347 PixelUnpackBufferStorageTestCase::PixelUnpackBufferStorageTestCase(const glw::Functions& gl,
3348 																   tcu::TestContext& testContext, glw::GLint page_size)
3349 	: m_gl(gl)
3350 	, m_helper_bo(0)
3351 	, m_page_size(page_size)
3352 	, m_read_data_ptr(DE_NULL)
3353 	, m_sparse_bo(0)
3354 	, m_sparse_bo_size(0)
3355 	, m_sparse_bo_size_rounded(0)
3356 	, m_testCtx(testContext)
3357 	, m_texture_data_ptr(DE_NULL)
3358 	, m_texture_data_size(0)
3359 	, m_to(0)
3360 	, m_to_data_zero(DE_NULL)
3361 	, m_to_height(1024)
3362 	, m_to_width(1024)
3363 {
3364 	m_texture_data_size = m_to_width * m_to_height * 4; /* rgba */
3365 }
3366 
3367 /** Releases all GL objects used across all test case iterations.
3368  *
3369  *  Called once during BufferStorage test run-time.
3370  */
deinitTestCaseGlobal()3371 void PixelUnpackBufferStorageTestCase::deinitTestCaseGlobal()
3372 {
3373 	if (m_helper_bo != 0)
3374 	{
3375 		m_gl.deleteBuffers(1, &m_helper_bo);
3376 
3377 		m_helper_bo = 0;
3378 	}
3379 
3380 	if (m_read_data_ptr != DE_NULL)
3381 	{
3382 		delete[] m_read_data_ptr;
3383 
3384 		m_read_data_ptr = DE_NULL;
3385 	}
3386 
3387 	if (m_texture_data_ptr != DE_NULL)
3388 	{
3389 		delete[] m_texture_data_ptr;
3390 
3391 		m_texture_data_ptr = DE_NULL;
3392 	}
3393 
3394 	if (m_to != 0)
3395 	{
3396 		m_gl.deleteTextures(1, &m_to);
3397 
3398 		m_to = 0;
3399 	}
3400 
3401 	if (m_to_data_zero != DE_NULL)
3402 	{
3403 		delete[] m_to_data_zero;
3404 
3405 		m_to_data_zero = DE_NULL;
3406 	}
3407 }
3408 
3409 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()3410 void PixelUnpackBufferStorageTestCase::deinitTestCaseIteration()
3411 {
3412 	if (m_sparse_bo != 0)
3413 	{
3414 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3415 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3416 
3417 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
3418 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3419 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3420 
3421 		m_sparse_bo = 0;
3422 	}
3423 }
3424 
3425 /** Executes a single test iteration. The BufferStorage test will call this method
3426  *  numerously during its life-time, testing various valid flag combinations applied
3427  *  to the tested sparse buffer object at glBufferStorage() call time.
3428  *
3429  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3430  *                                 call to set up the sparse buffer's storage.
3431  *
3432  *  @return true if the test case executed correctly, false otherwise.
3433  */
execute(glw::GLuint sparse_bo_storage_flags)3434 bool PixelUnpackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3435 {
3436 	(void)sparse_bo_storage_flags;
3437 	bool result = true;
3438 
3439 	m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo);
3440 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3441 
3442 	m_gl.bindTexture(GL_TEXTURE_2D, m_to);
3443 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
3444 
3445 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3446 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
3447 
3448 	/* Run three separate iterations:
3449 	 *
3450 	 * a) All pages holding the source texture data are committed.
3451 	 * b) Use a zig-zag memory page commitment layout patern.
3452 	 * b) No pages are committed.
3453 	 */
3454 	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
3455 	{
3456 		bool result_local = true;
3457 
3458 		/* Set up the memory page commitment & the storage contents*/
3459 		switch (n_iteration)
3460 		{
3461 		case 0:
3462 		{
3463 			m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0,			 /* offset */
3464 										 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
3465 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3466 
3467 			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, /* readOffset */
3468 								   0,											   /* writeOffset */
3469 								   m_texture_data_size);
3470 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3471 
3472 			break;
3473 		}
3474 
3475 		case 1:
3476 		{
3477 			const unsigned int n_pages = m_texture_data_size / m_page_size;
3478 
3479 			for (unsigned int n_page = 0; n_page < n_pages; ++n_page)
3480 			{
3481 				const bool should_commit = ((n_page % 2) == 0);
3482 
3483 				m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, m_page_size * n_page, m_page_size,
3484 											 should_commit ? GL_TRUE : GL_FALSE);
3485 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3486 
3487 				if (should_commit)
3488 				{
3489 					m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER,
3490 										   m_page_size * n_page, /* readOffset */
3491 										   m_page_size * n_page, /* writeOffset */
3492 										   m_page_size);
3493 					GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3494 				}
3495 			} /* for (all relevant memory pages) */
3496 
3497 			break;
3498 		}
3499 
3500 		case 2:
3501 		{
3502 			/* Do nothing */
3503 			break;
3504 		}
3505 
3506 		default:
3507 		{
3508 			TCU_FAIL("Invalid iteration index");
3509 		}
3510 		} /* switch (n_iteration) */
3511 
3512 		/* Clean up the base mip-map's contents before we proceeding with updating it
3513 		 * with data downloaded from the BO, in order to avoid situation where silently
3514 		 * failing glTexSubImage2D() calls slip past unnoticed */
3515 		m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
3516 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3517 
3518 		m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
3519 						   0,				 /* xoffset */
3520 						   0,				 /* yoffset */
3521 						   m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, m_to_data_zero);
3522 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed.");
3523 
3524 		m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo);
3525 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3526 
3527 		/* Update the base mip-map's contents */
3528 		m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
3529 						   0,				 /* xoffset */
3530 						   0,				 /* yoffset */
3531 						   m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, (const glw::GLvoid*)0);
3532 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed.");
3533 
3534 		/* Read back the stored mip-map data */
3535 		memset(m_read_data_ptr, 0xFF, m_texture_data_size);
3536 
3537 		m_gl.getTexImage(GL_TEXTURE_2D, 0, /* level */
3538 						 GL_RGBA, GL_UNSIGNED_BYTE, m_read_data_ptr);
3539 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetTexImage() call failed.");
3540 
3541 		/* Verify the data */
3542 		unsigned int n_current_tex_data_byte	= 0;
3543 		const char*  read_data_traveller_ptr	= (const char*)m_read_data_ptr;
3544 		const char*  texture_data_traveller_ptr = (const char*)m_texture_data_ptr;
3545 
3546 		for (unsigned int y = 0; y < m_to_height && result_local; ++y)
3547 		{
3548 			for (unsigned int x = 0; x < m_to_width && result_local; ++x)
3549 			{
3550 				for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component)
3551 				{
3552 					char expected_value			= 0;
3553 					bool is_from_committed_page = true;
3554 
3555 					if (n_iteration == 1) /* zig-zag */
3556 					{
3557 						is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0;
3558 					}
3559 					else if (n_iteration == 2) /* no pages committed */
3560 					{
3561 						is_from_committed_page = false;
3562 					}
3563 
3564 					if (is_from_committed_page)
3565 					{
3566 						expected_value = *texture_data_traveller_ptr;
3567 					}
3568 
3569 					if (is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) >= 1)
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 										   << *read_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  */
initTestCaseGlobal()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  **/
initTestCaseIteration(glw::GLuint sparse_bo)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 	return result;
3678 }
3679 
3680 /** Constructor.
3681  *
3682  *  @param gl                         GL entry-points container
3683  *  @param testContext                CTS test context
3684  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
3685  *  @param ibo_usage                  Specifies if an indexed draw call should be used by the test. For more details,
3686  *                                    please see documentation for _ibo_usage.
3687  *  @param use_color_data             true to use the color data for the tested draw call;
3688  *                                    false to omit usage of attribute data.
3689  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
3690  */
QuadsBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size,_ibo_usage ibo_usage,bool use_color_data)3691 QuadsBufferStorageTestCase::QuadsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
3692 													   glw::GLint page_size, _ibo_usage ibo_usage, bool use_color_data)
3693 	: m_attribute_color_location(0)	/* predefined attribute locations */
3694 	, m_attribute_position_location(1) /* predefined attribute locations */
3695 	, m_color_data_offset(0)
3696 	, m_data(DE_NULL)
3697 	, m_data_size(0)
3698 	, m_data_size_rounded(0)
3699 	, m_fbo(0)
3700 	, m_gl(gl)
3701 	, m_helper_bo(0)
3702 	, m_ibo_data_offset(-1)
3703 	, m_ibo_usage(ibo_usage)
3704 	, m_n_quad_delta_x(5)
3705 	, m_n_quad_delta_y(5)
3706 	, m_n_quad_height(5)
3707 	, m_n_quad_width(5)
3708 	, m_n_quads_x(100) /* as per spec */
3709 	, m_n_quads_y(100) /* as per spec */
3710 	, m_n_vertices_to_draw(0)
3711 	, m_pages_committed(false)
3712 	, m_po(0)
3713 	, m_sparse_bo(0)
3714 	, m_testCtx(testContext)
3715 	, m_to(0)
3716 	, m_to_height(1024) /* as per spec */
3717 	, m_to_width(1024)  /* as per spec */
3718 	, m_use_color_data(use_color_data)
3719 	, m_vao(0)
3720 	, m_vbo_data_offset(-1)
3721 {
3722 	/*
3723 	 * Each quad = 2 triangles, 1 triangle = 3 vertices, 1 vertex = 4 components.
3724 	 * The inefficient representation has been used on purpose - we want the data to take
3725 	 * more than 64KB so that it is guaranteed that it will span over more than 1 page.
3726 	 */
3727 	m_data_size = 0;
3728 
3729 	m_n_vertices_to_draw = m_n_quads_x * /* quads in X */
3730 						   m_n_quads_y * /* quads in Y */
3731 						   2 *			 /* triangles */
3732 						   3;			 /* vertices per triangle */
3733 
3734 	m_data_size = static_cast<glw::GLuint>(m_n_vertices_to_draw * 4 /* components */ * sizeof(float));
3735 
3736 	if (m_ibo_usage != IBO_USAGE_NONE)
3737 	{
3738 		DE_ASSERT(m_n_vertices_to_draw < 65536);
3739 
3740 		m_data_size = static_cast<glw::GLuint>(m_data_size + (m_n_vertices_to_draw * sizeof(unsigned short)));
3741 	}
3742 
3743 	if (m_use_color_data)
3744 	{
3745 		m_data_size = static_cast<glw::GLuint>(m_data_size +
3746 											   (m_n_vertices_to_draw * sizeof(unsigned char) * 4 * /* rgba components */
3747 												2 *												   /* triangles */
3748 												3)); /* vertices per triangle */
3749 	}
3750 
3751 	m_data_size_rounded = SparseBufferTestUtilities::alignOffset(m_data_size, page_size);
3752 }
3753 
3754 /** Allocates a data buffer and fills it with vertex/index/color data. Vertex data is always stored,
3755  *  index data only if m_ibo_usage is different from IBO_USAGE_NONE. Color data is only saved if
3756  *  m_use_color_data is true.
3757  *
3758  *  @param out_data              Deref will be used to store a pointer to the allocated data buffer.
3759  *                               Ownership is transferred to the caller. Must not be NULL.
3760  *  @param out_vbo_data_offset   Deref will be used to store an offset, from which VBO data starts,
3761  *                               relative to the beginning of *out_data. Must not be NULL.
3762  *  @param out_ibo_data_offset   Deref will be used to store an offset, from which IBO data starts,
3763  *                               relative to the beginning of *out_data. May be NULL if m_ibo_usage
3764  *                               is IBO_USAGE_NONE.
3765  *  @param out_color_data_offset Deref will be used to store na offset, from which color data starts,
3766  *                               relative to the beginning of *out_data. May be NULL if m_use_color_data
3767  *                               is false.
3768  *
3769  */
createTestData(unsigned char ** out_data,unsigned int * out_vbo_data_offset,unsigned int * out_ibo_data_offset,unsigned int * out_color_data_offset) const3770 void QuadsBufferStorageTestCase::createTestData(unsigned char** out_data, unsigned int* out_vbo_data_offset,
3771 												unsigned int* out_ibo_data_offset,
3772 												unsigned int* out_color_data_offset) const
3773 {
3774 	unsigned char* data_traveller_ptr = NULL;
3775 
3776 	*out_data			 = new unsigned char[m_data_size];
3777 	*out_vbo_data_offset = 0;
3778 
3779 	data_traveller_ptr = *out_data;
3780 
3781 	for (unsigned int n_quad_y = 0; n_quad_y < m_n_quads_y; ++n_quad_y)
3782 	{
3783 		for (unsigned int n_quad_x = 0; n_quad_x < m_n_quads_x; ++n_quad_x)
3784 		{
3785 			const unsigned int quad_start_x_px = n_quad_x * (m_n_quad_delta_x + m_n_quad_width);
3786 			const unsigned int quad_start_y_px = n_quad_y * (m_n_quad_delta_y + m_n_quad_height);
3787 			const unsigned int quad_end_x_px   = quad_start_x_px + m_n_quad_width;
3788 			const unsigned int quad_end_y_px   = quad_start_y_px + m_n_quad_height;
3789 
3790 			const float quad_end_x_ss   = float(quad_end_x_px) / float(m_to_width) * 2.0f - 1.0f;
3791 			const float quad_end_y_ss   = float(quad_end_y_px) / float(m_to_height) * 2.0f - 1.0f;
3792 			const float quad_start_x_ss = float(quad_start_x_px) / float(m_to_width) * 2.0f - 1.0f;
3793 			const float quad_start_y_ss = float(quad_start_y_px) / float(m_to_height) * 2.0f - 1.0f;
3794 
3795 			/*  1,4--5
3796 			 *  |\   |
3797 			 *  | \  |
3798 			 *  2----3,6
3799 			 */
3800 			const float v1_4[] = {
3801 				quad_start_x_ss, quad_start_y_ss, 0.0f, /* z */
3802 				1.0f,									/* w */
3803 			};
3804 			const float v2[] = {
3805 				quad_start_x_ss, quad_end_y_ss, 0.0f, /* z */
3806 				1.0f								  /* w */
3807 			};
3808 			const float v3_6[] = {
3809 				quad_end_x_ss, quad_end_y_ss, 0.0f, /* z */
3810 				1.0f								/* w */
3811 			};
3812 			const float v5[] = {
3813 				quad_end_x_ss, quad_start_y_ss, 0.0f, /* z */
3814 				1.0f								  /* w */
3815 			};
3816 
3817 			memcpy(data_traveller_ptr, v1_4, sizeof(v1_4));
3818 			data_traveller_ptr += sizeof(v1_4);
3819 
3820 			memcpy(data_traveller_ptr, v2, sizeof(v2));
3821 			data_traveller_ptr += sizeof(v2);
3822 
3823 			memcpy(data_traveller_ptr, v3_6, sizeof(v3_6));
3824 			data_traveller_ptr += sizeof(v3_6);
3825 
3826 			memcpy(data_traveller_ptr, v1_4, sizeof(v1_4));
3827 			data_traveller_ptr += sizeof(v1_4);
3828 
3829 			memcpy(data_traveller_ptr, v5, sizeof(v5));
3830 			data_traveller_ptr += sizeof(v5);
3831 
3832 			memcpy(data_traveller_ptr, v3_6, sizeof(v3_6));
3833 			data_traveller_ptr += sizeof(v3_6);
3834 		} /* for (all quads in X) */
3835 	}	 /* for (all quads in Y) */
3836 
3837 	/* Set up index data if needed */
3838 	if (m_ibo_usage != IBO_USAGE_NONE)
3839 	{
3840 		*out_ibo_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data);
3841 
3842 		for (int index = m_n_vertices_to_draw - 1; index >= 0; --index)
3843 		{
3844 			*(unsigned short*)data_traveller_ptr = (unsigned short)index;
3845 			data_traveller_ptr += sizeof(unsigned short);
3846 		} /* for (all index values) */
3847 	}	 /* if (m_use_ibo) */
3848 	else
3849 	{
3850 		*out_ibo_data_offset = 0;
3851 	}
3852 
3853 	/* Set up color data if needed */
3854 	if (m_use_color_data)
3855 	{
3856 		*out_color_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data);
3857 
3858 		for (unsigned int n_quad = 0; n_quad < m_n_quads_x * m_n_quads_y; ++n_quad)
3859 		{
3860 			/* Use magic formulas to generate a color data set for the quads. The data
3861 			 * needs to be duplicated for 6 vertices forming a single quad. */
3862 			for (unsigned int n_vertex = 0; n_vertex < 6; ++n_vertex)
3863 			{
3864 				/* Red */
3865 				*data_traveller_ptr = static_cast<unsigned char>(n_quad % 256); //((n_quad + 15) * 14) % 256;
3866 				data_traveller_ptr++;
3867 
3868 				/* Green */
3869 				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 32) * 7) % 255);
3870 				data_traveller_ptr++;
3871 
3872 				/* Blue */
3873 				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 7) * 53) % 255);
3874 				data_traveller_ptr++;
3875 
3876 				/* Alpha */
3877 				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 13) * 3) % 255);
3878 				data_traveller_ptr++;
3879 			}
3880 		} /* for (all quads) */
3881 	}
3882 	else
3883 	{
3884 		*out_color_data_offset = 0;
3885 	}
3886 }
3887 
3888 /** Releases all GL objects used across all test case iterations.
3889  *
3890  *  Called once during BufferStorage test run-time.
3891  */
deinitTestCaseGlobal()3892 void QuadsBufferStorageTestCase::deinitTestCaseGlobal()
3893 {
3894 	if (m_data != DE_NULL)
3895 	{
3896 		delete[] m_data;
3897 
3898 		m_data = DE_NULL;
3899 	}
3900 
3901 	if (m_fbo != 0)
3902 	{
3903 		m_gl.deleteFramebuffers(1, &m_fbo);
3904 
3905 		m_fbo = 0;
3906 	}
3907 
3908 	if (m_helper_bo != 0)
3909 	{
3910 		m_gl.deleteBuffers(1, &m_helper_bo);
3911 
3912 		m_helper_bo = 0;
3913 	}
3914 
3915 	if (m_po != 0)
3916 	{
3917 		m_gl.deleteProgram(m_po);
3918 
3919 		m_po = 0;
3920 	}
3921 
3922 	if (m_to != 0)
3923 	{
3924 		m_gl.deleteTextures(1, &m_to);
3925 
3926 		m_to = 0;
3927 	}
3928 
3929 	if (m_vao != 0)
3930 	{
3931 		m_gl.deleteVertexArrays(1, &m_vao);
3932 
3933 		m_vao = 0;
3934 	}
3935 }
3936 
3937 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()3938 void QuadsBufferStorageTestCase::deinitTestCaseIteration()
3939 {
3940 	/* If the test executed successfully, all pages should've been released by now.
3941 	 * However, if it failed, it's a good idea to de-commit them at this point.
3942 	 * Redundant calls are fine spec-wise, too. */
3943 	if (m_sparse_bo != 0)
3944 	{
3945 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3946 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3947 
3948 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			 /* offset */
3949 									 m_data_size_rounded, GL_FALSE); /* commit */
3950 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3951 
3952 		m_sparse_bo = 0;
3953 	}
3954 }
3955 
3956 /** Executes a single test iteration. The BufferStorage test will call this method
3957  *  numerously during its life-time, testing various valid flag combinations applied
3958  *  to the tested sparse buffer object at glBufferStorage() call time.
3959  *
3960  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3961  *                                 call to set up the sparse buffer's storage.
3962  *
3963  *  @return true if the test case executed correctly, false otherwise.
3964  */
execute(glw::GLuint sparse_bo_storage_flags)3965 bool QuadsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3966 {
3967 	bool result = true;
3968 
3969 	m_gl.viewport(0, /* x */
3970 				  0, /* y */
3971 				  m_to_width, m_to_height);
3972 
3973 	m_gl.useProgram(m_po);
3974 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
3975 
3976 	m_gl.clearColor(0.0f,  /* red */
3977 					0.0f,  /* green */
3978 					0.0f,  /* blue */
3979 					0.0f); /* alpha */
3980 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor() call failed.");
3981 
3982 	/* Render the quads.
3983 	 *
3984 	 * Run in two iterations:
3985 	 *
3986 	 * a) Iteration 1 performs the draw call with the VBO & IBO pages committed
3987 	 * b) Iteration 2 performs the draw call with the VBO & IBO pages without any
3988 	 *    physical backing.
3989 	 **/
3990 	for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
3991 	{
3992 		initSparseBO((n_iteration == 0), /* decommit pages after upload */
3993 					 (sparse_bo_storage_flags & GL_DYNAMIC_STORAGE_BIT) != 0);
3994 
3995 		m_gl.clear(GL_COLOR_BUFFER_BIT);
3996 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear() call failed.");
3997 
3998 		switch (m_ibo_usage)
3999 		{
4000 		case IBO_USAGE_NONE:
4001 		{
4002 			m_gl.drawArrays(GL_TRIANGLES, 0, /* first */
4003 							m_n_vertices_to_draw);
4004 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
4005 
4006 			break;
4007 		}
4008 
4009 		case IBO_USAGE_INDEXED_DRAW_CALL:
4010 		{
4011 			m_gl.drawElements(GL_TRIANGLES, m_n_vertices_to_draw, GL_UNSIGNED_SHORT,
4012 							  (glw::GLvoid*)(intptr_t)m_ibo_data_offset);
4013 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed.");
4014 
4015 			break;
4016 		}
4017 
4018 		case IBO_USAGE_INDEXED_RANGED_DRAW_CALL:
4019 		{
4020 			m_gl.drawRangeElements(GL_TRIANGLES, 0,		 /* start */
4021 								   m_n_vertices_to_draw, /* end */
4022 								   m_n_vertices_to_draw, /* count */
4023 								   GL_UNSIGNED_SHORT, (glw::GLvoid*)(intptr_t)m_ibo_data_offset);
4024 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawRangeElements() call failed.");
4025 
4026 			break;
4027 		}
4028 
4029 		default:
4030 		{
4031 			TCU_FAIL("Unrecognized IBO usage value");
4032 		}
4033 		} /* switch (m_ibo_usage) */
4034 
4035 		/* Retrieve the rendered output */
4036 		unsigned char* read_data = new unsigned char[m_to_width * m_to_height * sizeof(char) * 4 /* rgba */];
4037 
4038 		m_gl.readPixels(0, /* x */
4039 						0, /* y */
4040 						m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, read_data);
4041 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed.");
4042 
4043 		/* IF the data pages have been committed by the time the draw call was made, validate the data.
4044 		 *
4045 		 * For each quad region (be it filled or not), check the center and make sure the retrieved
4046 		 * color corresponds to the expected value.
4047 		 */
4048 		if (m_pages_committed)
4049 		{
4050 			for (unsigned int n_quad_region_y = 0; n_quad_region_y < m_n_quads_y * 2; /* quad + empty "delta" region */
4051 				 ++n_quad_region_y)
4052 			{
4053 				for (unsigned int n_quad_region_x = 0; n_quad_region_x < m_n_quads_x * 2; ++n_quad_region_x)
4054 				{
4055 					/* Determine the expected texel color */
4056 					unsigned char expected_color[4];
4057 					unsigned char found_color[4];
4058 					bool		  is_delta_region = (n_quad_region_x % 2) != 0 || (n_quad_region_y % 2) != 0;
4059 
4060 					if (is_delta_region)
4061 					{
4062 						memset(expected_color, 0, sizeof(expected_color));
4063 					} /* if (is_delta_region) */
4064 					else
4065 					{
4066 						if (m_use_color_data)
4067 						{
4068 							const unsigned int   n_quad_x = n_quad_region_x / 2;
4069 							const unsigned int   n_quad_y = n_quad_region_y / 2;
4070 							const unsigned char* data_ptr =
4071 								m_data + m_color_data_offset +
4072 								(n_quad_y * m_n_quads_x + n_quad_x) * 4 /* rgba */ * 6; /* vertices */
4073 
4074 							memcpy(expected_color, data_ptr, sizeof(expected_color));
4075 						} /* if (m_use_color_data) */
4076 						else
4077 						{
4078 							memset(expected_color, 255, sizeof(expected_color));
4079 						}
4080 					}
4081 
4082 					/* Do we have a match? */
4083 					DE_ASSERT(m_n_quad_height == m_n_quad_delta_y);
4084 					DE_ASSERT(m_n_quad_width == m_n_quad_delta_x);
4085 
4086 					const unsigned int sample_texel_x = m_n_quad_delta_x * n_quad_region_x;
4087 					const unsigned int sample_texel_y = m_n_quad_delta_y * n_quad_region_y;
4088 
4089 					memcpy(found_color, read_data + (sample_texel_y * m_to_width + sample_texel_x) * 4, /* rgba */
4090 						   sizeof(found_color));
4091 
4092 					if (memcmp(expected_color, found_color, sizeof(expected_color)) != 0)
4093 					{
4094 						m_testCtx.getLog() << tcu::TestLog::Message << "Invalid color found at "
4095 																	   "("
4096 										   << sample_texel_x << ", " << sample_texel_y << "): "
4097 																						  "Expected color:"
4098 																						  "("
4099 										   << (int)expected_color[0] << ", " << (int)expected_color[1] << ", "
4100 										   << (int)expected_color[2] << ", " << (int)expected_color[3] << "), "
4101 																										  "Found:"
4102 																										  "("
4103 										   << (int)found_color[0] << ", " << (int)found_color[1] << ", "
4104 										   << (int)found_color[2] << ", " << (int)found_color[3] << "), "
4105 										   << tcu::TestLog::EndMessage;
4106 
4107 						result = false;
4108 						goto end;
4109 					}
4110 				} /* for (all quads in X) */
4111 			}	 /* for (all quads in Y) */
4112 		}		  /* if (m_pages_committed) */
4113 
4114 		delete[] read_data;
4115 		read_data = DE_NULL;
4116 	} /* for (both iterations) */
4117 
4118 end:
4119 	return result;
4120 }
4121 
4122 /** Creates test data and fills the result buffer object (whose ID is stored under m_helper_bo)
4123  *  with the data.
4124  */
initHelperBO()4125 void QuadsBufferStorageTestCase::initHelperBO()
4126 {
4127 	DE_ASSERT(m_data == DE_NULL);
4128 	DE_ASSERT(m_helper_bo == 0);
4129 
4130 	createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset);
4131 
4132 	m_gl.genBuffers(1, &m_helper_bo);
4133 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4134 
4135 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4136 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4137 
4138 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_data_size, m_data, 0); /* flags */
4139 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
4140 }
4141 
4142 /** Creates test data (if necessary), configures sparse buffer's memory page commitment
4143  *  and uploads the test data to the buffer object. Finally, the method configures the
4144  *  vertex array object, used by ::execute() at the draw call time.
4145  *
4146  *  @param decommit_data_pages_after_upload true to de-commit memory pages requested before
4147  *                                          uploading the vertex/index/color data.
4148  *  @param is_dynamic_storage               true to upload the data via glBufferSubData() call.
4149  *                                          false to use a copy op for the operation.
4150  **/
initSparseBO(bool decommit_data_pages_after_upload,bool is_dynamic_storage)4151 void QuadsBufferStorageTestCase::initSparseBO(bool decommit_data_pages_after_upload, bool is_dynamic_storage)
4152 {
4153 	/* Set up the vertex buffer object. */
4154 	if (m_data == DE_NULL)
4155 	{
4156 		createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset);
4157 	}
4158 	else
4159 	{
4160 		/* Sanity checks */
4161 		if (m_ibo_usage != IBO_USAGE_NONE)
4162 		{
4163 			DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset);
4164 		}
4165 
4166 		if (m_use_color_data)
4167 		{
4168 			DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset);
4169 			DE_ASSERT(m_ibo_data_offset != m_color_data_offset);
4170 		}
4171 	}
4172 
4173 	/* Commit as many pages as we need to upload the data */
4174 	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			/* offset */
4175 								 m_data_size_rounded, GL_TRUE); /* commit */
4176 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4177 
4178 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4179 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4180 
4181 	m_pages_committed = true;
4182 
4183 	/* Upload the data */
4184 	if (is_dynamic_storage)
4185 	{
4186 		m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
4187 						   m_data_size, m_data);
4188 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
4189 	}
4190 	else
4191 	{
4192 		/* Sparse BO cannot be directly uploaded data to. Copy the data from a helper BO */
4193 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, /* readOffset */
4194 							   0,										/* writeOffset */
4195 							   m_data_size);
4196 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4197 	}
4198 
4199 	/* Set the VAO up */
4200 	m_gl.vertexAttribPointer(m_attribute_position_location, 4, /* size */
4201 							 GL_FLOAT, GL_FALSE,			   /* normalized */
4202 							 0,								   /* stride */
4203 							 (glw::GLvoid*)(intptr_t)m_vbo_data_offset);
4204 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed.");
4205 
4206 	m_gl.enableVertexAttribArray(m_attribute_position_location); /* index */
4207 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed.");
4208 
4209 	if (m_use_color_data)
4210 	{
4211 		m_gl.vertexAttribPointer(m_attribute_color_location, 4, /* size */
4212 								 GL_UNSIGNED_BYTE, GL_TRUE,		/* normalized */
4213 								 0,								/* stride */
4214 								 (glw::GLvoid*)(intptr_t)m_color_data_offset);
4215 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed.");
4216 
4217 		m_gl.enableVertexAttribArray(m_attribute_color_location); /* index */
4218 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed.");
4219 	}
4220 	else
4221 	{
4222 		m_gl.vertexAttrib4f(m_attribute_color_location, 1.0f, 1.0f, 1.0f, 1.0f);
4223 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttrib4f() call failed.");
4224 
4225 		m_gl.disableVertexAttribArray(m_attribute_color_location);
4226 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisableVertexAttribArray() call failed.");
4227 	}
4228 
4229 	if (m_ibo_usage != IBO_USAGE_NONE)
4230 	{
4231 		m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sparse_bo);
4232 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4233 	} /* if (m_use_ibo) */
4234 
4235 	/* If we were requested to do so, decommit the pages we have just uploaded
4236 	 * the data to.
4237 	 */
4238 	if (decommit_data_pages_after_upload)
4239 	{
4240 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			 /* offset */
4241 									 m_data_size_rounded, GL_FALSE); /* commit */
4242 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4243 
4244 		m_pages_committed = false;
4245 	} /* if (decommit_data_pages_after_upload) */
4246 }
4247 
4248 /** Initializes GL objects used across all test case iterations.
4249  *
4250  *  Called once during BufferStorage test run-time.
4251  */
initTestCaseGlobal()4252 bool QuadsBufferStorageTestCase::initTestCaseGlobal()
4253 {
4254 	bool result = true;
4255 
4256 	/* Set up the texture object */
4257 	DE_ASSERT(m_to == 0);
4258 
4259 	m_gl.genTextures(1, &m_to);
4260 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
4261 
4262 	m_gl.bindTexture(GL_TEXTURE_2D, m_to);
4263 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
4264 
4265 	m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
4266 					  GL_RGBA8, m_to_width, m_to_height);
4267 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed.");
4268 
4269 	/* Set up the framebuffer object */
4270 	DE_ASSERT(m_fbo == 0);
4271 
4272 	m_gl.genFramebuffers(1, &m_fbo);
4273 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed.");
4274 
4275 	m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
4276 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed.");
4277 
4278 	m_gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to, 0); /* level */
4279 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferTexture2D() call failed.");
4280 
4281 	/* Set up the vertex array object */
4282 	DE_ASSERT(m_vao == 0);
4283 
4284 	m_gl.genVertexArrays(1, &m_vao);
4285 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
4286 
4287 	m_gl.bindVertexArray(m_vao);
4288 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
4289 
4290 	/* Init a helper BO */
4291 	initHelperBO();
4292 
4293 	/* Set up the program object */
4294 	const char* fs_body = "#version 430 core\n"
4295 						  "\n"
4296 						  "flat in  vec4 fs_color;\n"
4297 						  "     out vec4 color;\n"
4298 						  "\n"
4299 						  "void main()\n"
4300 						  "{\n"
4301 						  "    color = fs_color;\n"
4302 						  "}\n";
4303 
4304 	const char* vs_body = "#version 430 core\n"
4305 						  "\n"
4306 						  "in vec4 color;\n"
4307 						  "in vec4 position;\n"
4308 						  "\n"
4309 						  "flat out vec4 fs_color;\n"
4310 						  "\n"
4311 						  "void main()\n"
4312 						  "{\n"
4313 						  "    fs_color    = color;\n"
4314 						  "    gl_Position = position;\n"
4315 						  "}\n";
4316 
4317 	const unsigned int attribute_locations[] = { m_attribute_color_location, m_attribute_position_location };
4318 	const char*		   attribute_names[]	 = { "color", "position" };
4319 	const unsigned int n_attributes			 = sizeof(attribute_locations) / sizeof(attribute_locations[0]);
4320 
4321 	DE_ASSERT(m_po == 0);
4322 
4323 	m_po = SparseBufferTestUtilities::createProgram(m_gl, &fs_body, 1, /* n_fs_body_parts */
4324 													&vs_body, 1, attribute_names, attribute_locations,
4325 													n_attributes); /* n_vs_body_parts */
4326 
4327 	if (m_po == 0)
4328 	{
4329 		result = false;
4330 
4331 		goto end;
4332 	}
4333 
4334 end:
4335 	return result;
4336 }
4337 
4338 /** Initializes GL objects which are needed for a single test case iteration.
4339  *
4340  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4341  *  to release these objects.
4342  **/
initTestCaseIteration(glw::GLuint sparse_bo)4343 bool QuadsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4344 {
4345 	bool result = true;
4346 
4347 	/* Cache the BO id, if not cached already */
4348 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4349 
4350 	m_sparse_bo = sparse_bo;
4351 
4352 	return result;
4353 }
4354 
4355 /** Constructor.
4356  *
4357  *  @param gl                         GL entry-points container
4358  *  @param testContext                CTS test context
4359  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4360  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4361  */
QueryBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)4362 QueryBufferStorageTestCase::QueryBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
4363 													   glw::GLint page_size)
4364 	: m_gl(gl)
4365 	, m_helper_bo(0)
4366 	, m_n_triangles(15)
4367 	, m_page_size(page_size)
4368 	, m_po(0)
4369 	, m_qo(0)
4370 	, m_sparse_bo(0)
4371 	, m_sparse_bo_size(0)
4372 	, m_sparse_bo_size_rounded(0)
4373 	, m_testCtx(testContext)
4374 	, m_vao(0)
4375 {
4376 	/* Left blank on purpose */
4377 }
4378 
4379 /** Releases all GL objects used across all test case iterations.
4380  *
4381  *  Called once during BufferStorage test run-time.
4382  */
deinitTestCaseGlobal()4383 void QueryBufferStorageTestCase::deinitTestCaseGlobal()
4384 {
4385 	if (m_helper_bo != 0)
4386 	{
4387 		m_gl.deleteBuffers(1, &m_helper_bo);
4388 
4389 		m_helper_bo = 0;
4390 	}
4391 
4392 	if (m_po != 0)
4393 	{
4394 		m_gl.deleteProgram(m_po);
4395 
4396 		m_po = 0;
4397 	}
4398 
4399 	if (m_qo != 0)
4400 	{
4401 		m_gl.deleteQueries(1, &m_qo);
4402 
4403 		m_qo = 0;
4404 	}
4405 
4406 	if (m_vao != 0)
4407 	{
4408 		m_gl.deleteVertexArrays(1, &m_vao);
4409 
4410 		m_vao = 0;
4411 	}
4412 }
4413 
4414 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()4415 void QueryBufferStorageTestCase::deinitTestCaseIteration()
4416 {
4417 	if (m_sparse_bo != 0)
4418 	{
4419 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
4420 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4421 
4422 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
4423 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4424 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4425 
4426 		m_sparse_bo = 0;
4427 	}
4428 }
4429 
4430 /** Executes a single test iteration. The BufferStorage test will call this method
4431  *  numerously during its life-time, testing various valid flag combinations applied
4432  *  to the tested sparse buffer object at glBufferStorage() call time.
4433  *
4434  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
4435  *                                 call to set up the sparse buffer's storage.
4436  *
4437  *  @return true if the test case executed correctly, false otherwise.
4438  */
execute(glw::GLuint sparse_bo_storage_flags)4439 bool QueryBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
4440 {
4441 	(void)sparse_bo_storage_flags;
4442 	static const unsigned char data_r8_zero = 0;
4443 	bool					   result		= true;
4444 
4445 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
4446 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4447 
4448 	m_gl.useProgram(m_po);
4449 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
4450 
4451 	/* Run two separate iterations:
4452 	 *
4453 	 * a) The page holding the query result value is committed.
4454 	 * b) The page is not committed.
4455 	 */
4456 	for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
4457 	{
4458 		const bool should_commit_page = (n_iteration == 0);
4459 
4460 		/* Set up the memory page commitment */
4461 		m_gl.bufferPageCommitmentARB(GL_QUERY_BUFFER, 0, /* offset */
4462 									 m_sparse_bo_size_rounded, should_commit_page ? GL_TRUE : GL_FALSE);
4463 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4464 
4465 		/* Run the draw call */
4466 		m_gl.beginQuery(GL_PRIMITIVES_GENERATED, m_qo);
4467 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginQuery() call failed.");
4468 
4469 		m_gl.drawArrays(GL_TRIANGLES, 0, /* first */
4470 						m_n_triangles * 3);
4471 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
4472 
4473 		m_gl.endQuery(GL_PRIMITIVES_GENERATED);
4474 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndQuery() call failed.");
4475 
4476 		/* Copy the query result to the sparse buffer */
4477 		for (unsigned int n_getter_call = 0; n_getter_call < 4; ++n_getter_call)
4478 		{
4479 			glw::GLsizei result_n_bytes;
4480 
4481 			switch (n_getter_call)
4482 			{
4483 			case 0:
4484 			{
4485 				result_n_bytes = sizeof(glw::GLint);
4486 				m_gl.getQueryObjectiv(m_qo, GL_QUERY_RESULT, (glw::GLint*)0); /* params */
4487 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectiv() call failed.");
4488 
4489 				break;
4490 			}
4491 
4492 			case 1:
4493 			{
4494 				result_n_bytes = sizeof(glw::GLint);
4495 				m_gl.getQueryObjectuiv(m_qo, GL_QUERY_RESULT, (glw::GLuint*)0); /* params */
4496 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectuiv() call failed.");
4497 
4498 				break;
4499 			}
4500 
4501 			case 2:
4502 			{
4503 				result_n_bytes = sizeof(glw::GLint64);
4504 				m_gl.getQueryObjecti64v(m_qo, GL_QUERY_RESULT, (glw::GLint64*)0);
4505 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjecti64v() call failed.");
4506 
4507 				break;
4508 			}
4509 
4510 			case 3:
4511 			{
4512 				result_n_bytes = sizeof(glw::GLint64);
4513 				m_gl.getQueryObjectui64v(m_qo, GL_QUERY_RESULT, (glw::GLuint64*)0);
4514 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectui64v() call failed.");
4515 
4516 				break;
4517 			}
4518 
4519 			default:
4520 			{
4521 				TCU_FAIL("Invalid getter call type");
4522 			}
4523 			} /* switch (n_getter_call) */
4524 
4525 			/* Verify the query result */
4526 			if (should_commit_page)
4527 			{
4528 				const glw::GLint64* result_ptr = NULL;
4529 
4530 				m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
4531 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4532 
4533 				m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_r8_zero);
4534 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
4535 
4536 				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4537 									   0,											 /* writeOffset */
4538 									   result_n_bytes);
4539 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4540 
4541 				result_ptr = (const glw::GLint64*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY);
4542 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
4543 
4544 				if (*result_ptr != m_n_triangles)
4545 				{
4546 					m_testCtx.getLog() << tcu::TestLog::Message
4547 									   << "Invalid query result stored in a sparse buffer. Found: "
4548 										  "["
4549 									   << *result_ptr << "]"
4550 														 ", expected: "
4551 														 "["
4552 									   << m_n_triangles << "]" << tcu::TestLog::EndMessage;
4553 
4554 					result = false;
4555 				}
4556 
4557 				m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
4558 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
4559 			} /* for (all query getter call types) */
4560 		}	 /* if (should_commit_page) */
4561 	}		  /* for (both iterations) */
4562 
4563 	return result;
4564 }
4565 
4566 /** Initializes GL objects used across all test case iterations.
4567  *
4568  *  Called once during BufferStorage test run-time.
4569  */
initTestCaseGlobal()4570 bool QueryBufferStorageTestCase::initTestCaseGlobal()
4571 {
4572 	/* Determine sparse buffer storage size */
4573 	m_sparse_bo_size		 = sizeof(glw::GLuint64);
4574 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
4575 
4576 	/* Set up the test program object */
4577 	static const char* vs_body = "#version 140\n"
4578 								 "\n"
4579 								 "void main()\n"
4580 								 "{\n"
4581 								 "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
4582 								 "}\n";
4583 
4584 	m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
4585 													0,			   /* n_fs_body_parts */
4586 													&vs_body, 1,   /* n_vs_body_parts */
4587 													DE_NULL,	   /* attribute_names */
4588 													DE_NULL,	   /* attribute_locations */
4589 													0);			   /* n_attribute_locations */
4590 
4591 	if (m_po == 0)
4592 	{
4593 		TCU_FAIL("Test program linking failure");
4594 	}
4595 
4596 	/* Set up the helper buffer object */
4597 	m_gl.genBuffers(1, &m_helper_bo);
4598 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4599 
4600 	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
4601 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4602 
4603 	m_gl.bufferStorage(GL_COPY_WRITE_BUFFER, sizeof(glw::GLint64), DE_NULL, /* data */
4604 					   GL_MAP_READ_BIT);
4605 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
4606 
4607 	/* Set up the test query object */
4608 	m_gl.genQueries(1, &m_qo);
4609 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenQueries() call failed.");
4610 
4611 	/* Set up the VAO */
4612 	m_gl.genVertexArrays(1, &m_vao);
4613 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
4614 
4615 	m_gl.bindVertexArray(m_vao);
4616 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
4617 
4618 	return true;
4619 }
4620 
4621 /** Initializes GL objects which are needed for a single test case iteration.
4622  *
4623  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4624  *  to release these objects.
4625  **/
initTestCaseIteration(glw::GLuint sparse_bo)4626 bool QueryBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4627 {
4628 	bool result = true;
4629 
4630 	/* Cache the BO id, if not cached already */
4631 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4632 
4633 	m_sparse_bo = sparse_bo;
4634 
4635 	/* Set up the sparse buffer. */
4636 	m_gl.bindBuffer(GL_QUERY_BUFFER, m_sparse_bo);
4637 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4638 
4639 	return result;
4640 }
4641 
4642 /** Constructor.
4643  *
4644  *  @param gl                         GL entry-points container
4645  *  @param testContext                CTS test context
4646  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4647  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4648  */
SSBOStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)4649 SSBOStorageTestCase::SSBOStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size)
4650 	: m_gl(gl)
4651 	, m_helper_bo(0)
4652 	, m_page_size(page_size)
4653 	, m_po(0)
4654 	, m_po_local_wg_size(1024)
4655 	, m_result_bo(0)
4656 	, m_sparse_bo(0)
4657 	, m_sparse_bo_size(0)
4658 	, m_sparse_bo_size_rounded(0)
4659 	, m_ssbo_data(DE_NULL)
4660 	, m_testCtx(testContext)
4661 {
4662 	/* min max for SSBO size from GL_ARB_shader_storage_buffer_object is 16mb;
4663 	 *
4664 	 * The specified amount of space lets the test write as many
4665 	 * ints as it's possible, with an assertion that our CS
4666 	 * uses a std140 layout and the SSBO only contains an unsized array.
4667 	 *
4668 	 * NOTE: 16777216 % 1024 = 0, which is awesome because we can hardcode the
4669 	 *       local workgroup size directly in the CS.
4670 	 */
4671 	m_sparse_bo_size		 = (16777216 / (sizeof(int) * 4) /* std140 */) * (sizeof(int) * 4);
4672 	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
4673 }
4674 
4675 /** Releases all GL objects used across all test case iterations.
4676  *
4677  *  Called once during BufferStorage test run-time.
4678  */
deinitTestCaseGlobal()4679 void SSBOStorageTestCase::deinitTestCaseGlobal()
4680 {
4681 	if (m_helper_bo != 0)
4682 	{
4683 		m_gl.deleteBuffers(1, &m_helper_bo);
4684 
4685 		m_helper_bo = 0;
4686 	}
4687 
4688 	if (m_po != 0)
4689 	{
4690 		m_gl.deleteProgram(m_po);
4691 
4692 		m_po = 0;
4693 	}
4694 
4695 	if (m_result_bo != 0)
4696 	{
4697 		m_gl.deleteBuffers(1, &m_result_bo);
4698 
4699 		m_result_bo = 0;
4700 	}
4701 
4702 	if (m_ssbo_data != DE_NULL)
4703 	{
4704 		delete[] m_ssbo_data;
4705 
4706 		m_ssbo_data = DE_NULL;
4707 	}
4708 }
4709 
4710 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()4711 void SSBOStorageTestCase::deinitTestCaseIteration()
4712 {
4713 	if (m_sparse_bo != 0)
4714 	{
4715 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
4716 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4717 
4718 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
4719 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4720 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4721 
4722 		m_sparse_bo = 0;
4723 	}
4724 }
4725 
4726 /** Executes a single test iteration. The BufferStorage test will call this method
4727  *  numerously during its life-time, testing various valid flag combinations applied
4728  *  to the tested sparse buffer object at glBufferStorage() call time.
4729  *
4730  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
4731  *                                 call to set up the sparse buffer's storage.
4732  *
4733  *  @return true if the test case executed correctly, false otherwise.
4734  */
execute(glw::GLuint sparse_bo_storage_flags)4735 bool SSBOStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
4736 {
4737 	(void)sparse_bo_storage_flags;
4738 	bool result = true;
4739 
4740 	/* Bind the program object */
4741 	m_gl.useProgram(m_po);
4742 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
4743 
4744 	/* Set up shader storage buffer bindings */
4745 	m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_sparse_bo);
4746 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4747 
4748 	m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */
4749 						m_sparse_bo);
4750 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
4751 
4752 	/* Run the test in three iterations:
4753 	 *
4754 	 * a) All required pages are committed.
4755 	 * b) Only half of the pages are committed (in a zig-zag layout)
4756 	 * c) None of the pages are committed.
4757 	 */
4758 	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
4759 	{
4760 		bool result_local = true;
4761 
4762 		/* Set up the shader storage buffer object's memory backing */
4763 		const bool   is_zigzag_ssbo			  = (n_iteration == 1);
4764 		unsigned int ssbo_commit_size		  = 0;
4765 		unsigned int ssbo_commit_start_offset = 0;
4766 
4767 		switch (n_iteration)
4768 		{
4769 		case 0:
4770 		case 1:
4771 		{
4772 			ssbo_commit_size		 = m_sparse_bo_size_rounded;
4773 			ssbo_commit_start_offset = 0;
4774 
4775 			if (is_zigzag_ssbo)
4776 			{
4777 				const unsigned int n_pages = ssbo_commit_size / m_page_size;
4778 
4779 				for (unsigned int n_page = 0; n_page < n_pages; n_page += 2)
4780 				{
4781 					m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, m_page_size * n_page, /* offset */
4782 												 m_page_size,									 /* size */
4783 												 GL_TRUE);										 /* commit */
4784 				} /* for (all memory pages) */
4785 			}
4786 			else
4787 			{
4788 				m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0, /* offset */
4789 											 ssbo_commit_size, GL_TRUE);  /* commit */
4790 			}
4791 
4792 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed.");
4793 
4794 			break;
4795 		}
4796 
4797 		case 2:
4798 		{
4799 			/* Use no physical memory backing */
4800 			break;
4801 		}
4802 
4803 		default:
4804 		{
4805 			TCU_FAIL("Unrecognized iteration index");
4806 		}
4807 		} /* switch (n_iteration) */
4808 
4809 		/* Set up bindings for the copy op */
4810 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4811 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
4812 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
4813 
4814 		/* Set up the sparse buffer's data storage */
4815 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4816 							   0,											 /* writeOffset */
4817 							   m_sparse_bo_size);
4818 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4819 
4820 		/* Run the compute program */
4821 		DE_ASSERT((m_sparse_bo_size % m_po_local_wg_size) == 0);
4822 
4823 		m_gl.dispatchCompute(m_sparse_bo_size / m_po_local_wg_size, 1, /* num_groups_y */
4824 							 1);									   /* num_groups_z */
4825 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed.");
4826 
4827 		/* Flush the caches */
4828 		m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4829 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed.");
4830 
4831 		/* Copy SSBO's storage to a mappable result BO */
4832 		m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
4833 		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_result_bo);
4834 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
4835 
4836 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4837 							   0,											 /* writeOffset */
4838 							   m_sparse_bo_size);
4839 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4840 
4841 		/* Map the result BO to the process space */
4842 		unsigned int		current_ssbo_offset = 0;
4843 		const unsigned int* ssbo_data_ptr = (const unsigned int*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY);
4844 
4845 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
4846 
4847 		for (unsigned int n_invocation = 0; current_ssbo_offset < m_sparse_bo_size && result_local; ++n_invocation,
4848 						  current_ssbo_offset = static_cast<unsigned int>(current_ssbo_offset +
4849 																		  (sizeof(int) * 4 /* std140 */)))
4850 		{
4851 			const unsigned int n_page = current_ssbo_offset / m_page_size;
4852 
4853 			if ((is_zigzag_ssbo && (n_page % 2) == 0) ||
4854 				(!is_zigzag_ssbo && (current_ssbo_offset >= ssbo_commit_start_offset &&
4855 									 current_ssbo_offset < (ssbo_commit_start_offset + ssbo_commit_size))))
4856 			{
4857 				if (ssbo_data_ptr[n_invocation * 4] != (n_invocation + 1))
4858 				{
4859 					m_testCtx.getLog() << tcu::TestLog::Message << "Value written to the SSBO at byte "
4860 																   "["
4861 									   << (sizeof(int) * n_invocation) << "]"
4862 																		  " is invalid. Found:"
4863 									   << "[" << ssbo_data_ptr[n_invocation * 4] << "]"
4864 																					", expected:"
4865 									   << "[" << (n_invocation + 1) << "]" << tcu::TestLog::EndMessage;
4866 
4867 					result_local = false;
4868 				}
4869 			} /* if (ssbo_data_ptr[n_texel] != 1) */
4870 		}	 /* for (all result values) */
4871 
4872 		result &= result_local;
4873 
4874 		m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
4875 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
4876 
4877 		/* Remove the physical backing from the sparse buffer  */
4878 		m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0,		  /* offset */
4879 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4880 
4881 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4882 	} /* for (three iterations) */
4883 
4884 	return result;
4885 }
4886 
4887 /** Initializes GL objects used across all test case iterations.
4888  *
4889  *  Called once during BufferStorage test run-time.
4890  */
initTestCaseGlobal()4891 bool SSBOStorageTestCase::initTestCaseGlobal()
4892 {
4893 	/* Set up the test program */
4894 	static const char* cs_body =
4895 		"#version 430 core\n"
4896 		"\n"
4897 		"layout(local_size_x = 1024) in;\n"
4898 		"\n"
4899 		"layout(std140, binding = 0) buffer data\n"
4900 		"{\n"
4901 		"    restrict uint io_values[];\n"
4902 		"};\n"
4903 		"\n"
4904 		"void main()\n"
4905 		"{\n"
4906 		"    uint value_index = gl_GlobalInvocationID.x;\n"
4907 		"    uint new_value   = (io_values[value_index] == value_index) ? (value_index + 1u) : value_index;\n"
4908 		"\n"
4909 		"    io_values[value_index] = new_value;\n"
4910 		"}\n";
4911 
4912 	m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
4913 
4914 	/* Set up a data buffer we will use to initialize the SSBO with default data.
4915 	 *
4916 	 * CS uses a std140 layout for the SSBO, so we need to add the additional padding.
4917 	 */
4918 	DE_ASSERT((m_sparse_bo_size) != 0);
4919 	DE_ASSERT((m_sparse_bo_size % (sizeof(int) * 4)) == 0);
4920 	DE_ASSERT((m_sparse_bo_size % 1024) == 0);
4921 
4922 	m_ssbo_data = new unsigned int[m_sparse_bo_size / sizeof(int)];
4923 
4924 	memset(m_ssbo_data, 0, m_sparse_bo_size);
4925 
4926 	for (unsigned int index = 0; index < m_sparse_bo_size / sizeof(int) / 4; ++index)
4927 	{
4928 		/* Mind the std140 rules for arrays of ints */
4929 		m_ssbo_data[4 * index] = index;
4930 	}
4931 
4932 	/* During execution, we will need to use a helper buffer object. The BO will hold
4933 	 * data we will be copying into the sparse buffer object for each iteration.
4934 	 */
4935 	m_gl.genBuffers(1, &m_helper_bo);
4936 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4937 
4938 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4939 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4940 
4941 	m_gl.bufferData(GL_COPY_READ_BUFFER, m_sparse_bo_size, m_ssbo_data, GL_STATIC_DRAW);
4942 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
4943 
4944 	/* To retrieve the data written to a sparse SSBO, we need to use another
4945 	 * non-sparse helper BO.
4946 	 */
4947 	m_gl.genBuffers(1, &m_result_bo);
4948 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4949 
4950 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_result_bo);
4951 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4952 
4953 	m_gl.bufferData(GL_ARRAY_BUFFER, m_sparse_bo_size, DE_NULL, /* data */
4954 					GL_STATIC_DRAW);
4955 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
4956 
4957 	return true;
4958 }
4959 
4960 /** Initializes GL objects which are needed for a single test case iteration.
4961  *
4962  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4963  *  to release these objects.
4964  **/
initTestCaseIteration(glw::GLuint sparse_bo)4965 bool SSBOStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4966 {
4967 	bool result = true;
4968 
4969 	/* Cache the BO id, if not cached already */
4970 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4971 
4972 	m_sparse_bo = sparse_bo;
4973 
4974 	return result;
4975 }
4976 
4977 /** Constructor.
4978  *
4979  *  @param gl                         GL entry-points container
4980  *  @param testContext                CTS test context
4981  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4982  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4983  *  @param all_pages_committed        true to provide memory backing for all memory pages holding data used by the test.
4984  *                                    false to leave some of them uncommitted.
4985  */
TransformFeedbackBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size,bool all_pages_committed)4986 TransformFeedbackBufferStorageTestCase::TransformFeedbackBufferStorageTestCase(const glw::Functions& gl,
4987 																			   tcu::TestContext&	 testContext,
4988 																			   glw::GLint			 page_size,
4989 																			   bool all_pages_committed)
4990 	: m_all_pages_committed(all_pages_committed)
4991 	, m_data_bo(0)
4992 	, m_data_bo_index_data_offset(0)
4993 	, m_data_bo_indexed_indirect_arg_offset(0)
4994 	, m_data_bo_indexed_mdi_arg_offset(0)
4995 	, m_data_bo_regular_indirect_arg_offset(0)
4996 	, m_data_bo_regular_mdi_arg_offset(0)
4997 	, m_data_bo_size(0)
4998 	, m_draw_call_baseInstance(1231)
4999 	, m_draw_call_baseVertex(65537)
5000 	, m_draw_call_first(913)
5001 	, m_draw_call_firstIndex(4)
5002 	, m_gl(gl)
5003 	, m_helper_bo(0)
5004 	, m_index_data(DE_NULL)
5005 	, m_index_data_size(0)
5006 	, m_indirect_arg_data(DE_NULL)
5007 	, m_indirect_arg_data_size(0)
5008 	, m_min_memory_page_span(4) /* as per test spec */
5009 	, m_multidrawcall_drawcount(-1)
5010 	, m_multidrawcall_primcount(-1)
5011 	, m_n_instances_to_test(4)
5012 	, m_n_vertices_per_instance(0)
5013 	, m_page_size(page_size)
5014 	, m_po_ia(0)
5015 	, m_po_sa(0)
5016 	, m_result_bo(0)
5017 	, m_result_bo_size(0)
5018 	, m_result_bo_size_rounded(0)
5019 	, m_testCtx(testContext)
5020 	, m_vao(0)
5021 {
5022 	/* Left blank on purpose */
5023 }
5024 
5025 /** Releases all GL objects used across all test case iterations.
5026  *
5027  *  Called once during BufferStorage test run-time.
5028  */
deinitTestCaseGlobal()5029 void TransformFeedbackBufferStorageTestCase::deinitTestCaseGlobal()
5030 {
5031 	if (m_data_bo != 0)
5032 	{
5033 		m_gl.deleteBuffers(1, &m_data_bo);
5034 
5035 		m_data_bo = 0;
5036 	}
5037 
5038 	if (m_helper_bo != 0)
5039 	{
5040 		m_gl.deleteBuffers(1, &m_helper_bo);
5041 
5042 		m_helper_bo = 0;
5043 	}
5044 
5045 	if (m_index_data != DE_NULL)
5046 	{
5047 		delete[] m_index_data;
5048 
5049 		m_index_data = DE_NULL;
5050 	}
5051 
5052 	if (m_indirect_arg_data != DE_NULL)
5053 	{
5054 		delete[] m_indirect_arg_data;
5055 
5056 		m_indirect_arg_data = DE_NULL;
5057 	}
5058 
5059 	if (m_po_ia != 0)
5060 	{
5061 		m_gl.deleteProgram(m_po_ia);
5062 
5063 		m_po_ia = 0;
5064 	}
5065 
5066 	if (m_po_sa != 0)
5067 	{
5068 		m_gl.deleteProgram(m_po_sa);
5069 
5070 		m_po_sa = 0;
5071 	}
5072 
5073 	if (m_result_bo != 0)
5074 	{
5075 		m_gl.deleteBuffers(1, &m_result_bo);
5076 
5077 		m_result_bo = 0;
5078 	}
5079 
5080 	if (m_vao != 0)
5081 	{
5082 		m_gl.deleteVertexArrays(1, &m_vao);
5083 
5084 		m_vao = 0;
5085 	}
5086 }
5087 
5088 /** Executes a single test iteration. The BufferStorage test will call this method
5089  *  numerously during its life-time, testing various valid flag combinations applied
5090  *  to the tested sparse buffer object at glBufferStorage() call time.
5091  *
5092  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
5093  *                                 call to set up the sparse buffer's storage.
5094  *
5095  *  @return true if the test case executed correctly, false otherwise.
5096  */
execute(glw::GLuint sparse_bo_storage_flags)5097 bool TransformFeedbackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
5098 {
5099 	bool result = true;
5100 
5101 	/* Iterate through two different transform feedback modes we need to test */
5102 	for (unsigned int n_tf_type = 0; n_tf_type < 2; /* interleaved & separate attribs */
5103 		 ++n_tf_type)
5104 	{
5105 		const bool is_ia_iteration = (n_tf_type == 0);
5106 
5107 		/* Bind the test PO to the context */
5108 		m_gl.useProgram(is_ia_iteration ? m_po_ia : m_po_sa);
5109 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
5110 
5111 		/* Set up TF general binding, which is needed for a glClearBufferData() call
5112 		 * we'll be firing shortly.
5113 		 */
5114 		m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, /* needed for the subsequent glClearBufferData() call */
5115 						m_result_bo);
5116 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5117 
5118 		/* Iterate through all draw call types */
5119 		for (unsigned int n_draw_call_type = 0; n_draw_call_type < DRAW_CALL_COUNT; ++n_draw_call_type)
5120 		{
5121 			int				   draw_call_count					= 0; /* != 1 for multi-draw calls only */
5122 			int				   draw_call_first_instance_id[2]   = { -1 };
5123 			int				   draw_call_first_vertex_id[2]		= { -1 };
5124 			int				   draw_call_n_instances[2]			= { 0 };
5125 			int				   draw_call_n_vertices[2]			= { 0 };
5126 			bool			   draw_call_is_vertex_id_ascending = false;
5127 			const _draw_call   draw_call_type					= (_draw_call)n_draw_call_type;
5128 			unsigned int	   n_result_bytes_per_instance[2]   = { 0 };
5129 			const unsigned int n_result_bytes_per_vertex		= sizeof(unsigned int) * 2;
5130 			unsigned int	   n_result_bytes_total				= 0;
5131 			glw::GLuint*	   result_ptr						= DE_NULL;
5132 
5133 			m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_data_bo);
5134 			m_gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_data_bo);
5135 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
5136 
5137 			/* Commit pages needed to execute transform feed-back */
5138 			if (m_all_pages_committed)
5139 			{
5140 				m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0,	/* offset */
5141 											 m_result_bo_size_rounded, GL_TRUE); /* commit */
5142 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5143 			}
5144 			else
5145 			{
5146 				for (unsigned int n_page = 0; n_page < m_result_bo_size_rounded / m_page_size; ++n_page)
5147 				{
5148 					m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, n_page * m_page_size, /* offset */
5149 												 m_page_size,										 /* size   */
5150 												 (n_page % 2 == 0) ? GL_TRUE : GL_FALSE);			 /* commit */
5151 				}
5152 
5153 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5154 			}
5155 
5156 			/* Zero out the target BO before we begin the TF */
5157 			static const unsigned char data_zero = 0;
5158 
5159 			m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero);
5160 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
5161 
5162 			/* Set up transform feed-back buffer bindings */
5163 			DE_ASSERT(m_result_bo_size != 0);
5164 
5165 			if (is_ia_iteration)
5166 			{
5167 				DE_ASSERT(m_result_bo != 0);
5168 
5169 				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
5170 									 m_result_bo, 0,				  /* offset */
5171 									 m_result_bo_size);
5172 
5173 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
5174 			}
5175 			else
5176 			{
5177 				DE_ASSERT(m_result_bo_size % 2 == 0);
5178 
5179 				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
5180 									 m_result_bo, 0,				  /* offset */
5181 									 m_result_bo_size / 2);
5182 				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, /* index */
5183 									 m_result_bo, m_result_bo_size / 2, m_result_bo_size / 2);
5184 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call(s) failed.");
5185 			}
5186 
5187 			m_gl.beginTransformFeedback(GL_POINTS);
5188 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed.");
5189 
5190 			/* NOTE: Some discussion about the expected "vertex id" value:
5191 			 *
5192 			 * In GL 4.5 core spec (Feb2/2015 version), we have:
5193 			 *
5194 			 * >>
5195 			 * The index of any element transferred to the GL by DrawElementsOneInstance
5196 			 * is referred to as its vertex ID, and may be read by a vertex shader as
5197 			 * gl_VertexID. The vertex ID of the ith element transferred is the sum of
5198 			 * basevertex and the value stored in the currently bound element array buffer at
5199 			 * offset indices +i.
5200 			 * <<
5201 			 *
5202 			 * So for glDrawElements*() derivatives, we will be expecting gl_VertexID to be set to
5203 			 * (basevertex + index[i] + i)
5204 			 *
5205 			 * DrawArrays does not support the "base vertex" concept at all:
5206 			 *
5207 			 * >>
5208 			 * The index of any element transferred to the GL by DrawArraysOneInstance
5209 			 * is referred to as its vertex ID, and may be read by a vertex shader as gl_VertexID.
5210 			 * The vertex ID of the ith element transferred is first + i.
5211 			 * <<
5212 			 *
5213 			 * For regular draw calls, gl_VertexID should be of form:
5214 			 *
5215 			 * (first + i)
5216 			 *
5217 			 * In both cases, gl_InstanceID does NOT include the baseinstance value, as per:
5218 			 *
5219 			 * >>
5220 			 * If an enabled vertex attribute array is instanced (it has a non-zero divisor as
5221 			 * specified by VertexAttribDivisor), the element index that is transferred to the GL,
5222 			 * for all vertices, is given by
5223 			 *
5224 			 * floor(instance / divisor) + baseinstance
5225 			 *
5226 			 * The value of instance may be read by a vertex shader as gl_InstanceID, as
5227 			 * described in section 11.1.3.9
5228 			 * <<
5229 			 */
5230 			switch (draw_call_type)
5231 			{
5232 			case DRAW_CALL_INDEXED:
5233 			{
5234 				m_gl.drawElements(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5235 								  (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset);
5236 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed.");
5237 
5238 				draw_call_count					 = 1;
5239 				draw_call_first_instance_id[0]   = 0;
5240 				draw_call_first_vertex_id[0]	 = m_n_vertices_per_instance;
5241 				draw_call_is_vertex_id_ascending = false;
5242 				draw_call_n_instances[0]		 = 1;
5243 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5244 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5245 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5246 
5247 				break;
5248 			}
5249 
5250 			case DRAW_CALL_INDEXED_BASE_VERTEX:
5251 			{
5252 				m_gl.drawElementsBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5253 											(const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5254 											m_draw_call_baseVertex);
5255 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsBaseVertex() call failed.");
5256 
5257 				draw_call_count					 = 1;
5258 				draw_call_first_instance_id[0]   = 0;
5259 				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_n_vertices_per_instance;
5260 				draw_call_is_vertex_id_ascending = false;
5261 				draw_call_n_instances[0]		 = 1;
5262 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5263 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5264 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5265 
5266 				break;
5267 			}
5268 
5269 			case DRAW_CALL_INDEXED_INDIRECT:
5270 			{
5271 				m_gl.drawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT,
5272 										  (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_indirect_arg_offset);
5273 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsIndirect() call failed.");
5274 
5275 				draw_call_count				   = 1;
5276 				draw_call_first_instance_id[0] = 0;
5277 				draw_call_first_vertex_id[0] =
5278 					m_draw_call_baseVertex +
5279 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5280 								 sizeof(unsigned int)];
5281 				draw_call_is_vertex_id_ascending = false;
5282 				draw_call_n_instances[0]		 = m_n_instances_to_test;
5283 				draw_call_n_vertices[0]			 = m_multidrawcall_count[1];
5284 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5285 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5286 
5287 				break;
5288 			}
5289 
5290 			case DRAW_CALL_INDEXED_INDIRECT_MULTI:
5291 			{
5292 				m_gl.multiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT,
5293 											   (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_mdi_arg_offset,
5294 											   m_multidrawcall_drawcount, 0); /* stride */
5295 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsIndirect() call failed.");
5296 
5297 				draw_call_count				   = m_multidrawcall_drawcount;
5298 				draw_call_first_instance_id[0] = 0;
5299 				draw_call_first_instance_id[1] = 0;
5300 				draw_call_first_vertex_id[0] =
5301 					m_draw_call_baseVertex +
5302 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5303 								 sizeof(unsigned int)];
5304 				draw_call_first_vertex_id[1] =
5305 					m_draw_call_baseVertex +
5306 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5307 								 sizeof(unsigned int)];
5308 				draw_call_is_vertex_id_ascending = false;
5309 				draw_call_n_instances[0]		 = 1;
5310 				draw_call_n_instances[1]		 = m_n_instances_to_test;
5311 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5312 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5313 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5314 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * draw_call_n_vertices[1];
5315 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5316 									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5317 
5318 				break;
5319 			}
5320 
5321 			case DRAW_CALL_INDEXED_MULTI:
5322 			{
5323 				m_gl.multiDrawElements(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT, m_multidrawcall_index,
5324 									   m_multidrawcall_drawcount);
5325 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElements() call failed");
5326 
5327 				draw_call_count				   = m_multidrawcall_drawcount;
5328 				draw_call_first_instance_id[0] = 0;
5329 				draw_call_first_instance_id[1] = 0;
5330 				draw_call_first_vertex_id[0] =
5331 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5332 								 sizeof(unsigned int)];
5333 				draw_call_first_vertex_id[1] =
5334 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5335 								 sizeof(unsigned int)];
5336 				draw_call_is_vertex_id_ascending = false;
5337 				draw_call_n_instances[0]		 = 1;
5338 				draw_call_n_instances[1]		 = 1;
5339 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5340 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5341 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5342 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5343 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5344 									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5345 
5346 				break;
5347 			}
5348 
5349 			case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX:
5350 			{
5351 				m_gl.multiDrawElementsBaseVertex(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT,
5352 												 m_multidrawcall_index, m_multidrawcall_drawcount,
5353 												 m_multidrawcall_basevertex);
5354 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsBaseVertex() call failed.");
5355 
5356 				draw_call_count				   = m_multidrawcall_drawcount;
5357 				draw_call_first_instance_id[0] = 0;
5358 				draw_call_first_instance_id[1] = 0;
5359 				draw_call_first_vertex_id[0] =
5360 					m_multidrawcall_basevertex[0] +
5361 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5362 								 sizeof(unsigned int)];
5363 				draw_call_first_vertex_id[1] =
5364 					m_multidrawcall_basevertex[1] +
5365 					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5366 								 sizeof(unsigned int)];
5367 				draw_call_is_vertex_id_ascending = false;
5368 				draw_call_n_instances[0]		 = 1;
5369 				draw_call_n_instances[1]		 = 1;
5370 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5371 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5372 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5373 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5374 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5375 									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5376 
5377 				break;
5378 			}
5379 
5380 			case DRAW_CALL_INSTANCED_INDEXED:
5381 			{
5382 				m_gl.drawElementsInstanced(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5383 										   (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5384 										   m_n_instances_to_test);
5385 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstanced() call failed.");
5386 
5387 				draw_call_count					 = 1;
5388 				draw_call_first_instance_id[0]   = 0;
5389 				draw_call_first_vertex_id[0]	 = m_index_data[0];
5390 				draw_call_is_vertex_id_ascending = false;
5391 				draw_call_n_instances[0]		 = m_n_instances_to_test;
5392 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5393 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5394 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5395 
5396 				break;
5397 			}
5398 
5399 			case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX:
5400 			{
5401 				m_gl.drawElementsInstancedBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5402 													 (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5403 													 m_n_instances_to_test, m_draw_call_baseVertex);
5404 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertex() call failed.");
5405 
5406 				draw_call_count					 = 1;
5407 				draw_call_first_instance_id[0]   = 0;
5408 				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_index_data[0];
5409 				draw_call_is_vertex_id_ascending = false;
5410 				draw_call_n_instances[0]		 = m_n_instances_to_test;
5411 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5412 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5413 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5414 
5415 				break;
5416 			}
5417 
5418 			case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE:
5419 			{
5420 				m_gl.drawElementsInstancedBaseVertexBaseInstance(
5421 					GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5422 					(const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset, m_n_instances_to_test,
5423 					m_draw_call_baseVertex, m_draw_call_baseInstance);
5424 
5425 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertexBaseInstance() call failed.");
5426 
5427 				draw_call_count					 = 1;
5428 				draw_call_first_instance_id[0]   = 0;
5429 				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_index_data[0];
5430 				draw_call_is_vertex_id_ascending = false;
5431 				draw_call_n_instances[0]		 = m_n_instances_to_test;
5432 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5433 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5434 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5435 
5436 				break;
5437 			}
5438 
5439 			case DRAW_CALL_REGULAR:
5440 			{
5441 				m_gl.drawArrays(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance);
5442 
5443 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed");
5444 
5445 				draw_call_count					 = 1;
5446 				draw_call_first_instance_id[0]   = 0;
5447 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5448 				draw_call_is_vertex_id_ascending = true;
5449 				draw_call_n_instances[0]		 = 1;
5450 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5451 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5452 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5453 
5454 				break;
5455 			}
5456 
5457 			case DRAW_CALL_REGULAR_INDIRECT:
5458 			{
5459 				m_gl.drawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_indirect_arg_offset);
5460 
5461 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysIndirect() call failed.");
5462 
5463 				draw_call_count					 = 1;
5464 				draw_call_first_instance_id[0]   = 0;
5465 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5466 				draw_call_is_vertex_id_ascending = true;
5467 				draw_call_n_instances[0]		 = m_n_instances_to_test;
5468 				draw_call_n_vertices[0]			 = m_multidrawcall_count[1];
5469 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5470 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5471 
5472 				break;
5473 			}
5474 
5475 			case DRAW_CALL_REGULAR_INDIRECT_MULTI:
5476 			{
5477 				m_gl.multiDrawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_mdi_arg_offset,
5478 											 m_multidrawcall_drawcount, 0); /* stride */
5479 
5480 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArraysIndirect() call failed.");
5481 
5482 				draw_call_count					 = 2;
5483 				draw_call_first_instance_id[0]   = 0;
5484 				draw_call_first_instance_id[1]   = 0;
5485 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5486 				draw_call_first_vertex_id[1]	 = m_draw_call_first;
5487 				draw_call_is_vertex_id_ascending = true;
5488 				draw_call_n_instances[0]		 = 1;
5489 				draw_call_n_instances[1]		 = m_n_instances_to_test;
5490 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5491 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5492 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5493 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * draw_call_n_vertices[1];
5494 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5495 									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5496 
5497 				break;
5498 			}
5499 
5500 			case DRAW_CALL_REGULAR_INSTANCED:
5501 			{
5502 				m_gl.drawArraysInstanced(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance,
5503 										 m_n_instances_to_test);
5504 
5505 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed.");
5506 
5507 				draw_call_count					 = 1;
5508 				draw_call_first_instance_id[0]   = 0;
5509 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5510 				draw_call_is_vertex_id_ascending = true;
5511 				draw_call_n_instances[0]		 = m_n_instances_to_test;
5512 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5513 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5514 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5515 
5516 				break;
5517 			}
5518 
5519 			case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE:
5520 			{
5521 				m_gl.drawArraysInstancedBaseInstance(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance,
5522 													 m_n_instances_to_test, m_draw_call_baseInstance);
5523 
5524 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstancedBaseInstance() call failed.");
5525 
5526 				draw_call_count					 = 1;
5527 				draw_call_first_instance_id[0]   = 0;
5528 				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5529 				draw_call_is_vertex_id_ascending = true;
5530 				draw_call_n_instances[0]		 = m_n_instances_to_test;
5531 				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5532 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5533 				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5534 
5535 				break;
5536 			}
5537 
5538 			case DRAW_CALL_REGULAR_MULTI:
5539 			{
5540 				m_gl.multiDrawArrays(GL_POINTS, m_multidrawcall_first, m_multidrawcall_count,
5541 									 m_multidrawcall_drawcount);
5542 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArrays() call failed.");
5543 
5544 				draw_call_count					 = m_multidrawcall_drawcount;
5545 				draw_call_first_instance_id[0]   = 0;
5546 				draw_call_first_instance_id[1]   = 0;
5547 				draw_call_first_vertex_id[0]	 = m_multidrawcall_first[0];
5548 				draw_call_first_vertex_id[1]	 = m_multidrawcall_first[1];
5549 				draw_call_is_vertex_id_ascending = true;
5550 				draw_call_n_instances[0]		 = 1;
5551 				draw_call_n_instances[1]		 = 1;
5552 				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5553 				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5554 				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5555 				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5556 				n_result_bytes_total			 = n_result_bytes_per_instance[0] + n_result_bytes_per_instance[1];
5557 
5558 				break;
5559 			}
5560 
5561 			default:
5562 			{
5563 				TCU_FAIL("Unrecognized draw call type");
5564 			}
5565 			} /* switch (draw_call_type) */
5566 
5567 			DE_ASSERT(n_result_bytes_total <= m_result_bo_size);
5568 
5569 			m_gl.endTransformFeedback();
5570 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed.");
5571 
5572 			/* Retrieve the captured data */
5573 			glw::GLuint  mappable_bo_id			  = m_helper_bo;
5574 			unsigned int mappable_bo_start_offset = 0;
5575 
5576 			/* We cannot map the result BO storage directly into process space, since
5577 			 * it's a sparse buffer. Copy the generated data to a helper BO and map
5578 			 * that BO instead. */
5579 			m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_result_bo);
5580 			m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
5581 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
5582 
5583 			if (is_ia_iteration)
5584 			{
5585 				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
5586 									   0,											 /* writeOffset */
5587 									   n_result_bytes_total);
5588 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
5589 			}
5590 			else
5591 			{
5592 				DE_ASSERT((n_result_bytes_total % 2) == 0);
5593 
5594 				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
5595 									   0,											 /* writeOffset */
5596 									   n_result_bytes_total / 2);
5597 				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
5598 									   m_result_bo_size / 2,	  /* readOffset  */
5599 									   m_result_bo_size / 2,	  /* writeOffset */
5600 									   n_result_bytes_total / 2); /* size        */
5601 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
5602 			}
5603 
5604 			m_gl.bindBuffer(GL_ARRAY_BUFFER, mappable_bo_id);
5605 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5606 
5607 			result_ptr = (unsigned int*)m_gl.mapBufferRange(GL_ARRAY_BUFFER, mappable_bo_start_offset, m_result_bo_size,
5608 															GL_MAP_READ_BIT);
5609 
5610 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
5611 
5612 			/* Verify the generated output */
5613 			bool		continue_checking		  = true;
5614 			glw::GLuint result_instance_id_stride = 0;
5615 			glw::GLuint result_vertex_id_stride   = 0;
5616 
5617 			if (is_ia_iteration)
5618 			{
5619 				result_instance_id_stride = 2;
5620 				result_vertex_id_stride   = 2;
5621 			}
5622 			else
5623 			{
5624 				result_instance_id_stride = 1;
5625 				result_vertex_id_stride   = 1;
5626 			}
5627 
5628 			/* For all draw calls.. */
5629 			for (int n_draw_call = 0; n_draw_call < draw_call_count && continue_checking; ++n_draw_call)
5630 			{
5631 				/* ..and resulting draw call instances.. */
5632 				for (int n_instance = 0; n_instance < draw_call_n_instances[n_draw_call] && continue_checking;
5633 					 ++n_instance)
5634 				{
5635 					DE_ASSERT((n_result_bytes_per_instance[n_draw_call] % sizeof(unsigned int)) == 0);
5636 
5637 					/* Determine where the result TF data start from */
5638 					const glw::GLuint expected_instance_id = draw_call_first_instance_id[n_draw_call] + n_instance;
5639 					glw::GLuint*	  result_instance_id_traveller_ptr = DE_NULL;
5640 					glw::GLuint*	  result_vertex_id_traveller_ptr   = DE_NULL;
5641 
5642 					if (is_ia_iteration)
5643 					{
5644 						result_instance_id_traveller_ptr = result_ptr;
5645 
5646 						for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call)
5647 						{
5648 							result_instance_id_traveller_ptr += draw_call_n_instances[n_prev_draw_call] *
5649 																n_result_bytes_per_instance[n_prev_draw_call] /
5650 																sizeof(unsigned int);
5651 						}
5652 
5653 						result_instance_id_traveller_ptr +=
5654 							n_instance * n_result_bytes_per_instance[n_draw_call] / sizeof(unsigned int);
5655 						result_vertex_id_traveller_ptr = result_instance_id_traveller_ptr + 1;
5656 					} /* if (is_ia_iteration) */
5657 					else
5658 					{
5659 						DE_ASSERT((m_result_bo_size % 2) == 0);
5660 
5661 						result_instance_id_traveller_ptr = result_ptr;
5662 
5663 						for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call)
5664 						{
5665 							result_instance_id_traveller_ptr +=
5666 								draw_call_n_instances[n_prev_draw_call] *
5667 								n_result_bytes_per_instance[n_prev_draw_call] /
5668 								2 / /* instance id..instance id data | vertex id..vertex id data */
5669 								sizeof(unsigned int);
5670 						}
5671 
5672 						result_instance_id_traveller_ptr +=
5673 							n_instance * n_result_bytes_per_instance[n_draw_call] / 2 / sizeof(unsigned int);
5674 						result_vertex_id_traveller_ptr =
5675 							result_instance_id_traveller_ptr + (m_result_bo_size / 2) / sizeof(unsigned int);
5676 					}
5677 
5678 					/* Start checking the generated output */
5679 					for (int n_point = 0; n_point < draw_call_n_vertices[n_draw_call] && continue_checking; ++n_point)
5680 					{
5681 						glw::GLuint expected_vertex_id	= 1;
5682 						glw::GLuint retrieved_instance_id = 2;
5683 						glw::GLuint retrieved_vertex_id   = 3;
5684 
5685 						if (draw_call_is_vertex_id_ascending)
5686 						{
5687 							expected_vertex_id = draw_call_first_vertex_id[n_draw_call] + n_point;
5688 						} /* if (draw_call_is_vertex_id_ascending) */
5689 						else
5690 						{
5691 							if (draw_call_first_vertex_id[n_draw_call] >= n_point)
5692 							{
5693 								expected_vertex_id = draw_call_first_vertex_id[n_draw_call] - n_point;
5694 							}
5695 							else
5696 							{
5697 								expected_vertex_id = 0;
5698 							}
5699 						}
5700 
5701 						/* Only perform the check if the offsets refer to pages with physical backing.
5702 						 *
5703 						 * Note that, on platforms, whose page size % 4 != 0, the values can land partially in the no-man's land,
5704 						 * and partially in the safe zone. In such cases, skip the verification. */
5705 						const bool result_instance_id_page_has_physical_backing =
5706 							(((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) ==
5707 							 0) &&
5708 							((((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) -
5709 								1) /
5710 							   m_page_size) %
5711 							  2) == 0);
5712 						const bool result_vertex_id_page_has_physical_backing =
5713 							(((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) == 0) &&
5714 							((((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) -
5715 								1) /
5716 							   m_page_size) %
5717 							  2) == 0);
5718 
5719 						retrieved_instance_id = *result_instance_id_traveller_ptr;
5720 						result_instance_id_traveller_ptr += result_instance_id_stride;
5721 
5722 						retrieved_vertex_id = *result_vertex_id_traveller_ptr;
5723 						result_vertex_id_traveller_ptr += result_vertex_id_stride;
5724 
5725 						if ((result_instance_id_page_has_physical_backing &&
5726 							 retrieved_instance_id != expected_instance_id) ||
5727 							(result_vertex_id_page_has_physical_backing && retrieved_vertex_id != expected_vertex_id))
5728 						{
5729 							m_testCtx.getLog()
5730 								<< tcu::TestLog::Message << "For "
5731 															"["
5732 								<< getName() << "]"
5733 												", sparse BO flags "
5734 												"["
5735 								<< SparseBufferTestUtilities::getSparseBOFlagsString(sparse_bo_storage_flags)
5736 								<< "]"
5737 								   ", draw call type "
5738 								<< getDrawCallTypeString(draw_call_type) << " at index "
5739 																			"["
5740 								<< n_draw_call << " / " << (draw_call_count - 1) << "]"
5741 																					", TF mode "
5742 																					"["
5743 								<< ((is_ia_iteration) ? "interleaved attribs" : "separate attribs") << "]"
5744 								<< ", instance "
5745 								   "["
5746 								<< n_instance << " / " << (draw_call_n_instances[n_draw_call] - 1) << "]"
5747 								<< ", point at index "
5748 								   "["
5749 								<< n_point << " / " << (draw_call_n_vertices[n_draw_call] - 1) << "]"
5750 								<< ", VS-level gl_VertexID was equal to "
5751 								   "["
5752 								<< retrieved_vertex_id << "]"
5753 														  " and gl_InstanceID was set to "
5754 														  "["
5755 								<< retrieved_instance_id << "]"
5756 															", whereas gl_VertexID of value "
5757 															"["
5758 								<< expected_vertex_id << "]"
5759 														 " and gl_InstanceID of value "
5760 														 "["
5761 								<< expected_instance_id << "]"
5762 														   " were anticipated."
5763 								<< tcu::TestLog::EndMessage;
5764 
5765 							continue_checking = false;
5766 							result			  = false;
5767 
5768 							break;
5769 						} /* if (reported gl_InstanceID / gl_VertexID values are wrong) */
5770 					}	 /* for (all drawn points) */
5771 				}		  /* for (all instances) */
5772 
5773 				/* Release memory pages we have allocated for the transform feed-back.
5774 				 *
5775 				 * NOTE: For some iterations, this call will attempt to de-commit pages which
5776 				 *       have not been assigned physical backing. This is a valid behavior,
5777 				 *       as per spec.
5778 				 */
5779 				m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0,	 /* offset */
5780 											 m_result_bo_size_rounded, GL_FALSE); /* commit */
5781 				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5782 			} /* for (all draw call) */
5783 
5784 			m_gl.unmapBuffer(GL_ARRAY_BUFFER);
5785 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
5786 		} /* for (all draw call types) */
5787 	}	 /* for (both TF modes) */
5788 
5789 	return result;
5790 }
5791 
5792 /** Converts the internal enum to a null-terminated text string.
5793  *
5794  *  @param draw_call Draw call type to return a string for.
5795  *
5796  *  @return The requested string or "[?!]", if the enum was not recognized.
5797  **/
getDrawCallTypeString(_draw_call draw_call)5798 const char* TransformFeedbackBufferStorageTestCase::getDrawCallTypeString(_draw_call draw_call)
5799 {
5800 	const char* result = "[?!]";
5801 
5802 	switch (draw_call)
5803 	{
5804 	case DRAW_CALL_INDEXED:
5805 		result = "glDrawElements()";
5806 		break;
5807 	case DRAW_CALL_INDEXED_BASE_VERTEX:
5808 		result = "glDrawElementsBaseVertex()";
5809 		break;
5810 	case DRAW_CALL_INDEXED_INDIRECT:
5811 		result = "glDrawElementsIndirect()";
5812 		break;
5813 	case DRAW_CALL_INDEXED_INDIRECT_MULTI:
5814 		result = "glMultiDrawElementIndirect()";
5815 		break;
5816 	case DRAW_CALL_INDEXED_MULTI:
5817 		result = "glMultiDrawElements()";
5818 		break;
5819 	case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX:
5820 		result = "glMultiDrawElementsBaseVertex()";
5821 		break;
5822 	case DRAW_CALL_INSTANCED_INDEXED:
5823 		result = "glDrawElementsInstanced()";
5824 		break;
5825 	case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX:
5826 		result = "glDrawElementsInstancedBaseVertex()";
5827 		break;
5828 	case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE:
5829 		result = "glDrawElementsInstancedBaseVertexBaseInstance()";
5830 		break;
5831 	case DRAW_CALL_REGULAR:
5832 		result = "glDrawArrays()";
5833 		break;
5834 	case DRAW_CALL_REGULAR_INDIRECT:
5835 		result = "glDrawArraysIndirect()";
5836 		break;
5837 	case DRAW_CALL_REGULAR_INDIRECT_MULTI:
5838 		result = "glMultiDrawArraysIndirect()";
5839 		break;
5840 	case DRAW_CALL_REGULAR_INSTANCED:
5841 		result = "glDrawArraysInstanced()";
5842 		break;
5843 	case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE:
5844 		result = "glDrawArraysInstancedBaseInstance()";
5845 		break;
5846 	case DRAW_CALL_REGULAR_MULTI:
5847 		result = "glMultiDrawArrays()";
5848 		break;
5849 
5850 	default:
5851 		break;
5852 	} /* switch (draw_call) */
5853 
5854 	return result;
5855 }
5856 
5857 /** Initializes test data buffer, and then sets up:
5858  *
5859  *  - an immutable buffer object (id stored in m_data_bo), to which the test data
5860  *    is copied.
5861  *  - a mappable immutable buffer object (id stored in m_helper_bo)
5862  **/
initDataBO()5863 void TransformFeedbackBufferStorageTestCase::initDataBO()
5864 {
5865 	initTestData();
5866 
5867 	/* Initialize data BO (the BO which holds index + indirect draw call args */
5868 	DE_ASSERT(m_data_bo == 0);
5869 
5870 	m_gl.genBuffers(1, &m_data_bo);
5871 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
5872 
5873 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_data_bo);
5874 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5875 
5876 	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_data_bo_size, DE_NULL, GL_DYNAMIC_STORAGE_BIT);
5877 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
5878 
5879 	m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_indexed_indirect_arg_offset, m_indirect_arg_data_size,
5880 					   m_indirect_arg_data);
5881 	m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_index_data_offset, m_index_data_size, m_index_data);
5882 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call(s) failed.");
5883 
5884 	/* Generate & bind a helper BO we need to copy the data to from the sparse BO
5885 	 * if direct mapping is not possible.
5886 	 */
5887 	DE_ASSERT(m_result_bo_size != 0);
5888 	DE_ASSERT(m_result_bo == 0);
5889 	DE_ASSERT(m_helper_bo == 0);
5890 
5891 	m_gl.genBuffers(1, &m_helper_bo);
5892 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
5893 
5894 	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
5895 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5896 
5897 	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_result_bo_size, DE_NULL, /* data */
5898 					   GL_MAP_READ_BIT);
5899 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
5900 }
5901 
5902 /** Initializes GL objects used across all test case iterations.
5903  *
5904  *  Called once during BufferStorage test run-time.
5905  */
initTestCaseGlobal()5906 bool TransformFeedbackBufferStorageTestCase::initTestCaseGlobal()
5907 {
5908 	bool result = true;
5909 
5910 	/* Initialize test program object */
5911 	static const char*		  tf_varyings[] = { "instance_id", "vertex_id" };
5912 	static const unsigned int n_tf_varyings = sizeof(tf_varyings) / sizeof(tf_varyings[0]);
5913 	static const char*		  vs_body		= "#version 420 core\n"
5914 								 "\n"
5915 								 "out uint instance_id;\n"
5916 								 "out uint vertex_id;\n"
5917 								 "\n"
5918 								 "void main()\n"
5919 								 "{\n"
5920 								 "    instance_id = gl_InstanceID;\n"
5921 								 "    vertex_id   = gl_VertexID;\n"
5922 								 "}\n";
5923 
5924 	m_po_ia = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
5925 													   0,			  /* n_fs_body_parts */
5926 													   &vs_body, 1,   /* n_vs_body_parts */
5927 													   DE_NULL,		  /* attribute_names */
5928 													   DE_NULL,		  /* attribute_locations */
5929 													   0,			  /* n_attribute_properties */
5930 													   tf_varyings, n_tf_varyings, GL_INTERLEAVED_ATTRIBS);
5931 
5932 	m_po_sa = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
5933 													   0,			  /* n_fs_body_parts */
5934 													   &vs_body, 1,   /* n_vs_body_parts */
5935 													   DE_NULL,		  /* attribute_names */
5936 													   DE_NULL,		  /* attribute_locations */
5937 													   0,			  /* n_attribute_properties */
5938 													   tf_varyings, n_tf_varyings, GL_SEPARATE_ATTRIBS);
5939 
5940 	if (m_po_ia == 0 || m_po_sa == 0)
5941 	{
5942 		result = false;
5943 
5944 		goto end;
5945 	}
5946 
5947 	/* Generate & bind a VAO */
5948 	m_gl.genVertexArrays(1, &m_vao);
5949 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
5950 
5951 	m_gl.bindVertexArray(m_vao);
5952 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
5953 
5954 	initDataBO();
5955 
5956 end:
5957 	return result;
5958 }
5959 
5960 /** Initializes GL objects which are needed for a single test case iteration.
5961  *
5962  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
5963  *  to release these objects.
5964  **/
initTestCaseIteration(glw::GLuint sparse_bo)5965 bool TransformFeedbackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
5966 {
5967 	bool result = true;
5968 
5969 	/* Initialize buffer objects used by the test case */
5970 	m_result_bo = sparse_bo;
5971 
5972 	/* Sanity check */
5973 	DE_ASSERT(m_data_bo != 0);
5974 
5975 	return result;
5976 }
5977 
5978 /** Sets up client-side data arrays, later uploaded to the test buffer object, used as a source for:
5979  *
5980  *  - index data
5981  *  - indirect draw call arguments
5982  *  - multi draw call arguments
5983  **/
initTestData()5984 void TransformFeedbackBufferStorageTestCase::initTestData()
5985 {
5986 	/* We need the result data to span across at least m_min_memory_page_span memory pages.
5987 	 * Each vertex outputs 2 * sizeof(int) = 8 bytes of data.
5988 	 *
5989 	 * For simplicity, we assume the number of bytes we calculate here is per instance. */
5990 	m_n_vertices_per_instance = static_cast<unsigned int>((m_page_size * m_min_memory_page_span / (sizeof(int) * 2)));
5991 
5992 	/* Let:
5993 	 *
5994 	 *     index_data_size       = (n of vertices per a single instance) * sizeof(unsigned int)
5995 	 *     indexed_indirect_size = sizeof(glDrawElementsIndirect()      indirect arguments)
5996 	 *     indexed_mdi_size      = sizeof(glMultiDrawElementsIndirect() indirect arguments) * 2 (single instance & multiple instances case)
5997 	 *     regular_indirect_size = sizeof(glDrawArraysIndirect()        indirect arguments)
5998 	 *     regular_mdi_size      = sizeof(glMultiDrawArraysIndirect()   indirect arguments) * 2 (single instance & multiple instances case)
5999 	 *
6000 	 *
6001 	 * The layout we will use for the data buffer is:
6002 	 *
6003 	 * [indexed indirect arg data // Size: indexed_indirect_size bytes]
6004 	 * [indexed MDI arg data      // Size: indexed_mdi_size      bytes]
6005 	 * [regular indirect arg data // Size: regular_indirect_size bytes]
6006 	 * [regular MDI arg data      // Size: regular_mdi_size      bytes]
6007 	 * [index data                // Size: index_data_size       bytes]
6008 	 */
6009 	const unsigned int indexed_indirect_size = sizeof(unsigned int) * 5 /* as per GL spec */;
6010 	const unsigned int indexed_mdi_size		 = sizeof(unsigned int) * 5 /* as per GL spec */ * 2; /* draw calls */
6011 	const unsigned int regular_indirect_size = sizeof(unsigned int) * 4;						  /* as per GL spec */
6012 	const unsigned int regular_mdi_size		 = sizeof(unsigned int) * 4 /* as per GL spec */ * 2; /* draw calls */
6013 
6014 	m_data_bo_indexed_indirect_arg_offset = 0;
6015 	m_data_bo_indexed_mdi_arg_offset	  = m_data_bo_indexed_indirect_arg_offset + indexed_indirect_size;
6016 	m_data_bo_regular_indirect_arg_offset = m_data_bo_indexed_mdi_arg_offset + indexed_mdi_size;
6017 	m_data_bo_regular_mdi_arg_offset	  = m_data_bo_regular_indirect_arg_offset + regular_indirect_size;
6018 	m_data_bo_index_data_offset			  = m_data_bo_regular_mdi_arg_offset + regular_mdi_size;
6019 
6020 	/* Form the index data */
6021 	DE_ASSERT(m_index_data == DE_NULL);
6022 	DE_ASSERT(m_draw_call_firstIndex == sizeof(unsigned int));
6023 
6024 	m_index_data_size = static_cast<glw::GLuint>(
6025 		(1 /* extra index, as per m_draw_call_firstIndex */ + m_n_vertices_per_instance) * sizeof(unsigned int));
6026 	m_index_data = (unsigned int*)new unsigned char[m_index_data_size];
6027 
6028 	for (unsigned int n_index = 0; n_index < m_n_vertices_per_instance + 1; ++n_index)
6029 	{
6030 		m_index_data[n_index] = m_n_vertices_per_instance - n_index;
6031 	} /* for (all available indices) */
6032 
6033 	/* Set multi draw-call arguments */
6034 	m_multidrawcall_basevertex[0] = m_draw_call_baseVertex;
6035 	m_multidrawcall_basevertex[1] = 257;
6036 	m_multidrawcall_count[0]	  = m_n_vertices_per_instance;
6037 	m_multidrawcall_count[1]	  = m_n_vertices_per_instance - 16;
6038 	m_multidrawcall_drawcount	 = 2;
6039 	m_multidrawcall_first[0]	  = 0;
6040 	m_multidrawcall_first[1]	  = m_draw_call_first;
6041 	m_multidrawcall_index[0]	  = (glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset;
6042 	m_multidrawcall_index[1]	  = (glw::GLvoid*)(intptr_t)(m_data_bo_index_data_offset + m_draw_call_firstIndex);
6043 	m_multidrawcall_primcount	 = m_n_instances_to_test;
6044 
6045 	/* Form the indirect data */
6046 	DE_ASSERT(m_indirect_arg_data == DE_NULL);
6047 
6048 	m_indirect_arg_data_size = m_data_bo_index_data_offset - m_data_bo_indexed_indirect_arg_offset;
6049 	m_indirect_arg_data		 = (unsigned int*)new unsigned char[m_indirect_arg_data_size];
6050 
6051 	unsigned int* indirect_arg_data_traveller_ptr = m_indirect_arg_data;
6052 
6053 	/* 1. Indexed indirect arg data */
6054 	DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[1]) % sizeof(unsigned int)) == 0);
6055 
6056 	*indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */
6057 	indirect_arg_data_traveller_ptr++;
6058 
6059 	*indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */
6060 	indirect_arg_data_traveller_ptr++;
6061 
6062 	*indirect_arg_data_traveller_ptr = static_cast<unsigned int>((unsigned int)(intptr_t)(m_multidrawcall_index[1]) /
6063 																 sizeof(unsigned int)); /* firstIndex */
6064 	indirect_arg_data_traveller_ptr++;
6065 
6066 	*indirect_arg_data_traveller_ptr = m_draw_call_baseVertex; /* baseVertex */
6067 	indirect_arg_data_traveller_ptr++;
6068 
6069 	*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6070 	indirect_arg_data_traveller_ptr++;
6071 
6072 	/* 2. Indexed MDI arg data */
6073 	for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call)
6074 	{
6075 		DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) % sizeof(unsigned int)) == 0);
6076 
6077 		*indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */
6078 		indirect_arg_data_traveller_ptr++;
6079 
6080 		*indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* primCount */
6081 		indirect_arg_data_traveller_ptr++;
6082 
6083 		*indirect_arg_data_traveller_ptr = static_cast<unsigned int>(
6084 			(unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) / sizeof(unsigned int)); /* firstIndex */
6085 		indirect_arg_data_traveller_ptr++;
6086 
6087 		*indirect_arg_data_traveller_ptr = m_draw_call_baseVertex;
6088 		indirect_arg_data_traveller_ptr++;
6089 
6090 		*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance;
6091 		indirect_arg_data_traveller_ptr++;
6092 	} /* for (both single-instanced and multi-instanced cases) */
6093 
6094 	/* 3. Regular indirect arg data */
6095 	*indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */
6096 	indirect_arg_data_traveller_ptr++;
6097 
6098 	*indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */
6099 	indirect_arg_data_traveller_ptr++;
6100 
6101 	*indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */
6102 	indirect_arg_data_traveller_ptr++;
6103 
6104 	*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6105 	indirect_arg_data_traveller_ptr++;
6106 
6107 	/* 4. Regular MDI arg data */
6108 	for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call)
6109 	{
6110 		*indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */
6111 		indirect_arg_data_traveller_ptr++;
6112 
6113 		*indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* instanceCount */
6114 		indirect_arg_data_traveller_ptr++;
6115 
6116 		*indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */
6117 		indirect_arg_data_traveller_ptr++;
6118 
6119 		*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6120 		indirect_arg_data_traveller_ptr++;
6121 	} /* for (both single-instanced and multi-instanced cases) */
6122 
6123 	/* Store the number of bytes we will need to allocate for the data BO */
6124 	m_data_bo_size = m_index_data_size + m_indirect_arg_data_size;
6125 
6126 	/* Determine the number of bytes we will need to have at hand to hold all the captured TF varyings.
6127 	 * The equation below takes into account the heaviest draw call the test will ever issue.
6128 	 */
6129 	m_result_bo_size =
6130 		static_cast<glw::GLuint>(sizeof(unsigned int) * 2 /* TF varyings per vertex */ *
6131 								 (m_multidrawcall_count[0] + m_multidrawcall_count[1]) * m_multidrawcall_primcount);
6132 	m_result_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_result_bo_size, m_page_size);
6133 
6134 	/* Sanity checks */
6135 	DE_ASSERT(m_min_memory_page_span > 0);
6136 	DE_ASSERT(m_page_size > 0);
6137 	DE_ASSERT(m_result_bo_size >= (m_min_memory_page_span * m_page_size));
6138 }
6139 
6140 /** Constructor.
6141  *
6142  *  @param gl                         GL entry-points container
6143  *  @param testContext                CTS test context
6144  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
6145  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
6146  */
UniformBufferStorageTestCase(const glw::Functions & gl,tcu::TestContext & testContext,glw::GLint page_size)6147 UniformBufferStorageTestCase::UniformBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
6148 														   glw::GLint page_size)
6149 	: m_gl(gl)
6150 	, m_gl_uniform_buffer_offset_alignment_value(0)
6151 	, m_helper_bo(0)
6152 	, m_n_pages_to_use(4)
6153 	, m_n_ubo_uints(0)
6154 	, m_page_size(page_size)
6155 	, m_po(0)
6156 	, m_sparse_bo(0)
6157 	, m_sparse_bo_data_size(0)
6158 	, m_sparse_bo_data_start_offset(0)
6159 	, m_sparse_bo_size(0)
6160 	, m_sparse_bo_size_rounded(0)
6161 	, m_testCtx(testContext)
6162 	, m_tf_bo(0)
6163 	, m_ubo_data(DE_NULL)
6164 	, m_vao(0)
6165 {
6166 	if ((m_n_pages_to_use % 2) != 0)
6167 	{
6168 		DE_ASSERT(DE_FALSE);
6169 	}
6170 }
6171 
6172 /** Releases all GL objects used across all test case iterations.
6173  *
6174  *  Called once during BufferStorage test run-time.
6175  */
deinitTestCaseGlobal()6176 void UniformBufferStorageTestCase::deinitTestCaseGlobal()
6177 {
6178 	if (m_helper_bo != 0)
6179 	{
6180 		m_gl.deleteBuffers(1, &m_helper_bo);
6181 
6182 		m_helper_bo = 0;
6183 	}
6184 
6185 	if (m_po != 0)
6186 	{
6187 		m_gl.deleteProgram(m_po);
6188 
6189 		m_po = 0;
6190 	}
6191 
6192 	if (m_tf_bo != 0)
6193 	{
6194 		m_gl.deleteBuffers(1, &m_tf_bo);
6195 
6196 		m_tf_bo = 0;
6197 	}
6198 
6199 	if (m_ubo_data != DE_NULL)
6200 	{
6201 		delete[] m_ubo_data;
6202 
6203 		m_ubo_data = DE_NULL;
6204 	}
6205 
6206 	if (m_vao != 0)
6207 	{
6208 		m_gl.deleteVertexArrays(1, &m_vao);
6209 
6210 		m_vao = 0;
6211 	}
6212 }
6213 
6214 /** Releases temporary GL objects, created specifically for one test case iteration. */
deinitTestCaseIteration()6215 void UniformBufferStorageTestCase::deinitTestCaseIteration()
6216 {
6217 	if (m_sparse_bo != 0)
6218 	{
6219 		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6220 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6221 
6222 		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
6223 									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
6224 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6225 
6226 		m_sparse_bo = 0;
6227 	}
6228 }
6229 
6230 /** Executes a single test iteration. The BufferStorage test will call this method
6231  *  numerously during its life-time, testing various valid flag combinations applied
6232  *  to the tested sparse buffer object at glBufferStorage() call time.
6233  *
6234  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
6235  *                                 call to set up the sparse buffer's storage.
6236  *
6237  *  @return true if the test case executed correctly, false otherwise.
6238  */
execute(glw::GLuint sparse_bo_storage_flags)6239 bool UniformBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
6240 {
6241 	(void)sparse_bo_storage_flags;
6242 	bool result = true;
6243 
6244 	m_gl.bindBufferRange(GL_UNIFORM_BUFFER, 0, /* index */
6245 						 m_sparse_bo, m_sparse_bo_data_start_offset, m_sparse_bo_data_size);
6246 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
6247 
6248 	/* Run the test in three iterations:
6249 	 *
6250 	 * 1) Whole UBO storage is backed by physical backing.
6251 	 * 2) Half the UBO storage is backed by physical backing.
6252 	 * 3) None of the UBO storage is backed by physical backing.
6253 	 */
6254 	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
6255 	{
6256 		bool		 result_local			 = true;
6257 		unsigned int ubo_commit_size		 = 0;
6258 		unsigned int ubo_commit_start_offset = 0;
6259 
6260 		switch (n_iteration)
6261 		{
6262 		case 0:
6263 		{
6264 			ubo_commit_size			= m_sparse_bo_data_size;
6265 			ubo_commit_start_offset = m_sparse_bo_data_start_offset;
6266 
6267 			break;
6268 		}
6269 
6270 		case 1:
6271 		{
6272 			DE_ASSERT((m_sparse_bo_data_size % 2) == 0);
6273 			DE_ASSERT((m_sparse_bo_data_size % m_page_size) == 0);
6274 
6275 			ubo_commit_size			= m_sparse_bo_data_size / 2;
6276 			ubo_commit_start_offset = m_sparse_bo_data_start_offset;
6277 
6278 			break;
6279 		}
6280 
6281 		case 2:
6282 		{
6283 			/* The default values do just fine */
6284 
6285 			break;
6286 		}
6287 
6288 		default:
6289 		{
6290 			TCU_FAIL("Invalid iteration index");
6291 		}
6292 		} /* switch (n_iteration) */
6293 
6294 		m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, ubo_commit_start_offset, ubo_commit_size, GL_TRUE); /* commit */
6295 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6296 
6297 		/* Copy the UBO data */
6298 		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
6299 							   ubo_commit_start_offset, ubo_commit_size);
6300 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
6301 
6302 		/* Issue the draw call to execute the test */
6303 		m_gl.useProgram(m_po);
6304 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
6305 
6306 		m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6307 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6308 
6309 		m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
6310 							m_tf_bo);
6311 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
6312 
6313 		m_gl.beginTransformFeedback(GL_POINTS);
6314 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed.");
6315 
6316 		m_gl.drawArrays(GL_POINTS, 0, /* first */
6317 						m_n_ubo_uints);
6318 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
6319 
6320 		m_gl.endTransformFeedback();
6321 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed.");
6322 
6323 		/* Retrieve the data, verify the output */
6324 		const unsigned int* result_data_ptr =
6325 			(const unsigned int*)m_gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
6326 		unsigned int ubo_data_offset = m_sparse_bo_data_start_offset;
6327 
6328 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
6329 
6330 		for (unsigned int n_vertex = 0; n_vertex < m_n_ubo_uints && result_local;
6331 			 ++n_vertex, ubo_data_offset = static_cast<unsigned int>(ubo_data_offset + 4 * sizeof(unsigned int)))
6332 		{
6333 			const bool is_ub_data_physically_backed = (ubo_data_offset >= ubo_commit_start_offset &&
6334 													   ubo_data_offset < (ubo_commit_start_offset + ubo_commit_size)) ?
6335 														  1 :
6336 														  0;
6337 			unsigned int	   expected_value  = -1;
6338 			const unsigned int retrieved_value = result_data_ptr[n_vertex];
6339 
6340 			if (is_ub_data_physically_backed)
6341 			{
6342 				expected_value = 1;
6343 			}
6344 			else
6345 			{
6346 				/* Read ops applied against non-committed sparse buffers return an undefined value.
6347 				 */
6348 				continue;
6349 			}
6350 
6351 			if (expected_value != retrieved_value)
6352 			{
6353 				m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value "
6354 															   "("
6355 								   << retrieved_value << ") "
6356 														 "found at index "
6357 														 "("
6358 								   << n_vertex << ")"
6359 												  ", instead of the expected value "
6360 												  "("
6361 								   << expected_value << ")"
6362 														". Iteration index:"
6363 														"("
6364 								   << n_iteration << ")" << tcu::TestLog::EndMessage;
6365 
6366 				result_local = false;
6367 			}
6368 		}
6369 
6370 		result &= result_local;
6371 
6372 		/* Clean up in anticipation for the next iteration */
6373 		static const unsigned char data_zero_r8 = 0;
6374 
6375 		m_gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
6376 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
6377 
6378 		m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero_r8);
6379 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
6380 
6381 		m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */
6382 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6383 	} /* for (all three iterations) */
6384 
6385 	return result;
6386 }
6387 
6388 /** Initializes GL objects used across all test case iterations.
6389  *
6390  *  Called once during BufferStorage test run-time.
6391  */
initTestCaseGlobal()6392 bool UniformBufferStorageTestCase::initTestCaseGlobal()
6393 {
6394 	/* Cache GL constant values */
6395 	glw::GLint gl_max_uniform_block_size_value = 0;
6396 
6397 	m_gl.getIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gl_max_uniform_block_size_value);
6398 	m_gl.getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_gl_uniform_buffer_offset_alignment_value);
6399 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call(s) failed.");
6400 
6401 	/* Determine the number of uints we can access at once from a single VS invocation */
6402 	DE_ASSERT(gl_max_uniform_block_size_value >= 1);
6403 
6404 	/* Account for the fact that in std140 layout, array elements will be rounded up
6405 	 * to the size of a vec4, i.e. 16 bytes. */
6406 	m_n_ubo_uints = static_cast<unsigned int>(gl_max_uniform_block_size_value / (4 * sizeof(unsigned int)));
6407 
6408 	/* Prepare the test program */
6409 	std::stringstream vs_body_define_sstream;
6410 	std::string		  vs_body_define_string;
6411 
6412 	const char* tf_varying		 = "result";
6413 	const char* vs_body_preamble = "#version 140\n"
6414 								   "\n";
6415 
6416 	const char* vs_body_main = "\n"
6417 							   "layout(std140) uniform data\n"
6418 							   "{\n"
6419 							   "    uint data_input[N_UBO_UINTS];"
6420 							   "};\n"
6421 							   "\n"
6422 							   "out uint result;\n"
6423 							   "\n"
6424 							   "void main()\n"
6425 							   "{\n"
6426 							   "    result = (data_input[gl_VertexID] == uint(gl_VertexID) ) ? 1u : 0u;\n"
6427 							   "}";
6428 
6429 	vs_body_define_sstream << "#define N_UBO_UINTS (" << m_n_ubo_uints << ")\n";
6430 	vs_body_define_string = vs_body_define_sstream.str();
6431 
6432 	const char*		   vs_body_parts[] = { vs_body_preamble, vs_body_define_string.c_str(), vs_body_main };
6433 	const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]);
6434 
6435 	m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL,							 /* fs_body_parts */
6436 													0,										 /* n_fs_body_parts */
6437 													vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names */
6438 													DE_NULL,								 /* attribute_locations */
6439 													0,				/* n_attribute_properties */
6440 													&tf_varying, 1, /* n_tf_varyings */
6441 													GL_INTERLEAVED_ATTRIBS);
6442 
6443 	if (m_po == 0)
6444 	{
6445 		TCU_FAIL("The test program failed to link");
6446 	}
6447 
6448 	/* Determine the number of bytes the sparse buffer needs to be able to have
6449 	 * a physical backing or.
6450 	 *
6451 	 * We will provide physical backing for twice the required size and then use
6452 	 * a region in the centered of the allocated memory block.
6453 	 *
6454 	 * NOTE: We need to be able to use an offset which is aligned to both the page size,
6455 	 *       and the UB offset alignment.
6456 	 * */
6457 	m_sparse_bo_data_size = static_cast<unsigned int>(sizeof(unsigned int) * m_page_size);
6458 	m_sparse_bo_size	  = (m_page_size * m_gl_uniform_buffer_offset_alignment_value) * 2;
6459 
6460 	if (m_sparse_bo_size < m_sparse_bo_data_size * 2)
6461 	{
6462 		m_sparse_bo_size = m_sparse_bo_data_size * 2;
6463 	}
6464 
6465 	m_sparse_bo_size_rounded	  = m_sparse_bo_size; /* rounded to the page size by default */
6466 	m_sparse_bo_data_start_offset = (m_sparse_bo_size - m_sparse_bo_data_size) / 2;
6467 
6468 	/* Set up the TFBO storage */
6469 	const unsigned tfbo_size = static_cast<unsigned int>(sizeof(unsigned int) * m_n_ubo_uints);
6470 
6471 	m_gl.genBuffers(1, &m_tf_bo);
6472 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
6473 
6474 	m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6475 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6476 
6477 	m_gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, tfbo_size, DE_NULL, /* data */
6478 					   GL_MAP_READ_BIT);
6479 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
6480 
6481 	/* Set up the UBO contents. We're actually setting up an immutable BO here,
6482 	 * but we'll use its contents for a copy op, executed at the beginning of
6483 	 * each iteration.
6484 	 */
6485 	unsigned int* ubo_data_traveller_ptr = DE_NULL;
6486 
6487 	DE_ASSERT((m_sparse_bo_data_size % sizeof(unsigned int)) == 0);
6488 
6489 	m_ubo_data			   = new (std::nothrow) unsigned char[m_sparse_bo_data_size];
6490 	ubo_data_traveller_ptr = (unsigned int*)m_ubo_data;
6491 
6492 	for (unsigned int n_vertex = 0; n_vertex < m_sparse_bo_data_size / (4 * sizeof(unsigned int)); ++n_vertex)
6493 	{
6494 		*ubo_data_traveller_ptr = n_vertex;
6495 		ubo_data_traveller_ptr += 4;
6496 	}
6497 
6498 	m_gl.genBuffers(1, &m_helper_bo);
6499 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
6500 
6501 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
6502 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6503 
6504 	/* Set up helper BO storage */
6505 	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_data_size, m_ubo_data, 0); /* flags */
6506 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
6507 
6508 	/* Set up the VAO */
6509 	m_gl.genVertexArrays(1, &m_vao);
6510 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
6511 
6512 	m_gl.bindVertexArray(m_vao);
6513 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
6514 
6515 	return true;
6516 }
6517 
6518 /** Initializes GL objects which are needed for a single test case iteration.
6519  *
6520  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
6521  *  to release these objects.
6522  **/
initTestCaseIteration(glw::GLuint sparse_bo)6523 bool UniformBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
6524 {
6525 	bool result = true;
6526 
6527 	/* Cache the BO id, if not cached already */
6528 	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
6529 
6530 	m_sparse_bo = sparse_bo;
6531 
6532 	/* Set up the sparse buffer bindings. */
6533 	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
6534 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
6535 
6536 	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
6537 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6538 
6539 	m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6540 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6541 
6542 	return result;
6543 }
6544 
6545 /** Constructor.
6546  *
6547  *  @param context     Rendering context
6548  *  @param name        Test name
6549  *  @param description Test description
6550  */
BufferStorageTest(deqp::Context & context)6551 BufferStorageTest::BufferStorageTest(deqp::Context& context)
6552 	: TestCase(context, "BufferStorageTest", "Tests various interactions between sparse buffers and other API areas")
6553 	, m_sparse_bo(0)
6554 {
6555 	/* Left blank intentionally */
6556 }
6557 
6558 /** Tears down any GL objects set up to run the test. */
deinit()6559 void BufferStorageTest::deinit()
6560 {
6561 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6562 
6563 	/* De-initialize all test the test cases */
6564 	for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6565 	{
6566 		(*itTestCase)->deinitTestCaseGlobal();
6567 
6568 		delete (*itTestCase);
6569 	} /* for (all registered test case objects) */
6570 
6571 	m_testCases.clear();
6572 
6573 	if (m_sparse_bo != 0)
6574 	{
6575 		gl.deleteBuffers(1, &m_sparse_bo);
6576 
6577 		m_sparse_bo = 0;
6578 	}
6579 }
6580 
6581 /** Stub init method */
init()6582 void BufferStorageTest::init()
6583 {
6584 	/* We cannot initialize the test case objects here as there are cases where there
6585 	 * is no rendering context bound to the thread, when this method is called. */
6586 }
6587 
6588 /** Fills m_testCases with BufferStorageTestCase instances which implement the sub-cases
6589  *  for the second test described in the CTS_ARB_sparse_buffer test specification
6590  **/
initTestCases()6591 void BufferStorageTest::initTestCases()
6592 {
6593 	const glw::Functions& gl		= m_context.getRenderContext().getFunctions();
6594 	glw::GLint			  page_size = 0;
6595 
6596 	/* Retrieve "sparse buffer" GL constant values and entry-point func ptrs */
6597 	gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size);
6598 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname");
6599 
6600 	/* Initialize all test case objects:
6601 	 *
6602 	 * Test cases a1-a6 */
6603 	m_testCases.push_back(new QuadsBufferStorageTestCase(
6604 		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_NONE, false)); /* use_color_data */
6605 	m_testCases.push_back(new QuadsBufferStorageTestCase(
6606 		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, false)); /* use_color_data */
6607 	m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size,
6608 														 QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL,
6609 														 false)); /* use_color_data */
6610 	m_testCases.push_back(new QuadsBufferStorageTestCase(
6611 		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, true)); /* use_color_data */
6612 	m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size,
6613 														 QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL,
6614 														 true)); /* use_color_data */
6615 
6616 	/* Test case b1 */
6617 	m_testCases.push_back(
6618 		new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_tf_pages_committed */
6619 
6620 	/* Test case b2 */
6621 	m_testCases.push_back(
6622 		new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_tf_pages_committed */
6623 
6624 	/* Test case c */
6625 	m_testCases.push_back(new ClearOpsBufferStorageTestCase(gl, m_testCtx, page_size));
6626 
6627 	/* Test case d */
6628 	m_testCases.push_back(new InvalidateBufferStorageTestCase(gl, m_testCtx, page_size));
6629 
6630 	/* Test case e */
6631 	m_testCases.push_back(
6632 		new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_pages_committed */
6633 	m_testCases.push_back(
6634 		new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_pages_committed */
6635 
6636 	/* Test case f */
6637 	m_testCases.push_back(new BufferTextureStorageTestCase(gl, m_context, m_testCtx, page_size));
6638 
6639 	/* Test case g */
6640 	m_testCases.push_back(new CopyOpsBufferStorageTestCase(gl, m_testCtx, page_size));
6641 
6642 	/* Test case h */
6643 	m_testCases.push_back(new IndirectDispatchBufferStorageTestCase(gl, m_testCtx, page_size));
6644 
6645 	/* Test case i */
6646 	m_testCases.push_back(new SSBOStorageTestCase(gl, m_testCtx, page_size));
6647 
6648 	/* Test case j */
6649 	m_testCases.push_back(new UniformBufferStorageTestCase(gl, m_testCtx, page_size));
6650 
6651 	/* Test case k */
6652 	m_testCases.push_back(new PixelPackBufferStorageTestCase(gl, m_testCtx, page_size));
6653 
6654 	/* Test case l */
6655 	m_testCases.push_back(new PixelUnpackBufferStorageTestCase(gl, m_testCtx, page_size));
6656 
6657 	/* Test case m */
6658 	m_testCases.push_back(new QueryBufferStorageTestCase(gl, m_testCtx, page_size));
6659 
6660 	/* Initialize all test cases */
6661 	for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6662 	{
6663 		(*itTestCase)->initTestCaseGlobal();
6664 	}
6665 }
6666 
6667 /** Executes test iteration.
6668  *
6669  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
6670  */
iterate()6671 tcu::TestNode::IterateResult BufferStorageTest::iterate()
6672 {
6673 	const glw::Functions& gl	 = m_context.getRenderContext().getFunctions();
6674 	bool				  result = true;
6675 
6676 	/* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
6677 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
6678 	{
6679 		throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
6680 	}
6681 
6682 	/* The buffer storage test cases require OpenGL 4.3 feature-set. */
6683 	if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)))
6684 	{
6685 		throw tcu::NotSupportedError("GL_ARB_sparse_buffer conformance tests require OpenGL 4.3 core feature-set");
6686 	}
6687 
6688 	/* Register & initialize the test case objects */
6689 	initTestCases();
6690 
6691 	/* Iterate over all sparse BO flag combinations. We need to consider a total of 4 flags:
6692 	 *
6693 	 * - GL_CLIENT_STORAGE_BIT  (bit 0)
6694 	 * - GL_DYNAMIC_STORAGE_BIT (bit 1)
6695 	 * - GL_MAP_COHERENT_BIT    (bit 2)
6696 	 * - GL_MAP_PERSISTENT_BIT  (bit 3)
6697 	 *
6698 	 *  GL_MAP_READ_BIT and GL_MAP_WRITE_BIT are excluded, since they are incompatible
6699 	 *  with sparse buffers by definition.
6700 	 *
6701 	 *  GL_SPARSE_STORAGE_BIT_ARB is assumed to be always defined. Some of the combinations are invalid.
6702 	 *  Such loop iterations will be skipped.
6703 	 * */
6704 
6705 	for (unsigned int n_flag_combination = 0; n_flag_combination < (1 << 4); ++n_flag_combination)
6706 	{
6707 		const glw::GLint flags = ((n_flag_combination & (1 << 0)) ? GL_CLIENT_STORAGE_BIT : 0) |
6708 								 ((n_flag_combination & (1 << 1)) ? GL_DYNAMIC_STORAGE_BIT : 0) |
6709 								 ((n_flag_combination & (1 << 2)) ? GL_MAP_COHERENT_BIT : 0) |
6710 								 ((n_flag_combination & (1 << 3)) ? GL_MAP_PERSISTENT_BIT : 0) |
6711 								 GL_SPARSE_STORAGE_BIT_ARB;
6712 
6713 		if ((flags & GL_MAP_PERSISTENT_BIT) != 0)
6714 		{
6715 			if ((flags & GL_MAP_READ_BIT) == 0 && (flags & GL_MAP_WRITE_BIT) == 0)
6716 			{
6717 				continue;
6718 			}
6719 		}
6720 
6721 		if (((flags & GL_MAP_COHERENT_BIT) != 0) && ((flags & GL_MAP_PERSISTENT_BIT) == 0))
6722 		{
6723 			continue;
6724 		}
6725 
6726 		/* Set up the sparse BO */
6727 		gl.genBuffers(1, &m_sparse_bo);
6728 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
6729 
6730 		gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6731 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
6732 
6733 		gl.bufferStorage(GL_ARRAY_BUFFER, 1024768 * 1024, /* as per test spec */
6734 						 DE_NULL,						  /* data */
6735 						 flags);
6736 
6737 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call failed.");
6738 
6739 		for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6740 		{
6741 			gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6742 			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
6743 
6744 			if (!(*itTestCase)->initTestCaseIteration(m_sparse_bo))
6745 			{
6746 				m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName()
6747 								   << "] "
6748 									  "has failed to initialize."
6749 								   << tcu::TestLog::EndMessage;
6750 
6751 				result = false;
6752 				goto end;
6753 			}
6754 
6755 			if (!(*itTestCase)->execute(flags))
6756 			{
6757 				m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName()
6758 								   << "] "
6759 									  "has failed to execute correctly."
6760 								   << tcu::TestLog::EndMessage;
6761 
6762 				result = false;
6763 			} /* if (!testCaseResult) */
6764 
6765 			(*itTestCase)->deinitTestCaseIteration();
6766 		} /* for (all added test cases) */
6767 
6768 		/* Release the sparse BO */
6769 		gl.deleteBuffers(1, &m_sparse_bo);
6770 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() call failed.");
6771 
6772 		m_sparse_bo = 0;
6773 	}
6774 
6775 end:
6776 	m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
6777 
6778 	return STOP;
6779 }
6780 
6781 /** Constructor.
6782  *
6783  *  @param context Rendering context.
6784  */
SparseBufferTests(deqp::Context & context)6785 SparseBufferTests::SparseBufferTests(deqp::Context& context)
6786 	: TestCaseGroup(context, "sparse_buffer_tests", "Verify conformance of CTS_ARB_sparse_buffer implementation")
6787 {
6788 }
6789 
6790 /** Initializes the test group contents. */
init()6791 void SparseBufferTests::init()
6792 {
6793 	addChild(new BufferStorageTest(m_context));
6794 	addChild(new NegativeTests(m_context));
6795 	addChild(new PageSizeGetterTest(m_context));
6796 }
6797 
6798 } /* gl4cts namespace */
6799