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 * \file gl3cTransformFeedbackOverflowQueryTests.cpp
26 * \brief Implements conformance tests for "Transform Feedback Overflow
27 * Query" functionality.
28 */ /*-------------------------------------------------------------------*/
29
30 #include "gl3cTransformFeedbackOverflowQueryTests.hpp"
31
32 #include "deMath.h"
33 #include "deSharedPtr.hpp"
34
35 #include "gluContextInfo.hpp"
36 #include "gluDefs.hpp"
37 #include "gluPixelTransfer.hpp"
38 #include "gluShaderProgram.hpp"
39
40 #include "tcuFuzzyImageCompare.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuRenderTarget.hpp"
43 #include "tcuSurface.hpp"
44 #include "tcuTestLog.hpp"
45
46 #include "glw.h"
47 #include "glwFunctions.hpp"
48
49 namespace gl3cts
50 {
51
52 /*
53 Base class of all test cases of the feature. Enforces the requirements below:
54
55 * Check that the extension string is available.
56 */
57 class TransformFeedbackOverflowQueryBaseTest : public deqp::TestCase
58 {
59 protected:
TransformFeedbackOverflowQueryBaseTest(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name,const char * description)60 TransformFeedbackOverflowQueryBaseTest(deqp::Context& context, TransformFeedbackOverflowQueryTests::API api,
61 const char* name, const char* description)
62 : TestCase(context, name, description), m_api(api), m_max_vertex_streams(0)
63 {
64 }
65
66 /* Checks whether the feature is supported. */
featureSupported()67 bool featureSupported()
68 {
69 if (m_api == TransformFeedbackOverflowQueryTests::API_GL_ARB_transform_feedback_overflow_query)
70 {
71 glu::ContextType contextType = m_context.getRenderContext().getType();
72 if (m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback_overflow_query") ||
73 glu::contextSupports(contextType, glu::ApiType::core(4, 6)))
74 {
75 return true;
76 }
77 }
78 return false;
79 }
80
81 /* Checks whether transform_feedback2 is supported. */
supportsTransformFeedback2()82 bool supportsTransformFeedback2()
83 {
84 return (m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback2") ||
85 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType(4, 0, glu::PROFILE_CORE)));
86 }
87
88 /* Checks whether transform_feedback3 is supported. */
supportsTransformFeedback3()89 bool supportsTransformFeedback3()
90 {
91 return (m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback3") ||
92 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType(4, 0, glu::PROFILE_CORE)));
93 }
94
95 /* Checks whether gpu_shader5 is supported. */
supportsGpuShader5()96 bool supportsGpuShader5()
97 {
98 return (m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader5") ||
99 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType(4, 0, glu::PROFILE_CORE)));
100 }
101
102 /* Checks whether conditional_render_inverted is supported. */
supportsConditionalRenderInverted()103 bool supportsConditionalRenderInverted()
104 {
105 return (m_context.getContextInfo().isExtensionSupported("GL_ARB_conditional_render_inverted") ||
106 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType(4, 5, glu::PROFILE_CORE)));
107 }
108
109 /* Checks whether query_buffer_object are supported. */
supportsQueryBufferObject()110 bool supportsQueryBufferObject()
111 {
112 return (m_context.getContextInfo().isExtensionSupported("GL_ARB_query_buffer_object") ||
113 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType(4, 4, glu::PROFILE_CORE)));
114 }
115
116 /* Returns the maximum number of vertex streams. */
getMaxVertexStreams() const117 GLuint getMaxVertexStreams() const
118 {
119 return m_max_vertex_streams;
120 }
121
122 /* Basic test init, child classes must call it. */
init()123 virtual void init()
124 {
125 if (!featureSupported())
126 {
127 throw tcu::NotSupportedError("Required transform_feedback_overflow_query extension is not supported");
128 }
129
130 if (supportsTransformFeedback3())
131 {
132 m_max_vertex_streams = (GLuint)m_context.getContextInfo().getInt(GL_MAX_VERTEX_STREAMS);
133 }
134 }
135
136 protected:
137 const TransformFeedbackOverflowQueryTests::API m_api;
138
139 private:
140 GLuint m_max_vertex_streams;
141 };
142
143 /*
144 API Implementation Dependent State Test
145
146 * Check that calling GetQueryiv with target TRANSFORM_FEEDBACK_OVERFLOW
147 and pname QUERY_COUNTER_BITS returns a non-negative value without error.
148
149 * If GL 4.0 or ARB_transform_feedback3 is supported, check that calling
150 GetQueryiv with target TRANSFORM_FEEDBACK_STREAM_OVERFLOW and pname
151 QUERY_COUNTER_BITS returns a non-negative value without error.
152 */
153 class TransformFeedbackOverflowQueryImplDepState : public TransformFeedbackOverflowQueryBaseTest
154 {
155 public:
TransformFeedbackOverflowQueryImplDepState(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)156 TransformFeedbackOverflowQueryImplDepState(deqp::Context& context, TransformFeedbackOverflowQueryTests::API api,
157 const char* name)
158 : TransformFeedbackOverflowQueryBaseTest(
159 context, api, name,
160 "Tests whether the implementation dependent state defined by the feature matches the requirements.")
161 {
162 }
163
164 /* Test case iterate function. Contains the actual test case logic. */
iterate()165 IterateResult iterate()
166 {
167 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
168 GLint counterBits;
169
170 gl.getQueryiv(GL_TRANSFORM_FEEDBACK_OVERFLOW, GL_QUERY_COUNTER_BITS, &counterBits);
171 if (counterBits < 0)
172 {
173 TCU_FAIL("Value of QUERY_COUNTER_BITS for query target TRANSFORM_FEEDBACK_OVERFLOW is invalid");
174 }
175
176 if (supportsTransformFeedback3())
177 {
178 gl.getQueryiv(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, GL_QUERY_COUNTER_BITS, &counterBits);
179 if (counterBits < 0)
180 {
181 TCU_FAIL("Value of QUERY_COUNTER_BITS for query target TRANSFORM_FEEDBACK_STREAM_OVERFLOW is invalid");
182 }
183 }
184
185 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
186
187 return STOP;
188 }
189 };
190
191 /*
192 Base class for all test cases of the feature that verify newly introduced context state.
193 */
194 class TransformFeedbackOverflowQueryContextStateBase : public TransformFeedbackOverflowQueryBaseTest
195 {
196 protected:
TransformFeedbackOverflowQueryContextStateBase(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name,const char * description)197 TransformFeedbackOverflowQueryContextStateBase(deqp::Context& context, TransformFeedbackOverflowQueryTests::API api,
198 const char* name, const char* description)
199 : TransformFeedbackOverflowQueryBaseTest(context, api, name, description)
200 {
201 }
202
203 /* Returns whether CURRENT_QUERY state for the specified target and index matches the given value. */
verifyCurrentQueryState(GLenum target,GLuint index,GLuint value)204 bool verifyCurrentQueryState(GLenum target, GLuint index, GLuint value)
205 {
206 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
207 GLint expected = (GLint)value;
208 GLint actual;
209
210 // Use GetQueryIndexediv by default
211 gl.getQueryIndexediv(target, index, GL_CURRENT_QUERY, &actual);
212 if (actual != expected)
213 {
214 return false;
215 }
216
217 if (index == 0)
218 {
219 // If index is zero then GetQueryiv should also return the expected value
220 gl.getQueryiv(target, GL_CURRENT_QUERY, &actual);
221 if (actual != expected)
222 {
223 return false;
224 }
225 }
226
227 return true;
228 }
229 };
230
231 /*
232 API Default Context State Test
233
234 * Check that calling GetQueryiv with target TRANSFORM_FEEDBACK_OVERFLOW
235 and pname CURRENT_QUERY returns zero by default.
236
237 * If GL 4.0 or ARB_transform_feedback3 is supported, check that calling
238 GetQueryIndexediv with target TRANSFORM_FEEDBACK_STREAM_OVERFLOW and
239 pname CURRENT_QUERY returns zero for any index between zero and MAX_-
240 VERTEX_STREAMS.
241 */
242 class TransformFeedbackOverflowQueryDefaultState : public TransformFeedbackOverflowQueryContextStateBase
243 {
244 public:
TransformFeedbackOverflowQueryDefaultState(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)245 TransformFeedbackOverflowQueryDefaultState(deqp::Context& context, TransformFeedbackOverflowQueryTests::API api,
246 const char* name)
247 : TransformFeedbackOverflowQueryContextStateBase(
248 context, api, name,
249 "Tests whether the new context state defined by the feature has the expected default values.")
250 {
251 }
252
253 /* Test case iterate function. Contains the actual test case logic. */
iterate()254 IterateResult iterate()
255 {
256 if (!verifyCurrentQueryState(GL_TRANSFORM_FEEDBACK_OVERFLOW, 0, 0))
257 {
258 TCU_FAIL("Default value of CURRENT_QUERY for query target TRANSFORM_FEEDBACK_OVERFLOW is non-zero");
259 }
260
261 if (supportsTransformFeedback3())
262 {
263 for (GLuint i = 0; i < getMaxVertexStreams(); ++i)
264 {
265 if (!verifyCurrentQueryState(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, 0, 0))
266 {
267 TCU_FAIL("Default value of CURRENT_QUERY for query target TRANSFORM_FEEDBACK_STREAM_OVERFLOW "
268 "is non-zero");
269 }
270 }
271 }
272
273 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
274
275 return STOP;
276 }
277 };
278
279 /*
280 API Context State Update Test
281
282 * Check that after a successful call to BeginQuery with target TRANSFORM_-
283 FEEDBACK_OVERFLOW_ARB calling GetQueryiv with the same target and with
284 pname CURRENT_QUERY returns the name of the query previously passed to
285 BeginQuery. Also check that after calling EndQuery with the same target
286 GetQueryiv returns zero for the same parameters.
287
288 * If GL 4.0 or ARB_transform_feedback3 is supported, check that after a
289 successful call to BeginQueryIndexed with target TRANSFORM_FEEDBACK_-
290 STREAM_OVERFLOW_ARB calling GetQueryIndexediv with the same target and
291 with pname CURRENT_QUERY returns the name of the query previously passed
292 to BeginQueryIndexed if the index parameters match and otherwise it
293 returns zero. Also check that after calling EndQueryIndexed with the
294 same target and index GetQueryIndexediv returns zero for the same
295 parameters for all indices. Indices used should be between zero and
296 MAX_VERTEX_STREAMS.
297 */
298 class TransformFeedbackOverflowQueryStateUpdate : public TransformFeedbackOverflowQueryContextStateBase
299 {
300 public:
TransformFeedbackOverflowQueryStateUpdate(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)301 TransformFeedbackOverflowQueryStateUpdate(deqp::Context& context, TransformFeedbackOverflowQueryTests::API api,
302 const char* name)
303 : TransformFeedbackOverflowQueryContextStateBase(
304 context, api, name,
305 "Tests whether the new context state defined by the feature is correctly updated after a successful "
306 "call to {Begin|End}Query[Indexed] if the target of the query is one of the newly introduced ones.")
307 , m_overflow_query(0)
308 , m_stream_overflow_query(0)
309 {
310 }
311
312 /* Test case init. */
init()313 virtual void init()
314 {
315 TransformFeedbackOverflowQueryContextStateBase::init();
316
317 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
318
319 gl.genQueries(1, &m_overflow_query);
320 gl.genQueries(1, &m_stream_overflow_query);
321 }
322
323 /* Test case deinit */
deinit()324 virtual void deinit()
325 {
326 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
327
328 gl.deleteQueries(1, &m_overflow_query);
329 gl.deleteQueries(1, &m_stream_overflow_query);
330
331 TransformFeedbackOverflowQueryContextStateBase::deinit();
332 }
333
334 /* Test case iterate function. Contains the actual test case logic. */
iterate()335 IterateResult iterate()
336 {
337 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
338
339 // Call BeginQuery
340 gl.beginQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW, m_overflow_query);
341
342 // Verify that CURRENT_QUERY is set to the name of the query
343 if (!verifyCurrentQueryState(GL_TRANSFORM_FEEDBACK_OVERFLOW, 0, m_overflow_query))
344 {
345 TCU_FAIL("Value of CURRENT_QUERY for query target TRANSFORM_FEEDBACK_OVERFLOW is not updated properly "
346 "after a call to BeginQuery");
347 }
348
349 // Call EndQuery
350 gl.endQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW);
351
352 // Verify that CURRENT_QUERY is reset to zero
353 if (!verifyCurrentQueryState(GL_TRANSFORM_FEEDBACK_OVERFLOW, 0, 0))
354 {
355 TCU_FAIL("Value of CURRENT_QUERY for query target TRANSFORM_FEEDBACK_OVERFLOW is not reset properly "
356 "after a call to EndQuery");
357 }
358
359 if (supportsTransformFeedback3())
360 {
361 for (GLuint i = 0; i < getMaxVertexStreams(); ++i)
362 {
363 // Call BeginQueryIndexed with specified index
364 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, i, m_stream_overflow_query);
365
366 // Verify that CURRENT_QUERY is set to the name of the query for the specified index, but remains zero for other indices
367 for (GLuint j = 0; j < getMaxVertexStreams(); ++j)
368 {
369 if (i == j)
370 {
371 if (!verifyCurrentQueryState(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, j, m_stream_overflow_query))
372 {
373 TCU_FAIL("Value of CURRENT_QUERY for query target TRANSFORM_FEEDBACK_STREAM_OVERFLOW "
374 "is not updated properly after a call to BeginQueryIndexed");
375 }
376 }
377 else
378 {
379 if (!verifyCurrentQueryState(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, j, 0))
380 {
381 TCU_FAIL("Value of CURRENT_QUERY for query target TRANSFORM_FEEDBACK_STREAM_OVERFLOW "
382 "is incorrectly updated for an unrelated vertex stream"
383 "index after a call to BeginQueryIndexed");
384 }
385 }
386 }
387
388 // Call EndQueryIndexed with specified index
389 gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, i);
390
391 // Verify that CURRENT_QUERY is reset to zero for the specified index and still remains zero for other indices
392 for (GLuint j = 0; j < getMaxVertexStreams(); ++j)
393 {
394 if (i == j)
395 {
396 if (!verifyCurrentQueryState(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, j, 0))
397 {
398 TCU_FAIL("Value of CURRENT_QUERY for query target TRANSFORM_FEEDBACK_STREAM_OVERFLOW "
399 "is not reset properly after a call to EndQueryIndexed");
400 }
401 }
402 else
403 {
404 if (!verifyCurrentQueryState(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, j, 0))
405 {
406 TCU_FAIL("Value of CURRENT_QUERY for query target TRANSFORM_FEEDBACK_STREAM_OVERFLOW "
407 "is incorrectly updated for an unrelated vertex stream"
408 "index after a call to EndQueryIndexed");
409 }
410 }
411 }
412 }
413 }
414
415 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
416
417 return STOP;
418 }
419
420 protected:
421 GLuint m_overflow_query;
422 GLuint m_stream_overflow_query;
423 };
424
425 /*
426 Base class for all test cases of the feature that verify various error scenarios.
427 */
428 class TransformFeedbackOverflowQueryErrorBase : public TransformFeedbackOverflowQueryBaseTest
429 {
430 protected:
TransformFeedbackOverflowQueryErrorBase(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name,const char * description)431 TransformFeedbackOverflowQueryErrorBase(deqp::Context& context, TransformFeedbackOverflowQueryTests::API api,
432 const char* name, const char* description)
433 : TransformFeedbackOverflowQueryBaseTest(context, api, name, description), m_case_name(0)
434 {
435 }
436
437 /* Starts a new error scenario sub-test with the given name. The name is used in error messages if the sub-test fails. */
startTest(const char * caseName)438 void startTest(const char* caseName)
439 {
440 m_case_name = caseName;
441 }
442
443 /* Verifies whether the actually generated error matches that of the expected one. If not then it triggers the failure
444 of the test case with the sub-case name used as the failure message. */
verifyError(GLenum expectedError)445 void verifyError(GLenum expectedError)
446 {
447 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
448
449 GLenum actualError = gl.getError();
450
451 if (actualError != expectedError)
452 {
453 TCU_FAIL(m_case_name);
454 }
455 }
456
457 private:
458 const char* m_case_name;
459 };
460
461 /*
462 API Invalid Index Error Test
463
464 * Check that calling GetQueryIndexediv with target TRANSFORM_FEEDBACK_-
465 OVERFLOW_ARB and a non-zero index generates an INVALID_VALUE error.
466
467 * If GL 4.0 or ARB_transform_feedback3 is supported, check that calling
468 GetQueryIndexediv with target TRANSFORM_FEEDBACK_STREAM_OVERFLOW
469 and an index greater than or equal to MAX_VERTEX_STREAMS generates an
470 INVALID_VALUE error.
471
472 * Check that calling BeginQueryIndexed with target TRANSFORM_FEEDBACK_-
473 OVERFLOW_ARB and a non-zero index generates an INVALID_VALUE error.
474
475 * If GL 4.0 or ARB_transform_feedback3 is supported, check that calling
476 BeginQueryIndexed with target TRANSFORM_FEEDBACK_STREAM_OVERFLOW
477 and an index greater than or equal to MAX_VERTEX_STREAMS generates an
478 INVALID_VALUE error.
479 */
480 class TransformFeedbackOverflowQueryErrorInvalidIndex : public TransformFeedbackOverflowQueryErrorBase
481 {
482 public:
TransformFeedbackOverflowQueryErrorInvalidIndex(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)483 TransformFeedbackOverflowQueryErrorInvalidIndex(deqp::Context& context,
484 TransformFeedbackOverflowQueryTests::API api, const char* name)
485 : TransformFeedbackOverflowQueryErrorBase(
486 context, api, name, "Verifies whether an INVALID_VALUE error is properly generated if GetQueryIndexediv "
487 "or BeginQueryIndexed is called "
488 "with an invalid index when using the new targets introduced by the feature.")
489 , m_query(0)
490 {
491 }
492
493 /* Test case init. */
init()494 virtual void init()
495 {
496 TransformFeedbackOverflowQueryErrorBase::init();
497
498 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
499
500 gl.genQueries(1, &m_query);
501 }
502
503 /* Test case deinit */
deinit()504 virtual void deinit()
505 {
506 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
507
508 gl.deleteQueries(1, &m_query);
509
510 TransformFeedbackOverflowQueryErrorBase::deinit();
511 }
512
513 /* Test case iterate function. Contains the actual test case logic. */
iterate()514 IterateResult iterate()
515 {
516 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
517 GLint value;
518
519 startTest("GetQueryIndexediv must generate INVALID_VALUE if <target> is "
520 "TRANSFORM_FEEDBACK_OVERFLOW and <index> is non-zero.");
521
522 for (GLuint i = 1; i < getMaxVertexStreams(); ++i)
523 {
524 gl.getQueryIndexediv(GL_TRANSFORM_FEEDBACK_OVERFLOW, i, GL_CURRENT_QUERY, &value);
525 verifyError(GL_INVALID_VALUE);
526 }
527
528 if (supportsTransformFeedback3())
529 {
530 startTest("GetQueryIndexediv must generate INVALID_VALUE if <target> is "
531 "TRANSFORM_FEEDBACK_STREAM_OVERFLOW and <index> is greater "
532 "than or equal to MAX_VERTEX_STREAMS.");
533
534 for (GLuint i = getMaxVertexStreams(); i < getMaxVertexStreams() + 4; ++i)
535 {
536 gl.getQueryIndexediv(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, i, GL_CURRENT_QUERY, &value);
537 verifyError(GL_INVALID_VALUE);
538 }
539 }
540
541 startTest("BeginQueryIndexed must generate INVALID_VALUE if <target> is "
542 "TRANSFORM_FEEDBACK_OVERFLOW and <index> is non-zero.");
543
544 for (GLuint i = 1; i < getMaxVertexStreams(); ++i)
545 {
546 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_OVERFLOW, i, m_query);
547 verifyError(GL_INVALID_VALUE);
548 }
549
550 if (supportsTransformFeedback3())
551 {
552 startTest("BeginQueryIndexed must generate INVALID_VALUE if <target> is "
553 "TRANSFORM_FEEDBACK_STREAM_OVERFLOW and <index> is greater "
554 "than or equal to MAX_VERTEX_STREAMS.");
555
556 for (GLuint i = getMaxVertexStreams(); i < getMaxVertexStreams() + 4; ++i)
557 {
558 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, i, m_query);
559 verifyError(GL_INVALID_VALUE);
560 }
561 }
562
563 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
564
565 return STOP;
566 }
567
568 protected:
569 GLuint m_query;
570 };
571
572 /*
573 API Already Active Error Test
574
575 * Check that calling BeginQuery with target TRANSFORM_FEEDBACK_OVERFLOW
576 generates an INVALID_OPERATION error if there is already an active
577 query for TRANSFORM_FEEDBACK_OVERFLOW.
578
579 * If GL 4.0 or ARB_transform_feedback3 is supported, check that calling
580 BeginQueryIndexed with target TRANSFORM_FEEDBACK_STREAM_OVERFLOW
581 generates an INVALID_OPERATION error if there is already an active
582 query for TRANSFORM_FEEDBACK_STREAM_OVERFLOW for the specified
583 index.
584
585 * If GL 4.0 or ARB_transform_feedback3 is supported, check that calling
586 BeginQueryIndexed with target TRANSFORM_FEEDBACK_STREAM_OVERFLOW
587 generates an INVALID_OPERATION error if the specified query is already
588 active on another TRANSFORM_FEEDBACK_STREAM_OVERFLOW target with
589 a different index.
590 */
591 class TransformFeedbackOverflowQueryErrorAlreadyActive : public TransformFeedbackOverflowQueryErrorBase
592 {
593 public:
TransformFeedbackOverflowQueryErrorAlreadyActive(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)594 TransformFeedbackOverflowQueryErrorAlreadyActive(deqp::Context& context,
595 TransformFeedbackOverflowQueryTests::API api, const char* name)
596 : TransformFeedbackOverflowQueryErrorBase(context, api, name,
597 "Verifies whether an INVALID_OPERATION error is properly generated "
598 "if BeginQuery[Indexed] is used to try to start "
599 "a query on an index that has already a query active, or the query "
600 "object itself is active on another index.")
601 , m_query(0)
602 , m_active_overflow_query(0)
603 , m_active_stream_overflow_query(0)
604 , m_active_query_stream_index(0)
605 {
606 }
607
608 /* Test case init. */
init()609 virtual void init()
610 {
611 TransformFeedbackOverflowQueryErrorBase::init();
612
613 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
614
615 gl.genQueries(1, &m_query);
616
617 gl.genQueries(1, &m_active_overflow_query);
618 gl.beginQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW, m_active_overflow_query);
619
620 if (supportsTransformFeedback3())
621 {
622 gl.genQueries(1, &m_active_stream_overflow_query);
623 m_active_query_stream_index = 2;
624 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_active_query_stream_index,
625 m_active_stream_overflow_query);
626 }
627 }
628
629 /* Test case deinit */
deinit()630 virtual void deinit()
631 {
632 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
633
634 if (supportsTransformFeedback3())
635 {
636 gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_active_query_stream_index);
637 gl.deleteQueries(1, &m_active_stream_overflow_query);
638 }
639
640 gl.endQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW);
641 gl.deleteQueries(1, &m_active_overflow_query);
642
643 gl.deleteQueries(1, &m_query);
644
645 TransformFeedbackOverflowQueryErrorBase::deinit();
646 }
647
648 /* Test case iterate function. Contains the actual test case logic. */
iterate()649 IterateResult iterate()
650 {
651 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
652
653 startTest("BeginQuery[Indexed] must generate INVALID_OPERATION if <target> is "
654 "TRANSFORM_FEEDBACK_OVERFLOW and there is already an active "
655 "query for TRANSFORM_FEEDBACK_ARB.");
656
657 gl.beginQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW, m_query);
658 verifyError(GL_INVALID_OPERATION);
659 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_OVERFLOW, 0, m_query);
660 verifyError(GL_INVALID_OPERATION);
661
662 if (supportsTransformFeedback3())
663 {
664 startTest("BeginQueryIndexed must generate INVALID_OPERATION if <target> is "
665 "TRANSFORM_FEEDBACK_STREAM_OVERFLOW and there is already an active "
666 "query for TRANSFORM_FEEDBACK_STREAM_OVERFLOW for the specified index.");
667
668 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_active_query_stream_index, m_query);
669 verifyError(GL_INVALID_OPERATION);
670
671 startTest("BeginQuery[Indexed] must generate INVALID_OPERATION if <target> is "
672 "TRANSFORM_FEEDBACK_STREAM_OVERFLOW and the specified query is "
673 "already active on another TRANSFORM_FEEDBACK_STREAM_OVERFLOW "
674 "target with a different index.");
675
676 for (GLuint i = 0; i < getMaxVertexStreams(); ++i)
677 {
678 if (i != m_active_query_stream_index)
679 {
680 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, i, m_active_stream_overflow_query);
681 verifyError(GL_INVALID_OPERATION);
682
683 if (i == 0)
684 {
685 gl.beginQuery(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_active_stream_overflow_query);
686 verifyError(GL_INVALID_OPERATION);
687 }
688 }
689 }
690 }
691
692 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
693
694 return STOP;
695 }
696
697 protected:
698 GLuint m_query;
699 GLuint m_active_overflow_query;
700 GLuint m_active_stream_overflow_query;
701 GLuint m_active_query_stream_index;
702 };
703
704 /*
705 API Incompatible Target Error Test
706
707 * If GL 4.0 or ARB_transform_feedback3 is supported, check that calling
708 BeginQueryIndexed with target TRANSFORM_FEEDBACK_STREAM_OVERFLOW
709 generates an INVALID_OPERATION error if the specified query was
710 previously used as a TRANSFORM_FEEDBACK_OVERFLOW query. Also check
711 the other way around.
712 */
713 class TransformFeedbackOverflowQueryErrorIncompatibleTarget : public TransformFeedbackOverflowQueryErrorBase
714 {
715 public:
TransformFeedbackOverflowQueryErrorIncompatibleTarget(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)716 TransformFeedbackOverflowQueryErrorIncompatibleTarget(deqp::Context& context,
717 TransformFeedbackOverflowQueryTests::API api,
718 const char* name)
719 : TransformFeedbackOverflowQueryErrorBase(context, api, name,
720 "Verifies whether an INVALID_OPERATION error is properly generated "
721 "if BeginQuery[Indexed] is called with one of "
722 "the newly introduced query targets but one that is different than "
723 "that used earlier on the same query object.")
724 , m_overflow_query(0)
725 , m_stream_overflow_query(0)
726 , m_incompatible_query(0)
727 {
728 }
729
730 /* Test case init. */
init()731 virtual void init()
732 {
733 TransformFeedbackOverflowQueryErrorBase::init();
734
735 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
736
737 gl.genQueries(1, &m_incompatible_query);
738 gl.beginQuery(GL_SAMPLES_PASSED, m_incompatible_query);
739 gl.endQuery(GL_SAMPLES_PASSED);
740
741 gl.genQueries(1, &m_overflow_query);
742 gl.beginQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW, m_overflow_query);
743 gl.endQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW);
744
745 if (supportsTransformFeedback3())
746 {
747 gl.genQueries(1, &m_stream_overflow_query);
748 gl.beginQuery(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_stream_overflow_query);
749 gl.endQuery(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW);
750 }
751 }
752
753 /* Test case deinit */
deinit()754 virtual void deinit()
755 {
756 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
757
758 gl.deleteQueries(1, &m_incompatible_query);
759
760 gl.deleteQueries(1, &m_overflow_query);
761
762 if (supportsTransformFeedback3())
763 {
764 gl.deleteQueries(1, &m_stream_overflow_query);
765 }
766
767 TransformFeedbackOverflowQueryErrorBase::deinit();
768 }
769
770 /* Test case iterate function. Contains the actual test case logic. */
iterate()771 IterateResult iterate()
772 {
773 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
774
775 startTest("BeginQuery[Indexed] must generate INVALID_OPERATION if <target> is "
776 "TRANSFORM_FEEDBACK_OVERFLOW and the specified query was "
777 "previously used with another target.");
778
779 gl.beginQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW, m_incompatible_query);
780 verifyError(GL_INVALID_OPERATION);
781 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_OVERFLOW, 0, m_incompatible_query);
782 verifyError(GL_INVALID_OPERATION);
783
784 if (supportsTransformFeedback3())
785 {
786 gl.beginQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW, m_stream_overflow_query);
787 verifyError(GL_INVALID_OPERATION);
788 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_OVERFLOW, 0, m_stream_overflow_query);
789 verifyError(GL_INVALID_OPERATION);
790
791 startTest("BeginQuery[Indexed] must generate INVALID_OPERATION if <target> is "
792 "TRANSFORM_FEEDBACK_STREAM_OVERFLOW and the specified query "
793 "was previously used with another target.");
794
795 gl.beginQuery(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_incompatible_query);
796 verifyError(GL_INVALID_OPERATION);
797 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, 2, m_incompatible_query);
798 verifyError(GL_INVALID_OPERATION);
799
800 gl.beginQuery(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_overflow_query);
801 verifyError(GL_INVALID_OPERATION);
802 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, 2, m_overflow_query);
803 verifyError(GL_INVALID_OPERATION);
804 }
805
806 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
807
808 return STOP;
809 }
810
811 protected:
812 GLuint m_overflow_query;
813 GLuint m_stream_overflow_query;
814 GLuint m_incompatible_query;
815 };
816
817 /*
818 API No Query Active Error Test
819
820 * Check that calling EndQuery with target TRANSFORM_FEEDBACK_OVERFLOW
821 generates an INVALID_OPERATION error if no query is active for
822 TRANSFORM_FEEDBACK_OVERFLOW.
823
824 * If GL 4.0 or ARB_transform_feedback3 is supported, check that calling
825 EndQueryIndexed with target TRANSFORM_FEEDBACK_STREAM_OVERFLOW
826 generates an INVALID_OPERATION error if no query is active for
827 TRANSFORM_FEEDBACK_STREAM_OVERFLOW for the specified index, even
828 if there is an active query for another index.
829 */
830 class TransformFeedbackOverflowQueryErrorNoActiveQuery : public TransformFeedbackOverflowQueryErrorBase
831 {
832 public:
TransformFeedbackOverflowQueryErrorNoActiveQuery(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)833 TransformFeedbackOverflowQueryErrorNoActiveQuery(deqp::Context& context,
834 TransformFeedbackOverflowQueryTests::API api, const char* name)
835 : TransformFeedbackOverflowQueryErrorBase(context, api, name,
836 "Verifies whether an INVALID_OPERATION error is properly generated "
837 "if EndQuery[Indexed] is called with a target "
838 "(and index) for which there isn't a currently active query.")
839 , m_active_stream_overflow_query(0)
840 , m_active_query_stream_index(0)
841 {
842 }
843
844 /* Test case init. */
init()845 virtual void init()
846 {
847 TransformFeedbackOverflowQueryErrorBase::init();
848
849 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
850
851 if (supportsTransformFeedback3())
852 {
853 gl.genQueries(1, &m_active_stream_overflow_query);
854 m_active_query_stream_index = 2;
855 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_active_query_stream_index,
856 m_active_stream_overflow_query);
857 }
858 }
859
860 /* Test case deinit */
deinit()861 virtual void deinit()
862 {
863 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
864
865 if (supportsTransformFeedback3())
866 {
867 gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, m_active_query_stream_index);
868 gl.deleteQueries(1, &m_active_stream_overflow_query);
869 }
870
871 TransformFeedbackOverflowQueryErrorBase::deinit();
872 }
873
874 /* Test case iterate function. Contains the actual test case logic. */
iterate()875 IterateResult iterate()
876 {
877 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
878
879 startTest("EndQuery[Indexed] must generate INVALID_OPERATION if <target> is "
880 "TRANSFORM_FEEDBACK_OVERFLOW and there is no query active "
881 "for TRANSFORM_FEEDBACK_OVERFLOW.");
882
883 gl.endQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW);
884 verifyError(GL_INVALID_OPERATION);
885 gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_OVERFLOW, 0);
886 verifyError(GL_INVALID_OPERATION);
887
888 if (supportsTransformFeedback3())
889 {
890 startTest("EndQuery[Indexed] must generate INVALID_OPERATION if <target> is "
891 "TRANSFORM_FEEDBACK_STREAM_OVERFLOW and there is no query active "
892 "for TRANSFORM_FEEDBACK_STREAM_OVERFLOW for the given index.");
893
894 for (GLuint i = 0; i < getMaxVertexStreams(); ++i)
895 {
896 if (i != m_active_query_stream_index)
897 {
898 gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, i);
899 verifyError(GL_INVALID_OPERATION);
900
901 if (i == 0)
902 {
903 gl.endQuery(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW);
904 verifyError(GL_INVALID_OPERATION);
905 }
906 }
907 }
908 }
909
910 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
911
912 return STOP;
913 }
914
915 protected:
916 GLuint m_active_stream_overflow_query;
917 GLuint m_active_query_stream_index;
918 };
919
920 /*
921 Base class of all functionality tests. Helps enforce the following requirements:
922
923 * Ensuring that QUERY_COUNTER_BITS is at least one for the TRANSFORM_FEEDBACK_OVERFLOW query
924 target before running any test that uses such a query's result.
925
926 * Ensuring that GL 4.0 or ARB_transform_feedback3 is supported and QUERY_COUNTER_BITS is at least
927 one for the TRANSFORM_FEEDBACK_STREAM_OVERFLOW query target before running any test that
928 uses such a query's result.
929 */
930 class TransformFeedbackOverflowQueryFunctionalBase : public TransformFeedbackOverflowQueryBaseTest
931 {
932 protected:
TransformFeedbackOverflowQueryFunctionalBase(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name,const char * description)933 TransformFeedbackOverflowQueryFunctionalBase(deqp::Context& context, TransformFeedbackOverflowQueryTests::API api,
934 const char* name, const char* description)
935 : TransformFeedbackOverflowQueryBaseTest(context, api, name, description)
936 , m_overflow_query(0)
937 , m_stream_overflow_query(NULL)
938 , m_query_buffer(0)
939 , m_tf_buffer_count(0)
940 , m_tf_buffer(NULL)
941 , m_vao(0)
942 , m_program(0)
943 , m_checker_program(NULL)
944 {
945 }
946
947 /* Tells whether functional tests using TRANSFORM_FEEDBACK_OVERFLOW are runnable */
canTestOverflow()948 bool canTestOverflow()
949 {
950 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
951 GLint counterBits;
952
953 gl.getQueryiv(GL_TRANSFORM_FEEDBACK_OVERFLOW, GL_QUERY_COUNTER_BITS, &counterBits);
954
955 return counterBits > 0;
956 }
957
958 /* Tells whether functional tests using TRANSFORM_FEEDBACK_STREAM_OVERFLOW are runnable */
canTestStreamOverflow()959 bool canTestStreamOverflow()
960 {
961 if (supportsTransformFeedback3())
962 {
963 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
964 GLint counterBits;
965
966 gl.getQueryiv(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, GL_QUERY_COUNTER_BITS, &counterBits);
967
968 return counterBits > 0;
969 }
970 else
971 {
972 return false;
973 }
974 }
975
976 /* Dummy vertex shader. */
dummyVsh()977 const char* dummyVsh()
978 {
979 return "#version 150 core\n"
980 "void main() {\n"
981 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
982 "}\n";
983 }
984
985 /* Dummy fragment shader */
dummyFsh()986 const char* dummyFsh()
987 {
988 return "#version 150 core\n"
989 "void main() {}\n";
990 }
991
992 /* Functional test init. Creates necessary query objects. */
init()993 virtual void init()
994 {
995 TransformFeedbackOverflowQueryBaseTest::init();
996
997 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
998
999 if (canTestOverflow())
1000 {
1001 // Setup vertex array
1002 gl.genVertexArrays(1, &m_vao);
1003 gl.bindVertexArray(m_vao);
1004
1005 // Setup queries
1006 gl.genQueries(1, &m_overflow_query);
1007
1008 if (canTestStreamOverflow())
1009 {
1010 m_stream_overflow_query = new GLuint[getMaxVertexStreams()];
1011
1012 gl.genQueries(getMaxVertexStreams(), m_stream_overflow_query);
1013 }
1014
1015 // Setup checker program
1016 m_checker_program =
1017 new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(dummyVsh(), dummyFsh()));
1018 if (!m_checker_program->isOk())
1019 {
1020 TCU_FAIL("Checker program compilation failed");
1021 }
1022
1023 // Setup transform feedback shader and buffers
1024 buildTransformFeedbackProgram();
1025 setupTransformFeedbackBuffers();
1026 }
1027 else
1028 {
1029 throw tcu::NotSupportedError(
1030 "QUERY_COUNTER_BITS for TRANSFORM_FEEDBACK_OVERFLOW queries is zero, skipping test");
1031 }
1032 }
1033
1034 /* Functional test deinit. Deletes created query objects */
deinit()1035 virtual void deinit()
1036 {
1037 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1038
1039 gl.deleteVertexArrays(1, &m_vao);
1040
1041 gl.deleteQueries(1, &m_overflow_query);
1042
1043 if (canTestStreamOverflow())
1044 {
1045 if (m_stream_overflow_query != NULL)
1046 {
1047 gl.deleteQueries(getMaxVertexStreams(), m_stream_overflow_query);
1048
1049 delete[] m_stream_overflow_query;
1050 }
1051 }
1052
1053 if (m_checker_program != NULL)
1054 {
1055 delete m_checker_program;
1056 }
1057
1058 gl.useProgram(0);
1059 gl.deleteProgram(m_program);
1060
1061 if (m_tf_buffer != NULL)
1062 {
1063 gl.deleteBuffers(m_tf_buffer_count, m_tf_buffer);
1064
1065 delete[] m_tf_buffer;
1066 }
1067
1068 TransformFeedbackOverflowQueryBaseTest::deinit();
1069 }
1070
1071 /*
1072 Basic Checking Mechanism
1073
1074 * Call BeginConditionalRender with mode QUERY_WAIT and with the given
1075 query object as parameters. Draw something, then call EndConditional-
1076 Render. If the expected result for the query is FALSE, expect
1077 conditional render to discard the previous draw command.
1078
1079 * If GL 4.5 or ARB_conditional_render_inverted is supported, call Begin-
1080 ConditionalRender with mode QUERY_WAIT_INVERTED and with the given query
1081 object as parameters. Draw something, then call EndConditionalRender. If
1082 the expected result for the query is TRUE, expect conditional render to
1083 discard the previous draw command.
1084
1085 * Finally, check using GetQueryObjectiv with QUERY_RESULT that the result
1086 of the query matches the expected result.
1087
1088 * If GL 4.4 or ARB_query_buffer_object is supported then check the result
1089 of the query against the expected result also by having a query buffer
1090 bound at the time of calling GetQueryObjectiv.
1091 */
verifyQueryResult(GLuint query,GLboolean expected)1092 bool verifyQueryResult(GLuint query, GLboolean expected)
1093 {
1094 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1095 bool result = true;
1096 GLuint actual;
1097
1098 GLuint current_program = m_context.getContextInfo().getInt(GL_CURRENT_PROGRAM);
1099 GLuint checker_query, check_result;
1100
1101 // We'll use a PRIMITIVES_GENERATED query to test whether conditional
1102 // rendering actually executed the draw command or not. If the draw command
1103 // was discarded then the PRIMITIVES_GENERATED query should have a result
1104 // of zero.
1105 gl.genQueries(1, &checker_query);
1106
1107 gl.useProgram(m_checker_program->getProgram());
1108
1109 // Verify that conditional render discards the rendering if the expected
1110 // result is FALSE and renders otherwise.
1111 gl.beginConditionalRender(query, GL_QUERY_WAIT);
1112 gl.beginQuery(GL_PRIMITIVES_GENERATED, checker_query);
1113 gl.drawArrays(GL_POINTS, 0, 1);
1114 gl.endQuery(GL_PRIMITIVES_GENERATED);
1115 gl.endConditionalRender();
1116 gl.getQueryObjectuiv(checker_query, GL_QUERY_RESULT, &check_result);
1117 if (check_result != (GLuint)expected)
1118 {
1119 result = false;
1120 }
1121
1122 // Verify that an inverted conditional render discards the rendering if
1123 // the expected result is TRUE and renders otherwise.
1124 if (supportsConditionalRenderInverted())
1125 {
1126 gl.beginConditionalRender(query, GL_QUERY_WAIT_INVERTED);
1127 gl.beginQuery(GL_PRIMITIVES_GENERATED, checker_query);
1128 gl.drawArrays(GL_POINTS, 0, 1);
1129 gl.endQuery(GL_PRIMITIVES_GENERATED);
1130 gl.endConditionalRender();
1131 gl.getQueryObjectuiv(checker_query, GL_QUERY_RESULT, &check_result);
1132 if (check_result == (GLuint)expected)
1133 {
1134 result = false;
1135 }
1136 }
1137
1138 gl.useProgram(current_program);
1139
1140 // Verify that the result of the query matches the expected result.
1141 gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &actual);
1142 if ((GLboolean)actual != expected)
1143 {
1144 result = false;
1145 }
1146
1147 // Verify that the result of the query matches the expected result even
1148 // when using a query buffer.
1149 if (supportsQueryBufferObject())
1150 {
1151 const GLuint initValue = 0xDEADBEEF;
1152
1153 gl.genBuffers(1, &m_query_buffer);
1154 gl.bindBuffer(GL_QUERY_BUFFER, m_query_buffer);
1155 gl.bufferData(GL_QUERY_BUFFER, sizeof(initValue), &initValue, GL_STREAM_READ);
1156 gl.getQueryObjectuiv(query, GL_QUERY_RESULT, NULL);
1157 gl.getBufferSubData(GL_QUERY_BUFFER, 0, sizeof(actual), &actual);
1158 gl.deleteBuffers(1, &m_query_buffer);
1159
1160 if ((GLboolean)actual != expected)
1161 {
1162 result = false;
1163 }
1164 }
1165
1166 gl.deleteQueries(1, &checker_query);
1167
1168 return result;
1169 }
1170
1171 /* Verifies the result of all queries. There can only be up to 5 non-FALSE result queries as none of
1172 the tests use more than 4 vertex streams so the rest is assumed to always have a FALSE result. */
verifyQueryResults(GLboolean any,GLboolean stream0,GLboolean stream1,GLboolean stream2=GL_FALSE,GLboolean stream3=GL_FALSE)1173 void verifyQueryResults(GLboolean any, GLboolean stream0, GLboolean stream1, GLboolean stream2 = GL_FALSE,
1174 GLboolean stream3 = GL_FALSE)
1175 {
1176 bool result = true;
1177
1178 // Verify the result of the TRANSFORM_FEEDBACK_OVERFLOW query.
1179 result &= verifyQueryResult(m_overflow_query, any);
1180
1181 if (supportsTransformFeedback3())
1182 {
1183 // Verify the result of the TRANSFORM_FEEDBACK_STREAM_OVERFLOW queries
1184 // corresponding to the first 4 vertex streams.
1185 result &= verifyQueryResult(m_stream_overflow_query[0], stream0);
1186 result &= verifyQueryResult(m_stream_overflow_query[1], stream1);
1187 result &= verifyQueryResult(m_stream_overflow_query[2], stream2);
1188 result &= verifyQueryResult(m_stream_overflow_query[3], stream3);
1189
1190 // Expect the rest of the TRANSFORM_FEEDBACK_STREAM_OVERFLOW queries
1191 // to have a FALSE result.
1192 for (GLuint i = 4; i < getMaxVertexStreams(); ++i)
1193 {
1194 result &= verifyQueryResult(m_stream_overflow_query[i], GL_FALSE);
1195 }
1196 }
1197
1198 if (!result)
1199 {
1200 TCU_FAIL("Failed to validate the results of the queries");
1201 }
1202 }
1203
1204 /* Single stream version of verifyQueryResults */
verifyQueryResults(GLboolean result)1205 void verifyQueryResults(GLboolean result)
1206 {
1207 verifyQueryResults(result, result, GL_FALSE, GL_FALSE, GL_FALSE);
1208 }
1209
1210 /* Compiles and links transform feedback program. */
buildTransformFeedbackProgram()1211 void buildTransformFeedbackProgram()
1212 {
1213 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1214
1215 GLint status;
1216
1217 m_program = gl.createProgram();
1218
1219 const char* vsSource = transformFeedbackVertexShader();
1220
1221 GLuint vShader = gl.createShader(GL_VERTEX_SHADER);
1222 gl.shaderSource(vShader, 1, (const char**)&vsSource, NULL);
1223 gl.compileShader(vShader);
1224 gl.getShaderiv(vShader, GL_COMPILE_STATUS, &status);
1225 if (status == GL_FALSE)
1226 {
1227 GLint infoLogLength = 0;
1228 gl.getShaderiv(vShader, GL_INFO_LOG_LENGTH, &infoLogLength);
1229
1230 std::vector<char> infoLogBuf(infoLogLength + 1);
1231 gl.getShaderInfoLog(vShader, (GLsizei)infoLogBuf.size(), NULL, &infoLogBuf[0]);
1232
1233 std::string infoLog = &infoLogBuf[0];
1234 m_testCtx.getLog().writeShader(QP_SHADER_TYPE_VERTEX, vsSource, false, infoLog.c_str());
1235
1236 gl.deleteShader(vShader);
1237
1238 TCU_FAIL("Failed to compile transform feedback vertex shader");
1239 }
1240 gl.attachShader(m_program, vShader);
1241 gl.deleteShader(vShader);
1242
1243 const char* gsSource = transformFeedbackGeometryShader();
1244
1245 if (gsSource)
1246 {
1247 GLuint gShader = gl.createShader(GL_GEOMETRY_SHADER);
1248 gl.shaderSource(gShader, 1, (const char**)&gsSource, NULL);
1249 gl.compileShader(gShader);
1250 gl.getShaderiv(gShader, GL_COMPILE_STATUS, &status);
1251 if (status == GL_FALSE)
1252 {
1253 GLint infoLogLength = 0;
1254 gl.getShaderiv(gShader, GL_INFO_LOG_LENGTH, &infoLogLength);
1255
1256 std::vector<char> infoLogBuf(infoLogLength + 1);
1257 gl.getShaderInfoLog(gShader, (GLsizei)infoLogBuf.size(), NULL, &infoLogBuf[0]);
1258
1259 std::string infoLog = &infoLogBuf[0];
1260 m_testCtx.getLog().writeShader(QP_SHADER_TYPE_GEOMETRY, gsSource, false, infoLog.c_str());
1261
1262 gl.deleteShader(gShader);
1263
1264 TCU_FAIL("Failed to compile transform feedback geometry shader");
1265 }
1266 gl.attachShader(m_program, gShader);
1267 gl.deleteShader(gShader);
1268 }
1269
1270 gl.transformFeedbackVaryings(m_program, varyingsCount(), varyings(), bufferMode());
1271 gl.linkProgram(m_program);
1272 gl.getProgramiv(m_program, GL_LINK_STATUS, &status);
1273 if (status == GL_FALSE)
1274 {
1275 GLint infoLogLength = 0;
1276 gl.getProgramiv(m_program, GL_INFO_LOG_LENGTH, &infoLogLength);
1277
1278 std::vector<char> infoLogBuf(infoLogLength + 1);
1279 gl.getProgramInfoLog(m_program, (GLsizei)infoLogBuf.size(), NULL, &infoLogBuf[0]);
1280
1281 std::string infoLog = &infoLogBuf[0];
1282 m_testCtx.getLog().writeShader(QP_SHADER_TYPE_VERTEX, vsSource, true, infoLog.c_str());
1283
1284 TCU_FAIL("Failed to link transform feedback program");
1285 }
1286
1287 gl.useProgram(m_program);
1288 }
1289
1290 /* Generates a number of transform feedback buffers and binds them. */
setupTransformFeedbackBuffers()1291 void setupTransformFeedbackBuffers()
1292 {
1293 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1294
1295 m_tf_buffer_count = bufferCount();
1296
1297 m_tf_buffer = new GLuint[m_tf_buffer_count];
1298
1299 gl.genBuffers(m_tf_buffer_count, m_tf_buffer);
1300
1301 for (GLint i = 0; i < m_tf_buffer_count; ++i)
1302 {
1303 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, m_tf_buffer[i]);
1304 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bufferSize(i), NULL, GL_DYNAMIC_COPY);
1305 }
1306 }
1307
1308 /* Starts all overflow queries. */
beginQueries()1309 void beginQueries()
1310 {
1311 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1312
1313 gl.beginQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW, m_overflow_query);
1314
1315 if (supportsTransformFeedback3())
1316 {
1317 for (GLuint i = 0; i < getMaxVertexStreams(); ++i)
1318 {
1319 gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, i, m_stream_overflow_query[i]);
1320 }
1321 }
1322 }
1323
1324 /* Stops all overflow queries. */
endQueries()1325 void endQueries()
1326 {
1327 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1328
1329 gl.endQuery(GL_TRANSFORM_FEEDBACK_OVERFLOW);
1330
1331 if (supportsTransformFeedback3())
1332 {
1333 for (GLuint i = 0; i < getMaxVertexStreams(); ++i)
1334 {
1335 gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW, i);
1336 }
1337 }
1338 }
1339
1340 /* Draws a set of points to vertex stream #0 while having the overflow queries active. */
drawPoints(GLsizei count)1341 void drawPoints(GLsizei count)
1342 {
1343 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1344
1345 beginQueries();
1346 gl.drawArrays(GL_POINTS, 0, count);
1347 endQueries();
1348 }
1349
1350 /* Draws a set of triangles to vertex stream #0 while having the overflow queries active. */
drawTriangles(GLsizei count)1351 void drawTriangles(GLsizei count)
1352 {
1353 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1354
1355 beginQueries();
1356 gl.drawArrays(GL_TRIANGLES, 0, count * 3);
1357 endQueries();
1358 }
1359
1360 /* Vertex shader to use for transform feedback. */
1361 virtual const char* transformFeedbackVertexShader() = 0;
1362
1363 /* Geometry shader to use for transform feedback. */
1364 virtual const char* transformFeedbackGeometryShader() = 0;
1365
1366 /* Returns the number of transform feedback varyings. */
1367 virtual GLsizei varyingsCount() = 0;
1368
1369 /* Returns the array of transform feedback varying names. */
1370 virtual const char** varyings() = 0;
1371
1372 /* Returns the transform feedback buffer mode. */
1373 virtual GLenum bufferMode() = 0;
1374
1375 /* Returns the number of transform feedback buffers. */
1376 virtual GLsizei bufferCount() = 0;
1377
1378 /* Returns the size of the specified transform feedback buffer. */
1379 virtual GLsizei bufferSize(GLint index) = 0;
1380
1381 protected:
1382 GLuint m_overflow_query;
1383 GLuint* m_stream_overflow_query;
1384 GLuint m_query_buffer;
1385 GLsizei m_tf_buffer_count;
1386 GLuint* m_tf_buffer;
1387 GLuint m_vao;
1388 GLuint m_program;
1389 glu::ShaderProgram* m_checker_program;
1390 };
1391
1392 /*
1393 Base class for all single stream test cases.
1394 */
1395 class TransformFeedbackOverflowQuerySingleStreamBase : public TransformFeedbackOverflowQueryFunctionalBase
1396 {
1397 protected:
TransformFeedbackOverflowQuerySingleStreamBase(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name,const char * description)1398 TransformFeedbackOverflowQuerySingleStreamBase(deqp::Context& context, TransformFeedbackOverflowQueryTests::API api,
1399 const char* name, const char* description)
1400 : TransformFeedbackOverflowQueryFunctionalBase(context, api, name, description)
1401 {
1402 }
1403
1404 /* Vertex shader to use for transform feedback. */
transformFeedbackVertexShader()1405 virtual const char* transformFeedbackVertexShader()
1406 {
1407 return "#version 150 core\n"
1408 "out float output1;\n"
1409 "out float output2;\n"
1410 "out float output3;\n"
1411 "out float output4;\n"
1412 "void main() {\n"
1413 " output1 = 1.0;\n"
1414 " output2 = 2.0;\n"
1415 " output3 = 3.0;\n"
1416 " output4 = 4.0;\n"
1417 "}";
1418 }
1419
1420 /* No geometry shader for single stream test cases. */
transformFeedbackGeometryShader()1421 virtual const char* transformFeedbackGeometryShader()
1422 {
1423 return NULL;
1424 }
1425
1426 /* There are a total of 4 varyings. */
varyingsCount()1427 virtual GLsizei varyingsCount()
1428 {
1429 return 4;
1430 }
1431
1432 /* The varying name list contains all outputs in order. */
varyings()1433 virtual const char** varyings()
1434 {
1435 static const char* vars[] = { "output1", "output2", "output3", "output4" };
1436 return vars;
1437 }
1438 };
1439
1440 /*
1441 Test case #1 - Basic single stream, interleaved attributes.
1442 */
1443 class TransformFeedbackOverflowQueryBasicSingleStreamInterleavedAttribs
1444 : public TransformFeedbackOverflowQuerySingleStreamBase
1445 {
1446 public:
TransformFeedbackOverflowQueryBasicSingleStreamInterleavedAttribs(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)1447 TransformFeedbackOverflowQueryBasicSingleStreamInterleavedAttribs(deqp::Context& context,
1448 TransformFeedbackOverflowQueryTests::API api,
1449 const char* name)
1450 : TransformFeedbackOverflowQuerySingleStreamBase(context, api, name,
1451 "Basic single stream, interleaved attributes.")
1452 {
1453 }
1454
1455 /* Use interleaved attributes. */
bufferMode()1456 virtual GLenum bufferMode()
1457 {
1458 return GL_INTERLEAVED_ATTRIBS;
1459 }
1460
1461 /* A single transform feedback buffer is enough. */
bufferCount()1462 virtual GLsizei bufferCount()
1463 {
1464 return 1;
1465 }
1466
1467 /* The transform feedback buffer should be able to capture exactly 10 vertices. */
bufferSize(GLint index)1468 virtual GLsizei bufferSize(GLint index)
1469 {
1470 (void)index;
1471 return static_cast<GLsizei>(10 * sizeof(GLfloat) * varyingsCount());
1472 }
1473
1474 /* Test case iterate function. Contains the actual test case logic. */
iterate()1475 IterateResult iterate()
1476 {
1477 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1478
1479 // Call BeginTransformFeedback with mode POINTS.
1480 gl.beginTransformFeedback(GL_POINTS);
1481
1482 // Start the query, submit draw that results in feeding back exactly 10
1483 // points, then stop the query.
1484 drawPoints(10);
1485
1486 // Call EndTransformFeedback.
1487 gl.endTransformFeedback();
1488
1489 // Use the basic checking mechanism to validate that the result of the
1490 // query is FALSE.
1491 verifyQueryResults(GL_FALSE);
1492
1493 // Repeat the above steps, but this time feed back more than 10 vertices
1494 // and expect the result of the query to be TRUE.
1495 gl.beginTransformFeedback(GL_POINTS);
1496 drawPoints(11);
1497 gl.endTransformFeedback();
1498 verifyQueryResults(GL_TRUE);
1499
1500 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1501
1502 return STOP;
1503 }
1504 };
1505
1506 /*
1507 Test case #2 - Basic single stream, separate attributes.
1508 */
1509 class TransformFeedbackOverflowQueryBasicSingleStreamSeparateAttribs
1510 : public TransformFeedbackOverflowQuerySingleStreamBase
1511 {
1512 public:
TransformFeedbackOverflowQueryBasicSingleStreamSeparateAttribs(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)1513 TransformFeedbackOverflowQueryBasicSingleStreamSeparateAttribs(deqp::Context& context,
1514 TransformFeedbackOverflowQueryTests::API api,
1515 const char* name)
1516 : TransformFeedbackOverflowQuerySingleStreamBase(context, api, name,
1517 "Basic single stream, separate attributes.")
1518 {
1519 }
1520
1521 /* Use separate attributes. */
bufferMode()1522 virtual GLenum bufferMode()
1523 {
1524 return GL_SEPARATE_ATTRIBS;
1525 }
1526
1527 /* We need a separate buffer for each varying. */
bufferCount()1528 virtual GLsizei bufferCount()
1529 {
1530 return varyingsCount();
1531 }
1532
1533 /* One of the transform feedback buffers should be able to capture exactly 12 vertices,
1534 the others should be able to capture at least 15 vertices. */
bufferSize(GLint index)1535 virtual GLsizei bufferSize(GLint index)
1536 {
1537 if (index == 1)
1538 {
1539 return 12 * sizeof(GLfloat);
1540 }
1541 else
1542 {
1543 return 15 * sizeof(GLfloat);
1544 }
1545 }
1546
1547 /* Test case iterate function. Contains the actual test case logic. */
iterate()1548 IterateResult iterate()
1549 {
1550 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1551
1552 // Call BeginTransformFeedback with mode TRIANGLES.
1553 gl.beginTransformFeedback(GL_TRIANGLES);
1554
1555 // Start the query, submit draw that results in feeding back exactly 4
1556 // triangles, then stop the query.
1557 drawTriangles(4);
1558
1559 // Call EndTransformFeedback.
1560 gl.endTransformFeedback();
1561
1562 // Use the basic checking mechanism to validate that the result of the
1563 // query is FALSE.
1564 verifyQueryResults(GL_FALSE);
1565
1566 // Repeat the above steps, but this time feed back exactly 5 triangles
1567 // and expect the result of the query to be TRUE.
1568 gl.beginTransformFeedback(GL_TRIANGLES);
1569 drawTriangles(5);
1570 gl.endTransformFeedback();
1571 verifyQueryResults(GL_TRUE);
1572
1573 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1574
1575 return STOP;
1576 }
1577 };
1578
1579 /*
1580 Test case #3 - Advanced single stream, interleaved attributes.
1581 */
1582 class TransformFeedbackOverflowQueryAdvancedSingleStreamInterleavedAttribs
1583 : public TransformFeedbackOverflowQuerySingleStreamBase
1584 {
1585 public:
TransformFeedbackOverflowQueryAdvancedSingleStreamInterleavedAttribs(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)1586 TransformFeedbackOverflowQueryAdvancedSingleStreamInterleavedAttribs(deqp::Context& context,
1587 TransformFeedbackOverflowQueryTests::API api,
1588 const char* name)
1589 : TransformFeedbackOverflowQuerySingleStreamBase(context, api, name,
1590 "Advanced single stream, interleaved attributes.")
1591 {
1592 }
1593
1594 /* Use interleaved attributes. */
bufferMode()1595 virtual GLenum bufferMode()
1596 {
1597 return GL_INTERLEAVED_ATTRIBS;
1598 }
1599
1600 /* A single transform feedback buffer is enough. */
bufferCount()1601 virtual GLsizei bufferCount()
1602 {
1603 return 1;
1604 }
1605
1606 /* The transform feedback buffer should be able to capture exactly 10 vertices. */
bufferSize(GLint index)1607 virtual GLsizei bufferSize(GLint index)
1608 {
1609 (void)index;
1610 return static_cast<GLsizei>(10 * sizeof(GLfloat) * varyingsCount());
1611 }
1612
1613 /* Test case iterate function. Contains the actual test case logic. */
iterate()1614 IterateResult iterate()
1615 {
1616 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1617
1618 // If GL 4.0 and ARB_transform_feedback2 are not supported then skip this
1619 // test case.
1620 if (!supportsTransformFeedback2())
1621 {
1622 throw tcu::NotSupportedError("Required transform_feedback2 extension is not supported");
1623 }
1624
1625 // Call BeginTransformFeedback with mode POINTS.
1626 gl.beginTransformFeedback(GL_POINTS);
1627
1628 // Start the query, submit draw that results in feeding back exactly 8
1629 // triangles, then stop the query.
1630 drawPoints(8);
1631
1632 // Call PauseTransformFeedback.
1633 gl.pauseTransformFeedback();
1634
1635 // Use the basic checking mechanism to validate that the result of the
1636 // query is FALSE.
1637 verifyQueryResults(GL_FALSE);
1638
1639 // Start the query, submit draw that would result in feeding back more than
1640 // 10 points if transform feedback wasn't paused, then stop the query.
1641 drawPoints(11);
1642
1643 // Use the basic checking mechanism to validate that the result of the
1644 // query is FALSE.
1645 verifyQueryResults(GL_FALSE);
1646
1647 // Call ResumeTransformFeedback.
1648 gl.resumeTransformFeedback();
1649
1650 // Start the query, submit draw that results in feeding back exactly 1
1651 // point, then stop the query.
1652 drawPoints(1);
1653
1654 // Call PauseTransformFeedback.
1655 gl.pauseTransformFeedback();
1656
1657 // Use the basic checking mechanism to validate that the result of the
1658 // query is FALSE.
1659 verifyQueryResults(GL_FALSE);
1660
1661 // Call ResumeTransformFeedback.
1662 gl.resumeTransformFeedback();
1663
1664 // Start the query, submit draw that results in feeding back exactly 2
1665 // point, then stop the query.
1666 drawPoints(2);
1667
1668 // Call EndTransformFeedback.
1669 gl.endTransformFeedback();
1670
1671 // Use the basic checking mechanism to validate that the result of the
1672 // query is TRUE.
1673 verifyQueryResults(GL_TRUE);
1674
1675 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1676
1677 return STOP;
1678 }
1679 };
1680
1681 /*
1682 Test case #4 - Advanced single stream, separate attributes.
1683 */
1684 class TransformFeedbackOverflowQueryAdvancedSingleStreamSeparateAttribs
1685 : public TransformFeedbackOverflowQuerySingleStreamBase
1686 {
1687 public:
TransformFeedbackOverflowQueryAdvancedSingleStreamSeparateAttribs(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)1688 TransformFeedbackOverflowQueryAdvancedSingleStreamSeparateAttribs(deqp::Context& context,
1689 TransformFeedbackOverflowQueryTests::API api,
1690 const char* name)
1691 : TransformFeedbackOverflowQuerySingleStreamBase(context, api, name,
1692 "Advanced single stream, separate attributes.")
1693 {
1694 }
1695
1696 /* Use separate attributes. */
bufferMode()1697 virtual GLenum bufferMode()
1698 {
1699 return GL_SEPARATE_ATTRIBS;
1700 }
1701
1702 /* We need a separate buffer for each varying. */
bufferCount()1703 virtual GLsizei bufferCount()
1704 {
1705 return varyingsCount();
1706 }
1707
1708 /* One of the transform feedback buffers should be able to capture exactly 12 vertices,
1709 the others should be able to capture at least 15 vertices. */
bufferSize(GLint index)1710 virtual GLsizei bufferSize(GLint index)
1711 {
1712 if (index == 2)
1713 {
1714 return 12 * sizeof(GLfloat);
1715 }
1716 else
1717 {
1718 return 15 * sizeof(GLfloat);
1719 }
1720 }
1721
1722 /* Test case iterate function. Contains the actual test case logic. */
iterate()1723 IterateResult iterate()
1724 {
1725 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1726
1727 // If GL 4.0 and ARB_transform_feedback2 are not supported then skip this
1728 // test case.
1729 if (!supportsTransformFeedback2())
1730 {
1731 throw tcu::NotSupportedError("Required transform_feedback2 extension is not supported");
1732 }
1733
1734 // Call BeginTransformFeedback with mode TRIANGLES.
1735 gl.beginTransformFeedback(GL_TRIANGLES);
1736
1737 // Start the query, submit draw that results in feeding back exactly 2
1738 // triangles, then stop the query.
1739 drawTriangles(2);
1740
1741 // Call PauseTransformFeedback.
1742 gl.pauseTransformFeedback();
1743
1744 // Use the basic checking mechanism to validate that the result of the
1745 // query is FALSE.
1746 verifyQueryResults(GL_FALSE);
1747
1748 // Start the query, submit draw that would result in feeding back more than
1749 // 4 triangles if transform feedback wasn't paused, then stop the query.
1750 drawTriangles(4);
1751
1752 // Use the basic checking mechanism to validate that the result of the
1753 // query is FALSE.
1754 verifyQueryResults(GL_FALSE);
1755
1756 // Call ResumeTransformFeedback.
1757 gl.resumeTransformFeedback();
1758
1759 // Start the query, submit draw that results in feeding back exactly 2
1760 // triangles, then stop the query.
1761 drawTriangles(2);
1762
1763 // Call PauseTransformFeedback.
1764 gl.pauseTransformFeedback();
1765
1766 // Use the basic checking mechanism to validate that the result of the
1767 // query is FALSE.
1768 verifyQueryResults(GL_FALSE);
1769
1770 // Call ResumeTransformFeedback.
1771 gl.resumeTransformFeedback();
1772
1773 // Start the query, submit draw that results in feeding back exactly 1
1774 // triangles, then stop the query.
1775 drawTriangles(1);
1776
1777 // Call EndTransformFeedback.
1778 gl.endTransformFeedback();
1779
1780 // Use the basic checking mechanism to validate that the result of the
1781 // query is TRUE.
1782 verifyQueryResults(GL_TRUE);
1783
1784 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1785
1786 return STOP;
1787 }
1788 };
1789
1790 /*
1791 Base class for all multiple stream test cases.
1792 */
1793 class TransformFeedbackOverflowQueryMultipleStreamsBase : public TransformFeedbackOverflowQueryFunctionalBase
1794 {
1795 protected:
TransformFeedbackOverflowQueryMultipleStreamsBase(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name,const char * description)1796 TransformFeedbackOverflowQueryMultipleStreamsBase(deqp::Context& context,
1797 TransformFeedbackOverflowQueryTests::API api, const char* name,
1798 const char* description)
1799 : TransformFeedbackOverflowQueryFunctionalBase(context, api, name, description)
1800 {
1801 }
1802
1803 /* Vertex shader to use for transform feedback. */
transformFeedbackVertexShader()1804 virtual const char* transformFeedbackVertexShader()
1805 {
1806 return "#version 150 core\n"
1807 "void main() {\n"
1808 "}";
1809 }
1810
1811 /* Use interleaved attributes. */
bufferMode()1812 virtual GLenum bufferMode()
1813 {
1814 return GL_INTERLEAVED_ATTRIBS;
1815 }
1816
1817 /* Always use 4 transform feedback buffers. */
bufferCount()1818 virtual GLsizei bufferCount()
1819 {
1820 return 4;
1821 }
1822
1823 /* Draws a set of points to each vertex stream while having the overflow queries active. */
drawStreams(GLsizei count0,GLsizei count1=0,GLsizei count2=0,GLsizei count3=0)1824 void drawStreams(GLsizei count0, GLsizei count1 = 0, GLsizei count2 = 0, GLsizei count3 = 0)
1825 {
1826 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1827
1828 GLint streamLoc = gl.getUniformLocation(m_program, "stream");
1829
1830 beginQueries();
1831
1832 gl.uniform1ui(streamLoc, 0);
1833 gl.drawArrays(GL_POINTS, 0, count0);
1834
1835 gl.uniform1ui(streamLoc, 1);
1836 gl.drawArrays(GL_POINTS, 0, count1);
1837
1838 gl.uniform1ui(streamLoc, 2);
1839 gl.drawArrays(GL_POINTS, 0, count2);
1840
1841 gl.uniform1ui(streamLoc, 3);
1842 gl.drawArrays(GL_POINTS, 0, count3);
1843
1844 endQueries();
1845 }
1846 };
1847
1848 /*
1849 Test case #5 - Advanced multiple streams, one buffer per stream.
1850 */
1851 class TransformFeedbackOverflowQueryMultipleStreamsOneBufferPerStream
1852 : public TransformFeedbackOverflowQueryMultipleStreamsBase
1853 {
1854 public:
TransformFeedbackOverflowQueryMultipleStreamsOneBufferPerStream(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)1855 TransformFeedbackOverflowQueryMultipleStreamsOneBufferPerStream(deqp::Context& context,
1856 TransformFeedbackOverflowQueryTests::API api,
1857 const char* name)
1858 : TransformFeedbackOverflowQueryMultipleStreamsBase(context, api, name,
1859 "Advanced multiple streams, one buffer per stream.")
1860 {
1861 }
1862
1863 /* Geometry shader to use for transform feedback. */
transformFeedbackGeometryShader()1864 virtual const char* transformFeedbackGeometryShader()
1865 {
1866 return "#version 150 core\n"
1867 "#extension GL_ARB_gpu_shader5 : require\n"
1868 "layout(points) in;\n"
1869 "layout(points, max_vertices = 1) out;\n"
1870 "layout(stream=0) out float output1;\n"
1871 "layout(stream=1) out float output2;\n"
1872 "layout(stream=2) out float output3;\n"
1873 "layout(stream=3) out float output4;\n"
1874 "uniform uint stream;\n"
1875 "void main() {\n"
1876 " if (stream == 0) {\n"
1877 " output1 = 1.0;\n"
1878 " EmitStreamVertex(0);\n"
1879 " EndStreamPrimitive(0);\n"
1880 " }\n"
1881 " if (stream == 1) {\n"
1882 " output2 = 2.0;\n"
1883 " EmitStreamVertex(1);\n"
1884 " EndStreamPrimitive(1);\n"
1885 " }\n"
1886 " if (stream == 2) {\n"
1887 " output3 = 3.0;\n"
1888 " EmitStreamVertex(2);\n"
1889 " EndStreamPrimitive(2);\n"
1890 " }\n"
1891 " if (stream == 3) {\n"
1892 " output4 = 4.0;\n"
1893 " EmitStreamVertex(3);\n"
1894 " EndStreamPrimitive(3);\n"
1895 " }\n"
1896 "}";
1897 }
1898
1899 /* Together with the separators there are a total of 7 varyings. */
varyingsCount()1900 virtual GLsizei varyingsCount()
1901 {
1902 return 7;
1903 }
1904
1905 /* Each output goes to different buffer. The mapping between vertex stream outputs and transform feedback buffers is non-identity. */
varyings()1906 virtual const char** varyings()
1907 {
1908 static const char* vars[] = { "output4", "gl_NextBuffer", "output3", "gl_NextBuffer",
1909 "output2", "gl_NextBuffer", "output1" };
1910 return vars;
1911 }
1912
1913 /* The size of the transform feedback buffers should be enough to be able to capture exactly 10 vertices for each vertex stream. */
bufferSize(GLint index)1914 virtual GLsizei bufferSize(GLint index)
1915 {
1916 (void)index;
1917 return 10 * sizeof(GLfloat);
1918 }
1919
1920 /* Test case iterate function. Contains the actual test case logic. */
iterate()1921 IterateResult iterate()
1922 {
1923 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1924
1925 // If GL 4.0 and ARB_transform_feedback3 are not supported then skip this
1926 // test case.
1927 if (!supportsTransformFeedback3())
1928 {
1929 throw tcu::NotSupportedError("Required transform_feedback3 extension is not supported");
1930 }
1931
1932 // If GL 4.0 and ARB_gpu_shader5 are not supported then skip this
1933 // test case.
1934 if (!supportsGpuShader5())
1935 {
1936 throw tcu::NotSupportedError("Required gpu_shader5 extension is not supported");
1937 }
1938
1939 // Call BeginTransformFeedback with mode POINTS.
1940 gl.beginTransformFeedback(GL_POINTS);
1941
1942 // Start all queries, submit draw that results in feeding back exactly 8
1943 // points for all four vertex streams, then stop the queries.
1944 drawStreams(8, 8, 8, 8);
1945
1946 // Call PauseTransformFeedback.
1947 gl.pauseTransformFeedback();
1948
1949 // Use the basic checking mechanism to validate that the result of the
1950 // queries are all FALSE.
1951 verifyQueryResults(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1952
1953 // Start the queries, submit draw that would result in feeding back more
1954 // than 10 points for all four vertex streams if transform feedback wasn't
1955 // paused, then stop the queries.
1956 drawStreams(11, 11, 11, 11);
1957
1958 // Use the basic checking mechanism to validate that the result of the
1959 // queries are all FALSE.
1960 verifyQueryResults(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1961
1962 // Call ResumeTransformFeedback.
1963 gl.resumeTransformFeedback();
1964
1965 // Start the queries, submit draw that results in feeding back exactly 3
1966 // points only for vertex streams #1 and #3, then stop the queries.
1967 drawStreams(0, 3, 0, 3);
1968
1969 // Call PauseTransformFeedback.
1970 gl.pauseTransformFeedback();
1971
1972 // Use the basic checking mechanism to validate that the result of the
1973 // queries are all FALSE, except for the TRANSFORM_FEEDBACK_OVERFLOW
1974 // query, and the TRANSFORM_FEEDBACK_STREAM_OVERFLOW queries for
1975 // vertex streams #1 and #3, which should have a TRUE result.
1976 verifyQueryResults(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
1977
1978 // Call ResumeTransformFeedback.
1979 gl.resumeTransformFeedback();
1980
1981 // Start the queries, submit draw that results in feeding back exactly 2
1982 // points only for vertex streams #0 and #2, then stop the queries.
1983 drawStreams(2, 0, 2, 0);
1984
1985 // Call PauseTransformFeedback.
1986 gl.pauseTransformFeedback();
1987
1988 // Use the basic checking mechanism to validate that the result of the
1989 // queries are all FALSE.
1990 verifyQueryResults(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1991
1992 // Call ResumeTransformFeedback.
1993 gl.resumeTransformFeedback();
1994
1995 // Start the queries, submit draw that results in feeding back exactly 1
1996 // point for vertex streams #2 and #3, then stop the queries.
1997 drawStreams(0, 0, 1, 1);
1998
1999 // Call EndTransformFeedback.
2000 gl.endTransformFeedback();
2001
2002 // Use the basic checking mechanism to validate that the result of the
2003 // queries are all FALSE, except for the TRANSFORM_FEEDBACK_OVERFLOW
2004 // query, and the TRANSFORM_FEEDBACK_STREAM_OVERFLOW queries for
2005 // vertex streams #2 and #3, which should have a TRUE result.
2006 verifyQueryResults(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE);
2007
2008 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2009
2010 return STOP;
2011 }
2012 };
2013
2014 /*
2015 Test case #6 - Advanced multiple streams, multiple buffers per stream.
2016 */
2017 class TransformFeedbackOverflowQueryMultipleStreamsMultipleBufferPerStream
2018 : public TransformFeedbackOverflowQueryMultipleStreamsBase
2019 {
2020 public:
TransformFeedbackOverflowQueryMultipleStreamsMultipleBufferPerStream(deqp::Context & context,TransformFeedbackOverflowQueryTests::API api,const char * name)2021 TransformFeedbackOverflowQueryMultipleStreamsMultipleBufferPerStream(deqp::Context& context,
2022 TransformFeedbackOverflowQueryTests::API api,
2023 const char* name)
2024 : TransformFeedbackOverflowQueryMultipleStreamsBase(context, api, name,
2025 "Advanced multiple streams, multiple buffers per stream.")
2026 {
2027 }
2028
2029 /* Geometry shader to use for transform feedback. */
transformFeedbackGeometryShader()2030 virtual const char* transformFeedbackGeometryShader()
2031 {
2032 return "#version 150 core\n"
2033 "#extension GL_ARB_gpu_shader5 : require\n"
2034 "layout(points) in;\n"
2035 "layout(points, max_vertices = 1) out;\n"
2036 "layout(stream=0) out float output1;\n"
2037 "layout(stream=0) out float output2;\n"
2038 "layout(stream=1) out float output3;\n"
2039 "layout(stream=1) out float output4;\n"
2040 "uniform uint stream;\n"
2041 "void main() {\n"
2042 " if (stream == 0) {\n"
2043 " output1 = 1.0;\n"
2044 " output2 = 2.0;\n"
2045 " EmitStreamVertex(0);\n"
2046 " EndStreamPrimitive(0);\n"
2047 " }\n"
2048 " if (stream == 1) {\n"
2049 " output3 = 3.0;\n"
2050 " output4 = 4.0;\n"
2051 " EmitStreamVertex(1);\n"
2052 " EndStreamPrimitive(1);\n"
2053 " }\n"
2054 "}";
2055 }
2056
2057 /* Together with the separators there are a total of 7 varyings. */
varyingsCount()2058 virtual GLsizei varyingsCount()
2059 {
2060 return 7;
2061 }
2062
2063 /* Vertex stream #0 is captured by transform feedback buffers #1 and #2, while
2064 vertex stream #1 is captured by transform feedback buffers #3 and #0. */
varyings()2065 virtual const char** varyings()
2066 {
2067 static const char* vars[] = { "output4", "gl_NextBuffer", "output1", "gl_NextBuffer",
2068 "output2", "gl_NextBuffer", "output3" };
2069 return vars;
2070 }
2071
2072 /* Transform feedback buffers #0 and #1 should be able to capture exactly 10 vertices, while
2073 transform feedback buffers #2 and #3 should be able to capture exactly 20 vertices. */
bufferSize(GLint index)2074 virtual GLsizei bufferSize(GLint index)
2075 {
2076 if (index < 2)
2077 {
2078 return 10 * sizeof(GLfloat);
2079 }
2080 else
2081 {
2082 return 20 * sizeof(GLfloat);
2083 }
2084 }
2085
2086 /* Test case iterate function. Contains the actual test case logic. */
iterate()2087 IterateResult iterate()
2088 {
2089 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2090
2091 // If GL 4.0 and ARB_transform_feedback3 are not supported then skip this
2092 // test case.
2093 if (!supportsTransformFeedback3())
2094 {
2095 throw tcu::NotSupportedError("Required transform_feedback3 extension is not supported");
2096 }
2097
2098 // If GL 4.0 and ARB_gpu_shader5 are not supported then skip this
2099 // test case.
2100 if (!supportsGpuShader5())
2101 {
2102 throw tcu::NotSupportedError("Required gpu_shader5 extension is not supported");
2103 }
2104
2105 // Call BeginTransformFeedback with mode POINTS.
2106 gl.beginTransformFeedback(GL_POINTS);
2107
2108 // Start all queries, submit draw that results in feeding back exactly 8
2109 // points to both vertex streams, then stop the queries.
2110 drawStreams(8, 8);
2111
2112 // Call PauseTransformFeedback.
2113 gl.pauseTransformFeedback();
2114
2115 // Use the basic checking mechanism to validate that the result of the
2116 // queries are all FALSE.
2117 verifyQueryResults(GL_FALSE, GL_FALSE, GL_FALSE);
2118
2119 // Start the queries, submit draw that would result in feeding back more
2120 // than 10 points for both vertex streams if transform feedback wasn't
2121 // paused, then stop the queries.
2122 drawStreams(11, 11);
2123
2124 // Use the basic checking mechanism to validate that the result of the
2125 // queries are all FALSE.
2126 verifyQueryResults(GL_FALSE, GL_FALSE, GL_FALSE);
2127
2128 // Call ResumeTransformFeedback.
2129 gl.resumeTransformFeedback();
2130
2131 // Start the queries, submit draw that results in feeding back exactly 1
2132 // point for vertex stream #0 and exactly 3 points for vertex stream #1,
2133 // then stop the queries.
2134 drawStreams(1, 3);
2135
2136 // Call PauseTransformFeedback.
2137 gl.pauseTransformFeedback();
2138
2139 // Use the basic checking mechanism to validate that the result of the
2140 // queries are all FALSE, except for the TRANSFORM_FEEDBACK_OVERFLOW
2141 // query, and the TRANSFORM_FEEDBACK_STREAM_OVERFLOW query for vertex
2142 // stream #1, which should have a TRUE result.
2143 verifyQueryResults(GL_TRUE, GL_FALSE, GL_TRUE);
2144
2145 // Call ResumeTransformFeedback.
2146 gl.resumeTransformFeedback();
2147
2148 // Start the queries, submit draw that results in feeding back exactly 1
2149 // point only for vertex stream #0, then stop the queries.
2150 drawStreams(1, 0);
2151
2152 // Call PauseTransformFeedback.
2153 gl.pauseTransformFeedback();
2154
2155 // Use the basic checking mechanism to validate that the result of the
2156 // queries are all FALSE.
2157 verifyQueryResults(GL_FALSE, GL_FALSE, GL_FALSE);
2158
2159 // Call ResumeTransformFeedback.
2160 gl.resumeTransformFeedback();
2161
2162 // Start the queries, submit draw that results in feeding back exactly 1
2163 // point for vertex streams #0 and #1, then stop the queries.
2164 drawStreams(1, 1);
2165
2166 // Call EndTransformFeedback.
2167 gl.endTransformFeedback();
2168
2169 // Use the basic checking mechanism to validate that the result of the
2170 // queries are all FALSE, except for the TRANSFORM_FEEDBACK_OVERFLOW
2171 // query, and the TRANSFORM_FEEDBACK_STREAM_OVERFLOW queries for
2172 // vertex streams #0 and #1, which should have a TRUE result.
2173 verifyQueryResults(GL_TRUE, GL_TRUE, GL_TRUE);
2174
2175 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2176
2177 return STOP;
2178 }
2179 };
2180
apiToTestName(TransformFeedbackOverflowQueryTests::API api)2181 const char* apiToTestName(TransformFeedbackOverflowQueryTests::API api)
2182 {
2183 switch (api)
2184 {
2185 case TransformFeedbackOverflowQueryTests::API_GL_ARB_transform_feedback_overflow_query:
2186 return "transform_feedback_overflow_query_ARB";
2187 }
2188 DE_ASSERT(0);
2189 return "";
2190 }
2191
2192 /** Constructor.
2193 *
2194 * @param context Rendering context.
2195 * @param api API to test (core vs ARB extension)
2196 **/
TransformFeedbackOverflowQueryTests(deqp::Context & context,API api)2197 TransformFeedbackOverflowQueryTests::TransformFeedbackOverflowQueryTests(deqp::Context& context, API api)
2198 : TestCaseGroup(context, apiToTestName(api), "Verifies \"transform_feedback_overflow_query\" functionality")
2199 , m_api(api)
2200 {
2201 /* Left blank on purpose */
2202 }
2203
2204 /** Destructor.
2205 *
2206 **/
~TransformFeedbackOverflowQueryTests()2207 TransformFeedbackOverflowQueryTests::~TransformFeedbackOverflowQueryTests()
2208 {
2209 }
2210
2211 /** Initializes the texture_barrier test group.
2212 *
2213 **/
init(void)2214 void TransformFeedbackOverflowQueryTests::init(void)
2215 {
2216 addChild(new TransformFeedbackOverflowQueryImplDepState(m_context, m_api, "implementation-dependent-state"));
2217 addChild(new TransformFeedbackOverflowQueryDefaultState(m_context, m_api, "default-context-state"));
2218 addChild(new TransformFeedbackOverflowQueryStateUpdate(m_context, m_api, "context-state-update"));
2219 addChild(new TransformFeedbackOverflowQueryErrorInvalidIndex(m_context, m_api, "error-invalid-index"));
2220 addChild(new TransformFeedbackOverflowQueryErrorAlreadyActive(m_context, m_api, "error-already-active"));
2221 addChild(new TransformFeedbackOverflowQueryErrorIncompatibleTarget(m_context, m_api, "error-incompatible-target"));
2222 addChild(new TransformFeedbackOverflowQueryErrorNoActiveQuery(m_context, m_api, "error-no-active-query"));
2223 addChild(new TransformFeedbackOverflowQueryBasicSingleStreamInterleavedAttribs(
2224 m_context, m_api, "basic-single-stream-interleaved-attribs"));
2225 addChild(new TransformFeedbackOverflowQueryBasicSingleStreamSeparateAttribs(
2226 m_context, m_api, "basic-single-stream-separate-attribs"));
2227 addChild(new TransformFeedbackOverflowQueryAdvancedSingleStreamInterleavedAttribs(
2228 m_context, m_api, "advanced-single-stream-interleaved-attribs"));
2229 addChild(new TransformFeedbackOverflowQueryAdvancedSingleStreamSeparateAttribs(
2230 m_context, m_api, "advanced-single-stream-separate-attribs"));
2231 addChild(new TransformFeedbackOverflowQueryMultipleStreamsOneBufferPerStream(
2232 m_context, m_api, "multiple-streams-one-buffer-per-stream"));
2233 addChild(new TransformFeedbackOverflowQueryMultipleStreamsMultipleBufferPerStream(
2234 m_context, m_api, "multiple-streams-multiple-buffers-per-stream"));
2235 }
2236 } /* glcts namespace */
2237