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