1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 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 Rbo state query tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fRboStateQueryTests.hpp"
25#include "glsStateQueryUtil.hpp"
26#include "es3fApiCase.hpp"
27#include "gluRenderContext.hpp"
28#include "glwEnums.hpp"
29#include "glwFunctions.hpp"
30#include "deRandom.hpp"
31#include "deMath.h"
32
33using namespace glw; // GLint and other GL types
34using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard;
35
36
37namespace deqp
38{
39namespace gles3
40{
41namespace Functional
42{
43namespace
44{
45
46void checkRenderbufferComponentSize (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, int r, int g, int b, int a, int d, int s)
47{
48	using tcu::TestLog;
49
50	const int referenceSizes[] = {r, g, b, a, d, s};
51	const GLenum paramNames[] =
52	{
53		GL_RENDERBUFFER_RED_SIZE,
54		GL_RENDERBUFFER_GREEN_SIZE,
55		GL_RENDERBUFFER_BLUE_SIZE,
56		GL_RENDERBUFFER_ALPHA_SIZE,
57		GL_RENDERBUFFER_DEPTH_SIZE,
58		GL_RENDERBUFFER_STENCIL_SIZE
59	};
60
61	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(referenceSizes) == DE_LENGTH_OF_ARRAY(paramNames));
62
63	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(referenceSizes); ++ndx)
64	{
65		if (referenceSizes[ndx] == -1)
66			continue;
67
68		StateQueryMemoryWriteGuard<GLint> state;
69		gl.glGetRenderbufferParameteriv(GL_RENDERBUFFER, paramNames[ndx], &state);
70
71		if (!state.verifyValidity(testCtx))
72			return;
73
74		if (state < referenceSizes[ndx])
75		{
76			testCtx.getLog() << TestLog::Message << "// ERROR: Expected greater or equal to " << referenceSizes[ndx] << "; got " << state << TestLog::EndMessage;
77			if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
78				testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
79		}
80	}
81}
82
83void checkIntEquals (tcu::TestContext& testCtx, GLint got, GLint expected)
84{
85	using tcu::TestLog;
86
87	if (got != expected)
88	{
89		testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage;
90		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
91			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
92	}
93}
94
95void checkIntGreaterOrEqual (tcu::TestContext& testCtx, GLint got, GLint expected)
96{
97	using tcu::TestLog;
98
99	if (got < expected)
100	{
101		testCtx.getLog() << TestLog::Message << "// ERROR: Expected greater or equal to " << expected << "; got " << got << TestLog::EndMessage;
102		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
103			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
104	}
105}
106
107void checkRenderbufferParam (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLenum pname, GLenum reference)
108{
109	StateQueryMemoryWriteGuard<GLint> state;
110	gl.glGetRenderbufferParameteriv(GL_RENDERBUFFER, pname, &state);
111
112	if (state.verifyValidity(testCtx))
113		checkIntEquals(testCtx, state, reference);
114}
115
116void checkRenderbufferParamGreaterOrEqual (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLenum pname, GLenum reference)
117{
118	StateQueryMemoryWriteGuard<GLint> state;
119	gl.glGetRenderbufferParameteriv(GL_RENDERBUFFER, pname, &state);
120
121	if (state.verifyValidity(testCtx))
122		checkIntGreaterOrEqual(testCtx, state, reference);
123}
124
125class RboSizeCase : public ApiCase
126{
127public:
128	RboSizeCase (Context& context, const char* name, const char* description)
129		: ApiCase(context, name, description)
130	{
131	}
132
133	void test (void)
134	{
135		de::Random rnd(0xabcdef);
136
137		GLuint renderbufferID = 0;
138		glGenRenderbuffers(1, &renderbufferID);
139		glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
140		expectError(GL_NO_ERROR);
141
142		checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_WIDTH,		0);
143		checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_HEIGHT,	0);
144		expectError(GL_NO_ERROR);
145
146		const int numIterations = 60;
147		for (int i = 0; i < numIterations; ++i)
148		{
149			const GLint w = rnd.getInt(0, 128);
150			const GLint h = rnd.getInt(0, 128);
151
152			glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, w, h);
153
154			checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_WIDTH,		w);
155			checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_HEIGHT,	h);
156		}
157
158		glDeleteRenderbuffers(1, &renderbufferID);
159	}
160};
161
162class RboInternalFormatCase : public ApiCase
163{
164public:
165	RboInternalFormatCase (Context& context, const char* name, const char* description)
166		: ApiCase(context, name, description)
167	{
168	}
169
170	void test (void)
171	{
172		GLuint renderbufferID = 0;
173		glGenRenderbuffers(1, &renderbufferID);
174		glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
175		expectError(GL_NO_ERROR);
176
177		const glu::ContextType& contextType = m_context.getRenderContext().getType();
178		const bool isCoreGL45 = glu::contextSupports(contextType, glu::ApiType::core(4, 5));
179
180		GLenum initialValue = isCoreGL45 ? GL_RGBA : GL_RGBA4;
181		checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_INTERNAL_FORMAT, initialValue);
182		expectError(GL_NO_ERROR);
183
184		const GLenum requiredColorformats[] =
185		{
186			GL_R8, GL_RG8, GL_RGB8, GL_RGB565, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2,
187			GL_RGB10_A2UI, GL_SRGB8_ALPHA8, GL_R8I, GL_R8UI, GL_R16I, GL_R16UI, GL_R32I, GL_R32UI,
188			GL_RG8I, GL_RG8UI, GL_RG16I, GL_RG16UI, GL_RG32I, GL_RG32UI, GL_RGBA8I, GL_RGBA8UI,
189			GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI
190		};
191
192		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requiredColorformats); ++ndx)
193		{
194			glRenderbufferStorage(GL_RENDERBUFFER, requiredColorformats[ndx], 128, 128);
195			expectError(GL_NO_ERROR);
196
197			checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_INTERNAL_FORMAT, requiredColorformats[ndx]);
198		}
199
200		glDeleteRenderbuffers(1, &renderbufferID);
201	}
202};
203
204class RboComponentSizeColorCase : public ApiCase
205{
206public:
207	RboComponentSizeColorCase (Context& context, const char* name, const char* description)
208		: ApiCase(context, name, description)
209	{
210	}
211
212	void test (void)
213	{
214		GLuint renderbufferID = 0;
215		glGenRenderbuffers(1, &renderbufferID);
216		glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
217		expectError(GL_NO_ERROR);
218
219		checkRenderbufferComponentSize(m_testCtx, *this, 0, 0, 0, 0, 0, 0);
220		expectError(GL_NO_ERROR);
221
222		const struct ColorFormat
223		{
224			GLenum	internalFormat;
225			int		bitsR, bitsG, bitsB, bitsA;
226		} requiredColorFormats[] =
227		{
228			{ GL_R8,			8,	0,	0,	0	},
229			{ GL_RG8,			8,	8,	0,	0	},
230			{ GL_RGB8,			8,	8,	8,	0	},
231			{ GL_RGB565,		5,	6,	5,	0	},
232			{ GL_RGBA4,			4,	4,	4,	4	},
233			{ GL_RGB5_A1,		5,	5,	5,	1	},
234			{ GL_RGBA8,			8,	8,	8,	8	},
235			{ GL_RGB10_A2,		10, 10, 10, 2	},
236			{ GL_RGB10_A2UI,	10, 10, 10, 2	},
237			{ GL_SRGB8_ALPHA8,	8,	8,	8,	8	},
238			{ GL_R8I,			8,	0,	0,	0	},
239			{ GL_R8UI,			8,	0,	0,	0	},
240			{ GL_R16I,			16, 0,	0,	0	},
241			{ GL_R16UI,			16, 0,	0,	0	},
242			{ GL_R32I,			32, 0,	0,	0	},
243			{ GL_R32UI,			32, 0,	0,	0	},
244			{ GL_RG8I,			8,	8,	0,	0	},
245			{ GL_RG8UI,			8,	8,	0,	0	},
246			{ GL_RG16I,			16, 16, 0,	0	},
247			{ GL_RG16UI,		16, 16, 0,	0	},
248			{ GL_RG32I,			32, 32, 0,	0	},
249			{ GL_RG32UI,		32, 32, 0,	0	},
250			{ GL_RGBA8I,		8,	8,	8,	8	},
251			{ GL_RGBA8UI,		8,	8,	8,	8	},
252			{ GL_RGBA16I,		16, 16, 16, 16	},
253			{ GL_RGBA16UI,		16, 16, 16, 16	},
254			{ GL_RGBA32I,		32, 32, 32, 32	},
255			{ GL_RGBA32UI,		32, 32, 32, 32	}
256		};
257
258		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requiredColorFormats); ++ndx)
259		{
260			glRenderbufferStorage(GL_RENDERBUFFER, requiredColorFormats[ndx].internalFormat, 128, 128);
261			expectError(GL_NO_ERROR);
262
263			checkRenderbufferComponentSize(m_testCtx, *this, requiredColorFormats[ndx].bitsR, requiredColorFormats[ndx].bitsG, requiredColorFormats[ndx].bitsB, requiredColorFormats[ndx].bitsA, -1, -1);
264		}
265
266		glDeleteRenderbuffers(1, &renderbufferID);
267	}
268};
269
270class RboComponentSizeDepthCase : public ApiCase
271{
272public:
273	RboComponentSizeDepthCase (Context& context, const char* name, const char* description)
274		: ApiCase(context, name, description)
275	{
276	}
277
278	void test (void)
279	{
280		using tcu::TestLog;
281
282		GLuint renderbufferID = 0;
283		glGenRenderbuffers(1, &renderbufferID);
284		glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
285		expectError(GL_NO_ERROR);
286
287		const struct DepthFormat
288		{
289			GLenum	internalFormat;
290			int		dbits;
291			int		sbits;
292		} requiredDepthFormats[] =
293		{
294			{ GL_DEPTH_COMPONENT16,		16, 0 },
295			{ GL_DEPTH_COMPONENT24,		24, 0 },
296			{ GL_DEPTH_COMPONENT32F,	32, 0 },
297			{ GL_DEPTH24_STENCIL8,		24, 8 },
298			{ GL_DEPTH32F_STENCIL8,		32, 8 },
299		};
300
301		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requiredDepthFormats); ++ndx)
302		{
303			glRenderbufferStorage(GL_RENDERBUFFER, requiredDepthFormats[ndx].internalFormat, 128, 128);
304			expectError(GL_NO_ERROR);
305
306			checkRenderbufferComponentSize(m_testCtx, *this, -1, -1, -1, -1, requiredDepthFormats[ndx].dbits, requiredDepthFormats[ndx].sbits);
307		}
308
309		// STENCIL_INDEX8 is required, in that case sBits >= 8
310		{
311			glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, 128, 128);
312			expectError(GL_NO_ERROR);
313
314			StateQueryMemoryWriteGuard<GLint> state;
315			glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_STENCIL_SIZE, &state);
316
317			if (state.verifyValidity(m_testCtx) && state < 8)
318			{
319				m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected greater or equal to 8; got " << state << TestLog::EndMessage;
320				if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
321					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
322			}
323		}
324
325		glDeleteRenderbuffers(1, &renderbufferID);
326	}
327};
328
329class RboSamplesCase : public ApiCase
330{
331public:
332	RboSamplesCase (Context& context, const char* name, const char* description)
333		: ApiCase(context, name, description)
334	{
335	}
336
337	void test (void)
338	{
339		GLuint renderbufferID = 0;
340		glGenRenderbuffers(1, &renderbufferID);
341		glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
342		expectError(GL_NO_ERROR);
343
344		checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_SAMPLES, 0);
345		expectError(GL_NO_ERROR);
346
347		StateQueryMemoryWriteGuard<GLint> max_samples;
348		glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
349		if (!max_samples.verifyValidity(m_testCtx))
350			return;
351
352		// 0 samples is a special case
353		{
354			glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, 128, 128);
355			expectError(GL_NO_ERROR);
356
357			checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_SAMPLES, 0);
358		}
359
360		// test [1, n] samples
361		for (int samples = 1; samples <= max_samples; ++samples)
362		{
363			glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, 128, 128);
364			expectError(GL_NO_ERROR);
365
366			checkRenderbufferParamGreaterOrEqual(m_testCtx, *this, GL_RENDERBUFFER_SAMPLES, samples);
367		}
368
369		glDeleteRenderbuffers(1, &renderbufferID);
370	}
371};
372
373} // anonymous
374
375
376RboStateQueryTests::RboStateQueryTests (Context& context)
377	: TestCaseGroup(context, "rbo", "Rbo State Query tests")
378{
379}
380
381void RboStateQueryTests::init (void)
382{
383	addChild(new RboSizeCase				(m_context, "renderbuffer_size",					"RENDERBUFFER_WIDTH and RENDERBUFFER_HEIGHT"));
384	addChild(new RboInternalFormatCase		(m_context, "renderbuffer_internal_format",			"RENDERBUFFER_INTERNAL_FORMAT"));
385	addChild(new RboComponentSizeColorCase	(m_context, "renderbuffer_component_size_color",	"RENDERBUFFER_x_SIZE"));
386	addChild(new RboComponentSizeDepthCase	(m_context, "renderbuffer_component_size_depth",	"RENDERBUFFER_x_SIZE"));
387	addChild(new RboSamplesCase				(m_context, "renderbuffer_samples",					"RENDERBUFFER_SAMPLES"));
388}
389
390} // Functional
391} // gles3
392} // deqp
393