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