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