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