es3fFboCompletenessTests.cpp revision bf845c4e3814b85e1a3e23a27f50c8f888f4bd2d
1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) 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 completeness tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fFboCompletenessTests.hpp"
25
26#include "glsFboCompletenessTests.hpp"
27#include <sstream>
28
29using namespace glw;
30using deqp::gls::Range;
31using namespace deqp::gls::FboUtil;
32using namespace deqp::gls::FboUtil::config;
33namespace fboc = deqp::gls::fboc;
34typedef tcu::TestCase::IterateResult IterateResult;
35using std::string;
36using std::ostringstream;
37
38namespace deqp
39{
40namespace gles3
41{
42namespace Functional
43{
44
45static const FormatKey s_es3ColorRenderables[] =
46{
47	// GLES3, 4.4.4: "An internal format is color-renderable if it is one of
48	// the formats from table 3.12 noted as color-renderable..."
49	GL_R8, GL_RG8, GL_RGB8, GL_RGB565, GL_RGBA4, GL_RGB5_A1, GL_RGBA8,
50	GL_RGB10_A2, GL_RGB10_A2UI, GL_SRGB8_ALPHA8,
51	GL_R8I, GL_R8UI, GL_R16I, GL_R16UI, GL_R32I, GL_R32UI,
52	GL_RG8I, GL_RG8UI, GL_RG16I, GL_RG16UI, GL_RG32I, GL_RG32UI,
53	GL_RGBA8I, GL_RGBA8UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI,
54};
55
56static const FormatKey s_es3UnsizedColorRenderables[] =
57{
58	// "...or if it is unsized format RGBA or RGB."
59	// See Table 3.3 in GLES3.
60	GLS_UNSIZED_FORMATKEY(GL_RGBA,	GL_UNSIGNED_BYTE),
61	GLS_UNSIZED_FORMATKEY(GL_RGBA,	GL_UNSIGNED_SHORT_4_4_4_4),
62	GLS_UNSIZED_FORMATKEY(GL_RGBA,	GL_UNSIGNED_SHORT_5_5_5_1),
63	GLS_UNSIZED_FORMATKEY(GL_RGB,	GL_UNSIGNED_BYTE),
64	GLS_UNSIZED_FORMATKEY(GL_RGB,	GL_UNSIGNED_SHORT_5_6_5),
65};
66
67static const FormatKey s_es3DepthRenderables[] =
68{
69	// GLES3, 4.4.4: "An internal format is depth-renderable if it is one of
70	// the formats from table 3.13."
71	GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32F,
72	GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8,
73};
74
75static const FormatKey s_es3StencilRboRenderables[] =
76{
77	// GLES3, 4.4.4: "An internal format is stencil-renderable if it is
78	// STENCIL_INDEX8..."
79	GL_STENCIL_INDEX8,
80};
81
82static const FormatKey s_es3StencilRenderables[] =
83{
84	// "...or one of the formats from table 3.13 whose base internal format is
85	// DEPTH_STENCIL."
86	GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8,
87};
88
89static const FormatKey s_es3TextureFloatFormats[] =
90{
91	GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F,
92	GL_RG32F, GL_RG16F, GL_R32F, GL_R16F,
93	GL_RGBA16F, GL_RGB16F, GL_RG16F, GL_R16F,
94};
95
96static const FormatKey s_es3NotRenderableTextureFormats[] =
97{
98	GL_R8_SNORM, GL_RG8_SNORM, GL_RGB8_SNORM, GL_RGBA8_SNORM,
99	GL_RGB9_E5, GL_SRGB8,
100	GL_RGB8I, GL_RGB16I, GL_RGB32I,
101	GL_RGB8UI, GL_RGB16UI,GL_RGB32UI,
102};
103
104static const FormatEntry s_es3Formats[] =
105{
106	// Renderbuffers don't support unsized formats
107	{ REQUIRED_RENDERABLE | COLOR_RENDERABLE | TEXTURE_VALID,
108	  GLS_ARRAY_RANGE(s_es3UnsizedColorRenderables) },
109	{ REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID,
110	  GLS_ARRAY_RANGE(s_es3ColorRenderables) },
111	{ REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID,
112	  GLS_ARRAY_RANGE(s_es3DepthRenderables) },
113	{ REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID,
114	  GLS_ARRAY_RANGE(s_es3StencilRboRenderables) },
115	{ REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID,
116	  GLS_ARRAY_RANGE(s_es3StencilRenderables) },
117	{ TEXTURE_VALID,
118	  GLS_ARRAY_RANGE(s_es3NotRenderableTextureFormats) },
119
120	// These are not color-renderable in vanilla ES3, but we need to mark them
121	// as valid for textures, since EXT_color_buffer_(half_)float brings in
122	// color-renderability and only renderbuffer-validity.
123	{ TEXTURE_VALID,
124	  GLS_ARRAY_RANGE(s_es3TextureFloatFormats) },
125};
126
127// GL_EXT_color_buffer_float
128static const FormatKey s_extColorBufferFloatFormats[] =
129{
130	GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, GL_RG32F, GL_RG16F, GL_R32F, GL_R16F,
131};
132
133// GL_OES_texture_stencil8
134static const FormatKey s_extOESTextureStencil8[] =
135{
136	GL_STENCIL_INDEX8,
137};
138
139// GL_EXT_render_snorm
140static const FormatKey s_extRenderSnorm[] =
141{
142	GL_R8_SNORM, GL_RG8_SNORM, GL_RGBA8_SNORM,
143};
144
145static const FormatExtEntry s_es3ExtFormats[] =
146{
147	{
148		"GL_EXT_color_buffer_float",
149		// These are already texture-valid in ES3, the extension just adds RBO
150		// support and makes them color-renderable.
151		REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID,
152		GLS_ARRAY_RANGE(s_extColorBufferFloatFormats)
153	},
154	{
155		"GL_OES_texture_stencil8",
156		// \note: es3 RBO tests actually cover the first two requirements
157		// - kept here for completeness
158		REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID,
159		GLS_ARRAY_RANGE(s_extOESTextureStencil8)
160	},
161
162	// Since GLES31 is backwards compatible to GLES3, we might actually be running on a GLES31.
163	// Add rule changes of GLES31 that have no corresponding GLES3 extension.
164	//
165	// \note Not all feature changes are listed here but only those that alter GLES3 subset of
166	//       the formats
167	{
168		"DEQP_gles31_core_compatible GL_EXT_render_snorm",
169		REQUIRED_RENDERABLE | COLOR_RENDERABLE | TEXTURE_VALID | RENDERBUFFER_VALID,
170		GLS_ARRAY_RANGE(s_extRenderSnorm)
171	},
172};
173
174class ES3Checker : public Checker
175{
176public:
177				ES3Checker	(void)
178					: m_numSamples			(-1)
179					, m_depthStencilImage	(0)
180					, m_depthStencilType	(GL_NONE) {}
181	void		check 		(GLenum attPoint, const Attachment& att, const Image* image);
182
183private:
184	//! The common number of samples of images.
185	GLsizei		m_numSamples;
186
187	//! The common image for depth and stencil attachments.
188	GLuint		m_depthStencilImage;
189	GLenum		m_depthStencilType;
190};
191
192void ES3Checker::check (GLenum attPoint, const Attachment& att, const Image* image)
193{
194	GLsizei imgSamples = imageNumSamples(*image);
195
196	if (m_numSamples == -1)
197	{
198		m_numSamples = imgSamples;
199	}
200	else
201	{
202		// GLES3: "The value of RENDERBUFFER_SAMPLES is the same for all attached
203		// renderbuffers and, if the attached images are a mix of renderbuffers
204		// and textures, the value of RENDERBUFFER_SAMPLES is zero."
205		//
206		// On creating a renderbuffer: "If _samples_ is zero, then
207		// RENDERBUFFER_SAMPLES is set to zero. Otherwise [...] the resulting
208		// value for RENDERBUFFER_SAMPLES is guaranteed to be greater than or
209		// equal to _samples_ and no more than the next larger sample count
210		// supported by the implementation."
211
212		// Either all attachments are zero-sample renderbuffers and/or
213		// textures, or none of them are.
214		if ((m_numSamples == 0) != (imgSamples == 0))
215			addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, "Mixed multi- and single-sampled attachments");
216
217		// If the attachments requested a different number of samples, the
218		// implementation is allowed to report this as incomplete. However, it
219		// is also possible that despite the different requests, the
220		// implementation allocated the same number of samples to both. Hence
221		// reporting the framebuffer as complete is also legal.
222		if (m_numSamples != imgSamples)
223			addPotentialFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, "Number of samples differ");
224	}
225
226	// "Depth and stencil attachments, if present, are the same image."
227	if (attPoint == GL_DEPTH_ATTACHMENT || attPoint == GL_STENCIL_ATTACHMENT)
228	{
229		if (m_depthStencilImage == 0)
230		{
231			m_depthStencilImage = att.imageName;
232			m_depthStencilType = attachmentType(att);
233		}
234		else
235		{
236			if (m_depthStencilImage != att.imageName || m_depthStencilType != attachmentType(att))
237				addFBOStatus(GL_FRAMEBUFFER_UNSUPPORTED, "Depth and stencil attachments are not the same image");
238		}
239	}
240}
241
242struct NumLayersParams
243{
244	GLenum		textureKind;		//< GL_TEXTURE_3D or GL_TEXTURE_2D_ARRAY
245	GLsizei		numLayers;			//< Number of layers in texture
246	GLsizei		attachmentLayer;	//< Layer referenced by attachment
247
248	static string	getName			(const NumLayersParams& params);
249	static string	getDescription	(const NumLayersParams& params);
250};
251
252string NumLayersParams::getName (const NumLayersParams& params)
253{
254	ostringstream os;
255	const string kindStr = params.textureKind == GL_TEXTURE_3D ? "3d" : "2darr";
256	os << kindStr << "_" << params.numLayers << "_" << params.attachmentLayer;
257	return os.str();
258}
259
260string NumLayersParams::getDescription (const NumLayersParams& params)
261{
262	ostringstream os;
263	const string kindStr = (params.textureKind == GL_TEXTURE_3D
264							? "3D Texture"
265							: "2D Array Texture");
266	os << kindStr + ", "
267	   << params.numLayers << " layers, "
268	   << "attached layer " << params.attachmentLayer << ".";
269	return os.str();
270}
271
272class NumLayersTest : public fboc::ParamTest<NumLayersParams>
273{
274public:
275					NumLayersTest		(fboc::Context& ctx, NumLayersParams param)
276						: fboc::ParamTest<NumLayersParams> (ctx, param) {}
277
278	IterateResult	build				(FboBuilder& builder);
279};
280
281IterateResult NumLayersTest::build (FboBuilder& builder)
282{
283	TextureLayered* texCfg = DE_NULL;
284	const GLenum target = GL_COLOR_ATTACHMENT0;
285
286	switch (m_params.textureKind)
287	{
288		case GL_TEXTURE_3D:
289			texCfg = &builder.makeConfig<Texture3D>();
290			break;
291		case GL_TEXTURE_2D_ARRAY:
292			texCfg = &builder.makeConfig<Texture2DArray>();
293			break;
294		default:
295			DE_ASSERT(!"Impossible case");
296	}
297	texCfg->internalFormat = getDefaultFormat(target, GL_TEXTURE);
298	texCfg->width = 64;
299	texCfg->height = 64;
300	texCfg->numLayers = m_params.numLayers;
301	const GLuint tex = builder.glCreateTexture(*texCfg);
302
303	TextureLayerAttachment* att = &builder.makeConfig<TextureLayerAttachment>();
304	att->layer = m_params.attachmentLayer;
305	att->imageName = tex;
306
307	builder.glAttach(target, att);
308
309	return STOP;
310}
311
312enum
313{
314	SAMPLES_NONE = -2,
315	SAMPLES_TEXTURE = -1
316};
317struct NumSamplesParams
318{
319	// >= 0: renderbuffer with N samples, -1: texture, -2: no attachment
320	GLsizei		numSamples[3];
321
322	static string	getName			(const NumSamplesParams& params);
323	static string	getDescription	(const NumSamplesParams& params);
324};
325
326string NumSamplesParams::getName (const NumSamplesParams& params)
327{
328	ostringstream os;
329	bool first = true;
330	for (const GLsizei* ns	=	DE_ARRAY_BEGIN(params.numSamples);
331		 ns 				!=	DE_ARRAY_END(params.numSamples);
332		 ns++)
333	{
334		if (first)
335			first = false;
336		else
337			os << "_";
338
339		if (*ns == SAMPLES_NONE)
340			os << "none";
341		else if (*ns == SAMPLES_TEXTURE)
342			os << "tex";
343		else
344			os << "rbo" << *ns;
345	}
346	return os.str();
347}
348
349string NumSamplesParams::getDescription (const NumSamplesParams& params)
350{
351	ostringstream os;
352	bool first = true;
353	static const char* const s_names[] = { "color", "depth", "stencil" };
354	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == DE_LENGTH_OF_ARRAY(params.numSamples));
355
356	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_names); i++)
357	{
358		GLsizei ns = params.numSamples[i];
359
360		if (ns == SAMPLES_NONE)
361			continue;
362
363		if (first)
364			first = false;
365		else
366			os << ", ";
367
368		if (ns == SAMPLES_TEXTURE)
369			os << "texture " << s_names[i] << " attachment";
370		else
371			os << ns << "-sample renderbuffer " << s_names[i] << " attachment";
372	}
373	return os.str();
374}
375
376class NumSamplesTest : public fboc::ParamTest<NumSamplesParams>
377{
378public:
379					NumSamplesTest		(fboc::Context& ctx, NumSamplesParams param)
380						: fboc::ParamTest<NumSamplesParams> (ctx, param) {}
381
382	IterateResult	build				(FboBuilder& builder);
383};
384
385IterateResult NumSamplesTest::build (FboBuilder& builder)
386{
387	static const GLenum s_targets[] =
388		{
389			GL_COLOR_ATTACHMENT0,	GL_COLOR_ATTACHMENT1,	GL_DEPTH_ATTACHMENT,
390		};
391	// Non-integer formats for each attachment type.
392	// \todo [2013-12-17 lauri] Add fixed/floating/integer metadata for formats so
393	// we can pick one smartly or maybe try several.
394	static const GLenum s_formats[] =
395		{
396			GL_RGBA8,				GL_RGB565,				GL_DEPTH_COMPONENT24,
397		};
398	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_targets) == DE_LENGTH_OF_ARRAY(m_params.numSamples));
399
400	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_targets); i++)
401	{
402		const GLenum target = s_targets[i];
403		const ImageFormat fmt = { s_formats[i], GL_NONE };
404
405		const GLsizei ns = m_params.numSamples[i];
406		if (ns == -2)
407			continue;
408
409		if (ns == -1)
410		{
411			attachTargetToNew(target, GL_TEXTURE, fmt, 64, 64, builder);
412		}
413		else
414		{
415			Renderbuffer& rboCfg = builder.makeConfig<Renderbuffer>();
416			rboCfg.internalFormat = fmt;
417			rboCfg.width = rboCfg.height = 64;
418			rboCfg.numSamples = ns;
419
420			const GLuint rbo = builder.glCreateRbo(rboCfg);
421			// Implementations do not necessarily support sample sizes greater than 1.
422			TCU_CHECK_AND_THROW(NotSupportedError,
423								builder.getError() != GL_INVALID_OPERATION,
424								"Unsupported number of samples");
425			RenderbufferAttachment& att = builder.makeConfig<RenderbufferAttachment>();
426			att.imageName = rbo;
427			builder.glAttach(target, &att);
428		}
429	}
430
431	return STOP;
432}
433
434class ES3CheckerFactory : public CheckerFactory
435{
436public:
437	Checker*			createChecker	(void) { return new ES3Checker(); }
438};
439
440class TestGroup : public TestCaseGroup
441{
442public:
443						TestGroup		(Context& context);
444	void				init			(void);
445private:
446	ES3CheckerFactory	m_checkerFactory;
447	fboc::Context		m_fboc;
448};
449
450void TestGroup::init (void)
451{
452	addChild(m_fboc.createRenderableTests());
453	addChild(m_fboc.createAttachmentTests());
454	addChild(m_fboc.createSizeTests());
455
456	TestCaseGroup* layerTests = new TestCaseGroup(
457		getContext(), "layer", "Tests for layer attachments");
458
459	static const NumLayersParams s_layersParams[] =
460		{ //  textureKind			numLayers	attachmentKind
461			{ GL_TEXTURE_2D_ARRAY,	1,			0 },
462			{ GL_TEXTURE_2D_ARRAY,	1,			3 },
463			{ GL_TEXTURE_2D_ARRAY,	4,			3 },
464			{ GL_TEXTURE_2D_ARRAY,	4,			15 },
465			{ GL_TEXTURE_3D,		1,			0 },
466			{ GL_TEXTURE_3D,		1,			15 },
467			{ GL_TEXTURE_3D,		4,			15 },
468			{ GL_TEXTURE_3D,		64,			15 },
469		};
470
471	for (const NumLayersParams* lp	=	DE_ARRAY_BEGIN(s_layersParams);
472		 lp							!=  DE_ARRAY_END(s_layersParams);
473		 ++lp)
474		layerTests->addChild(new NumLayersTest(m_fboc, *lp));
475
476	addChild(layerTests);
477
478	TestCaseGroup* sampleTests = new TestCaseGroup(
479		getContext(), "samples", "Tests for multisample attachments");
480
481	static const NumSamplesParams s_samplesParams[] =
482	{
483		{ { 0,					SAMPLES_NONE,		SAMPLES_NONE } },
484		{ { 1,					SAMPLES_NONE,		SAMPLES_NONE } },
485		{ { 2,					SAMPLES_NONE,		SAMPLES_NONE } },
486		{ { 0,					SAMPLES_TEXTURE,	SAMPLES_NONE } },
487		{ { 1,					SAMPLES_TEXTURE,	SAMPLES_NONE } },
488		{ { 2,					SAMPLES_TEXTURE,	SAMPLES_NONE } },
489		{ { 2,					1,					SAMPLES_NONE } },
490		{ { 2,					2,					SAMPLES_NONE } },
491		{ { 0,					0,					SAMPLES_TEXTURE } },
492		{ { 1,					2,					0 } },
493		{ { 2,					2,					0 } },
494		{ { 1,					1,					1 } },
495		{ { 1,					2,					4 } },
496	};
497
498	for (const NumSamplesParams* lp	=	DE_ARRAY_BEGIN(s_samplesParams);
499		 lp							!=  DE_ARRAY_END(s_samplesParams);
500		 ++lp)
501		sampleTests->addChild(new NumSamplesTest(m_fboc, *lp));
502
503	addChild(sampleTests);
504}
505
506TestGroup::TestGroup (Context& ctx)
507	: TestCaseGroup		(ctx, "completeness", "Completeness tests")
508	, m_checkerFactory	()
509	, m_fboc			(ctx.getTestContext(), ctx.getRenderContext(), m_checkerFactory)
510{
511	const FormatEntries stdRange = GLS_ARRAY_RANGE(s_es3Formats);
512	const FormatExtEntries extRange = GLS_ARRAY_RANGE(s_es3ExtFormats);
513
514	m_fboc.addFormats(stdRange);
515	m_fboc.addExtFormats(extRange);
516	m_fboc.setHaveMulticolorAtts(true); // Vanilla ES3 has multiple color attachments
517}
518
519tcu::TestCaseGroup* createFboCompletenessTests (Context& context)
520{
521	return new TestGroup(context);
522}
523
524} // Functional
525} // gles3
526} // deqp
527