1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-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  gl4cPipelineStatisticsQueryTests.cpp
27  * \brief Implements conformance tests for GL_ARB_pipeline_statistics_query functionality
28  */ /*-------------------------------------------------------------------*/
29 
30 #include "gl4cPipelineStatisticsQueryTests.hpp"
31 #include "gluContextInfo.hpp"
32 #include "gluDefs.hpp"
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 #include "tcuRenderTarget.hpp"
36 #include "tcuTestLog.hpp"
37 
38 #include <string>
39 #include <vector>
40 
41 #ifndef GL_VERTICES_SUBMITTED_ARB
42 #define GL_VERTICES_SUBMITTED_ARB (0x82EE)
43 #endif
44 #ifndef GL_PRIMITIVES_SUBMITTED_ARB
45 #define GL_PRIMITIVES_SUBMITTED_ARB (0x82EF)
46 #endif
47 #ifndef GL_VERTEX_SHADER_INVOCATIONS_ARB
48 #define GL_VERTEX_SHADER_INVOCATIONS_ARB (0x82F0)
49 #endif
50 #ifndef GL_TESS_CONTROL_SHADER_PATCHES_ARB
51 #define GL_TESS_CONTROL_SHADER_PATCHES_ARB (0x82F1)
52 #endif
53 #ifndef GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB
54 #define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB (0x82F2)
55 #endif
56 #ifndef GL_GEOMETRY_SHADER_INVOCATIONS
57 #define GL_GEOMETRY_SHADER_INVOCATIONS (0x887F)
58 #endif
59 #ifndef GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB
60 #define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB (0x82F3)
61 #endif
62 #ifndef GL_FRAGMENT_SHADER_INVOCATIONS_ARB
63 #define GL_FRAGMENT_SHADER_INVOCATIONS_ARB (0x82F4)
64 #endif
65 #ifndef GL_COMPUTE_SHADER_INVOCATIONS_ARB
66 #define GL_COMPUTE_SHADER_INVOCATIONS_ARB (0x82F5)
67 #endif
68 #ifndef GL_CLIPPING_INPUT_PRIMITIVES_ARB
69 #define GL_CLIPPING_INPUT_PRIMITIVES_ARB (0x82F6)
70 #endif
71 #ifndef GL_CLIPPING_OUTPUT_PRIMITIVES_ARB
72 #define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB (0x82F7)
73 #endif
74 
75 namespace glcts
76 {
77 const char* PipelineStatisticsQueryUtilities::minimal_cs_code =
78 	"#version 430\n"
79 	"\n"
80 	"layout(local_size_x=1, local_size_y = 1, local_size_z = 1) in;\n"
81 	"\n"
82 	"layout(binding = 0) uniform atomic_uint test_counter;\n"
83 	"\n"
84 	"void main()\n"
85 	"{\n"
86 	"    atomicCounterIncrement(test_counter);\n"
87 	"}\n";
88 
89 const char* PipelineStatisticsQueryUtilities::minimal_cs_code_arb =
90 	"#version 420 core\n"
91 	"#extension GL_ARB_compute_shader : require\n"
92 	"#extension GL_ARB_shader_atomic_counters : require\n"
93 	"\n"
94 	"layout(local_size_x=1, local_size_y = 1, local_size_z = 1) in;\n"
95 	"\n"
96 	"layout(binding = 0) uniform atomic_uint test_counter;\n"
97 	"\n"
98 	"void main()\n"
99 	"{\n"
100 	"    atomicCounterIncrement(test_counter);\n"
101 	"}\n";
102 const char* PipelineStatisticsQueryUtilities::minimal_fs_code = "#version 130\n"
103 															  "\n"
104 															  "out vec4 result;\n"
105 															  "\n"
106 															  "void main()\n"
107 															  "{\n"
108 															  "    result = gl_FragCoord;\n"
109 															  "}\n";
110 const char* PipelineStatisticsQueryUtilities::minimal_tc_code =
111 	"#version 400\n"
112 	"\n"
113 	"layout(vertices = 3) out;\n"
114 	"\n"
115 	"void main()\n"
116 	"{\n"
117 	"    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
118 	"    gl_TessLevelInner[0]                = 1.0;\n"
119 	"    gl_TessLevelInner[1]                = 2.0;\n"
120 	"    gl_TessLevelOuter[0]                = 3.0;\n"
121 	"    gl_TessLevelOuter[1]                = 4.0;\n"
122 	"    gl_TessLevelOuter[2]                = 5.0;\n"
123 	"    gl_TessLevelOuter[3]                = 6.0;\n"
124 	"}\n";
125 const char* PipelineStatisticsQueryUtilities::minimal_te_code =
126 	"#version 400\n"
127 	"\n"
128 	"layout(triangles) in;\n"
129 	"\n"
130 	"void main()\n"
131 	"{\n"
132 	"    gl_Position = gl_TessCoord.xyxy * gl_in[gl_PrimitiveID].gl_Position;\n"
133 	"}\n";
134 const char* PipelineStatisticsQueryUtilities::minimal_vs_code = "#version 130\n"
135 															  "\n"
136 															  "in vec4 position;\n"
137 															  "\n"
138 															  "void main()\n"
139 															  "{\n"
140 															  "    gl_Position = position;\n"
141 															  "}\n";
142 
143 /** An array holding all query targets that are introduced by GL_ARB_pipeline_statistics_query */
144 const glw::GLenum PipelineStatisticsQueryUtilities::query_targets[] = {
145 	GL_VERTICES_SUBMITTED_ARB,
146 	GL_PRIMITIVES_SUBMITTED_ARB,
147 	GL_VERTEX_SHADER_INVOCATIONS_ARB,
148 	GL_TESS_CONTROL_SHADER_PATCHES_ARB,
149 	GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB,
150 	GL_GEOMETRY_SHADER_INVOCATIONS,
151 	GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB,
152 	GL_FRAGMENT_SHADER_INVOCATIONS_ARB,
153 	GL_COMPUTE_SHADER_INVOCATIONS_ARB,
154 	GL_CLIPPING_INPUT_PRIMITIVES_ARB,
155 	GL_CLIPPING_OUTPUT_PRIMITIVES_ARB,
156 };
157 const unsigned int PipelineStatisticsQueryUtilities::n_query_targets = sizeof(query_targets) / sizeof(query_targets[0]);
158 
159 /* Offsets that point to locations in a buffer object storage that will hold
160  * query object result values for a specific value type. */
161 const unsigned int PipelineStatisticsQueryUtilities::qo_bo_int_offset   = (0);
162 const unsigned int PipelineStatisticsQueryUtilities::qo_bo_int64_offset = (0 + 4 /* int */ + 4 /* alignment */);
163 const unsigned int PipelineStatisticsQueryUtilities::qo_bo_uint_offset  = (0 + 8 /* int + alignment */ + 8 /* int64 */);
164 const unsigned int PipelineStatisticsQueryUtilities::qo_bo_uint64_offset =
165 	(0 + 8 /* int + alignment */ + 8 /* int64 */ + 8 /* uint + alignment */);
166 const unsigned int PipelineStatisticsQueryUtilities::qo_bo_size = 32;
167 
168 /** Buffer object size required to run the second functional test. */
169 const unsigned int PipelineStatisticsQueryTestFunctional2::bo_size = 32;
170 
171 /** Builds body of a geometry shader, given user-specified properties.
172  *
173  *  This function works in two different ways:
174  *
175  *  1) If the caller only needs the geometry shader to use a single stream, the body
176  *     will be constructed in a way that ignores stream existence completely.
177  *  2) Otherwise, the shader will only be compilable by platforms that support vertex
178  *     streams.
179  *
180  *  The shader will emit @param n_primitives_to_emit_in_stream0 primitives on the zeroth
181  *  stream, (@param n_primitives_to_emit_in_stream0 + 1) primitives on the first stream,
182  *  and so on.
183  *
184  *  @param gs_input                         Input primitive type that should be used by the geometry shader body.
185  *  @param gs_output                        Output primitive type that should be used by the geometry shader body.
186  *  @param n_primitives_to_emit_in_stream0  Number of primitives to be emitted on the zeroth vertex stream.
187  *  @param n_streams                        Number of streams the geometry shader should emit primitives on.
188  *
189  *  @return Geometry shader body.
190  **/
buildGeometryShaderBody(_geometry_shader_input gs_input, _geometry_shader_output gs_output, unsigned int n_primitives_to_emit_in_stream0, unsigned int n_streams)191 std::string PipelineStatisticsQueryUtilities::buildGeometryShaderBody(_geometry_shader_input  gs_input,
192 																	  _geometry_shader_output gs_output,
193 																	  unsigned int n_primitives_to_emit_in_stream0,
194 																	  unsigned int n_streams)
195 {
196 	DE_ASSERT(n_primitives_to_emit_in_stream0 >= 1);
197 	DE_ASSERT(n_streams >= 1);
198 
199 	/* Each stream will output (n+1) primitives, where n corresponds to the number of primitives emitted
200 	 * by the previous stream. Stream 0 emits user-defined number of primitievs.
201 	 */
202 	std::stringstream gs_body_sstream;
203 	const std::string gs_input_string  = getGLSLStringForGSInput(gs_input);
204 	const std::string gs_output_string = getGLSLStringForGSOutput(gs_output);
205 	unsigned int	  n_max_vertices   = 0;
206 	unsigned int	  n_vertices_required_for_gs_output =
207 		PipelineStatisticsQueryUtilities::getNumberOfVerticesForGSOutput(gs_output);
208 
209 	for (unsigned int n_stream = 0; n_stream < n_streams; ++n_stream)
210 	{
211 		n_max_vertices += n_vertices_required_for_gs_output * (n_primitives_to_emit_in_stream0 + n_stream);
212 	} /* for (all streams) */
213 
214 	/* Form the preamble. Note that we need to use the right ES SL version,
215 	 * since vertex streams are not a core GL3.2 feature.
216 	 **/
217 	gs_body_sstream << ((n_streams > 1) ? "#version 400" : "#version 150\n") << "\n"
218 																				"layout("
219 					<< gs_input_string << ")                 in;\n"
220 										  "layout("
221 					<< gs_output_string << ", max_vertices=" << n_max_vertices << ") out;\n";
222 
223 	/* If we need to define multiple streams, do it now */
224 	if (n_streams > 1)
225 	{
226 		gs_body_sstream << "\n";
227 
228 		for (unsigned int n_stream = 0; n_stream < n_streams; ++n_stream)
229 		{
230 			gs_body_sstream << "layout(stream = " << n_stream << ") out vec4 out_stream" << n_stream << ";\n";
231 		} /* for (all streams) */
232 	}	 /* if (n_streams > 1) */
233 
234 	/* Contine forming actual body */
235 	gs_body_sstream << "\n"
236 					   "void main()\n"
237 					   "{\n";
238 
239 	/* Emit primitives */
240 	const unsigned int n_output_primitive_vertices =
241 		PipelineStatisticsQueryUtilities::getNumberOfVerticesForGSOutput(gs_output);
242 
243 	for (unsigned int n_stream = 0; n_stream < n_streams; ++n_stream)
244 	{
245 		const unsigned int n_primitives_to_emit = n_primitives_to_emit_in_stream0 + n_stream;
246 
247 		for (unsigned int n_primitive = 0; n_primitive < n_primitives_to_emit; ++n_primitive)
248 		{
249 			for (unsigned int n_vertex = 0; n_vertex < n_output_primitive_vertices; ++n_vertex)
250 			{
251 				gs_body_sstream << "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n";
252 
253 				if (n_streams == 1)
254 				{
255 					gs_body_sstream << "    EmitVertex();\n";
256 				}
257 				else
258 				{
259 					gs_body_sstream << "    EmitStreamVertex(" << n_stream << ");\n";
260 				}
261 			}
262 
263 			if (n_streams == 1)
264 			{
265 				gs_body_sstream << "    EndPrimitive();\n";
266 			}
267 			else
268 			{
269 				gs_body_sstream << "    EndStreamPrimitive(" << n_stream << ");\n";
270 			}
271 		} /* for (all primitives the caller wants the shader to emit) */
272 	}	 /* for (all streams) */
273 
274 	gs_body_sstream << "}\n";
275 
276 	return gs_body_sstream.str();
277 }
278 
279 /** Executes the query and collects the result data from both query object buffer object
280  *  (if these are supported by the running OpenGL implementation) and the query counters.
281  *  The result data is then exposed via @param out_result.
282  *
283  *  @param query_type     Type of the query to be executed for the iteration.
284  *  @param qo_id          ID of the query object to be used for the execution.
285  *                        The query object must not have been assigned a type
286  *                        prior to the call, or the type must be a match with
287  *                        @param query_type .
288  *  @param qo_bo_id       ID of the query buffer object to use for the call.
289  *                        Pass 0, if the running OpenGL implementation does not
290  *                        support QBOs.
291  *  @param pfn_draw       Function pointer to caller-specific routine that is
292  *                        going to execute the draw call. Must not be NULL.
293  *  @param draw_user_arg  Caller-specific user argument to be passed with the
294  *                        @param pfn_draw callback.
295  *  @param render_context glu::RenderContext& to be used by the method.
296  *  @param test_context   tcu::TestContext& to be used by the method.
297  *  @param context_info   glu::ContextInfo& to be used by the method.
298  *  @param out_result     Deref will be used to store the test execution result.
299  *                        Must not be NULL. Will only be modified if the method
300  *                        returns true.
301  *
302  *  @return true if the test executed successfully, and @param out_result 's fields
303  *          were modified.
304  *
305  */
executeQuery(glw::GLenum query_type, glw::GLuint qo_id, glw::GLuint qo_bo_id, PFNQUERYDRAWHANDLERPROC pfn_draw, void* draw_user_arg, const glu::RenderContext& render_context, tcu::TestContext& test_context, const glu::ContextInfo& context_info, _test_execution_result* out_result, bool& skipped)306 bool PipelineStatisticsQueryUtilities::executeQuery(glw::GLenum query_type, glw::GLuint qo_id, glw::GLuint qo_bo_id,
307 													PFNQUERYDRAWHANDLERPROC pfn_draw, void* draw_user_arg,
308 													const glu::RenderContext& render_context,
309 													tcu::TestContext&		  test_context,
310 													const glu::ContextInfo&   context_info,
311 													_test_execution_result*   out_result,
312 													bool&                     skipped)
313 {
314 	glw::GLenum			  error_code = GL_NO_ERROR;
315 	const glw::Functions& gl		 = render_context.getFunctions();
316 	bool				  result	 = true;
317 
318 	/* Check if the implementation provides non-zero number of bits for the query.
319 	 * Queries, for which GL implementations provide zero bits of space return
320 	 * indeterminate values, so we should skip them */
321 	glw::GLint n_query_bits = 0;
322 
323 	gl.getQueryiv(query_type, GL_QUERY_COUNTER_BITS, &n_query_bits);
324 
325 	error_code = gl.getError();
326 	if (error_code != GL_NO_ERROR)
327 	{
328 		test_context.getLog() << tcu::TestLog::Message
329 							  << "glGetQueryiv() call failed for GL_QUERY_COUNTER_BITS pname and "
330 							  << PipelineStatisticsQueryUtilities::getStringForEnum(query_type) << "query target."
331 							  << tcu::TestLog::EndMessage;
332 
333 		return false;
334 	}
335 
336 	if (n_query_bits == 0)
337 	{
338 		test_context.getLog() << tcu::TestLog::Message << "Skipping "
339 														  "["
340 							  << PipelineStatisticsQueryUtilities::getStringForEnum(query_type)
341 							  << "]"
342 								 ": zero bits available for counter storage"
343 							  << tcu::TestLog::EndMessage;
344 
345 		skipped = true;
346 		return result;
347 	}
348 	skipped = false;
349 
350 	/* Start the query */
351 	gl.beginQuery(query_type, qo_id);
352 
353 	error_code = gl.getError();
354 	if (error_code != GL_NO_ERROR)
355 	{
356 		test_context.getLog() << tcu::TestLog::Message
357 							  << "A valid glBeginQuery() call generated the following error code:"
358 								 "["
359 							  << error_code << "]" << tcu::TestLog::EndMessage;
360 
361 		return false;
362 	}
363 
364 	/* If GL_ARB_query_buffer_object is supported and the caller supplied a BO id, use
365 	 * it before we fire any draw calls */
366 	if (context_info.isExtensionSupported("GL_ARB_query_buffer_object") && qo_bo_id != 0)
367 	{
368 		gl.bindBuffer(GL_QUERY_BUFFER, qo_bo_id);
369 
370 		error_code = gl.getError();
371 		if (error_code != GL_NO_ERROR)
372 		{
373 			test_context.getLog() << tcu::TestLog::Message
374 								  << "Could not bind a buffer object to GL_QUERY_BUFFER buffer object "
375 									 "binding point. Error reported:"
376 									 "["
377 								  << error_code << "]" << tcu::TestLog::EndMessage;
378 
379 			/* Stop the query before we leave */
380 			gl.endQuery(query_type);
381 
382 			return false;
383 		} /* if (buffer binding operation failed) */
384 	}	 /* if (GL_ARB_query_buffer_object extension is supported and the supplied QO BO id
385 	 *     is not 0) */
386 	else
387 	{
388 		/* Reset the QO BO id, so that we can skip the checks later */
389 		qo_bo_id = 0;
390 	}
391 
392 	/* Perform the draw calls, if any supplied call-back function pointer was supplied
393 	 * by the caller. */
394 	if (pfn_draw != DE_NULL)
395 	{
396 		pfn_draw(draw_user_arg);
397 	}
398 
399 	/* End the query */
400 	gl.endQuery(query_type);
401 
402 	error_code = gl.getError();
403 	if (error_code != GL_NO_ERROR)
404 	{
405 		test_context.getLog() << tcu::TestLog::Message << "glEndQuery() call failed with error code"
406 														  "["
407 							  << error_code << "]" << tcu::TestLog::EndMessage;
408 
409 		return false;
410 	} /* if (glEndQuery() call failed) */
411 
412 	/* We now need to retrieve the result data using all query getter functions
413 	 * GL has to offer. This will be handled in two iterations:
414 	 *
415 	 * 1. The data will be retrieved using the getters without a QO BO being bound.
416 	 * 2. If QO was provided, we will need to issue all getter calls executed against
417 	 *    the QO BO. We will then need to retrieve that data directly from the BO
418 	 *    storage.
419 	 */
420 	const unsigned int iteration_index_wo_qo_bo   = 0;
421 	const unsigned int iteration_index_with_qo_bo = 1;
422 
423 	for (unsigned int n_iteration = 0; n_iteration < 2; /* as per description */
424 		 ++n_iteration)
425 	{
426 		glw::GLint*	offset_int			 = DE_NULL;
427 		glw::GLint64*  offset_int64			 = DE_NULL;
428 		glw::GLuint*   offset_uint			 = DE_NULL;
429 		glw::GLuint64* offset_uint64		 = DE_NULL;
430 		glw::GLint	 result_int			 = INT_MAX;
431 		glw::GLint64   result_int64			 = LLONG_MAX;
432 		bool		   result_int64_written  = false;
433 		glw::GLuint	result_uint			 = UINT_MAX;
434 		glw::GLuint64  result_uint64		 = ULLONG_MAX;
435 		bool		   result_uint64_written = false;
436 
437 		/* Skip the QO BO iteration if QO BO id has not been provided */
438 		if (n_iteration == iteration_index_with_qo_bo && qo_bo_id == 0)
439 		{
440 			continue;
441 		}
442 
443 		/* Determine the offsets we should use for the getter calls */
444 		if (n_iteration == iteration_index_wo_qo_bo)
445 		{
446 			offset_int	= &result_int;
447 			offset_int64  = &result_int64;
448 			offset_uint   = &result_uint;
449 			offset_uint64 = &result_uint64;
450 		}
451 		else
452 		{
453 			offset_int	= (glw::GLint*)(deUintptr)PipelineStatisticsQueryUtilities::qo_bo_int_offset;
454 			offset_int64  = (glw::GLint64*)(deUintptr)PipelineStatisticsQueryUtilities::qo_bo_int64_offset;
455 			offset_uint   = (glw::GLuint*)(deUintptr)PipelineStatisticsQueryUtilities::qo_bo_uint_offset;
456 			offset_uint64 = (glw::GLuint64*)(deUintptr)PipelineStatisticsQueryUtilities::qo_bo_uint64_offset;
457 		}
458 
459 		/* Bind the QO BO if we need to use it for the getter calls */
460 		if (n_iteration == iteration_index_with_qo_bo)
461 		{
462 			gl.bindBuffer(GL_QUERY_BUFFER, qo_bo_id);
463 		}
464 		else if (qo_bo_id != 0)
465 		{
466 			gl.bindBuffer(GL_QUERY_BUFFER, 0 /* buffer */);
467 		}
468 
469 		error_code = gl.getError();
470 		if (error_code != GL_NO_ERROR)
471 		{
472 			test_context.getLog() << tcu::TestLog::Message
473 								  << "glBindBuffer() call failed for GL_QUERY_BUFFER target with error "
474 									 "["
475 								  << error_code << "]" << tcu::TestLog::EndMessage;
476 
477 			return false;
478 		}
479 
480 		/* Issue the getter calls.
481 		 *
482 		 * NOTE: 64-bit getter calls are supported only if >= GL 3.3*/
483 		if (glu::contextSupports(render_context.getType(), glu::ApiType::core(3, 3)))
484 		{
485 			gl.getQueryObjecti64v(qo_id, GL_QUERY_RESULT, offset_int64);
486 
487 			error_code = gl.getError();
488 			if (error_code != GL_NO_ERROR)
489 			{
490 				test_context.getLog() << tcu::TestLog::Message << "glGetQueryObjecti64v() call failed with error "
491 																  "["
492 									  << error_code << "]" << tcu::TestLog::EndMessage;
493 
494 				return false;
495 			}
496 
497 			result_int64_written = true;
498 		}
499 		else
500 		{
501 			result_int64_written = false;
502 		}
503 
504 		gl.getQueryObjectiv(qo_id, GL_QUERY_RESULT, offset_int);
505 
506 		error_code = gl.getError();
507 		if (error_code != GL_NO_ERROR)
508 		{
509 			test_context.getLog() << tcu::TestLog::Message << "glGetQueryObjectiv() call failed with error "
510 															  "["
511 								  << error_code << "]" << tcu::TestLog::EndMessage;
512 
513 			return false;
514 		}
515 
516 		if (glu::contextSupports(render_context.getType(), glu::ApiType::core(3, 3)))
517 		{
518 			gl.getQueryObjectui64v(qo_id, GL_QUERY_RESULT, offset_uint64);
519 
520 			error_code = gl.getError();
521 			if (error_code != GL_NO_ERROR)
522 			{
523 				test_context.getLog() << tcu::TestLog::Message << "glGetQueryObjectui64v() call failed with error "
524 																  "["
525 									  << error_code << "]" << tcu::TestLog::EndMessage;
526 
527 				return false;
528 			}
529 
530 			result_uint64_written = true;
531 		}
532 		else
533 		{
534 			result_uint64_written = false;
535 		}
536 
537 		gl.getQueryObjectuiv(qo_id, GL_QUERY_RESULT, offset_uint);
538 
539 		error_code = gl.getError();
540 		if (error_code != GL_NO_ERROR)
541 		{
542 			test_context.getLog() << tcu::TestLog::Message << "glGetQueryObjectuiv() call failed with error "
543 															  "["
544 								  << error_code << "]" << tcu::TestLog::EndMessage;
545 
546 			return false;
547 		}
548 
549 		/* If the getters wrote the result values to the BO, we need to retrieve the data
550 		 * from the BO storage */
551 		if (n_iteration == iteration_index_with_qo_bo)
552 		{
553 			/* Map the BO to process space */
554 			const unsigned char* bo_data_ptr = (const unsigned char*)gl.mapBuffer(GL_QUERY_BUFFER, GL_READ_ONLY);
555 
556 			error_code = gl.getError();
557 
558 			if (error_code != GL_NO_ERROR || bo_data_ptr == NULL)
559 			{
560 				test_context.getLog() << tcu::TestLog::Message << "QO BO mapping failed with error "
561 																  "["
562 									  << error_code << "] and data ptr returned:"
563 													   "["
564 									  << bo_data_ptr << "]" << tcu::TestLog::EndMessage;
565 
566 				return false;
567 			}
568 
569 			/* Retrieve the query result data */
570 			result_int	= *(glw::GLint*)(bo_data_ptr + (int)(deIntptr)offset_int);
571 			result_int64  = *(glw::GLint64*)(bo_data_ptr + (int)(deIntptr)offset_int64);
572 			result_uint   = *(glw::GLuint*)(bo_data_ptr + (int)(deIntptr)offset_uint);
573 			result_uint64 = *(glw::GLuint64*)(bo_data_ptr + (int)(deIntptr)offset_uint64);
574 
575 			/* Unmap the BO */
576 			gl.unmapBuffer(GL_QUERY_BUFFER);
577 
578 			error_code = gl.getError();
579 			if (error_code != GL_NO_ERROR)
580 			{
581 				test_context.getLog() << tcu::TestLog::Message << "QO BO unmapping failed with error "
582 																  "["
583 									  << error_code << "]" << tcu::TestLog::EndMessage;
584 
585 				return false;
586 			}
587 		} /* if (QO BO iteration) */
588 
589 		/* Store the retrieved data in user-provided location */
590 		if (n_iteration == iteration_index_with_qo_bo)
591 		{
592 			out_result->result_qo_int	= result_int;
593 			out_result->result_qo_int64  = result_int64;
594 			out_result->result_qo_uint   = result_uint;
595 			out_result->result_qo_uint64 = result_uint64;
596 		}
597 		else
598 		{
599 			out_result->result_int	= result_int;
600 			out_result->result_int64  = result_int64;
601 			out_result->result_uint   = result_uint;
602 			out_result->result_uint64 = result_uint64;
603 		}
604 
605 		out_result->int64_written  = result_int64_written;
606 		out_result->uint64_written = result_uint64_written;
607 	} /* for (both iterations) */
608 	return result;
609 }
610 
611 /** Retrieves a GLenum value corresponding to internal _primitive_type
612  *  enum value.
613  *
614  *  @param primitive_type Internal primitive type to use for the getter call.
615  *
616  *  @return Corresponding GL value that can be used for the draw calls, or
617  *          GL_NONE if the conversion failed.
618  *
619  **/
getEnumForPrimitiveType(_primitive_type primitive_type)620 glw::GLenum PipelineStatisticsQueryUtilities::getEnumForPrimitiveType(_primitive_type primitive_type)
621 {
622 	glw::GLenum result = GL_NONE;
623 
624 	switch (primitive_type)
625 	{
626 	case PRIMITIVE_TYPE_POINTS:
627 		result = GL_POINTS;
628 		break;
629 	case PRIMITIVE_TYPE_LINE_LOOP:
630 		result = GL_LINE_LOOP;
631 		break;
632 	case PRIMITIVE_TYPE_LINE_STRIP:
633 		result = GL_LINE_STRIP;
634 		break;
635 	case PRIMITIVE_TYPE_LINES:
636 		result = GL_LINES;
637 		break;
638 	case PRIMITIVE_TYPE_LINES_ADJACENCY:
639 		result = GL_LINES_ADJACENCY;
640 		break;
641 	case PRIMITIVE_TYPE_PATCHES:
642 		result = GL_PATCHES;
643 		break;
644 	case PRIMITIVE_TYPE_TRIANGLE_FAN:
645 		result = GL_TRIANGLE_FAN;
646 		break;
647 	case PRIMITIVE_TYPE_TRIANGLE_STRIP:
648 		result = GL_TRIANGLE_STRIP;
649 		break;
650 	case PRIMITIVE_TYPE_TRIANGLES:
651 		result = GL_TRIANGLES;
652 		break;
653 	case PRIMITIVE_TYPE_TRIANGLES_ADJACENCY:
654 		result = GL_TRIANGLES_ADJACENCY;
655 		break;
656 
657 	default:
658 	{
659 		TCU_FAIL("Unrecognized primitive type");
660 	}
661 	} /* switch (primitive_type) */
662 
663 	return result;
664 }
665 
666 /** Retrieves a human-readable name for a _geometry_shader_input value.
667  *
668  *  @param gs_input Internal _geometry_shader_input value to use for
669  *                  the conversion.
670  *
671  *  @return Human-readable string or empty string, if the conversion failed.
672  *
673  **/
getGLSLStringForGSInput(_geometry_shader_input gs_input)674 std::string PipelineStatisticsQueryUtilities::getGLSLStringForGSInput(_geometry_shader_input gs_input)
675 {
676 	std::string result;
677 
678 	switch (gs_input)
679 	{
680 	case GEOMETRY_SHADER_INPUT_POINTS:
681 		result = "points";
682 		break;
683 	case GEOMETRY_SHADER_INPUT_LINES:
684 		result = "lines";
685 		break;
686 	case GEOMETRY_SHADER_INPUT_LINES_ADJACENCY:
687 		result = "lines_adjacency";
688 		break;
689 	case GEOMETRY_SHADER_INPUT_TRIANGLES:
690 		result = "triangles";
691 		break;
692 	case GEOMETRY_SHADER_INPUT_TRIANGLES_ADJACENCY:
693 		result = "triangles_adjacency";
694 		break;
695 
696 	default:
697 	{
698 		TCU_FAIL("Unrecognized geometry shader input enum");
699 	}
700 	} /* switch (gs_input) */
701 
702 	return result;
703 }
704 
705 /** Retrieves a human-readable string for a _geometry_shader_output value.
706  *
707  *  @param  gs_output _geometry_shader_output value to use for the conversion.
708  *
709  *  @return Requested value or empty string, if the value was not recognized.
710  *
711  **/
getGLSLStringForGSOutput(_geometry_shader_output gs_output)712 std::string PipelineStatisticsQueryUtilities::getGLSLStringForGSOutput(_geometry_shader_output gs_output)
713 {
714 	std::string result;
715 
716 	switch (gs_output)
717 	{
718 	case GEOMETRY_SHADER_OUTPUT_POINTS:
719 		result = "points";
720 		break;
721 	case GEOMETRY_SHADER_OUTPUT_LINE_STRIP:
722 		result = "line_strip";
723 		break;
724 	case GEOMETRY_SHADER_OUTPUT_TRIANGLE_STRIP:
725 		result = "triangle_strip";
726 		break;
727 
728 	default:
729 	{
730 		TCU_FAIL("Unrecognized geometry shader output enum");
731 	}
732 	} /* switch (gs_output) */
733 
734 	return result;
735 }
736 
737 /** Number of vertices the geometry shader can access on the input, if the shader
738  *  uses @param gs_input input primitive type.
739  *
740  *  @param gs_input Geometry shader input to use for the query.
741  *
742  *  @return Requested value or 0 if @param gs_input was not recognized.
743  **/
getNumberOfVerticesForGSInput(_geometry_shader_input gs_input)744 unsigned int PipelineStatisticsQueryUtilities::getNumberOfVerticesForGSInput(_geometry_shader_input gs_input)
745 {
746 	unsigned int result = 0;
747 
748 	switch (gs_input)
749 	{
750 	case GEOMETRY_SHADER_INPUT_POINTS:
751 		result = 1;
752 		break;
753 	case GEOMETRY_SHADER_INPUT_LINES:
754 		result = 2;
755 		break;
756 	case GEOMETRY_SHADER_INPUT_LINES_ADJACENCY:
757 		result = 4;
758 		break;
759 	case GEOMETRY_SHADER_INPUT_TRIANGLES:
760 		result = 3;
761 		break;
762 	case GEOMETRY_SHADER_INPUT_TRIANGLES_ADJACENCY:
763 		result = 6;
764 		break;
765 
766 	default:
767 	{
768 		TCU_FAIL("Unrecognized geometry shader input type");
769 	}
770 	} /* switch (gs_input) */
771 
772 	return result;
773 }
774 
775 /** Retrieves a number of vertices that need to be emitted before the shader
776  *  can end the primitive, with the primitive being complete, assuming the
777  *  geometry shader outputs a primitive of type described by @param gs_output.
778  *
779  *  @param gs_output Primitive type to be outputted by the geometry shader.
780  *
781  *  @return As per description, or 0 if @param gs_output was not recognized.
782  **/
getNumberOfVerticesForGSOutput(_geometry_shader_output gs_output)783 unsigned int PipelineStatisticsQueryUtilities::getNumberOfVerticesForGSOutput(_geometry_shader_output gs_output)
784 {
785 	unsigned int n_result_vertices = 0;
786 
787 	switch (gs_output)
788 	{
789 	case GEOMETRY_SHADER_OUTPUT_LINE_STRIP:
790 		n_result_vertices = 2;
791 		break;
792 	case GEOMETRY_SHADER_OUTPUT_POINTS:
793 		n_result_vertices = 1;
794 		break;
795 	case GEOMETRY_SHADER_OUTPUT_TRIANGLE_STRIP:
796 		n_result_vertices = 3;
797 		break;
798 
799 	default:
800 		TCU_FAIL("Unrecognized geometry shader output type");
801 	}
802 
803 	/* All done */
804 	return n_result_vertices;
805 }
806 
807 /** Returns the number of vertices a single primitive of type described by @param primitive_type
808  *  consists of.
809  *
810  *  @param primitive_type Primitive type to use for the query.
811  *
812  *  @return Result value, or 0 if @param primive_type was not recognized.
813  **/
getNumberOfVerticesForPrimitiveType(_primitive_type primitive_type)814 unsigned int PipelineStatisticsQueryUtilities::getNumberOfVerticesForPrimitiveType(_primitive_type primitive_type)
815 {
816 	unsigned int result = 0;
817 
818 	switch (primitive_type)
819 	{
820 	case PRIMITIVE_TYPE_POINTS:
821 		result = 1;
822 		break;
823 	case PRIMITIVE_TYPE_LINE_LOOP:  /* fall-through */
824 	case PRIMITIVE_TYPE_LINE_STRIP: /* fall-through */
825 	case PRIMITIVE_TYPE_LINES:
826 		result = 2;
827 		break;
828 	case PRIMITIVE_TYPE_TRIANGLE_FAN:   /* fall-through */
829 	case PRIMITIVE_TYPE_TRIANGLE_STRIP: /* fall-through */
830 	case PRIMITIVE_TYPE_TRIANGLES:
831 		result = 3;
832 		break;
833 	case PRIMITIVE_TYPE_LINES_ADJACENCY:
834 		result = 4;
835 		break;
836 	case PRIMITIVE_TYPE_TRIANGLES_ADJACENCY:
837 		result = 6;
838 		break;
839 
840 	default:
841 		TCU_FAIL("Unrecognized primitive type");
842 	} /* switch (primitive_type) */
843 
844 	return result;
845 }
846 
847 /** Converts user-specified _geometry_shader_input value to a _primitive_type value.
848  *
849  *  @param gs_input Input value for the conversion.
850  *
851  *  @return Requested value, or PRIMITIVE_TYPE_COUNT if the user-specified value
852  *          was unrecognized.
853  **/
getPrimitiveTypeFromGSInput( _geometry_shader_input gs_input)854 PipelineStatisticsQueryUtilities::_primitive_type PipelineStatisticsQueryUtilities::getPrimitiveTypeFromGSInput(
855 	_geometry_shader_input gs_input)
856 {
857 	_primitive_type result = PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_COUNT;
858 
859 	switch (gs_input)
860 	{
861 	case GEOMETRY_SHADER_INPUT_POINTS:
862 		result = PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_POINTS;
863 		break;
864 	case GEOMETRY_SHADER_INPUT_LINES:
865 		result = PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINES;
866 		break;
867 	case GEOMETRY_SHADER_INPUT_LINES_ADJACENCY:
868 		result = PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINES_ADJACENCY;
869 		break;
870 	case GEOMETRY_SHADER_INPUT_TRIANGLES:
871 		result = PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLES;
872 		break;
873 	case GEOMETRY_SHADER_INPUT_TRIANGLES_ADJACENCY:
874 		result = PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLES_ADJACENCY;
875 		break;
876 
877 	default:
878 	{
879 		TCU_FAIL("Unrecognized geometry shader input enum");
880 	}
881 	} /* switch (gs_input) */
882 
883 	return result;
884 }
885 
886 /** Converts user-specified _draw_call_type value to a human-readable string.
887  *
888  *  @param draw_call_type Input value to use for the conversion.
889  *
890  *  @return Human-readable string, or "[?]" (without the quotation marks) if
891  *          the input value was not recognized.
892  **/
getStringForDrawCallType(_draw_call_type draw_call_type)893 std::string PipelineStatisticsQueryUtilities::getStringForDrawCallType(_draw_call_type draw_call_type)
894 {
895 	std::string result = "[?]";
896 
897 	switch (draw_call_type)
898 	{
899 	case DRAW_CALL_TYPE_GLDRAWARRAYS:
900 		result = "glDrawArrays()";
901 		break;
902 	case DRAW_CALL_TYPE_GLDRAWARRAYSINDIRECT:
903 		result = "glDrawArraysIndirect()";
904 		break;
905 	case DRAW_CALL_TYPE_GLDRAWARRAYSINSTANCED:
906 		result = "glDrawArraysInstanced()";
907 		break;
908 	case DRAW_CALL_TYPE_GLDRAWARRAYSINSTANCEDBASEINSTANCE:
909 		result = "glDrawArraysInstancedBaseInstance()";
910 		break;
911 	case DRAW_CALL_TYPE_GLDRAWELEMENTS:
912 		result = "glDrawElements()";
913 		break;
914 	case DRAW_CALL_TYPE_GLDRAWELEMENTSBASEVERTEX:
915 		result = "glDrawElementsBaseVertex()";
916 		break;
917 	case DRAW_CALL_TYPE_GLDRAWELEMENTSINDIRECT:
918 		result = "glDrawElementsIndirect()";
919 		break;
920 	case DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCED:
921 		result = "glDrawElementsInstanced()";
922 		break;
923 	case DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCEDBASEINSTANCE:
924 		result = "glDrawElementsInstancedBaseInstance()";
925 		break;
926 	case DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCE:
927 		result = "glDrawElementsInstancedBaseVertexBaseInstance()";
928 		break;
929 	case DRAW_CALL_TYPE_GLDRAWRANGEELEMENTS:
930 		result = "glDrawRangeElements()";
931 		break;
932 	case DRAW_CALL_TYPE_GLDRAWRANGEELEMENTSBASEVERTEX:
933 		result = "glDrawRangeElementsBaseVertex()";
934 		break;
935 	default:
936 		DE_ASSERT(0);
937 		break;
938 	}
939 
940 	return result;
941 }
942 
943 /** Converts a GL enum value expressing a pipeline statistics query type
944  *  into a human-readable string.
945  *
946  *  @param value Input value to use for the conversion.
947  *
948  *  @return Human-readable string or "[?]" (without the quotation marks)
949  *          if the input value was not recognized.
950  **/
getStringForEnum(glw::GLenum value)951 std::string PipelineStatisticsQueryUtilities::getStringForEnum(glw::GLenum value)
952 {
953 	std::string result = "[?]";
954 
955 	switch (value)
956 	{
957 	case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
958 		result = "GL_CLIPPING_INPUT_PRIMITIVES_ARB";
959 		break;
960 	case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
961 		result = "GL_CLIPPING_OUTPUT_PRIMITIVES_ARB";
962 		break;
963 	case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
964 		result = "GL_COMPUTE_SHADER_INVOCATIONS_ARB";
965 		break;
966 	case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
967 		result = "GL_FRAGMENT_SHADER_INVOCATIONS_ARB";
968 		break;
969 	case GL_GEOMETRY_SHADER_INVOCATIONS:
970 		result = "GL_GEOMETRY_SHADER_INVOCATIONS";
971 		break;
972 	case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
973 		result = "GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB";
974 		break;
975 	case GL_PRIMITIVES_SUBMITTED_ARB:
976 		result = "GL_PRIMITIVES_SUBMITTED_ARB";
977 		break;
978 	case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
979 		result = "GL_TESS_CONTROL_SHADER_PATCHES_ARB";
980 		break;
981 	case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
982 		result = "GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB";
983 		break;
984 	case GL_VERTEX_SHADER_INVOCATIONS_ARB:
985 		result = "GL_VERTEX_SHADER_INVOCATIONS_ARB";
986 		break;
987 	case GL_VERTICES_SUBMITTED_ARB:
988 		result = "GL_VERTICES_SUBMITTED_ARB";
989 		break;
990 	} /* switch (value) */
991 
992 	return result;
993 }
994 
995 /** Converts a _primitive_type value into a human-readable string.
996  *
997  *  @param primitive_type Input value to use for the conversion.
998  *
999  *  @return Requested string or "[?]" (without the quotation marks)
1000  *          if the input value was not recognized.
1001  **/
getStringForPrimitiveType(_primitive_type primitive_type)1002 std::string PipelineStatisticsQueryUtilities::getStringForPrimitiveType(_primitive_type primitive_type)
1003 {
1004 	std::string result = "[?]";
1005 
1006 	switch (primitive_type)
1007 	{
1008 	case PRIMITIVE_TYPE_POINTS:
1009 		result = "GL_POINTS";
1010 		break;
1011 	case PRIMITIVE_TYPE_LINE_LOOP:
1012 		result = "GL_LINE_LOOP";
1013 		break;
1014 	case PRIMITIVE_TYPE_LINE_STRIP:
1015 		result = "GL_LINE_STRIP";
1016 		break;
1017 	case PRIMITIVE_TYPE_LINES:
1018 		result = "GL_LINES";
1019 		break;
1020 	case PRIMITIVE_TYPE_LINES_ADJACENCY:
1021 		result = "GL_LINES_ADJACENCY";
1022 		break;
1023 	case PRIMITIVE_TYPE_PATCHES:
1024 		result = "GL_PATCHES";
1025 		break;
1026 	case PRIMITIVE_TYPE_TRIANGLE_FAN:
1027 		result = "GL_TRIANGLE_FAN";
1028 		break;
1029 	case PRIMITIVE_TYPE_TRIANGLE_STRIP:
1030 		result = "GL_TRIANGLE_STRIP";
1031 		break;
1032 	case PRIMITIVE_TYPE_TRIANGLES:
1033 		result = "GL_TRIANGLES";
1034 		break;
1035 	case PRIMITIVE_TYPE_TRIANGLES_ADJACENCY:
1036 		result = "GL_TRIANGLES_ADJACENCY";
1037 		break;
1038 	default:
1039 		DE_ASSERT(0);
1040 		break;
1041 	}
1042 
1043 	return result;
1044 }
1045 
1046 /** Tells if it is safe to use a specific draw call type.
1047  *
1048  *  @param draw_call Draw call type to use for the query.
1049  *
1050  *  @return True if corresponding GL entry-point is available.
1051  */
isDrawCallSupported(_draw_call_type draw_call, const glw::Functions& gl)1052 bool PipelineStatisticsQueryUtilities::isDrawCallSupported(_draw_call_type draw_call, const glw::Functions& gl)
1053 {
1054 
1055 	bool result = false;
1056 
1057 	switch (draw_call)
1058 	{
1059 	case DRAW_CALL_TYPE_GLDRAWARRAYS:
1060 		result = (gl.drawArrays != DE_NULL);
1061 		break;
1062 	case DRAW_CALL_TYPE_GLDRAWARRAYSINDIRECT:
1063 		result = (gl.drawArraysIndirect != DE_NULL);
1064 		break;
1065 	case DRAW_CALL_TYPE_GLDRAWARRAYSINSTANCED:
1066 		result = (gl.drawArraysInstanced != DE_NULL);
1067 		break;
1068 	case DRAW_CALL_TYPE_GLDRAWARRAYSINSTANCEDBASEINSTANCE:
1069 		result = (gl.drawArraysInstancedBaseInstance != DE_NULL);
1070 		break;
1071 	case DRAW_CALL_TYPE_GLDRAWELEMENTS:
1072 		result = (gl.drawElements != DE_NULL);
1073 		break;
1074 	case DRAW_CALL_TYPE_GLDRAWELEMENTSBASEVERTEX:
1075 		result = (gl.drawElementsBaseVertex != DE_NULL);
1076 		break;
1077 	case DRAW_CALL_TYPE_GLDRAWELEMENTSINDIRECT:
1078 		result = (gl.drawElementsIndirect != DE_NULL);
1079 		break;
1080 	case DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCED:
1081 		result = (gl.drawElementsInstanced != DE_NULL);
1082 		break;
1083 	case DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCEDBASEINSTANCE:
1084 		result = (gl.drawElementsInstancedBaseInstance != DE_NULL);
1085 		break;
1086 	case DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCE:
1087 		result = (gl.drawElementsInstancedBaseVertexBaseInstance != DE_NULL);
1088 		break;
1089 	case DRAW_CALL_TYPE_GLDRAWRANGEELEMENTS:
1090 		result = (gl.drawRangeElements != DE_NULL);
1091 		break;
1092 	case DRAW_CALL_TYPE_GLDRAWRANGEELEMENTSBASEVERTEX:
1093 		result = (gl.drawRangeElementsBaseVertex != DE_NULL);
1094 		break;
1095 
1096 	default:
1097 	{
1098 		TCU_FAIL("Unrecognized draw call type");
1099 	}
1100 	} /* switch (draw_call) */
1101 
1102 	return result;
1103 }
1104 
1105 /** Tells if user-specified draw call type is an instanced draw call.
1106  *
1107  *  @param draw_call Input value to use for the conversion.
1108  *
1109  *  @return true if @param draw_call corresponds to an instanced draw call,
1110  *          false otherwise.
1111  **/
isInstancedDrawCall(_draw_call_type draw_call)1112 bool PipelineStatisticsQueryUtilities::isInstancedDrawCall(_draw_call_type draw_call)
1113 {
1114 	bool result =
1115 		(draw_call == PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWARRAYSINDIRECT ||
1116 		 draw_call == PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWARRAYSINSTANCED ||
1117 		 draw_call == PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWARRAYSINSTANCEDBASEINSTANCE ||
1118 		 draw_call == PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSINDIRECT ||
1119 		 draw_call == PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCED ||
1120 		 draw_call == PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCEDBASEINSTANCE ||
1121 		 draw_call == PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCE);
1122 
1123 	return result;
1124 }
1125 
1126 /** Tells if the running GL implementation supports user-specified pipeline
1127  *  statistics query.
1128  *
1129  *  @param value          GL enum definining the pipeline statistics query type
1130  *                        that should be used for the query.
1131  *  @param context_info   glu::ContextInfo instance that can be used by the method.
1132  *  @param render_context glu::RenderContext instance that can be used by the method.
1133  *
1134  *  @return true if the query is supported, false otherwise. This method will return
1135  *          true for unrecognized enums.
1136  **/
isQuerySupported(glw::GLenum value, const glu::ContextInfo& context_info, const glu::RenderContext& render_context)1137 bool PipelineStatisticsQueryUtilities::isQuerySupported(glw::GLenum value, const glu::ContextInfo& context_info,
1138 														const glu::RenderContext& render_context)
1139 {
1140 	bool result = true;
1141 
1142 	switch (value)
1143 	{
1144 	case GL_GEOMETRY_SHADER_INVOCATIONS:
1145 	case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
1146 	{
1147 		if (!glu::contextSupports(render_context.getType(), glu::ApiType::core(3, 2)) &&
1148 			!context_info.isExtensionSupported("GL_ARB_geometry_shader4"))
1149 		{
1150 			result = false;
1151 		}
1152 
1153 		break;
1154 	}
1155 
1156 	case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
1157 	case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
1158 	{
1159 		if (!glu::contextSupports(render_context.getType(), glu::ApiType::compatibility(4, 0)) &&
1160 			!context_info.isExtensionSupported("GL_ARB_tessellation_shader"))
1161 		{
1162 			result = false;
1163 		}
1164 
1165 		break;
1166 	}
1167 
1168 	case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
1169 	{
1170 		if (!glu::contextSupports(render_context.getType(), glu::ApiType::core(4, 3)) &&
1171 			!context_info.isExtensionSupported("GL_ARB_compute_shader"))
1172 		{
1173 			result = false;
1174 		}
1175 
1176 		break;
1177 	}
1178 	} /* switch (value) */
1179 
1180 	return result;
1181 }
1182 
1183 /** Takes a filled _test_execution_result structure and performs the validation
1184  *  of the embedded data.
1185  *
1186  *  @param run_result                   A filled _test_execution_result structure that
1187  *                                      should be used as input by the method.
1188  *  @param n_expected_values            Number of possible expected values.
1189  *  @param expected_values              Array of possible expected values.
1190  *  @param should_check_qo_bo_values    true if the method should also verify the values
1191  *                                      retrieved from a query buffer object, false
1192  *                                      if it is OK to ignore them.
1193  *  @param query_type                   Pipeline statistics query type that was used to
1194  *                                      capture the results stored in @param run_result .
1195  *  @param draw_call_type_ptr           Type of the draw call that was used to capture the
1196  *                                      results stored in @param run_result .
1197  *  @param primitive_type_ptr           Primitive type that was used for the draw call that
1198  *                                      was used to capture the results stored in @param
1199  *                                      run_result .
1200  *  @param is_primitive_restart_enabled true if "Primitive Restart" rendering mode had been enabled
1201  *                                      when the draw call used to capture the results was made.
1202  *  @param test_context                 tcu::TestContext instance that the method can use.
1203  *  @param verification_type            Tells how the captured values should be compared against the
1204  *                                      reference value.
1205  *
1206  *  @return true if the result values were found valid, false otherwise.
1207  **/
verifyResultValues( const _test_execution_result& run_result, unsigned int n_expected_values, const glw::GLuint64* expected_values, bool should_check_qo_bo_values, const glw::GLenum query_type, const _draw_call_type* draw_call_type_ptr, const _primitive_type* primitive_type_ptr, bool is_primitive_restart_enabled, tcu::TestContext& test_context, _verification_type verification_type)1208 bool PipelineStatisticsQueryUtilities::verifyResultValues(
1209 	const _test_execution_result& run_result, unsigned int n_expected_values, const glw::GLuint64* expected_values,
1210 	bool should_check_qo_bo_values, const glw::GLenum query_type, const _draw_call_type* draw_call_type_ptr,
1211 	const _primitive_type* primitive_type_ptr, bool is_primitive_restart_enabled, tcu::TestContext& test_context,
1212 	_verification_type verification_type)
1213 {
1214 	bool result = true;
1215 
1216 	/* Make sure all values are set to one of the expected values */
1217 	std::string draw_call_name;
1218 	std::string primitive_name;
1219 
1220 	bool is_result_int_valid	   = false;
1221 	bool is_result_int64_valid	 = false;
1222 	bool is_result_uint_valid	  = false;
1223 	bool is_result_uint64_valid	= false;
1224 	bool is_result_qo_int_valid	= false;
1225 	bool is_result_qo_int64_valid  = false;
1226 	bool is_result_qo_uint_valid   = false;
1227 	bool is_result_qo_uint64_valid = false;
1228 
1229 	if (draw_call_type_ptr != DE_NULL)
1230 	{
1231 		draw_call_name = getStringForDrawCallType(*draw_call_type_ptr);
1232 	}
1233 	else
1234 	{
1235 		draw_call_name = "(does not apply)";
1236 	}
1237 
1238 	if (primitive_type_ptr != DE_NULL)
1239 	{
1240 		primitive_name = getStringForPrimitiveType(*primitive_type_ptr);
1241 	}
1242 	else
1243 	{
1244 		primitive_name = "(does not apply)";
1245 	}
1246 
1247 	for (unsigned int n_expected_value = 0; n_expected_value < n_expected_values; ++n_expected_value)
1248 	{
1249 		glw::GLuint64 expected_value = 0;
1250 
1251 		expected_value = expected_values[n_expected_value];
1252 
1253 		if ((verification_type == VERIFICATION_TYPE_EXACT_MATCH &&
1254 			 (glw::GLuint64)run_result.result_int == expected_value) ||
1255 			(verification_type == VERIFICATION_TYPE_EQUAL_OR_GREATER &&
1256 			 (glw::GLuint64)run_result.result_int >= expected_value))
1257 		{
1258 			is_result_int_valid = true;
1259 		}
1260 
1261 		if (run_result.int64_written && ((verification_type == VERIFICATION_TYPE_EXACT_MATCH &&
1262 										  run_result.result_int64 == (glw::GLint64)expected_value) ||
1263 										 (verification_type == VERIFICATION_TYPE_EQUAL_OR_GREATER &&
1264 										  run_result.result_int64 >= (glw::GLint64)expected_value)))
1265 		{
1266 			is_result_int64_valid = true;
1267 		}
1268 
1269 		if ((verification_type == VERIFICATION_TYPE_EXACT_MATCH &&
1270 			 (glw::GLuint64)run_result.result_uint == expected_value) ||
1271 			(verification_type == VERIFICATION_TYPE_EQUAL_OR_GREATER &&
1272 			 (glw::GLuint64)run_result.result_uint >= expected_value))
1273 		{
1274 			is_result_uint_valid = true;
1275 		}
1276 
1277 		if (run_result.uint64_written &&
1278 			((verification_type == VERIFICATION_TYPE_EXACT_MATCH && run_result.result_uint64 == expected_value) ||
1279 			 (verification_type == VERIFICATION_TYPE_EQUAL_OR_GREATER && run_result.result_uint64 >= expected_value)))
1280 		{
1281 			is_result_uint64_valid = true;
1282 		}
1283 
1284 		if (should_check_qo_bo_values)
1285 		{
1286 			if ((verification_type == VERIFICATION_TYPE_EXACT_MATCH &&
1287 				 (glw::GLuint64)run_result.result_qo_int == expected_value) ||
1288 				(verification_type == VERIFICATION_TYPE_EQUAL_OR_GREATER &&
1289 				 (glw::GLuint64)run_result.result_qo_int >= expected_value))
1290 			{
1291 				is_result_qo_int_valid = true;
1292 			}
1293 
1294 			if (run_result.int64_written && ((verification_type == VERIFICATION_TYPE_EXACT_MATCH &&
1295 											  run_result.result_qo_int64 == (glw::GLint64)expected_value) ||
1296 											 (verification_type == VERIFICATION_TYPE_EQUAL_OR_GREATER &&
1297 											  run_result.result_qo_int64 >= (glw::GLint64)expected_value)))
1298 			{
1299 				is_result_qo_int64_valid = true;
1300 			}
1301 
1302 			if ((verification_type == VERIFICATION_TYPE_EXACT_MATCH &&
1303 				 (glw::GLuint64)run_result.result_qo_uint == expected_value) ||
1304 				(verification_type == VERIFICATION_TYPE_EQUAL_OR_GREATER &&
1305 				 (glw::GLuint64)run_result.result_qo_uint >= expected_value))
1306 			{
1307 				is_result_qo_uint_valid = true;
1308 			}
1309 
1310 			if (run_result.uint64_written && ((verification_type == VERIFICATION_TYPE_EXACT_MATCH &&
1311 											   run_result.result_qo_uint64 == expected_value) ||
1312 											  (verification_type == VERIFICATION_TYPE_EQUAL_OR_GREATER &&
1313 											   run_result.result_qo_uint64 >= expected_value)))
1314 			{
1315 				is_result_qo_uint64_valid = true;
1316 			}
1317 		} /* if (should_check_qo_bo_values) */
1318 	}	 /* for (both expected values) */
1319 
1320 	if (!is_result_int_valid)
1321 	{
1322 		std::string log = PipelineStatisticsQueryUtilities::getVerifyResultValuesErrorString<glw::GLint>(
1323 			run_result.result_int, "non-QO BO int32", n_expected_values, expected_values, query_type, draw_call_name,
1324 			primitive_name, is_primitive_restart_enabled);
1325 
1326 		test_context.getLog() << tcu::TestLog::Message << log.c_str() << tcu::TestLog::EndMessage;
1327 
1328 		result = false;
1329 	}
1330 
1331 	if (run_result.int64_written && !is_result_int64_valid)
1332 	{
1333 		std::string log = PipelineStatisticsQueryUtilities::getVerifyResultValuesErrorString<glw::GLint64>(
1334 			run_result.result_int64, "non-QO BO int64", n_expected_values, expected_values, query_type, draw_call_name,
1335 			primitive_name, is_primitive_restart_enabled);
1336 
1337 		test_context.getLog() << tcu::TestLog::Message << log.c_str() << tcu::TestLog::EndMessage;
1338 
1339 		result = false;
1340 	}
1341 
1342 	if (!is_result_uint_valid)
1343 	{
1344 		std::string log = PipelineStatisticsQueryUtilities::getVerifyResultValuesErrorString<glw::GLuint>(
1345 			run_result.result_uint, "non-QO BO uint32", n_expected_values, expected_values, query_type, draw_call_name,
1346 			primitive_name, is_primitive_restart_enabled);
1347 
1348 		test_context.getLog() << tcu::TestLog::Message << log.c_str() << tcu::TestLog::EndMessage;
1349 
1350 		result = false;
1351 	}
1352 
1353 	if (run_result.uint64_written && !is_result_uint64_valid)
1354 	{
1355 		std::string log = PipelineStatisticsQueryUtilities::getVerifyResultValuesErrorString<glw::GLuint64>(
1356 			run_result.result_uint, "non-QO BO uint64", n_expected_values, expected_values, query_type, draw_call_name,
1357 			primitive_name, is_primitive_restart_enabled);
1358 
1359 		test_context.getLog() << tcu::TestLog::Message << log.c_str() << tcu::TestLog::EndMessage;
1360 
1361 		result = false;
1362 	}
1363 
1364 	if (should_check_qo_bo_values)
1365 	{
1366 		if (!is_result_qo_int_valid)
1367 		{
1368 			std::string log = PipelineStatisticsQueryUtilities::getVerifyResultValuesErrorString<glw::GLint>(
1369 				run_result.result_qo_int, "QO BO int32", n_expected_values, expected_values, query_type, draw_call_name,
1370 				primitive_name, is_primitive_restart_enabled);
1371 
1372 			test_context.getLog() << tcu::TestLog::Message << log.c_str() << tcu::TestLog::EndMessage;
1373 
1374 			result = false;
1375 		}
1376 
1377 		if (run_result.int64_written && !is_result_qo_int64_valid)
1378 		{
1379 			std::string log = PipelineStatisticsQueryUtilities::getVerifyResultValuesErrorString<glw::GLint64>(
1380 				run_result.result_qo_int64, "QO BO int64", n_expected_values, expected_values, query_type,
1381 				draw_call_name, primitive_name, is_primitive_restart_enabled);
1382 
1383 			test_context.getLog() << tcu::TestLog::Message << log.c_str() << tcu::TestLog::EndMessage;
1384 
1385 			result = false;
1386 		}
1387 
1388 		if (!is_result_qo_uint_valid)
1389 		{
1390 			std::string log = PipelineStatisticsQueryUtilities::getVerifyResultValuesErrorString<glw::GLuint>(
1391 				run_result.result_qo_uint, "QO BO uint32", n_expected_values, expected_values, query_type,
1392 				draw_call_name, primitive_name, is_primitive_restart_enabled);
1393 
1394 			test_context.getLog() << tcu::TestLog::Message << log.c_str() << tcu::TestLog::EndMessage;
1395 
1396 			result = false;
1397 		}
1398 
1399 		if (run_result.uint64_written && !is_result_qo_uint64_valid)
1400 		{
1401 			std::string log = PipelineStatisticsQueryUtilities::getVerifyResultValuesErrorString<glw::GLuint64>(
1402 				run_result.result_qo_uint64, "QO BO uint64", n_expected_values, expected_values, query_type,
1403 				draw_call_name, primitive_name, is_primitive_restart_enabled);
1404 
1405 			test_context.getLog() << tcu::TestLog::Message << log.c_str() << tcu::TestLog::EndMessage;
1406 
1407 			result = false;
1408 		}
1409 	}
1410 
1411 	return result;
1412 }
1413 
1414 /** Constructor.
1415  *
1416  *  @param context     Rendering context
1417  *  @param name        Test name
1418  *  @param description Test description
1419  */
PipelineStatisticsQueryTestAPICoverage1(deqp::Context& context)1420 PipelineStatisticsQueryTestAPICoverage1::PipelineStatisticsQueryTestAPICoverage1(deqp::Context& context)
1421 	: TestCase(context, "api_coverage_invalid_glbeginquery_calls",
1422 			   "Verifies that an attempt to assign a different query object type "
1423 			   "to an object thas has already been assigned a type, results in "
1424 			   "an error.")
1425 	, m_qo_id(0)
1426 {
1427 	/* Left blank intentionally */
1428 }
1429 
1430 /** Deinitializes all GL objects that were created during test execution. */
deinit()1431 void PipelineStatisticsQueryTestAPICoverage1::deinit()
1432 {
1433 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1434 
1435 	if (m_qo_id != 0)
1436 	{
1437 		gl.deleteQueries(1, &m_qo_id);
1438 
1439 		m_qo_id = 0;
1440 	}
1441 }
1442 
1443 /** Executes test iteration.
1444  *
1445  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1446  */
iterate()1447 tcu::TestNode::IterateResult PipelineStatisticsQueryTestAPICoverage1::iterate()
1448 {
1449 	const glu::ContextInfo& context_info   = m_context.getContextInfo();
1450 	bool					has_passed	 = true;
1451 	glu::RenderContext&		render_context = m_context.getRenderContext();
1452 	glu::ContextType		contextType	= m_context.getRenderContext().getType();
1453 
1454 	/* Only continue if GL_ARB_pipeline_statistics_query extension is supported */
1455 	if (!glu::contextSupports(contextType, glu::ApiType::core(4, 6)) &&
1456 		!context_info.isExtensionSupported("GL_ARB_pipeline_statistics_query"))
1457 	{
1458 		throw tcu::NotSupportedError("GL_ARB_pipeline_statistics_query extension is not supported");
1459 	}
1460 
1461 	/* Verify that a query object which has been assigned a pipeline statistics query target A,
1462 	 * cannot be assigned another type B (assuming A != B) */
1463 	const glw::Functions& gl = render_context.getFunctions();
1464 
1465 	for (unsigned int n_current_item = 0; n_current_item < PipelineStatisticsQueryUtilities::n_query_targets;
1466 		 ++n_current_item)
1467 	{
1468 		glw::GLenum current_pq = PipelineStatisticsQueryUtilities::query_targets[n_current_item];
1469 
1470 		/* Make sure the query is supported */
1471 		if (!PipelineStatisticsQueryUtilities::isQuerySupported(current_pq, context_info, render_context))
1472 		{
1473 			continue;
1474 		}
1475 
1476 		/* Generate a new query object */
1477 		gl.genQueries(1, &m_qo_id);
1478 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries() call failed.");
1479 
1480 		/* Assign a type to the query object */
1481 		gl.beginQuery(current_pq, m_qo_id);
1482 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQuery() call failed.");
1483 
1484 		gl.endQuery(current_pq);
1485 		GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery() call failed.");
1486 
1487 		for (unsigned int n_different_item = 0; n_different_item < PipelineStatisticsQueryUtilities::n_query_targets;
1488 			 ++n_different_item)
1489 		{
1490 			glw::GLenum different_pq = PipelineStatisticsQueryUtilities::query_targets[n_different_item];
1491 
1492 			if (current_pq == different_pq)
1493 			{
1494 				/* Skip valid iterations */
1495 				continue;
1496 			}
1497 
1498 			/* Make sure the other query type is supported */
1499 			if (!PipelineStatisticsQueryUtilities::isQuerySupported(different_pq, context_info, render_context))
1500 			{
1501 				continue;
1502 			}
1503 
1504 			/* Try using a different type for the same object */
1505 			glw::GLenum error_code = GL_NO_ERROR;
1506 
1507 			gl.beginQuery(different_pq, m_qo_id);
1508 
1509 			/* Has GL_INVALID_OPERATION error been generated? */
1510 			error_code = gl.getError();
1511 
1512 			if (error_code != GL_INVALID_OPERATION)
1513 			{
1514 				m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected error code "
1515 															   "["
1516 								   << error_code << "]"
1517 													" generated when using glBeginQuery() for a query object of type "
1518 													"["
1519 								   << PipelineStatisticsQueryUtilities::getStringForEnum(current_pq)
1520 								   << "]"
1521 									  ", when used for a query type "
1522 									  "["
1523 								   << PipelineStatisticsQueryUtilities::getStringForEnum(different_pq) << "]"
1524 								   << tcu::TestLog::EndMessage;
1525 
1526 				has_passed = false;
1527 			}
1528 
1529 			if (error_code == GL_NO_ERROR)
1530 			{
1531 				/* Clean up before we continue */
1532 				gl.endQuery(different_pq);
1533 				GLU_EXPECT_NO_ERROR(gl.getError(),
1534 									"glEndQuery() should not have failed for a successful glBeginQuery() call");
1535 			}
1536 		} /* for (all query object types) */
1537 
1538 		/* We need to switch to a new pipeline statistics query, so
1539 		 * delete the query object */
1540 		gl.deleteQueries(1, &m_qo_id);
1541 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteQueries() call failed.");
1542 	} /* for (all pipeline statistics query object types) */
1543 
1544 	if (has_passed)
1545 	{
1546 		/* Test case passed */
1547 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1548 	}
1549 	else
1550 	{
1551 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1552 	}
1553 
1554 	return STOP;
1555 }
1556 
1557 /** Constructor.
1558  *
1559  *  @param context     Rendering context
1560  *  @param name        Test name
1561  *  @param description Test description
1562  */
PipelineStatisticsQueryTestAPICoverage2(deqp::Context& context)1563 PipelineStatisticsQueryTestAPICoverage2::PipelineStatisticsQueryTestAPICoverage2(deqp::Context& context)
1564 	: TestCase(context, "api_coverage_unsupported_calls",
1565 			   "Verifies that an attempt of using unsupported pipeline statistics queries"
1566 			   " results in a GL_INVALID_ENUM error.")
1567 	, m_qo_id(0)
1568 {
1569 	/* Left blank intentionally */
1570 }
1571 
1572 /** Deinitializes all GL objects that were created during test execution. */
deinit()1573 void PipelineStatisticsQueryTestAPICoverage2::deinit()
1574 {
1575 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1576 
1577 	if (m_qo_id != 0)
1578 	{
1579 		gl.deleteQueries(1, &m_qo_id);
1580 
1581 		m_qo_id = 0;
1582 	}
1583 }
1584 
1585 /** Executes test iteration.
1586  *
1587  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1588  */
iterate()1589 tcu::TestNode::IterateResult PipelineStatisticsQueryTestAPICoverage2::iterate()
1590 {
1591 	const glu::ContextInfo& context_info   = m_context.getContextInfo();
1592 	glw::GLenum				error_code	 = GL_NO_ERROR;
1593 	bool					has_passed	 = true;
1594 	glu::RenderContext&		render_context = m_context.getRenderContext();
1595 	const glw::Functions&   gl			   = render_context.getFunctions();
1596 	glu::ContextType		contextType	= m_context.getRenderContext().getType();
1597 
1598 	/* Only continue if GL_ARB_pipeline_statistics_query extension is supported */
1599 	if (!glu::contextSupports(contextType, glu::ApiType::core(4, 6)) &&
1600 		!m_context.getContextInfo().isExtensionSupported("GL_ARB_pipeline_statistics_query"))
1601 	{
1602 		throw tcu::NotSupportedError("GL_ARB_pipeline_statistics_query extension is not supported");
1603 	}
1604 
1605 	/* Generate a query object we will use for the tests */
1606 	gl.genQueries(1, &m_qo_id);
1607 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries() call failed.");
1608 
1609 	const glw::GLenum query_types[] = { GL_GEOMETRY_SHADER_INVOCATIONS, GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB,
1610 										GL_TESS_CONTROL_SHADER_PATCHES_ARB, GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB,
1611 										GL_COMPUTE_SHADER_INVOCATIONS_ARB };
1612 	const unsigned int n_query_types = sizeof(query_types) / sizeof(query_types[0]);
1613 
1614 	for (unsigned int n_query_type = 0; n_query_type < n_query_types; ++n_query_type)
1615 	{
1616 		glw::GLenum query_type = query_types[n_query_type];
1617 
1618 		if (!PipelineStatisticsQueryUtilities::isQuerySupported(query_type, context_info, render_context))
1619 		{
1620 			gl.beginQuery(query_type, m_qo_id);
1621 
1622 			error_code = gl.getError();
1623 			if (error_code != GL_INVALID_ENUM)
1624 			{
1625 				m_testCtx.getLog() << tcu::TestLog::Message
1626 								   << "glBeginQuery() call did not generate a GL_INVALID_ENUM error "
1627 									  "for an unsupported query type "
1628 									  "["
1629 								   << PipelineStatisticsQueryUtilities::getStringForEnum(query_type) << "]"
1630 								   << tcu::TestLog::EndMessage;
1631 
1632 				has_passed = false;
1633 			}
1634 
1635 			/* If the query succeeded, stop it before we continue */
1636 			if (error_code == GL_NO_ERROR)
1637 			{
1638 				gl.endQuery(query_type);
1639 
1640 				GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery() call failed.");
1641 			}
1642 		} /* if (query is not supported) */
1643 	}	 /* for (all query types) */
1644 
1645 	if (has_passed)
1646 	{
1647 		/* Test case passed */
1648 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1649 	}
1650 	else
1651 	{
1652 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1653 	}
1654 
1655 	return STOP;
1656 }
1657 
1658 /** Constructor.
1659  *
1660  *  @param context     Rendering context
1661  *  @param name        Test name
1662  *  @param description Test description
1663  */
PipelineStatisticsQueryTestFunctionalBase(deqp::Context& context, const char* name, const char* description)1664 PipelineStatisticsQueryTestFunctionalBase::PipelineStatisticsQueryTestFunctionalBase(deqp::Context& context,
1665 																					 const char*	name,
1666 																					 const char*	description)
1667 	: TestCase(context, name, description)
1668 	, m_bo_qo_id(0)
1669 	, m_fbo_id(0)
1670 	, m_po_id(0)
1671 	, m_qo_id(0)
1672 	, m_to_id(0)
1673 	, m_vao_id(0)
1674 	, m_vbo_id(0)
1675 	, m_to_height(64)
1676 	, m_to_width(64)
1677 	, m_vbo_indirect_arrays_argument_offset(0)
1678 	, m_vbo_indirect_elements_argument_offset(0)
1679 	, m_vbo_index_data_offset(0)
1680 	, m_vbo_n_indices(0)
1681 	, m_vbo_vertex_data_offset(0)
1682 	, m_current_draw_call_type(PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_COUNT)
1683 	, m_current_primitive_type(PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_COUNT)
1684 	, m_indirect_draw_call_baseinstance_argument(0)
1685 	, m_indirect_draw_call_basevertex_argument(0)
1686 	, m_indirect_draw_call_count_argument(0)
1687 	, m_indirect_draw_call_first_argument(0)
1688 	, m_indirect_draw_call_firstindex_argument(0)
1689 	, m_indirect_draw_call_primcount_argument(0)
1690 {
1691 	/* Left blank intentionally */
1692 }
1693 
1694 /** Creates a program object that can be used for dispatch/draw calls, using
1695  *  user-specified shader bodies. The method can either create a compute program,
1696  *  or a regular rendering program.
1697  *
1698  *  ID of the initialized program object is stored in m_po_id.
1699  *
1700  *  @param cs_body Compute shader body. If not NULL, all other arguments must
1701  *                 be NULL.
1702  *  @param fs_body Fragment shader body. If not NULL, @param cs_body must be NULL.
1703  *  @param gs_body Geometry shader body. If not NULL, @param cs_body must be NULL.
1704  *  @param tc_body Tess control shader body. If not NULL, @param cs_body must be NULL.
1705  *  @param te_body Tess evaluation shader body. If not NULL, @param cs_body must be NULL.
1706  *  @param vs_body Vertex shader body. If not NULL, @param cs_body must be NULL.
1707  *
1708  * */
buildProgram(const char* cs_body, const char* fs_body, const char* gs_body, const char* tc_body, const char* te_body, const char* vs_body)1709 void PipelineStatisticsQueryTestFunctionalBase::buildProgram(const char* cs_body, const char* fs_body,
1710 															 const char* gs_body, const char* tc_body,
1711 															 const char* te_body, const char* vs_body)
1712 {
1713 	const glw::Functions& gl	= m_context.getRenderContext().getFunctions();
1714 	glw::GLuint			  cs_id = 0;
1715 	glw::GLuint			  fs_id = 0;
1716 	glw::GLuint			  gs_id = 0;
1717 	glw::GLuint			  tc_id = 0;
1718 	glw::GLuint			  te_id = 0;
1719 	glw::GLuint			  vs_id = 0;
1720 
1721 	/* Quick checks */
1722 	DE_ASSERT((cs_body != DE_NULL && (fs_body == DE_NULL && gs_body == DE_NULL && tc_body == DE_NULL &&
1723 									  te_body == DE_NULL && vs_body == DE_NULL)) ||
1724 			  (cs_body == DE_NULL && (fs_body != DE_NULL || gs_body != DE_NULL || tc_body != DE_NULL ||
1725 									  te_body != DE_NULL || vs_body != DE_NULL)));
1726 
1727 	/* Any existing program object already initialzied? Purge it before we continue */
1728 	if (m_po_id != 0)
1729 	{
1730 		gl.deleteProgram(m_po_id);
1731 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram() call failed.");
1732 
1733 		m_po_id = 0;
1734 	}
1735 
1736 	/* Generate all shader objects we'll need to use for the program */
1737 	if (cs_body != DE_NULL)
1738 	{
1739 		cs_id = gl.createShader(GL_COMPUTE_SHADER);
1740 	}
1741 
1742 	if (fs_body != DE_NULL)
1743 	{
1744 		fs_id = gl.createShader(GL_FRAGMENT_SHADER);
1745 	}
1746 
1747 	if (gs_body != DE_NULL)
1748 	{
1749 		gs_id = gl.createShader(GL_GEOMETRY_SHADER);
1750 	}
1751 
1752 	if (tc_body != DE_NULL)
1753 	{
1754 		tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
1755 	}
1756 
1757 	if (te_body != DE_NULL)
1758 	{
1759 		te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
1760 	}
1761 
1762 	if (vs_body != DE_NULL)
1763 	{
1764 		vs_id = gl.createShader(GL_VERTEX_SHADER);
1765 	}
1766 
1767 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
1768 
1769 	/* Create a program object */
1770 	m_po_id = gl.createProgram();
1771 
1772 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
1773 
1774 	/* Set source code of the shaders we've created */
1775 	if (cs_id != 0)
1776 	{
1777 		gl.shaderSource(cs_id, 1,			/* count */
1778 						&cs_body, DE_NULL); /* length */
1779 	}
1780 
1781 	if (fs_id != 0)
1782 	{
1783 		gl.shaderSource(fs_id, 1,			/* count */
1784 						&fs_body, DE_NULL); /* length */
1785 	}
1786 
1787 	if (gs_id != 0)
1788 	{
1789 		gl.shaderSource(gs_id, 1,			/* count */
1790 						&gs_body, DE_NULL); /* length */
1791 	}
1792 
1793 	if (tc_id != 0)
1794 	{
1795 		gl.shaderSource(tc_id, 1,			/* count */
1796 						&tc_body, DE_NULL); /* length */
1797 	}
1798 
1799 	if (te_id != 0)
1800 	{
1801 		gl.shaderSource(te_id, 1,			/* count */
1802 						&te_body, DE_NULL); /* length */
1803 	}
1804 
1805 	if (vs_id != 0)
1806 	{
1807 		gl.shaderSource(vs_id, 1,			/* count */
1808 						&vs_body, DE_NULL); /* length */
1809 	}
1810 
1811 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
1812 
1813 	/* Compile the shaders */
1814 	const glw::GLuint  so_ids[] = { cs_id, fs_id, gs_id, tc_id, te_id, vs_id };
1815 	const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
1816 
1817 	for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
1818 	{
1819 		glw::GLint  compile_status = GL_FALSE;
1820 		glw::GLuint so_id		   = so_ids[n_so_id];
1821 
1822 		if (so_id != 0)
1823 		{
1824 			gl.compileShader(so_id);
1825 			GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
1826 
1827 			gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
1828 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
1829 
1830 			if (compile_status == GL_FALSE)
1831 			{
1832 				TCU_FAIL("Shader compilation failed.");
1833 			}
1834 
1835 			gl.attachShader(m_po_id, so_id);
1836 			GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
1837 		} /* if (so_id != 0) */
1838 	}	 /* for (all shader objects) */
1839 
1840 	/* Link the program object */
1841 	glw::GLint link_status = GL_FALSE;
1842 
1843 	gl.linkProgram(m_po_id);
1844 	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
1845 
1846 	gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
1847 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
1848 
1849 	if (link_status == GL_FALSE)
1850 	{
1851 		TCU_FAIL("Program linking failed.");
1852 	}
1853 
1854 	/* Release the shader objects - we no longer need them */
1855 	if (cs_id != 0)
1856 	{
1857 		gl.deleteShader(cs_id);
1858 	}
1859 
1860 	if (fs_id != 0)
1861 	{
1862 		gl.deleteShader(fs_id);
1863 	}
1864 
1865 	if (gs_id != 0)
1866 	{
1867 		gl.deleteShader(gs_id);
1868 	}
1869 
1870 	if (tc_id != 0)
1871 	{
1872 		gl.deleteShader(tc_id);
1873 	}
1874 
1875 	if (te_id != 0)
1876 	{
1877 		gl.deleteShader(te_id);
1878 	}
1879 
1880 	if (vs_id != 0)
1881 	{
1882 		gl.deleteShader(vs_id);
1883 	}
1884 
1885 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call(s) failed.");
1886 }
1887 
1888 /** Deinitializes all GL objects that were created during test execution.
1889  *  Also calls the inheriting object's deinitObjects() method.
1890  **/
deinit()1891 void PipelineStatisticsQueryTestFunctionalBase::deinit()
1892 {
1893 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1894 
1895 	if (m_bo_qo_id != 0)
1896 	{
1897 		gl.deleteBuffers(1, &m_bo_qo_id);
1898 
1899 		m_bo_qo_id = 0;
1900 	}
1901 
1902 	if (m_fbo_id != 0)
1903 	{
1904 		gl.deleteFramebuffers(1, &m_fbo_id);
1905 
1906 		m_fbo_id = 0;
1907 	}
1908 
1909 	if (m_po_id != 0)
1910 	{
1911 		gl.deleteProgram(m_po_id);
1912 
1913 		m_po_id = 0;
1914 	}
1915 
1916 	if (m_qo_id != 0)
1917 	{
1918 		gl.deleteQueries(1, &m_qo_id);
1919 
1920 		m_qo_id = 0;
1921 	}
1922 
1923 	if (m_to_id != 0)
1924 	{
1925 		gl.deleteTextures(1, &m_to_id);
1926 
1927 		m_to_id = 0;
1928 	}
1929 
1930 	if (m_vao_id != 0)
1931 	{
1932 		gl.deleteVertexArrays(1, &m_vao_id);
1933 
1934 		m_vao_id = 0;
1935 	}
1936 
1937 	if (m_vbo_id != 0)
1938 	{
1939 		gl.deleteBuffers(1, &m_vbo_id);
1940 
1941 		m_vbo_id = 0;
1942 	}
1943 
1944 	deinitObjects();
1945 }
1946 
1947 /** Empty method that should be overloaded by inheriting methods.
1948  *
1949  *  The method can be thought as of a placeholder for code that deinitializes
1950  *  test-specific GL objects.
1951  **/
deinitObjects()1952 void PipelineStatisticsQueryTestFunctionalBase::deinitObjects()
1953 {
1954 	/* Left blank intentionally - this method should be overloaded by deriving
1955 	 * classes.
1956 	 */
1957 }
1958 
1959 /** Initializes a framebuffer object that can be used by inheriting tests
1960  *  for holding rendered data.
1961  **/
initFBO()1962 void PipelineStatisticsQueryTestFunctionalBase::initFBO()
1963 {
1964 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1965 
1966 	/* Set up a framebuffer object */
1967 	gl.genFramebuffers(1, &m_fbo_id);
1968 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
1969 
1970 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id);
1971 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
1972 
1973 	/* Set up a texture object we will later use as a color attachment for the FBO */
1974 	gl.genTextures(1, &m_to_id);
1975 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
1976 
1977 	gl.bindTexture(GL_TEXTURE_2D, m_to_id);
1978 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
1979 
1980 	gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
1981 					GL_RGBA8, m_to_width, m_to_height);
1982 	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
1983 
1984 	/* Set up the TO as a color attachment */
1985 	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); /* level */
1986 	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
1987 
1988 	gl.viewport(0, 0, m_to_width, m_to_height);
1989 	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
1990 }
1991 
1992 /** An empty method, which can be thought of as a placeholder to initialize
1993  *  test-specific GL objects.
1994  **/
initObjects()1995 void PipelineStatisticsQueryTestFunctionalBase::initObjects()
1996 {
1997 	/* Left blank intentionally - this method should be overloaded by deriving
1998 	 * classes.
1999 	 */
2000 }
2001 
2002 /** Initializes a vertex array object which is going to be used for the draw calls.
2003  *  The initialized VAO's ID is going to be stored under m_vao_id. Zeroth vertex
2004  *  array attribute will be configured to use @param n_components_per_vertex components
2005  *  and will use vertex buffer object defined by ID stored in m_vbo_id, whose data
2006  *  are expected to start at an offset defined by m_vbo_vertex_data_offset.
2007  *
2008  *  @param n_components_per_vertex As per description.
2009  */
initVAO(unsigned int n_components_per_vertex)2010 void PipelineStatisticsQueryTestFunctionalBase::initVAO(unsigned int n_components_per_vertex)
2011 {
2012 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2013 
2014 	/* Release an VAO that's already been created */
2015 	if (m_vao_id != 0)
2016 	{
2017 		gl.deleteVertexArrays(1, &m_vao_id);
2018 
2019 		m_vao_id = 0;
2020 	}
2021 
2022 	/* Generate a new one */
2023 	gl.genVertexArrays(1, &m_vao_id);
2024 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2025 
2026 	gl.bindVertexArray(m_vao_id);
2027 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2028 
2029 	/* Set it up */
2030 	gl.vertexAttribPointer(0,											/* index */
2031 						   n_components_per_vertex, GL_FLOAT, GL_FALSE, /* normalized */
2032 						   0,											/* stride */
2033 						   (glw::GLvoid*)(deUintptr)m_vbo_vertex_data_offset);
2034 	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
2035 
2036 	gl.enableVertexAttribArray(0); /* index */
2037 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
2038 
2039 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbo_id);
2040 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2041 }
2042 
2043 /** Initializes a vertex buffer object and stores its ID under m_vbo_id.
2044  *  It is assumed index data is expressed in GL_UNSIGNED_INT.
2045  *
2046  *  The following fields will be modified by the method:
2047  *
2048  *  m_vbo_n_indices:                          Will hold the number of indices stored in index
2049  *                                            data buffer.
2050  *  m_vbo_vertex_data_offset:                 Will hold the offset, from which the vertex
2051  *                                            data will be stored in VBO.
2052  *  m_vbo_index_data_offset:                  Will hold the offset, from which the index
2053  *                                            data will be stored in VBO.
2054  *  m_vbo_indirect_arrays_argument_offset:    Will hold the offset, from which
2055  *                                            glDrawArraysIndirect() arguments will be
2056  *                                            stored in VBO.
2057  *  m_vbo_indirect_elements_argument_offset:  Will hold the offset, from which
2058  *                                            glDrawElementsIndirect() arguments will be
2059  *                                            stored in VBO.
2060  *  m_indirect_draw_call_firstindex_argument: Will be updated to point to the location, from
2061  *                                            which index data starts.
2062  *
2063  *  @param raw_vertex_data                        Pointer to a buffer that holds vertex data
2064  *                                                which should be used when constructing the VBO.
2065  *                                                Must not be NULL.
2066  *  @param raw_vertex_data_size                   Number of bytes available for reading under
2067  *                                                @param raw_vertex_data.
2068  *  @param raw_index_data                         Pointer to a buffer that holds index data
2069  *                                                which should be used when constructing the VBO.
2070  *                                                Must not be NULL.
2071  *  @param raw_index_data_size                    Number of bytes available for reading under
2072  *                                                @param raw_index_data .
2073  *  @param indirect_draw_bo_count_argument        Argument to be used for indirect draw calls'
2074  *                                                "count" argument.
2075  *  @param indirect_draw_bo_primcount_argument    Argument to be used for indirect draw calls'
2076  *                                                "primcount" argument.
2077  *  @param indirect_draw_bo_baseinstance_argument Argument to be used for indirect draw calls'
2078  *                                                "baseinstance" argument.
2079  *  @param indirect_draw_bo_first_argument        Argument to be used for indirect draw calls'
2080  *                                                "first" argument.
2081  *  @param indirect_draw_bo_basevertex_argument   Argument to be used for indirect draw calls'
2082  *                                                "basevertex" argument.
2083  *
2084  **/
initVBO( const float* raw_vertex_data, unsigned int raw_vertex_data_size, const unsigned int* raw_index_data, unsigned int raw_index_data_size, unsigned int indirect_draw_bo_count_argument, unsigned int indirect_draw_bo_primcount_argument, unsigned int indirect_draw_bo_baseinstance_argument, unsigned int indirect_draw_bo_first_argument, unsigned int indirect_draw_bo_basevertex_argument)2085 void PipelineStatisticsQueryTestFunctionalBase::initVBO(
2086 	const float* raw_vertex_data, unsigned int raw_vertex_data_size, const unsigned int* raw_index_data,
2087 	unsigned int raw_index_data_size, unsigned int indirect_draw_bo_count_argument,
2088 	unsigned int indirect_draw_bo_primcount_argument, unsigned int indirect_draw_bo_baseinstance_argument,
2089 	unsigned int indirect_draw_bo_first_argument, unsigned int indirect_draw_bo_basevertex_argument)
2090 {
2091 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2092 	glu::ContextType contextType = m_context.getRenderContext().getType();
2093 
2094 	/* If we already have initialized a VBO, delete it before we continue */
2095 	if (m_vbo_id != 0)
2096 	{
2097 		gl.deleteBuffers(1, &m_vbo_id);
2098 
2099 		m_vbo_id = 0;
2100 	}
2101 
2102 	/* Our BO storage is formed as below:
2103 	 *
2104 	 * [raw vertex data]
2105 	 * [raw index data]
2106 	 * [indirect glDrawArrays() call arguments]
2107 	 * [indirect glDrawElements() call arguments]
2108 	 *
2109 	 * We store the relevant offsets in member fields, so that they can be used by actual test
2110 	 * implementation.
2111 	 */
2112 	const unsigned int indirect_arrays_draw_call_arguments_size   = sizeof(unsigned int) * 4; /* as per spec */
2113 	const unsigned int indirect_elements_draw_call_arguments_size = sizeof(unsigned int) * 5; /* as per spec */
2114 
2115 	m_vbo_n_indices						  = raw_index_data_size / sizeof(unsigned int);
2116 	m_vbo_vertex_data_offset			  = 0;
2117 	m_vbo_index_data_offset				  = raw_vertex_data_size;
2118 	m_vbo_indirect_arrays_argument_offset = m_vbo_index_data_offset + raw_index_data_size;
2119 	m_vbo_indirect_elements_argument_offset =
2120 		m_vbo_indirect_arrays_argument_offset + indirect_arrays_draw_call_arguments_size;
2121 
2122 	/* Set up 'firstindex' argument so that it points at correct index data location */
2123 	DE_ASSERT((m_vbo_index_data_offset % sizeof(unsigned int)) == 0);
2124 
2125 	m_indirect_draw_call_firstindex_argument =
2126 		static_cast<unsigned int>(m_vbo_index_data_offset / sizeof(unsigned int));
2127 
2128 	/* Form indirect draw call argument buffers */
2129 	unsigned int arrays_draw_call_arguments[] = { indirect_draw_bo_count_argument, indirect_draw_bo_primcount_argument,
2130 												  indirect_draw_bo_first_argument,
2131 												  indirect_draw_bo_baseinstance_argument };
2132 	unsigned int elements_draw_call_arguments[] = {
2133 		indirect_draw_bo_count_argument, indirect_draw_bo_primcount_argument, m_indirect_draw_call_firstindex_argument,
2134 		indirect_draw_bo_basevertex_argument, indirect_draw_bo_baseinstance_argument
2135 	};
2136 
2137 	/* Set up BO storage */
2138 	const unsigned int bo_data_size =
2139 		m_vbo_indirect_elements_argument_offset + indirect_elements_draw_call_arguments_size;
2140 
2141 	gl.genBuffers(1, &m_vbo_id);
2142 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2143 
2144 	gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
2145 	if (glu::contextSupports(contextType, glu::ApiType::core(4, 0)) ||
2146 	    m_context.getContextInfo().isExtensionSupported("GL_ARB_draw_indirect"))
2147 	{
2148 		gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_vbo_id);
2149 	}
2150 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbo_id);
2151 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed.");
2152 
2153 	gl.bufferData(GL_ARRAY_BUFFER, bo_data_size, DE_NULL, /* data */
2154 				  GL_STATIC_DRAW);
2155 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2156 
2157 	gl.bufferSubData(GL_ARRAY_BUFFER, m_vbo_vertex_data_offset, raw_vertex_data_size, raw_vertex_data);
2158 	gl.bufferSubData(GL_ARRAY_BUFFER, m_vbo_index_data_offset, raw_index_data_size, raw_index_data);
2159 	gl.bufferSubData(GL_ARRAY_BUFFER, m_vbo_indirect_arrays_argument_offset, sizeof(arrays_draw_call_arguments),
2160 					 arrays_draw_call_arguments);
2161 	gl.bufferSubData(GL_ARRAY_BUFFER, m_vbo_indirect_elements_argument_offset, sizeof(elements_draw_call_arguments),
2162 					 elements_draw_call_arguments);
2163 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
2164 }
2165 
2166 /** Performs the actual test.
2167  *
2168  *  @return Always STOP.
2169  **/
iterate()2170 tcu::TestNode::IterateResult PipelineStatisticsQueryTestFunctionalBase::iterate()
2171 {
2172 	bool has_passed = true;
2173 	glu::ContextType contextType = m_context.getRenderContext().getType();
2174 
2175 	/* Carry on only if GL_ARB_pipeline_statistics_query extension is supported */
2176 	if (!glu::contextSupports(contextType, glu::ApiType::core(4, 6)) &&
2177 		!m_context.getContextInfo().isExtensionSupported("GL_ARB_pipeline_statistics_query"))
2178 	{
2179 		throw tcu::NotSupportedError("GL_ARB_pipeline_statistics_query extension is not supported");
2180 	}
2181 
2182 	/* Initialize QO BO storage if GL_ARB_query_buffer_object is supported */
2183 	if (m_context.getContextInfo().isExtensionSupported("GL_ARB_query_buffer_object"))
2184 	{
2185 		initQOBO();
2186 
2187 		DE_ASSERT(m_bo_qo_id != 0);
2188 	}
2189 
2190 	/* Initialize other test-specific objects */
2191 	initObjects();
2192 
2193 	/* Iterate through all pipeline statistics query object types */
2194 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2195 
2196 	for (unsigned int n_query_target = 0; n_query_target < PipelineStatisticsQueryUtilities::n_query_targets;
2197 		 ++n_query_target)
2198 	{
2199 		glw::GLenum current_query_target = PipelineStatisticsQueryUtilities::query_targets[n_query_target];
2200 
2201 		/* Make sure the query is supported */
2202 		if (!PipelineStatisticsQueryUtilities::isQuerySupported(current_query_target, m_context.getContextInfo(), m_context.getRenderContext()))
2203 		{
2204 			continue;
2205 		}
2206 
2207 		if (shouldExecuteForQueryTarget(current_query_target))
2208 		{
2209 			/* Initialize the query object */
2210 			gl.genQueries(1, &m_qo_id);
2211 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries() call failed.");
2212 
2213 			/* Execute the test for the particular query target. */
2214 			has_passed &= executeTest(current_query_target);
2215 
2216 			/* Delete the query object */
2217 			gl.deleteQueries(1, &m_qo_id);
2218 			GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteQueries() call failed.");
2219 
2220 			m_qo_id = 0;
2221 		}
2222 	} /* for (all query targets) */
2223 
2224 	if (has_passed)
2225 	{
2226 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2227 	}
2228 	else
2229 	{
2230 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2231 	}
2232 
2233 	return STOP;
2234 }
2235 
2236 /** Initializes a query buffer object. */
initQOBO()2237 void PipelineStatisticsQueryTestFunctionalBase::initQOBO()
2238 {
2239 	const glw::Functions gl = m_context.getRenderContext().getFunctions();
2240 
2241 	/* Set up the buffer object we will use for storage of query object results */
2242 	unsigned char bo_data[PipelineStatisticsQueryUtilities::qo_bo_size];
2243 
2244 	memset(bo_data, 0xFF, sizeof(bo_data));
2245 
2246 	gl.genBuffers(1, &m_bo_qo_id);
2247 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2248 
2249 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_qo_id);
2250 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2251 
2252 	gl.bufferData(GL_ARRAY_BUFFER, PipelineStatisticsQueryUtilities::qo_bo_size, bo_data, GL_STATIC_DRAW);
2253 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2254 }
2255 
2256 /** Executes a draw call, whose type is specified under pThis->m_current_draw_call_type.
2257  *
2258  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctionalBase instance, which
2259  *               should be used to extract the draw call type.
2260  *
2261  *  @return Always true.
2262  **/
queryCallbackDrawCallHandler(void* pThis)2263 bool PipelineStatisticsQueryTestFunctionalBase::queryCallbackDrawCallHandler(void* pThis)
2264 {
2265 	PipelineStatisticsQueryTestFunctionalBase* pInstance = (PipelineStatisticsQueryTestFunctionalBase*)pThis;
2266 	const glw::Functions&					   gl		 = pInstance->m_context.getRenderContext().getFunctions();
2267 
2268 	/* Issue the draw call */
2269 	glw::GLenum primitive_type =
2270 		PipelineStatisticsQueryUtilities::getEnumForPrimitiveType(pInstance->m_current_primitive_type);
2271 
2272 	switch (pInstance->m_current_draw_call_type)
2273 	{
2274 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWARRAYS:
2275 	{
2276 		gl.drawArrays(primitive_type, pInstance->m_indirect_draw_call_first_argument,
2277 					  pInstance->m_indirect_draw_call_count_argument);
2278 
2279 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
2280 
2281 		break;
2282 	}
2283 
2284 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWARRAYSINDIRECT:
2285 	{
2286 		gl.drawArraysIndirect(primitive_type,
2287 							  (const glw::GLvoid*)(deUintptr)pInstance->m_vbo_indirect_arrays_argument_offset);
2288 
2289 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArraysIndirect() call failed.");
2290 
2291 		break;
2292 	}
2293 
2294 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWARRAYSINSTANCED:
2295 	{
2296 		gl.drawArraysInstanced(primitive_type, pInstance->m_indirect_draw_call_first_argument,
2297 							   pInstance->m_indirect_draw_call_count_argument,
2298 							   pInstance->m_indirect_draw_call_primcount_argument);
2299 
2300 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArraysInstanced() call failed.");
2301 
2302 		break;
2303 	}
2304 
2305 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWARRAYSINSTANCEDBASEINSTANCE:
2306 	{
2307 		gl.drawArraysInstancedBaseInstance(primitive_type, pInstance->m_indirect_draw_call_first_argument,
2308 										   pInstance->m_indirect_draw_call_count_argument,
2309 										   pInstance->m_indirect_draw_call_primcount_argument,
2310 										   pInstance->m_indirect_draw_call_baseinstance_argument);
2311 
2312 		break;
2313 	}
2314 
2315 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTS:
2316 	{
2317 		gl.drawElements(primitive_type, pInstance->m_indirect_draw_call_count_argument, GL_UNSIGNED_INT,
2318 						(glw::GLvoid*)(deUintptr)pInstance->m_vbo_index_data_offset);
2319 
2320 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElements() call failed.");
2321 
2322 		break;
2323 	}
2324 
2325 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSBASEVERTEX:
2326 	{
2327 		gl.drawElementsBaseVertex(primitive_type, pInstance->m_indirect_draw_call_count_argument, GL_UNSIGNED_INT,
2328 								  (glw::GLvoid*)(deUintptr)pInstance->m_vbo_index_data_offset,
2329 								  pInstance->m_indirect_draw_call_basevertex_argument);
2330 
2331 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElementsBaseVertex() call failed.");
2332 
2333 		break;
2334 	}
2335 
2336 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSINDIRECT:
2337 	{
2338 		gl.drawElementsIndirect(primitive_type, GL_UNSIGNED_INT,
2339 								(glw::GLvoid*)(deUintptr)pInstance->m_vbo_indirect_elements_argument_offset);
2340 
2341 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElementsIndirect() call failed.");
2342 
2343 		break;
2344 	}
2345 
2346 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCED:
2347 	{
2348 		gl.drawElementsInstanced(primitive_type, pInstance->m_indirect_draw_call_count_argument, GL_UNSIGNED_INT,
2349 								 (glw::GLvoid*)(deUintptr)pInstance->m_vbo_index_data_offset,
2350 								 pInstance->m_indirect_draw_call_primcount_argument);
2351 
2352 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElementsInstanced() call failed.");
2353 
2354 		break;
2355 	}
2356 
2357 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCEDBASEINSTANCE:
2358 	{
2359 		gl.drawElementsInstancedBaseInstance(
2360 			primitive_type, pInstance->m_indirect_draw_call_count_argument, GL_UNSIGNED_INT,
2361 			(glw::GLvoid*)(deUintptr)pInstance->m_vbo_index_data_offset,
2362 			pInstance->m_indirect_draw_call_primcount_argument, pInstance->m_indirect_draw_call_baseinstance_argument);
2363 
2364 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElementsInstancedBaseInstance() call failed.");
2365 
2366 		break;
2367 	}
2368 
2369 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCE:
2370 	{
2371 		gl.drawElementsInstancedBaseVertexBaseInstance(
2372 			primitive_type, pInstance->m_indirect_draw_call_count_argument, GL_UNSIGNED_INT,
2373 			(glw::GLvoid*)(deUintptr)pInstance->m_vbo_index_data_offset,
2374 			pInstance->m_indirect_draw_call_primcount_argument, pInstance->m_indirect_draw_call_basevertex_argument,
2375 			pInstance->m_indirect_draw_call_baseinstance_argument);
2376 
2377 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElementsInstancedBaseVertexBaseInstance() call failed.");
2378 
2379 		break;
2380 	}
2381 
2382 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWRANGEELEMENTS:
2383 	{
2384 		gl.drawRangeElements(primitive_type, 0, /* start */
2385 							 pInstance->m_vbo_n_indices, pInstance->m_indirect_draw_call_count_argument,
2386 							 GL_UNSIGNED_INT, (glw::GLvoid*)(deUintptr)pInstance->m_vbo_index_data_offset);
2387 
2388 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawRangeElements() call failed.");
2389 
2390 		break;
2391 	}
2392 
2393 	case PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWRANGEELEMENTSBASEVERTEX:
2394 	{
2395 		gl.drawRangeElementsBaseVertex(primitive_type, 0,								   /* start */
2396 									   pInstance->m_indirect_draw_call_count_argument - 1, /* end */
2397 									   pInstance->m_indirect_draw_call_count_argument, GL_UNSIGNED_INT,
2398 									   (glw::GLvoid*)(deUintptr)pInstance->m_vbo_index_data_offset,
2399 									   pInstance->m_indirect_draw_call_basevertex_argument);
2400 
2401 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawRangeElementsBaseVertex() call failed.");
2402 
2403 		break;
2404 	}
2405 
2406 	default:
2407 	{
2408 		TCU_FAIL("Unrecognized draw call type");
2409 	}
2410 	} /* switch (m_current_draw_call_type) */
2411 
2412 	return true;
2413 }
2414 
2415 /** Tells whether the test instance should be executed for user-specified query target.
2416  *  Base class implementation returns true for all values of @param query_target.
2417  *
2418  *  @param query_target Query target to be used for the call.
2419  *
2420  *  @return Always true.
2421  **/
shouldExecuteForQueryTarget(glw::GLenum query_target)2422 bool PipelineStatisticsQueryTestFunctionalBase::shouldExecuteForQueryTarget(glw::GLenum query_target)
2423 {
2424 	(void)query_target;
2425 	return true;
2426 }
2427 
2428 /** Constructor.
2429  *
2430  *  @param context Rendering context.
2431  **/
PipelineStatisticsQueryTestFunctional1(deqp::Context& context)2432 PipelineStatisticsQueryTestFunctional1::PipelineStatisticsQueryTestFunctional1(deqp::Context& context)
2433 	: PipelineStatisticsQueryTestFunctionalBase(context, "functional_default_qo_values",
2434 												"Verifies that all pipeline statistics query objects "
2435 												"use a default value of 0.")
2436 {
2437 	/* Left blank intentionally */
2438 }
2439 
2440 /** Executes a test iteration for user-specified query target.
2441  *
2442  *  @param current_query_target Pipeline statistics query target to execute the iteration
2443  *                              for.
2444  *
2445  *  @return true if the test passed for the iteration, false otherwise.
2446  **/
executeTest(glw::GLenum current_query_target)2447 bool PipelineStatisticsQueryTestFunctional1::executeTest(glw::GLenum current_query_target)
2448 {
2449 	bool													 result = true;
2450 	bool													 skipped = false;
2451 	PipelineStatisticsQueryUtilities::_test_execution_result run_result;
2452 
2453 	if (!PipelineStatisticsQueryUtilities::executeQuery(
2454 			current_query_target, m_qo_id, m_bo_qo_id, DE_NULL, /* pfn_draw */
2455 			DE_NULL,											/* draw_user_arg */
2456 			m_context.getRenderContext(), m_testCtx, m_context.getContextInfo(), &run_result, skipped))
2457 	{
2458 		m_testCtx.getLog() << tcu::TestLog::Message << "Could not retrieve test run results for query target "
2459 													   "["
2460 						   << PipelineStatisticsQueryUtilities::getStringForEnum(current_query_target) << "]"
2461 						   << tcu::TestLog::EndMessage;
2462 
2463 		result = false;
2464 	}
2465 	else if (!skipped)
2466 	{
2467 		const glw::GLuint64 expected_value = 0;
2468 
2469 		result &= PipelineStatisticsQueryUtilities::verifyResultValues(
2470 			run_result, 1, &expected_value, m_bo_qo_id != 0, /* should_check_qo_bo_values */
2471 			current_query_target, DE_NULL, DE_NULL,
2472 			false, /* is_primitive_restart_enabled */
2473 			m_testCtx, PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EXACT_MATCH);
2474 	} /* if (run results were obtained successfully) */
2475 
2476 	return result;
2477 }
2478 
2479 /** Constructor.
2480  *
2481  *  @param context Rendering context
2482  */
PipelineStatisticsQueryTestFunctional2(deqp::Context& context)2483 PipelineStatisticsQueryTestFunctional2::PipelineStatisticsQueryTestFunctional2(deqp::Context& context)
2484 	: PipelineStatisticsQueryTestFunctionalBase(context, "functional_non_rendering_commands_do_not_affect_queries",
2485 												"Verifies that non-rendering commands do not affect query"
2486 												" values.")
2487 	, m_bo_id(0)
2488 	, m_fbo_draw_id(0)
2489 	, m_fbo_read_id(0)
2490 	, m_to_draw_fbo_id(0)
2491 	, m_to_read_fbo_id(0)
2492 	, m_to_height(16)
2493 	, m_to_width(16)
2494 {
2495 	/* Left blank intentionally */
2496 }
2497 
2498 /** Deinitializes all GL objects that were created during test execution. */
deinitObjects()2499 void PipelineStatisticsQueryTestFunctional2::deinitObjects()
2500 {
2501 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2502 
2503 	if (m_bo_id != 0)
2504 	{
2505 		gl.deleteBuffers(1, &m_bo_id);
2506 
2507 		m_bo_id = 0;
2508 	}
2509 
2510 	if (m_fbo_draw_id != 0)
2511 	{
2512 		gl.deleteFramebuffers(1, &m_fbo_draw_id);
2513 
2514 		m_fbo_draw_id = 0;
2515 	}
2516 
2517 	if (m_fbo_read_id != 0)
2518 	{
2519 		gl.deleteFramebuffers(1, &m_fbo_read_id);
2520 
2521 		m_fbo_read_id = 0;
2522 	}
2523 
2524 	if (m_to_draw_fbo_id != 0)
2525 	{
2526 		gl.deleteTextures(1, &m_to_draw_fbo_id);
2527 
2528 		m_to_draw_fbo_id = 0;
2529 	}
2530 
2531 	if (m_to_read_fbo_id != 0)
2532 	{
2533 		gl.deleteTextures(1, &m_to_read_fbo_id);
2534 
2535 		m_to_read_fbo_id = 0;
2536 	}
2537 }
2538 
2539 /** Callback handler which calls glBlitFramebuffer() API function and makes sure it
2540  *  was executed successfully.
2541  *
2542  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2543  *               be NULL.
2544  *
2545  *  @return Always true.
2546  **/
executeBlitFramebufferTest(void* pThis)2547 bool PipelineStatisticsQueryTestFunctional2::executeBlitFramebufferTest(void* pThis)
2548 {
2549 	PipelineStatisticsQueryTestFunctional2* data_ptr = (PipelineStatisticsQueryTestFunctional2*)pThis;
2550 	const glw::Functions&					gl		 = data_ptr->m_context.getRenderContext().getFunctions();
2551 
2552 	/* Framebuffer objects are bound to their FB targets at this point */
2553 	gl.blitFramebuffer(0,						   /* srcX0 */
2554 					   0,						   /* srcY0 */
2555 					   data_ptr->m_to_width,	   /* srcX1 */
2556 					   data_ptr->m_to_height,	  /* srcY1 */
2557 					   0,						   /* dstX0 */
2558 					   0,						   /* dstY0 */
2559 					   data_ptr->m_to_width << 1,  /* dstX1 */
2560 					   data_ptr->m_to_height << 1, /* dstY1 */
2561 					   GL_COLOR_BUFFER_BIT,		   /* mask */
2562 					   GL_LINEAR);				   /* filter */
2563 
2564 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBlitFramebuffer() call failed.");
2565 
2566 	return true;
2567 }
2568 
2569 /** Callback handler which calls glBufferSubData() API function and makes sure it
2570  *  was executed successfully.
2571  *
2572  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2573  *               be NULL.
2574  *
2575  *  @return Always true.
2576  **/
executeBufferSubDataTest(void* pThis)2577 bool PipelineStatisticsQueryTestFunctional2::executeBufferSubDataTest(void* pThis)
2578 {
2579 	PipelineStatisticsQueryTestFunctional2* data_ptr	   = (PipelineStatisticsQueryTestFunctional2*)pThis;
2580 	const glw::Functions&					gl			   = data_ptr->m_context.getRenderContext().getFunctions();
2581 	const unsigned int						test_data_size = (PipelineStatisticsQueryTestFunctional2::bo_size / 2);
2582 	unsigned char							test_bo_data[test_data_size];
2583 
2584 	memset(test_bo_data, 0xFF, test_data_size);
2585 
2586 	gl.bindBuffer(GL_ARRAY_BUFFER, data_ptr->m_bo_id);
2587 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2588 
2589 	gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
2590 					 test_data_size, test_bo_data);
2591 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
2592 
2593 	return true;
2594 }
2595 
2596 /** Callback handler which calls glClearBufferfv() API function and makes sure it
2597  *  was executed successfully.
2598  *
2599  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2600  *               be NULL.
2601  *
2602  *  @return Always true.
2603  **/
executeClearBufferfvColorBufferTest(void* pThis)2604 bool PipelineStatisticsQueryTestFunctional2::executeClearBufferfvColorBufferTest(void* pThis)
2605 {
2606 	const glw::GLfloat						clear_color[4] = { 0, 0.1f, 0.2f, 0.3f };
2607 	PipelineStatisticsQueryTestFunctional2* data_ptr	   = (PipelineStatisticsQueryTestFunctional2*)pThis;
2608 	const glw::Functions&					gl			   = data_ptr->m_context.getRenderContext().getFunctions();
2609 
2610 	gl.clearBufferfv(GL_COLOR, 0, /* drawbuffer */
2611 					 clear_color);
2612 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferfv() call failed.");
2613 
2614 	return true;
2615 }
2616 
2617 /** Callback handler which calls glClearBufferfv() API function and makes sure it
2618  *  was executed successfully.
2619  *
2620  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2621  *               be NULL.
2622  *
2623  *  @return Always true.
2624  **/
executeClearBufferfvDepthBufferTest(void* pThis)2625 bool PipelineStatisticsQueryTestFunctional2::executeClearBufferfvDepthBufferTest(void* pThis)
2626 {
2627 	const glw::GLfloat						clear_depth = 0.1f;
2628 	PipelineStatisticsQueryTestFunctional2* data_ptr	= (PipelineStatisticsQueryTestFunctional2*)pThis;
2629 	const glw::Functions&					gl			= data_ptr->m_context.getRenderContext().getFunctions();
2630 
2631 	gl.clearBufferfv(GL_DEPTH, 0, /* drawbuffer */
2632 					 &clear_depth);
2633 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferfv() call failed.");
2634 
2635 	return true;
2636 }
2637 
2638 /** Callback handler which calls glClearBufferiv() API function and makes sure it
2639  *  was executed successfully.
2640  *
2641  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2642  *               be NULL.
2643  *
2644  *  @return Always true.
2645  **/
executeClearBufferivStencilBufferTest(void* pThis)2646 bool PipelineStatisticsQueryTestFunctional2::executeClearBufferivStencilBufferTest(void* pThis)
2647 {
2648 	const glw::GLint						clear_stencil = 123;
2649 	PipelineStatisticsQueryTestFunctional2* data_ptr	  = (PipelineStatisticsQueryTestFunctional2*)pThis;
2650 	const glw::Functions&					gl			  = data_ptr->m_context.getRenderContext().getFunctions();
2651 
2652 	gl.clearBufferiv(GL_STENCIL, 0, /* drawbuffer */
2653 					 &clear_stencil);
2654 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferfv() call failed.");
2655 
2656 	return true;
2657 }
2658 
2659 /** Callback handler which calls glClearBufferSubData() API function and makes sure it
2660  *  was executed successfully.
2661  *
2662  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2663  *               be NULL.
2664  *
2665  *  @return true if glClearBufferSubData() is available, false otherwise.
2666  **/
executeClearBufferSubDataTest(void* pThis)2667 bool PipelineStatisticsQueryTestFunctional2::executeClearBufferSubDataTest(void* pThis)
2668 {
2669 	PipelineStatisticsQueryTestFunctional2* data_ptr = (PipelineStatisticsQueryTestFunctional2*)pThis;
2670 	const glw::Functions&					gl		 = data_ptr->m_context.getRenderContext().getFunctions();
2671 	bool									result   = true;
2672 
2673 	if (!glu::contextSupports(data_ptr->m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)) &&
2674 		gl.clearBufferSubData == NULL)
2675 	{
2676 		/* API is unavailable */
2677 		return false;
2678 	}
2679 
2680 	/* Execute the API call */
2681 	const unsigned char value = 0xFF;
2682 
2683 	gl.clearBufferSubData(GL_ARRAY_BUFFER, GL_R8, 0, /* offset */
2684 						  data_ptr->bo_size, GL_RED, GL_UNSIGNED_BYTE, &value);
2685 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferSubData() call failed.");
2686 
2687 	/* All done */
2688 	return result;
2689 }
2690 
2691 /** Callback handler which calls glClear() API function configured to clear color
2692  *  buffer and makes sure it was executed successfully.
2693  *
2694  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2695  *               be NULL.
2696  *
2697  *  @return Always true.
2698  **/
executeClearColorBufferTest(void* pThis)2699 bool PipelineStatisticsQueryTestFunctional2::executeClearColorBufferTest(void* pThis)
2700 {
2701 	PipelineStatisticsQueryTestFunctional2* data_ptr = (PipelineStatisticsQueryTestFunctional2*)pThis;
2702 	const glw::Functions&					gl		 = data_ptr->m_context.getRenderContext().getFunctions();
2703 
2704 	gl.clear(GL_COLOR_BUFFER_BIT);
2705 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
2706 
2707 	return true;
2708 }
2709 
2710 /** Callback handler which calls glClear() API function configured to clear depth
2711  *  buffer and makes sure it was executed successfully.
2712  *
2713  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2714  *               be NULL.
2715  *
2716  *  @return Always true.
2717  **/
executeClearDepthBufferTest(void* pThis)2718 bool PipelineStatisticsQueryTestFunctional2::executeClearDepthBufferTest(void* pThis)
2719 {
2720 	PipelineStatisticsQueryTestFunctional2* data_ptr = (PipelineStatisticsQueryTestFunctional2*)pThis;
2721 	const glw::Functions&					gl		 = data_ptr->m_context.getRenderContext().getFunctions();
2722 
2723 	gl.clear(GL_DEPTH_BUFFER_BIT);
2724 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
2725 
2726 	return true;
2727 }
2728 
2729 /** Callback handler which calls glClear() API function configured to clear stencil
2730  *  buffer and makes sure it was executed successfully.
2731  *
2732  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2733  *               be NULL.
2734  *
2735  *  @return Always true.
2736  **/
executeClearStencilBufferTest(void* pThis)2737 bool PipelineStatisticsQueryTestFunctional2::executeClearStencilBufferTest(void* pThis)
2738 {
2739 	PipelineStatisticsQueryTestFunctional2* data_ptr = (PipelineStatisticsQueryTestFunctional2*)pThis;
2740 	const glw::Functions&					gl		 = data_ptr->m_context.getRenderContext().getFunctions();
2741 
2742 	gl.clear(GL_STENCIL_BUFFER_BIT);
2743 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
2744 
2745 	return true;
2746 }
2747 
2748 /** Callback handler which calls glClearTexSubImage() API function (if available).
2749  *
2750  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2751  *               be NULL.
2752  *
2753  *  @return true if the function is supported by the running GL implementation, false
2754  *               otherwise.
2755  **/
executeClearTexSubImageTest(void* pThis)2756 bool PipelineStatisticsQueryTestFunctional2::executeClearTexSubImageTest(void* pThis)
2757 {
2758 	PipelineStatisticsQueryTestFunctional2* data_ptr = (PipelineStatisticsQueryTestFunctional2*)pThis;
2759 	const glw::Functions&					gl		 = data_ptr->m_context.getRenderContext().getFunctions();
2760 	bool									result   = true;
2761 
2762 	if (!glu::contextSupports(data_ptr->m_context.getRenderContext().getType(), glu::ApiType::core(4, 4)) &&
2763 		gl.clearTexSubImage == NULL)
2764 	{
2765 		/* API is unavailable */
2766 		return false;
2767 	}
2768 
2769 	/* Execute the API call */
2770 	const unsigned char test_value = 0xFF;
2771 
2772 	gl.clearTexSubImage(data_ptr->m_to_draw_fbo_id, 0,							/* level */
2773 						0,														/* xoffset */
2774 						0,														/* yoffset */
2775 						0,														/* zoffset */
2776 						data_ptr->m_to_width / 2, data_ptr->m_to_height / 2, 1, /* depth */
2777 						GL_RED, GL_UNSIGNED_BYTE, &test_value);
2778 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearTexSubImage() call failed.");
2779 
2780 	/* All done */
2781 	return result;
2782 }
2783 
2784 /** Callback handler which calls glCopyImageSubData() API function (if available).
2785  *
2786  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2787  *               be NULL.
2788  *
2789  *  @return true if the function is supported by the running GL implementation, false
2790  *               otherwise.
2791  **/
executeCopyImageSubDataTest(void* pThis)2792 bool PipelineStatisticsQueryTestFunctional2::executeCopyImageSubDataTest(void* pThis)
2793 {
2794 	PipelineStatisticsQueryTestFunctional2* data_ptr = (PipelineStatisticsQueryTestFunctional2*)pThis;
2795 	const glw::Functions&					gl		 = data_ptr->m_context.getRenderContext().getFunctions();
2796 	bool									result   = true;
2797 
2798 	if (!glu::contextSupports(data_ptr->m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)) &&
2799 		gl.copyImageSubData == NULL)
2800 	{
2801 		/* API is unavailable */
2802 		return false;
2803 	}
2804 
2805 	/* Execute the API call */
2806 	gl.copyImageSubData(data_ptr->m_to_draw_fbo_id, GL_TEXTURE_2D, 0,			 /* srcLevel */
2807 						0,														 /* srcX */
2808 						0,														 /* srcY */
2809 						0,														 /* srcZ */
2810 						data_ptr->m_to_read_fbo_id, GL_TEXTURE_2D, 0,			 /* dstLevel */
2811 						0,														 /* dstX */
2812 						0,														 /* dstY */
2813 						0,														 /* dstZ */
2814 						data_ptr->m_to_width / 2, data_ptr->m_to_height / 2, 1); /* src_depth */
2815 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCopyImageSubData() call failed.");
2816 
2817 	/* All done */
2818 	return result;
2819 }
2820 
2821 /** Callback handler which calls glTexSubImage2D().
2822  *
2823  *  @param pThis Pointer to a PipelineStatisticsQueryTestFunctional2 instance. Must not
2824  *               be NULL.
2825  *
2826  *  @return true Always true.
2827  **/
executeTexSubImageTest(void* pThis)2828 bool PipelineStatisticsQueryTestFunctional2::executeTexSubImageTest(void* pThis)
2829 {
2830 	PipelineStatisticsQueryTestFunctional2* data_ptr	   = (PipelineStatisticsQueryTestFunctional2*)pThis;
2831 	const glw::Functions&					gl			   = data_ptr->m_context.getRenderContext().getFunctions();
2832 	const unsigned int						test_data_size = PipelineStatisticsQueryTestFunctional2::bo_size / 2;
2833 	unsigned char							test_data[test_data_size];
2834 
2835 	memset(test_data, 0xFF, test_data_size);
2836 
2837 	gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
2838 					 0,				   /* xoffset */
2839 					 0,				   /* yoffset */
2840 					 data_ptr->m_to_width / 2, data_ptr->m_to_height / 2, GL_RED, GL_UNSIGNED_BYTE, test_data);
2841 	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed.");
2842 
2843 	return true;
2844 }
2845 
2846 /** Executes a test iteration for user-specified query target.
2847  *
2848  *  @param current_query_target Pipeline statistics query target to execute the iteration
2849  *                              for.
2850  *
2851  *  @return true if the test passed for the iteration, false otherwise.
2852  **/
executeTest(glw::GLenum current_query_target)2853 bool PipelineStatisticsQueryTestFunctional2::executeTest(glw::GLenum current_query_target)
2854 {
2855 	bool															result = true;
2856 	bool															skipped = false;
2857 	PipelineStatisticsQueryUtilities::_test_execution_result		run_result;
2858 	const PipelineStatisticsQueryUtilities::PFNQUERYDRAWHANDLERPROC query_draw_handlers[] = {
2859 		executeBlitFramebufferTest,
2860 		executeBufferSubDataTest,
2861 		executeClearBufferfvColorBufferTest,
2862 		executeClearBufferfvDepthBufferTest,
2863 		executeClearBufferivStencilBufferTest,
2864 		executeClearBufferSubDataTest,
2865 		executeClearColorBufferTest,
2866 		executeClearDepthBufferTest,
2867 		executeClearStencilBufferTest,
2868 		executeClearTexSubImageTest,
2869 		executeCopyImageSubDataTest,
2870 		executeTexSubImageTest,
2871 	};
2872 	const unsigned int n_query_draw_handlers = sizeof(query_draw_handlers) / sizeof(query_draw_handlers[0]);
2873 
2874 	for (unsigned int n = 0; n < n_query_draw_handlers; ++n)
2875 	{
2876 		const PipelineStatisticsQueryUtilities::PFNQUERYDRAWHANDLERPROC& draw_handler_pfn = query_draw_handlers[n];
2877 
2878 		/* Query executors can return false if a given test cannot be executed, given
2879 		 * work environment constraint (eg. insufficient GL version). In case of an error,
2880 		 * they will throw an exception.
2881 		 */
2882 		if (draw_handler_pfn(this))
2883 		{
2884 			if (!PipelineStatisticsQueryUtilities::executeQuery(
2885 					current_query_target, m_qo_id, m_bo_qo_id, DE_NULL, /* pfn_draw */
2886 					DE_NULL,											/* draw_user_arg */
2887 					m_context.getRenderContext(), m_testCtx, m_context.getContextInfo(), &run_result, skipped))
2888 			{
2889 				m_testCtx.getLog() << tcu::TestLog::Message << "Query execution failed for query target "
2890 															   "["
2891 								   << PipelineStatisticsQueryUtilities::getStringForEnum(current_query_target) << "]"
2892 								   << tcu::TestLog::EndMessage;
2893 
2894 				result = false;
2895 			}
2896 			else if (!skipped)
2897 			{
2898 				const glw::GLuint64 expected_value = 0;
2899 				bool				has_passed	 = true;
2900 
2901 				has_passed = PipelineStatisticsQueryUtilities::verifyResultValues(
2902 					run_result, 1, &expected_value, m_bo_qo_id != 0,  /* should_check_qo_bo_values */
2903 					current_query_target, DE_NULL, DE_NULL, false, /* is_primitive_restart_enabled */
2904 					m_testCtx, PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EXACT_MATCH);
2905 
2906 				if (!has_passed)
2907 				{
2908 					m_testCtx.getLog() << tcu::TestLog::Message << "Test failed for iteration index [" << n << "]."
2909 									   << tcu::TestLog::EndMessage;
2910 
2911 					result = false;
2912 				}
2913 			} /* if (run results were obtained successfully) */
2914 		}	 /* if (draw handler executed successfully) */
2915 	}
2916 
2917 	return result;
2918 }
2919 
2920 /* Initializes all GL objects used by the test */
initObjects()2921 void PipelineStatisticsQueryTestFunctional2::initObjects()
2922 {
2923 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2924 
2925 	/* Set up a buffer object we will use for one of the tests */
2926 	gl.genBuffers(1, &m_bo_id);
2927 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2928 
2929 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id);
2930 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed.");
2931 
2932 	gl.bufferData(GL_ARRAY_BUFFER, bo_size, DE_NULL, /* data */
2933 				  GL_STATIC_DRAW);
2934 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2935 
2936 	/* Set up texture objects we will  use as color attachments for test FBOs */
2937 	gl.genTextures(1, &m_to_draw_fbo_id);
2938 	gl.genTextures(1, &m_to_read_fbo_id);
2939 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call(s) failed");
2940 
2941 	gl.bindTexture(GL_TEXTURE_2D, m_to_draw_fbo_id);
2942 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
2943 
2944 	gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
2945 					GL_RGBA8, m_to_width, m_to_height);
2946 	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
2947 
2948 	gl.bindTexture(GL_TEXTURE_2D, m_to_read_fbo_id);
2949 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
2950 
2951 	gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
2952 					GL_RGBA8, m_to_width, m_to_height);
2953 	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
2954 
2955 	/* Set up framebuffer objects */
2956 	gl.genFramebuffers(1, &m_fbo_draw_id);
2957 	gl.genFramebuffers(1, &m_fbo_read_id);
2958 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call(s) failed.");
2959 
2960 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_draw_id);
2961 	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read_id);
2962 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call(s) failed.");
2963 
2964 	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_draw_fbo_id, 0); /* level */
2965 	gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_read_fbo_id, 0); /* level */
2966 	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call(s) failed.");
2967 }
2968 
2969 /** Constructor.
2970  *
2971  *  @param context Rendering context
2972  */
PipelineStatisticsQueryTestFunctional3(deqp::Context& context)2973 PipelineStatisticsQueryTestFunctional3::PipelineStatisticsQueryTestFunctional3(deqp::Context& context)
2974 	: PipelineStatisticsQueryTestFunctionalBase(
2975 		  context, "functional_primitives_vertices_submitted_and_clipping_input_output_primitives",
2976 		  "Verifies that GL_PRIMITIVES_SUBMITTED_ARB, GL_VERTICES_SUBMITTED_ARB, "
2977 		  "GL_CLIPPING_INPUT_PRIMITIVES_ARB, and GL_CLIPPING_OUTPUT_PRIMITIVES_ARB "
2978 		  "queries work correctly.")
2979 	, m_is_primitive_restart_enabled(false)
2980 {
2981 	/* Left blank intentionally */
2982 }
2983 
2984 /** Deinitializes all GL objects that were created during test execution. */
deinitObjects()2985 void PipelineStatisticsQueryTestFunctional3::deinitObjects()
2986 {
2987 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2988 
2989 	if (m_po_id != 0)
2990 	{
2991 		gl.deleteProgram(m_po_id);
2992 
2993 		m_po_id = 0;
2994 	}
2995 
2996 	/* Disable "primitive restart" functionality */
2997 	gl.disable(GL_PRIMITIVE_RESTART);
2998 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call failed.");
2999 }
3000 
3001 /** Executes a test iteration for user-specified query target.
3002  *
3003  *  @param current_query_target Pipeline statistics query target to execute the iteration
3004  *                              for.
3005  *
3006  *  @return true if the test passed for the iteration, false otherwise.
3007  **/
executeTest(glw::GLenum current_query_target)3008 bool PipelineStatisticsQueryTestFunctional3::executeTest(glw::GLenum current_query_target)
3009 {
3010 	const glw::Functions&									 gl		= m_context.getRenderContext().getFunctions();
3011 	bool													 result = true;
3012 	bool													 skipped = false;
3013 	PipelineStatisticsQueryUtilities::_test_execution_result run_result;
3014 
3015 	/* Quick check: This method should only be called for GL_VERTICES_SUBMITTED_ARB,
3016 	 * GL_PRIMITIVES_SUBMITTED_ARB, GL_CLIPPING_INPUT_PRIMITIVES_ARB and
3017 	 * GL_CLIPPING_OUTPUT_PRIMITIVES_ARB queries */
3018 	DE_ASSERT(current_query_target == GL_VERTICES_SUBMITTED_ARB ||
3019 			  current_query_target == GL_PRIMITIVES_SUBMITTED_ARB ||
3020 			  current_query_target == GL_CLIPPING_INPUT_PRIMITIVES_ARB ||
3021 			  current_query_target == GL_CLIPPING_OUTPUT_PRIMITIVES_ARB);
3022 
3023 	/* Set up VBO. We don't really care much about the visual outcome,
3024 	 * so any data will do.
3025 	 */
3026 	const unsigned int n_vertex_components = 2;
3027 	const float		   vertex_data[]	   = { -0.1f, 0.2f, 0.3f,  0.1f,  0.2f,  -0.7f, 0.5f,  -0.5f,
3028 								  0.0f,  0.0f, -0.6f, -0.9f, -0.3f, 0.3f,  -0.5f, -0.5f };
3029 	const unsigned int index_data[] = {
3030 		0, 6, 2, 1, 3, 5, 4,
3031 	};
3032 	const unsigned int n_indices = sizeof(index_data) / sizeof(index_data[0]);
3033 
3034 	m_indirect_draw_call_baseinstance_argument = 1;
3035 	m_indirect_draw_call_basevertex_argument   = 0;
3036 	m_indirect_draw_call_count_argument		   = n_indices;
3037 	m_indirect_draw_call_first_argument		   = 0;
3038 	m_indirect_draw_call_primcount_argument	= 3;
3039 
3040 	initVBO(vertex_data, sizeof(vertex_data), index_data, sizeof(index_data), m_indirect_draw_call_count_argument,
3041 			m_indirect_draw_call_primcount_argument, m_indirect_draw_call_baseinstance_argument,
3042 			m_indirect_draw_call_first_argument, m_indirect_draw_call_basevertex_argument);
3043 
3044 	initVAO(n_vertex_components);
3045 
3046 	/* Verify that the query works correctly both when primitive restart functionality
3047 	 * is disabled and enabled */
3048 	const bool		   pr_statuses[] = { false, true };
3049 	const unsigned int n_pr_statuses = sizeof(pr_statuses) / sizeof(pr_statuses[0]);
3050 
3051 	for (unsigned int n_pr_status = 0; n_pr_status < n_pr_statuses; ++n_pr_status)
3052 	{
3053 		m_is_primitive_restart_enabled = pr_statuses[n_pr_status];
3054 
3055 		/* Primitive restart should never be enabled for GL_CLIPPING_INPUT_PRIMITIVES_ARB query. */
3056 		if ((current_query_target == GL_CLIPPING_INPUT_PRIMITIVES_ARB ||
3057 			 current_query_target == GL_CLIPPING_OUTPUT_PRIMITIVES_ARB) &&
3058 			m_is_primitive_restart_enabled)
3059 		{
3060 			continue;
3061 		}
3062 
3063 		/* Configure 'primitive restart' functionality */
3064 		if (!m_is_primitive_restart_enabled)
3065 		{
3066 			gl.disable(GL_PRIMITIVE_RESTART);
3067 			GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call failed.");
3068 		}
3069 		else
3070 		{
3071 			gl.primitiveRestartIndex(0);
3072 			GLU_EXPECT_NO_ERROR(gl.getError(), "glPrimitiveRestartIndex() call failed.");
3073 
3074 			gl.enable(GL_PRIMITIVE_RESTART);
3075 			GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call failed.");
3076 		}
3077 
3078 		/* Iterate through all primitive types */
3079 		for (unsigned int n_primitive_type = 0;
3080 			 n_primitive_type < PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_COUNT; ++n_primitive_type)
3081 		{
3082 			m_current_primitive_type = (PipelineStatisticsQueryUtilities::_primitive_type)n_primitive_type;
3083 
3084 			/* Exclude patches from the test */
3085 			if (m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_PATCHES)
3086 			{
3087 				continue;
3088 			}
3089 
3090 			/* Iterate through all draw call types while the query is enabled (skip DrawArrays calls if primitive restart is enabled) */
3091 			for (unsigned int n_draw_call_type =
3092 					 (m_is_primitive_restart_enabled ? PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_GLDRAWELEMENTS :
3093 													   0);
3094 				 n_draw_call_type < PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_COUNT; ++n_draw_call_type)
3095 			{
3096 				m_current_draw_call_type = (PipelineStatisticsQueryUtilities::_draw_call_type)n_draw_call_type;
3097 
3098 				/* Only continue if the draw call is supported by the context */
3099 				if (!PipelineStatisticsQueryUtilities::isDrawCallSupported(m_current_draw_call_type, gl))
3100 				{
3101 					continue;
3102 				}
3103 
3104 				if (!PipelineStatisticsQueryUtilities::executeQuery(
3105 						current_query_target, m_qo_id, m_bo_qo_id, queryCallbackDrawCallHandler,
3106 						(PipelineStatisticsQueryTestFunctionalBase*)this, m_context.getRenderContext(), m_testCtx,
3107 						m_context.getContextInfo(), &run_result, skipped))
3108 				{
3109 					m_testCtx.getLog() << tcu::TestLog::Message
3110 									   << "Could not retrieve test run results for query target "
3111 										  "["
3112 									   << PipelineStatisticsQueryUtilities::getStringForEnum(current_query_target)
3113 									   << "]" << tcu::TestLog::EndMessage;
3114 
3115 					result = false;
3116 				}
3117 				else if (!skipped)
3118 				{
3119 					glw::GLuint64										 expected_values[4] = { 0 };
3120 					unsigned int										 n_expected_values  = 0;
3121 					PipelineStatisticsQueryUtilities::_verification_type verification_type =
3122 						PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EXACT_MATCH;
3123 
3124 					if (current_query_target == GL_CLIPPING_OUTPUT_PRIMITIVES_ARB)
3125 					{
3126 						verification_type = PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EQUAL_OR_GREATER;
3127 					}
3128 
3129 					if (current_query_target == GL_VERTICES_SUBMITTED_ARB)
3130 					{
3131 						getExpectedVerticesSubmittedQueryResult(m_current_primitive_type, &n_expected_values,
3132 																expected_values);
3133 					}
3134 					else
3135 					{
3136 						getExpectedPrimitivesSubmittedQueryResult(m_current_primitive_type, &n_expected_values,
3137 																  expected_values);
3138 					}
3139 
3140 					result &= PipelineStatisticsQueryUtilities::verifyResultValues(
3141 						run_result, n_expected_values, expected_values, m_bo_qo_id != 0, /* should_check_qo_bo_values */
3142 						current_query_target, &m_current_draw_call_type, &m_current_primitive_type,
3143 						m_is_primitive_restart_enabled, m_testCtx, verification_type);
3144 
3145 				} /* if (run results were obtained successfully) */
3146 			}	 /* for (all draw call types) */
3147 		}		  /* for (all primitive types) */
3148 	}			  /* for (both when primitive restart is disabled and enabled) */
3149 
3150 	return result;
3151 }
3152 
3153 /** Returns the expected result value(s) for a GL_PRIMITIVES_SUBMITTED_ARB query. There
3154  *  can be either one or two result values, depending on how the implementation handles
3155  *  incomplete primitives.
3156  *
3157  *  @param current_primitive_type Primitive type used for the draw call, for which
3158  *                                the query would be executed
3159  *  @param out_result1_written    Deref will be set to true, if the first result value
3160  *                                was written to @param out_result1. Otherwise, it will
3161  *                                be set to false.
3162  *  @param out_result1            Deref will be set to the first of the acceptable
3163  *                                result values, if @param out_result1_written was set
3164  *                                to true.
3165  *  @param out_result2_written    Deref will be set to true, if the second result value
3166  *                                was written to @param out_result2. Otherwise, it will
3167  *                                be set to false.
3168  *  @param out_result2            Deref will be set to the second of the acceptable
3169  *                                result values, if @param out_result2_written was set
3170  *                                to true.
3171  *
3172  **/
getExpectedPrimitivesSubmittedQueryResult( PipelineStatisticsQueryUtilities::_primitive_type current_primitive_type, unsigned int* out_results_written, glw::GLuint64 out_results[4])3173 void PipelineStatisticsQueryTestFunctional3::getExpectedPrimitivesSubmittedQueryResult(
3174 	PipelineStatisticsQueryUtilities::_primitive_type current_primitive_type, unsigned int* out_results_written,
3175 	glw::GLuint64 out_results[4])
3176 {
3177 	unsigned int n_input_vertices = m_indirect_draw_call_count_argument;
3178 
3179 	*out_results_written = 0;
3180 
3181 	/* Quick checks */
3182 	DE_ASSERT(current_primitive_type != PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_PATCHES);
3183 
3184 	/* Carry on */
3185 	if (m_is_primitive_restart_enabled)
3186 	{
3187 		/* Primitive restart functionality in our test removes a single index.
3188 		 *
3189 		 * Note: This also applies to arrayed draw calls, since we're testing
3190 		 *       GL_PRIMITIVE_RESTART rendering mode, and we're using a primitive
3191 		 *       restart index of 0.
3192 		 **/
3193 		n_input_vertices--;
3194 	}
3195 
3196 	switch (current_primitive_type)
3197 	{
3198 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_POINTS:
3199 	{
3200 		out_results[(*out_results_written)++] = n_input_vertices;
3201 
3202 		break;
3203 	}
3204 
3205 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINE_LOOP:
3206 	{
3207 		if (n_input_vertices > 2)
3208 		{
3209 			out_results[(*out_results_written)++] = n_input_vertices;
3210 		}
3211 		else if (n_input_vertices > 1)
3212 		{
3213 			out_results[(*out_results_written)++] = 1;
3214 		}
3215 		else
3216 		{
3217 			out_results[(*out_results_written)++] = 0;
3218 		}
3219 
3220 		break;
3221 	} /* PRIMITIVE_TYPE_LINE_LOOP */
3222 
3223 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLE_FAN:
3224 	{
3225 		if (n_input_vertices > 2)
3226 		{
3227 			out_results[(*out_results_written)++] = n_input_vertices - 2;
3228 		}
3229 		else
3230 		{
3231 			out_results[(*out_results_written)++] = 0;
3232 
3233 			if (n_input_vertices >= 1)
3234 			{
3235 				/* If the submitted triangle fan is incomplete, also include the case
3236 				 * where the incomplete triangle fan's vertices are counted as a primitive.
3237 				 */
3238 				out_results[(*out_results_written)++] = 1;
3239 			}
3240 		}
3241 
3242 		break;
3243 	}
3244 
3245 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINE_STRIP:
3246 	{
3247 		if (n_input_vertices > 1)
3248 		{
3249 			out_results[(*out_results_written)++] = n_input_vertices - 1;
3250 		}
3251 		else
3252 		{
3253 			out_results[(*out_results_written)++] = 0;
3254 
3255 			if (n_input_vertices > 0)
3256 			{
3257 				/* If the submitted line strip is incomplete, also include the case
3258 				 * where the incomplete line's vertices are counted as a primitive.
3259 				 */
3260 				out_results[(*out_results_written)++] = 1;
3261 			}
3262 		}
3263 
3264 		break;
3265 	}
3266 
3267 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLE_STRIP:
3268 	{
3269 		if (n_input_vertices > 2)
3270 		{
3271 			out_results[(*out_results_written)++] = n_input_vertices - 2;
3272 		}
3273 		else
3274 		{
3275 			out_results[(*out_results_written)++] = 0;
3276 
3277 			if (n_input_vertices >= 1)
3278 			{
3279 				/* If the submitted triangle strip is incomplete, also include the case
3280 				 * where the incomplete triangle's vertices are counted as a primitive.
3281 				 */
3282 				out_results[(*out_results_written)++] = 1;
3283 			}
3284 		}
3285 
3286 		break;
3287 	}
3288 
3289 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINES:
3290 	{
3291 		out_results[(*out_results_written)++] = n_input_vertices / 2;
3292 
3293 		/* If the submitted line is incomplete, also include the case where
3294 		 * the incomplete line's vertices are counted as a primitive.
3295 		 */
3296 		if (n_input_vertices > 0 && (n_input_vertices % 2) != 0)
3297 		{
3298 			out_results[(*out_results_written)++] = n_input_vertices / 2 + 1;
3299 		}
3300 
3301 		break;
3302 	}
3303 
3304 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINES_ADJACENCY:
3305 	{
3306 		out_results[(*out_results_written)++] = n_input_vertices / 4;
3307 
3308 		/* If the submitted line is incomplete, also include the case where
3309 		 * the incomplete line's vertices are counted as a primitive.
3310 		 */
3311 		if (n_input_vertices > 0 && (n_input_vertices % 4) != 0)
3312 		{
3313 			out_results[(*out_results_written)++] = n_input_vertices / 4 + 1;
3314 		}
3315 
3316 		break;
3317 	}
3318 
3319 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLES:
3320 	{
3321 		out_results[(*out_results_written)++] = n_input_vertices / 3;
3322 
3323 		/* If the submitted triangle is incomplete, also include the case
3324 		 * when the incomplete triangle's vertices are counted as a primitive.
3325 		 */
3326 		if (n_input_vertices > 0 && (n_input_vertices % 3) != 0)
3327 		{
3328 			out_results[(*out_results_written)++] = n_input_vertices / 3 + 1;
3329 		}
3330 
3331 		break;
3332 	}
3333 
3334 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLES_ADJACENCY:
3335 	{
3336 		out_results[(*out_results_written)++] = n_input_vertices / 6;
3337 
3338 		/* If the submitted triangle is incomplete, also include the case
3339 		 * when the incomplete triangle's vertices are counted as a primitive.
3340 		 */
3341 		if (n_input_vertices > 0 && (n_input_vertices % 6) != 0)
3342 		{
3343 			out_results[(*out_results_written)++] = n_input_vertices / 6 + 1;
3344 		}
3345 
3346 		break;
3347 	}
3348 
3349 	default:
3350 	{
3351 		TCU_FAIL("Unrecognized primitive type");
3352 	}
3353 	} /* switch (current_primitive_type) */
3354 
3355 	if (PipelineStatisticsQueryUtilities::isInstancedDrawCall(m_current_draw_call_type))
3356 	{
3357 		for (unsigned int i = 0; i < *out_results_written; ++i)
3358 		{
3359 			out_results[i] *= m_indirect_draw_call_primcount_argument;
3360 		}
3361 	} /* if (instanced draw call type) */
3362 }
3363 
3364 /** Returns the expected result value(s) for a GL_VERTICES_SUBMITTED_ARB query. There
3365  *  can be either one or two result values, depending on how the implementation handles
3366  *  incomplete primitives.
3367  *
3368  *  @param current_primitive_type Primitive type used for the draw call, for which
3369  *                                the query would be executed
3370  *  @param out_result1_written    Deref will be set to true, if the first result value
3371  *                                was written to @param out_result1. Otherwise, it will
3372  *                                be set to false.
3373  *  @param out_result1            Deref will be set to the first of the acceptable
3374  *                                result values, if @param out_result1_written was set
3375  *                                to true.
3376  *  @param out_result2_written    Deref will be set to true, if the second result value
3377  *                                was written to @param out_result2. Otherwise, it will
3378  *                                be set to false.
3379  *  @param out_result2            Deref will be set to the second of the acceptable
3380  *                                result values, if @param out_result2_written was set
3381  *                                to true.
3382  *
3383  **/
getExpectedVerticesSubmittedQueryResult( PipelineStatisticsQueryUtilities::_primitive_type current_primitive_type, unsigned int* out_results_written, glw::GLuint64 out_results[4])3384 void PipelineStatisticsQueryTestFunctional3::getExpectedVerticesSubmittedQueryResult(
3385 	PipelineStatisticsQueryUtilities::_primitive_type current_primitive_type, unsigned int* out_results_written,
3386 	glw::GLuint64 out_results[4])
3387 {
3388 	unsigned int n_input_vertices = m_indirect_draw_call_count_argument;
3389 
3390 	*out_results_written = 0;
3391 
3392 	/* Quick checks */
3393 	DE_ASSERT(current_primitive_type != PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_PATCHES);
3394 
3395 	/* Carry on */
3396 	if (m_is_primitive_restart_enabled)
3397 	{
3398 		/* Primitive restart functionality in our test removes a single index.
3399 		 *
3400 		 * Note: This also applies to arrayed draw calls, since we're testing
3401 		 *       GL_PRIMITIVE_RESTART rendering mode, and we're using a primitive
3402 		 *       restart index of 0.
3403 		 **/
3404 		n_input_vertices--;
3405 	}
3406 
3407 	switch (current_primitive_type)
3408 	{
3409 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_POINTS:
3410 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINE_STRIP:
3411 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLE_FAN:
3412 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLE_STRIP:
3413 	{
3414 		out_results[(*out_results_written)++] = n_input_vertices;
3415 
3416 		break;
3417 	}
3418 
3419 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINE_LOOP:
3420 	{
3421 		out_results[(*out_results_written)++] = n_input_vertices;
3422 
3423 		/* Allow line loops to count the first vertex twice as that vertex
3424 		 * is part of both the first and the last primitives.
3425 		 */
3426 		out_results[(*out_results_written)++] = n_input_vertices + 1;
3427 		break;
3428 	}
3429 
3430 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINES:
3431 	{
3432 		out_results[(*out_results_written)++] = n_input_vertices;
3433 
3434 		/* If the submitted line is incomplete, also include the case where
3435 		 * the incomplete line's vertices are not counted.
3436 		 */
3437 		if (n_input_vertices > 0 && (n_input_vertices % 2) != 0)
3438 		{
3439 			out_results[(*out_results_written)++] = n_input_vertices - 1;
3440 		}
3441 
3442 		break;
3443 	}
3444 
3445 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINES_ADJACENCY:
3446 	{
3447 		/* Allow implementations to both include or exclude the adjacency
3448 		 * vertices.
3449 		 */
3450 		out_results[(*out_results_written)++] = n_input_vertices;
3451 		out_results[(*out_results_written)++] = n_input_vertices / 2;
3452 
3453 		/* If the submitted line is incomplete, also include the case where
3454 		 * the incomplete line's vertices are not counted.
3455 		 */
3456 		if (n_input_vertices > 0 && (n_input_vertices % 4) != 0)
3457 		{
3458 			out_results[(*out_results_written)++] = n_input_vertices - (n_input_vertices % 4);
3459 			out_results[(*out_results_written)++] = (n_input_vertices - (n_input_vertices % 4)) / 2;
3460 		}
3461 
3462 		break;
3463 	}
3464 
3465 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLES:
3466 	{
3467 		out_results[(*out_results_written)++] = n_input_vertices;
3468 
3469 		/* If the submitted triangle is incomplete, also include the case
3470 		 * when the incomplete triangle's vertices are not counted.
3471 		 */
3472 		if (n_input_vertices > 0 && (n_input_vertices % 3) != 0)
3473 		{
3474 			out_results[(*out_results_written)++] = n_input_vertices - (n_input_vertices % 3);
3475 		}
3476 
3477 		break;
3478 	}
3479 
3480 	case PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLES_ADJACENCY:
3481 	{
3482 		/* Allow implementations to both include or exclude the adjacency
3483 		 * vertices.
3484 		 */
3485 		out_results[(*out_results_written)++] = n_input_vertices;
3486 		out_results[(*out_results_written)++] = n_input_vertices / 2;
3487 
3488 		/* If the submitted triangle is incomplete, also include the case
3489 		 * when the incomplete triangle's vertices are not counted.
3490 		 */
3491 		if (n_input_vertices > 0 && (n_input_vertices % 6) != 0)
3492 		{
3493 			out_results[(*out_results_written)++] = n_input_vertices - (n_input_vertices % 6);
3494 			out_results[(*out_results_written)++] = (n_input_vertices - (n_input_vertices % 6)) / 2;
3495 		}
3496 
3497 		break;
3498 	}
3499 
3500 	default:
3501 	{
3502 		TCU_FAIL("Unrecognized primitive type");
3503 	}
3504 	} /* switch (current_primitive_type) */
3505 
3506 	if (PipelineStatisticsQueryUtilities::isInstancedDrawCall(m_current_draw_call_type))
3507 	{
3508 		for (unsigned int i = 0; i < *out_results_written; ++i)
3509 		{
3510 			out_results[i] *= m_indirect_draw_call_primcount_argument;
3511 		}
3512 	} /* if (instanced draw call type) */
3513 }
3514 
3515 /** Initializes GL objects used by the test */
initObjects()3516 void PipelineStatisticsQueryTestFunctional3::initObjects()
3517 {
3518 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3519 
3520 	buildProgram(DE_NULL,												   /* cs_body */
3521 				 PipelineStatisticsQueryUtilities::minimal_fs_code, DE_NULL, /* gs_body */
3522 				 DE_NULL,												   /* tc_body */
3523 				 DE_NULL,												   /* te_body */
3524 				 PipelineStatisticsQueryUtilities::minimal_vs_code);
3525 
3526 	gl.useProgram(m_po_id);
3527 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
3528 }
3529 
3530 /** Tells whether the test instance should be executed for user-specified query target.
3531  *
3532  *  @param query_target Query target to be used for the call.
3533  *
3534  *  @return true  if @param query_target is either GL_VERTICES_SUBMITTED_ARB,
3535  *                GL_PRIMITIVES_SUBMITTED_ARB, GL_CLIPPING_INPUT_PRIMITIVES_ARB, or
3536  *                GL_CLIPPING_OUTPUT_PRIMITIVES_ARB.
3537  *          false otherwise.
3538  **/
shouldExecuteForQueryTarget(glw::GLenum query_target)3539 bool PipelineStatisticsQueryTestFunctional3::shouldExecuteForQueryTarget(glw::GLenum query_target)
3540 {
3541 	return (query_target == GL_VERTICES_SUBMITTED_ARB || query_target == GL_PRIMITIVES_SUBMITTED_ARB ||
3542 			query_target == GL_CLIPPING_INPUT_PRIMITIVES_ARB || query_target == GL_CLIPPING_OUTPUT_PRIMITIVES_ARB);
3543 }
3544 
3545 /** Constructor.
3546  *
3547  *  @param context Rendering context
3548  */
PipelineStatisticsQueryTestFunctional4(deqp::Context& context)3549 PipelineStatisticsQueryTestFunctional4::PipelineStatisticsQueryTestFunctional4(deqp::Context& context)
3550 	: PipelineStatisticsQueryTestFunctionalBase(context, "functional_vertex_shader_invocations",
3551 												"Verifies GL_VERTEX_SHADER_INVOCATIONS_ARB query works correctly")
3552 {
3553 	/* Left blank intentionally */
3554 }
3555 
3556 /** Deinitializes all GL objects that were created during test execution. */
deinitObjects()3557 void PipelineStatisticsQueryTestFunctional4::deinitObjects()
3558 {
3559 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3560 
3561 	if (m_po_id != 0)
3562 	{
3563 		gl.deleteProgram(m_po_id);
3564 
3565 		m_po_id = 0;
3566 	}
3567 }
3568 
3569 /** Executes a test iteration for user-specified query target.
3570  *
3571  *  @param current_query_target Pipeline statistics query target to execute the iteration
3572  *                              for.
3573  *
3574  *  @return true if the test passed for the iteration, false otherwise.
3575  **/
executeTest(glw::GLenum current_query_target)3576 bool PipelineStatisticsQueryTestFunctional4::executeTest(glw::GLenum current_query_target)
3577 {
3578 	const glw::Functions&									 gl		= m_context.getRenderContext().getFunctions();
3579 	bool													 result = true;
3580 	bool													 skipped = false;
3581 	PipelineStatisticsQueryUtilities::_test_execution_result run_result;
3582 
3583 	/* Quick check: This method should only be called for GL_VERTEX_SHADER_INVOCATIONS_ARB
3584 	 * query */
3585 	DE_ASSERT(current_query_target == GL_VERTEX_SHADER_INVOCATIONS_ARB);
3586 
3587 	/* Set up VBO. */
3588 	const unsigned int n_vertex_components = 2;
3589 	const float		   vertex_data[]  = { -0.1f, 0.2f, 0.3f, 0.1f, 0.2f, -0.7f, 0.5f, -0.5f, 0.0f, 0.0f, 0.1f, 0.2f };
3590 	const unsigned int index_data[]   = { 4, 3, 2, 1, 0 };
3591 	const unsigned int n_data_indices = sizeof(index_data) / sizeof(index_data[0]);
3592 
3593 	/* Issue the test for 1 to 5 indices */
3594 	for (unsigned int n_indices = 1; n_indices < n_data_indices; ++n_indices)
3595 	{
3596 		m_indirect_draw_call_baseinstance_argument = 1;
3597 		m_indirect_draw_call_basevertex_argument   = 1;
3598 		m_indirect_draw_call_count_argument		   = n_indices;
3599 		m_indirect_draw_call_first_argument		   = 0;
3600 		m_indirect_draw_call_primcount_argument	= 4;
3601 
3602 		initVBO(vertex_data, sizeof(vertex_data), index_data, sizeof(index_data), m_indirect_draw_call_count_argument,
3603 				m_indirect_draw_call_primcount_argument, m_indirect_draw_call_baseinstance_argument,
3604 				m_indirect_draw_call_first_argument, m_indirect_draw_call_basevertex_argument);
3605 
3606 		initVAO(n_vertex_components);
3607 
3608 		/* Iterate through all primitive types */
3609 		for (unsigned int n_primitive_type = 0;
3610 			 n_primitive_type < PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_COUNT; ++n_primitive_type)
3611 		{
3612 			m_current_primitive_type = (PipelineStatisticsQueryUtilities::_primitive_type)n_primitive_type;
3613 
3614 			/* Exclude patches from the test */
3615 			if (m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_PATCHES)
3616 			{
3617 				continue;
3618 			}
3619 
3620 			/* Exclude the primitive types, for which the number of indices is insufficient to form
3621 			 * a primitive.
3622 			 */
3623 			if ((m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINE_LOOP &&
3624 				 n_indices < 2) ||
3625 				(m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINE_STRIP &&
3626 				 n_indices < 2) ||
3627 				(m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINES && n_indices < 2) ||
3628 				(m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLE_FAN &&
3629 				 n_indices < 3) ||
3630 				(m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLE_STRIP &&
3631 				 n_indices < 3) ||
3632 				(m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLES &&
3633 				 n_indices < 3))
3634 			{
3635 				/* Skip the iteration */
3636 				continue;
3637 			}
3638 
3639 			/* Exclude adjacency primitive types from the test, since we're not using geometry shader stage. */
3640 			if (m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_LINES_ADJACENCY ||
3641 				m_current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_TRIANGLES_ADJACENCY)
3642 			{
3643 				continue;
3644 			}
3645 
3646 			/* Iterate through all draw call types */
3647 			for (unsigned int n_draw_call_type = 0;
3648 				 n_draw_call_type < PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_COUNT; ++n_draw_call_type)
3649 			{
3650 				m_current_draw_call_type = (PipelineStatisticsQueryUtilities::_draw_call_type)n_draw_call_type;
3651 
3652 				/* Only continue if the draw call is supported by the context */
3653 				if (!PipelineStatisticsQueryUtilities::isDrawCallSupported(m_current_draw_call_type, gl))
3654 				{
3655 					continue;
3656 				}
3657 
3658 				/* Execute the query */
3659 				if (!PipelineStatisticsQueryUtilities::executeQuery(
3660 						current_query_target, m_qo_id, m_bo_qo_id, queryCallbackDrawCallHandler,
3661 						(PipelineStatisticsQueryTestFunctionalBase*)this, m_context.getRenderContext(), m_testCtx,
3662 						m_context.getContextInfo(), &run_result, skipped))
3663 				{
3664 					m_testCtx.getLog() << tcu::TestLog::Message
3665 									   << "Could not retrieve test run results for query target "
3666 										  "["
3667 									   << PipelineStatisticsQueryUtilities::getStringForEnum(current_query_target)
3668 									   << "]" << tcu::TestLog::EndMessage;
3669 
3670 					result = false;
3671 				}
3672 				else if (!skipped)
3673 				{
3674 					static const glw::GLuint64 expected_value = 1;
3675 
3676 					/* Compare it against query result values */
3677 					result &= PipelineStatisticsQueryUtilities::verifyResultValues(
3678 						run_result, 1, &expected_value, m_bo_qo_id != 0, /* should_check_qo_bo_values */
3679 						current_query_target, &m_current_draw_call_type, &m_current_primitive_type,
3680 						false, /* is_primitive_restart_enabled */
3681 						m_testCtx, PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EQUAL_OR_GREATER);
3682 
3683 				} /* if (run results were obtained successfully) */
3684 			}	 /* for (all draw call types) */
3685 		}		  /* for (all primitive types) */
3686 	}			  /* for (1 to 5 indices) */
3687 
3688 	return result;
3689 }
3690 
3691 /** Initializes all GL objects used by the test */
initObjects()3692 void PipelineStatisticsQueryTestFunctional4::initObjects()
3693 {
3694 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3695 
3696 	buildProgram(DE_NULL, /* cs_body */
3697 				 DE_NULL, /* fs_body */
3698 				 DE_NULL, /* gs_body */
3699 				 DE_NULL, /* tc_body */
3700 				 DE_NULL, /* te_body */
3701 				 PipelineStatisticsQueryUtilities::minimal_vs_code);
3702 
3703 	gl.useProgram(m_po_id);
3704 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
3705 }
3706 
3707 /** Tells whether the test instance should be executed for user-specified query target.
3708  *
3709  *  @param query_target Query target to be used for the call.
3710  *
3711  *  @return true  if @param query_target is GL_VERTEX_SHADER_INVOCATIONS_ARB.
3712  *          false otherwise.
3713  **/
shouldExecuteForQueryTarget(glw::GLenum query_target)3714 bool PipelineStatisticsQueryTestFunctional4::shouldExecuteForQueryTarget(glw::GLenum query_target)
3715 {
3716 	return (query_target == GL_VERTEX_SHADER_INVOCATIONS_ARB);
3717 }
3718 
3719 /** Constructor.
3720  *
3721  *  @param context Rendering context
3722  */
PipelineStatisticsQueryTestFunctional5(deqp::Context& context)3723 PipelineStatisticsQueryTestFunctional5::PipelineStatisticsQueryTestFunctional5(deqp::Context& context)
3724 	: PipelineStatisticsQueryTestFunctionalBase(context, "functional_tess_queries",
3725 												"Verifies that GL_TESS_CONTROL_SHADER_PATCHES_ARB and "
3726 												"GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB queries "
3727 												"work correctly.")
3728 {
3729 	/* Left blank intentionally */
3730 }
3731 
3732 /** Deinitializes all GL objects that were created during test execution. */
deinitObjects()3733 void PipelineStatisticsQueryTestFunctional5::deinitObjects()
3734 {
3735 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3736 
3737 	if (m_po_id != 0)
3738 	{
3739 		gl.deleteProgram(m_po_id);
3740 
3741 		m_po_id = 0;
3742 	}
3743 }
3744 
3745 /** Executes a test iteration for user-specified query target.
3746  *
3747  *  @param current_query_target Pipeline statistics query target to execute the iteration
3748  *                              for.
3749  *
3750  *  @return true if the test passed for the iteration, false otherwise.
3751  **/
executeTest(glw::GLenum current_query_target)3752 bool PipelineStatisticsQueryTestFunctional5::executeTest(glw::GLenum current_query_target)
3753 {
3754 	const glw::Functions&									 gl		= m_context.getRenderContext().getFunctions();
3755 	bool													 result = true;
3756 	bool													 skipped = false;
3757 	PipelineStatisticsQueryUtilities::_test_execution_result run_result;
3758 
3759 	/* Quick check: This method should only be called for GL_TESS_CONTROL_SHADER_PATCHES_ARB and
3760 	 * GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB queries. */
3761 	DE_ASSERT(current_query_target == GL_TESS_CONTROL_SHADER_PATCHES_ARB ||
3762 			  current_query_target == GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB);
3763 
3764 	/* Set up VBO. */
3765 	const unsigned int n_vertex_components = 2;
3766 	const float		   vertex_data[]	   = {
3767 		-0.1f, 0.2f, 0.2f, -0.7f, 0.5f, -0.5f,
3768 	};
3769 	const unsigned int index_data[] = { 2, 1, 0 };
3770 
3771 	m_indirect_draw_call_baseinstance_argument = 1;
3772 	m_indirect_draw_call_basevertex_argument   = 1;
3773 	m_indirect_draw_call_count_argument		   = 3; /* default GL_PATCH_VERTICES value */
3774 	m_indirect_draw_call_first_argument		   = 0;
3775 	m_indirect_draw_call_primcount_argument	= 4;
3776 
3777 	initVBO(vertex_data, sizeof(vertex_data), index_data, sizeof(index_data), m_indirect_draw_call_count_argument,
3778 			m_indirect_draw_call_primcount_argument, m_indirect_draw_call_baseinstance_argument,
3779 			m_indirect_draw_call_first_argument, m_indirect_draw_call_basevertex_argument);
3780 
3781 	initVAO(n_vertex_components);
3782 
3783 	/* Set up the primitive type */
3784 	m_current_primitive_type = PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_PATCHES;
3785 
3786 	/* Iterate through all draw call types */
3787 	for (unsigned int n_draw_call_type = 0; n_draw_call_type < PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_COUNT;
3788 		 ++n_draw_call_type)
3789 	{
3790 		m_current_draw_call_type = (PipelineStatisticsQueryUtilities::_draw_call_type)n_draw_call_type;
3791 
3792 		/* Only continue if the draw call is supported by the context */
3793 		if (!PipelineStatisticsQueryUtilities::isDrawCallSupported(m_current_draw_call_type, gl))
3794 		{
3795 			continue;
3796 		}
3797 
3798 		/* Execute the query */
3799 		if (!PipelineStatisticsQueryUtilities::executeQuery(
3800 				current_query_target, m_qo_id, m_bo_qo_id, queryCallbackDrawCallHandler,
3801 				(PipelineStatisticsQueryTestFunctionalBase*)this, m_context.getRenderContext(), m_testCtx,
3802 				m_context.getContextInfo(), &run_result, skipped))
3803 		{
3804 			m_testCtx.getLog() << tcu::TestLog::Message << "Could not retrieve test run results for query target "
3805 														   "["
3806 							   << PipelineStatisticsQueryUtilities::getStringForEnum(current_query_target) << "]"
3807 							   << tcu::TestLog::EndMessage;
3808 
3809 			result = false;
3810 		}
3811 		else if (!skipped)
3812 		{
3813 			static const glw::GLuint64 expected_value = 1; /* as per test spec */
3814 
3815 			/* Compare it against query result values */
3816 			result &= PipelineStatisticsQueryUtilities::verifyResultValues(
3817 				run_result, 1, &expected_value, m_bo_qo_id != 0, /* should_check_qo_bo_values */
3818 				current_query_target, &m_current_draw_call_type, &m_current_primitive_type,
3819 				false, /* is_primitive_restart_enabled */
3820 				m_testCtx, PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EQUAL_OR_GREATER);
3821 
3822 		} /* if (run results were obtained successfully) */
3823 	}	 /* for (all draw call types) */
3824 
3825 	return result;
3826 }
3827 
3828 /** Initializes all GL objects used by the test */
initObjects()3829 void PipelineStatisticsQueryTestFunctional5::initObjects()
3830 {
3831 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3832 
3833 	/* This test should not execute if we're not running at least a GL4.0 context */
3834 	if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)))
3835 	{
3836 		throw tcu::NotSupportedError("OpenGL 4.0+ is required to run this test.");
3837 	}
3838 
3839 	buildProgram(DE_NULL,												   /* cs_body */
3840 				 PipelineStatisticsQueryUtilities::minimal_fs_code, DE_NULL, /* gs_body */
3841 				 PipelineStatisticsQueryUtilities::minimal_tc_code, PipelineStatisticsQueryUtilities::minimal_te_code,
3842 				 PipelineStatisticsQueryUtilities::minimal_vs_code);
3843 
3844 	gl.useProgram(m_po_id);
3845 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
3846 }
3847 
3848 /** Tells whether the test instance should be executed for user-specified query target.
3849  *
3850  *  @param query_target Query target to be used for the call.
3851  *
3852  *  @return true  if @param query_target is either GL_TESS_CONTROL_SHADER_PATCHES_ARB,
3853  *                or GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB.
3854  *          false otherwise.
3855  **/
shouldExecuteForQueryTarget(glw::GLenum query_target)3856 bool PipelineStatisticsQueryTestFunctional5::shouldExecuteForQueryTarget(glw::GLenum query_target)
3857 {
3858 	return (query_target == GL_TESS_CONTROL_SHADER_PATCHES_ARB ||
3859 			query_target == GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB);
3860 }
3861 
3862 /** Constructor.
3863  *
3864  *  @param context Rendering context
3865  */
PipelineStatisticsQueryTestFunctional6(deqp::Context& context)3866 PipelineStatisticsQueryTestFunctional6::PipelineStatisticsQueryTestFunctional6(deqp::Context& context)
3867 	: PipelineStatisticsQueryTestFunctionalBase(context, "functional_geometry_shader_queries",
3868 												"Verifies that GL_GEOMETRY_SHADER_INVOCATIONS and "
3869 												"GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB queries "
3870 												"work correctly.")
3871 	, m_n_primitives_emitted_by_gs(3)
3872 	, m_n_streams_emitted_by_gs(3)
3873 {
3874 	/* Left blank intentionally */
3875 }
3876 
3877 /** Deinitializes all GL objects that were created during test execution. */
deinitObjects()3878 void PipelineStatisticsQueryTestFunctional6::deinitObjects()
3879 {
3880 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3881 
3882 	if (m_po_id != 0)
3883 	{
3884 		gl.deleteProgram(m_po_id);
3885 
3886 		m_po_id = 0;
3887 	}
3888 }
3889 
3890 /** Executes a test iteration for user-specified query target.
3891  *
3892  *  @param current_query_target Pipeline statistics query target to execute the iteration
3893  *                              for.
3894  *
3895  *  @return true if the test passed for the iteration, false otherwise.
3896  **/
executeTest(glw::GLenum current_query_target)3897 bool PipelineStatisticsQueryTestFunctional6::executeTest(glw::GLenum current_query_target)
3898 {
3899 	const glw::Functions&									 gl		= m_context.getRenderContext().getFunctions();
3900 	bool													 result = true;
3901 	bool													 skipped = false;
3902 	PipelineStatisticsQueryUtilities::_test_execution_result run_result;
3903 
3904 	/* Quick check: This method should only be called for GL_GEOMETRY_SHADER_INVOCATIONS and
3905 	 * GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB queries. */
3906 	DE_ASSERT(current_query_target == GL_GEOMETRY_SHADER_INVOCATIONS ||
3907 			  current_query_target == GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB);
3908 
3909 	/* Set up VBO. */
3910 	const unsigned int n_vertex_components = 2;
3911 	const float		   vertex_data[]	   = {
3912 		-0.1f, 0.2f, 0.2f, -0.7f, 0.5f, -0.5f, 0.1f, -0.2f, -0.2f, 0.7f, -0.5f, 0.5f,
3913 	};
3914 	const unsigned int index_data[]			   = { 2, 1, 0 };
3915 	m_indirect_draw_call_baseinstance_argument = 1;
3916 	m_indirect_draw_call_basevertex_argument   = 1;
3917 	m_indirect_draw_call_count_argument =
3918 		3; /* note: we will update the argument per iteration, so just use anything for now */
3919 	m_indirect_draw_call_first_argument		= 0;
3920 	m_indirect_draw_call_primcount_argument = 4;
3921 
3922 	initVBO(vertex_data, sizeof(vertex_data), index_data, sizeof(index_data), m_indirect_draw_call_count_argument,
3923 			m_indirect_draw_call_primcount_argument, m_indirect_draw_call_baseinstance_argument,
3924 			m_indirect_draw_call_first_argument, m_indirect_draw_call_basevertex_argument);
3925 
3926 	initVAO(n_vertex_components);
3927 
3928 	/* Iterate over all input primitives supported by geometry shaders */
3929 	for (int gs_input_it = static_cast<int>(PipelineStatisticsQueryUtilities::GEOMETRY_SHADER_INPUT_FIRST);
3930 		 gs_input_it != static_cast<int>(PipelineStatisticsQueryUtilities::GEOMETRY_SHADER_INPUT_COUNT); ++gs_input_it)
3931 	{
3932 		PipelineStatisticsQueryUtilities::_geometry_shader_input gs_input =
3933 			static_cast<PipelineStatisticsQueryUtilities::_geometry_shader_input>(gs_input_it);
3934 		/* Set up the 'count' argument and update the VBO contents */
3935 		m_indirect_draw_call_count_argument = PipelineStatisticsQueryUtilities::getNumberOfVerticesForGSInput(gs_input);
3936 
3937 		/* Update the VBO contents */
3938 		gl.bufferSubData(
3939 			GL_ARRAY_BUFFER,
3940 			m_vbo_indirect_arrays_argument_offset, /* the very first argument is 'count' which we need to update */
3941 			sizeof(m_indirect_draw_call_count_argument), &m_indirect_draw_call_count_argument);
3942 		gl.bufferSubData(
3943 			GL_ARRAY_BUFFER,
3944 			m_vbo_indirect_elements_argument_offset, /* the very first argument is 'count' which we need to update */
3945 			sizeof(m_indirect_draw_call_count_argument), &m_indirect_draw_call_count_argument);
3946 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call(s) failed.");
3947 
3948 		for (int gs_output_it = static_cast<int>(PipelineStatisticsQueryUtilities::GEOMETRY_SHADER_OUTPUT_FIRST);
3949 			 gs_output_it != static_cast<int>(PipelineStatisticsQueryUtilities::GEOMETRY_SHADER_OUTPUT_COUNT);
3950 			 ++gs_output_it)
3951 		{
3952 			PipelineStatisticsQueryUtilities::_geometry_shader_output gs_output =
3953 				static_cast<PipelineStatisticsQueryUtilities::_geometry_shader_output>(gs_output_it);
3954 			/* For GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB query, we need to test both single-stream and
3955 			 * multi-stream geometry shaders.
3956 			 *
3957 			 * For GL_GEOMETRY_SHADER_INVOCATIONS, we only need a single iteration.
3958 			 **/
3959 			const bool streams_supported = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0));
3960 			const unsigned int n_internal_iterations =
3961 				(current_query_target == GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB && streams_supported) ? 2 : 1;
3962 
3963 			for (unsigned int n_internal_iteration = 0; n_internal_iteration < n_internal_iterations;
3964 				 ++n_internal_iteration)
3965 			{
3966 				/* Build the test program. */
3967 				std::string gs_body;
3968 
3969 				if (n_internal_iteration == 1)
3970 				{
3971 					/* This path will only be entered for GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB query.
3972 					 *
3973 					 * OpenGL does not support multiple vertex streams for output primitive types other than
3974 					 * points.
3975 					 */
3976 					if (gs_output != PipelineStatisticsQueryUtilities::GEOMETRY_SHADER_OUTPUT_POINTS)
3977 					{
3978 						continue;
3979 					}
3980 
3981 					/* Build a multi-streamed geometry shader */
3982 					gs_body = PipelineStatisticsQueryUtilities::buildGeometryShaderBody(
3983 						gs_input, gs_output, m_n_primitives_emitted_by_gs, m_n_streams_emitted_by_gs);
3984 				}
3985 				else
3986 				{
3987 					gs_body = PipelineStatisticsQueryUtilities::buildGeometryShaderBody(
3988 						gs_input, gs_output, m_n_primitives_emitted_by_gs, 1); /* n_streams */
3989 				}
3990 
3991 				buildProgram(DE_NULL,																	/* cs_body */
3992 							 PipelineStatisticsQueryUtilities::minimal_fs_code, gs_body.c_str(), DE_NULL, /* tc_body */
3993 							 DE_NULL,																	/* te_body */
3994 							 PipelineStatisticsQueryUtilities::minimal_vs_code);
3995 
3996 				gl.useProgram(m_po_id);
3997 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
3998 
3999 				/* Set up the primitive type */
4000 				m_current_primitive_type = PipelineStatisticsQueryUtilities::getPrimitiveTypeFromGSInput(gs_input);
4001 
4002 				/* Iterate through all draw call types */
4003 				for (unsigned int n_draw_call_type = 0;
4004 					 n_draw_call_type < PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_COUNT; ++n_draw_call_type)
4005 				{
4006 					m_current_draw_call_type = (PipelineStatisticsQueryUtilities::_draw_call_type)n_draw_call_type;
4007 
4008 					/* Only continue if the draw call is supported by the context */
4009 					if (!PipelineStatisticsQueryUtilities::isDrawCallSupported(m_current_draw_call_type, gl))
4010 					{
4011 						continue;
4012 					}
4013 
4014 					/* Execute the query */
4015 					if (!PipelineStatisticsQueryUtilities::executeQuery(
4016 							current_query_target, m_qo_id, m_bo_qo_id, queryCallbackDrawCallHandler,
4017 							(PipelineStatisticsQueryTestFunctionalBase*)this, m_context.getRenderContext(), m_testCtx,
4018 							m_context.getContextInfo(), &run_result, skipped))
4019 					{
4020 						m_testCtx.getLog()
4021 							<< tcu::TestLog::Message << "Could not retrieve test run results for query target "
4022 														"["
4023 							<< PipelineStatisticsQueryUtilities::getStringForEnum(current_query_target) << "]"
4024 							<< tcu::TestLog::EndMessage;
4025 
4026 						result = false;
4027 					}
4028 					else if (!skipped)
4029 					{
4030 						unsigned int										 n_expected_values  = 0;
4031 						glw::GLuint64										 expected_values[2] = { 0 };
4032 						PipelineStatisticsQueryUtilities::_verification_type verification_type =
4033 							PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_UNDEFINED;
4034 
4035 						if (current_query_target == GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB)
4036 						{
4037 							n_expected_values  = 2;
4038 							expected_values[0] = m_n_primitives_emitted_by_gs;
4039 							expected_values[1] = m_n_primitives_emitted_by_gs;
4040 							verification_type  = PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EXACT_MATCH;
4041 
4042 							if (n_internal_iteration == 1)
4043 							{
4044 								/* Multi-stream geometry shader case. Count in non-default vertex streams */
4045 								for (unsigned int n_stream = 1; n_stream < m_n_streams_emitted_by_gs; ++n_stream)
4046 								{
4047 									expected_values[1] += (m_n_primitives_emitted_by_gs + n_stream);
4048 								} /* for (non-default streams) */
4049 							}
4050 
4051 							if (PipelineStatisticsQueryUtilities::isInstancedDrawCall(m_current_draw_call_type))
4052 							{
4053 								expected_values[0] *= m_indirect_draw_call_primcount_argument;
4054 								expected_values[1] *= m_indirect_draw_call_primcount_argument;
4055 							}
4056 						}
4057 						else
4058 						{
4059 							n_expected_values  = 1;
4060 							expected_values[0] = 1; /* as per test spec */
4061 							verification_type  = PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EQUAL_OR_GREATER;
4062 						}
4063 
4064 						/* Compare it against query result values */
4065 						result &= PipelineStatisticsQueryUtilities::verifyResultValues(
4066 							run_result, n_expected_values, expected_values,
4067 							m_bo_qo_id != 0, /* should_check_qo_bo_values */
4068 							current_query_target, &m_current_draw_call_type, &m_current_primitive_type,
4069 							false, /* is_primitive_restart_enabled */
4070 							m_testCtx, verification_type);
4071 
4072 					} /* if (run results were obtained successfully) */
4073 				}	 /* for (all draw call types) */
4074 			}		  /* for (all internal iterations) */
4075 		}			  /* for (all geometry shader output primitive types) */
4076 	}				  /* for (all geometry shader input primitive types) */
4077 	return result;
4078 }
4079 
4080 /** Initializes all GL objects used by the test */
initObjects()4081 void PipelineStatisticsQueryTestFunctional6::initObjects()
4082 {
4083 	/* This test should not execute if we're not running at least a GL3.2 context */
4084 	if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 2)))
4085 	{
4086 		throw tcu::NotSupportedError("OpenGL 3.2+ is required to run this test.");
4087 	}
4088 }
4089 
4090 /** Tells whether the test instance should be executed for user-specified query target.
4091  *
4092  *  @param query_target Query target to be used for the call.
4093  *
4094  *  @return true  if @param query_target is either GL_GEOMETRY_SHADER_INVOCATIONS, or
4095  *                GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB.
4096  *          false otherwise.
4097  **/
shouldExecuteForQueryTarget(glw::GLenum query_target)4098 bool PipelineStatisticsQueryTestFunctional6::shouldExecuteForQueryTarget(glw::GLenum query_target)
4099 {
4100 	return (query_target == GL_GEOMETRY_SHADER_INVOCATIONS ||
4101 			query_target == GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB);
4102 }
4103 
4104 /** Constructor.
4105  *
4106  *  @param context Rendering context
4107  */
PipelineStatisticsQueryTestFunctional7(deqp::Context& context)4108 PipelineStatisticsQueryTestFunctional7::PipelineStatisticsQueryTestFunctional7(deqp::Context& context)
4109 	: PipelineStatisticsQueryTestFunctionalBase(context, "functional_fragment_shader_invocations",
4110 												"Verifies GL_FRAGMENT_SHADER_INVOCATIONS_ARB queries "
4111 												"work correctly.")
4112 {
4113 	/* Left blank intentionally */
4114 }
4115 
4116 /** Deinitializes all GL objects that were created during test execution. */
deinitObjects()4117 void PipelineStatisticsQueryTestFunctional7::deinitObjects()
4118 {
4119 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4120 
4121 	if (m_po_id != 0)
4122 	{
4123 		gl.deleteProgram(m_po_id);
4124 
4125 		m_po_id = 0;
4126 	}
4127 }
4128 
4129 /** Executes a test iteration for user-specified query target.
4130  *
4131  *  @param current_query_target Pipeline statistics query target to execute the iteration
4132  *                              for.
4133  *
4134  *  @return true if the test passed for the iteration, false otherwise.
4135  **/
executeTest(glw::GLenum current_query_target)4136 bool PipelineStatisticsQueryTestFunctional7::executeTest(glw::GLenum current_query_target)
4137 {
4138 	const glw::Functions&									 gl		= m_context.getRenderContext().getFunctions();
4139 	bool													 result = true;
4140 	bool													 skipped = false;
4141 	PipelineStatisticsQueryUtilities::_test_execution_result run_result;
4142 
4143 	/* Quick check: This method should only be called for GL_FRAGMENT_SHADER_INVOCATIONS_ARB query */
4144 	DE_ASSERT(current_query_target == GL_FRAGMENT_SHADER_INVOCATIONS_ARB);
4145 
4146 	/* Set up VBO. */
4147 	const unsigned int n_vertex_components = 2;
4148 	const float		   vertex_data[]	   = { 0.0f,  0.75f, -0.75f, -0.75f, 0.75f, -0.75f, 0.3f, 0.7f,
4149 								  -0.4f, 0.2f,  0.6f,   -0.3f,  -0.3f, -0.7f,  0.0f, 0.0f };
4150 	const unsigned int index_data[] = { 0, 2, 1, 3, 4, 5, 6, 7 };
4151 
4152 	m_indirect_draw_call_baseinstance_argument = 1;
4153 	m_indirect_draw_call_basevertex_argument   = 1;
4154 	m_indirect_draw_call_count_argument =
4155 		3; /* this value will be updated in the actual loop, so use anything for now */
4156 	m_indirect_draw_call_first_argument		= 0;
4157 	m_indirect_draw_call_primcount_argument = 4;
4158 
4159 	initFBO();
4160 	initVBO(vertex_data, sizeof(vertex_data), index_data, sizeof(index_data), m_indirect_draw_call_count_argument,
4161 			m_indirect_draw_call_primcount_argument, m_indirect_draw_call_baseinstance_argument,
4162 			m_indirect_draw_call_first_argument, m_indirect_draw_call_basevertex_argument);
4163 
4164 	initVAO(n_vertex_components);
4165 
4166 	/* Iterate over all primitive types */
4167 	for (int current_primitive_type_it = static_cast<int>(PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_FIRST);
4168 		 current_primitive_type_it < static_cast<int>(PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_COUNT);
4169 		 ++current_primitive_type_it)
4170 	{
4171 		PipelineStatisticsQueryUtilities::_primitive_type current_primitive_type =
4172 			static_cast<PipelineStatisticsQueryUtilities::_primitive_type>(current_primitive_type_it);
4173 		/* Exclude 'patches' primitive type */
4174 		if (current_primitive_type == PipelineStatisticsQueryUtilities::PRIMITIVE_TYPE_PATCHES)
4175 		{
4176 			continue;
4177 		}
4178 
4179 		m_current_primitive_type = current_primitive_type;
4180 
4181 		/* Update 'count' argument so that we only use as many vertices as needed for current
4182 		 * primitive type.
4183 		 */
4184 		unsigned int count_argument_value =
4185 			PipelineStatisticsQueryUtilities::getNumberOfVerticesForPrimitiveType(m_current_primitive_type);
4186 
4187 		m_indirect_draw_call_count_argument = count_argument_value;
4188 
4189 		gl.bufferSubData(GL_ARRAY_BUFFER, m_vbo_indirect_arrays_argument_offset, sizeof(unsigned int),
4190 						 &m_indirect_draw_call_count_argument);
4191 		gl.bufferSubData(GL_ARRAY_BUFFER, m_vbo_indirect_elements_argument_offset, sizeof(unsigned int),
4192 						 &m_indirect_draw_call_count_argument);
4193 
4194 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call(s) failed.");
4195 
4196 		/* Iterate through all draw call types */
4197 		for (unsigned int n_draw_call_type = 0;
4198 			 n_draw_call_type < PipelineStatisticsQueryUtilities::DRAW_CALL_TYPE_COUNT; ++n_draw_call_type)
4199 		{
4200 			m_current_draw_call_type = (PipelineStatisticsQueryUtilities::_draw_call_type)n_draw_call_type;
4201 
4202 			/* Only continue if the draw call is supported by the context */
4203 			if (!PipelineStatisticsQueryUtilities::isDrawCallSupported(m_current_draw_call_type, gl))
4204 			{
4205 				continue;
4206 			}
4207 
4208 			/* Clear the buffers before we proceed */
4209 			gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4210 			GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
4211 
4212 			/* Execute the query */
4213 			if (!PipelineStatisticsQueryUtilities::executeQuery(
4214 					current_query_target, m_qo_id, m_bo_qo_id, queryCallbackDrawCallHandler,
4215 					(PipelineStatisticsQueryTestFunctionalBase*)this, m_context.getRenderContext(), m_testCtx,
4216 					m_context.getContextInfo(), &run_result, skipped))
4217 			{
4218 				m_testCtx.getLog() << tcu::TestLog::Message << "Could not retrieve test run results for query target "
4219 															   "["
4220 								   << PipelineStatisticsQueryUtilities::getStringForEnum(current_query_target) << "]"
4221 								   << tcu::TestLog::EndMessage;
4222 
4223 				result = false;
4224 			}
4225 			else if (!skipped)
4226 			{
4227 				static const glw::GLuint64 expected_value = 1; /* as per test spec */
4228 
4229 				/* Compare it against query result values */
4230 				result &= PipelineStatisticsQueryUtilities::verifyResultValues(
4231 					run_result, 1, &expected_value, m_bo_qo_id != 0, /* should_check_qo_bo_values */
4232 					current_query_target, &m_current_draw_call_type, &m_current_primitive_type,
4233 					false, /* is_primitive_restart_enabled */
4234 					m_testCtx, PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EQUAL_OR_GREATER);
4235 
4236 			} /* if (run results were obtained successfully) */
4237 		}	 /* for (all draw call types) */
4238 	}		  /* for (all primitive types) */
4239 
4240 	return result;
4241 }
4242 
4243 /** Initializes all GL objects used by the test */
initObjects()4244 void PipelineStatisticsQueryTestFunctional7::initObjects()
4245 {
4246 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4247 
4248 	buildProgram(DE_NULL,												   /* cs_body */
4249 				 PipelineStatisticsQueryUtilities::minimal_fs_code, DE_NULL, /* gs_body */
4250 				 DE_NULL,												   /* tc_body */
4251 				 DE_NULL,												   /* te_body */
4252 				 PipelineStatisticsQueryUtilities::minimal_vs_code);
4253 
4254 	gl.useProgram(m_po_id);
4255 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
4256 }
4257 
4258 /** Tells whether the test instance should be executed for user-specified query target.
4259  *
4260  *  @param query_target Query target to be used for the call.
4261  *
4262  *  @return true  if @param query_target is GL_FRAGMENT_SHADER_INVOCATIONS_ARB.
4263  *          false otherwise.
4264  **/
shouldExecuteForQueryTarget(glw::GLenum query_target)4265 bool PipelineStatisticsQueryTestFunctional7::shouldExecuteForQueryTarget(glw::GLenum query_target)
4266 {
4267 	return (query_target == GL_FRAGMENT_SHADER_INVOCATIONS_ARB);
4268 }
4269 
4270 /** Constructor.
4271  *
4272  *  @param context Rendering context
4273  */
PipelineStatisticsQueryTestFunctional8(deqp::Context& context)4274 PipelineStatisticsQueryTestFunctional8::PipelineStatisticsQueryTestFunctional8(deqp::Context& context)
4275 	: PipelineStatisticsQueryTestFunctionalBase(context, "functional_compute_shader_invocations",
4276 												"Verifies that GL_COMPUTE_SHADER_INVOCATIONS_ARB queries "
4277 												"work correctly.")
4278 	, m_bo_dispatch_compute_indirect_args_offset(0)
4279 	, m_bo_id(0)
4280 	, m_current_iteration(0)
4281 {
4282 	/* Left blank intentionally */
4283 }
4284 
4285 /** Deinitializes all GL objects that were created during test execution. */
deinitObjects()4286 void PipelineStatisticsQueryTestFunctional8::deinitObjects()
4287 {
4288 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4289 
4290 	if (m_bo_id != 0)
4291 	{
4292 		gl.deleteBuffers(1, &m_bo_id);
4293 
4294 		m_bo_id = 0;
4295 	}
4296 }
4297 
4298 /** Executes a test iteration for user-specified query target.
4299  *
4300  *  @param current_query_target Pipeline statistics query target to execute the iteration
4301  *                              for.
4302  *
4303  *  @return true if the test passed for the iteration, false otherwise.
4304  **/
executeTest(glw::GLenum current_query_target)4305 bool PipelineStatisticsQueryTestFunctional8::executeTest(glw::GLenum current_query_target)
4306 {
4307 	bool													 result = true;
4308 	bool													 skipped = false;
4309 	PipelineStatisticsQueryUtilities::_test_execution_result run_result;
4310 
4311 	/* Quick check: This method should only be called for
4312 	 * GL_COMPUTE_SHADER_INVOCATIONS_ARB queries. */
4313 	DE_ASSERT(current_query_target == GL_COMPUTE_SHADER_INVOCATIONS_ARB);
4314 
4315 	/* This test needs to be run in two iterations:
4316 	 *
4317 	 * 1. glDispatchCompute() should be called.
4318 	 * 2. glDispatchComputeIndirect() should be called.
4319 	 *
4320 	 */
4321 	for (m_current_iteration = 0; m_current_iteration < 2; /* as per description */
4322 		 ++m_current_iteration)
4323 	{
4324 		/* Execute the query */
4325 		if (!PipelineStatisticsQueryUtilities::executeQuery(
4326 				current_query_target, m_qo_id, m_bo_qo_id, queryCallbackDispatchCallHandler, this,
4327 				m_context.getRenderContext(), m_testCtx, m_context.getContextInfo(), &run_result, skipped))
4328 		{
4329 			m_testCtx.getLog() << tcu::TestLog::Message << "Could not retrieve test run results for query target "
4330 														   "["
4331 							   << PipelineStatisticsQueryUtilities::getStringForEnum(current_query_target) << "]"
4332 							   << tcu::TestLog::EndMessage;
4333 
4334 			result = false;
4335 		}
4336 		else if (!skipped)
4337 		{
4338 			static const glw::GLuint64 expected_value = 1; /* as per test spec */
4339 
4340 			/* Compare it against query result values */
4341 			result &= PipelineStatisticsQueryUtilities::verifyResultValues(
4342 				run_result, 1, &expected_value, m_bo_qo_id != 0,  /* should_check_qo_bo_values */
4343 				current_query_target, DE_NULL, DE_NULL, false, /* is_primitive_restart_enabled */
4344 				m_testCtx, PipelineStatisticsQueryUtilities::VERIFICATION_TYPE_EQUAL_OR_GREATER);
4345 		} /* if (run results were obtained successfully) */
4346 	}	 /* for (both iterations) */
4347 
4348 	return result;
4349 }
4350 
4351 /** Initializes all GL objects used by the test */
initObjects()4352 void PipelineStatisticsQueryTestFunctional8::initObjects()
4353 {
4354 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4355 	const char*			  cs_code = NULL;
4356 
4357 	/* This test should not execute if we don't have compute shaders */
4358 	if (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)))
4359 	{
4360 		cs_code = PipelineStatisticsQueryUtilities::minimal_cs_code;
4361 	}
4362 	else if (m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader") &&
4363 	m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
4364 	{
4365 		cs_code = PipelineStatisticsQueryUtilities::minimal_cs_code_arb;
4366 	}
4367 	else
4368 	{
4369 		throw tcu::NotSupportedError("OpenGL 4.3+ / compute shaders and atomic counters required to run this test.");
4370 	}
4371 
4372 	buildProgram(cs_code,
4373 				 DE_NULL,												   /* fs_body */
4374 				 DE_NULL,												   /* gs_body */
4375 				 DE_NULL,												   /* tc_body */
4376 				 DE_NULL,												   /* te_body */
4377 				 DE_NULL);												   /* vs_body */
4378 
4379 	gl.useProgram(m_po_id);
4380 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
4381 
4382 	/* Init BO to hold atomic counter data, as well as the indirect dispatch compute
4383 	 * draw call arguments */
4384 	unsigned int	   atomic_counter_value = 0;
4385 	const unsigned int bo_size				= sizeof(unsigned int) * (1 /* counter value */ + 3 /* draw call args */);
4386 
4387 	const unsigned int drawcall_args[] = {
4388 		1, /* num_groups_x */
4389 		1, /* num_groups_y */
4390 		1  /* num_groups_z */
4391 	};
4392 
4393 	gl.genBuffers(1, &m_bo_id);
4394 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
4395 
4396 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id);
4397 	gl.bindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_bo_id);
4398 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed.");
4399 
4400 	gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
4401 					  m_bo_id);
4402 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
4403 
4404 	gl.bufferData(GL_ARRAY_BUFFER, bo_size, DE_NULL, GL_STATIC_DRAW);
4405 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
4406 
4407 	gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
4408 					 sizeof(unsigned int), &atomic_counter_value);
4409 	gl.bufferSubData(GL_ARRAY_BUFFER, sizeof(unsigned int), /* offset */
4410 					 sizeof(drawcall_args), drawcall_args);
4411 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
4412 
4413 	/* Store rthe offset, at which the draw call args start */
4414 	m_bo_dispatch_compute_indirect_args_offset = sizeof(unsigned int);
4415 }
4416 
4417 /** Either issues a regular or indirect compute shader dispatch call, and then verifies
4418  *  the call has executed without any error being generated. The regular dispatch call
4419  *  will be executed if pInstance->m_current_iteration is equal to 0, otherwise the
4420  *  method will use the indirect version.
4421  *
4422  *  @param pInstance Pointer to a PipelineStatisticsQueryTestFunctional8 instance.
4423  */
queryCallbackDispatchCallHandler(void* pInstance)4424 bool PipelineStatisticsQueryTestFunctional8::queryCallbackDispatchCallHandler(void* pInstance)
4425 {
4426 	glw::GLenum								error_code = GL_NO_ERROR;
4427 	PipelineStatisticsQueryTestFunctional8* pThis	  = (PipelineStatisticsQueryTestFunctional8*)pInstance;
4428 	bool									result	 = true;
4429 	const glw::Functions&					gl		   = pThis->m_context.getRenderContext().getFunctions();
4430 
4431 	if (pThis->m_current_iteration == 0)
4432 	{
4433 		gl.dispatchCompute(1,  /* num_groups_x */
4434 						   1,  /* num_groups_y */
4435 						   1); /* num_groups_z */
4436 	}
4437 	else
4438 	{
4439 		gl.dispatchComputeIndirect(pThis->m_bo_dispatch_compute_indirect_args_offset);
4440 	}
4441 
4442 	error_code = gl.getError();
4443 	if (error_code != GL_NO_ERROR)
4444 	{
4445 		pThis->m_testCtx.getLog() << tcu::TestLog::Message
4446 								  << ((pThis->m_current_iteration == 0) ? "glDispatchCompute()" :
4447 																		  "glDispatchComputeIndirect()")
4448 								  << " call failed with error code "
4449 									 "["
4450 								  << error_code << "]." << tcu::TestLog::EndMessage;
4451 
4452 		result = false;
4453 	}
4454 
4455 	return result;
4456 }
4457 
4458 /** Tells whether the test instance should be executed for user-specified query target.
4459  *
4460  *  @param query_target Query target to be used for the call.
4461  *
4462  *  @return true  if @param query_target is GL_COMPUT_SHADER_INVOCATIONS_ARB.
4463  *          false otherwise.
4464  **/
shouldExecuteForQueryTarget(glw::GLenum query_target)4465 bool PipelineStatisticsQueryTestFunctional8::shouldExecuteForQueryTarget(glw::GLenum query_target)
4466 {
4467 	return (query_target == GL_COMPUTE_SHADER_INVOCATIONS_ARB);
4468 }
4469 
4470 /** Constructor.
4471  *
4472  *  @param context Rendering context.
4473  */
PipelineStatisticsQueryTests(deqp::Context& context)4474 PipelineStatisticsQueryTests::PipelineStatisticsQueryTests(deqp::Context& context)
4475 	: TestCaseGroup(context, "pipeline_statistics_query_tests_ARB",
4476 					"Contains conformance tests that verify GL implementation's support "
4477 					"for GL_ARB_pipeline_statistics_query extension.")
4478 {
4479 	/* Left blank intentionally */
4480 }
4481 
4482 /** Initializes the test group contents. */
init()4483 void PipelineStatisticsQueryTests::init()
4484 {
4485 	addChild(new PipelineStatisticsQueryTestAPICoverage1(m_context));
4486 	addChild(new PipelineStatisticsQueryTestAPICoverage2(m_context));
4487 	addChild(new PipelineStatisticsQueryTestFunctional1(m_context));
4488 	addChild(new PipelineStatisticsQueryTestFunctional2(m_context));
4489 	addChild(new PipelineStatisticsQueryTestFunctional3(m_context));
4490 	addChild(new PipelineStatisticsQueryTestFunctional4(m_context));
4491 	addChild(new PipelineStatisticsQueryTestFunctional5(m_context));
4492 	addChild(new PipelineStatisticsQueryTestFunctional6(m_context));
4493 	addChild(new PipelineStatisticsQueryTestFunctional7(m_context));
4494 	addChild(new PipelineStatisticsQueryTestFunctional8(m_context));
4495 }
4496 } /* glcts namespace */
4497