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