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