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