Home | History | Annotate | Download | only in functional
      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 
     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 
     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:
     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 		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:
    141 	TransformFeedbackBufferBindingCase (Context& context, const char* name, const char* description)
    142 		: TransformFeedbackCase(context, name, description)
    143 	{
    144 	}
    145 
    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:
    186 	TransformFeedbackBufferBufferCase (Context& context, const char* name, const char* description)
    187 		: TransformFeedbackCase(context, name, description)
    188 	{
    189 	}
    190 
    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:
    248 	TransformFeedbackSwitchingBufferCase (Context& context, const char* name, const char* description)
    249 		: TransformFeedbackCase(context, name, description)
    250 	{
    251 	}
    252 
    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:
    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 
    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:
    381 	UniformBufferBindingCase (Context& context, const char* name, const char* description)
    382 		: UniformBufferCase(context, name, description)
    383 	{
    384 	}
    385 
    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:
    424 	UniformBufferBufferCase (Context& context, const char* name, const char* description)
    425 		: UniformBufferCase(context, name, description)
    426 	{
    427 	}
    428 
    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 
    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 
    510 IndexedStateQueryTests::IndexedStateQueryTests (Context& context)
    511 	: TestCaseGroup(context, "indexed", "Indexed Integer Values")
    512 {
    513 }
    514 
    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