• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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