• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  **/
GPUShader5ImagesArrayIndexing(Context & context,const ExtParameters & extParams,const char * name,const char * description)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  */
initTest(void)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  **/
iterate(void)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  */
deinit(void)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  */
getComputeShaderCode(const std::string & local_size_x,const std::string & local_size_y)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