• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2024 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */ /*!
20  * \file
21  * \brief
22  */ /*-------------------------------------------------------------------*/
23 
24 /**
25  */ /*!
26  * \file  glcTransformFeedbackTests.cpp
27  * \brief Conformance tests for the transform_feedback2 functionality.
28  */ /*-------------------------------------------------------------------*/
29 
30 #include "deMath.h"
31 
32 #include "glcTransformFeedbackTests.hpp"
33 #include "gluDefs.hpp"
34 #include "gluShaderProgram.hpp"
35 #include "gluContextInfo.hpp"
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 #include "tcuStringTemplate.hpp"
39 #include "tcuTestLog.hpp"
40 
41 using namespace glw;
42 using namespace glu;
43 
44 namespace
45 {
46 // clang-format off
47 GLfloat vertices[24] = {
48     -0.8f, -0.8f, 0.0f, 1.0f,
49     0.8f,  -0.8f, 0.0f, 1.0f,
50     -0.8f, 0.8f,  0.0f, 1.0f,
51 
52     0.8f,  0.8f,  0.0f, 1.0f,
53     -0.8f, 0.8f,  0.0f, 1.0f,
54     0.8f,  -0.8f, 0.0f, 1.0f,
55 };
56 // clang-format on
57 
58 } // namespace
59 
60 namespace glcts
61 {
62 
63 // clang-format off
64 /** @brief Vertex shader source code to test transform feedback states conformance. */
65 const glw::GLchar* glcts::TransformFeedbackStatesTestCase::m_shader_vert =
66     R"(${VERSION}
67     in vec4 in_vertex;
68 
69     void main (void)
70     {
71         vec4 temp = in_vertex;
72 
73         temp.xyz *= 0.5;
74 
75         gl_Position = temp;
76     }
77 )";
78 
79 /** @brief Fragment shader source code to test transform feedback states conformance. */
80 const glw::GLchar* glcts::TransformFeedbackStatesTestCase::m_shader_frag =
81     R"(${VERSION}
82     ${PRECISION}
83     out vec4 frag;
84     void main (void)
85     {
86         frag = vec4(0.0);
87     }
88 )";
89 // clang-format on
90 
91 /** Constructor.
92  *
93  *  @param context     Rendering context
94  */
TransformFeedbackStatesTestCase(deqp::Context & context)95 TransformFeedbackStatesTestCase::TransformFeedbackStatesTestCase(deqp::Context &context)
96     : TestCase(context, "transform_feedback2_states", "Verifies transform feedback objects with different states")
97     , m_program(0)
98     , m_vao(0)
99     , m_buffers{0, 0}
100     , m_tf_id(0)
101     , m_queries{0, 0}
102     , m_isContextES(false)
103     , m_testSupported(false)
104 {
105 }
106 
~TransformFeedbackStatesTestCase()107 TransformFeedbackStatesTestCase::~TransformFeedbackStatesTestCase()
108 {
109     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
110 
111     gl.deleteQueries(2, m_queries);
112     GLU_EXPECT_NO_ERROR(gl.getError(), "deleteQueries");
113 
114     gl.deleteBuffers(2, m_buffers);
115     GLU_EXPECT_NO_ERROR(gl.getError(), "deleteBuffers");
116 
117     if (m_tf_id != 0)
118     {
119         gl.deleteTransformFeedbacks(1, &m_tf_id);
120         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTransformFeedbacks");
121     }
122 
123     if (m_vao != 0)
124     {
125         gl.deleteVertexArrays(1, &m_vao);
126         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteVertexArrays");
127     }
128 
129     if (m_program != 0)
130     {
131         gl.deleteProgram(m_program);
132         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteProgram");
133     }
134 }
135 
136 /** Stub deinit method. */
deinit()137 void TransformFeedbackStatesTestCase::deinit()
138 {
139     /* Left blank intentionally */
140 }
141 
142 /** Stub init method */
init()143 void TransformFeedbackStatesTestCase::init()
144 {
145     const glu::RenderContext &renderContext = m_context.getRenderContext();
146     glu::GLSLVersion glslVersion            = glu::getContextTypeGLSLVersion(renderContext.getType());
147     m_isContextES                           = glu::isContextTypeES(renderContext.getType());
148 
149     specializationMap["VERSION"]   = glu::getGLSLVersionDeclaration(glslVersion);
150     specializationMap["PRECISION"] = "";
151 
152     if (m_isContextES)
153     {
154         specializationMap["PRECISION"] = "precision highp float;";
155         m_testSupported                = true;
156     }
157     else
158     {
159         auto contextType = m_context.getRenderContext().getType();
160         m_testSupported  = (glu::contextSupports(contextType, glu::ApiType::core(1, 4)) &&
161                            m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback2")) ||
162                           glu::contextSupports(contextType, glu::ApiType::core(4, 0));
163     }
164 }
165 
166 /* Compiles and links transform feedback program. */
buildTransformFeedbackProgram(const char * vsSource,const char * fsSource)167 void TransformFeedbackStatesTestCase::buildTransformFeedbackProgram(const char *vsSource, const char *fsSource)
168 {
169     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
170 
171     GLint status = 0;
172     m_program    = gl.createProgram();
173     if (!m_program)
174     {
175         TCU_FAIL("Program object not valid");
176     }
177     GLU_EXPECT_NO_ERROR(gl.getError(), "createProgram");
178 
179     // vertex shader
180     {
181         GLuint vShader = gl.createShader(GL_VERTEX_SHADER);
182         if (!vShader)
183         {
184             TCU_FAIL("Shader object not valid");
185         }
186         GLU_EXPECT_NO_ERROR(gl.getError(), "createShader");
187 
188         gl.shaderSource(vShader, 1, (const char **)&vsSource, NULL);
189         GLU_EXPECT_NO_ERROR(gl.getError(), "shaderSource");
190 
191         gl.compileShader(vShader);
192         GLU_EXPECT_NO_ERROR(gl.getError(), "compileShader");
193 
194         gl.getShaderiv(vShader, GL_COMPILE_STATUS, &status);
195         GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv");
196 
197         if (status == GL_FALSE)
198         {
199             GLint infoLogLength = 0;
200             gl.getShaderiv(vShader, GL_INFO_LOG_LENGTH, &infoLogLength);
201             GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv");
202 
203             std::vector<char> infoLogBuf(infoLogLength + 1);
204             gl.getShaderInfoLog(vShader, (GLsizei)infoLogBuf.size(), NULL, infoLogBuf.data());
205             GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderInfoLog");
206 
207             m_testCtx.getLog() << tcu::TestLog::Message << "Vertex shader build failed.\n"
208                                << "Vertex: " << infoLogBuf.data() << "\n"
209                                << vsSource << "\n"
210                                << tcu::TestLog::EndMessage;
211 
212             gl.deleteShader(vShader);
213             GLU_EXPECT_NO_ERROR(gl.getError(), "deleteShader");
214 
215             TCU_FAIL("Failed to compile transform feedback vertex shader");
216         }
217         gl.attachShader(m_program, vShader);
218         GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader");
219 
220         gl.deleteShader(vShader);
221         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteShader");
222     }
223 
224     if (fsSource)
225     {
226         GLuint fShader = gl.createShader(GL_FRAGMENT_SHADER);
227         gl.shaderSource(fShader, 1, (const char **)&fsSource, NULL);
228         GLU_EXPECT_NO_ERROR(gl.getError(), "shaderSource");
229 
230         gl.compileShader(fShader);
231         GLU_EXPECT_NO_ERROR(gl.getError(), "compileShader");
232 
233         gl.getShaderiv(fShader, GL_COMPILE_STATUS, &status);
234         GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv");
235 
236         if (status == GL_FALSE)
237         {
238             GLint infoLogLength = 0;
239             gl.getShaderiv(fShader, GL_INFO_LOG_LENGTH, &infoLogLength);
240             GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv");
241 
242             std::vector<char> infoLogBuf(infoLogLength + 1);
243             gl.getShaderInfoLog(fShader, (GLsizei)infoLogBuf.size(), NULL, &infoLogBuf[0]);
244             GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderInfoLog");
245 
246             m_testCtx.getLog() << tcu::TestLog::Message << "Fragment shader build failed.\n"
247                                << "Fragment: " << infoLogBuf.data() << "\n"
248                                << fsSource << "\n"
249                                << tcu::TestLog::EndMessage;
250 
251             gl.deleteShader(fShader);
252             GLU_EXPECT_NO_ERROR(gl.getError(), "deleteShader");
253 
254             TCU_FAIL("Failed to compile transform feedback fragment shader");
255         }
256         gl.attachShader(m_program, fShader);
257         GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader");
258 
259         gl.deleteShader(fShader);
260         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteShader");
261     }
262 
263     const char *outputVaryings[] = {"gl_Position"};
264     int varyingcount             = 1;
265 
266     gl.transformFeedbackVaryings(m_program, varyingcount, &outputVaryings[0], GL_SEPARATE_ATTRIBS);
267     GLU_EXPECT_NO_ERROR(gl.getError(), "transformFeedbackVaryings");
268 
269     gl.linkProgram(m_program);
270     GLU_EXPECT_NO_ERROR(gl.getError(), "linkProgram");
271 
272     gl.getProgramiv(m_program, GL_LINK_STATUS, &status);
273     GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
274 
275     if (status == GL_FALSE)
276     {
277         GLint infoLogLength = 0;
278         gl.getProgramiv(m_program, GL_INFO_LOG_LENGTH, &infoLogLength);
279         GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
280 
281         std::vector<char> infoLogBuf(infoLogLength + 1);
282         gl.getProgramInfoLog(m_program, (GLsizei)infoLogBuf.size(), NULL, infoLogBuf.data());
283         GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramInfoLog");
284 
285         m_testCtx.getLog() << tcu::TestLog::Message << "Fragment shader build failed.\n"
286                            << "link log: " << infoLogBuf.data() << "\n"
287                            << tcu::TestLog::EndMessage;
288 
289         TCU_FAIL("Failed to link transform feedback program");
290     }
291 
292     gl.useProgram(m_program);
293     GLU_EXPECT_NO_ERROR(gl.getError(), "useProgram");
294 }
295 
296 /** Executes test iteration.
297  *
298  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
299  */
iterate()300 tcu::TestNode::IterateResult TransformFeedbackStatesTestCase::iterate()
301 {
302     if (!m_testSupported)
303     {
304         throw tcu::NotSupportedError("transform_feedback2 is not supported");
305         return STOP;
306     }
307 
308     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
309     bool ret                 = true;
310 
311     /* setup shader program */
312     std::string vshader = tcu::StringTemplate(m_shader_vert).specialize(specializationMap);
313     std::string fshader = tcu::StringTemplate(m_shader_frag).specialize(specializationMap);
314 
315     {
316         ProgramSources sources;
317         sources.sources[SHADERTYPE_VERTEX].push_back(vshader);
318         sources.sources[SHADERTYPE_FRAGMENT].push_back(fshader);
319 
320         ShaderProgram checker_program(gl, sources);
321 
322         if (!checker_program.isOk())
323         {
324             m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n"
325                                << "Vertex: " << checker_program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
326                                << checker_program.getShader(SHADERTYPE_VERTEX)->getSource() << "\n"
327                                << "Fragment: " << checker_program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
328                                << checker_program.getShader(SHADERTYPE_FRAGMENT)->getSource() << "\n"
329                                << "Program: " << checker_program.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
330             TCU_FAIL("Compile failed");
331         }
332     }
333 
334     // fragment shader needed for GLES program linking
335     buildTransformFeedbackProgram(vshader.c_str(), m_isContextES ? fshader.c_str() : nullptr);
336 
337     GLuint queryresults[2] = {0, 0};
338     GLint bbinding         = 0;
339     GLint64 bsize = 0, bstart = 0;
340 
341     /* Create and bind a user transform feedback object with
342         GenTransformFeedbacks and BindTransformFeedback and ensure the test
343         runs correctly. Delete the user transform buffer object.
344 
345       * Create multiple user transform feedback objects and configure different
346         state in each object. The state tested should be the following:
347 
348         TRANSFORM_FEEDBACK_BUFFER_BINDING
349         TRANSFORM_FEEDBACK_BUFFER_START
350         TRANSFORM_FEEDBACK_BUFFER_SIZE
351     */
352     gl.genTransformFeedbacks(1, &m_tf_id);
353     GLU_EXPECT_NO_ERROR(gl.getError(), "genTransformFeedbacks");
354 
355     gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_tf_id);
356     GLU_EXPECT_NO_ERROR(gl.getError(), "bindTransformFeedback");
357 
358     gl.genBuffers(2, m_buffers);
359     GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers");
360 
361     gl.bindBuffer(GL_ARRAY_BUFFER, m_buffers[0]);
362     GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
363 
364     gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertices), NULL, GL_STATIC_DRAW);
365     GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
366 
367     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffers[0]);
368     GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferBase");
369 
370     gl.bindBuffer(GL_ARRAY_BUFFER, m_buffers[1]);
371     GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
372 
373     gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
374     GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
375 
376     /*Test*/
377     gl.getIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &bbinding);
378     GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv");
379 
380     if (m_isContextES)
381     {
382         gl.getInteger64i_v(GL_TRANSFORM_FEEDBACK_BUFFER_START, 0, &bstart);
383         GLU_EXPECT_NO_ERROR(gl.getError(), "getInteger64i_v");
384 
385         gl.getInteger64i_v(GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, 0, &bsize);
386         GLU_EXPECT_NO_ERROR(gl.getError(), "getInteger64i_v");
387     }
388     else
389     {
390         gl.getTransformFeedbacki64_v(m_tf_id, GL_TRANSFORM_FEEDBACK_BUFFER_START, 0, &bstart);
391         GLU_EXPECT_NO_ERROR(gl.getError(), "getTransformFeedbacki64_v");
392 
393         gl.getTransformFeedbacki64_v(m_tf_id, GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, 0, &bsize);
394         GLU_EXPECT_NO_ERROR(gl.getError(), "getTransformFeedbacki64_v");
395     }
396 
397     if (bbinding >= 0 && ((GLuint)bbinding != m_tf_id) && (bstart != 0) && (bsize != sizeof(vertices)))
398     {
399         TCU_FAIL("Unexpected state of transform feedback buffer");
400     }
401 
402     /*
403     * Create two query objects and call BeginQuery(PRIMITIVES_GENERATED) and
404         BeginQuery(TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN), which can be used
405         to determine when feedback is complete.
406     */
407     gl.genQueries(2, m_queries);
408     GLU_EXPECT_NO_ERROR(gl.getError(), "genQueries");
409 
410     if (!m_isContextES)
411     {
412         gl.beginQuery(GL_PRIMITIVES_GENERATED, m_queries[0]);
413         GLU_EXPECT_NO_ERROR(gl.getError(), "beginQuery");
414     }
415 
416     gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_queries[1]);
417     GLU_EXPECT_NO_ERROR(gl.getError(), "beginQuery");
418 
419     ret = draw_simple2(m_program, GL_TRIANGLES, 6, true);
420     if (!ret)
421     {
422         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
423         return STOP;
424     }
425 
426     if (!m_isContextES)
427     {
428         gl.endQuery(GL_PRIMITIVES_GENERATED);
429         GLU_EXPECT_NO_ERROR(gl.getError(), "endQuery");
430     }
431 
432     gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
433     GLU_EXPECT_NO_ERROR(gl.getError(), "endQuery");
434 
435     if (!m_isContextES)
436     {
437         gl.getQueryObjectuiv(m_queries[0], GL_QUERY_RESULT, &queryresults[0]);
438         GLU_EXPECT_NO_ERROR(gl.getError(), "getQueryObjectuiv");
439     }
440 
441     gl.getQueryObjectuiv(m_queries[1], GL_QUERY_RESULT, &queryresults[1]);
442     GLU_EXPECT_NO_ERROR(gl.getError(), "getQueryObjectuiv");
443 
444     if ((!m_isContextES && queryresults[0] != 5) || queryresults[1] != 2)
445     {
446         ret = false;
447 
448         if (!m_isContextES)
449         {
450             m_testCtx.getLog() << tcu::TestLog::Message << "Query result error: " << queryresults[0] << " != 5, "
451                                << queryresults[1] << " != 2" << tcu::TestLog::EndMessage;
452         }
453         else
454         {
455             m_testCtx.getLog() << tcu::TestLog::Message << "Query result error: " << queryresults[1] << " != 2"
456                                << tcu::TestLog::EndMessage;
457         }
458     }
459 
460     if (ret)
461         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
462     else
463         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
464     return STOP;
465 }
466 
467 /* basic drawing function
468  MH-2024.05.10: stripped while porting from kc (GTFTransformFeedback2.c; drawsimple2) to vk-gl due to limited use in one test */
draw_simple2(GLuint program,GLenum primitivetype,GLint vertexcount,bool pauseresume)469 bool TransformFeedbackStatesTestCase::draw_simple2(GLuint program, GLenum primitivetype, GLint vertexcount,
470                                                    bool pauseresume)
471 {
472     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
473 
474     GLint locVertices = gl.getAttribLocation(program, "in_vertex");
475     if (locVertices < 0)
476     {
477         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
478         return false;
479     }
480     GLU_EXPECT_NO_ERROR(gl.getError(), "getAttribLocation");
481 
482     bool result = true;
483 
484     if (!m_isContextES)
485     {
486         gl.genVertexArrays(1, &m_vao);
487         GLU_EXPECT_NO_ERROR(gl.getError(), "genVertexArrays");
488         gl.bindVertexArray(m_vao);
489         GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray");
490     }
491 
492     gl.clearColor(0.1f, 0.0f, 0.0f, 1.0f);
493     GLU_EXPECT_NO_ERROR(gl.getError(), "clearColor");
494     gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
495     GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
496 
497     gl.vertexAttribPointer(locVertices, 4, GL_FLOAT, GL_FALSE, 0, NULL);
498     GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttribPointer");
499     gl.enableVertexAttribArray(locVertices);
500     GLU_EXPECT_NO_ERROR(gl.getError(), "enableVertexAttribArray");
501 
502     gl.beginTransformFeedback(primitivetype);
503     GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
504 
505     if (pauseresume)
506     {
507         /* Query the transform feedback state for TRANSFORM_FEEDBACK_BUFFER_PAUSED
508             and TRANSFORM_FEEDBACK_BUFFER_ACTIVE to verify the state is reflected
509             correctly.
510         */
511         GLboolean paused, active;
512 
513         gl.pauseTransformFeedback();
514         GLU_EXPECT_NO_ERROR(gl.getError(), "pauseTransformFeedback");
515 
516         /* While the transform feedback is paused, verify that drawing with
517            incompatible primitives does not produce an error like it would when
518            transform feedback is not paused.
519         */
520         gl.drawArrays(GL_LINES, 0, vertexcount);
521         GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
522 
523         if (gl.getError() != GL_NO_ERROR)
524         {
525             result = false;
526         }
527 
528         gl.getBooleanv(GL_TRANSFORM_FEEDBACK_PAUSED, &paused);
529         GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv");
530 
531         gl.getBooleanv(GL_TRANSFORM_FEEDBACK_ACTIVE, &active);
532         GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv");
533 
534         if (!paused || !active)
535         {
536             result = false;
537         }
538 
539         gl.resumeTransformFeedback();
540         GLU_EXPECT_NO_ERROR(gl.getError(), "resumeTransformFeedback");
541 
542         gl.getBooleanv(GL_TRANSFORM_FEEDBACK_PAUSED, &paused);
543         GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv");
544 
545         gl.getBooleanv(GL_TRANSFORM_FEEDBACK_ACTIVE, &active);
546         GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv");
547 
548         if (paused || !active)
549         {
550             result = false;
551         }
552     }
553 
554     {
555         /* Draw primitives. For Halti only DrawArrays can be used with transform
556         feedback; it does not support DrawElements with transform feedback. In
557         addition Halti only supports independent primitives (POINTS, LINES and
558         TRIANGLES), no primitive restart interaction and no writing of
559         gl_Position.
560         */
561         gl.drawArrays(primitivetype, 0, vertexcount);
562         GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
563 
564         if (!m_isContextES)
565         {
566             /* For Halti an overflow while writing out to transform feedback buffers
567             generates and GL_INVALID_OPERATION error. Clear out the error
568             in case of an overflow.
569             */
570             gl.getError();
571         }
572     }
573 
574     gl.endTransformFeedback();
575     GLU_EXPECT_NO_ERROR(gl.getError(), "endTransformFeedback");
576 
577     gl.disableVertexAttribArray(locVertices);
578     GLU_EXPECT_NO_ERROR(gl.getError(), "disableVertexAttribArray");
579 
580     if (!m_isContextES)
581     {
582         gl.bindVertexArray(0);
583         GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray");
584     }
585     return result;
586 }
587 
588 /** Constructor.
589  *
590  *  @param context Rendering context.
591  */
TransformFeedbackTests(deqp::Context & context)592 TransformFeedbackTests::TransformFeedbackTests(deqp::Context &context)
593     : TestCaseGroup(context, "transform_feedback2", "Verify conformance of transform_feedback2 functionality")
594 {
595 }
596 
597 /** Initializes the test group contents. */
init()598 void TransformFeedbackTests::init()
599 {
600     addChild(new TransformFeedbackStatesTestCase(m_context));
601 }
602 
603 } // namespace glcts
604