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 #include "gluDefs.hpp"
25 #include "glwEnums.hpp"
26 #include "glwFunctions.hpp"
27 #include "tcuTestLog.hpp"
28
29 #include "esextcGeometryShaderAdjacency.hpp"
30 #include <math.h>
31
32 namespace glcts
33 {
34 /** Constructor
35 *
36 **/
AdjacencyGrid()37 AdjacencyGrid::AdjacencyGrid()
38 : m_line_segments(0), m_points(0), m_triangles(0), m_n_points(0), m_n_segments(0), m_n_triangles(0)
39 {
40 /* Nothing to be done here */
41 }
42
43 /** Destructor
44 *
45 **/
~AdjacencyGrid()46 AdjacencyGrid::~AdjacencyGrid()
47 {
48 if (m_line_segments)
49 {
50 delete[] m_line_segments;
51 m_line_segments = 0;
52 }
53
54 if (m_points)
55 {
56 delete[] m_points;
57 m_points = 0;
58 }
59
60 if (m_triangles)
61 {
62 delete[] m_triangles;
63 m_triangles = 0;
64 }
65 }
66
67 /** Constructor
68 *
69 **/
AdjacencyGridStrip()70 AdjacencyGridStrip::AdjacencyGridStrip() : m_n_points(0), m_points(0)
71 {
72 /* Nothing to be done here */
73 }
74
75 /** Destructor
76 *
77 **/
~AdjacencyGridStrip()78 AdjacencyGridStrip::~AdjacencyGridStrip()
79 {
80 if (m_points)
81 {
82 delete[] m_points;
83 }
84 }
85
86 /** Constructor
87 *
88 **/
AdjacencyTestData()89 AdjacencyTestData::AdjacencyTestData()
90 : m_gs_code(0)
91 , m_mode(0)
92 , m_n_vertices(0)
93 , m_grid(0)
94 , m_geometry_bo_size(0)
95 , m_index_data_bo_size(0)
96 , m_vertex_data_bo_size(0)
97 , m_expected_adjacency_geometry(0)
98 , m_expected_geometry(0)
99 , m_index_data(0)
100 , m_tf_mode(0)
101 , m_vertex_data(0)
102 {
103 /* Nothing to be done here */
104 }
105
106 /** Destructor
107 *
108 **/
~AdjacencyTestData()109 AdjacencyTestData::~AdjacencyTestData()
110 {
111 if (m_expected_adjacency_geometry)
112 {
113 delete[] m_expected_adjacency_geometry;
114 m_expected_adjacency_geometry = 0;
115 }
116
117 if (m_expected_geometry)
118 {
119 delete[] m_expected_geometry;
120 m_expected_geometry = 0;
121 }
122
123 if (m_vertex_data)
124 {
125 delete[] m_vertex_data;
126 m_vertex_data = 0;
127 }
128
129 if (m_index_data)
130 {
131 delete[] m_index_data;
132 m_index_data = 0;
133 }
134
135 if (m_grid)
136 {
137 delete m_grid;
138 m_grid = 0;
139 }
140 }
141
142 /** Constructor
143 *
144 * @param context Test context
145 * @param name Test case's name
146 * @param description Test case's desricption
147 **/
GeometryShaderAdjacency(Context & context,const ExtParameters & extParams,const char * name,const char * description,AdjacencyTestData & testData)148 GeometryShaderAdjacency::GeometryShaderAdjacency(Context& context, const ExtParameters& extParams, const char* name,
149 const char* description, AdjacencyTestData& testData)
150 : TestCaseBase(context, extParams, name, description)
151 , m_adjacency_geometry_bo_id(0)
152 , m_fs_id(0)
153 , m_geometry_bo_id(0)
154 , m_gs_id(0)
155 , m_index_data_bo_id(0)
156 , m_vertex_data_bo_id(0)
157 , m_po_id(0)
158 , m_test_data(testData)
159 , m_vao_id(0)
160 , m_vs_id(0)
161 , m_components_input(2)
162 , m_epsilon(0.00001F)
163 , m_position_attribute_location(0)
164 {
165 /* Nothing to be done here */
166 }
167
168 /** Deinitializes GLES objects created during the test.
169 *
170 */
deinit(void)171 void GeometryShaderAdjacency::deinit(void)
172 {
173 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
174
175 /* Reset OpenGL ES state */
176 gl.useProgram(0);
177 gl.bindVertexArray(0);
178 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
179 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, 0);
180 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
181
182 if (m_po_id != 0)
183 {
184 gl.deleteProgram(m_po_id);
185 }
186
187 if (m_fs_id != 0)
188 {
189 gl.deleteShader(m_fs_id);
190 }
191
192 if (m_gs_id != 0)
193 {
194 gl.deleteShader(m_gs_id);
195 }
196
197 if (m_vs_id != 0)
198 {
199 gl.deleteShader(m_vs_id);
200 }
201
202 if (m_adjacency_geometry_bo_id != 0)
203 {
204 gl.deleteBuffers(1, &m_adjacency_geometry_bo_id);
205 }
206 if (m_geometry_bo_id != 0)
207 {
208 gl.deleteBuffers(1, &m_geometry_bo_id);
209 }
210
211 if (m_index_data_bo_id != 0)
212 {
213 gl.deleteBuffers(1, &m_index_data_bo_id);
214 }
215
216 if (m_vertex_data_bo_id != 0)
217 {
218 gl.deleteBuffers(1, &m_vertex_data_bo_id);
219 }
220
221 if (m_vao_id != 0)
222 {
223 gl.deleteVertexArrays(1, &m_vao_id);
224 }
225
226 TestCaseBase::deinit();
227 }
228
229 /** Returns code for Fragment Shader
230 * @return pointer to literal with Fragment Shader code
231 **/
getFragmentShaderCode()232 const char* GeometryShaderAdjacency::getFragmentShaderCode()
233 {
234 static const char* result = "${VERSION}\n"
235 "\n"
236 "precision highp float;\n"
237 "\n"
238 "void main()\n"
239 "{\n"
240 "}\n";
241 return result;
242 }
243
244 /** Returns code for Vertex Shader
245 * @return pointer to literal with Vertex Shader code
246 **/
getVertexShaderCode()247 const char* GeometryShaderAdjacency::getVertexShaderCode()
248 {
249 static const char* result = "${VERSION}\n"
250 "\n"
251 "precision highp float;\n"
252 "\n"
253 "layout(location = 0) in vec2 position_data;\n"
254 "\n"
255 "void main()\n"
256 "{\n"
257 " gl_Position = vec4(position_data, 0, 1);\n"
258 "}\n";
259 return result;
260 }
261
262 /** Initializes GLES objects used during the test.
263 *
264 **/
initTest(void)265 void GeometryShaderAdjacency::initTest(void)
266 {
267 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
268
269 /* check if EXT_geometry_shader extension is supported */
270 if (!m_is_geometry_shader_extension_supported)
271 {
272 throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
273 }
274
275 gl.genVertexArrays(1, &m_vao_id);
276 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
277
278 /* Get shader code */
279 const char* fsCode = getFragmentShaderCode();
280 const char* gsCode = m_test_data.m_gs_code;
281 const char* vsCode = getVertexShaderCode();
282
283 /* Create shader and program objects */
284 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
285 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
286 m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
287 m_po_id = gl.createProgram();
288
289 GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program/shader objects.");
290
291 /* If gs code is available set gs out data for transformfeedback*/
292 if (m_test_data.m_gs_code)
293 {
294 const char* varyings[] = { "out_adjacent_geometry", "out_geometry" };
295
296 gl.transformFeedbackVaryings(m_po_id, 2, varyings, GL_SEPARATE_ATTRIBS);
297 }
298 else
299 {
300 const char* varyings[] = { "gl_Position" };
301
302 gl.transformFeedbackVaryings(m_po_id, 1, varyings, GL_SEPARATE_ATTRIBS);
303 }
304 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex array object!");
305
306 /* Build program */
307 if (!buildProgram(m_po_id, m_fs_id, 1, /* parts */ &fsCode, (gsCode) ? m_gs_id : 0, (gsCode) ? 1 : 0,
308 (gsCode) ? &gsCode : 0, m_vs_id, 1, /* parts */ &vsCode))
309 {
310 TCU_FAIL("Could not create a program object from a valid shader!");
311 }
312
313 /* Generate buffers for input/output vertex data */
314 gl.genBuffers(1, &m_vertex_data_bo_id);
315 gl.genBuffers(1, &m_adjacency_geometry_bo_id);
316 gl.genBuffers(1, &m_geometry_bo_id);
317
318 /* Configure buffers for input/output vertex data */
319 gl.bindBuffer(GL_ARRAY_BUFFER, m_adjacency_geometry_bo_id);
320 gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_geometry_bo_size * 4, 0, GL_DYNAMIC_DRAW);
321 gl.bindBuffer(GL_ARRAY_BUFFER, m_geometry_bo_id);
322 gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_geometry_bo_size * 4, 0, GL_DYNAMIC_DRAW);
323 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_data_bo_id);
324 gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_vertex_data_bo_size, m_test_data.m_vertex_data, GL_DYNAMIC_DRAW);
325 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
326
327 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex buffer objects for vertex data!");
328
329 /* Configure buffer for index data */
330 if (m_test_data.m_index_data_bo_size > 0)
331 {
332 gl.genBuffers(1, &m_index_data_bo_id);
333 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_data_bo_id);
334 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, m_test_data.m_index_data_bo_size, m_test_data.m_index_data,
335 GL_DYNAMIC_DRAW);
336 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
337
338 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex buffer objects for index data!");
339 }
340 }
341
342 /** Executes the test.
343 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
344 * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
345 * Note the function throws exception should an error occur!
346 **/
iterate(void)347 tcu::TestNode::IterateResult GeometryShaderAdjacency::iterate(void)
348 {
349 initTest();
350
351 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
352
353 /** Bind a vertex array object */
354 gl.bindVertexArray(m_vao_id);
355 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
356
357 /* Bind buffer objects used as data store for transform feedback to TF binding points*/
358 if (m_test_data.m_gs_code)
359 {
360 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_adjacency_geometry_bo_id);
361 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, m_geometry_bo_id);
362 }
363 else
364 {
365 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_geometry_bo_id);
366 }
367
368 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring transform feedback buffer binding points!");
369
370 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_data_bo_id);
371 m_position_attribute_location = gl.getAttribLocation(m_po_id, "position_data");
372 gl.vertexAttribPointer(m_position_attribute_location, m_components_input, GL_FLOAT, GL_FALSE, 0, 0);
373 gl.enableVertexAttribArray(m_position_attribute_location);
374 GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting vertex attribute array for position_data attribute");
375
376 /* bind index buffer */
377 if (m_test_data.m_index_data_bo_size > 0)
378 {
379 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_data_bo_id);
380 }
381 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding index data buffer");
382
383 /* Configure program */
384 gl.enable(GL_RASTERIZER_DISCARD);
385 gl.useProgram(m_po_id);
386 gl.beginTransformFeedback(m_test_data.m_tf_mode);
387
388 glw::GLuint nVertices = m_test_data.m_n_vertices * ((m_test_data.m_mode == m_glExtTokens.LINE_STRIP_ADJACENCY ||
389 m_test_data.m_mode == m_glExtTokens.TRIANGLE_STRIP_ADJACENCY) ?
390 1 :
391 2 /* include adjacency info */);
392
393 /* Use glDrawElements if data is indicied */
394 if (m_test_data.m_index_data_bo_size > 0)
395 {
396 gl.drawElements(m_test_data.m_mode, nVertices, GL_UNSIGNED_INT, 0);
397 }
398 /* Use glDrawArrays if data is non indicied */
399 else
400 {
401 gl.drawArrays(m_test_data.m_mode, 0, nVertices);
402 }
403 GLU_EXPECT_NO_ERROR(gl.getError(), "Error while trying to render");
404
405 gl.disable(GL_RASTERIZER_DISCARD);
406 gl.endTransformFeedback();
407
408 /* Map result buffer objects into client space */
409 float* result_adjacency_geometry_ptr = 0;
410 float* result_geometry_ptr = 0;
411
412 /* If gs is available read adjacency data using TF and compare with expected data*/
413 if (m_test_data.m_gs_code)
414 {
415 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_adjacency_geometry_bo_id);
416 result_adjacency_geometry_ptr =
417 (float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_test_data.m_geometry_bo_size, GL_MAP_READ_BIT);
418 GLU_EXPECT_NO_ERROR(gl.getError(), "Error when mapping data to client space");
419
420 std::stringstream sstreamExpected;
421 std::stringstream sstreamResult;
422 sstreamExpected << "[";
423 sstreamResult << "[";
424
425 for (unsigned int n = 0; n < m_test_data.m_geometry_bo_size / sizeof(float); ++n)
426 {
427 sstreamExpected << m_test_data.m_expected_adjacency_geometry[n] << ", ";
428 sstreamResult << result_adjacency_geometry_ptr[n] << ", ";
429
430 if (de::abs(result_adjacency_geometry_ptr[n] - m_test_data.m_expected_adjacency_geometry[n]) >= m_epsilon)
431 {
432 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
433
434 m_testCtx.getLog() << tcu::TestLog::Message << "At [" << n
435 << "] position adjacency buffer position Reference value is different than the "
436 "rendered data (epsilon "
437 << m_epsilon << " )"
438 << " (" << m_test_data.m_expected_adjacency_geometry[n] << ") vs "
439 << "(" << result_adjacency_geometry_ptr[n] << ")" << tcu::TestLog::EndMessage;
440
441 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
442 return STOP;
443 }
444 }
445
446 sstreamExpected << "]";
447 sstreamResult << "]";
448 m_testCtx.getLog() << tcu::TestLog::Message << "Adjacency Expected: " << sstreamExpected.str().c_str()
449 << tcu::TestLog::EndMessage;
450 m_testCtx.getLog() << tcu::TestLog::Message << "Adjacency Result: " << sstreamResult.str().c_str()
451 << tcu::TestLog::EndMessage;
452
453 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
454 }
455
456 /* Read vertex data using TF and compare with expected data*/
457 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_geometry_bo_id);
458 result_geometry_ptr =
459 (float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_test_data.m_geometry_bo_size, GL_MAP_READ_BIT);
460 GLU_EXPECT_NO_ERROR(gl.getError(), "Error when mapping data to client space");
461
462 std::stringstream sstreamExpected;
463 std::stringstream sstreamResult;
464 sstreamExpected << "[";
465 sstreamResult << "[";
466
467 for (unsigned int n = 0; n < m_test_data.m_geometry_bo_size / sizeof(float); ++n)
468 {
469 sstreamExpected << m_test_data.m_expected_geometry[n] << ", ";
470 sstreamResult << result_geometry_ptr[n] << ", ";
471
472 if (de::abs(result_geometry_ptr[n] - m_test_data.m_expected_geometry[n]) >= m_epsilon)
473 {
474 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
475
476 m_testCtx.getLog()
477 << tcu::TestLog::Message << "At [" << n
478 << "] position geometry buffer position Reference value is different than the rendered data (epsilon "
479 << m_epsilon << " )"
480 << " (" << m_test_data.m_expected_geometry[n] << ") vs "
481 << "(" << result_geometry_ptr[n] << ")" << tcu::TestLog::EndMessage;
482
483 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
484 return STOP;
485 }
486 }
487
488 sstreamExpected << "]";
489 sstreamResult << "]";
490 m_testCtx.getLog() << tcu::TestLog::Message << "Expected: " << sstreamExpected.str().c_str()
491 << tcu::TestLog::EndMessage;
492 m_testCtx.getLog() << tcu::TestLog::Message << "Result: " << sstreamResult.str().c_str()
493 << tcu::TestLog::EndMessage;
494
495 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
496
497 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
498 return STOP;
499 }
500
501 } // namespace glcts
502