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