1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
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 Object lifetime tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fLifetimeTests.hpp"
25
26 #include "deRandom.hpp"
27 #include "deUniquePtr.hpp"
28 #include "tcuRenderTarget.hpp"
29 #include "tcuSurface.hpp"
30 #include "gluDrawUtil.hpp"
31 #include "gluObjectWrapper.hpp"
32 #include "gluPixelTransfer.hpp"
33 #include "gluShaderProgram.hpp"
34 #include "glsLifetimeTests.hpp"
35 #include "glwEnums.hpp"
36 #include "glwFunctions.hpp"
37
38 #include <vector>
39
40 namespace deqp
41 {
42 namespace gles3
43 {
44 namespace Functional
45 {
46 namespace
47 {
48
49 using de::MovePtr;
50 using de::Random;
51 using glu::Buffer;
52 using glu::CallLogWrapper;
53 using glu::ProgramSources;
54 using glu::RenderContext;
55 using glu::VertexArray;
56 using std::vector;
57 using tcu::RenderTarget;
58 using tcu::Surface;
59 using tcu::TestContext;
60 using tcu::TestLog;
61 namespace lt = gls::LifetimeTests;
62 using namespace lt;
63 using namespace glw;
64 typedef TestCase::IterateResult IterateResult;
65
66 enum
67 {
68 VIEWPORT_SIZE = 128
69 };
70
71 class ScaleProgram : public glu::ShaderProgram
72 {
73 public:
74 ScaleProgram(lt::Context &ctx);
75 void draw(GLuint vao, GLfloat scale, bool tf, Surface *dst);
76 void setPos(GLuint buffer, GLuint vao);
77
78 private:
79 ProgramSources getSources(void);
80
81 const RenderContext &m_renderCtx;
82 GLint m_scaleLoc;
83 GLint m_posLoc;
84 };
85
86 enum
87 {
88 NUM_COMPONENTS = 4,
89 NUM_VERTICES = 3
90 };
91
ScaleProgram(lt::Context & ctx)92 ScaleProgram::ScaleProgram(lt::Context &ctx)
93 : glu::ShaderProgram(ctx.getRenderContext(), getSources())
94 , m_renderCtx(ctx.getRenderContext())
95 {
96 const Functions &gl = m_renderCtx.getFunctions();
97 TCU_CHECK(isOk());
98 m_scaleLoc = gl.getUniformLocation(getProgram(), "scale");
99 m_posLoc = gl.getAttribLocation(getProgram(), "pos");
100 }
101
102 #define GLSL(VERSION, BODY) ("#version " #VERSION "\n" #BODY "\n")
103
104 static const char *const s_vertexShaderSrc = GLSL(
105 100, attribute vec4 pos; uniform float scale; void main() { gl_Position = vec4(scale * pos.xy, pos.zw); });
106
107 static const char *const s_fragmentShaderSrc = GLSL(
108 100, void main() { gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0); });
109
getSources(void)110 ProgramSources ScaleProgram::getSources(void)
111 {
112 using namespace glu;
113 ProgramSources sources;
114 sources << VertexSource(s_vertexShaderSrc) << FragmentSource(s_fragmentShaderSrc)
115 << TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS) << TransformFeedbackVarying("gl_Position");
116 return sources;
117 }
118
draw(GLuint vao,GLfloat scale,bool tf,Surface * dst)119 void ScaleProgram::draw(GLuint vao, GLfloat scale, bool tf, Surface *dst)
120 {
121 const Functions &gl = m_renderCtx.getFunctions();
122 de::Random rnd(vao);
123 Rectangle viewport = randomViewport(m_renderCtx, VIEWPORT_SIZE, VIEWPORT_SIZE, rnd);
124 setViewport(m_renderCtx, viewport);
125 gl.clearColor(0, 0, 0, 1);
126 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
127
128 gl.bindVertexArray(vao);
129 gl.enableVertexAttribArray(m_posLoc);
130 GLU_CHECK_CALL_ERROR(gl.useProgram(getProgram()), gl.getError());
131
132 gl.uniform1f(m_scaleLoc, scale);
133
134 if (tf)
135 gl.beginTransformFeedback(GL_TRIANGLES);
136 GLU_CHECK_CALL_ERROR(gl.drawArrays(GL_TRIANGLES, 0, 3), gl.getError());
137 if (tf)
138 gl.endTransformFeedback();
139
140 if (dst != DE_NULL)
141 readRectangle(m_renderCtx, viewport, *dst);
142
143 gl.bindVertexArray(0);
144 }
145
setPos(GLuint buffer,GLuint vao)146 void ScaleProgram::setPos(GLuint buffer, GLuint vao)
147 {
148 const Functions &gl = m_renderCtx.getFunctions();
149
150 gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
151 gl.bindVertexArray(vao);
152 GLU_CHECK_CALL_ERROR(gl.vertexAttribPointer(m_posLoc, NUM_COMPONENTS, GL_FLOAT, false, 0, DE_NULL), gl.getError());
153 gl.bindVertexArray(0);
154 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
155 GLU_CHECK_ERROR(gl.getError());
156 }
157
158 class VertexArrayBinder : public SimpleBinder
159 {
160 public:
VertexArrayBinder(lt::Context & ctx)161 VertexArrayBinder(lt::Context &ctx) : SimpleBinder(ctx, 0, GL_NONE, GL_VERTEX_ARRAY_BINDING, true)
162 {
163 }
bind(GLuint name)164 void bind(GLuint name)
165 {
166 glBindVertexArray(name);
167 }
168 };
169
170 class SamplerBinder : public Binder
171 {
172 public:
SamplerBinder(lt::Context & ctx)173 SamplerBinder(lt::Context &ctx) : Binder(ctx)
174 {
175 }
bind(GLuint name)176 void bind(GLuint name)
177 {
178 glBindSampler(0, name);
179 }
getBinding(void)180 GLuint getBinding(void)
181 {
182 GLint arr[32] = {};
183 glGetIntegerv(GL_SAMPLER_BINDING, arr);
184 log() << TestLog::Message << "// First output integer: " << arr[0] << TestLog::EndMessage;
185 return arr[0];
186 }
genRequired(void) const187 bool genRequired(void) const
188 {
189 return true;
190 }
191 };
192
193 class QueryBinder : public Binder
194 {
195 public:
QueryBinder(lt::Context & ctx)196 QueryBinder(lt::Context &ctx) : Binder(ctx)
197 {
198 }
bind(GLuint name)199 void bind(GLuint name)
200 {
201 if (name != 0)
202 glBeginQuery(GL_ANY_SAMPLES_PASSED, name);
203 else
204 glEndQuery(GL_ANY_SAMPLES_PASSED);
205 }
getBinding(void)206 GLuint getBinding(void)
207 {
208 return 0;
209 }
210 };
211
212 class BufferVAOAttacher : public Attacher
213 {
214 public:
BufferVAOAttacher(lt::Context & ctx,Type & elementType,Type & varrType,ScaleProgram & program)215 BufferVAOAttacher(lt::Context &ctx, Type &elementType, Type &varrType, ScaleProgram &program)
216 : Attacher(ctx, elementType, varrType)
217 , m_program(program)
218 {
219 }
220 void initAttachment(GLuint seed, GLuint element);
221 void attach(GLuint element, GLuint container);
222 void detach(GLuint element, GLuint container);
canAttachDeleted(void) const223 bool canAttachDeleted(void) const
224 {
225 return false;
226 }
getProgram(void)227 ScaleProgram &getProgram(void)
228 {
229 return m_program;
230 }
231 GLuint getAttachment(GLuint container);
232
233 private:
234 ScaleProgram &m_program;
235 };
236
237 static const GLfloat s_varrData[NUM_VERTICES * NUM_COMPONENTS] = {-1.0, 0.0, 0.0, 1.0, 1.0, 1.0,
238 0.0, 1.0, 0.0, -1.0, 0.0, 1.0};
239
initBuffer(const Functions & gl,GLuint seed,GLenum usage,GLuint buffer)240 void initBuffer(const Functions &gl, GLuint seed, GLenum usage, GLuint buffer)
241 {
242 gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
243 if (seed == 0)
244 gl.bufferData(GL_ARRAY_BUFFER, sizeof(s_varrData), s_varrData, usage);
245 else
246 {
247 Random rnd(seed);
248 GLfloat data[DE_LENGTH_OF_ARRAY(s_varrData)];
249
250 for (int ndx = 0; ndx < NUM_VERTICES; ndx++)
251 {
252 GLfloat *vertex = &data[ndx * NUM_COMPONENTS];
253 vertex[0] = 2.0f * (rnd.getFloat() - 0.5f);
254 vertex[1] = 2.0f * (rnd.getFloat() - 0.5f);
255 DE_STATIC_ASSERT(NUM_COMPONENTS == 4);
256 vertex[2] = 0.0f;
257 vertex[3] = 1.0f;
258 }
259 gl.bufferData(GL_ARRAY_BUFFER, sizeof(data), data, usage);
260 }
261 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
262 GLU_CHECK_ERROR(gl.getError());
263 }
264
initAttachment(GLuint seed,GLuint buffer)265 void BufferVAOAttacher::initAttachment(GLuint seed, GLuint buffer)
266 {
267 initBuffer(gl(), seed, GL_STATIC_DRAW, buffer);
268 log() << TestLog::Message << "// Initialized buffer " << buffer << " from seed " << seed << TestLog::EndMessage;
269 }
270
attach(GLuint buffer,GLuint vao)271 void BufferVAOAttacher::attach(GLuint buffer, GLuint vao)
272 {
273 m_program.setPos(buffer, vao);
274 log() << TestLog::Message << "// Set the `pos` attribute in VAO " << vao << " to buffer " << buffer
275 << TestLog::EndMessage;
276 }
277
detach(GLuint buffer,GLuint varr)278 void BufferVAOAttacher::detach(GLuint buffer, GLuint varr)
279 {
280 DE_UNREF(buffer);
281 attach(0, varr);
282 }
283
getAttachment(GLuint varr)284 GLuint BufferVAOAttacher::getAttachment(GLuint varr)
285 {
286 GLint name = 0;
287 gl().bindVertexArray(varr);
288 gl().getVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &name);
289 gl().bindVertexArray(0);
290 GLU_CHECK_ERROR(gl().getError());
291 return GLuint(name);
292 }
293
294 class BufferVAOInputAttacher : public InputAttacher
295 {
296 public:
BufferVAOInputAttacher(BufferVAOAttacher & attacher)297 BufferVAOInputAttacher(BufferVAOAttacher &attacher) : InputAttacher(attacher), m_program(attacher.getProgram())
298 {
299 }
300 void drawContainer(GLuint container, Surface &dst);
301
302 private:
303 ScaleProgram &m_program;
304 };
305
drawContainer(GLuint vao,Surface & dst)306 void BufferVAOInputAttacher::drawContainer(GLuint vao, Surface &dst)
307 {
308 m_program.draw(vao, 1.0, false, &dst);
309 log() << TestLog::Message << "// Drew an output image with VAO " << vao << TestLog::EndMessage;
310 }
311
312 class BufferTfAttacher : public Attacher
313 {
314 public:
BufferTfAttacher(lt::Context & ctx,Type & bufferType,Type & tfType)315 BufferTfAttacher(lt::Context &ctx, Type &bufferType, Type &tfType) : Attacher(ctx, bufferType, tfType)
316 {
317 }
318 void initAttachment(GLuint seed, GLuint element);
319 void attach(GLuint buffer, GLuint tf);
320 void detach(GLuint buffer, GLuint tf);
canAttachDeleted(void) const321 bool canAttachDeleted(void) const
322 {
323 return false;
324 }
325 GLuint getAttachment(GLuint tf);
326 };
327
initAttachment(GLuint seed,GLuint buffer)328 void BufferTfAttacher::initAttachment(GLuint seed, GLuint buffer)
329 {
330 initBuffer(gl(), seed, GL_DYNAMIC_READ, buffer);
331 log() << TestLog::Message << "// Initialized buffer " << buffer << " from seed " << seed << TestLog::EndMessage;
332 }
333
attach(GLuint buffer,GLuint tf)334 void BufferTfAttacher::attach(GLuint buffer, GLuint tf)
335 {
336 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf);
337 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer);
338 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
339 GLU_CHECK_ERROR(gl().getError());
340 }
341
detach(GLuint buffer,GLuint tf)342 void BufferTfAttacher::detach(GLuint buffer, GLuint tf)
343 {
344 DE_UNREF(buffer);
345 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf);
346 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
347 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
348 GLU_CHECK_ERROR(gl().getError());
349 }
350
getAttachment(GLuint tf)351 GLuint BufferTfAttacher::getAttachment(GLuint tf)
352 {
353 GLint ret = 0;
354 gl().bindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf);
355 gl().getIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &ret);
356 gl().bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
357 GLU_CHECK_ERROR(gl().getError());
358 return GLuint(ret);
359 }
360
361 class BufferTfOutputAttacher : public OutputAttacher
362 {
363 public:
BufferTfOutputAttacher(BufferTfAttacher & attacher,ScaleProgram & program)364 BufferTfOutputAttacher(BufferTfAttacher &attacher, ScaleProgram &program)
365 : OutputAttacher(attacher)
366 , m_program(program)
367 {
368 }
369 void setupContainer(GLuint seed, GLuint container);
370 void drawAttachment(GLuint attachment, Surface &dst);
371
372 private:
373 ScaleProgram &m_program;
374 };
375
drawAttachment(GLuint buffer,Surface & dst)376 void BufferTfOutputAttacher::drawAttachment(GLuint buffer, Surface &dst)
377 {
378 VertexArray vao(getRenderContext());
379
380 m_program.setPos(buffer, *vao);
381 m_program.draw(*vao, 1.0, false, &dst);
382 log() << TestLog::Message << "// Drew output image with vertices from buffer " << buffer << TestLog::EndMessage;
383 GLU_CHECK_ERROR(gl().getError());
384 }
385
setupContainer(GLuint seed,GLuint tf)386 void BufferTfOutputAttacher::setupContainer(GLuint seed, GLuint tf)
387 {
388 Buffer posBuf(getRenderContext());
389 VertexArray vao(getRenderContext());
390
391 initBuffer(gl(), seed, GL_STATIC_DRAW, *posBuf);
392 m_program.setPos(*posBuf, *vao);
393
394 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf);
395 m_program.draw(*vao, -1.0, true, DE_NULL);
396 log() << TestLog::Message << "// Drew an image with seed " << seed << " with transform feedback to " << tf
397 << TestLog::EndMessage;
398 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
399 GLU_CHECK_ERROR(gl().getError());
400 }
401
402 class ES3Types : public ES2Types
403 {
404 public:
405 ES3Types(lt::Context &ctx);
406
407 private:
408 ScaleProgram m_program;
409 QueryBinder m_queryBind;
410 SimpleType m_queryType;
411 SimpleBinder m_tfBind;
412 SimpleType m_tfType;
413 VertexArrayBinder m_varrBind;
414 SimpleType m_varrType;
415 SamplerBinder m_samplerBind;
416 SimpleType m_samplerType;
417 BufferVAOAttacher m_bufVarrAtt;
418 BufferVAOInputAttacher m_bufVarrInAtt;
419 BufferTfAttacher m_bufTfAtt;
420 BufferTfOutputAttacher m_bufTfOutAtt;
421 };
422
ES3Types(lt::Context & ctx)423 ES3Types::ES3Types(lt::Context &ctx)
424 : ES2Types(ctx)
425 , m_program(ctx)
426 , m_queryBind(ctx)
427 , m_queryType(ctx, "query", &CallLogWrapper::glGenQueries, &CallLogWrapper::glDeleteQueries,
428 &CallLogWrapper::glIsQuery, &m_queryBind)
429 , m_tfBind(ctx, &CallLogWrapper::glBindTransformFeedback, GL_TRANSFORM_FEEDBACK, GL_TRANSFORM_FEEDBACK_BINDING,
430 true)
431 , m_tfType(ctx, "transform_feedback", &CallLogWrapper::glGenTransformFeedbacks,
432 &CallLogWrapper::glDeleteTransformFeedbacks, &CallLogWrapper::glIsTransformFeedback, &m_tfBind)
433 , m_varrBind(ctx)
434 , m_varrType(ctx, "vertex_array", &CallLogWrapper::glGenVertexArrays, &CallLogWrapper::glDeleteVertexArrays,
435 &CallLogWrapper::glIsVertexArray, &m_varrBind)
436 , m_samplerBind(ctx)
437 , m_samplerType(ctx, "sampler", &CallLogWrapper::glGenSamplers, &CallLogWrapper::glDeleteSamplers,
438 &CallLogWrapper::glIsSampler, &m_samplerBind, true)
439 , m_bufVarrAtt(ctx, m_bufferType, m_varrType, m_program)
440 , m_bufVarrInAtt(m_bufVarrAtt)
441 , m_bufTfAtt(ctx, m_bufferType, m_tfType)
442 , m_bufTfOutAtt(m_bufTfAtt, m_program)
443 {
444 Type *types[] = {&m_queryType, &m_tfType, &m_varrType, &m_samplerType};
445 m_types.insert(m_types.end(), DE_ARRAY_BEGIN(types), DE_ARRAY_END(types));
446
447 m_attachers.push_back(&m_bufVarrAtt);
448 m_attachers.push_back(&m_bufTfAtt);
449
450 m_inAttachers.push_back(&m_bufVarrInAtt);
451 m_outAttachers.push_back(&m_bufTfOutAtt);
452 }
453
454 class TfDeleteActiveTest : public TestCase, private CallLogWrapper
455 {
456 public:
457 TfDeleteActiveTest(gles3::Context &context, const char *name, const char *description);
458 IterateResult iterate(void);
459 };
460
TfDeleteActiveTest(gles3::Context & context,const char * name,const char * description)461 TfDeleteActiveTest::TfDeleteActiveTest(gles3::Context &context, const char *name, const char *description)
462 : TestCase(context, name, description)
463 , CallLogWrapper(context.getRenderContext().getFunctions(), context.getTestContext().getLog())
464 {
465 enableLogging(true);
466 }
467
468 class ScopedTransformFeedbackFeedback
469 {
470 public:
471 ScopedTransformFeedbackFeedback(glu::CallLogWrapper &gl, GLenum type);
472 ~ScopedTransformFeedbackFeedback(void);
473
474 private:
475 glu::CallLogWrapper &m_gl;
476 };
477
ScopedTransformFeedbackFeedback(glu::CallLogWrapper & gl,GLenum type)478 ScopedTransformFeedbackFeedback::ScopedTransformFeedbackFeedback(glu::CallLogWrapper &gl, GLenum type) : m_gl(gl)
479 {
480 m_gl.glBeginTransformFeedback(type);
481 GLU_EXPECT_NO_ERROR(m_gl.glGetError(), "glBeginTransformFeedback");
482 }
483
~ScopedTransformFeedbackFeedback(void)484 ScopedTransformFeedbackFeedback::~ScopedTransformFeedbackFeedback(void)
485 {
486 m_gl.glEndTransformFeedback();
487 }
488
iterate(void)489 IterateResult TfDeleteActiveTest::iterate(void)
490 {
491 static const char *const s_xfbVertexSource =
492 "#version 300 es\n"
493 "void main ()\n"
494 "{\n"
495 " gl_Position = vec4(float(gl_VertexID) / 2.0, float(gl_VertexID % 2) / 2.0, 0.0, 1.0);\n"
496 "}\n";
497 static const char *const s_xfbFragmentSource = "#version 300 es\n"
498 "layout(location=0) out mediump vec4 dEQP_FragColor;\n"
499 "void main ()\n"
500 "{\n"
501 " dEQP_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
502 "}\n";
503
504 glu::Buffer buf(m_context.getRenderContext());
505 GLuint tf = 0;
506 glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources()
507 << glu::VertexSource(s_xfbVertexSource)
508 << glu::FragmentSource(s_xfbFragmentSource)
509 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS)
510 << glu::TransformFeedbackVarying("gl_Position"));
511
512 if (!program.isOk())
513 {
514 m_testCtx.getLog() << program;
515 throw tcu::TestError("failed to build program");
516 }
517
518 try
519 {
520 GLU_CHECK_CALL(glUseProgram(program.getProgram()));
521 GLU_CHECK_CALL(glGenTransformFeedbacks(1, &tf));
522 GLU_CHECK_CALL(glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf));
523 GLU_CHECK_CALL(glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, *buf));
524 GLU_CHECK_CALL(
525 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 3 * sizeof(glw::GLfloat[4]), DE_NULL, GL_DYNAMIC_COPY));
526
527 {
528 ScopedTransformFeedbackFeedback xfb(static_cast<glu::CallLogWrapper &>(*this), GL_TRIANGLES);
529
530 glDeleteTransformFeedbacks(1, &tf);
531 {
532 GLenum err = glGetError();
533 if (err != GL_INVALID_OPERATION)
534 getTestContext().setTestResult(
535 QP_TEST_RESULT_FAIL, "Deleting active transform feedback did not produce GL_INVALID_OPERATION");
536 else
537 getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
538 }
539 }
540 GLU_CHECK(); // ScopedTransformFeedbackFeedback::dtor might modify error state
541
542 GLU_CHECK_CALL(glDeleteTransformFeedbacks(1, &tf));
543 }
544 catch (const glu::Error &)
545 {
546 glDeleteTransformFeedbacks(1, &tf);
547 throw;
548 }
549
550 return STOP;
551 }
552
553 class TestGroup : public TestCaseGroup
554 {
555 public:
TestGroup(gles3::Context & context)556 TestGroup(gles3::Context &context) : TestCaseGroup(context, "lifetime", "Object lifetime tests")
557 {
558 }
559 void init(void);
560
561 private:
562 MovePtr<Types> m_types;
563 };
564
init(void)565 void TestGroup::init(void)
566 {
567 gles3::Context &ctx = getContext();
568 lt::Context ltCtx(ctx.getRenderContext(), ctx.getTestContext());
569
570 m_types = MovePtr<Types>(new ES3Types(ltCtx));
571
572 addTestCases(*this, *m_types);
573
574 TestCaseGroup *deleteActiveGroup = new TestCaseGroup(ctx, "delete_active", "Delete active object");
575 addChild(deleteActiveGroup);
576 deleteActiveGroup->addChild(new TfDeleteActiveTest(ctx, "transform_feedback", "Transform Feedback"));
577 }
578
579 } // namespace
580
createLifetimeTests(Context & context)581 TestCaseGroup *createLifetimeTests(Context &context)
582 {
583 return new TestGroup(context);
584 }
585
586 } // namespace Functional
587 } // namespace gles3
588 } // namespace deqp
589