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