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