Home | History | Annotate | Download | only in functional
      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 
     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 
    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 
    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 
    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:
    172 						VertexArrayBinder	(lt::Context& ctx)
    173 							: SimpleBinder	(ctx, 0, GL_NONE, GL_VERTEX_ARRAY_BINDING, true) {}
    174 	void				bind			(GLuint name) { glBindVertexArray(name); }
    175 };
    176 
    177 class SamplerBinder : public Binder
    178 {
    179 public:
    180 						SamplerBinder	(lt::Context& ctx) : Binder(ctx) {}
    181 	void				bind			(GLuint name) { glBindSampler(0, name); }
    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 	}
    190 	bool				genRequired		(void) const { return true; }
    191 };
    192 
    193 class QueryBinder : public Binder
    194 {
    195 public:
    196 						QueryBinder		(lt::Context& ctx) : Binder(ctx) {}
    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 	}
    204 	GLuint				getBinding		(void) { return 0; }
    205 };
    206 
    207 class BufferVAOAttacher : public Attacher
    208 {
    209 public:
    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);
    217 	bool				canAttachDeleted	(void) const { return false; }
    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 
    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 
    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 
    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 
    272 void BufferVAOAttacher::detach (GLuint buffer, GLuint varr)
    273 {
    274 	DE_UNREF(buffer);
    275 	attach(0, varr);
    276 }
    277 
    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:
    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 
    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:
    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);
    315 	bool		canAttachDeleted	(void) const { return false; }
    316 	GLuint		getAttachment		(GLuint tf);
    317 };
    318 
    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 
    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 
    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 
    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:
    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 
    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 
    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 
    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 
    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 
    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 
    484 ScopedTransformFeedbackFeedback::~ScopedTransformFeedbackFeedback (void)
    485 {
    486 	m_gl.glEndTransformFeedback();
    487 }
    488 
    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:
    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 
    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 
    582 TestCaseGroup* createLifetimeTests (Context& context)
    583 {
    584 	return new TestGroup(context);
    585 }
    586 
    587 } // Functional
    588 } // gles3
    589 } // deqp
    590