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  **/
GPUShader5UniformBlocksArrayIndexing(Context & context,const ExtParameters & extParams,const char * name,const char * description)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  **/
initTest(void)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  **/
iterate(void)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  */
drawAndCheckResult(glw::GLuint index_location,glw::GLuint index_value)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  */
deinit(void)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