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