Home | History | Annotate | Download | only in gpu_shader5
      1 /*-------------------------------------------------------------------------
      2  * OpenGL Conformance Test Suite
      3  * -----------------------------
      4  *
      5  * Copyright (c) 2014-2016 The Khronos Group Inc.
      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
     22  */ /*-------------------------------------------------------------------*/
     23 
     24 /*!
     25  * \file esextcGPUShader5UniformBlocksArrayIndexing.cpp
     26  * \brief GPUShader5 Uniform Blocks Array Indexing Test (Test Group 4)
     27  */ /*-------------------------------------------------------------------*/
     28 
     29 #include "esextcGPUShader5UniformBlocksArrayIndexing.hpp"
     30 #include "gluContextInfo.hpp"
     31 #include "gluDefs.hpp"
     32 #include "glwEnums.hpp"
     33 #include "glwFunctions.hpp"
     34 #include "tcuTestLog.hpp"
     35 #include <cstring>
     36 
     37 namespace glcts
     38 {
     39 
     40 const glw::GLuint GPUShader5UniformBlocksArrayIndexing::m_n_array_size			= 4;
     41 const glw::GLuint GPUShader5UniformBlocksArrayIndexing::m_n_position_components = 4;
     42 
     43 /* Data to fill in the buffer object associated with positionBlocks uniform array */
     44 const glw::GLfloat GPUShader5UniformBlocksArrayIndexing::m_position_data[] = { -1.0, -1.0, 0.0, 1.0,  -1.0, 1.0,
     45 																			   0.0,  1.0,  1.0, -1.0, 0.0,  1.0,
     46 																			   1.0,  1.0,  0.0, 1.0 };
     47 
     48 /* Fragment Shader code */
     49 const char* GPUShader5UniformBlocksArrayIndexing::m_fragment_shader_code = "${VERSION}\n"
     50 																		   "\n"
     51 																		   "${GPU_SHADER5_REQUIRE}\n"
     52 																		   "\n"
     53 																		   "precision highp float;\n"
     54 																		   "\n"
     55 																		   "out vec4 color;\n"
     56 																		   "\n"
     57 																		   "void main()\n"
     58 																		   "{\n"
     59 																		   "   color = vec4(1, 1, 1, 1);\n"
     60 																		   "}\n";
     61 
     62 /* Vertex Shader code */
     63 const char* GPUShader5UniformBlocksArrayIndexing::m_vertex_shader_code =
     64 	"${VERSION}\n"
     65 	"\n"
     66 	"${GPU_SHADER5_REQUIRE}\n"
     67 	"\n"
     68 	"precision highp float;\n"
     69 	"\n"
     70 	"uniform PositionBlock\n"
     71 	"{\n"
     72 	"   vec4 position;\n"
     73 	"} positionBlocks[4];\n"
     74 	"\n"
     75 	"uniform uint index;\n"
     76 	"\n"
     77 	"void main()\n"
     78 	"{\n"
     79 	"   gl_Position = positionBlocks[index].position;\n"
     80 	"}\n";
     81 
     82 /** Constructor
     83  *
     84  * @param context     Test context
     85  * @param name        Test case's name
     86  * @param description Test case's description
     87  **/
     88 GPUShader5UniformBlocksArrayIndexing::GPUShader5UniformBlocksArrayIndexing(Context&				context,
     89 																		   const ExtParameters& extParams,
     90 																		   const char* name, const char* description)
     91 	: TestCaseBase(context, extParams, name, description)
     92 	, m_fragment_shader_id(0)
     93 	, m_program_id(0)
     94 	, m_tf_buffer_id(0)
     95 	, m_uniform_buffer_ids(DE_NULL)
     96 	, m_vertex_shader_id(0)
     97 	, m_vao_id(0)
     98 {
     99 	/* Nothing to be done here */
    100 }
    101 
    102 /** Initializes GLES objects used during the test.
    103  *
    104  **/
    105 void GPUShader5UniformBlocksArrayIndexing::initTest(void)
    106 {
    107 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    108 
    109 	/* Check if gpu_shader5 extension is supported */
    110 	if (!m_is_gpu_shader5_supported)
    111 	{
    112 		throw tcu::NotSupportedError(GPU_SHADER5_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
    113 	}
    114 
    115 	/* Feedback varyings */
    116 	const char*		   feedbackVaryings[] = { "gl_Position" };
    117 	const unsigned int nVaryings		  = sizeof(feedbackVaryings) / sizeof(char*);
    118 
    119 	/* Generate and bind VAO */
    120 	gl.genVertexArrays(1, &m_vao_id);
    121 	gl.bindVertexArray(m_vao_id);
    122 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create vertex array object");
    123 
    124 	/* Create program object */
    125 	m_program_id = gl.createProgram();
    126 	GLU_EXPECT_NO_ERROR(gl.getError(), "Creating program object failed!");
    127 
    128 	gl.transformFeedbackVaryings(m_program_id, nVaryings, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);
    129 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set transform feedback varyings!");
    130 
    131 	/* Create shader objects */
    132 	m_vertex_shader_id   = gl.createShader(GL_VERTEX_SHADER);
    133 	m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
    134 	GLU_EXPECT_NO_ERROR(gl.getError(), "Creating shader objects failed!");
    135 
    136 	/* Build program */
    137 	if (!buildProgram(m_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_vertex_shader_id, 1,
    138 					  &m_vertex_shader_code))
    139 	{
    140 		TCU_FAIL("Program could not have been created sucessfully from a valid vertex/fragment shader!");
    141 	}
    142 
    143 	/* Create a buffer object */
    144 	gl.genBuffers(1, &m_tf_buffer_id);
    145 	gl.bindBuffer(GL_ARRAY_BUFFER, m_tf_buffer_id);
    146 	gl.bufferData(GL_ARRAY_BUFFER, m_n_position_components * sizeof(glw::GLfloat) * nVaryings, DE_NULL,
    147 				  GL_DYNAMIC_COPY);
    148 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create and initialize a buffer object to be used for XFB!");
    149 
    150 	/* Bind buffer object to transform feedback binding point */
    151 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
    152 					  m_tf_buffer_id);
    153 
    154 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object to transform feedback binding point!");
    155 }
    156 
    157 /** Executes the test.
    158  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
    159  *
    160  *  Note the function throws exception should an error occur!
    161  *
    162  *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
    163  *
    164  **/
    165 tcu::TestNode::IterateResult GPUShader5UniformBlocksArrayIndexing::iterate(void)
    166 {
    167 	initTest();
    168 
    169 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    170 
    171 	/* Use the test program object */
    172 	gl.useProgram(m_program_id);
    173 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use program object!");
    174 
    175 	/* Set up uniform buffer bindings */
    176 	m_uniform_buffer_ids = new glw::GLuint[m_n_array_size];
    177 	memset(m_uniform_buffer_ids, 0, m_n_array_size * sizeof(glw::GLuint));
    178 
    179 	gl.genBuffers(m_n_array_size, m_uniform_buffer_ids);
    180 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
    181 
    182 	for (glw::GLuint index_value = 0; index_value < m_n_array_size; ++index_value)
    183 	{
    184 		glw::GLuint		  blockIndex = 0;
    185 		std::stringstream positionBlock;
    186 
    187 		positionBlock << "PositionBlock[" << index_value << "]";
    188 
    189 		blockIndex = gl.getUniformBlockIndex(m_program_id, positionBlock.str().c_str());
    190 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get uniform block index");
    191 
    192 		gl.uniformBlockBinding(m_program_id, blockIndex, index_value);
    193 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not assign uniform block binding");
    194 
    195 		gl.bindBuffer(GL_UNIFORM_BUFFER, m_uniform_buffer_ids[index_value]);
    196 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object");
    197 
    198 		gl.bufferData(GL_UNIFORM_BUFFER, m_n_position_components * sizeof(float),
    199 					  m_position_data + m_n_position_components * index_value, GL_STATIC_READ);
    200 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set buffer object data");
    201 
    202 		gl.bindBufferBase(GL_UNIFORM_BUFFER, index_value, m_uniform_buffer_ids[index_value]);
    203 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object to uniform block binding point");
    204 	}
    205 
    206 	/* Retrieve 'index' uniform location. */
    207 	glw::GLint index_uniform_location = gl.getUniformLocation(m_program_id, "index");
    208 
    209 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call failed.");
    210 
    211 	if (index_uniform_location == -1)
    212 	{
    213 		TCU_FAIL("Could not get index uniform location!");
    214 	}
    215 
    216 	/* Run the test */
    217 	bool testFailed = false;
    218 
    219 	for (glw::GLuint index_value = 0; index_value < m_n_array_size; ++index_value)
    220 	{
    221 		if (!drawAndCheckResult(index_uniform_location, index_value))
    222 		{
    223 			testFailed = true;
    224 
    225 			break;
    226 		}
    227 	}
    228 
    229 	if (testFailed)
    230 	{
    231 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    232 	}
    233 	else
    234 	{
    235 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    236 	}
    237 
    238 	return STOP;
    239 }
    240 
    241 /** Draws and checks result data fetched via transform feedback
    242  *
    243  *   @param index_value value to be set for the index uniform variable.
    244  *
    245  *   @return true if the result data is correct, false otherwise
    246  */
    247 bool GPUShader5UniformBlocksArrayIndexing::drawAndCheckResult(glw::GLuint index_location, glw::GLuint index_value)
    248 {
    249 	const glw::Functions& gl	 = m_context.getRenderContext().getFunctions();
    250 	bool				  result = true;
    251 
    252 	gl.uniform1ui(index_location, index_value);
    253 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1ui() call failed");
    254 
    255 	gl.enable(GL_RASTERIZER_DISCARD);
    256 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed");
    257 
    258 	gl.beginTransformFeedback(GL_POINTS);
    259 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) call failed");
    260 
    261 	gl.drawArrays(GL_POINTS, 0, /* first */
    262 				  1);			/* count */
    263 	GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed!");
    264 
    265 	gl.endTransformFeedback();
    266 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
    267 
    268 	gl.disable(GL_RASTERIZER_DISCARD);
    269 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) call failed");
    270 
    271 	/* Fetch the results via transform feedback */
    272 	const glw::GLfloat* feedback_result =
    273 		(glw::GLfloat*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
    274 										 sizeof(float) * m_n_position_components, GL_MAP_READ_BIT);
    275 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not map buffer to process space");
    276 
    277 	if (de::abs(feedback_result[0] - m_position_data[index_value * m_n_position_components + 0]) > m_epsilon_float ||
    278 		de::abs(feedback_result[1] - m_position_data[index_value * m_n_position_components + 1]) > m_epsilon_float ||
    279 		de::abs(feedback_result[2] - m_position_data[index_value * m_n_position_components + 2]) > m_epsilon_float ||
    280 		de::abs(feedback_result[3] - m_position_data[index_value * m_n_position_components + 3]) > m_epsilon_float)
    281 	{
    282 		m_testCtx.getLog() << tcu::TestLog::Message << "Expected Data ("
    283 						   << m_position_data[index_value * m_n_position_components + 0] << ", "
    284 						   << m_position_data[index_value * m_n_position_components + 1] << ", "
    285 						   << m_position_data[index_value * m_n_position_components + 2] << ", "
    286 						   << m_position_data[index_value * m_n_position_components + 3] << ") Result Data ("
    287 						   << feedback_result[0] << ", " << feedback_result[1] << ", " << feedback_result[2] << ", "
    288 						   << feedback_result[3] << ")" << tcu::TestLog::EndMessage;
    289 		result = false;
    290 	}
    291 
    292 	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
    293 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
    294 
    295 	return result;
    296 }
    297 
    298 /** Deinitializes GLES objects created during the test.
    299  *
    300  */
    301 void GPUShader5UniformBlocksArrayIndexing::deinit(void)
    302 {
    303 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    304 
    305 	/* Reset OpenGL ES state */
    306 	gl.useProgram(0);
    307 	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
    308 	gl.bindBuffer(GL_UNIFORM_BUFFER, 0);
    309 	gl.bindVertexArray(0);
    310 
    311 	/* Delete program object and shaders */
    312 	if (m_program_id != 0)
    313 	{
    314 		gl.deleteProgram(m_program_id);
    315 
    316 		m_program_id = 0;
    317 	}
    318 
    319 	if (m_vertex_shader_id != 0)
    320 	{
    321 		gl.deleteShader(m_vertex_shader_id);
    322 
    323 		m_vertex_shader_id = 0;
    324 	}
    325 
    326 	if (m_fragment_shader_id != 0)
    327 	{
    328 		gl.deleteShader(m_fragment_shader_id);
    329 
    330 		m_fragment_shader_id = 0;
    331 	}
    332 
    333 	if (m_tf_buffer_id != 0)
    334 	{
    335 		gl.deleteBuffers(1, &m_tf_buffer_id);
    336 
    337 		m_tf_buffer_id = 0;
    338 	}
    339 
    340 	if (m_uniform_buffer_ids != DE_NULL)
    341 	{
    342 		gl.deleteBuffers(m_n_array_size, m_uniform_buffer_ids);
    343 
    344 		delete[] m_uniform_buffer_ids;
    345 		m_uniform_buffer_ids = DE_NULL;
    346 	}
    347 
    348 	if (m_vao_id != 0)
    349 	{
    350 		gl.deleteVertexArrays(1, &m_vao_id);
    351 
    352 		m_vao_id = 0;
    353 	}
    354 
    355 	/* Call base class' deinit() */
    356 	TestCaseBase::deinit();
    357 }
    358 
    359 } // namespace glcts
    360