Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.1 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 Framebuffer without attachments (GL_ARB_framebuffer_no_attachments) tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fFboNoAttachmentTests.hpp"
     25 
     26 #include "glwDefs.hpp"
     27 #include "glwEnums.hpp"
     28 #include "glwFunctions.hpp"
     29 
     30 #include "gluRenderContext.hpp"
     31 #include "gluDefs.hpp"
     32 #include "gluShaderProgram.hpp"
     33 
     34 #include "tcuTestContext.hpp"
     35 #include "tcuVectorType.hpp"
     36 #include "tcuVectorUtil.hpp"
     37 #include "tcuTestLog.hpp"
     38 #include "tcuCommandLine.hpp"
     39 
     40 #include "deMemory.h"
     41 #include "deRandom.hpp"
     42 #include "deString.h"
     43 #include "deStringUtil.hpp"
     44 
     45 #include <string>
     46 #include <vector>
     47 
     48 namespace deqp
     49 {
     50 namespace gles31
     51 {
     52 namespace Functional
     53 {
     54 namespace
     55 {
     56 
     57 using namespace glw;
     58 
     59 using tcu::IVec2;
     60 using tcu::TestLog;
     61 
     62 using std::stringstream;
     63 using std::string;
     64 using std::vector;
     65 
     66 bool checkFramebufferSize (TestLog& log, const glu::RenderContext& renderCtx, GLuint framebuffer, const IVec2& size)
     67 {
     68 	const glw::Functions&		gl				= renderCtx.getFunctions();
     69 
     70 	const char* const			vertexSource	= "#version 310 es\n"
     71 												  "in layout(location = 0) highp vec2 a_position;\n\n"
     72 												  "void main()\n"
     73 												  "{\n"
     74 												  "	gl_Position = vec4(a_position, 0.0, 1.0);\n"
     75 												  "}\n";
     76 
     77 	const char* const			fragmentSource	= "#version 310 es\n"
     78 												  "uniform layout(location = 0) highp ivec2 u_expectedSize;\n"
     79 												  "out layout(location = 0) mediump vec4 f_color;\n\n"
     80 												  "void main()\n"
     81 												  "{\n"
     82 												  "	if (ivec2(gl_FragCoord.xy) != u_expectedSize) discard;\n"
     83 												  "	f_color = vec4(1.0, 0.5, 0.25, 1.0);\n"
     84 												  "}\n";
     85 
     86 	const glu::ShaderProgram	program			(renderCtx, glu::makeVtxFragSources(vertexSource, fragmentSource));
     87 	GLuint						query			= 0;
     88 	GLuint						insidePassed	= 0;
     89 	GLuint						outsideXPassed	= 0;
     90 	GLuint						outsideYPassed	= 0;
     91 
     92 	if (!program.isOk())
     93 		log << program;
     94 
     95 	TCU_CHECK(program.isOk());
     96 
     97 	gl.useProgram(program.getProgram());
     98 	gl.enable(GL_DEPTH_TEST);
     99 	gl.depthFunc(GL_ALWAYS);
    100 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
    101 	gl.viewport(0, 0, size.x()*2, size.y()*2); // Oversized viewport so that it will not accidentally limit us to the correct size
    102 
    103 	log << TestLog::Message << "Using " << size.x()*2 << "x" << size.y()*2 << " viewport" << TestLog::EndMessage;
    104 	log << TestLog::Message << "Discarding fragments outside pixel of interest" << TestLog::EndMessage;
    105 	log << TestLog::Message << "Using occlusion query to check for rendered fragments" << TestLog::EndMessage;
    106 
    107 	TCU_CHECK(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    108 
    109 	// Render
    110 	{
    111 		const float data[] =
    112 		{
    113 			 1.0f,  1.0f,
    114 			 1.0f, -1.0f,
    115 			-1.0f,  1.0f,
    116 			-1.0f,  1.0f,
    117 			 1.0f, -1.0f,
    118 			-1.0f, -1.0f,
    119 		};
    120 
    121 		GLuint vertexArray	= 0;
    122 		GLuint vertexBuffer	= 0;
    123 
    124 		gl.genQueries(1, &query);
    125 		gl.genVertexArrays(1, &vertexArray);
    126 		gl.bindVertexArray(vertexArray);
    127 
    128 		gl.genBuffers(1, &vertexBuffer);
    129 		gl.bindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    130 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
    131 
    132 		gl.enableVertexAttribArray(0);
    133 		gl.vertexAttribPointer(0, 2, GL_FLOAT, false, 0, DE_NULL);
    134 
    135 		gl.uniform2i(0, size.x()-1, size.y()-1);
    136 		gl.beginQuery(GL_ANY_SAMPLES_PASSED, query);
    137 		gl.drawArrays(GL_TRIANGLES, 0, 6);
    138 		gl.endQuery(GL_ANY_SAMPLES_PASSED);
    139 		gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &insidePassed);
    140 		log << TestLog::Message << "A fragment was not discarded at (" << size.x()-1 << ", " << size.y()-1 << "). "
    141 			<< "Occlusion query reports it was " << (insidePassed > 0 ? "rendered." : "not rendered") << TestLog::EndMessage;
    142 
    143 		gl.uniform2i(0, size.x(), size.y()-1);
    144 		gl.beginQuery(GL_ANY_SAMPLES_PASSED, query);
    145 		gl.drawArrays(GL_TRIANGLES, 0, 6);
    146 		gl.endQuery(GL_ANY_SAMPLES_PASSED);
    147 		gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &outsideXPassed);
    148 		log << TestLog::Message << "A fragment was not discarded at (" << size.x() << ", " << size.y()-1 << "). "
    149 			<< "Occlusion query reports it was " << (outsideXPassed > 0 ? "rendered." : "not rendered") << TestLog::EndMessage;
    150 
    151 		gl.uniform2i(0, size.x()-1, size.y());
    152 		gl.beginQuery(GL_ANY_SAMPLES_PASSED, query);
    153 		gl.drawArrays(GL_TRIANGLES, 0, 6);
    154 		gl.endQuery(GL_ANY_SAMPLES_PASSED);
    155 		gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &outsideYPassed);
    156 		log << TestLog::Message << "A fragment was not discarded at (" << size.x()-1 << ", " << size.y() << "). "
    157 			<< "Occlusion query reports it was " << (outsideYPassed > 0 ? "rendered." : "not rendered") << TestLog::EndMessage;
    158 
    159 		gl.disableVertexAttribArray(0);
    160 		gl.bindBuffer(GL_ARRAY_BUFFER, 0);
    161 		gl.bindVertexArray(0);
    162 		gl.deleteBuffers(1, &vertexBuffer);
    163 		gl.deleteVertexArrays(1, &vertexArray);
    164 	}
    165 
    166 	gl.deleteQueries(1, &query);
    167 
    168 	GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed");
    169 
    170 	return insidePassed && !outsideXPassed && !outsideYPassed;
    171 }
    172 
    173 bool checkFramebufferRenderable (TestLog& log, const glu::RenderContext& renderCtx, GLuint framebuffer, const IVec2& size)
    174 {
    175 	const glw::Functions&		gl				= renderCtx.getFunctions();
    176 
    177 	const char* const			vertexSource	= "#version 310 es\n"
    178 												  "in layout(location = 0) highp vec2 a_position;\n\n"
    179 												  "void main()\n"
    180 												  "{\n"
    181 												  "	gl_Position = vec4(a_position, 0.0, 1.0);\n"
    182 												  "}\n";
    183 
    184 	const char* const			fragmentSource	= "#version 310 es\n"
    185 												  "out layout(location = 0) mediump vec4 f_color;\n\n"
    186 												  "void main()\n"
    187 												  "{\n"
    188 												  "	f_color = vec4(1.0, 0.5, 0.25, 1.0);\n"
    189 												  "}\n";
    190 
    191 	const glu::ShaderProgram	program			(renderCtx, glu::makeVtxFragSources(vertexSource, fragmentSource));
    192 	GLuint						query			= 0;
    193 
    194 	if (!program.isOk())
    195 		log << program;
    196 
    197 	TCU_CHECK(program.isOk());
    198 
    199 	gl.useProgram(program.getProgram());
    200 	gl.enable(GL_DEPTH_TEST);
    201 	gl.depthFunc(GL_ALWAYS);
    202 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
    203 	gl.viewport(0, 0, size.x(), size.y());
    204 
    205 	TCU_CHECK(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    206 
    207 	log << TestLog::Message << "Rendering full framebuffer quad with color ouput, verifying output presence with occlusion query" << TestLog::EndMessage;
    208 
    209 	// Render
    210 	{
    211 		const float data[] =
    212 		{
    213 			 1.0f,  1.0f,
    214 			 1.0f, -1.0f,
    215 			-1.0f,  1.0f,
    216 			-1.0f,  1.0f,
    217 			 1.0f, -1.0f,
    218 			-1.0f, -1.0f,
    219 		};
    220 
    221 		GLuint vertexArray	= 0;
    222 		GLuint vertexBuffer	= 0;
    223 
    224 		gl.genQueries(1, &query);
    225 		gl.genVertexArrays(1, &vertexArray);
    226 		gl.bindVertexArray(vertexArray);
    227 
    228 		gl.genBuffers(1, &vertexBuffer);
    229 		gl.bindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    230 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
    231 
    232 		gl.enableVertexAttribArray(0);
    233 		gl.vertexAttribPointer(0, 2, GL_FLOAT, false, 0, DE_NULL);
    234 
    235 		gl.beginQuery(GL_ANY_SAMPLES_PASSED, query);
    236 		gl.drawArrays(GL_TRIANGLES, 0, 6);
    237 		gl.endQuery(GL_ANY_SAMPLES_PASSED);
    238 
    239 		gl.disableVertexAttribArray(0);
    240 		gl.bindBuffer(GL_ARRAY_BUFFER, 0);
    241 		gl.bindVertexArray(0);
    242 		gl.deleteBuffers(1, &vertexBuffer);
    243 		gl.deleteVertexArrays(1, &vertexArray);
    244 	}
    245 
    246 	// Read
    247 	{
    248 		GLuint passed = 0;
    249 
    250 		gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &passed);
    251 		gl.deleteQueries(1, &query);
    252 
    253 		GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed");
    254 
    255 		if (passed)
    256 			log << TestLog::Message << "Query passed" << TestLog::EndMessage;
    257 		else
    258 			log << TestLog::Message << "Query did not pass" << TestLog::EndMessage;
    259 
    260 		return passed != 0;
    261 	}
    262 }
    263 
    264 class FramebufferCompletenessCase : public tcu::TestCase
    265 {
    266 public:
    267 								FramebufferCompletenessCase		(tcu::TestContext&			testCtx,
    268 																 const glu::RenderContext&	renderCtx,
    269 																 const char*				name,
    270 																 const char*				desc);
    271 	virtual						~FramebufferCompletenessCase	 (void) {}
    272 	virtual IterateResult		iterate							(void);
    273 
    274 private:
    275 	const glu::RenderContext&	m_renderCtx;
    276 	tcu::ResultCollector		m_results;
    277 };
    278 
    279 FramebufferCompletenessCase::FramebufferCompletenessCase (tcu::TestContext&			testCtx,
    280 														  const glu::RenderContext&	renderCtx,
    281 														  const char*				name,
    282 														  const char*				desc)
    283 	: TestCase		(testCtx, name, desc)
    284 	, m_renderCtx	(renderCtx)
    285 {
    286 }
    287 
    288 FramebufferCompletenessCase::IterateResult FramebufferCompletenessCase::iterate (void)
    289 {
    290 	const glw::Functions&	gl			= m_renderCtx.getFunctions();
    291 	GLuint					framebuffer	= 0;
    292 
    293 	gl.genFramebuffers(1, &framebuffer);
    294 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
    295 
    296 	m_results.check(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "Framebuffer was incorrectly reported as complete when it had no width, height or attachments");
    297 
    298 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 16);
    299 	m_results.check(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "Framebuffer was incorrectly reported as complete when it only had a width");
    300 
    301 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 16);
    302 	m_results.check(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Framebuffer not reported as complete when it had width and height set");
    303 
    304 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 0);
    305 	m_results.check(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "Framebuffer was incorrectly reported as complete when it only had a height");
    306 
    307 	gl.deleteFramebuffers(1, &framebuffer);
    308 
    309 	m_results.setTestContextResult(m_testCtx);
    310 	return STOP;
    311 }
    312 
    313 struct FboSpec
    314 {
    315 	int width;
    316 	int height;
    317 	int samples;
    318 
    319 	FboSpec(int width_, int height_, int samples_) : width(width_), height(height_), samples(samples_){}
    320 };
    321 
    322 class SizeCase : public tcu::TestCase
    323 {
    324 public:
    325 								SizeCase	(tcu::TestContext&			testCtx,
    326 											 const glu::RenderContext&	renderCtx,
    327 											 const char*				name,
    328 											 const char*				desc,
    329 											 const FboSpec&				spec);
    330 	virtual						~SizeCase	(void) {}
    331 
    332 	virtual IterateResult		iterate		(void);
    333 
    334 	enum
    335 	{
    336 		USE_MAXIMUM = -1
    337 	};
    338 private:
    339 	int							getWidth	(void) const;
    340 	int							getHeight	(void) const;
    341 	int							getSamples	(void) const;
    342 
    343 	const glu::RenderContext&	m_renderCtx;
    344 
    345 	const FboSpec				m_spec;
    346 };
    347 
    348 SizeCase::SizeCase (tcu::TestContext&			testCtx,
    349 					const glu::RenderContext&	renderCtx,
    350 					const char*					name,
    351 					const char*					desc,
    352 					const FboSpec&				spec)
    353 	: TestCase		(testCtx, name, desc)
    354 	, m_renderCtx	(renderCtx)
    355 	, m_spec		(spec)
    356 {
    357 }
    358 
    359 SizeCase::IterateResult SizeCase::iterate (void)
    360 {
    361 	const glw::Functions&	gl			= m_renderCtx.getFunctions();
    362 	TestLog&				log			= m_testCtx.getLog();
    363 	GLuint					framebuffer	= 0;
    364 	const int				width		= getWidth();
    365 	const int				height		= getHeight();
    366 	const int				samples		= getSamples();
    367 
    368 	gl.genFramebuffers(1, &framebuffer);
    369 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
    370 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, width);
    371 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, height);
    372 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, samples);
    373 
    374 	log << TestLog::Message << "Verifying " << width << "x" << height << " framebuffer with " << samples << "x multisampling" << TestLog::EndMessage;
    375 
    376 	if(checkFramebufferRenderable(log, m_renderCtx, framebuffer, IVec2(width, height)) && checkFramebufferSize(log, m_renderCtx, framebuffer, IVec2(width, height)))
    377 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    378 	else
    379 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Framebuffer did not behave as expected");
    380 
    381 	gl.deleteFramebuffers(1, &framebuffer);
    382 
    383 	return STOP;
    384 }
    385 
    386 int SizeCase::getWidth (void) const
    387 {
    388 	if (m_spec.width != USE_MAXIMUM)
    389 		return m_spec.width;
    390 	else
    391 	{
    392 		const glw::Functions&	gl		= m_renderCtx.getFunctions();
    393 		GLint					width	= 0;
    394 
    395 		gl.getIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &width);
    396 
    397 		return width;
    398 	}
    399 }
    400 
    401 int SizeCase::getHeight (void) const
    402 {
    403 	if (m_spec.height != USE_MAXIMUM)
    404 		return m_spec.height;
    405 	else
    406 	{
    407 		const glw::Functions&	gl		= m_renderCtx.getFunctions();
    408 		GLint					height	= 0;
    409 
    410 		gl.getIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &height);
    411 
    412 		return height;
    413 	}
    414 }
    415 
    416 int SizeCase::getSamples (void) const
    417 {
    418 	if (m_spec.samples != USE_MAXIMUM)
    419 		return m_spec.samples;
    420 	else
    421 	{
    422 		const glw::Functions&	gl		= m_renderCtx.getFunctions();
    423 		GLint					samples	= 0;
    424 
    425 		gl.getIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &samples);
    426 
    427 		return samples;
    428 	}
    429 }
    430 
    431 class AttachmentInteractionCase : public tcu::TestCase
    432 {
    433 public:
    434 								AttachmentInteractionCase	(tcu::TestContext&			testCtx,
    435 															 const glu::RenderContext&	renderCtx,
    436 															 const char*				name,
    437 															 const char*				desc,
    438 															 const FboSpec&				defaultSpec,
    439 															 const FboSpec&				attachmentSpec);
    440 	virtual						~AttachmentInteractionCase	(void) {}
    441 
    442 	virtual IterateResult		iterate						(void);
    443 
    444 private:
    445 	const glu::RenderContext&	m_renderCtx;
    446 	const FboSpec				m_defaultSpec;
    447 	const FboSpec				m_attachmentSpec;
    448 };
    449 
    450 AttachmentInteractionCase::AttachmentInteractionCase (tcu::TestContext&			testCtx,
    451 													  const glu::RenderContext&	renderCtx,
    452 													  const char*				name,
    453 													  const char*				desc,
    454 													  const FboSpec&			defaultSpec,
    455 													  const FboSpec&			attachmentSpec)
    456 	: TestCase			(testCtx, name, desc)
    457 	, m_renderCtx		(renderCtx)
    458 	, m_defaultSpec		(defaultSpec)
    459 	, m_attachmentSpec	(attachmentSpec)
    460 {
    461 }
    462 
    463 AttachmentInteractionCase::IterateResult AttachmentInteractionCase::iterate (void)
    464 {
    465 	const glw::Functions&	gl			= m_renderCtx.getFunctions();
    466 	TestLog&				log			= m_testCtx.getLog();
    467 	GLuint					framebuffer	= 0;
    468 	GLuint					renderbuffer= 0;
    469 
    470 	gl.genFramebuffers(1, &framebuffer);
    471 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
    472 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, m_defaultSpec.width);
    473 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, m_defaultSpec.height);
    474 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, m_defaultSpec.samples);
    475 
    476 	gl.genRenderbuffers(1, &renderbuffer);
    477 	gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
    478 	gl.renderbufferStorageMultisample(GL_RENDERBUFFER, m_attachmentSpec.samples, GL_RGBA8, m_attachmentSpec.width, m_attachmentSpec.height);
    479 	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
    480 
    481 	log << TestLog::Message << "Verifying " << m_attachmentSpec.width << "x" << m_attachmentSpec.height << " framebuffer with " << m_attachmentSpec.samples << "x multisampling"
    482 		<< " and defaults set to " << m_defaultSpec.width << "x" << m_defaultSpec.height << " with " << m_defaultSpec.samples << "x multisampling" << TestLog::EndMessage;
    483 
    484 	if(checkFramebufferRenderable(log, m_renderCtx, framebuffer, IVec2(m_attachmentSpec.width, m_attachmentSpec.height))
    485 	   && checkFramebufferSize(log, m_renderCtx, framebuffer, IVec2(m_attachmentSpec.width, m_attachmentSpec.height)))
    486 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    487 	else
    488 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Framebuffer did not behave as expected");
    489 
    490 	gl.deleteRenderbuffers(1, &renderbuffer);
    491 	gl.deleteFramebuffers(1, &framebuffer);
    492 
    493 	return STOP;
    494 }
    495 
    496 } // Anonymous
    497 
    498 tcu::TestCaseGroup* createFboNoAttachmentTests(Context& context)
    499 {
    500 	const glu::RenderContext&	renderCtx	= context.getRenderContext();
    501 	tcu::TestContext&			testCtx		= context.getTestContext();
    502 
    503 	const int					maxWidth	= 2048; // MAX_FRAMEBUFFER_WIDTH in ES 3.1
    504 	const int					maxHeight	= 2048; // MAX_FRAMEBUFFER_HEIGHT in ES 3.1
    505 	const int					maxSamples	= 4;
    506 
    507 	tcu::TestCaseGroup* const	root		= new tcu::TestCaseGroup(testCtx, "no_attachments", "Framebuffer without attachments");
    508 
    509 	// Size
    510 	{
    511 		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "size", "Basic functionality tests with varying default size");
    512 
    513 		root->addChild(group);
    514 
    515 		for (int width = 16; width <= maxWidth; width *= 4)
    516 		{
    517 			for (int height = 16; height <= maxHeight; height *= 4)
    518 			{
    519 				const FboSpec	spec (width, height, 0);
    520 				stringstream	name;
    521 
    522 				name << width << "x" << height;
    523 
    524 				group->addChild(new SizeCase(testCtx, renderCtx, name.str().c_str(), name.str().c_str(), spec));
    525 			}
    526 		}
    527 	}
    528 
    529 	// NPOT size
    530 	{
    531 		const FboSpec specs[] =
    532 		{
    533 			// Square
    534 			FboSpec(1,    1,    0),
    535 			FboSpec(3,    3,    0),
    536 			FboSpec(15,   15,   0),
    537 			FboSpec(17,   17,   0),
    538 			FboSpec(31,   31,   0),
    539 			FboSpec(33,   33,   0),
    540 			FboSpec(63,   63,   0),
    541 			FboSpec(65,   65,   0),
    542 			FboSpec(127,  127,  0),
    543 			FboSpec(129,  129,  0),
    544 			FboSpec(255,  255,  0),
    545 			FboSpec(257,  257,  0),
    546 			FboSpec(511,  511,  0),
    547 			FboSpec(513,  513,  0),
    548 			FboSpec(1023, 1023, 0),
    549 			FboSpec(1025, 1025, 0),
    550 			FboSpec(2047, 2047, 0),
    551 
    552 			// Non-square
    553 			FboSpec(15,   511,  0),
    554 			FboSpec(127,  15,   0),
    555 			FboSpec(129,  127,  0),
    556 			FboSpec(511,  127,  0),
    557 			FboSpec(2047, 1025, 0),
    558 		};
    559 		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "npot_size", "Basic functionality with Non-power-of-two size");
    560 
    561 		root->addChild(group);
    562 
    563 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(specs); caseNdx++)
    564 		{
    565 			const FboSpec&	spec = specs[caseNdx];
    566 			stringstream	name;
    567 
    568 			name << spec.width << "x" << spec.height;
    569 
    570 			group->addChild(new SizeCase(testCtx, renderCtx, name.str().c_str(), name.str().c_str(), spec));
    571 		}
    572 	}
    573 
    574 	// Multisample
    575 	{
    576 		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "multisample", "Basic functionality with multisampled fbo");
    577 
    578 		root->addChild(group);
    579 
    580 		for (int samples = 0; samples <= maxSamples; samples++)
    581 		{
    582 			const FboSpec	spec (128, 128, samples);
    583 			stringstream	name;
    584 
    585 			name << "samples" << samples;
    586 
    587 			group->addChild(new SizeCase(testCtx, renderCtx, name.str().c_str(), name.str().c_str(), spec));
    588 		}
    589 	}
    590 
    591 	// Randomized
    592 	{
    593 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(testCtx, "random", "Randomized size & multisampling");
    594 		de::Random					rng		(0xF0E1E2D3 ^ testCtx.getCommandLine().getBaseSeed());
    595 
    596 		root->addChild(group);
    597 
    598 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
    599 		{
    600 			const int		width	= rng.getInt(1, maxWidth);
    601 			const int		height	= rng.getInt(1, maxHeight);
    602 			const int		samples = rng.getInt(0, maxSamples);
    603 			const FboSpec	spec	(width, height, samples);
    604 			const string	name	= de::toString(caseNdx);
    605 
    606 			group->addChild(new SizeCase(testCtx, renderCtx, name.c_str(), name.c_str(), spec));
    607 		}
    608 	}
    609 
    610 	// Normal fbo with defaults set
    611 	{
    612 		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "interaction", "Interaction of default parameters with normal fbo");
    613 
    614 		root->addChild(group);
    615 
    616 		const FboSpec specs[][2] =
    617 		{
    618 			{ FboSpec(256,  256,  0), FboSpec(128,  128,  1) },
    619 			{ FboSpec(256,  256,  1), FboSpec(128,  128,  0) },
    620 			{ FboSpec(256,  256,  0), FboSpec(512,  512,  2) },
    621 			{ FboSpec(256,  256,  2), FboSpec(128,  512,  0) },
    622 			{ FboSpec(127,  127,  0), FboSpec(129,  129,  0) },
    623 			{ FboSpec(17,   512,  4), FboSpec(16,   16,   2) },
    624 			{ FboSpec(2048, 2048, 4), FboSpec(1,    1,    0) },
    625 			{ FboSpec(1,    1,    0), FboSpec(2048, 2048, 4) },
    626 		};
    627 
    628 		for (int specNdx = 0; specNdx < DE_LENGTH_OF_ARRAY(specs); specNdx++)
    629 		{
    630 			const FboSpec& baseSpec = specs[specNdx][0];
    631 			const FboSpec& altSpec	= specs[specNdx][1];
    632 			stringstream baseSpecName, altSpecName;
    633 
    634 			baseSpecName << baseSpec.width << "x" << baseSpec.height << "ms" << baseSpec.samples;
    635 			altSpecName << altSpec.width << "x" << altSpec.height << "ms" << altSpec.samples;
    636 
    637 			{
    638 				const string name = baseSpecName.str() + "_default_" + altSpecName.str();
    639 
    640 				group->addChild(new AttachmentInteractionCase(testCtx, renderCtx, name.c_str(), name.c_str(), altSpec, baseSpec));
    641 			}
    642 		}
    643 	}
    644 
    645 	// Maximums
    646 	{
    647 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(testCtx, "maximums", "Maximum dimensions");
    648 
    649 		root->addChild(group);
    650 		group->addChild(new SizeCase(testCtx, renderCtx, "width",	"Maximum width",		  FboSpec(SizeCase::USE_MAXIMUM,	128,					0)));
    651 		group->addChild(new SizeCase(testCtx, renderCtx, "height",	"Maximum height",		  FboSpec(128,						SizeCase::USE_MAXIMUM,  0)));
    652 		group->addChild(new SizeCase(testCtx, renderCtx, "size",	"Maximum size",			  FboSpec(SizeCase::USE_MAXIMUM,	SizeCase::USE_MAXIMUM,  0)));
    653 		group->addChild(new SizeCase(testCtx, renderCtx, "samples", "Maximum samples",		  FboSpec(128,						128,					SizeCase::USE_MAXIMUM)));
    654 		group->addChild(new SizeCase(testCtx, renderCtx, "all",		"Maximum size & samples", FboSpec(SizeCase::USE_MAXIMUM,	SizeCase::USE_MAXIMUM,  SizeCase::USE_MAXIMUM)));
    655 	}
    656 
    657 	return root;
    658 }
    659 
    660 tcu::TestCaseGroup* createFboNoAttachmentCompletenessTests(Context& context)
    661 {
    662 	TestCaseGroup* const group = new TestCaseGroup(context, "completeness", "Completeness tests");
    663 
    664 	group->addChild(new FramebufferCompletenessCase(context.getTestContext(), context.getRenderContext(), "no_attachments", "No attachments completeness"));
    665 
    666 	return group;
    667 }
    668 
    669 } // Functional
    670 } // gles31
    671 } // deqp
    672