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
48namespace deqp
49{
50namespace gles31
51{
52namespace Functional
53{
54namespace
55{
56
57using namespace glw;
58
59using tcu::IVec2;
60using tcu::TestLog;
61
62using std::stringstream;
63using std::string;
64using std::vector;
65
66bool 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
173bool 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
264class FramebufferCompletenessCase : public tcu::TestCase
265{
266public:
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
274private:
275	const glu::RenderContext&	m_renderCtx;
276	tcu::ResultCollector		m_results;
277};
278
279FramebufferCompletenessCase::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
288FramebufferCompletenessCase::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
313struct 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
322class SizeCase : public tcu::TestCase
323{
324public:
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	};
338private:
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
348SizeCase::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
359SizeCase::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
386int 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
401int 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
416int 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
431class AttachmentInteractionCase : public tcu::TestCase
432{
433public:
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
444private:
445	const glu::RenderContext&	m_renderCtx;
446	const FboSpec				m_defaultSpec;
447	const FboSpec				m_attachmentSpec;
448};
449
450AttachmentInteractionCase::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
463AttachmentInteractionCase::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
498tcu::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
660tcu::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