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 "esextcTessellationShaderXFB.hpp"
25e5c31af7Sopenharmony_ci#include "esextcTessellationShaderUtils.hpp"
26e5c31af7Sopenharmony_ci#include "gluContextInfo.hpp"
27e5c31af7Sopenharmony_ci#include "gluDefs.hpp"
28e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
29e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
30e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
31e5c31af7Sopenharmony_ci
32e5c31af7Sopenharmony_cinamespace glcts
33e5c31af7Sopenharmony_ci{
34e5c31af7Sopenharmony_ci
35e5c31af7Sopenharmony_ci/** Constructor
36e5c31af7Sopenharmony_ci *
37e5c31af7Sopenharmony_ci * @param context Test context
38e5c31af7Sopenharmony_ci **/
39e5c31af7Sopenharmony_ciTessellationShaderXFB::TessellationShaderXFB(Context& context, const ExtParameters& extParams)
40e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, "xfb_captures_data_from_correct_stage",
41e5c31af7Sopenharmony_ci				   "Verifies transform-feedback captures data from appropriate shader stage.")
42e5c31af7Sopenharmony_ci	, m_bo_id(0)
43e5c31af7Sopenharmony_ci	, m_fs_id(0)
44e5c31af7Sopenharmony_ci	, m_gs_id(0)
45e5c31af7Sopenharmony_ci	, m_po_id(0)
46e5c31af7Sopenharmony_ci	, m_tc_id(0)
47e5c31af7Sopenharmony_ci	, m_te_id(0)
48e5c31af7Sopenharmony_ci	, m_vs_id(0)
49e5c31af7Sopenharmony_ci	, m_pipeline_id(0)
50e5c31af7Sopenharmony_ci	, m_fs_program_id(0)
51e5c31af7Sopenharmony_ci	, m_gs_program_id(0)
52e5c31af7Sopenharmony_ci	, m_tc_program_id(0)
53e5c31af7Sopenharmony_ci	, m_te_program_id(0)
54e5c31af7Sopenharmony_ci	, m_vs_program_id(0)
55e5c31af7Sopenharmony_ci	, m_vao_id(0)
56e5c31af7Sopenharmony_ci{
57e5c31af7Sopenharmony_ci	/* Left blank on purpose */
58e5c31af7Sopenharmony_ci}
59e5c31af7Sopenharmony_ci
60e5c31af7Sopenharmony_ci/** Deinitializes ES objects created for the test. */
61e5c31af7Sopenharmony_civoid TessellationShaderXFB::deinit()
62e5c31af7Sopenharmony_ci{
63e5c31af7Sopenharmony_ci	/* Call base class' deinit() */
64e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
65e5c31af7Sopenharmony_ci
66e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
67e5c31af7Sopenharmony_ci	{
68e5c31af7Sopenharmony_ci		return;
69e5c31af7Sopenharmony_ci	}
70e5c31af7Sopenharmony_ci
71e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
72e5c31af7Sopenharmony_ci
73e5c31af7Sopenharmony_ci	/* Reset GL_PATCH_VERTICES_EXT value */
74e5c31af7Sopenharmony_ci	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
75e5c31af7Sopenharmony_ci
76e5c31af7Sopenharmony_ci	/* Disable any pipeline object that may still be active */
77e5c31af7Sopenharmony_ci	gl.bindProgramPipeline(0);
78e5c31af7Sopenharmony_ci
79e5c31af7Sopenharmony_ci	/* Reset TF buffer object bindings */
80e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
81e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
82e5c31af7Sopenharmony_ci
83e5c31af7Sopenharmony_ci	/* Unbind vertex array object */
84e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
85e5c31af7Sopenharmony_ci
86e5c31af7Sopenharmony_ci	/* Free all ES objects we allocated for the test */
87e5c31af7Sopenharmony_ci	if (m_bo_id != 0)
88e5c31af7Sopenharmony_ci	{
89e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_bo_id);
90e5c31af7Sopenharmony_ci
91e5c31af7Sopenharmony_ci		m_bo_id = 0;
92e5c31af7Sopenharmony_ci	}
93e5c31af7Sopenharmony_ci
94e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
95e5c31af7Sopenharmony_ci	{
96e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
97e5c31af7Sopenharmony_ci
98e5c31af7Sopenharmony_ci		m_fs_id = 0;
99e5c31af7Sopenharmony_ci	}
100e5c31af7Sopenharmony_ci
101e5c31af7Sopenharmony_ci	if (m_fs_program_id != 0)
102e5c31af7Sopenharmony_ci	{
103e5c31af7Sopenharmony_ci		gl.deleteProgram(m_fs_program_id);
104e5c31af7Sopenharmony_ci
105e5c31af7Sopenharmony_ci		m_fs_program_id = 0;
106e5c31af7Sopenharmony_ci	}
107e5c31af7Sopenharmony_ci
108e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
109e5c31af7Sopenharmony_ci	{
110e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
111e5c31af7Sopenharmony_ci
112e5c31af7Sopenharmony_ci		m_gs_id = 0;
113e5c31af7Sopenharmony_ci	}
114e5c31af7Sopenharmony_ci
115e5c31af7Sopenharmony_ci	if (m_gs_program_id != 0)
116e5c31af7Sopenharmony_ci	{
117e5c31af7Sopenharmony_ci		gl.deleteProgram(m_gs_program_id);
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci		m_gs_program_id = 0;
120e5c31af7Sopenharmony_ci	}
121e5c31af7Sopenharmony_ci
122e5c31af7Sopenharmony_ci	if (m_pipeline_id != 0)
123e5c31af7Sopenharmony_ci	{
124e5c31af7Sopenharmony_ci		gl.deleteProgramPipelines(1, &m_pipeline_id);
125e5c31af7Sopenharmony_ci
126e5c31af7Sopenharmony_ci		m_pipeline_id = 0;
127e5c31af7Sopenharmony_ci	}
128e5c31af7Sopenharmony_ci
129e5c31af7Sopenharmony_ci	if (m_po_id != 0)
130e5c31af7Sopenharmony_ci	{
131e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
132e5c31af7Sopenharmony_ci
133e5c31af7Sopenharmony_ci		m_po_id = 0;
134e5c31af7Sopenharmony_ci	}
135e5c31af7Sopenharmony_ci
136e5c31af7Sopenharmony_ci	if (m_tc_id != 0)
137e5c31af7Sopenharmony_ci	{
138e5c31af7Sopenharmony_ci		gl.deleteShader(m_tc_id);
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_ci		m_tc_id = 0;
141e5c31af7Sopenharmony_ci	}
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ci	if (m_tc_program_id != 0)
144e5c31af7Sopenharmony_ci	{
145e5c31af7Sopenharmony_ci		gl.deleteProgram(m_tc_program_id);
146e5c31af7Sopenharmony_ci
147e5c31af7Sopenharmony_ci		m_tc_program_id = 0;
148e5c31af7Sopenharmony_ci	}
149e5c31af7Sopenharmony_ci
150e5c31af7Sopenharmony_ci	if (m_te_id != 0)
151e5c31af7Sopenharmony_ci	{
152e5c31af7Sopenharmony_ci		gl.deleteShader(m_te_id);
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci		m_te_id = 0;
155e5c31af7Sopenharmony_ci	}
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_ci	if (m_te_program_id != 0)
158e5c31af7Sopenharmony_ci	{
159e5c31af7Sopenharmony_ci		gl.deleteProgram(m_te_program_id);
160e5c31af7Sopenharmony_ci
161e5c31af7Sopenharmony_ci		m_te_program_id = 0;
162e5c31af7Sopenharmony_ci	}
163e5c31af7Sopenharmony_ci
164e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
165e5c31af7Sopenharmony_ci	{
166e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
167e5c31af7Sopenharmony_ci
168e5c31af7Sopenharmony_ci		m_vs_id = 0;
169e5c31af7Sopenharmony_ci	}
170e5c31af7Sopenharmony_ci
171e5c31af7Sopenharmony_ci	if (m_vs_program_id != 0)
172e5c31af7Sopenharmony_ci	{
173e5c31af7Sopenharmony_ci		gl.deleteProgram(m_vs_program_id);
174e5c31af7Sopenharmony_ci
175e5c31af7Sopenharmony_ci		m_vs_program_id = 0;
176e5c31af7Sopenharmony_ci	}
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
179e5c31af7Sopenharmony_ci	{
180e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
181e5c31af7Sopenharmony_ci
182e5c31af7Sopenharmony_ci		m_vao_id = 0;
183e5c31af7Sopenharmony_ci	}
184e5c31af7Sopenharmony_ci}
185e5c31af7Sopenharmony_ci
186e5c31af7Sopenharmony_ci/** Create separable programs **/
187e5c31af7Sopenharmony_ciglw::GLuint TessellationShaderXFB::createSeparableProgram(glw::GLenum shader_type, unsigned int n_strings,
188e5c31af7Sopenharmony_ci														  const char* const* strings, unsigned int n_varyings,
189e5c31af7Sopenharmony_ci														  const char* const* varyings, bool should_succeed)
190e5c31af7Sopenharmony_ci{
191e5c31af7Sopenharmony_ci	const glw::Functions& gl	= m_context.getRenderContext().getFunctions();
192e5c31af7Sopenharmony_ci	glw::GLuint			  po_id = 0;
193e5c31af7Sopenharmony_ci	glw::GLuint			  so_id = 0;
194e5c31af7Sopenharmony_ci
195e5c31af7Sopenharmony_ci	/* Create a shader object */
196e5c31af7Sopenharmony_ci	so_id = gl.createShader(shader_type);
197e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ci	/* Create a program object */
200e5c31af7Sopenharmony_ci	po_id = gl.createProgram();
201e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
202e5c31af7Sopenharmony_ci
203e5c31af7Sopenharmony_ci	/* Mark the program object as separable */
204e5c31af7Sopenharmony_ci	gl.programParameteri(po_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
205e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed");
206e5c31af7Sopenharmony_ci
207e5c31af7Sopenharmony_ci	/* Configure XFB for the program object */
208e5c31af7Sopenharmony_ci	if (n_varyings != 0)
209e5c31af7Sopenharmony_ci	{
210e5c31af7Sopenharmony_ci		gl.transformFeedbackVaryings(po_id, n_varyings, varyings, GL_SEPARATE_ATTRIBS);
211e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
212e5c31af7Sopenharmony_ci	}
213e5c31af7Sopenharmony_ci
214e5c31af7Sopenharmony_ci	bool build_success = buildProgram(po_id, so_id, n_strings, strings);
215e5c31af7Sopenharmony_ci
216e5c31af7Sopenharmony_ci	/* Safe to delete the shader object at this point */
217e5c31af7Sopenharmony_ci	gl.deleteShader(so_id);
218e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed");
219e5c31af7Sopenharmony_ci
220e5c31af7Sopenharmony_ci	if (!build_success)
221e5c31af7Sopenharmony_ci	{
222e5c31af7Sopenharmony_ci		gl.deleteProgram(po_id);
223e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram() call failed");
224e5c31af7Sopenharmony_ci		po_id = 0;
225e5c31af7Sopenharmony_ci
226e5c31af7Sopenharmony_ci		if (should_succeed)
227e5c31af7Sopenharmony_ci		{
228e5c31af7Sopenharmony_ci			TCU_FAIL("Separable program should have succeeded");
229e5c31af7Sopenharmony_ci		}
230e5c31af7Sopenharmony_ci	}
231e5c31af7Sopenharmony_ci	else if (!should_succeed)
232e5c31af7Sopenharmony_ci	{
233e5c31af7Sopenharmony_ci		std::string shader_source = getShaderSource(so_id);
234e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Shader source:\n\n"
235e5c31af7Sopenharmony_ci						   << shader_source << "\n\n"
236e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
237e5c31af7Sopenharmony_ci		TCU_FAIL("Separable program should have failed");
238e5c31af7Sopenharmony_ci	}
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci	return po_id;
241e5c31af7Sopenharmony_ci}
242e5c31af7Sopenharmony_ci
243e5c31af7Sopenharmony_ci/** Initializes ES objects necessary to run the test. */
244e5c31af7Sopenharmony_civoid TessellationShaderXFB::initTest()
245e5c31af7Sopenharmony_ci{
246e5c31af7Sopenharmony_ci	/* Skip if required extensions are not supported. */
247e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
248e5c31af7Sopenharmony_ci	{
249e5c31af7Sopenharmony_ci		return;
250e5c31af7Sopenharmony_ci	}
251e5c31af7Sopenharmony_ci
252e5c31af7Sopenharmony_ci	/* Generate all objects needed for the test */
253e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
254e5c31af7Sopenharmony_ci
255e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
256e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
259e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
260e5c31af7Sopenharmony_ci
261e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_bo_id);
262e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
265e5c31af7Sopenharmony_ci	m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
266e5c31af7Sopenharmony_ci	m_te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
267e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
268e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
269e5c31af7Sopenharmony_ci
270e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
271e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
272e5c31af7Sopenharmony_ci
273e5c31af7Sopenharmony_ci	if (m_is_geometry_shader_extension_supported)
274e5c31af7Sopenharmony_ci	{
275e5c31af7Sopenharmony_ci		m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
276e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed for GL_GEOMETRY_SHADER_EXT");
277e5c31af7Sopenharmony_ci	}
278e5c31af7Sopenharmony_ci
279e5c31af7Sopenharmony_ci	gl.genProgramPipelines(1, &m_pipeline_id);
280e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() failed");
281e5c31af7Sopenharmony_ci
282e5c31af7Sopenharmony_ci	/* Configure fragment shader body */
283e5c31af7Sopenharmony_ci	const char* fs_body = "${VERSION}\n"
284e5c31af7Sopenharmony_ci						  "\n"
285e5c31af7Sopenharmony_ci						  "${SHADER_IO_BLOCKS_REQUIRE}\n"
286e5c31af7Sopenharmony_ci						  "\n"
287e5c31af7Sopenharmony_ci						  "precision highp float;\n"
288e5c31af7Sopenharmony_ci						  "in BLOCK_INOUT { vec4 value; } user_in;\n"
289e5c31af7Sopenharmony_ci						  "\n"
290e5c31af7Sopenharmony_ci						  "void main()\n"
291e5c31af7Sopenharmony_ci						  "{\n"
292e5c31af7Sopenharmony_ci						  "}\n";
293e5c31af7Sopenharmony_ci
294e5c31af7Sopenharmony_ci	shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
295e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
296e5c31af7Sopenharmony_ci
297e5c31af7Sopenharmony_ci	/* Create a fragment shader program */
298e5c31af7Sopenharmony_ci	glw::GLint		   link_status			= GL_FALSE;
299e5c31af7Sopenharmony_ci	const glw::GLchar* varying_name			= "BLOCK_INOUT.value";
300e5c31af7Sopenharmony_ci
301e5c31af7Sopenharmony_ci	m_fs_program_id = createSeparableProgram(GL_FRAGMENT_SHADER, 1, /* n_strings */
302e5c31af7Sopenharmony_ci											 &fs_body, 0,			/* n_varyings */
303e5c31af7Sopenharmony_ci											 DE_NULL,				/* varyings */
304e5c31af7Sopenharmony_ci											 true);					/* should_succeed */
305e5c31af7Sopenharmony_ci
306e5c31af7Sopenharmony_ci	gl.getProgramiv(m_fs_program_id, GL_LINK_STATUS, &link_status);
307e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
308e5c31af7Sopenharmony_ci
309e5c31af7Sopenharmony_ci	if (link_status != GL_TRUE)
310e5c31af7Sopenharmony_ci	{
311e5c31af7Sopenharmony_ci		TCU_FAIL("Fragment shader program failed to link.");
312e5c31af7Sopenharmony_ci	}
313e5c31af7Sopenharmony_ci
314e5c31af7Sopenharmony_ci	/* Configure geometry shader body */
315e5c31af7Sopenharmony_ci	const char* gs_body = "${VERSION}\n"
316e5c31af7Sopenharmony_ci						  "\n"
317e5c31af7Sopenharmony_ci						  "${GEOMETRY_SHADER_REQUIRE}\n"
318e5c31af7Sopenharmony_ci						  "\n"
319e5c31af7Sopenharmony_ci						  "layout(points)                   in;\n"
320e5c31af7Sopenharmony_ci						  "layout(points, max_vertices = 1) out;\n"
321e5c31af7Sopenharmony_ci						  "\n"
322e5c31af7Sopenharmony_ci						  "precision highp float;\n"
323e5c31af7Sopenharmony_ci						  "${IN_PER_VERTEX_DECL_ARRAY}"
324e5c31af7Sopenharmony_ci						  "${OUT_PER_VERTEX_DECL}"
325e5c31af7Sopenharmony_ci						  "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
326e5c31af7Sopenharmony_ci						  "out BLOCK_INOUT { vec4 value; } user_out;\n"
327e5c31af7Sopenharmony_ci						  "\n"
328e5c31af7Sopenharmony_ci						  "void main()\n"
329e5c31af7Sopenharmony_ci						  "{\n"
330e5c31af7Sopenharmony_ci						  "    user_out.value = vec4(1.0, 2.0, 3.0, 4.0);\n"
331e5c31af7Sopenharmony_ci						  "    gl_Position    = vec4(0.0, 0.0, 0.0, 1.0);\n"
332e5c31af7Sopenharmony_ci						  "\n"
333e5c31af7Sopenharmony_ci						  "    EmitVertex();\n"
334e5c31af7Sopenharmony_ci						  "}\n";
335e5c31af7Sopenharmony_ci
336e5c31af7Sopenharmony_ci	if (m_is_geometry_shader_extension_supported)
337e5c31af7Sopenharmony_ci	{
338e5c31af7Sopenharmony_ci		shaderSourceSpecialized(m_gs_id, 1 /* count */, &gs_body);
339e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for geometry shader");
340e5c31af7Sopenharmony_ci
341e5c31af7Sopenharmony_ci		/* Create a geometry shader program */
342e5c31af7Sopenharmony_ci		m_gs_program_id = createSeparableProgram(m_glExtTokens.GEOMETRY_SHADER, 1, /* n_strings */
343e5c31af7Sopenharmony_ci												 &gs_body, 1,					   /* n_varyings */
344e5c31af7Sopenharmony_ci												 &varying_name, true);			   /* should_succeed */
345e5c31af7Sopenharmony_ci
346e5c31af7Sopenharmony_ci		if (m_gs_program_id == 0)
347e5c31af7Sopenharmony_ci		{
348e5c31af7Sopenharmony_ci			TCU_FAIL("Could not create a separate geometry program object");
349e5c31af7Sopenharmony_ci		}
350e5c31af7Sopenharmony_ci
351e5c31af7Sopenharmony_ci		gl.getProgramiv(m_gs_program_id, GL_LINK_STATUS, &link_status);
352e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
353e5c31af7Sopenharmony_ci
354e5c31af7Sopenharmony_ci		if (link_status != GL_TRUE)
355e5c31af7Sopenharmony_ci		{
356e5c31af7Sopenharmony_ci			TCU_FAIL("Geometry shader program failed to link.");
357e5c31af7Sopenharmony_ci		}
358e5c31af7Sopenharmony_ci	}
359e5c31af7Sopenharmony_ci
360e5c31af7Sopenharmony_ci	/* Configure tessellation control shader body */
361e5c31af7Sopenharmony_ci	const char* tc_body = "${VERSION}\n"
362e5c31af7Sopenharmony_ci						  "\n"
363e5c31af7Sopenharmony_ci						  "${TESSELLATION_SHADER_REQUIRE}\n"
364e5c31af7Sopenharmony_ci						  "\n"
365e5c31af7Sopenharmony_ci						  "layout (vertices=4) out;\n"
366e5c31af7Sopenharmony_ci						  "\n"
367e5c31af7Sopenharmony_ci						  "precision highp float;\n"
368e5c31af7Sopenharmony_ci						  "${IN_PER_VERTEX_DECL_ARRAY}"
369e5c31af7Sopenharmony_ci						  "${OUT_PER_VERTEX_DECL_ARRAY}"
370e5c31af7Sopenharmony_ci						  "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
371e5c31af7Sopenharmony_ci						  "out BLOCK_INOUT { vec4 value; } user_out[];\n"
372e5c31af7Sopenharmony_ci						  "\n"
373e5c31af7Sopenharmony_ci						  "void main()\n"
374e5c31af7Sopenharmony_ci						  "{\n"
375e5c31af7Sopenharmony_ci						  "    gl_out   [gl_InvocationID].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
376e5c31af7Sopenharmony_ci						  "    user_out [gl_InvocationID].value       = vec4(2.0, 3.0, 4.0, 5.0);\n"
377e5c31af7Sopenharmony_ci						  "\n"
378e5c31af7Sopenharmony_ci						  "    gl_TessLevelOuter[0] = 1.0;\n"
379e5c31af7Sopenharmony_ci						  "    gl_TessLevelOuter[1] = 1.0;\n"
380e5c31af7Sopenharmony_ci						  "}\n";
381e5c31af7Sopenharmony_ci
382e5c31af7Sopenharmony_ci	shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body);
383e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci	/* Test creating a tessellation control shader program with feedback.
386e5c31af7Sopenharmony_ci	 * For ES, this will fail, and so we will create a different
387e5c31af7Sopenharmony_ci	 * program without the feedback varyings that we can use for our testing.
388e5c31af7Sopenharmony_ci	 * (We can safely ignore the return value for the expected failure case.
389e5c31af7Sopenharmony_ci	 * In the event that the failure case incorrectly succeeds,
390e5c31af7Sopenharmony_ci	 * createSeparableProgram will generate a test failure exception.)
391e5c31af7Sopenharmony_ci	 */
392e5c31af7Sopenharmony_ci
393e5c31af7Sopenharmony_ci	bool tc_feedback_valid;
394e5c31af7Sopenharmony_ci	if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
395e5c31af7Sopenharmony_ci	{
396e5c31af7Sopenharmony_ci		tc_feedback_valid = true;
397e5c31af7Sopenharmony_ci	}
398e5c31af7Sopenharmony_ci	else
399e5c31af7Sopenharmony_ci	{
400e5c31af7Sopenharmony_ci		tc_feedback_valid = false;
401e5c31af7Sopenharmony_ci	}
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci	/* Create a tessellation control shader program */
404e5c31af7Sopenharmony_ci	m_tc_program_id = createSeparableProgram(m_glExtTokens.TESS_CONTROL_SHADER, 1, /* n_strings */
405e5c31af7Sopenharmony_ci											 &tc_body, 1,						   /* n_varyings */
406e5c31af7Sopenharmony_ci											 &varying_name,						   /* varyings */
407e5c31af7Sopenharmony_ci											 tc_feedback_valid);				   /* should_succeed */
408e5c31af7Sopenharmony_ci
409e5c31af7Sopenharmony_ci	if (!tc_feedback_valid)
410e5c31af7Sopenharmony_ci	{
411e5c31af7Sopenharmony_ci		/* Create a valid tessellation control shader program for ES */
412e5c31af7Sopenharmony_ci		m_tc_program_id = createSeparableProgram(m_glExtTokens.TESS_CONTROL_SHADER, 1, /* n_strings */
413e5c31af7Sopenharmony_ci												 &tc_body, 0,						   /* n_varyings */
414e5c31af7Sopenharmony_ci												 DE_NULL,							   /* varyings */
415e5c31af7Sopenharmony_ci												 true);								   /* should_succeed */
416e5c31af7Sopenharmony_ci	}
417e5c31af7Sopenharmony_ci
418e5c31af7Sopenharmony_ci	if (m_tc_program_id == 0)
419e5c31af7Sopenharmony_ci	{
420e5c31af7Sopenharmony_ci		TCU_FAIL("Could not create a separate tessellation control program object");
421e5c31af7Sopenharmony_ci	}
422e5c31af7Sopenharmony_ci
423e5c31af7Sopenharmony_ci	gl.getProgramiv(m_tc_program_id, GL_LINK_STATUS, &link_status);
424e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
425e5c31af7Sopenharmony_ci
426e5c31af7Sopenharmony_ci	if (link_status != GL_TRUE)
427e5c31af7Sopenharmony_ci	{
428e5c31af7Sopenharmony_ci		TCU_FAIL("Tessellation control shader program failed to link.");
429e5c31af7Sopenharmony_ci	}
430e5c31af7Sopenharmony_ci
431e5c31af7Sopenharmony_ci	/* Configure tessellation evaluation shader body */
432e5c31af7Sopenharmony_ci	const char* te_body = "${VERSION}\n"
433e5c31af7Sopenharmony_ci						  "\n"
434e5c31af7Sopenharmony_ci						  "${TESSELLATION_SHADER_REQUIRE}\n"
435e5c31af7Sopenharmony_ci						  "\n"
436e5c31af7Sopenharmony_ci						  "layout (isolines, point_mode) in;\n"
437e5c31af7Sopenharmony_ci						  "\n"
438e5c31af7Sopenharmony_ci						  "precision highp float;\n"
439e5c31af7Sopenharmony_ci						  "${IN_PER_VERTEX_DECL_ARRAY}"
440e5c31af7Sopenharmony_ci						  "${OUT_PER_VERTEX_DECL}"
441e5c31af7Sopenharmony_ci						  "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
442e5c31af7Sopenharmony_ci						  "out BLOCK_INOUT { vec4 value; } user_out;\n"
443e5c31af7Sopenharmony_ci						  "\n"
444e5c31af7Sopenharmony_ci						  "void main()\n"
445e5c31af7Sopenharmony_ci						  "{\n"
446e5c31af7Sopenharmony_ci						  "    gl_Position     = gl_in[0].gl_Position;\n"
447e5c31af7Sopenharmony_ci						  "    user_out.value = vec4(3.0, 4.0, 5.0, 6.0);\n"
448e5c31af7Sopenharmony_ci						  "}\n";
449e5c31af7Sopenharmony_ci
450e5c31af7Sopenharmony_ci	shaderSourceSpecialized(m_te_id, 1 /* count */, &te_body);
451e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
452e5c31af7Sopenharmony_ci
453e5c31af7Sopenharmony_ci	/* Create a tessellation evaluation shader program */
454e5c31af7Sopenharmony_ci	m_te_program_id = createSeparableProgram(m_glExtTokens.TESS_EVALUATION_SHADER, 1, /* n_strings */
455e5c31af7Sopenharmony_ci											 &te_body, 1,							  /* n_varyings */
456e5c31af7Sopenharmony_ci											 &varying_name, true);					  /* should_succeed */
457e5c31af7Sopenharmony_ci
458e5c31af7Sopenharmony_ci	if (m_te_program_id == 0)
459e5c31af7Sopenharmony_ci	{
460e5c31af7Sopenharmony_ci		TCU_FAIL("Could not create a separate tessellation evaluation program object");
461e5c31af7Sopenharmony_ci	}
462e5c31af7Sopenharmony_ci
463e5c31af7Sopenharmony_ci	gl.getProgramiv(m_te_program_id, GL_LINK_STATUS, &link_status);
464e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
465e5c31af7Sopenharmony_ci
466e5c31af7Sopenharmony_ci	if (link_status != GL_TRUE)
467e5c31af7Sopenharmony_ci	{
468e5c31af7Sopenharmony_ci		TCU_FAIL("Tessellation evaluation shader program failed to link.");
469e5c31af7Sopenharmony_ci	}
470e5c31af7Sopenharmony_ci
471e5c31af7Sopenharmony_ci	/* Configure vertex shader body */
472e5c31af7Sopenharmony_ci	const char* vs_body = "${VERSION}\n"
473e5c31af7Sopenharmony_ci						  "\n"
474e5c31af7Sopenharmony_ci						  "${SHADER_IO_BLOCKS_REQUIRE}\n"
475e5c31af7Sopenharmony_ci						  "\n"
476e5c31af7Sopenharmony_ci						  "precision highp float;\n"
477e5c31af7Sopenharmony_ci						  "${OUT_PER_VERTEX_DECL}"
478e5c31af7Sopenharmony_ci						  "out BLOCK_INOUT { vec4 value; } user_out;\n"
479e5c31af7Sopenharmony_ci						  "\n"
480e5c31af7Sopenharmony_ci						  "void main()\n"
481e5c31af7Sopenharmony_ci						  "{\n"
482e5c31af7Sopenharmony_ci						  "    gl_Position    = vec4(1.0, 0.0, 0.0, 1.0);\n"
483e5c31af7Sopenharmony_ci						  "    user_out.value = vec4(4.0, 5.0, 6.0, 7.0);\n"
484e5c31af7Sopenharmony_ci						  "}\n";
485e5c31af7Sopenharmony_ci
486e5c31af7Sopenharmony_ci	shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
487e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
488e5c31af7Sopenharmony_ci
489e5c31af7Sopenharmony_ci	/* Configure vertex shader program */
490e5c31af7Sopenharmony_ci	m_vs_program_id = createSeparableProgram(GL_VERTEX_SHADER, 1,  /* n_strings */
491e5c31af7Sopenharmony_ci											 &vs_body, 1,		   /* n_varyings */
492e5c31af7Sopenharmony_ci											 &varying_name, true); /* should_succeed */
493e5c31af7Sopenharmony_ci
494e5c31af7Sopenharmony_ci	/* Compile all the shaders */
495e5c31af7Sopenharmony_ci	const glw::GLuint shaders[] = { m_fs_id, (m_is_geometry_shader_extension_supported) ? m_gs_id : 0, m_tc_id, m_te_id,
496e5c31af7Sopenharmony_ci									m_vs_id };
497e5c31af7Sopenharmony_ci	const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
498e5c31af7Sopenharmony_ci
499e5c31af7Sopenharmony_ci	for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
500e5c31af7Sopenharmony_ci	{
501e5c31af7Sopenharmony_ci		glw::GLuint shader = shaders[n_shader];
502e5c31af7Sopenharmony_ci
503e5c31af7Sopenharmony_ci		if (shader != 0)
504e5c31af7Sopenharmony_ci		{
505e5c31af7Sopenharmony_ci			glw::GLint compile_status = GL_FALSE;
506e5c31af7Sopenharmony_ci
507e5c31af7Sopenharmony_ci			gl.compileShader(shader);
508e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
509e5c31af7Sopenharmony_ci
510e5c31af7Sopenharmony_ci			gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
511e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
512e5c31af7Sopenharmony_ci
513e5c31af7Sopenharmony_ci			if (compile_status != GL_TRUE)
514e5c31af7Sopenharmony_ci			{
515e5c31af7Sopenharmony_ci				const char* src[] = { fs_body, gs_body, tc_body, te_body, vs_body };
516e5c31af7Sopenharmony_ci
517e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
518e5c31af7Sopenharmony_ci								   << " failed.\n"
519e5c31af7Sopenharmony_ci								   << "Info log:\n"
520e5c31af7Sopenharmony_ci								   << getCompilationInfoLog(shader) << "Shader:\n"
521e5c31af7Sopenharmony_ci								   << src[n_shader] << tcu::TestLog::EndMessage;
522e5c31af7Sopenharmony_ci
523e5c31af7Sopenharmony_ci				TCU_FAIL("Shader compilation failed");
524e5c31af7Sopenharmony_ci			}
525e5c31af7Sopenharmony_ci		}
526e5c31af7Sopenharmony_ci	} /* for (all shaders) */
527e5c31af7Sopenharmony_ci
528e5c31af7Sopenharmony_ci	/* Attach fragment & vertex shaders to the program object */
529e5c31af7Sopenharmony_ci	gl.attachShader(m_po_id, m_fs_id);
530e5c31af7Sopenharmony_ci	gl.attachShader(m_po_id, m_vs_id);
531e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
532e5c31af7Sopenharmony_ci
533e5c31af7Sopenharmony_ci	/* Configure pipeline object's fragment & vertex stages */
534e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_id, GL_FRAGMENT_SHADER_BIT, m_fs_program_id);
535e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed for fragment stage");
536e5c31af7Sopenharmony_ci
537e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_id, GL_VERTEX_SHADER_BIT, m_vs_program_id);
538e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed for vertex stage");
539e5c31af7Sopenharmony_ci
540e5c31af7Sopenharmony_ci	/* Set up XFB for conventional program object */
541e5c31af7Sopenharmony_ci	gl.transformFeedbackVaryings(m_po_id, 1 /* count */, &varying_name, GL_SEPARATE_ATTRIBS);
542e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
543e5c31af7Sopenharmony_ci
544e5c31af7Sopenharmony_ci	/* Set up buffer object storage.
545e5c31af7Sopenharmony_ci	 * We allocate enough space for a 4 vertex patch, which is the size
546e5c31af7Sopenharmony_ci	 * needed by desktop GL for the tessellation control shader feedback
547e5c31af7Sopenharmony_ci	 * whenever GL_NV_gpu_shader5 is present. */
548e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
549e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
550e5c31af7Sopenharmony_ci
551e5c31af7Sopenharmony_ci	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4 /* components */ * 4 /* vertices per patch */,
552e5c31af7Sopenharmony_ci				  NULL, /* data */
553e5c31af7Sopenharmony_ci				  GL_STATIC_DRAW);
554e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
555e5c31af7Sopenharmony_ci
556e5c31af7Sopenharmony_ci	/* Bind the buffer object to indiced TF binding point */
557e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
558e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
559e5c31af7Sopenharmony_ci}
560e5c31af7Sopenharmony_ci
561e5c31af7Sopenharmony_ci/** Executes the test.
562e5c31af7Sopenharmony_ci *
563e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
564e5c31af7Sopenharmony_ci *
565e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
566e5c31af7Sopenharmony_ci *
567e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
568e5c31af7Sopenharmony_ci **/
569e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderXFB::iterate(void)
570e5c31af7Sopenharmony_ci{
571e5c31af7Sopenharmony_ci	/* Do not execute if required extensions are not supported. */
572e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
573e5c31af7Sopenharmony_ci	{
574e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
575e5c31af7Sopenharmony_ci	}
576e5c31af7Sopenharmony_ci
577e5c31af7Sopenharmony_ci	typedef std::vector<_test_descriptor> _tests;
578e5c31af7Sopenharmony_ci	typedef _tests::const_iterator		  _tests_const_iterator;
579e5c31af7Sopenharmony_ci
580e5c31af7Sopenharmony_ci	/* Initialize ES test objects */
581e5c31af7Sopenharmony_ci	initTest();
582e5c31af7Sopenharmony_ci
583e5c31af7Sopenharmony_ci	/* Describe test iterations */
584e5c31af7Sopenharmony_ci	_test_descriptor test_1; /* vs+tc+te+gs */
585e5c31af7Sopenharmony_ci	_test_descriptor test_2; /* vs+tc+te */
586e5c31af7Sopenharmony_ci	_test_descriptor test_3; /* vs+tc */
587e5c31af7Sopenharmony_ci	_tests			 tests;
588e5c31af7Sopenharmony_ci
589e5c31af7Sopenharmony_ci	if (m_is_geometry_shader_extension_supported)
590e5c31af7Sopenharmony_ci	{
591e5c31af7Sopenharmony_ci		test_1.expected_data_source  = m_glExtTokens.GEOMETRY_SHADER;
592e5c31af7Sopenharmony_ci		test_1.expected_n_values	 = 2;
593e5c31af7Sopenharmony_ci		test_1.should_draw_call_fail = false;
594e5c31af7Sopenharmony_ci		test_1.requires_pipeline	 = false;
595e5c31af7Sopenharmony_ci		test_1.tf_mode				 = GL_POINTS;
596e5c31af7Sopenharmony_ci		test_1.use_gs				 = true;
597e5c31af7Sopenharmony_ci		test_1.use_tc				 = true;
598e5c31af7Sopenharmony_ci		test_1.use_te				 = true;
599e5c31af7Sopenharmony_ci
600e5c31af7Sopenharmony_ci		tests.push_back(test_1);
601e5c31af7Sopenharmony_ci	}
602e5c31af7Sopenharmony_ci
603e5c31af7Sopenharmony_ci	test_2.expected_data_source  = m_glExtTokens.TESS_EVALUATION_SHADER;
604e5c31af7Sopenharmony_ci	test_2.expected_n_values	 = 2;
605e5c31af7Sopenharmony_ci	test_2.should_draw_call_fail = false;
606e5c31af7Sopenharmony_ci	test_2.requires_pipeline	 = false;
607e5c31af7Sopenharmony_ci	test_2.tf_mode				 = GL_POINTS;
608e5c31af7Sopenharmony_ci	test_2.use_gs				 = false;
609e5c31af7Sopenharmony_ci	test_2.use_tc				 = true;
610e5c31af7Sopenharmony_ci	test_2.use_te				 = true;
611e5c31af7Sopenharmony_ci
612e5c31af7Sopenharmony_ci	tests.push_back(test_2);
613e5c31af7Sopenharmony_ci
614e5c31af7Sopenharmony_ci	/* Note: This is a special negative case */
615e5c31af7Sopenharmony_ci	test_3.expected_data_source = m_glExtTokens.TESS_CONTROL_SHADER;
616e5c31af7Sopenharmony_ci	test_3.expected_n_values	= 4;
617e5c31af7Sopenharmony_ci	if (!glu::isContextTypeES(m_context.getRenderContext().getType()) && isExtensionSupported("GL_NV_gpu_shader5"))
618e5c31af7Sopenharmony_ci	{
619e5c31af7Sopenharmony_ci		test_3.should_draw_call_fail = false;
620e5c31af7Sopenharmony_ci		test_3.tf_mode				 = m_glExtTokens.PATCHES;
621e5c31af7Sopenharmony_ci	}
622e5c31af7Sopenharmony_ci	else
623e5c31af7Sopenharmony_ci	{
624e5c31af7Sopenharmony_ci		test_3.should_draw_call_fail = true;
625e5c31af7Sopenharmony_ci		test_3.tf_mode				 = GL_POINTS;
626e5c31af7Sopenharmony_ci	}
627e5c31af7Sopenharmony_ci	test_3.requires_pipeline = true;
628e5c31af7Sopenharmony_ci	test_3.use_gs			 = false;
629e5c31af7Sopenharmony_ci	test_3.use_tc			 = true;
630e5c31af7Sopenharmony_ci	test_3.use_te			 = false;
631e5c31af7Sopenharmony_ci
632e5c31af7Sopenharmony_ci	tests.push_back(test_3);
633e5c31af7Sopenharmony_ci
634e5c31af7Sopenharmony_ci	/* Use only one vertex per patch */
635e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
636e5c31af7Sopenharmony_ci
637e5c31af7Sopenharmony_ci	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
638e5c31af7Sopenharmony_ci
639e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed.");
640e5c31af7Sopenharmony_ci
641e5c31af7Sopenharmony_ci	/* This test runs in two iterations:
642e5c31af7Sopenharmony_ci	 *
643e5c31af7Sopenharmony_ci	 * 1) Shaders are attached to a program object at the beginning of
644e5c31af7Sopenharmony_ci	 *    each test. The test then executes. Once it's completed, the
645e5c31af7Sopenharmony_ci	 *    shaders are detached from the program object;
646e5c31af7Sopenharmony_ci	 * 2) A pipeline object is used instead of a program object.
647e5c31af7Sopenharmony_ci	 */
648e5c31af7Sopenharmony_ci	for (int n_iteration = 0; n_iteration < 2; ++n_iteration)
649e5c31af7Sopenharmony_ci	{
650e5c31af7Sopenharmony_ci		bool use_pipeline_object = (n_iteration == 1);
651e5c31af7Sopenharmony_ci
652e5c31af7Sopenharmony_ci		if (use_pipeline_object)
653e5c31af7Sopenharmony_ci		{
654e5c31af7Sopenharmony_ci			gl.bindProgramPipeline(m_pipeline_id);
655e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() failed.");
656e5c31af7Sopenharmony_ci
657e5c31af7Sopenharmony_ci			gl.useProgram(0);
658e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
659e5c31af7Sopenharmony_ci		}
660e5c31af7Sopenharmony_ci		else
661e5c31af7Sopenharmony_ci		{
662e5c31af7Sopenharmony_ci			gl.bindProgramPipeline(0);
663e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() failed.");
664e5c31af7Sopenharmony_ci
665e5c31af7Sopenharmony_ci			/* The program object will be shortly re-linked so defer the glUseProgram() call */
666e5c31af7Sopenharmony_ci		}
667e5c31af7Sopenharmony_ci
668e5c31af7Sopenharmony_ci		/* Iterate through all tests */
669e5c31af7Sopenharmony_ci		for (_tests_const_iterator test_iterator = tests.begin(); test_iterator != tests.end(); test_iterator++)
670e5c31af7Sopenharmony_ci		{
671e5c31af7Sopenharmony_ci			const _test_descriptor& test = *test_iterator;
672e5c31af7Sopenharmony_ci
673e5c31af7Sopenharmony_ci			if (use_pipeline_object)
674e5c31af7Sopenharmony_ci			{
675e5c31af7Sopenharmony_ci				/* Configure the pipeline object */
676e5c31af7Sopenharmony_ci				if (m_is_geometry_shader_extension_supported)
677e5c31af7Sopenharmony_ci				{
678e5c31af7Sopenharmony_ci					gl.useProgramStages(m_pipeline_id, m_glExtTokens.GEOMETRY_SHADER_BIT,
679e5c31af7Sopenharmony_ci										test.use_gs ? m_gs_program_id : 0);
680e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_GEOMETRY_SHADER_BIT_EXT");
681e5c31af7Sopenharmony_ci				}
682e5c31af7Sopenharmony_ci
683e5c31af7Sopenharmony_ci				gl.useProgramStages(m_pipeline_id, m_glExtTokens.TESS_CONTROL_SHADER_BIT,
684e5c31af7Sopenharmony_ci									test.use_tc ? m_tc_program_id : 0);
685e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_TESS_CONTROL_SHADER_BIT_EXT");
686e5c31af7Sopenharmony_ci
687e5c31af7Sopenharmony_ci				gl.useProgramStages(m_pipeline_id, m_glExtTokens.TESS_EVALUATION_SHADER_BIT,
688e5c31af7Sopenharmony_ci									test.use_te ? m_te_program_id : 0);
689e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_TESS_EVALUATION_SHADER_BIT_EXT");
690e5c31af7Sopenharmony_ci
691e5c31af7Sopenharmony_ci				/* Validate the pipeline object */
692e5c31af7Sopenharmony_ci				gl.validateProgramPipeline(m_pipeline_id);
693e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() failed");
694e5c31af7Sopenharmony_ci
695e5c31af7Sopenharmony_ci				/* Retrieve the validation result */
696e5c31af7Sopenharmony_ci				glw::GLint validate_status = GL_FALSE;
697e5c31af7Sopenharmony_ci
698e5c31af7Sopenharmony_ci				gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status);
699e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() failed");
700e5c31af7Sopenharmony_ci
701e5c31af7Sopenharmony_ci				if (validate_status == GL_FALSE && !test.should_draw_call_fail)
702e5c31af7Sopenharmony_ci				{
703e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "A pipeline object consisting of: "
704e5c31af7Sopenharmony_ci									   << "[fragment stage] " << ((test.use_gs) ? "[geometry stage] " : "")
705e5c31af7Sopenharmony_ci									   << ((test.use_tc) ? "[tessellation control stage] " : "")
706e5c31af7Sopenharmony_ci									   << ((test.use_te) ? "[tessellation evaluation stage] " : "") << "[vertex stage] "
707e5c31af7Sopenharmony_ci									   << "was not validated successfully, even though it should."
708e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
709e5c31af7Sopenharmony_ci
710e5c31af7Sopenharmony_ci					TCU_FAIL("Pipeline object is considered invalid, even though the stage combination is valid");
711e5c31af7Sopenharmony_ci				}
712e5c31af7Sopenharmony_ci			}
713e5c31af7Sopenharmony_ci			else
714e5c31af7Sopenharmony_ci			{
715e5c31af7Sopenharmony_ci				if (test.requires_pipeline)
716e5c31af7Sopenharmony_ci				{
717e5c31af7Sopenharmony_ci					continue;
718e5c31af7Sopenharmony_ci				}
719e5c31af7Sopenharmony_ci
720e5c31af7Sopenharmony_ci				/* Attach the shaders to the program object as described in
721e5c31af7Sopenharmony_ci				 * the test descriptor */
722e5c31af7Sopenharmony_ci				if (test.use_gs)
723e5c31af7Sopenharmony_ci				{
724e5c31af7Sopenharmony_ci					gl.attachShader(m_po_id, m_gs_id);
725e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach geometry shader");
726e5c31af7Sopenharmony_ci				}
727e5c31af7Sopenharmony_ci
728e5c31af7Sopenharmony_ci				if (test.use_tc)
729e5c31af7Sopenharmony_ci				{
730e5c31af7Sopenharmony_ci					gl.attachShader(m_po_id, m_tc_id);
731e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach tessellation control shader");
732e5c31af7Sopenharmony_ci				}
733e5c31af7Sopenharmony_ci
734e5c31af7Sopenharmony_ci				if (test.use_te)
735e5c31af7Sopenharmony_ci				{
736e5c31af7Sopenharmony_ci					gl.attachShader(m_po_id, m_te_id);
737e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach tessellation evaluation shader");
738e5c31af7Sopenharmony_ci				}
739e5c31af7Sopenharmony_ci
740e5c31af7Sopenharmony_ci				/* Link the program object */
741e5c31af7Sopenharmony_ci				gl.linkProgram(m_po_id);
742e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "Could not link program object");
743e5c31af7Sopenharmony_ci
744e5c31af7Sopenharmony_ci				/* Has the linking succeeded? */
745e5c31af7Sopenharmony_ci				glw::GLint link_status = GL_FALSE;
746e5c31af7Sopenharmony_ci
747e5c31af7Sopenharmony_ci				gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
748e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
749e5c31af7Sopenharmony_ci
750e5c31af7Sopenharmony_ci				if (link_status != GL_TRUE)
751e5c31af7Sopenharmony_ci				{
752e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "A program object consisting of: "
753e5c31af7Sopenharmony_ci									   << "[fragment shader] " << ((test.use_gs) ? "[geometry shader] " : "")
754e5c31af7Sopenharmony_ci									   << ((test.use_tc) ? "[tessellation control shader] " : "")
755e5c31af7Sopenharmony_ci									   << ((test.use_te) ? "[tessellation evaluation shader] " : "")
756e5c31af7Sopenharmony_ci									   << "[vertex shader] "
757e5c31af7Sopenharmony_ci									   << "failed to link, even though it should link successfully."
758e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
759e5c31af7Sopenharmony_ci
760e5c31af7Sopenharmony_ci					TCU_FAIL("Program linking failed, even though the shader combination was valid");
761e5c31af7Sopenharmony_ci				}
762e5c31af7Sopenharmony_ci
763e5c31af7Sopenharmony_ci				gl.useProgram(m_po_id);
764e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed.");
765e5c31af7Sopenharmony_ci			}
766e5c31af7Sopenharmony_ci
767e5c31af7Sopenharmony_ci			/* Render a single point */
768e5c31af7Sopenharmony_ci			gl.enable(GL_RASTERIZER_DISCARD);
769e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
770e5c31af7Sopenharmony_ci
771e5c31af7Sopenharmony_ci			gl.beginTransformFeedback(test.tf_mode);
772e5c31af7Sopenharmony_ci
773e5c31af7Sopenharmony_ci			bool didBeginXFBFail = false;
774e5c31af7Sopenharmony_ci			if (!test.should_draw_call_fail)
775e5c31af7Sopenharmony_ci			{
776e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) failed");
777e5c31af7Sopenharmony_ci			}
778e5c31af7Sopenharmony_ci			else
779e5c31af7Sopenharmony_ci			{
780e5c31af7Sopenharmony_ci				/* For the negative case, i.e. beginTransformFeedback with an invalid pipeline of {VS, TCS, FS},
781e5c31af7Sopenharmony_ci				 * ES spec is not clear if beginTransformFeedback should error, so relax the requirment here so
782e5c31af7Sopenharmony_ci				 * that test passes as long as either beginTransformFeedback or the next draw call raises
783e5c31af7Sopenharmony_ci				 * INVALID_OPERATION */
784e5c31af7Sopenharmony_ci				glw::GLint err = gl.getError();
785e5c31af7Sopenharmony_ci				if (err == GL_INVALID_OPERATION)
786e5c31af7Sopenharmony_ci				{
787e5c31af7Sopenharmony_ci					didBeginXFBFail = true;
788e5c31af7Sopenharmony_ci				}
789e5c31af7Sopenharmony_ci				else if (err != GL_NO_ERROR)
790e5c31af7Sopenharmony_ci				{
791e5c31af7Sopenharmony_ci					TCU_FAIL("Unexpected GL error in a beginTransformFeedback made on the program pipeline whose"
792e5c31af7Sopenharmony_ci							 "program closest to TFB has no output varying specified");
793e5c31af7Sopenharmony_ci				}
794e5c31af7Sopenharmony_ci			}
795e5c31af7Sopenharmony_ci
796e5c31af7Sopenharmony_ci			{
797e5c31af7Sopenharmony_ci				gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
798e5c31af7Sopenharmony_ci
799e5c31af7Sopenharmony_ci				if (!test.should_draw_call_fail)
800e5c31af7Sopenharmony_ci				{
801e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
802e5c31af7Sopenharmony_ci				}
803e5c31af7Sopenharmony_ci				else
804e5c31af7Sopenharmony_ci				{
805e5c31af7Sopenharmony_ci					if (gl.getError() != GL_INVALID_OPERATION && !didBeginXFBFail)
806e5c31af7Sopenharmony_ci					{
807e5c31af7Sopenharmony_ci						TCU_FAIL("A draw call made using a program object lacking TES stage has"
808e5c31af7Sopenharmony_ci								 " not generated a GL_INVALID_OPERATION as specified");
809e5c31af7Sopenharmony_ci					}
810e5c31af7Sopenharmony_ci				}
811e5c31af7Sopenharmony_ci			}
812e5c31af7Sopenharmony_ci			gl.endTransformFeedback();
813e5c31af7Sopenharmony_ci
814e5c31af7Sopenharmony_ci			if (!didBeginXFBFail)
815e5c31af7Sopenharmony_ci			{
816e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
817e5c31af7Sopenharmony_ci			}
818e5c31af7Sopenharmony_ci			else
819e5c31af7Sopenharmony_ci			{
820e5c31af7Sopenharmony_ci				if (gl.getError() != GL_INVALID_OPERATION)
821e5c31af7Sopenharmony_ci				{
822e5c31af7Sopenharmony_ci					TCU_FAIL("An endTransformFeedback made on inactive xfb has not generated a "
823e5c31af7Sopenharmony_ci							 "GL_INVALID_OPERATION as specified");
824e5c31af7Sopenharmony_ci				}
825e5c31af7Sopenharmony_ci			}
826e5c31af7Sopenharmony_ci
827e5c31af7Sopenharmony_ci			gl.disable(GL_RASTERIZER_DISCARD);
828e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed");
829e5c31af7Sopenharmony_ci
830e5c31af7Sopenharmony_ci			if (!test.should_draw_call_fail)
831e5c31af7Sopenharmony_ci			{
832e5c31af7Sopenharmony_ci				/* Retrieve the captured result values */
833e5c31af7Sopenharmony_ci				glw::GLfloat* result_ptr = (glw::GLfloat*)gl.mapBufferRange(
834e5c31af7Sopenharmony_ci					GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
835e5c31af7Sopenharmony_ci					sizeof(float) * 4 /* components */ * test.expected_n_values, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
836e5c31af7Sopenharmony_ci
837e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
838e5c31af7Sopenharmony_ci
839e5c31af7Sopenharmony_ci				/* Verify the data */
840e5c31af7Sopenharmony_ci				const glw::GLfloat epsilon			  = (glw::GLfloat)1e-5;
841e5c31af7Sopenharmony_ci				const glw::GLfloat expected_gs_data[] = { 1.0f, 2.0f, 3.0f, 4.0f };
842e5c31af7Sopenharmony_ci				const glw::GLfloat expected_tc_data[] = { 2.0f, 3.0f, 4.0f, 5.0f };
843e5c31af7Sopenharmony_ci				const glw::GLfloat expected_te_data[] = { 3.0f, 4.0f, 5.0f, 6.0f };
844e5c31af7Sopenharmony_ci				const glw::GLfloat expected_vs_data[] = { 4.0f, 5.0f, 6.0f, 7.0f };
845e5c31af7Sopenharmony_ci
846e5c31af7Sopenharmony_ci				for (int n_value = 0; n_value < test.expected_n_values; ++n_value)
847e5c31af7Sopenharmony_ci				{
848e5c31af7Sopenharmony_ci					const glw::GLfloat* expected_data_ptr = NULL;
849e5c31af7Sopenharmony_ci					const glw::GLfloat* captured_data_ptr = result_ptr + n_value * 4 /* components */;
850e5c31af7Sopenharmony_ci
851e5c31af7Sopenharmony_ci					if (test.expected_data_source == m_glExtTokens.GEOMETRY_SHADER)
852e5c31af7Sopenharmony_ci					{
853e5c31af7Sopenharmony_ci						expected_data_ptr = expected_gs_data;
854e5c31af7Sopenharmony_ci					}
855e5c31af7Sopenharmony_ci					else if (test.expected_data_source == m_glExtTokens.TESS_CONTROL_SHADER)
856e5c31af7Sopenharmony_ci					{
857e5c31af7Sopenharmony_ci						expected_data_ptr = expected_tc_data;
858e5c31af7Sopenharmony_ci					}
859e5c31af7Sopenharmony_ci					else if (test.expected_data_source == m_glExtTokens.TESS_EVALUATION_SHADER)
860e5c31af7Sopenharmony_ci					{
861e5c31af7Sopenharmony_ci						expected_data_ptr = expected_te_data;
862e5c31af7Sopenharmony_ci					}
863e5c31af7Sopenharmony_ci					else if (test.expected_data_source == GL_VERTEX_SHADER)
864e5c31af7Sopenharmony_ci					{
865e5c31af7Sopenharmony_ci						expected_data_ptr = expected_vs_data;
866e5c31af7Sopenharmony_ci					}
867e5c31af7Sopenharmony_ci					else
868e5c31af7Sopenharmony_ci					{
869e5c31af7Sopenharmony_ci						TCU_FAIL("Unrecognized expected data source");
870e5c31af7Sopenharmony_ci					}
871e5c31af7Sopenharmony_ci
872e5c31af7Sopenharmony_ci					if (de::abs(captured_data_ptr[0] - expected_data_ptr[0]) > epsilon ||
873e5c31af7Sopenharmony_ci						de::abs(captured_data_ptr[1] - expected_data_ptr[1]) > epsilon ||
874e5c31af7Sopenharmony_ci						de::abs(captured_data_ptr[2] - expected_data_ptr[2]) > epsilon ||
875e5c31af7Sopenharmony_ci						de::abs(captured_data_ptr[3] - expected_data_ptr[3]) > epsilon)
876e5c31af7Sopenharmony_ci					{
877e5c31af7Sopenharmony_ci						m_testCtx.getLog() << tcu::TestLog::Message << "Captured data "
878e5c31af7Sopenharmony_ci										   << "(" << captured_data_ptr[0] << ", " << captured_data_ptr[1] << ", "
879e5c31af7Sopenharmony_ci										   << captured_data_ptr[2] << ", " << captured_data_ptr[3] << ")"
880e5c31af7Sopenharmony_ci										   << "is different from the expected value "
881e5c31af7Sopenharmony_ci										   << "(" << expected_data_ptr[0] << ", " << expected_data_ptr[1] << ", "
882e5c31af7Sopenharmony_ci										   << expected_data_ptr[2] << ", " << expected_data_ptr[3] << ")"
883e5c31af7Sopenharmony_ci										   << tcu::TestLog::EndMessage;
884e5c31af7Sopenharmony_ci
885e5c31af7Sopenharmony_ci						TCU_FAIL("Invalid data captured");
886e5c31af7Sopenharmony_ci					}
887e5c31af7Sopenharmony_ci				}
888e5c31af7Sopenharmony_ci
889e5c31af7Sopenharmony_ci				/* Unmap the buffer object, since we're done */
890e5c31af7Sopenharmony_ci				memset(result_ptr, 0, sizeof(float) * 4 /* components */ * test.expected_n_values);
891e5c31af7Sopenharmony_ci
892e5c31af7Sopenharmony_ci				gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
893e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed");
894e5c31af7Sopenharmony_ci			} /* if (!test.should_draw_call_fail) */
895e5c31af7Sopenharmony_ci
896e5c31af7Sopenharmony_ci			if (!use_pipeline_object)
897e5c31af7Sopenharmony_ci			{
898e5c31af7Sopenharmony_ci				/* Detach all shaders we attached to the program object at the beginning
899e5c31af7Sopenharmony_ci				 * of the iteration */
900e5c31af7Sopenharmony_ci				if (test.use_gs)
901e5c31af7Sopenharmony_ci				{
902e5c31af7Sopenharmony_ci					gl.detachShader(m_po_id, m_gs_id);
903e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach geometry shader");
904e5c31af7Sopenharmony_ci				}
905e5c31af7Sopenharmony_ci
906e5c31af7Sopenharmony_ci				if (test.use_tc)
907e5c31af7Sopenharmony_ci				{
908e5c31af7Sopenharmony_ci					gl.detachShader(m_po_id, m_tc_id);
909e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach tessellation control shader");
910e5c31af7Sopenharmony_ci				}
911e5c31af7Sopenharmony_ci
912e5c31af7Sopenharmony_ci				if (test.use_te)
913e5c31af7Sopenharmony_ci				{
914e5c31af7Sopenharmony_ci					gl.detachShader(m_po_id, m_te_id);
915e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach tessellation evaluation shader");
916e5c31af7Sopenharmony_ci				}
917e5c31af7Sopenharmony_ci
918e5c31af7Sopenharmony_ci			} /* if (!use_pipeline_object) */
919e5c31af7Sopenharmony_ci			else
920e5c31af7Sopenharmony_ci			{
921e5c31af7Sopenharmony_ci				/* We don't need to do anything with the pipeline object - stages will be
922e5c31af7Sopenharmony_ci				 * re-defined in next iteration */
923e5c31af7Sopenharmony_ci			}
924e5c31af7Sopenharmony_ci		} /* for (all tests) */
925e5c31af7Sopenharmony_ci	}	 /* for (all iterations) */
926e5c31af7Sopenharmony_ci
927e5c31af7Sopenharmony_ci	/* All done */
928e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
929e5c31af7Sopenharmony_ci	return STOP;
930e5c31af7Sopenharmony_ci}
931e5c31af7Sopenharmony_ci
932e5c31af7Sopenharmony_ci} /* namespace glcts */
933