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