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