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 esextcGPUShader5ImagesArrayIndexing.cpp
     26  * \brief GPUShader5 Images Array Indexing (Test 2)
     27  */ /*-------------------------------------------------------------------*/
     28 
     29 #include "esextcGPUShader5ImagesArrayIndexing.hpp"
     30 #include "gluContextInfo.hpp"
     31 #include "gluDefs.hpp"
     32 #include "glwEnums.hpp"
     33 #include "glwFunctions.hpp"
     34 #include "tcuTestLog.hpp"
     35 #include <string.h>
     36 
     37 namespace glcts
     38 {
     39 
     40 const glw::GLuint GPUShader5ImagesArrayIndexing::m_array_size			= 4;
     41 const glw::GLint  GPUShader5ImagesArrayIndexing::m_texture_n_components = 1;
     42 
     43 /** Constructor
     44  *
     45  *  @param context     Test context
     46  *  @param name        Test case's name
     47  *  @param description Test case's description
     48  **/
     49 GPUShader5ImagesArrayIndexing::GPUShader5ImagesArrayIndexing(Context& context, const ExtParameters& extParams,
     50 															 const char* name, const char* description)
     51 	: TestCaseBase(context, extParams, name, description)
     52 	, m_compute_shader_id(0)
     53 	, m_data_buffer(DE_NULL)
     54 	, m_program_id(0)
     55 	, m_texture_height(0)
     56 	, m_texture_width(0)
     57 	, m_to_ids(DE_NULL)
     58 	, m_fbo_id(0)
     59 {
     60 	/* Nothing to be done here */
     61 }
     62 
     63 /** Initializes GLES objects used during the test.
     64  *
     65  */
     66 void GPUShader5ImagesArrayIndexing::initTest(void)
     67 {
     68 	/* Check if gpu_shader5 extension is supported */
     69 	if (!m_is_gpu_shader5_supported)
     70 	{
     71 		throw tcu::NotSupportedError(GPU_SHADER5_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
     72 	}
     73 
     74 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
     75 
     76 	/* Calculate platform-specific value that should be used for local_size_x, local_size_y in compute shader */
     77 	glw::GLint max_compute_work_group_invocations_value = 0;
     78 
     79 	gl.getIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &m_texture_width);
     80 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query GL_MAX_COMPUTE_WORK_GROUP_SIZE!");
     81 
     82 	gl.getIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &m_texture_height);
     83 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query GL_MAX_COMPUTE_WORK_GROUP_SIZE!");
     84 
     85 	gl.getIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &max_compute_work_group_invocations_value);
     86 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS!");
     87 
     88 	if (m_texture_width * m_texture_height > max_compute_work_group_invocations_value)
     89 	{
     90 		m_texture_width = (max_compute_work_group_invocations_value / m_texture_height);
     91 	}
     92 
     93 	/* Construct compute shader code */
     94 	std::string		  compute_shader_code;
     95 	const char*		  compute_shader_code_ptr = DE_NULL;
     96 	std::stringstream local_size_x_stringstream;
     97 	std::stringstream local_size_y_stringstream;
     98 
     99 	local_size_x_stringstream << m_texture_width;
    100 	local_size_y_stringstream << m_texture_height;
    101 
    102 	compute_shader_code		= getComputeShaderCode(local_size_x_stringstream.str(), local_size_y_stringstream.str());
    103 	compute_shader_code_ptr = (const char*)compute_shader_code.c_str();
    104 
    105 	/* Create a program object */
    106 	m_program_id = gl.createProgram();
    107 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed");
    108 
    109 	/* Create a compute shader object */
    110 	m_compute_shader_id = gl.createShader(GL_COMPUTE_SHADER);
    111 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_COMPUTE_SHADER) failed");
    112 
    113 	/* Build a program object that consists only of the compute shader */
    114 	if (!buildProgram(m_program_id, m_compute_shader_id, 1, &compute_shader_code_ptr))
    115 	{
    116 		TCU_FAIL("Could not create program object!");
    117 	}
    118 
    119 	/* Generate texture objects */
    120 	m_to_ids = new glw::GLuint[m_array_size];
    121 	memset(m_to_ids, 0, m_array_size * sizeof(glw::GLuint));
    122 	gl.genTextures(m_array_size, m_to_ids);
    123 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate texture objects!");
    124 
    125 	/* Allocate a buffer we will later fill with data and use as a data source for a texture object */
    126 	glw::GLuint dataSize = m_texture_width * m_texture_height * m_texture_n_components;
    127 	m_data_buffer		 = new glw::GLuint[dataSize * m_array_size];
    128 
    129 	for (glw::GLuint array_index = 0; array_index < m_array_size; ++array_index)
    130 	{
    131 		for (glw::GLuint index = 0; index < dataSize; ++index)
    132 		{
    133 			m_data_buffer[index + array_index * dataSize] = 1 + array_index;
    134 		}
    135 	}
    136 
    137 	/* Initialize storage for the texture objects */
    138 	for (glw::GLuint index = 0; index < m_array_size; index++)
    139 	{
    140 		gl.activeTexture(GL_TEXTURE0 + index);
    141 		gl.bindTexture(GL_TEXTURE_2D, m_to_ids[index]);
    142 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind a texture object to texture unit!");
    143 
    144 		gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_R32UI, m_texture_width, m_texture_height);
    145 
    146 		gl.texSubImage2D(GL_TEXTURE_2D, 0 /* level */, 0 /* x offset */, 0 /* y offset */, m_texture_width,
    147 						 m_texture_height, GL_RED_INTEGER, GL_UNSIGNED_INT, &m_data_buffer[index * dataSize]);
    148 
    149 		gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    150 		gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    151 
    152 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not allocate storage for a texture object!");
    153 	}
    154 
    155 	delete[] m_data_buffer;
    156 	m_data_buffer = DE_NULL;
    157 }
    158 
    159 /** Executes the test.
    160  *
    161  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
    162  *
    163  *  Note the function throws exception should an error occur!
    164  *
    165  *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
    166  **/
    167 tcu::TestNode::IterateResult GPUShader5ImagesArrayIndexing::iterate(void)
    168 {
    169 	initTest();
    170 
    171 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    172 
    173 	gl.useProgram(m_program_id);
    174 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
    175 
    176 	for (glw::GLuint index = 0; index < m_array_size; index++)
    177 	{
    178 		gl.bindImageTexture(index /* unit */, m_to_ids[index], 0 /* level */, GL_FALSE, /* layered */
    179 							0,															/* layer */
    180 							GL_READ_WRITE, GL_R32UI);
    181 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind a texture object to image unit!");
    182 	}
    183 
    184 	gl.dispatchCompute(1,  /* num_groups_x */
    185 					   1,  /* num_groups_y */
    186 					   1); /* num_groups_z */
    187 	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to dispatch compute operation");
    188 
    189 	/* Create and configure a framebuffer object */
    190 	gl.genFramebuffers(1, &m_fbo_id);
    191 	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id);
    192 
    193 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create framebuffer object");
    194 
    195 	/* Set viewport */
    196 	gl.viewport(0, 0, m_texture_width, m_texture_height);
    197 	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed");
    198 
    199 	/* Allocate space for result data */
    200 	const glw::GLuint dataSize = m_texture_width * m_texture_height * m_texture_n_components * 4;
    201 	m_data_buffer			   = new glw::GLuint[dataSize];
    202 
    203 	gl.memoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT);
    204 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set memory barrier!");
    205 
    206 	for (unsigned int i = 0; i < m_array_size; ++i)
    207 	{
    208 		/* Attach texture to framebuffer's color attachment 0 */
    209 		gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_ids[i], 0 /* level */);
    210 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring color attachment for framebuffer object!");
    211 
    212 		/* Read the rendered data */
    213 		gl.readPixels(0 /* x */, 0 /* y */, m_texture_width, m_texture_height, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
    214 					  m_data_buffer);
    215 		GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed!");
    216 
    217 		glw::GLuint resultExpected[m_texture_n_components];
    218 
    219 		/* Loop over all pixels and compare the rendered data with reference value */
    220 		for (glw::GLint y = 0; y < m_texture_height; ++y)
    221 		{
    222 			glw::GLuint* data_row = m_data_buffer + y * m_texture_width * m_texture_n_components * 4;
    223 
    224 			for (glw::GLint x = 0; x < m_texture_width; ++x)
    225 			{
    226 				glw::GLuint* data = data_row + x * m_texture_n_components * 4;
    227 
    228 				resultExpected[0] = x + y + 1 + i;
    229 
    230 				if (resultExpected[0] != data[0])
    231 				{
    232 					m_testCtx.getLog() << tcu::TestLog::Message << "Invalid image data acquired for image at index "
    233 									   << i << ", position: (" << x << "," << y << ")"
    234 									   << ". Rendered data [" << data[0] << "]"
    235 									   << " Expected data [" << resultExpected[0] << "]" << tcu::TestLog::EndMessage;
    236 
    237 					delete[] m_data_buffer;
    238 					m_data_buffer = DE_NULL;
    239 
    240 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    241 					return STOP;
    242 				} /* if (data mismatch) */
    243 
    244 			} /* for (all columns) */
    245 		}	 /* for (all rows) */
    246 	}		  /*for (m_sizeOfArray)*/
    247 
    248 	delete[] m_data_buffer;
    249 	m_data_buffer = DE_NULL;
    250 
    251 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    252 	return STOP;
    253 }
    254 
    255 /** Deinitializes GLES objects created during the test.
    256  *
    257  */
    258 void GPUShader5ImagesArrayIndexing::deinit(void)
    259 {
    260 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    261 
    262 	/* Reset OpenGL ES state */
    263 	gl.useProgram(0);
    264 	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
    265 	gl.activeTexture(GL_TEXTURE0);
    266 	gl.bindTexture(GL_TEXTURE_2D, 0);
    267 	gl.bindVertexArray(0);
    268 
    269 	/* Delete program object and shaders */
    270 	if (m_program_id != 0)
    271 	{
    272 		gl.deleteProgram(m_program_id);
    273 
    274 		m_program_id = 0;
    275 	}
    276 
    277 	if (m_compute_shader_id != 0)
    278 	{
    279 		gl.deleteShader(m_compute_shader_id);
    280 
    281 		m_compute_shader_id = 0;
    282 	}
    283 
    284 	if (m_data_buffer != DE_NULL)
    285 	{
    286 		delete[] m_data_buffer;
    287 		m_data_buffer = DE_NULL;
    288 	}
    289 
    290 	if (m_to_ids != DE_NULL)
    291 	{
    292 		gl.deleteTextures(m_array_size, m_to_ids);
    293 		delete[] m_to_ids;
    294 		m_to_ids = DE_NULL;
    295 	}
    296 
    297 	if (m_fbo_id != 0)
    298 	{
    299 		gl.deleteFramebuffers(1, &m_fbo_id);
    300 		m_fbo_id = 0;
    301 	}
    302 
    303 	/* Call base class' deinit() */
    304 	TestCaseBase::deinit();
    305 }
    306 
    307 /** Fill compute shader template
    308  *
    309  *  @param _local_size_x    String storing a "local_size_x" layout qualifier definition;
    310  *  @param _local_size_y    String storing a "local_size_y" layout qualifier definition;
    311  *
    312  *  @return string containing compute shader code
    313  */
    314 std::string GPUShader5ImagesArrayIndexing::getComputeShaderCode(const std::string& local_size_x,
    315 																const std::string& local_size_y)
    316 {
    317 	/* Compute shader template code */
    318 	std::string m_compute_shader_template =
    319 		"${VERSION}\n"
    320 		"\n"
    321 		"${GPU_SHADER5_REQUIRE}\n"
    322 		"\n"
    323 		"layout (local_size_x = <-MAX-LOCAL-SIZE-X->,\n"
    324 		"        local_size_y = <-MAX-LOCAL-SIZE-Y->,\n"
    325 		"        local_size_z = 1) in;\n"
    326 		"\n"
    327 		"layout (r32ui, binding = 0) uniform highp uimage2D image[4];\n"
    328 		"\n"
    329 		"void main(void)\n"
    330 		"{\n"
    331 		"   uvec4 texel0 = imageLoad(image[0], ivec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) );\n"
    332 		"   uvec4 texel1 = imageLoad(image[1], ivec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) );\n"
    333 		"   uvec4 texel2 = imageLoad(image[2], ivec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) );\n"
    334 		"   uvec4 texel3 = imageLoad(image[3], ivec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) );\n"
    335 		"   uvec4 addon  = uvec4(gl_LocalInvocationID.x+gl_LocalInvocationID.y);\n"
    336 		"\n"
    337 		"   imageStore(image[0], ivec2( gl_LocalInvocationID.x, gl_LocalInvocationID.y), texel0  + addon);\n"
    338 		"   imageStore(image[1], ivec2( gl_LocalInvocationID.x, gl_LocalInvocationID.y), texel1  + addon);\n"
    339 		"   imageStore(image[2], ivec2( gl_LocalInvocationID.x, gl_LocalInvocationID.y), texel2  + addon);\n"
    340 		"   imageStore(image[3], ivec2( gl_LocalInvocationID.x, gl_LocalInvocationID.y), texel3  + addon);\n"
    341 		"}\n";
    342 
    343 	/* Insert information on local size in X direction */
    344 	std::string template_name	 = "<-MAX-LOCAL-SIZE-X->";
    345 	std::size_t template_position = m_compute_shader_template.find(template_name);
    346 
    347 	while (template_position != std::string::npos)
    348 	{
    349 		m_compute_shader_template =
    350 			m_compute_shader_template.replace(template_position, template_name.length(), local_size_x);
    351 
    352 		template_position = m_compute_shader_template.find(template_name);
    353 	}
    354 
    355 	/* Insert information on local size in Y direction */
    356 	template_name	 = "<-MAX-LOCAL-SIZE-Y->";
    357 	template_position = m_compute_shader_template.find(template_name);
    358 
    359 	while (template_position != std::string::npos)
    360 	{
    361 		m_compute_shader_template =
    362 			m_compute_shader_template.replace(template_position, template_name.length(), local_size_y);
    363 
    364 		template_position = m_compute_shader_template.find(template_name);
    365 	}
    366 
    367 	return m_compute_shader_template;
    368 }
    369 
    370 } // namespace glcts
    371