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 
30 using namespace glw; // GLint and other GL types
31 using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard;
32 
33 namespace deqp
34 {
35 namespace gles3
36 {
37 namespace Functional
38 {
39 namespace
40 {
41 
checkIntEquals(tcu::TestContext & testCtx,GLint got,GLint expected)42 void 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 
checkIntEquals(tcu::TestContext & testCtx,GLint64 got,GLint64 expected)54 void 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 
66 class TransformFeedbackCase : public ApiCase
67 {
68 public:
TransformFeedbackCase(Context & context,const char * name,const char * description)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 
test(void)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 
135 class TransformFeedbackBufferBindingCase : public TransformFeedbackCase
136 {
137 public:
TransformFeedbackBufferBindingCase(Context & context,const char * name,const char * description)138 	TransformFeedbackBufferBindingCase (Context& context, const char* name, const char* description)
139 		: TransformFeedbackCase(context, name, description)
140 	{
141 	}
142 
testTransformFeedback(void)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 
180 class TransformFeedbackBufferBufferCase : public TransformFeedbackCase
181 {
182 public:
TransformFeedbackBufferBufferCase(Context & context,const char * name,const char * description)183 	TransformFeedbackBufferBufferCase (Context& context, const char* name, const char* description)
184 		: TransformFeedbackCase(context, name, description)
185 	{
186 	}
187 
testTransformFeedback(void)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 
242 class UniformBufferCase : public ApiCase
243 {
244 public:
UniformBufferCase(Context & context,const char * name,const char * description)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 
test(void)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 
295 protected:
296 	GLuint	m_program;
297 };
298 
299 class UniformBufferBindingCase : public UniformBufferCase
300 {
301 public:
UniformBufferBindingCase(Context & context,const char * name,const char * description)302 	UniformBufferBindingCase (Context& context, const char* name, const char* description)
303 		: UniformBufferCase(context, name, description)
304 	{
305 	}
306 
testUniformBuffers(void)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 
342 class UniformBufferBufferCase : public UniformBufferCase
343 {
344 public:
UniformBufferBufferCase(Context & context,const char * name,const char * description)345 	UniformBufferBufferCase (Context& context, const char* name, const char* description)
346 		: UniformBufferCase(context, name, description)
347 	{
348 	}
349 
testUniformBuffers(void)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 
GetAlignment()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 
IndexedStateQueryTests(Context & context)431 IndexedStateQueryTests::IndexedStateQueryTests (Context& context)
432 	: TestCaseGroup(context, "indexed", "Indexed Integer Values")
433 {
434 }
435 
init(void)436 void 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