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 Indexed State Query tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fIndexedStateQueryTests.hpp"
25#include "es3fApiCase.hpp"
26#include "glsStateQueryUtil.hpp"
27#include "tcuRenderTarget.hpp"
28#include "glwEnums.hpp"
29
30using namespace glw; // GLint and other GL types
31using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard;
32
33namespace deqp
34{
35namespace gles3
36{
37namespace Functional
38{
39namespace
40{
41
42void checkIntEquals (tcu::TestContext& testCtx, GLint got, GLint expected)
43{
44	using tcu::TestLog;
45
46	if (got != expected)
47	{
48		testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage;
49		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
50			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
51	}
52}
53
54void checkIntEquals (tcu::TestContext& testCtx, GLint64 got, GLint64 expected)
55{
56	using tcu::TestLog;
57
58	if (got != expected)
59	{
60		testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage;
61		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
62			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
63	}
64}
65
66class TransformFeedbackCase : public ApiCase
67{
68public:
69	TransformFeedbackCase (Context& context, const char* name, const char* description)
70		: ApiCase(context, name, description)
71	{
72	}
73
74	virtual void testTransformFeedback (void) = DE_NULL;
75
76	void test (void)
77	{
78		static const char* transformFeedbackTestVertSource	=	"#version 300 es\n"
79																"out highp vec4 anotherOutput;\n"
80																"void main (void)\n"
81																"{\n"
82																"	gl_Position = vec4(0.0);\n"
83																"	anotherOutput = vec4(0.0);\n"
84																"}\n\0";
85		static const char* transformFeedbackTestFragSource	=	"#version 300 es\n"
86																"layout(location = 0) out mediump vec4 fragColor;"
87																"void main (void)\n"
88																"{\n"
89																"	fragColor = vec4(0.0);\n"
90																"}\n\0";
91
92		GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER);
93		GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER);
94
95		glShaderSource(shaderVert, 1, &transformFeedbackTestVertSource, DE_NULL);
96		glShaderSource(shaderFrag, 1, &transformFeedbackTestFragSource, DE_NULL);
97
98		glCompileShader(shaderVert);
99		glCompileShader(shaderFrag);
100		expectError(GL_NO_ERROR);
101
102		GLuint shaderProg = glCreateProgram();
103		glAttachShader(shaderProg, shaderVert);
104		glAttachShader(shaderProg, shaderFrag);
105
106		const char* transformFeedbackOutputs[] =
107		{
108			"gl_Position",
109			"anotherOutput"
110		};
111
112		glTransformFeedbackVaryings(shaderProg, 2, transformFeedbackOutputs, GL_INTERLEAVED_ATTRIBS);
113		glLinkProgram(shaderProg);
114		expectError(GL_NO_ERROR);
115
116		GLuint transformFeedbackId = 0;
117		glGenTransformFeedbacks(1, &transformFeedbackId);
118		glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackId);
119		expectError(GL_NO_ERROR);
120
121		testTransformFeedback();
122
123		// cleanup
124
125		glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
126
127		glDeleteTransformFeedbacks(1, &transformFeedbackId);
128		glDeleteShader(shaderVert);
129		glDeleteShader(shaderFrag);
130		glDeleteProgram(shaderProg);
131		expectError(GL_NO_ERROR);
132	}
133};
134
135class TransformFeedbackBufferBindingCase : public TransformFeedbackCase
136{
137public:
138	TransformFeedbackBufferBindingCase (Context& context, const char* name, const char* description)
139		: TransformFeedbackCase(context, name, description)
140	{
141	}
142
143	void testTransformFeedback (void)
144	{
145		const int feedbackPositionIndex = 0;
146		const int feedbackOutputIndex = 1;
147		const int feedbackIndex[2] = {feedbackPositionIndex, feedbackOutputIndex};
148
149		// bind bffers
150
151		GLuint feedbackBuffers[2];
152		glGenBuffers(2, feedbackBuffers);
153		expectError(GL_NO_ERROR);
154
155		for (int ndx = 0; ndx < 2; ++ndx)
156		{
157			glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[ndx]);
158			glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
159			glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackIndex[ndx], feedbackBuffers[ndx]);
160			expectError(GL_NO_ERROR);
161		}
162
163		// test TRANSFORM_FEEDBACK_BUFFER_BINDING
164
165		for (int ndx = 0; ndx < 2; ++ndx)
166		{
167			StateQueryMemoryWriteGuard<GLint> boundBuffer;
168			glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, feedbackIndex[ndx], &boundBuffer);
169			boundBuffer.verifyValidity(m_testCtx);
170			checkIntEquals(m_testCtx, boundBuffer, feedbackBuffers[ndx]);
171		}
172
173
174		// cleanup
175
176		glDeleteBuffers(2, feedbackBuffers);
177	}
178};
179
180class TransformFeedbackBufferBufferCase : public TransformFeedbackCase
181{
182public:
183	TransformFeedbackBufferBufferCase (Context& context, const char* name, const char* description)
184		: TransformFeedbackCase(context, name, description)
185	{
186	}
187
188	void testTransformFeedback (void)
189	{
190		const int feedbackPositionIndex = 0;
191		const int feedbackOutputIndex = 1;
192
193		const int rangeBufferOffset = 4;
194		const int rangeBufferSize = 8;
195
196		// bind buffers
197
198		GLuint feedbackBuffers[2];
199		glGenBuffers(2, feedbackBuffers);
200		expectError(GL_NO_ERROR);
201
202		glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[0]);
203		glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
204		glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackPositionIndex, feedbackBuffers[0]);
205		expectError(GL_NO_ERROR);
206
207		glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[1]);
208		glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
209		glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackOutputIndex, feedbackBuffers[1], rangeBufferOffset, rangeBufferSize);
210		expectError(GL_NO_ERROR);
211
212		// test TRANSFORM_FEEDBACK_BUFFER_START and TRANSFORM_FEEDBACK_BUFFER_SIZE
213
214		const struct BufferRequirements
215		{
216			GLint	index;
217			GLenum	pname;
218			GLint64 value;
219		} requirements[] =
220		{
221			{ feedbackPositionIndex,	GL_TRANSFORM_FEEDBACK_BUFFER_START, 0					},
222			{ feedbackPositionIndex,	GL_TRANSFORM_FEEDBACK_BUFFER_SIZE,	0					},
223			{ feedbackOutputIndex,		GL_TRANSFORM_FEEDBACK_BUFFER_START, rangeBufferOffset	},
224			{ feedbackOutputIndex,		GL_TRANSFORM_FEEDBACK_BUFFER_SIZE,	rangeBufferSize		}
225		};
226
227		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requirements); ++ndx)
228		{
229			StateQueryMemoryWriteGuard<GLint64> state;
230			glGetInteger64i_v(requirements[ndx].pname, requirements[ndx].index, &state);
231
232			if (state.verifyValidity(m_testCtx))
233				checkIntEquals(m_testCtx, state, requirements[ndx].value);
234		}
235
236		// cleanup
237
238		glDeleteBuffers(2, feedbackBuffers);
239	}
240};
241
242class UniformBufferCase : public ApiCase
243{
244public:
245	UniformBufferCase (Context& context, const char* name, const char* description)
246		: ApiCase	(context, name, description)
247		, m_program	(0)
248	{
249	}
250
251	virtual void testUniformBuffers (void) = DE_NULL;
252
253	void test (void)
254	{
255		static const char* testVertSource	=	"#version 300 es\n"
256												"uniform highp vec4 input1;\n"
257												"uniform highp vec4 input2;\n"
258												"void main (void)\n"
259												"{\n"
260												"	gl_Position = input1 + input2;\n"
261												"}\n\0";
262		static const char* testFragSource	=	"#version 300 es\n"
263												"layout(location = 0) out mediump vec4 fragColor;"
264												"void main (void)\n"
265												"{\n"
266												"	fragColor = vec4(0.0);\n"
267												"}\n\0";
268
269		GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER);
270		GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER);
271
272		glShaderSource(shaderVert, 1, &testVertSource, DE_NULL);
273		glShaderSource(shaderFrag, 1, &testFragSource, DE_NULL);
274
275		glCompileShader(shaderVert);
276		glCompileShader(shaderFrag);
277		expectError(GL_NO_ERROR);
278
279		m_program = glCreateProgram();
280		glAttachShader(m_program, shaderVert);
281		glAttachShader(m_program, shaderFrag);
282		glLinkProgram(m_program);
283		glUseProgram(m_program);
284		expectError(GL_NO_ERROR);
285
286		testUniformBuffers();
287
288		glUseProgram(0);
289		glDeleteShader(shaderVert);
290		glDeleteShader(shaderFrag);
291		glDeleteProgram(m_program);
292		expectError(GL_NO_ERROR);
293	}
294
295protected:
296	GLuint	m_program;
297};
298
299class UniformBufferBindingCase : public UniformBufferCase
300{
301public:
302	UniformBufferBindingCase (Context& context, const char* name, const char* description)
303		: UniformBufferCase(context, name, description)
304	{
305	}
306
307	void testUniformBuffers (void)
308	{
309		const char* uniformNames[] =
310		{
311			"input1",
312			"input2"
313		};
314		GLuint uniformIndices[2] = {0};
315		glGetUniformIndices(m_program, 2, uniformNames, uniformIndices);
316
317		GLuint buffers[2];
318		glGenBuffers(2, buffers);
319
320		for (int ndx = 0; ndx < 2; ++ndx)
321		{
322			glBindBuffer(GL_UNIFORM_BUFFER, buffers[ndx]);
323			glBufferData(GL_UNIFORM_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
324			glBindBufferBase(GL_UNIFORM_BUFFER, uniformIndices[ndx], buffers[ndx]);
325			expectError(GL_NO_ERROR);
326		}
327
328		for (int ndx = 0; ndx < 2; ++ndx)
329		{
330			StateQueryMemoryWriteGuard<GLint> boundBuffer;
331			glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, uniformIndices[ndx], &boundBuffer);
332
333			if (boundBuffer.verifyValidity(m_testCtx))
334				checkIntEquals(m_testCtx, boundBuffer, buffers[ndx]);
335			expectError(GL_NO_ERROR);
336		}
337
338		glDeleteBuffers(2, buffers);
339	}
340};
341
342class UniformBufferBufferCase : public UniformBufferCase
343{
344public:
345	UniformBufferBufferCase (Context& context, const char* name, const char* description)
346		: UniformBufferCase(context, name, description)
347	{
348	}
349
350	void testUniformBuffers (void)
351	{
352		const char* uniformNames[] =
353		{
354			"input1",
355			"input2"
356		};
357		GLuint uniformIndices[2] = {0};
358		glGetUniformIndices(m_program, 2, uniformNames, uniformIndices);
359
360		const GLint alignment = GetAlignment();
361		if (alignment == -1) // cannot continue without this
362			return;
363
364		m_testCtx.getLog() << tcu::TestLog::Message << "Alignment is " << alignment << tcu::TestLog::EndMessage;
365
366		int rangeBufferOffset		= alignment;
367		int rangeBufferSize			= alignment * 2;
368		int rangeBufferTotalSize	= rangeBufferOffset + rangeBufferSize + 8; // + 8 has no special meaning, just to make it != with the size of the range
369
370		GLuint buffers[2];
371		glGenBuffers(2, buffers);
372
373		glBindBuffer(GL_UNIFORM_BUFFER, buffers[0]);
374		glBufferData(GL_UNIFORM_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
375		glBindBufferBase(GL_UNIFORM_BUFFER, uniformIndices[0], buffers[0]);
376		expectError(GL_NO_ERROR);
377
378		glBindBuffer(GL_UNIFORM_BUFFER, buffers[1]);
379		glBufferData(GL_UNIFORM_BUFFER, rangeBufferTotalSize, DE_NULL, GL_DYNAMIC_DRAW);
380		glBindBufferRange(GL_UNIFORM_BUFFER, uniformIndices[1], buffers[1], rangeBufferOffset, rangeBufferSize);
381		expectError(GL_NO_ERROR);
382
383		// test UNIFORM_BUFFER_START and UNIFORM_BUFFER_SIZE
384
385		const struct BufferRequirements
386		{
387			GLuint	index;
388			GLenum	pname;
389			GLint64 value;
390		} requirements[] =
391		{
392			{ uniformIndices[0], GL_UNIFORM_BUFFER_START,	0					},
393			{ uniformIndices[0], GL_UNIFORM_BUFFER_SIZE,	0					},
394			{ uniformIndices[1], GL_UNIFORM_BUFFER_START,	rangeBufferOffset	},
395			{ uniformIndices[1], GL_UNIFORM_BUFFER_SIZE,	rangeBufferSize		}
396		};
397
398		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requirements); ++ndx)
399		{
400			StateQueryMemoryWriteGuard<GLint64> state;
401			glGetInteger64i_v(requirements[ndx].pname, requirements[ndx].index, &state);
402
403			if (state.verifyValidity(m_testCtx))
404				checkIntEquals(m_testCtx, state, requirements[ndx].value);
405			expectError(GL_NO_ERROR);
406		}
407
408		glDeleteBuffers(2, buffers);
409	}
410
411	int GetAlignment()
412	{
413		StateQueryMemoryWriteGuard<GLint> state;
414		glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &state);
415
416		if (!state.verifyValidity(m_testCtx))
417			return -1;
418
419		if (state <= 256)
420			return state;
421
422		m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: UNIFORM_BUFFER_OFFSET_ALIGNMENT has a maximum value of 256." << tcu::TestLog::EndMessage;
423		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid UNIFORM_BUFFER_OFFSET_ALIGNMENT value");
424
425		return -1;
426	}
427};
428
429} // anonymous
430
431IndexedStateQueryTests::IndexedStateQueryTests (Context& context)
432	: TestCaseGroup(context, "indexed", "Indexed Integer Values")
433{
434}
435
436void IndexedStateQueryTests::init (void)
437{
438	// transform feedback
439	addChild(new TransformFeedbackBufferBindingCase(m_context, "transform_feedback_buffer_binding", "TRANSFORM_FEEDBACK_BUFFER_BINDING"));
440	addChild(new TransformFeedbackBufferBufferCase(m_context, "transform_feedback_buffer_start_size", "TRANSFORM_FEEDBACK_BUFFER_START and TRANSFORM_FEEDBACK_BUFFER_SIZE"));
441
442	// uniform buffers
443	addChild(new UniformBufferBindingCase(m_context, "uniform_buffer_binding", "UNIFORM_BUFFER_BINDING"));
444	addChild(new UniformBufferBufferCase(m_context, "uniform_buffer_start_size", "UNIFORM_BUFFER_START and UNIFORM_BUFFER_SIZE"));
445}
446
447} // Functional
448} // gles3
449} // deqp
450