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