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		checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_INTERNAL_FORMAT, GL_RGBA4);
178		expectError(GL_NO_ERROR);
179
180		const GLenum requiredColorformats[] =
181		{
182			GL_R8, GL_RG8, GL_RGB8, GL_RGB565, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2,
183			GL_RGB10_A2UI, GL_SRGB8_ALPHA8, GL_R8I, GL_R8UI, GL_R16I, GL_R16UI, GL_R32I, GL_R32UI,
184			GL_RG8I, GL_RG8UI, GL_RG16I, GL_RG16UI, GL_RG32I, GL_RG32UI, GL_RGBA8I, GL_RGBA8UI,
185			GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI
186		};
187
188		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requiredColorformats); ++ndx)
189		{
190			glRenderbufferStorage(GL_RENDERBUFFER, requiredColorformats[ndx], 128, 128);
191			expectError(GL_NO_ERROR);
192
193			checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_INTERNAL_FORMAT, requiredColorformats[ndx]);
194		}
195
196		glDeleteRenderbuffers(1, &renderbufferID);
197	}
198};
199
200class RboComponentSizeColorCase : public ApiCase
201{
202public:
203	RboComponentSizeColorCase (Context& context, const char* name, const char* description)
204		: ApiCase(context, name, description)
205	{
206	}
207
208	void test (void)
209	{
210		GLuint renderbufferID = 0;
211		glGenRenderbuffers(1, &renderbufferID);
212		glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
213		expectError(GL_NO_ERROR);
214
215		checkRenderbufferComponentSize(m_testCtx, *this, 0, 0, 0, 0, 0, 0);
216		expectError(GL_NO_ERROR);
217
218		const struct ColorFormat
219		{
220			GLenum	internalFormat;
221			int		bitsR, bitsG, bitsB, bitsA;
222		} requiredColorFormats[] =
223		{
224			{ GL_R8,			8,	0,	0,	0	},
225			{ GL_RG8,			8,	8,	0,	0	},
226			{ GL_RGB8,			8,	8,	8,	0	},
227			{ GL_RGB565,		5,	6,	5,	0	},
228			{ GL_RGBA4,			4,	4,	4,	4	},
229			{ GL_RGB5_A1, 		5,	5,	5,	1	},
230			{ GL_RGBA8,			8,	8,	8,	8	},
231			{ GL_RGB10_A2,		10, 10, 10, 2	},
232			{ GL_RGB10_A2UI,	10, 10, 10, 2	},
233			{ GL_SRGB8_ALPHA8,	8,	8,	8,	8	},
234			{ GL_R8I,			8,	0,	0,	0	},
235			{ GL_R8UI,			8,	0,	0,	0	},
236			{ GL_R16I,			16, 0,	0,	0	},
237			{ GL_R16UI,			16, 0,	0,	0	},
238			{ GL_R32I,			32, 0,	0,	0	},
239			{ GL_R32UI,			32, 0,	0,	0	},
240			{ GL_RG8I,			8,	8,	0,	0	},
241			{ GL_RG8UI,			8,	8,	0,	0	},
242			{ GL_RG16I,			16, 16, 0,	0	},
243			{ GL_RG16UI,		16, 16, 0,	0	},
244			{ GL_RG32I,			32, 32, 0,	0	},
245			{ GL_RG32UI,		32, 32, 0,	0	},
246			{ GL_RGBA8I,		8,	8,	8,	8	},
247			{ GL_RGBA8UI,		8,	8,	8,	8	},
248			{ GL_RGBA16I,		16, 16, 16, 16	},
249			{ GL_RGBA16UI,		16, 16, 16, 16	},
250			{ GL_RGBA32I,		32, 32, 32, 32	},
251			{ GL_RGBA32UI,		32, 32, 32, 32	}
252		};
253
254		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requiredColorFormats); ++ndx)
255		{
256			glRenderbufferStorage(GL_RENDERBUFFER, requiredColorFormats[ndx].internalFormat, 128, 128);
257			expectError(GL_NO_ERROR);
258
259			checkRenderbufferComponentSize(m_testCtx, *this, requiredColorFormats[ndx].bitsR, requiredColorFormats[ndx].bitsG, requiredColorFormats[ndx].bitsB, requiredColorFormats[ndx].bitsA, -1, -1);
260		}
261
262		glDeleteRenderbuffers(1, &renderbufferID);
263	}
264};
265
266class RboComponentSizeDepthCase : public ApiCase
267{
268public:
269	RboComponentSizeDepthCase (Context& context, const char* name, const char* description)
270		: ApiCase(context, name, description)
271	{
272	}
273
274	void test (void)
275	{
276		using tcu::TestLog;
277
278		GLuint renderbufferID = 0;
279		glGenRenderbuffers(1, &renderbufferID);
280		glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
281		expectError(GL_NO_ERROR);
282
283		const struct DepthFormat
284		{
285			GLenum	internalFormat;
286			int		dbits;
287			int		sbits;
288		} requiredDepthFormats[] =
289		{
290			{ GL_DEPTH_COMPONENT16,		16, 0 },
291			{ GL_DEPTH_COMPONENT24,		24, 0 },
292			{ GL_DEPTH_COMPONENT32F,	32, 0 },
293			{ GL_DEPTH24_STENCIL8,		24, 8 },
294			{ GL_DEPTH32F_STENCIL8,		32, 8 },
295		};
296
297		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requiredDepthFormats); ++ndx)
298		{
299			glRenderbufferStorage(GL_RENDERBUFFER, requiredDepthFormats[ndx].internalFormat, 128, 128);
300			expectError(GL_NO_ERROR);
301
302			checkRenderbufferComponentSize(m_testCtx, *this, -1, -1, -1, -1, requiredDepthFormats[ndx].dbits, requiredDepthFormats[ndx].sbits);
303		}
304
305		// STENCIL_INDEX8 is required, in that case sBits >= 8
306		{
307			glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, 128, 128);
308			expectError(GL_NO_ERROR);
309
310			StateQueryMemoryWriteGuard<GLint> state;
311			glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_STENCIL_SIZE, &state);
312
313			if (state.verifyValidity(m_testCtx) && state < 8)
314			{
315				m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected greater or equal to 8; got " << state << TestLog::EndMessage;
316				if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
317					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
318			}
319		}
320
321		glDeleteRenderbuffers(1, &renderbufferID);
322	}
323};
324
325class RboSamplesCase : public ApiCase
326{
327public:
328	RboSamplesCase (Context& context, const char* name, const char* description)
329		: ApiCase(context, name, description)
330	{
331	}
332
333	void test (void)
334	{
335		GLuint renderbufferID = 0;
336		glGenRenderbuffers(1, &renderbufferID);
337		glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
338		expectError(GL_NO_ERROR);
339
340		checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_SAMPLES, 0);
341		expectError(GL_NO_ERROR);
342
343		StateQueryMemoryWriteGuard<GLint> max_samples;
344		glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
345		if (!max_samples.verifyValidity(m_testCtx))
346			return;
347
348		// 0 samples is a special case
349		{
350			glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, 128, 128);
351			expectError(GL_NO_ERROR);
352
353			checkRenderbufferParam(m_testCtx, *this, GL_RENDERBUFFER_SAMPLES, 0);
354		}
355
356		// test [1, n] samples
357		for (int samples = 1; samples <= max_samples; ++samples)
358		{
359			glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, 128, 128);
360			expectError(GL_NO_ERROR);
361
362			checkRenderbufferParamGreaterOrEqual(m_testCtx, *this, GL_RENDERBUFFER_SAMPLES, samples);
363		}
364
365		glDeleteRenderbuffers(1, &renderbufferID);
366	}
367};
368
369} // anonymous
370
371
372RboStateQueryTests::RboStateQueryTests (Context& context)
373	: TestCaseGroup(context, "rbo", "Rbo State Query tests")
374{
375}
376
377void RboStateQueryTests::init (void)
378{
379	addChild(new RboSizeCase				(m_context, "renderbuffer_size",					"RENDERBUFFER_WIDTH and RENDERBUFFER_HEIGHT"));
380	addChild(new RboInternalFormatCase		(m_context, "renderbuffer_internal_format",			"RENDERBUFFER_INTERNAL_FORMAT"));
381	addChild(new RboComponentSizeColorCase	(m_context, "renderbuffer_component_size_color",	"RENDERBUFFER_x_SIZE"));
382	addChild(new RboComponentSizeDepthCase	(m_context, "renderbuffer_component_size_depth",	"RENDERBUFFER_x_SIZE"));
383	addChild(new RboSamplesCase				(m_context, "renderbuffer_samples",					"RENDERBUFFER_SAMPLES"));
384}
385
386} // Functional
387} // gles3
388} // deqp
389