1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * OpenGL Conformance Test Suite
3e5c31af7Sopenharmony_ci * -----------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright (c) 2014-2016 The Khronos Group Inc.
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci */ /*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief
22e5c31af7Sopenharmony_ci */ /*-------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "gluDefs.hpp"
25e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
26e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
27e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
28e5c31af7Sopenharmony_ci
29e5c31af7Sopenharmony_ci#include "esextcGeometryShaderAdjacency.hpp"
30e5c31af7Sopenharmony_ci#include <math.h>
31e5c31af7Sopenharmony_ci
32e5c31af7Sopenharmony_cinamespace glcts
33e5c31af7Sopenharmony_ci{
34e5c31af7Sopenharmony_ci/** Constructor
35e5c31af7Sopenharmony_ci *
36e5c31af7Sopenharmony_ci **/
37e5c31af7Sopenharmony_ciAdjacencyGrid::AdjacencyGrid()
38e5c31af7Sopenharmony_ci	: m_line_segments(0), m_points(0), m_triangles(0), m_n_points(0), m_n_segments(0), m_n_triangles(0)
39e5c31af7Sopenharmony_ci{
40e5c31af7Sopenharmony_ci	/* Nothing to be done here */
41e5c31af7Sopenharmony_ci}
42e5c31af7Sopenharmony_ci
43e5c31af7Sopenharmony_ci/** Destructor
44e5c31af7Sopenharmony_ci *
45e5c31af7Sopenharmony_ci **/
46e5c31af7Sopenharmony_ciAdjacencyGrid::~AdjacencyGrid()
47e5c31af7Sopenharmony_ci{
48e5c31af7Sopenharmony_ci	if (m_line_segments)
49e5c31af7Sopenharmony_ci	{
50e5c31af7Sopenharmony_ci		delete[] m_line_segments;
51e5c31af7Sopenharmony_ci		m_line_segments = 0;
52e5c31af7Sopenharmony_ci	}
53e5c31af7Sopenharmony_ci
54e5c31af7Sopenharmony_ci	if (m_points)
55e5c31af7Sopenharmony_ci	{
56e5c31af7Sopenharmony_ci		delete[] m_points;
57e5c31af7Sopenharmony_ci		m_points = 0;
58e5c31af7Sopenharmony_ci	}
59e5c31af7Sopenharmony_ci
60e5c31af7Sopenharmony_ci	if (m_triangles)
61e5c31af7Sopenharmony_ci	{
62e5c31af7Sopenharmony_ci		delete[] m_triangles;
63e5c31af7Sopenharmony_ci		m_triangles = 0;
64e5c31af7Sopenharmony_ci	}
65e5c31af7Sopenharmony_ci}
66e5c31af7Sopenharmony_ci
67e5c31af7Sopenharmony_ci/** Constructor
68e5c31af7Sopenharmony_ci *
69e5c31af7Sopenharmony_ci **/
70e5c31af7Sopenharmony_ciAdjacencyGridStrip::AdjacencyGridStrip() : m_n_points(0), m_points(0)
71e5c31af7Sopenharmony_ci{
72e5c31af7Sopenharmony_ci	/* Nothing to be done here */
73e5c31af7Sopenharmony_ci}
74e5c31af7Sopenharmony_ci
75e5c31af7Sopenharmony_ci/** Destructor
76e5c31af7Sopenharmony_ci *
77e5c31af7Sopenharmony_ci **/
78e5c31af7Sopenharmony_ciAdjacencyGridStrip::~AdjacencyGridStrip()
79e5c31af7Sopenharmony_ci{
80e5c31af7Sopenharmony_ci	if (m_points)
81e5c31af7Sopenharmony_ci	{
82e5c31af7Sopenharmony_ci		delete[] m_points;
83e5c31af7Sopenharmony_ci	}
84e5c31af7Sopenharmony_ci}
85e5c31af7Sopenharmony_ci
86e5c31af7Sopenharmony_ci/** Constructor
87e5c31af7Sopenharmony_ci *
88e5c31af7Sopenharmony_ci **/
89e5c31af7Sopenharmony_ciAdjacencyTestData::AdjacencyTestData()
90e5c31af7Sopenharmony_ci	: m_gs_code(0)
91e5c31af7Sopenharmony_ci	, m_mode(0)
92e5c31af7Sopenharmony_ci	, m_n_vertices(0)
93e5c31af7Sopenharmony_ci	, m_grid(0)
94e5c31af7Sopenharmony_ci	, m_geometry_bo_size(0)
95e5c31af7Sopenharmony_ci	, m_index_data_bo_size(0)
96e5c31af7Sopenharmony_ci	, m_vertex_data_bo_size(0)
97e5c31af7Sopenharmony_ci	, m_expected_adjacency_geometry(0)
98e5c31af7Sopenharmony_ci	, m_expected_geometry(0)
99e5c31af7Sopenharmony_ci	, m_alternate_expected_adjacency_geometry(0)
100e5c31af7Sopenharmony_ci	, m_alternate_expected_geometry(0)
101e5c31af7Sopenharmony_ci	, m_index_data(0)
102e5c31af7Sopenharmony_ci	, m_tf_mode(0)
103e5c31af7Sopenharmony_ci	, m_vertex_data(0)
104e5c31af7Sopenharmony_ci{
105e5c31af7Sopenharmony_ci	/* Nothing to be done here */
106e5c31af7Sopenharmony_ci}
107e5c31af7Sopenharmony_ci
108e5c31af7Sopenharmony_ci/** Destructor
109e5c31af7Sopenharmony_ci *
110e5c31af7Sopenharmony_ci **/
111e5c31af7Sopenharmony_ciAdjacencyTestData::~AdjacencyTestData()
112e5c31af7Sopenharmony_ci{
113e5c31af7Sopenharmony_ci	if (m_expected_adjacency_geometry)
114e5c31af7Sopenharmony_ci	{
115e5c31af7Sopenharmony_ci		delete[] m_expected_adjacency_geometry;
116e5c31af7Sopenharmony_ci		m_expected_adjacency_geometry = 0;
117e5c31af7Sopenharmony_ci	}
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci	if (m_expected_geometry)
120e5c31af7Sopenharmony_ci	{
121e5c31af7Sopenharmony_ci		delete[] m_expected_geometry;
122e5c31af7Sopenharmony_ci		m_expected_geometry = 0;
123e5c31af7Sopenharmony_ci	}
124e5c31af7Sopenharmony_ci
125e5c31af7Sopenharmony_ci	if (m_alternate_expected_adjacency_geometry)
126e5c31af7Sopenharmony_ci	{
127e5c31af7Sopenharmony_ci		delete[] m_alternate_expected_adjacency_geometry;
128e5c31af7Sopenharmony_ci		m_alternate_expected_adjacency_geometry = 0;
129e5c31af7Sopenharmony_ci	}
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci	if (m_alternate_expected_geometry)
132e5c31af7Sopenharmony_ci	{
133e5c31af7Sopenharmony_ci		delete[] m_alternate_expected_geometry;
134e5c31af7Sopenharmony_ci		m_alternate_expected_geometry = 0;
135e5c31af7Sopenharmony_ci	}
136e5c31af7Sopenharmony_ci
137e5c31af7Sopenharmony_ci	if (m_vertex_data)
138e5c31af7Sopenharmony_ci	{
139e5c31af7Sopenharmony_ci		delete[] m_vertex_data;
140e5c31af7Sopenharmony_ci		m_vertex_data = 0;
141e5c31af7Sopenharmony_ci	}
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ci	if (m_index_data)
144e5c31af7Sopenharmony_ci	{
145e5c31af7Sopenharmony_ci		delete[] m_index_data;
146e5c31af7Sopenharmony_ci		m_index_data = 0;
147e5c31af7Sopenharmony_ci	}
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci	if (m_grid)
150e5c31af7Sopenharmony_ci	{
151e5c31af7Sopenharmony_ci		delete m_grid;
152e5c31af7Sopenharmony_ci		m_grid = 0;
153e5c31af7Sopenharmony_ci	}
154e5c31af7Sopenharmony_ci}
155e5c31af7Sopenharmony_ci
156e5c31af7Sopenharmony_ci/** Constructor
157e5c31af7Sopenharmony_ci *
158e5c31af7Sopenharmony_ci * @param context       Test context
159e5c31af7Sopenharmony_ci * @param name          Test case's name
160e5c31af7Sopenharmony_ci * @param description   Test case's desricption
161e5c31af7Sopenharmony_ci **/
162e5c31af7Sopenharmony_ciGeometryShaderAdjacency::GeometryShaderAdjacency(Context& context, const ExtParameters& extParams, const char* name,
163e5c31af7Sopenharmony_ci												 const char* description, AdjacencyTestData& testData)
164e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
165e5c31af7Sopenharmony_ci	, m_adjacency_geometry_bo_id(0)
166e5c31af7Sopenharmony_ci	, m_fs_id(0)
167e5c31af7Sopenharmony_ci	, m_geometry_bo_id(0)
168e5c31af7Sopenharmony_ci	, m_gs_id(0)
169e5c31af7Sopenharmony_ci	, m_index_data_bo_id(0)
170e5c31af7Sopenharmony_ci	, m_vertex_data_bo_id(0)
171e5c31af7Sopenharmony_ci	, m_po_id(0)
172e5c31af7Sopenharmony_ci	, m_test_data(testData)
173e5c31af7Sopenharmony_ci	, m_vao_id(0)
174e5c31af7Sopenharmony_ci	, m_vs_id(0)
175e5c31af7Sopenharmony_ci	, m_components_input(2)
176e5c31af7Sopenharmony_ci	, m_epsilon(0.00001F)
177e5c31af7Sopenharmony_ci	, m_position_attribute_location(0)
178e5c31af7Sopenharmony_ci{
179e5c31af7Sopenharmony_ci	/* Nothing to be done here */
180e5c31af7Sopenharmony_ci}
181e5c31af7Sopenharmony_ci
182e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test.
183e5c31af7Sopenharmony_ci *
184e5c31af7Sopenharmony_ci */
185e5c31af7Sopenharmony_civoid GeometryShaderAdjacency::deinit(void)
186e5c31af7Sopenharmony_ci{
187e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
188e5c31af7Sopenharmony_ci
189e5c31af7Sopenharmony_ci	/* Reset OpenGL ES state */
190e5c31af7Sopenharmony_ci	gl.useProgram(0);
191e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
192e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
193e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, 0);
194e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
195e5c31af7Sopenharmony_ci
196e5c31af7Sopenharmony_ci	if (m_po_id != 0)
197e5c31af7Sopenharmony_ci	{
198e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
199e5c31af7Sopenharmony_ci	}
200e5c31af7Sopenharmony_ci
201e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
202e5c31af7Sopenharmony_ci	{
203e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
204e5c31af7Sopenharmony_ci	}
205e5c31af7Sopenharmony_ci
206e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
207e5c31af7Sopenharmony_ci	{
208e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
209e5c31af7Sopenharmony_ci	}
210e5c31af7Sopenharmony_ci
211e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
212e5c31af7Sopenharmony_ci	{
213e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
214e5c31af7Sopenharmony_ci	}
215e5c31af7Sopenharmony_ci
216e5c31af7Sopenharmony_ci	if (m_adjacency_geometry_bo_id != 0)
217e5c31af7Sopenharmony_ci	{
218e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_adjacency_geometry_bo_id);
219e5c31af7Sopenharmony_ci	}
220e5c31af7Sopenharmony_ci	if (m_geometry_bo_id != 0)
221e5c31af7Sopenharmony_ci	{
222e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_geometry_bo_id);
223e5c31af7Sopenharmony_ci	}
224e5c31af7Sopenharmony_ci
225e5c31af7Sopenharmony_ci	if (m_index_data_bo_id != 0)
226e5c31af7Sopenharmony_ci	{
227e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_index_data_bo_id);
228e5c31af7Sopenharmony_ci	}
229e5c31af7Sopenharmony_ci
230e5c31af7Sopenharmony_ci	if (m_vertex_data_bo_id != 0)
231e5c31af7Sopenharmony_ci	{
232e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_vertex_data_bo_id);
233e5c31af7Sopenharmony_ci	}
234e5c31af7Sopenharmony_ci
235e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
236e5c31af7Sopenharmony_ci	{
237e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
238e5c31af7Sopenharmony_ci	}
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
241e5c31af7Sopenharmony_ci}
242e5c31af7Sopenharmony_ci
243e5c31af7Sopenharmony_ci/** Returns code for Fragment Shader
244e5c31af7Sopenharmony_ci * @return pointer to literal with Fragment Shader code
245e5c31af7Sopenharmony_ci **/
246e5c31af7Sopenharmony_ciconst char* GeometryShaderAdjacency::getFragmentShaderCode()
247e5c31af7Sopenharmony_ci{
248e5c31af7Sopenharmony_ci	static const char* result = "${VERSION}\n"
249e5c31af7Sopenharmony_ci								"\n"
250e5c31af7Sopenharmony_ci								"precision highp float;\n"
251e5c31af7Sopenharmony_ci								"\n"
252e5c31af7Sopenharmony_ci								"void main()\n"
253e5c31af7Sopenharmony_ci								"{\n"
254e5c31af7Sopenharmony_ci								"}\n";
255e5c31af7Sopenharmony_ci	return result;
256e5c31af7Sopenharmony_ci}
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_ci/** Returns code for Vertex Shader
259e5c31af7Sopenharmony_ci * @return pointer to literal with Vertex Shader code
260e5c31af7Sopenharmony_ci **/
261e5c31af7Sopenharmony_ciconst char* GeometryShaderAdjacency::getVertexShaderCode()
262e5c31af7Sopenharmony_ci{
263e5c31af7Sopenharmony_ci	static const char* result = "${VERSION}\n"
264e5c31af7Sopenharmony_ci								"\n"
265e5c31af7Sopenharmony_ci								"precision highp float;\n"
266e5c31af7Sopenharmony_ci								"\n"
267e5c31af7Sopenharmony_ci								"layout(location = 0) in vec2 position_data;\n"
268e5c31af7Sopenharmony_ci								"\n"
269e5c31af7Sopenharmony_ci								"void main()\n"
270e5c31af7Sopenharmony_ci								"{\n"
271e5c31af7Sopenharmony_ci								"    gl_Position = vec4(position_data, 0, 1);\n"
272e5c31af7Sopenharmony_ci								"}\n";
273e5c31af7Sopenharmony_ci	return result;
274e5c31af7Sopenharmony_ci}
275e5c31af7Sopenharmony_ci
276e5c31af7Sopenharmony_ci/** Initializes GLES objects used during the test.
277e5c31af7Sopenharmony_ci *
278e5c31af7Sopenharmony_ci **/
279e5c31af7Sopenharmony_civoid GeometryShaderAdjacency::initTest(void)
280e5c31af7Sopenharmony_ci{
281e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
282e5c31af7Sopenharmony_ci
283e5c31af7Sopenharmony_ci	/* check if EXT_geometry_shader extension is supported */
284e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
285e5c31af7Sopenharmony_ci	{
286e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
287e5c31af7Sopenharmony_ci	}
288e5c31af7Sopenharmony_ci
289e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
290e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
291e5c31af7Sopenharmony_ci
292e5c31af7Sopenharmony_ci	/* Get shader code */
293e5c31af7Sopenharmony_ci	const char* fsCode = getFragmentShaderCode();
294e5c31af7Sopenharmony_ci	const char* gsCode = m_test_data.m_gs_code;
295e5c31af7Sopenharmony_ci	const char* vsCode = getVertexShaderCode();
296e5c31af7Sopenharmony_ci
297e5c31af7Sopenharmony_ci	/* Create shader and program objects */
298e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
299e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
300e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
301e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
302e5c31af7Sopenharmony_ci
303e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program/shader objects.");
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_ci	/* If gs code is available set gs out data for transformfeedback*/
306e5c31af7Sopenharmony_ci	if (m_test_data.m_gs_code)
307e5c31af7Sopenharmony_ci	{
308e5c31af7Sopenharmony_ci		const char* varyings[] = { "out_adjacent_geometry", "out_geometry" };
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci		gl.transformFeedbackVaryings(m_po_id, 2, varyings, GL_SEPARATE_ATTRIBS);
311e5c31af7Sopenharmony_ci	}
312e5c31af7Sopenharmony_ci	else
313e5c31af7Sopenharmony_ci	{
314e5c31af7Sopenharmony_ci		const char* varyings[] = { "gl_Position" };
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci		gl.transformFeedbackVaryings(m_po_id, 1, varyings, GL_SEPARATE_ATTRIBS);
317e5c31af7Sopenharmony_ci	}
318e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex array object!");
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_ci	/* Build program */
321e5c31af7Sopenharmony_ci	if (!buildProgram(m_po_id, m_fs_id, 1, /* parts */ &fsCode, (gsCode) ? m_gs_id : 0, (gsCode) ? 1 : 0,
322e5c31af7Sopenharmony_ci					  (gsCode) ? &gsCode : 0, m_vs_id, 1, /* parts */ &vsCode))
323e5c31af7Sopenharmony_ci	{
324e5c31af7Sopenharmony_ci		TCU_FAIL("Could not create a program object from a valid shader!");
325e5c31af7Sopenharmony_ci	}
326e5c31af7Sopenharmony_ci
327e5c31af7Sopenharmony_ci	/* Generate buffers for input/output vertex data */
328e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_vertex_data_bo_id);
329e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_adjacency_geometry_bo_id);
330e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_geometry_bo_id);
331e5c31af7Sopenharmony_ci
332e5c31af7Sopenharmony_ci	/* Configure buffers for input/output vertex data */
333e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_adjacency_geometry_bo_id);
334e5c31af7Sopenharmony_ci	gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_geometry_bo_size * 4, 0, GL_DYNAMIC_DRAW);
335e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_geometry_bo_id);
336e5c31af7Sopenharmony_ci	gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_geometry_bo_size * 4, 0, GL_DYNAMIC_DRAW);
337e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_data_bo_id);
338e5c31af7Sopenharmony_ci	gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_vertex_data_bo_size, m_test_data.m_vertex_data, GL_DYNAMIC_DRAW);
339e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
340e5c31af7Sopenharmony_ci
341e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex buffer objects for vertex data!");
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_ci	/* Configure buffer for index data */
344e5c31af7Sopenharmony_ci	if (m_test_data.m_index_data_bo_size > 0)
345e5c31af7Sopenharmony_ci	{
346e5c31af7Sopenharmony_ci		gl.genBuffers(1, &m_index_data_bo_id);
347e5c31af7Sopenharmony_ci		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_data_bo_id);
348e5c31af7Sopenharmony_ci		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, m_test_data.m_index_data_bo_size, m_test_data.m_index_data,
349e5c31af7Sopenharmony_ci					  GL_DYNAMIC_DRAW);
350e5c31af7Sopenharmony_ci		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
351e5c31af7Sopenharmony_ci
352e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex buffer objects for index data!");
353e5c31af7Sopenharmony_ci	}
354e5c31af7Sopenharmony_ci}
355e5c31af7Sopenharmony_ci
356e5c31af7Sopenharmony_ci/** Executes the test.
357e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
358e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
359e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
360e5c31af7Sopenharmony_ci **/
361e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderAdjacency::iterate(void)
362e5c31af7Sopenharmony_ci{
363e5c31af7Sopenharmony_ci	initTest();
364e5c31af7Sopenharmony_ci
365e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
366e5c31af7Sopenharmony_ci
367e5c31af7Sopenharmony_ci	/** Bind a vertex array object */
368e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
369e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
370e5c31af7Sopenharmony_ci
371e5c31af7Sopenharmony_ci	/* Bind buffer objects used as data store for transform feedback to TF binding points*/
372e5c31af7Sopenharmony_ci	if (m_test_data.m_gs_code)
373e5c31af7Sopenharmony_ci	{
374e5c31af7Sopenharmony_ci		gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_adjacency_geometry_bo_id);
375e5c31af7Sopenharmony_ci		gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, m_geometry_bo_id);
376e5c31af7Sopenharmony_ci	}
377e5c31af7Sopenharmony_ci	else
378e5c31af7Sopenharmony_ci	{
379e5c31af7Sopenharmony_ci		gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_geometry_bo_id);
380e5c31af7Sopenharmony_ci	}
381e5c31af7Sopenharmony_ci
382e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring transform feedback buffer binding points!");
383e5c31af7Sopenharmony_ci
384e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_data_bo_id);
385e5c31af7Sopenharmony_ci	m_position_attribute_location = gl.getAttribLocation(m_po_id, "position_data");
386e5c31af7Sopenharmony_ci	gl.vertexAttribPointer(m_position_attribute_location, m_components_input, GL_FLOAT, GL_FALSE, 0, 0);
387e5c31af7Sopenharmony_ci	gl.enableVertexAttribArray(m_position_attribute_location);
388e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting vertex attribute array for position_data attribute");
389e5c31af7Sopenharmony_ci
390e5c31af7Sopenharmony_ci	/* bind index buffer */
391e5c31af7Sopenharmony_ci	if (m_test_data.m_index_data_bo_size > 0)
392e5c31af7Sopenharmony_ci	{
393e5c31af7Sopenharmony_ci		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_data_bo_id);
394e5c31af7Sopenharmony_ci	}
395e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding index data buffer");
396e5c31af7Sopenharmony_ci
397e5c31af7Sopenharmony_ci	/* Configure program */
398e5c31af7Sopenharmony_ci	gl.enable(GL_RASTERIZER_DISCARD);
399e5c31af7Sopenharmony_ci	gl.useProgram(m_po_id);
400e5c31af7Sopenharmony_ci	gl.beginTransformFeedback(m_test_data.m_tf_mode);
401e5c31af7Sopenharmony_ci
402e5c31af7Sopenharmony_ci	glw::GLuint nVertices = m_test_data.m_n_vertices * ((m_test_data.m_mode == m_glExtTokens.LINE_STRIP_ADJACENCY ||
403e5c31af7Sopenharmony_ci														 m_test_data.m_mode == m_glExtTokens.TRIANGLE_STRIP_ADJACENCY) ?
404e5c31af7Sopenharmony_ci															1 :
405e5c31af7Sopenharmony_ci															2 /* include adjacency info */);
406e5c31af7Sopenharmony_ci
407e5c31af7Sopenharmony_ci	/* Use glDrawElements if data is indicied */
408e5c31af7Sopenharmony_ci	if (m_test_data.m_index_data_bo_size > 0)
409e5c31af7Sopenharmony_ci	{
410e5c31af7Sopenharmony_ci		gl.drawElements(m_test_data.m_mode, nVertices, GL_UNSIGNED_INT, 0);
411e5c31af7Sopenharmony_ci	}
412e5c31af7Sopenharmony_ci	/* Use glDrawArrays if data is non indicied */
413e5c31af7Sopenharmony_ci	else
414e5c31af7Sopenharmony_ci	{
415e5c31af7Sopenharmony_ci		gl.drawArrays(m_test_data.m_mode, 0, nVertices);
416e5c31af7Sopenharmony_ci	}
417e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error while trying to render");
418e5c31af7Sopenharmony_ci
419e5c31af7Sopenharmony_ci	gl.disable(GL_RASTERIZER_DISCARD);
420e5c31af7Sopenharmony_ci	gl.endTransformFeedback();
421e5c31af7Sopenharmony_ci
422e5c31af7Sopenharmony_ci	/* Map result buffer objects into client space */
423e5c31af7Sopenharmony_ci	float* result_adjacency_geometry_ptr = 0;
424e5c31af7Sopenharmony_ci	float* result_geometry_ptr			 = 0;
425e5c31af7Sopenharmony_ci
426e5c31af7Sopenharmony_ci	bool hasAlternateData = m_test_data.m_alternate_expected_geometry != nullptr &&
427e5c31af7Sopenharmony_ci							m_test_data.m_alternate_expected_adjacency_geometry != nullptr;
428e5c31af7Sopenharmony_ci	bool adjacentMatchesExpected		  = true;
429e5c31af7Sopenharmony_ci	bool adjacentMatchesAlternateExpected = hasAlternateData;
430e5c31af7Sopenharmony_ci
431e5c31af7Sopenharmony_ci	/* If gs is available read adjacency data using TF and compare with expected data*/
432e5c31af7Sopenharmony_ci	if (m_test_data.m_gs_code)
433e5c31af7Sopenharmony_ci	{
434e5c31af7Sopenharmony_ci		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_adjacency_geometry_bo_id);
435e5c31af7Sopenharmony_ci		result_adjacency_geometry_ptr =
436e5c31af7Sopenharmony_ci			(float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_test_data.m_geometry_bo_size, GL_MAP_READ_BIT);
437e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "Error when mapping data to client space");
438e5c31af7Sopenharmony_ci
439e5c31af7Sopenharmony_ci		std::stringstream sstreamExpected;
440e5c31af7Sopenharmony_ci		std::stringstream sstreamAlternateExpected;
441e5c31af7Sopenharmony_ci		std::stringstream sstreamResult;
442e5c31af7Sopenharmony_ci		sstreamExpected << "[";
443e5c31af7Sopenharmony_ci		if (hasAlternateData)
444e5c31af7Sopenharmony_ci			sstreamAlternateExpected << "[";
445e5c31af7Sopenharmony_ci		sstreamResult << "[";
446e5c31af7Sopenharmony_ci
447e5c31af7Sopenharmony_ci		unsigned int differentExpectedIndex			 = 0;
448e5c31af7Sopenharmony_ci		unsigned int differentAlternateExpectedIndex = 0;
449e5c31af7Sopenharmony_ci		for (unsigned int n = 0; n < m_test_data.m_geometry_bo_size / sizeof(float); ++n)
450e5c31af7Sopenharmony_ci		{
451e5c31af7Sopenharmony_ci			sstreamExpected << m_test_data.m_expected_adjacency_geometry[n] << ", ";
452e5c31af7Sopenharmony_ci			if (hasAlternateData)
453e5c31af7Sopenharmony_ci				sstreamAlternateExpected << m_test_data.m_alternate_expected_adjacency_geometry[n] << ", ";
454e5c31af7Sopenharmony_ci			sstreamResult << result_adjacency_geometry_ptr[n] << ", ";
455e5c31af7Sopenharmony_ci
456e5c31af7Sopenharmony_ci			if (adjacentMatchesExpected &&
457e5c31af7Sopenharmony_ci				de::abs(result_adjacency_geometry_ptr[n] -
458e5c31af7Sopenharmony_ci									   m_test_data.m_expected_adjacency_geometry[n]) >= m_epsilon)
459e5c31af7Sopenharmony_ci			{
460e5c31af7Sopenharmony_ci				adjacentMatchesExpected = false;
461e5c31af7Sopenharmony_ci				differentExpectedIndex = n;
462e5c31af7Sopenharmony_ci			}
463e5c31af7Sopenharmony_ci			if (adjacentMatchesAlternateExpected &&
464e5c31af7Sopenharmony_ci				de::abs(result_adjacency_geometry_ptr[n] - m_test_data.m_alternate_expected_adjacency_geometry[n]) >=
465e5c31af7Sopenharmony_ci					m_epsilon)
466e5c31af7Sopenharmony_ci			{
467e5c31af7Sopenharmony_ci				adjacentMatchesAlternateExpected = false;
468e5c31af7Sopenharmony_ci				differentAlternateExpectedIndex = n;
469e5c31af7Sopenharmony_ci			}
470e5c31af7Sopenharmony_ci			if (!adjacentMatchesExpected && !adjacentMatchesAlternateExpected)
471e5c31af7Sopenharmony_ci			{
472e5c31af7Sopenharmony_ci				gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
473e5c31af7Sopenharmony_ci
474e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "At [" << differentExpectedIndex
475e5c31af7Sopenharmony_ci								   << "] position adjacency buffer position Reference value is different than the "
476e5c31af7Sopenharmony_ci									  "rendered data (epsilon "
477e5c31af7Sopenharmony_ci								   << m_epsilon << " )"
478e5c31af7Sopenharmony_ci								   << " (" << m_test_data.m_expected_adjacency_geometry[differentExpectedIndex]
479e5c31af7Sopenharmony_ci								   << ") vs "
480e5c31af7Sopenharmony_ci								   << "(" << result_adjacency_geometry_ptr[differentExpectedIndex] << ")"
481e5c31af7Sopenharmony_ci								   << tcu::TestLog::EndMessage;
482e5c31af7Sopenharmony_ci
483e5c31af7Sopenharmony_ci				if (hasAlternateData)
484e5c31af7Sopenharmony_ci				{
485e5c31af7Sopenharmony_ci					m_testCtx.getLog()
486e5c31af7Sopenharmony_ci						<< tcu::TestLog::Message << "At [" << differentAlternateExpectedIndex
487e5c31af7Sopenharmony_ci						<< "] alternate position adjacency buffer position Reference value is different than the "
488e5c31af7Sopenharmony_ci						   "rendered data (epsilon "
489e5c31af7Sopenharmony_ci						<< m_epsilon << " )"
490e5c31af7Sopenharmony_ci						<< " (" << m_test_data.m_alternate_expected_adjacency_geometry[differentAlternateExpectedIndex]
491e5c31af7Sopenharmony_ci						<< ") vs "
492e5c31af7Sopenharmony_ci						<< "(" << result_adjacency_geometry_ptr[differentAlternateExpectedIndex] << ")"
493e5c31af7Sopenharmony_ci						<< tcu::TestLog::EndMessage;
494e5c31af7Sopenharmony_ci				}
495e5c31af7Sopenharmony_ci
496e5c31af7Sopenharmony_ci				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
497e5c31af7Sopenharmony_ci				return STOP;
498e5c31af7Sopenharmony_ci			}
499e5c31af7Sopenharmony_ci		}
500e5c31af7Sopenharmony_ci
501e5c31af7Sopenharmony_ci		sstreamExpected << "]";
502e5c31af7Sopenharmony_ci		if (hasAlternateData)
503e5c31af7Sopenharmony_ci			sstreamAlternateExpected << "]";
504e5c31af7Sopenharmony_ci		sstreamResult << "]";
505e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Adjacency Expected: " << sstreamExpected.str().c_str()
506e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
507e5c31af7Sopenharmony_ci		if (hasAlternateData)
508e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message
509e5c31af7Sopenharmony_ci							   << "Alternate adjacency Expected: " << sstreamAlternateExpected.str().c_str()
510e5c31af7Sopenharmony_ci							   << tcu::TestLog::EndMessage;
511e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Adjacency Result:  " << sstreamResult.str().c_str()
512e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
513e5c31af7Sopenharmony_ci
514e5c31af7Sopenharmony_ci		gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
515e5c31af7Sopenharmony_ci	}
516e5c31af7Sopenharmony_ci
517e5c31af7Sopenharmony_ci	/* Read vertex data using TF and compare with expected data*/
518e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_geometry_bo_id);
519e5c31af7Sopenharmony_ci	result_geometry_ptr =
520e5c31af7Sopenharmony_ci		(float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_test_data.m_geometry_bo_size, GL_MAP_READ_BIT);
521e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error when mapping data to client space");
522e5c31af7Sopenharmony_ci
523e5c31af7Sopenharmony_ci	std::stringstream sstreamExpected;
524e5c31af7Sopenharmony_ci	std::stringstream sstreamAlternateExpected;
525e5c31af7Sopenharmony_ci	std::stringstream sstreamResult;
526e5c31af7Sopenharmony_ci	sstreamExpected << "[";
527e5c31af7Sopenharmony_ci	if (hasAlternateData)
528e5c31af7Sopenharmony_ci	{
529e5c31af7Sopenharmony_ci		sstreamAlternateExpected << "[";
530e5c31af7Sopenharmony_ci	}
531e5c31af7Sopenharmony_ci	sstreamResult << "[";
532e5c31af7Sopenharmony_ci
533e5c31af7Sopenharmony_ci	bool		 matchesExpected		  = true;
534e5c31af7Sopenharmony_ci	bool		 matchesAlternateExpected = hasAlternateData;
535e5c31af7Sopenharmony_ci	unsigned int differentIndex			  = 0;
536e5c31af7Sopenharmony_ci	unsigned int differentAlternateIndex  = 0;
537e5c31af7Sopenharmony_ci
538e5c31af7Sopenharmony_ci	for (unsigned int n = 0; n < m_test_data.m_geometry_bo_size / sizeof(float); ++n)
539e5c31af7Sopenharmony_ci	{
540e5c31af7Sopenharmony_ci		sstreamExpected << m_test_data.m_expected_geometry[n] << ", ";
541e5c31af7Sopenharmony_ci		if (hasAlternateData)
542e5c31af7Sopenharmony_ci		{
543e5c31af7Sopenharmony_ci			sstreamAlternateExpected << m_test_data.m_alternate_expected_geometry[n] << ", ";
544e5c31af7Sopenharmony_ci		}
545e5c31af7Sopenharmony_ci		sstreamResult << result_geometry_ptr[n] << ", ";
546e5c31af7Sopenharmony_ci
547e5c31af7Sopenharmony_ci		if (matchesExpected && de::abs(result_geometry_ptr[n] - m_test_data.m_expected_geometry[n]) >= m_epsilon)
548e5c31af7Sopenharmony_ci		{
549e5c31af7Sopenharmony_ci			matchesExpected = false;
550e5c31af7Sopenharmony_ci			differentIndex	= n;
551e5c31af7Sopenharmony_ci		}
552e5c31af7Sopenharmony_ci		if (matchesAlternateExpected &&
553e5c31af7Sopenharmony_ci			de::abs(result_geometry_ptr[n] - m_test_data.m_alternate_expected_geometry[n]) >= m_epsilon)
554e5c31af7Sopenharmony_ci		{
555e5c31af7Sopenharmony_ci			matchesAlternateExpected = false;
556e5c31af7Sopenharmony_ci			differentAlternateIndex	 = n;
557e5c31af7Sopenharmony_ci		}
558e5c31af7Sopenharmony_ci		if (!matchesExpected && !matchesAlternateExpected)
559e5c31af7Sopenharmony_ci		{
560e5c31af7Sopenharmony_ci			gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
561e5c31af7Sopenharmony_ci
562e5c31af7Sopenharmony_ci			m_testCtx.getLog()
563e5c31af7Sopenharmony_ci				<< tcu::TestLog::Message << "At [" << differentIndex
564e5c31af7Sopenharmony_ci				<< "] position geometry buffer position Reference value is different than the rendered data (epsilon "
565e5c31af7Sopenharmony_ci				<< m_epsilon << " )"
566e5c31af7Sopenharmony_ci				<< " (" << m_test_data.m_expected_geometry[differentIndex] << ") vs "
567e5c31af7Sopenharmony_ci				<< "(" << result_geometry_ptr[differentIndex] << ")" << tcu::TestLog::EndMessage;
568e5c31af7Sopenharmony_ci
569e5c31af7Sopenharmony_ci			if (hasAlternateData)
570e5c31af7Sopenharmony_ci			{
571e5c31af7Sopenharmony_ci				m_testCtx.getLog()
572e5c31af7Sopenharmony_ci					<< tcu::TestLog::Message << "At [" << differentAlternateIndex
573e5c31af7Sopenharmony_ci					<< "] alternate position geometry buffer position Reference value is different than the rendered data (epsilon "
574e5c31af7Sopenharmony_ci					<< m_epsilon << " )"
575e5c31af7Sopenharmony_ci					<< " (" << m_test_data.m_alternate_expected_geometry[differentAlternateIndex] << ") vs "
576e5c31af7Sopenharmony_ci					<< "(" << result_geometry_ptr[differentAlternateIndex] << ")" << tcu::TestLog::EndMessage;
577e5c31af7Sopenharmony_ci			}
578e5c31af7Sopenharmony_ci
579e5c31af7Sopenharmony_ci			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
580e5c31af7Sopenharmony_ci			return STOP;
581e5c31af7Sopenharmony_ci		}
582e5c31af7Sopenharmony_ci	}
583e5c31af7Sopenharmony_ci
584e5c31af7Sopenharmony_ci	if (matchesExpected && !adjacentMatchesExpected)
585e5c31af7Sopenharmony_ci	{
586e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
587e5c31af7Sopenharmony_ci						   << "Geometry matches OpenGL ordering but adjacent geometry matches Vulkan ordering"
588e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
589e5c31af7Sopenharmony_ci
590e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
591e5c31af7Sopenharmony_ci		return STOP;
592e5c31af7Sopenharmony_ci	}
593e5c31af7Sopenharmony_ci	if (matchesAlternateExpected && !adjacentMatchesAlternateExpected)
594e5c31af7Sopenharmony_ci	{
595e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
596e5c31af7Sopenharmony_ci						   << "Geometry matches Vulkan ordering but adjacent geometry matches OpenGL ordering"
597e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
598e5c31af7Sopenharmony_ci
599e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
600e5c31af7Sopenharmony_ci		return STOP;
601e5c31af7Sopenharmony_ci	}
602e5c31af7Sopenharmony_ci
603e5c31af7Sopenharmony_ci	sstreamExpected << "]";
604e5c31af7Sopenharmony_ci	sstreamResult << "]";
605e5c31af7Sopenharmony_ci	if (hasAlternateData)
606e5c31af7Sopenharmony_ci	{
607e5c31af7Sopenharmony_ci		sstreamAlternateExpected << "]";
608e5c31af7Sopenharmony_ci
609e5c31af7Sopenharmony_ci		sstreamExpected << "\nor\n" << sstreamAlternateExpected.str();
610e5c31af7Sopenharmony_ci	}
611e5c31af7Sopenharmony_ci	m_testCtx.getLog() << tcu::TestLog::Message << "Expected: " << sstreamExpected.str().c_str()
612e5c31af7Sopenharmony_ci					   << tcu::TestLog::EndMessage;
613e5c31af7Sopenharmony_ci	m_testCtx.getLog() << tcu::TestLog::Message << "Result:  " << sstreamResult.str().c_str()
614e5c31af7Sopenharmony_ci					   << tcu::TestLog::EndMessage;
615e5c31af7Sopenharmony_ci
616e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
617e5c31af7Sopenharmony_ci
618e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
619e5c31af7Sopenharmony_ci	return STOP;
620e5c31af7Sopenharmony_ci}
621e5c31af7Sopenharmony_ci
622e5c31af7Sopenharmony_ci} // namespace glcts
623