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