es31fInternalFormatQueryTests.cpp revision 96cb7f12003c49de4b9462e237eade317371fcce
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 Internal format query tests
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fInternalFormatQueryTests.hpp"
25#include "tcuTestLog.hpp"
26#include "gluRenderContext.hpp"
27#include "gluStrUtil.hpp"
28#include "gluContextInfo.hpp"
29#include "glwFunctions.hpp"
30#include "glwEnums.hpp"
31
32namespace deqp
33{
34namespace gles31
35{
36namespace Functional
37{
38namespace
39{
40
41class FormatSamplesCase : public TestCase
42{
43public:
44	enum FormatType
45	{
46		FORMAT_COLOR,
47		FORMAT_INT,
48		FORMAT_DEPTH_STENCIL
49	};
50
51						FormatSamplesCase	(Context& ctx, const char* name, const char* desc, glw::GLenum texTarget, glw::GLenum internalFormat, FormatType type);
52private:
53	void				init				(void);
54	IterateResult		iterate				(void);
55
56	const glw::GLenum	m_target;
57	const glw::GLenum	m_internalFormat;
58	const FormatType	m_type;
59};
60
61FormatSamplesCase::FormatSamplesCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, glw::GLenum internalFormat, FormatType type)
62	: TestCase			(ctx, name, desc)
63	, m_target			(target)
64	, m_internalFormat	(internalFormat)
65	, m_type			(type)
66{
67	DE_ASSERT(m_target == GL_TEXTURE_2D_MULTISAMPLE 		||
68			  m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY 	||
69			  m_target == GL_RENDERBUFFER);
70}
71
72void FormatSamplesCase::init (void)
73{
74	const bool isTextureTarget	=	(m_target == GL_TEXTURE_2D_MULTISAMPLE) ||
75									(m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
76	const bool isES32			=	contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
77
78	if (!isES32 && m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
79		TCU_THROW(NotSupportedError, "Test requires OES_texture_storage_multisample_2d_array extension or a context version equal or higher than 3.2");
80
81	// stencil8 textures are not supported without GL_OES_texture_stencil8 extension
82	if (!isES32 && isTextureTarget && m_internalFormat == GL_STENCIL_INDEX8 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_stencil8"))
83		TCU_THROW(NotSupportedError, "Test requires GL_OES_texture_stencil8 extension or a context version equal or higher than 3.2");
84}
85
86FormatSamplesCase::IterateResult FormatSamplesCase::iterate (void)
87{
88	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
89	bool					isFloatFormat	= false;
90	bool					error			= false;
91	glw::GLint				maxSamples		= 0;
92	glw::GLint				numSampleCounts	= 0;
93	const bool				isES32			= contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
94
95	if (!isES32)
96	{
97		if (m_internalFormat == GL_RGBA16F || m_internalFormat == GL_R32F || m_internalFormat == GL_RG32F || m_internalFormat == GL_RGBA32F || m_internalFormat == GL_R16F || m_internalFormat == GL_RG16F || m_internalFormat == GL_R11F_G11F_B10F)
98		{
99			TCU_THROW(NotSupportedError, "The internal format is not supported in a context lower than 3.2");
100		}
101	}
102	else if (m_internalFormat == GL_RGBA16F || m_internalFormat == GL_R32F || m_internalFormat == GL_RG32F || m_internalFormat == GL_RGBA32F)
103	{
104		isFloatFormat = true;
105	}
106
107	// Lowest limit
108	{
109		const glw::GLenum samplesEnum = (m_type == FORMAT_COLOR) ? (GL_MAX_COLOR_TEXTURE_SAMPLES) : (m_type == FORMAT_INT) ? (GL_MAX_INTEGER_SAMPLES) : (GL_MAX_DEPTH_TEXTURE_SAMPLES);
110		m_testCtx.getLog() << tcu::TestLog::Message << "Format must support sample count of " << glu::getGettableStateStr(samplesEnum) << tcu::TestLog::EndMessage;
111
112		gl.getIntegerv(samplesEnum, &maxSamples);
113		GLU_EXPECT_NO_ERROR(gl.getError(), "get MAX_*_SAMPLES");
114
115		m_testCtx.getLog() << tcu::TestLog::Message << glu::getGettableStateStr(samplesEnum) << " = " << maxSamples << tcu::TestLog::EndMessage;
116
117		if (maxSamples < 1)
118		{
119			m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: minimum value of "  << glu::getGettableStateStr(samplesEnum) << " is 1" << tcu::TestLog::EndMessage;
120			error = true;
121		}
122	}
123
124	// Number of sample counts
125	{
126		gl.getInternalformativ(m_target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts);
127		GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_NUM_SAMPLE_COUNTS");
128
129		m_testCtx.getLog() << tcu::TestLog::Message << "GL_NUM_SAMPLE_COUNTS = " << numSampleCounts << tcu::TestLog::EndMessage;
130
131		if (!isFloatFormat)
132		{
133			if (numSampleCounts < 1)
134			{
135				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Format MUST support some multisample configuration, got GL_NUM_SAMPLE_COUNTS = " << numSampleCounts << tcu::TestLog::EndMessage;
136				error = true;
137			}
138		}
139	}
140
141	// Sample counts
142	{
143		tcu::MessageBuilder		samplesMsg	(&m_testCtx.getLog());
144		std::vector<glw::GLint>	samples		(numSampleCounts > 0 ? numSampleCounts : 1);
145
146		if (numSampleCounts > 0 || isFloatFormat)
147		{
148			gl.getInternalformativ(m_target, m_internalFormat, GL_SAMPLES, numSampleCounts, &samples[0]);
149			GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_SAMPLES");
150		}
151		else
152			TCU_FAIL("glGetInternalFormativ() reported 0 supported sample counts");
153
154		// make a pretty log
155
156		samplesMsg << "GL_SAMPLES = [";
157		for (size_t ndx = 0; ndx < samples.size(); ++ndx)
158		{
159			if (ndx)
160				samplesMsg << ", ";
161			samplesMsg << samples[ndx];
162		}
163		samplesMsg << "]" << tcu::TestLog::EndMessage;
164
165		// Samples are in order
166		for (size_t ndx = 1; ndx < samples.size(); ++ndx)
167		{
168			if (samples[ndx-1] <= samples[ndx])
169			{
170				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Samples must be ordered descending." << tcu::TestLog::EndMessage;
171				error = true;
172				break;
173			}
174		}
175
176		// samples are positive
177		for (size_t ndx = 1; ndx < samples.size(); ++ndx)
178		{
179			if (samples[ndx-1] <= 0)
180			{
181				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Only positive SAMPLES allowed." << tcu::TestLog::EndMessage;
182				error = true;
183				break;
184			}
185		}
186
187		// maxSamples must be supported
188		if (!isFloatFormat)
189		{
190			if (samples[0] < maxSamples)
191			{
192				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: MAX_*_SAMPLES must be supported." << tcu::TestLog::EndMessage;
193				error = true;
194			}
195		}
196	}
197
198	// Result
199	if (!error)
200		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
201	else
202		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value");
203
204	return STOP;
205}
206
207class NumSampleCountsBufferCase : public TestCase
208{
209public:
210					NumSampleCountsBufferCase 	(Context& ctx, const char* name, const char* desc);
211
212private:
213	IterateResult	iterate						(void);
214};
215
216NumSampleCountsBufferCase::NumSampleCountsBufferCase (Context& ctx, const char* name, const char* desc)
217	: TestCase(ctx, name, desc)
218{
219}
220
221NumSampleCountsBufferCase::IterateResult NumSampleCountsBufferCase::iterate (void)
222{
223	const glw::GLint 		defaultValue 	= -123; // queries always return positive values
224	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
225	bool					error			= false;
226
227	// Query to larger buffer
228	{
229		glw::GLint buffer[2] = { defaultValue, defaultValue };
230
231		m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_NUM_SAMPLE_COUNTS to larger-than-needed buffer." << tcu::TestLog::EndMessage;
232		gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 2, buffer);
233		GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_NUM_SAMPLE_COUNTS");
234
235		if (buffer[1] != defaultValue)
236		{
237			m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: trailing values were modified." << tcu::TestLog::EndMessage;
238			error = true;
239		}
240	}
241
242	// Query to empty buffer
243	{
244		glw::GLint buffer[1] = { defaultValue };
245
246		m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_NUM_SAMPLE_COUNTS to zero-sized buffer." << tcu::TestLog::EndMessage;
247		gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 0, buffer);
248		GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_NUM_SAMPLE_COUNTS");
249
250		if (buffer[0] != defaultValue)
251		{
252			m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Query wrote over buffer bounds." << tcu::TestLog::EndMessage;
253			error = true;
254		}
255	}
256
257	// Result
258	if (!error)
259		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
260	else
261		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected buffer modification");
262
263	return STOP;
264}
265
266class SamplesBufferCase : public TestCase
267{
268public:
269					SamplesBufferCase 	(Context& ctx, const char* name, const char* desc);
270
271private:
272	IterateResult	iterate				(void);
273};
274
275SamplesBufferCase::SamplesBufferCase (Context& ctx, const char* name, const char* desc)
276	: TestCase(ctx, name, desc)
277{
278}
279
280SamplesBufferCase::IterateResult SamplesBufferCase::iterate (void)
281{
282	const glw::GLint 		defaultValue 	= -123; // queries always return positive values
283	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
284	bool					error			= false;
285
286	glw::GLint				numSampleCounts	= 0;
287
288	// Number of sample counts
289	{
290		gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts);
291		GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_NUM_SAMPLE_COUNTS");
292
293		m_testCtx.getLog() << tcu::TestLog::Message << "GL_NUM_SAMPLE_COUNTS = " << numSampleCounts << tcu::TestLog::EndMessage;
294	}
295
296	if (numSampleCounts < 1)
297	{
298		m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Format MUST support some multisample configuration, got GL_NUM_SAMPLE_COUNTS = " << numSampleCounts << tcu::TestLog::EndMessage;
299		error = true;
300	}
301	else
302	{
303		// Query to larger buffer
304		{
305			std::vector<glw::GLint> buffer(numSampleCounts + 1, defaultValue);
306
307			m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_SAMPLES to larger-than-needed buffer." << tcu::TestLog::EndMessage;
308			gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, (glw::GLsizei)buffer.size(), &buffer[0]);
309			GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_SAMPLES");
310
311			if (buffer.back() != defaultValue)
312			{
313				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: trailing value was modified." << tcu::TestLog::EndMessage;
314				error = true;
315			}
316		}
317
318		// Query to smaller buffer
319		if (numSampleCounts > 2)
320		{
321			glw::GLint buffer[3] = { defaultValue, defaultValue, defaultValue };
322
323			m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_SAMPLES to buffer with bufSize=2." << tcu::TestLog::EndMessage;
324			gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 2, buffer);
325			GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_SAMPLES");
326
327			if (buffer[2] != defaultValue)
328			{
329				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Query wrote over buffer bounds." << tcu::TestLog::EndMessage;
330				error = true;
331			}
332		}
333
334		// Query to empty buffer
335		{
336			glw::GLint buffer[1] = { defaultValue };
337
338			m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_SAMPLES to zero-sized buffer." << tcu::TestLog::EndMessage;
339			gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 0, buffer);
340			GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_SAMPLES");
341
342			if (buffer[0] != defaultValue)
343			{
344				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Query wrote over buffer bounds." << tcu::TestLog::EndMessage;
345				error = true;
346			}
347		}
348	}
349
350	// Result
351	if (!error)
352		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
353	else
354		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected buffer modification");
355
356	return STOP;
357}
358
359} // anonymous
360
361InternalFormatQueryTests::InternalFormatQueryTests (Context& context)
362	: TestCaseGroup(context, "internal_format", "Internal format queries")
363{
364}
365
366InternalFormatQueryTests::~InternalFormatQueryTests (void)
367{
368}
369
370void InternalFormatQueryTests::init (void)
371{
372	static const struct InternalFormat
373	{
374		const char*						name;
375		glw::GLenum						format;
376		FormatSamplesCase::FormatType	type;
377	} internalFormats[] =
378	{
379		// color renderable
380		{ "r8",						GL_R8,					FormatSamplesCase::FORMAT_COLOR			},
381		{ "rg8",					GL_RG8,					FormatSamplesCase::FORMAT_COLOR			},
382		{ "rgb8",					GL_RGB8,				FormatSamplesCase::FORMAT_COLOR			},
383		{ "rgb565",					GL_RGB565,				FormatSamplesCase::FORMAT_COLOR			},
384		{ "rgba4",					GL_RGBA4,				FormatSamplesCase::FORMAT_COLOR			},
385		{ "rgb5_a1",				GL_RGB5_A1,				FormatSamplesCase::FORMAT_COLOR			},
386		{ "rgba8",					GL_RGBA8,				FormatSamplesCase::FORMAT_COLOR			},
387		{ "rgb10_a2",				GL_RGB10_A2,			FormatSamplesCase::FORMAT_COLOR			},
388		{ "rgb10_a2ui",				GL_RGB10_A2UI,			FormatSamplesCase::FORMAT_INT			},
389		{ "srgb8_alpha8",			GL_SRGB8_ALPHA8,		FormatSamplesCase::FORMAT_COLOR			},
390		{ "r8i",					GL_R8I,					FormatSamplesCase::FORMAT_INT			},
391		{ "r8ui",					GL_R8UI,				FormatSamplesCase::FORMAT_INT			},
392		{ "r16i",					GL_R16I,				FormatSamplesCase::FORMAT_INT			},
393		{ "r16ui",					GL_R16UI,				FormatSamplesCase::FORMAT_INT			},
394		{ "r32i",					GL_R32I,				FormatSamplesCase::FORMAT_INT			},
395		{ "r32ui",					GL_R32UI,				FormatSamplesCase::FORMAT_INT			},
396		{ "rg8i",					GL_RG8I,				FormatSamplesCase::FORMAT_INT			},
397		{ "rg8ui",					GL_RG8UI,				FormatSamplesCase::FORMAT_INT			},
398		{ "rg16i",					GL_RG16I,				FormatSamplesCase::FORMAT_INT			},
399		{ "rg16ui",					GL_RG16UI,				FormatSamplesCase::FORMAT_INT			},
400		{ "rg32i",					GL_RG32I,				FormatSamplesCase::FORMAT_INT			},
401		{ "rg32ui",					GL_RG32UI,				FormatSamplesCase::FORMAT_INT			},
402		{ "rgba8i",					GL_RGBA8I,				FormatSamplesCase::FORMAT_INT			},
403		{ "rgba8ui",				GL_RGBA8UI,				FormatSamplesCase::FORMAT_INT			},
404		{ "rgba16i",				GL_RGBA16I,				FormatSamplesCase::FORMAT_INT			},
405		{ "rgba16ui",				GL_RGBA16UI,			FormatSamplesCase::FORMAT_INT			},
406		{ "rgba32i",				GL_RGBA32I,				FormatSamplesCase::FORMAT_INT			},
407		{ "rgba32ui",				GL_RGBA32UI,			FormatSamplesCase::FORMAT_INT			},
408
409		// float formats
410		{ "r16f",					GL_R16F,				FormatSamplesCase::FORMAT_COLOR			},
411		{ "rg16f",					GL_RG16F,				FormatSamplesCase::FORMAT_COLOR			},
412		{ "rgba16f",				GL_RGBA16F,				FormatSamplesCase::FORMAT_COLOR			},
413		{ "r32f",					GL_R32F,				FormatSamplesCase::FORMAT_INT			},
414		{ "rg32f",					GL_RG32F,				FormatSamplesCase::FORMAT_INT			},
415		{ "rgba32f",				GL_RGBA32F,				FormatSamplesCase::FORMAT_INT			},
416		{ "r11f_g11f_b10f",			GL_R11F_G11F_B10F,		FormatSamplesCase::FORMAT_COLOR			},
417
418		// depth renderable
419		{ "depth_component16",		GL_DEPTH_COMPONENT16,	FormatSamplesCase::FORMAT_DEPTH_STENCIL	},
420		{ "depth_component24",		GL_DEPTH_COMPONENT24,	FormatSamplesCase::FORMAT_DEPTH_STENCIL	},
421		{ "depth_component32f",		GL_DEPTH_COMPONENT32F,	FormatSamplesCase::FORMAT_DEPTH_STENCIL	},
422		{ "depth24_stencil8",		GL_DEPTH24_STENCIL8,	FormatSamplesCase::FORMAT_DEPTH_STENCIL	},
423		{ "depth32f_stencil8",		GL_DEPTH32F_STENCIL8,	FormatSamplesCase::FORMAT_DEPTH_STENCIL	},
424
425		// stencil renderable
426		{ "stencil_index8",			GL_STENCIL_INDEX8,		FormatSamplesCase::FORMAT_DEPTH_STENCIL	}
427		// DEPTH24_STENCIL8,  duplicate
428		// DEPTH32F_STENCIL8  duplicate
429	};
430
431	static const struct
432	{
433		const char*	name;
434		deUint32	target;
435	} textureTargets[] =
436	{
437		{ "renderbuffer",					GL_RENDERBUFFER					},
438		{ "texture_2d_multisample",			GL_TEXTURE_2D_MULTISAMPLE		},
439		{ "texture_2d_multisample_array",	GL_TEXTURE_2D_MULTISAMPLE_ARRAY	},
440	};
441
442	for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(textureTargets); ++groupNdx)
443	{
444		tcu::TestCaseGroup* const	group		= new tcu::TestCaseGroup(m_testCtx, textureTargets[groupNdx].name, glu::getInternalFormatTargetName(textureTargets[groupNdx].target));
445		const glw::GLenum			texTarget	= textureTargets[groupNdx].target;
446
447		addChild(group);
448
449		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(internalFormats); ++caseNdx)
450		{
451			const std::string name = std::string(internalFormats[caseNdx].name) + "_samples";
452			const std::string desc = std::string("Verify GL_SAMPLES of ") + internalFormats[caseNdx].name;
453
454			group->addChild(new FormatSamplesCase(m_context, name.c_str(), desc.c_str(), texTarget, internalFormats[caseNdx].format, internalFormats[caseNdx].type));
455		}
456	}
457
458	// Check buffer sizes are honored
459	{
460		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "partial_query", "Query data to too short a buffer");
461
462		addChild(group);
463
464		group->addChild(new NumSampleCountsBufferCase	(m_context, "num_sample_counts", 	"Query GL_NUM_SAMPLE_COUNTS to too short a buffer"));
465		group->addChild(new SamplesBufferCase			(m_context, "samples", 				"Query GL_SAMPLES to too short a buffer"));
466	}
467}
468
469} // Functional
470} // gles31
471} // deqp
472