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
49namespace deqp
50{
51namespace gles31
52{
53namespace Functional
54{
55namespace
56{
57
58using namespace glw;
59
60using tcu::IVec2;
61using tcu::TestLog;
62
63using std::stringstream;
64using std::string;
65using std::vector;
66
67bool 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
174bool 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
265class FramebufferCompletenessCase : public tcu::TestCase
266{
267public:
268								FramebufferCompletenessCase		(tcu::TestContext&			testCtx,
269																 const glu::RenderContext&	renderCtx,
270																 const char*				name,
271																 const char*				desc);
272	virtual						~FramebufferCompletenessCase	 (void) {}
273	virtual IterateResult		iterate							(void);
274
275private:
276	const glu::RenderContext&	m_renderCtx;
277	tcu::ResultCollector		m_results;
278};
279
280FramebufferCompletenessCase::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
289FramebufferCompletenessCase::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
314struct FboSpec
315{
316	int width;
317	int height;
318	int samples;
319
320	FboSpec(int width_, int height_, int samples_) : width(width_), height(height_), samples(samples_){}
321};
322
323class SizeCase : public tcu::TestCase
324{
325public:
326								SizeCase	(tcu::TestContext&			testCtx,
327											 const glu::RenderContext&	renderCtx,
328											 const char*				name,
329											 const char*				desc,
330											 const FboSpec&				spec);
331	virtual						~SizeCase	(void) {}
332
333	virtual IterateResult		iterate		(void);
334
335	enum
336	{
337		USE_MAXIMUM = -1
338	};
339private:
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
349SizeCase::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
360SizeCase::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
387int 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
402int 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
417int 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
432class AttachmentInteractionCase : public tcu::TestCase
433{
434public:
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);
441	virtual						~AttachmentInteractionCase	(void) {}
442
443	virtual IterateResult		iterate						(void);
444
445private:
446	const glu::RenderContext&	m_renderCtx;
447	const FboSpec				m_defaultSpec;
448	const FboSpec				m_attachmentSpec;
449};
450
451AttachmentInteractionCase::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
464AttachmentInteractionCase::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
499tcu::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
661tcu::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