• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 		glGenTransformFeedbacks(2, transformFeedbacks);
117 		// Also store the default transform feedback in the array.
118 		transformFeedbacks[2] = 0;
119 		glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[0]);
120 		expectError(GL_NO_ERROR);
121 
122 		testTransformFeedback();
123 
124 		// cleanup
125 
126 		glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
127 
128 		glDeleteTransformFeedbacks(2, transformFeedbacks);
129 		glDeleteShader(shaderVert);
130 		glDeleteShader(shaderFrag);
131 		glDeleteProgram(shaderProg);
132 		expectError(GL_NO_ERROR);
133 	}
134 protected:
135 	GLuint transformFeedbacks[3];
136 };
137 
138 class TransformFeedbackBufferBindingCase : public TransformFeedbackCase
139 {
140 public:
TransformFeedbackBufferBindingCase(Context & context,const char * name,const char * description)141 	TransformFeedbackBufferBindingCase (Context& context, const char* name, const char* description)
142 		: TransformFeedbackCase(context, name, description)
143 	{
144 	}
145 
testTransformFeedback(void)146 	void testTransformFeedback (void)
147 	{
148 		const int feedbackPositionIndex = 0;
149 		const int feedbackOutputIndex = 1;
150 		const int feedbackIndex[2] = {feedbackPositionIndex, feedbackOutputIndex};
151 
152 		// bind bffers
153 
154 		GLuint feedbackBuffers[2];
155 		glGenBuffers(2, feedbackBuffers);
156 		expectError(GL_NO_ERROR);
157 
158 		for (int ndx = 0; ndx < 2; ++ndx)
159 		{
160 			glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[ndx]);
161 			glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
162 			glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackIndex[ndx], feedbackBuffers[ndx]);
163 			expectError(GL_NO_ERROR);
164 		}
165 
166 		// test TRANSFORM_FEEDBACK_BUFFER_BINDING
167 
168 		for (int ndx = 0; ndx < 2; ++ndx)
169 		{
170 			StateQueryMemoryWriteGuard<GLint> boundBuffer;
171 			glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, feedbackIndex[ndx], &boundBuffer);
172 			boundBuffer.verifyValidity(m_testCtx);
173 			checkIntEquals(m_testCtx, boundBuffer, feedbackBuffers[ndx]);
174 		}
175 
176 
177 		// cleanup
178 
179 		glDeleteBuffers(2, feedbackBuffers);
180 	}
181 };
182 
183 class TransformFeedbackBufferBufferCase : public TransformFeedbackCase
184 {
185 public:
TransformFeedbackBufferBufferCase(Context & context,const char * name,const char * description)186 	TransformFeedbackBufferBufferCase (Context& context, const char* name, const char* description)
187 		: TransformFeedbackCase(context, name, description)
188 	{
189 	}
190 
testTransformFeedback(void)191 	void testTransformFeedback (void)
192 	{
193 		const int feedbackPositionIndex = 0;
194 		const int feedbackOutputIndex = 1;
195 
196 		const int rangeBufferOffset = 4;
197 		const int rangeBufferSize = 8;
198 
199 		// bind buffers
200 
201 		GLuint feedbackBuffers[2];
202 		glGenBuffers(2, feedbackBuffers);
203 		expectError(GL_NO_ERROR);
204 
205 		glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[0]);
206 		glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
207 		glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackPositionIndex, feedbackBuffers[0]);
208 		expectError(GL_NO_ERROR);
209 
210 		glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[1]);
211 		glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
212 		glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackOutputIndex, feedbackBuffers[1], rangeBufferOffset, rangeBufferSize);
213 		expectError(GL_NO_ERROR);
214 
215 		// test TRANSFORM_FEEDBACK_BUFFER_START and TRANSFORM_FEEDBACK_BUFFER_SIZE
216 
217 		const struct BufferRequirements
218 		{
219 			GLint	index;
220 			GLenum	pname;
221 			GLint64 value;
222 		} requirements[] =
223 		{
224 			{ feedbackPositionIndex,	GL_TRANSFORM_FEEDBACK_BUFFER_START, 0					},
225 			{ feedbackPositionIndex,	GL_TRANSFORM_FEEDBACK_BUFFER_SIZE,	0					},
226 			{ feedbackOutputIndex,		GL_TRANSFORM_FEEDBACK_BUFFER_START, rangeBufferOffset	},
227 			{ feedbackOutputIndex,		GL_TRANSFORM_FEEDBACK_BUFFER_SIZE,	rangeBufferSize		}
228 		};
229 
230 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requirements); ++ndx)
231 		{
232 			StateQueryMemoryWriteGuard<GLint64> state;
233 			glGetInteger64i_v(requirements[ndx].pname, requirements[ndx].index, &state);
234 
235 			if (state.verifyValidity(m_testCtx))
236 				checkIntEquals(m_testCtx, state, requirements[ndx].value);
237 		}
238 
239 		// cleanup
240 
241 		glDeleteBuffers(2, feedbackBuffers);
242 	}
243 };
244 
245 class TransformFeedbackSwitchingBufferCase : public TransformFeedbackCase
246 {
247 public:
TransformFeedbackSwitchingBufferCase(Context & context,const char * name,const char * description)248 	TransformFeedbackSwitchingBufferCase (Context& context, const char* name, const char* description)
249 		: TransformFeedbackCase(context, name, description)
250 	{
251 	}
252 
testTransformFeedback(void)253 	void testTransformFeedback (void)
254 	{
255 		GLuint feedbackBuffers[3];
256 		glGenBuffers(3, feedbackBuffers);
257 		expectError(GL_NO_ERROR);
258 
259 		for (int i = 0; i < 3; ++i)
260 		{
261 			glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[i]);
262 			expectError(GL_NO_ERROR);
263 			GLint value;
264 			glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &value);
265 			expectError(GL_NO_ERROR);
266 			checkIntEquals(m_testCtx, value, 0);
267 			glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, feedbackBuffers[i]);
268 			expectError(GL_NO_ERROR);
269 			// glBindBufferBase should also set the generic binding point.
270 			glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &value);
271 			expectError(GL_NO_ERROR);
272 			checkIntEquals(m_testCtx, value, feedbackBuffers[i]);
273 		}
274 
275 		for (int i = 0; i < 3; ++i)
276 		{
277 			// glBindTransformFeedback should change the indexed binding points, but
278 			// not the generic one.
279 			glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[i]);
280 			expectError(GL_NO_ERROR);
281 			GLint value;
282 			glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &value);
283 			expectError(GL_NO_ERROR);
284 			checkIntEquals(m_testCtx, value, feedbackBuffers[i]);
285 			glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &value);
286 			expectError(GL_NO_ERROR);
287 			// Should be unchanged.
288 			checkIntEquals(m_testCtx, value, feedbackBuffers[2]);
289 		}
290 
291 		glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[0]);
292 		expectError(GL_NO_ERROR);
293 		glDeleteBuffers(3, feedbackBuffers);
294 		expectError(GL_NO_ERROR);
295 
296 		// After deleting buffers the bound state should be changed but unbound
297 		// state should be unchanged.
298 
299 		GLint value;
300 		glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &value);
301 		expectError(GL_NO_ERROR);
302 		checkIntEquals(m_testCtx, value, 0);
303 		glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &value);
304 		expectError(GL_NO_ERROR);
305 		checkIntEquals(m_testCtx, value, 0);
306 
307 		for (int i = 1; i < 3; ++i)
308 		{
309 			glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[i]);
310 			expectError(GL_NO_ERROR);
311 			glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &value);
312 			expectError(GL_NO_ERROR);
313 			checkIntEquals(m_testCtx, value, feedbackBuffers[i]);
314 			glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &value);
315 			expectError(GL_NO_ERROR);
316 			checkIntEquals(m_testCtx, value, 0);
317 		}
318 	}
319 };
320 
321 class UniformBufferCase : public ApiCase
322 {
323 public:
UniformBufferCase(Context & context,const char * name,const char * description)324 	UniformBufferCase (Context& context, const char* name, const char* description)
325 		: ApiCase	(context, name, description)
326 		, m_program	(0)
327 	{
328 	}
329 
330 	virtual void testUniformBuffers (void) = DE_NULL;
331 
test(void)332 	void test (void)
333 	{
334 		static const char* testVertSource	=	"#version 300 es\n"
335 												"uniform highp vec4 input1;\n"
336 												"uniform highp vec4 input2;\n"
337 												"void main (void)\n"
338 												"{\n"
339 												"	gl_Position = input1 + input2;\n"
340 												"}\n\0";
341 		static const char* testFragSource	=	"#version 300 es\n"
342 												"layout(location = 0) out mediump vec4 fragColor;"
343 												"void main (void)\n"
344 												"{\n"
345 												"	fragColor = vec4(0.0);\n"
346 												"}\n\0";
347 
348 		GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER);
349 		GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER);
350 
351 		glShaderSource(shaderVert, 1, &testVertSource, DE_NULL);
352 		glShaderSource(shaderFrag, 1, &testFragSource, DE_NULL);
353 
354 		glCompileShader(shaderVert);
355 		glCompileShader(shaderFrag);
356 		expectError(GL_NO_ERROR);
357 
358 		m_program = glCreateProgram();
359 		glAttachShader(m_program, shaderVert);
360 		glAttachShader(m_program, shaderFrag);
361 		glLinkProgram(m_program);
362 		glUseProgram(m_program);
363 		expectError(GL_NO_ERROR);
364 
365 		testUniformBuffers();
366 
367 		glUseProgram(0);
368 		glDeleteShader(shaderVert);
369 		glDeleteShader(shaderFrag);
370 		glDeleteProgram(m_program);
371 		expectError(GL_NO_ERROR);
372 	}
373 
374 protected:
375 	GLuint	m_program;
376 };
377 
378 class UniformBufferBindingCase : public UniformBufferCase
379 {
380 public:
UniformBufferBindingCase(Context & context,const char * name,const char * description)381 	UniformBufferBindingCase (Context& context, const char* name, const char* description)
382 		: UniformBufferCase(context, name, description)
383 	{
384 	}
385 
testUniformBuffers(void)386 	void testUniformBuffers (void)
387 	{
388 		const char* uniformNames[] =
389 		{
390 			"input1",
391 			"input2"
392 		};
393 		GLuint uniformIndices[2] = {0};
394 		glGetUniformIndices(m_program, 2, uniformNames, uniformIndices);
395 
396 		GLuint buffers[2];
397 		glGenBuffers(2, buffers);
398 
399 		for (int ndx = 0; ndx < 2; ++ndx)
400 		{
401 			glBindBuffer(GL_UNIFORM_BUFFER, buffers[ndx]);
402 			glBufferData(GL_UNIFORM_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
403 			glBindBufferBase(GL_UNIFORM_BUFFER, uniformIndices[ndx], buffers[ndx]);
404 			expectError(GL_NO_ERROR);
405 		}
406 
407 		for (int ndx = 0; ndx < 2; ++ndx)
408 		{
409 			StateQueryMemoryWriteGuard<GLint> boundBuffer;
410 			glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, uniformIndices[ndx], &boundBuffer);
411 
412 			if (boundBuffer.verifyValidity(m_testCtx))
413 				checkIntEquals(m_testCtx, boundBuffer, buffers[ndx]);
414 			expectError(GL_NO_ERROR);
415 		}
416 
417 		glDeleteBuffers(2, buffers);
418 	}
419 };
420 
421 class UniformBufferBufferCase : public UniformBufferCase
422 {
423 public:
UniformBufferBufferCase(Context & context,const char * name,const char * description)424 	UniformBufferBufferCase (Context& context, const char* name, const char* description)
425 		: UniformBufferCase(context, name, description)
426 	{
427 	}
428 
testUniformBuffers(void)429 	void testUniformBuffers (void)
430 	{
431 		const char* uniformNames[] =
432 		{
433 			"input1",
434 			"input2"
435 		};
436 		GLuint uniformIndices[2] = {0};
437 		glGetUniformIndices(m_program, 2, uniformNames, uniformIndices);
438 
439 		const GLint alignment = GetAlignment();
440 		if (alignment == -1) // cannot continue without this
441 			return;
442 
443 		m_testCtx.getLog() << tcu::TestLog::Message << "Alignment is " << alignment << tcu::TestLog::EndMessage;
444 
445 		int rangeBufferOffset		= alignment;
446 		int rangeBufferSize			= alignment * 2;
447 		int rangeBufferTotalSize	= rangeBufferOffset + rangeBufferSize + 8; // + 8 has no special meaning, just to make it != with the size of the range
448 
449 		GLuint buffers[2];
450 		glGenBuffers(2, buffers);
451 
452 		glBindBuffer(GL_UNIFORM_BUFFER, buffers[0]);
453 		glBufferData(GL_UNIFORM_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
454 		glBindBufferBase(GL_UNIFORM_BUFFER, uniformIndices[0], buffers[0]);
455 		expectError(GL_NO_ERROR);
456 
457 		glBindBuffer(GL_UNIFORM_BUFFER, buffers[1]);
458 		glBufferData(GL_UNIFORM_BUFFER, rangeBufferTotalSize, DE_NULL, GL_DYNAMIC_DRAW);
459 		glBindBufferRange(GL_UNIFORM_BUFFER, uniformIndices[1], buffers[1], rangeBufferOffset, rangeBufferSize);
460 		expectError(GL_NO_ERROR);
461 
462 		// test UNIFORM_BUFFER_START and UNIFORM_BUFFER_SIZE
463 
464 		const struct BufferRequirements
465 		{
466 			GLuint	index;
467 			GLenum	pname;
468 			GLint64 value;
469 		} requirements[] =
470 		{
471 			{ uniformIndices[0], GL_UNIFORM_BUFFER_START,	0					},
472 			{ uniformIndices[0], GL_UNIFORM_BUFFER_SIZE,	0					},
473 			{ uniformIndices[1], GL_UNIFORM_BUFFER_START,	rangeBufferOffset	},
474 			{ uniformIndices[1], GL_UNIFORM_BUFFER_SIZE,	rangeBufferSize		}
475 		};
476 
477 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requirements); ++ndx)
478 		{
479 			StateQueryMemoryWriteGuard<GLint64> state;
480 			glGetInteger64i_v(requirements[ndx].pname, requirements[ndx].index, &state);
481 
482 			if (state.verifyValidity(m_testCtx))
483 				checkIntEquals(m_testCtx, state, requirements[ndx].value);
484 			expectError(GL_NO_ERROR);
485 		}
486 
487 		glDeleteBuffers(2, buffers);
488 	}
489 
GetAlignment()490 	int GetAlignment()
491 	{
492 		StateQueryMemoryWriteGuard<GLint> state;
493 		glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &state);
494 
495 		if (!state.verifyValidity(m_testCtx))
496 			return -1;
497 
498 		if (state <= 256)
499 			return state;
500 
501 		m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: UNIFORM_BUFFER_OFFSET_ALIGNMENT has a maximum value of 256." << tcu::TestLog::EndMessage;
502 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid UNIFORM_BUFFER_OFFSET_ALIGNMENT value");
503 
504 		return -1;
505 	}
506 };
507 
508 } // anonymous
509 
IndexedStateQueryTests(Context & context)510 IndexedStateQueryTests::IndexedStateQueryTests (Context& context)
511 	: TestCaseGroup(context, "indexed", "Indexed Integer Values")
512 {
513 }
514 
init(void)515 void IndexedStateQueryTests::init (void)
516 {
517 	// transform feedback
518 	addChild(new TransformFeedbackBufferBindingCase(m_context, "transform_feedback_buffer_binding", "TRANSFORM_FEEDBACK_BUFFER_BINDING"));
519 	addChild(new TransformFeedbackBufferBufferCase(m_context, "transform_feedback_buffer_start_size", "TRANSFORM_FEEDBACK_BUFFER_START and TRANSFORM_FEEDBACK_BUFFER_SIZE"));
520 	addChild(new TransformFeedbackSwitchingBufferCase(m_context, "transform_feedback_switching_buffer", "TRANSFORM_FEEDBACK_BUFFER_BINDING while switching transform feedback objects"));
521 
522 	// uniform buffers
523 	addChild(new UniformBufferBindingCase(m_context, "uniform_buffer_binding", "UNIFORM_BUFFER_BINDING"));
524 	addChild(new UniformBufferBufferCase(m_context, "uniform_buffer_start_size", "UNIFORM_BUFFER_START and UNIFORM_BUFFER_SIZE"));
525 }
526 
527 } // Functional
528 } // gles3
529 } // deqp
530