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 "esextcTessellationShaderProgramInterfaces.hpp"
25e5c31af7Sopenharmony_ci#include "gluContextInfo.hpp"
26e5c31af7Sopenharmony_ci#include "gluDefs.hpp"
27e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
28e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
29e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_cinamespace glcts
32e5c31af7Sopenharmony_ci{
33e5c31af7Sopenharmony_ci/** Constructor
34e5c31af7Sopenharmony_ci *
35e5c31af7Sopenharmony_ci * @param context       Test context
36e5c31af7Sopenharmony_ci * @param name          Test case's name
37e5c31af7Sopenharmony_ci * @param description   Test case's desricption
38e5c31af7Sopenharmony_ci **/
39e5c31af7Sopenharmony_ciTessellationShaderProgramInterfaces::TessellationShaderProgramInterfaces(Context&			  context,
40e5c31af7Sopenharmony_ci																		 const ExtParameters& extParams)
41e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, "ext_program_interface_query_dependency",
42e5c31af7Sopenharmony_ci				   "Verifies EXT_program_interface_query works correctly for tessellation"
43e5c31af7Sopenharmony_ci				   " control and tessellation evaluation shaders")
44e5c31af7Sopenharmony_ci	, m_fs_shader_id(0)
45e5c31af7Sopenharmony_ci	, m_po_id(0)
46e5c31af7Sopenharmony_ci	, m_tc_shader_id(0)
47e5c31af7Sopenharmony_ci	, m_te_shader_id(0)
48e5c31af7Sopenharmony_ci	, m_vs_shader_id(0)
49e5c31af7Sopenharmony_ci	, m_is_atomic_counters_supported(false)
50e5c31af7Sopenharmony_ci	, m_is_shader_storage_blocks_supported(false)
51e5c31af7Sopenharmony_ci{
52e5c31af7Sopenharmony_ci	/* Left blank on purpose */
53e5c31af7Sopenharmony_ci}
54e5c31af7Sopenharmony_ci
55e5c31af7Sopenharmony_ci/** Deinitializes all ES objects created for the test. */
56e5c31af7Sopenharmony_civoid TessellationShaderProgramInterfaces::deinit()
57e5c31af7Sopenharmony_ci{
58e5c31af7Sopenharmony_ci	/** Call base class' deinit() function */
59e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
60e5c31af7Sopenharmony_ci
61e5c31af7Sopenharmony_ci	/* Release all objects we might've created */
62e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
63e5c31af7Sopenharmony_ci
64e5c31af7Sopenharmony_ci	if (m_fs_shader_id != 0)
65e5c31af7Sopenharmony_ci	{
66e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_shader_id);
67e5c31af7Sopenharmony_ci
68e5c31af7Sopenharmony_ci		m_fs_shader_id = 0;
69e5c31af7Sopenharmony_ci	}
70e5c31af7Sopenharmony_ci
71e5c31af7Sopenharmony_ci	if (m_po_id != 0)
72e5c31af7Sopenharmony_ci	{
73e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
74e5c31af7Sopenharmony_ci
75e5c31af7Sopenharmony_ci		m_po_id = 0;
76e5c31af7Sopenharmony_ci	}
77e5c31af7Sopenharmony_ci
78e5c31af7Sopenharmony_ci	if (m_tc_shader_id != 0)
79e5c31af7Sopenharmony_ci	{
80e5c31af7Sopenharmony_ci		gl.deleteShader(m_tc_shader_id);
81e5c31af7Sopenharmony_ci
82e5c31af7Sopenharmony_ci		m_tc_shader_id = 0;
83e5c31af7Sopenharmony_ci	}
84e5c31af7Sopenharmony_ci
85e5c31af7Sopenharmony_ci	if (m_te_shader_id != 0)
86e5c31af7Sopenharmony_ci	{
87e5c31af7Sopenharmony_ci		gl.deleteShader(m_te_shader_id);
88e5c31af7Sopenharmony_ci
89e5c31af7Sopenharmony_ci		m_te_shader_id = 0;
90e5c31af7Sopenharmony_ci	}
91e5c31af7Sopenharmony_ci
92e5c31af7Sopenharmony_ci	if (m_vs_shader_id != 0)
93e5c31af7Sopenharmony_ci	{
94e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_shader_id);
95e5c31af7Sopenharmony_ci
96e5c31af7Sopenharmony_ci		m_vs_shader_id = 0;
97e5c31af7Sopenharmony_ci	}
98e5c31af7Sopenharmony_ci}
99e5c31af7Sopenharmony_ci
100e5c31af7Sopenharmony_ci/** Initializes all ES objects that will be used for the test. */
101e5c31af7Sopenharmony_civoid TessellationShaderProgramInterfaces::initTest()
102e5c31af7Sopenharmony_ci{
103e5c31af7Sopenharmony_ci	/* The test requires EXT_tessellation_shader and EXT_program_interfaces_query extensions */
104e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported || !m_is_program_interface_query_supported)
105e5c31af7Sopenharmony_ci	{
106e5c31af7Sopenharmony_ci		return;
107e5c31af7Sopenharmony_ci	}
108e5c31af7Sopenharmony_ci
109e5c31af7Sopenharmony_ci	/* Generate a program object we will later configure */
110e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
111e5c31af7Sopenharmony_ci
112e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
113e5c31af7Sopenharmony_ci
114e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
115e5c31af7Sopenharmony_ci
116e5c31af7Sopenharmony_ci	/* Generate shader objects the test will use */
117e5c31af7Sopenharmony_ci	m_fs_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
118e5c31af7Sopenharmony_ci	m_tc_shader_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
119e5c31af7Sopenharmony_ci	m_te_shader_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
120e5c31af7Sopenharmony_ci	m_vs_shader_id = gl.createShader(GL_VERTEX_SHADER);
121e5c31af7Sopenharmony_ci
122e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
123e5c31af7Sopenharmony_ci
124e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_control_shader_storage_blocks;
125e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_control_atomic_counter_buffers;
126e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_control_atomic_counters;
127e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_evaluation_shader_storage_blocks;
128e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_evaluation_atomic_counter_buffers;
129e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_evaluation_atomic_counters;
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, &gl_max_tess_control_atomic_counter_buffers);
132e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(),
133e5c31af7Sopenharmony_ci						"glGetIntegerv() failed for GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT pname");
134e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_ATOMIC_COUNTERS, &gl_max_tess_control_atomic_counters);
135e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT pname");
136e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, &gl_max_tess_control_shader_storage_blocks);
137e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(),
138e5c31af7Sopenharmony_ci						"glGetIntegerv() failed for GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT pname");
139e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,
140e5c31af7Sopenharmony_ci				   &gl_max_tess_evaluation_atomic_counter_buffers);
141e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(),
142e5c31af7Sopenharmony_ci						"glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT pname");
143e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_ATOMIC_COUNTERS, &gl_max_tess_evaluation_atomic_counters);
144e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT pname");
145e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
146e5c31af7Sopenharmony_ci				   &gl_max_tess_evaluation_shader_storage_blocks);
147e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(),
148e5c31af7Sopenharmony_ci						"glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT pname");
149e5c31af7Sopenharmony_ci
150e5c31af7Sopenharmony_ci	m_is_atomic_counters_supported =
151e5c31af7Sopenharmony_ci		(gl_max_tess_control_atomic_counter_buffers > 1) && (gl_max_tess_evaluation_atomic_counter_buffers > 1) &&
152e5c31af7Sopenharmony_ci		(gl_max_tess_control_atomic_counters > 0) && (gl_max_tess_evaluation_atomic_counters > 0);
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci	m_is_shader_storage_blocks_supported =
155e5c31af7Sopenharmony_ci		(gl_max_tess_control_shader_storage_blocks > 0) && (gl_max_tess_evaluation_shader_storage_blocks > 0);
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_ci	const char* atomic_counters_header = NULL;
158e5c31af7Sopenharmony_ci	if (m_is_atomic_counters_supported)
159e5c31af7Sopenharmony_ci	{
160e5c31af7Sopenharmony_ci		atomic_counters_header = "#define USE_ATOMIC_COUNTERS 1\n";
161e5c31af7Sopenharmony_ci	}
162e5c31af7Sopenharmony_ci	else
163e5c31af7Sopenharmony_ci	{
164e5c31af7Sopenharmony_ci		atomic_counters_header = "\n";
165e5c31af7Sopenharmony_ci	}
166e5c31af7Sopenharmony_ci
167e5c31af7Sopenharmony_ci	const char* shader_storage_blocks_header = NULL;
168e5c31af7Sopenharmony_ci	if (m_is_shader_storage_blocks_supported)
169e5c31af7Sopenharmony_ci	{
170e5c31af7Sopenharmony_ci		shader_storage_blocks_header = "#define USE_SHADER_STORAGE_BLOCKS\n";
171e5c31af7Sopenharmony_ci	}
172e5c31af7Sopenharmony_ci	else
173e5c31af7Sopenharmony_ci	{
174e5c31af7Sopenharmony_ci		shader_storage_blocks_header = "\n";
175e5c31af7Sopenharmony_ci	}
176e5c31af7Sopenharmony_ci
177e5c31af7Sopenharmony_ci	/* Build shader program */
178e5c31af7Sopenharmony_ci	const char* fs_body = "${VERSION}\n"
179e5c31af7Sopenharmony_ci						  "\n"
180e5c31af7Sopenharmony_ci						  "precision highp float;\n"
181e5c31af7Sopenharmony_ci						  "\n"
182e5c31af7Sopenharmony_ci						  "out vec4 test_output;\n"
183e5c31af7Sopenharmony_ci						  "\n"
184e5c31af7Sopenharmony_ci						  "void main()\n"
185e5c31af7Sopenharmony_ci						  "{\n"
186e5c31af7Sopenharmony_ci						  "    test_output = vec4(1, 0, 0, 0);\n"
187e5c31af7Sopenharmony_ci						  "}\n";
188e5c31af7Sopenharmony_ci
189e5c31af7Sopenharmony_ci	const char* tc_body = "\n"
190e5c31af7Sopenharmony_ci						  "layout (vertices = 1) out;\n"
191e5c31af7Sopenharmony_ci						  "\n"
192e5c31af7Sopenharmony_ci						  /* Uniforms */
193e5c31af7Sopenharmony_ci						  "uniform vec2 tc_uniform1;\n"
194e5c31af7Sopenharmony_ci						  "uniform mat4 tc_uniform2;\n"
195e5c31af7Sopenharmony_ci						  "\n"
196e5c31af7Sopenharmony_ci						  /* Uniform blocks */
197e5c31af7Sopenharmony_ci						  "uniform tc_uniform_block1\n"
198e5c31af7Sopenharmony_ci						  "{\n"
199e5c31af7Sopenharmony_ci						  "    float tc_uniform_block1_1;\n"
200e5c31af7Sopenharmony_ci						  "};\n"
201e5c31af7Sopenharmony_ci						  /* Atomic counter buffers */
202e5c31af7Sopenharmony_ci						  "#ifdef USE_ATOMIC_COUNTERS\n"
203e5c31af7Sopenharmony_ci						  "layout(binding = 1, offset = 0) uniform atomic_uint tc_atomic_counter1;\n"
204e5c31af7Sopenharmony_ci						  "#endif\n"
205e5c31af7Sopenharmony_ci						  /* Shader storage blocks & buffer variables */
206e5c31af7Sopenharmony_ci						  "#ifdef USE_SHADER_STORAGE_BLOCKS\n"
207e5c31af7Sopenharmony_ci						  "layout(std140, binding = 0) buffer tc_shader_storage_block1\n"
208e5c31af7Sopenharmony_ci						  "{\n"
209e5c31af7Sopenharmony_ci						  "    vec4 tc_shader_storage_buffer_object_1[];\n"
210e5c31af7Sopenharmony_ci						  "};\n"
211e5c31af7Sopenharmony_ci						  "#endif\n"
212e5c31af7Sopenharmony_ci						  /* Body */
213e5c31af7Sopenharmony_ci						  "void main()\n"
214e5c31af7Sopenharmony_ci						  "{\n"
215e5c31af7Sopenharmony_ci						  "    int test = 1;\n"
216e5c31af7Sopenharmony_ci						  "\n"
217e5c31af7Sopenharmony_ci						  /* Uniforms */
218e5c31af7Sopenharmony_ci						  "    if (tc_uniform1.x    == 0.0) test = 2;\n"
219e5c31af7Sopenharmony_ci						  "    if (tc_uniform2[0].y == 1.0) test = 3;\n"
220e5c31af7Sopenharmony_ci						  /* Uniform blocks */
221e5c31af7Sopenharmony_ci						  "    if (tc_uniform_block1_1 == 3.0) test = 4;\n"
222e5c31af7Sopenharmony_ci						  /* Atomic counter buffers */
223e5c31af7Sopenharmony_ci						  "#ifdef USE_ATOMIC_COUNTERS\n"
224e5c31af7Sopenharmony_ci						  "    if (atomicCounter(tc_atomic_counter1) == 1u) test = 5;\n"
225e5c31af7Sopenharmony_ci						  "#endif\n"
226e5c31af7Sopenharmony_ci						  /* Shader storage blocks & buffer variables */
227e5c31af7Sopenharmony_ci						  "#ifdef USE_SHADER_STORAGE_BLOCKS\n"
228e5c31af7Sopenharmony_ci						  "    if (tc_shader_storage_buffer_object_1[0].x == 0.0) test = 6;\n"
229e5c31af7Sopenharmony_ci						  "#endif\n"
230e5c31af7Sopenharmony_ci						  "\n"
231e5c31af7Sopenharmony_ci						  "    gl_out           [gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
232e5c31af7Sopenharmony_ci						  "    gl_TessLevelOuter[0]                           = 2.0 * float(test);\n"
233e5c31af7Sopenharmony_ci						  "    gl_TessLevelOuter[1]                           = 3.0;\n"
234e5c31af7Sopenharmony_ci						  "}\n";
235e5c31af7Sopenharmony_ci
236e5c31af7Sopenharmony_ci	const char* tc_code[] = { "${VERSION}\n",
237e5c31af7Sopenharmony_ci							  /* Required EXT_tessellation_shader functionality */
238e5c31af7Sopenharmony_ci							  "${TESSELLATION_SHADER_REQUIRE}\n", atomic_counters_header, shader_storage_blocks_header,
239e5c31af7Sopenharmony_ci							  tc_body };
240e5c31af7Sopenharmony_ci
241e5c31af7Sopenharmony_ci	const char* te_body = "\n"
242e5c31af7Sopenharmony_ci						  "layout (isolines, ccw, equal_spacing, point_mode) in;\n"
243e5c31af7Sopenharmony_ci						  "\n"
244e5c31af7Sopenharmony_ci						  /* Uniforms */
245e5c31af7Sopenharmony_ci						  "uniform vec2 te_uniform1;\n"
246e5c31af7Sopenharmony_ci						  "uniform mat4 te_uniform2;\n"
247e5c31af7Sopenharmony_ci						  "\n"
248e5c31af7Sopenharmony_ci						  /* Uniform blocks */
249e5c31af7Sopenharmony_ci						  "uniform te_uniform_block1\n"
250e5c31af7Sopenharmony_ci						  "{\n"
251e5c31af7Sopenharmony_ci						  "    float te_uniform_block1_1;\n"
252e5c31af7Sopenharmony_ci						  "};\n"
253e5c31af7Sopenharmony_ci						  /* Atomic counter buffers */
254e5c31af7Sopenharmony_ci						  "#ifdef USE_ATOMIC_COUNTERS\n"
255e5c31af7Sopenharmony_ci						  "layout(binding = 2, offset = 0) uniform atomic_uint te_atomic_counter1;\n"
256e5c31af7Sopenharmony_ci						  "#endif\n"
257e5c31af7Sopenharmony_ci						  /* Shader storage blocks & buffer variables */
258e5c31af7Sopenharmony_ci						  "#ifdef USE_SHADER_STORAGE_BLOCKS\n"
259e5c31af7Sopenharmony_ci						  "layout(std140, binding = 0) buffer te_shader_storage_block1\n"
260e5c31af7Sopenharmony_ci						  "{\n"
261e5c31af7Sopenharmony_ci						  "    vec4 te_shader_storage_buffer_object_1[];\n"
262e5c31af7Sopenharmony_ci						  "};\n"
263e5c31af7Sopenharmony_ci						  "#endif\n"
264e5c31af7Sopenharmony_ci						  "void main()\n"
265e5c31af7Sopenharmony_ci						  "{\n"
266e5c31af7Sopenharmony_ci						  "    int test = 1;\n"
267e5c31af7Sopenharmony_ci						  "\n"
268e5c31af7Sopenharmony_ci						  /* Uniforms */
269e5c31af7Sopenharmony_ci						  "    if (te_uniform1.x    == 0.0) test = 2;\n"
270e5c31af7Sopenharmony_ci						  "    if (te_uniform2[0].y == 1.0) test = 3;\n"
271e5c31af7Sopenharmony_ci						  /* Uniform blocks */
272e5c31af7Sopenharmony_ci						  "    if (te_uniform_block1_1 == 3.0) test = 4;\n"
273e5c31af7Sopenharmony_ci						  /* Atomic counter buffers */
274e5c31af7Sopenharmony_ci						  "#ifdef USE_ATOMIC_COUNTERS\n"
275e5c31af7Sopenharmony_ci						  "    if (atomicCounter(te_atomic_counter1) == 1u) test = 5;\n"
276e5c31af7Sopenharmony_ci						  "#endif\n"
277e5c31af7Sopenharmony_ci						  /* Shader storage blocks & buffer variables */
278e5c31af7Sopenharmony_ci						  "#ifdef USE_SHADER_STORAGE_BLOCKS\n"
279e5c31af7Sopenharmony_ci						  "   if (te_shader_storage_buffer_object_1[0].x == 0.0) test = 6;\n"
280e5c31af7Sopenharmony_ci						  "#endif\n"
281e5c31af7Sopenharmony_ci						  "\n"
282e5c31af7Sopenharmony_ci						  "    gl_Position = gl_in[0].gl_Position * float(test);\n"
283e5c31af7Sopenharmony_ci						  "}\n";
284e5c31af7Sopenharmony_ci
285e5c31af7Sopenharmony_ci	const char* te_code[] = { "${VERSION}\n",
286e5c31af7Sopenharmony_ci							  /* Required EXT_tessellation_shader functionality */
287e5c31af7Sopenharmony_ci							  "${TESSELLATION_SHADER_REQUIRE}\n", atomic_counters_header, shader_storage_blocks_header,
288e5c31af7Sopenharmony_ci							  te_body };
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci	const char* vs_body = "${VERSION}\n"
291e5c31af7Sopenharmony_ci						  "\n"
292e5c31af7Sopenharmony_ci						  "in vec4 test_input;\n"
293e5c31af7Sopenharmony_ci						  "\n"
294e5c31af7Sopenharmony_ci						  "void main()\n"
295e5c31af7Sopenharmony_ci						  "{\n"
296e5c31af7Sopenharmony_ci						  "    gl_Position = vec4(gl_VertexID, test_input.y, 0, 1);\n"
297e5c31af7Sopenharmony_ci						  "}\n";
298e5c31af7Sopenharmony_ci
299e5c31af7Sopenharmony_ci	bool link_success = buildProgram(m_po_id, m_fs_shader_id, 1, &fs_body, m_tc_shader_id, 5, tc_code, m_te_shader_id,
300e5c31af7Sopenharmony_ci									 5, te_code, m_vs_shader_id, 1, &vs_body);
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_ci	if (!link_success)
303e5c31af7Sopenharmony_ci	{
304e5c31af7Sopenharmony_ci		TCU_FAIL("Program compilation and linking failed");
305e5c31af7Sopenharmony_ci	}
306e5c31af7Sopenharmony_ci
307e5c31af7Sopenharmony_ci	/* We're good to execute the test! */
308e5c31af7Sopenharmony_ci}
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci/** Executes the test.
311e5c31af7Sopenharmony_ci *
312e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
313e5c31af7Sopenharmony_ci *
314e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
315e5c31af7Sopenharmony_ci *
316e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
317e5c31af7Sopenharmony_ci **/
318e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderProgramInterfaces::iterate(void)
319e5c31af7Sopenharmony_ci{
320e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
321e5c31af7Sopenharmony_ci
322e5c31af7Sopenharmony_ci	/* Do not execute if required extensions are not supported. */
323e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
324e5c31af7Sopenharmony_ci	{
325e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
326e5c31af7Sopenharmony_ci	}
327e5c31af7Sopenharmony_ci
328e5c31af7Sopenharmony_ci	/* Initialize ES objects needed to run the test */
329e5c31af7Sopenharmony_ci	initTest();
330e5c31af7Sopenharmony_ci
331e5c31af7Sopenharmony_ci	/* Iterate through all interfaces */
332e5c31af7Sopenharmony_ci	const glw::GLenum interfaces[] = {
333e5c31af7Sopenharmony_ci		GL_UNIFORM,			GL_UNIFORM_BLOCK, GL_ATOMIC_COUNTER_BUFFER, GL_SHADER_STORAGE_BLOCK,
334e5c31af7Sopenharmony_ci		GL_BUFFER_VARIABLE, GL_PROGRAM_INPUT, GL_PROGRAM_OUTPUT
335e5c31af7Sopenharmony_ci	};
336e5c31af7Sopenharmony_ci	const unsigned int n_interfaces = sizeof(interfaces) / sizeof(interfaces[0]);
337e5c31af7Sopenharmony_ci
338e5c31af7Sopenharmony_ci	for (unsigned int n_interface = 0; n_interface < n_interfaces; ++n_interface)
339e5c31af7Sopenharmony_ci	{
340e5c31af7Sopenharmony_ci		glw::GLenum interface = interfaces[n_interface];
341e5c31af7Sopenharmony_ci
342e5c31af7Sopenharmony_ci		if ((interface == GL_SHADER_STORAGE_BLOCK || interface == GL_BUFFER_VARIABLE) &&
343e5c31af7Sopenharmony_ci			!m_is_shader_storage_blocks_supported)
344e5c31af7Sopenharmony_ci		{
345e5c31af7Sopenharmony_ci			continue;
346e5c31af7Sopenharmony_ci		}
347e5c31af7Sopenharmony_ci
348e5c31af7Sopenharmony_ci		if (interface == GL_ATOMIC_COUNTER_BUFFER && !m_is_atomic_counters_supported)
349e5c31af7Sopenharmony_ci		{
350e5c31af7Sopenharmony_ci			continue;
351e5c31af7Sopenharmony_ci		}
352e5c31af7Sopenharmony_ci
353e5c31af7Sopenharmony_ci		/* For each interface, we want to check whether a specific resource
354e5c31af7Sopenharmony_ci		 * is recognized by the implementation. If the name is unknown,
355e5c31af7Sopenharmony_ci		 * the test should fail; if it's recognized, we should verify it's referenced
356e5c31af7Sopenharmony_ci		 * by both TC and TE shaders
357e5c31af7Sopenharmony_ci		 */
358e5c31af7Sopenharmony_ci		const char* tc_resource_name = DE_NULL;
359e5c31af7Sopenharmony_ci		const char* te_resource_name = DE_NULL;
360e5c31af7Sopenharmony_ci
361e5c31af7Sopenharmony_ci		switch (interface)
362e5c31af7Sopenharmony_ci		{
363e5c31af7Sopenharmony_ci		case GL_UNIFORM:
364e5c31af7Sopenharmony_ci		{
365e5c31af7Sopenharmony_ci			tc_resource_name = "tc_uniform1";
366e5c31af7Sopenharmony_ci			te_resource_name = "te_uniform1";
367e5c31af7Sopenharmony_ci
368e5c31af7Sopenharmony_ci			break;
369e5c31af7Sopenharmony_ci		}
370e5c31af7Sopenharmony_ci
371e5c31af7Sopenharmony_ci		case GL_UNIFORM_BLOCK:
372e5c31af7Sopenharmony_ci		{
373e5c31af7Sopenharmony_ci			tc_resource_name = "tc_uniform_block1";
374e5c31af7Sopenharmony_ci			te_resource_name = "te_uniform_block1";
375e5c31af7Sopenharmony_ci
376e5c31af7Sopenharmony_ci			break;
377e5c31af7Sopenharmony_ci		}
378e5c31af7Sopenharmony_ci
379e5c31af7Sopenharmony_ci		case GL_ATOMIC_COUNTER_BUFFER:
380e5c31af7Sopenharmony_ci		{
381e5c31af7Sopenharmony_ci			/* Atomic counter buffers are tested in a separate codepath. */
382e5c31af7Sopenharmony_ci			break;
383e5c31af7Sopenharmony_ci		}
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci		case GL_SHADER_STORAGE_BLOCK:
386e5c31af7Sopenharmony_ci		{
387e5c31af7Sopenharmony_ci			tc_resource_name = "tc_shader_storage_block1";
388e5c31af7Sopenharmony_ci			te_resource_name = "te_shader_storage_block1";
389e5c31af7Sopenharmony_ci
390e5c31af7Sopenharmony_ci			break;
391e5c31af7Sopenharmony_ci		}
392e5c31af7Sopenharmony_ci
393e5c31af7Sopenharmony_ci		case GL_BUFFER_VARIABLE:
394e5c31af7Sopenharmony_ci		{
395e5c31af7Sopenharmony_ci			tc_resource_name = "tc_shader_storage_buffer_object_1";
396e5c31af7Sopenharmony_ci			te_resource_name = "te_shader_storage_buffer_object_1";
397e5c31af7Sopenharmony_ci
398e5c31af7Sopenharmony_ci			break;
399e5c31af7Sopenharmony_ci		}
400e5c31af7Sopenharmony_ci
401e5c31af7Sopenharmony_ci		case GL_PROGRAM_INPUT:
402e5c31af7Sopenharmony_ci		{
403e5c31af7Sopenharmony_ci			tc_resource_name = DE_NULL;
404e5c31af7Sopenharmony_ci			te_resource_name = DE_NULL;
405e5c31af7Sopenharmony_ci
406e5c31af7Sopenharmony_ci			break;
407e5c31af7Sopenharmony_ci		}
408e5c31af7Sopenharmony_ci
409e5c31af7Sopenharmony_ci		case GL_PROGRAM_OUTPUT:
410e5c31af7Sopenharmony_ci		{
411e5c31af7Sopenharmony_ci			tc_resource_name = DE_NULL;
412e5c31af7Sopenharmony_ci			te_resource_name = DE_NULL;
413e5c31af7Sopenharmony_ci
414e5c31af7Sopenharmony_ci			break;
415e5c31af7Sopenharmony_ci		}
416e5c31af7Sopenharmony_ci
417e5c31af7Sopenharmony_ci		default:
418e5c31af7Sopenharmony_ci		{
419e5c31af7Sopenharmony_ci			TCU_FAIL("Unrecognized interface type");
420e5c31af7Sopenharmony_ci		}
421e5c31af7Sopenharmony_ci		} /* switch (interface) */
422e5c31af7Sopenharmony_ci
423e5c31af7Sopenharmony_ci		/* Run in two iterations - first for TC, then for TE */
424e5c31af7Sopenharmony_ci		for (int n_iteration = 0; n_iteration < 2; ++n_iteration)
425e5c31af7Sopenharmony_ci		{
426e5c31af7Sopenharmony_ci			glw::GLenum property = (n_iteration == 0) ? m_glExtTokens.REFERENCED_BY_TESS_CONTROL_SHADER :
427e5c31af7Sopenharmony_ci														m_glExtTokens.REFERENCED_BY_TESS_EVALUATION_SHADER;
428e5c31af7Sopenharmony_ci
429e5c31af7Sopenharmony_ci			if (interface == GL_ATOMIC_COUNTER_BUFFER)
430e5c31af7Sopenharmony_ci			{
431e5c31af7Sopenharmony_ci				/* We only need a single iteration run for this interface */
432e5c31af7Sopenharmony_ci				if (n_iteration == 1)
433e5c31af7Sopenharmony_ci				{
434e5c31af7Sopenharmony_ci					continue;
435e5c31af7Sopenharmony_ci				}
436e5c31af7Sopenharmony_ci
437e5c31af7Sopenharmony_ci				/* Atomic counter buffers are not assigned names, hence they need to be
438e5c31af7Sopenharmony_ci				 * tested slightly differently.
439e5c31af7Sopenharmony_ci				 *
440e5c31af7Sopenharmony_ci				 * Exactly two atomic counter buffers should be defined. Make sure that's the case.
441e5c31af7Sopenharmony_ci				 */
442e5c31af7Sopenharmony_ci				glw::GLint n_active_resources = 0;
443e5c31af7Sopenharmony_ci
444e5c31af7Sopenharmony_ci				gl.getProgramInterfaceiv(m_po_id, interface, GL_ACTIVE_RESOURCES, &n_active_resources);
445e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() failed.");
446e5c31af7Sopenharmony_ci
447e5c31af7Sopenharmony_ci				if (n_active_resources != 2)
448e5c31af7Sopenharmony_ci				{
449e5c31af7Sopenharmony_ci					TCU_FAIL("Invalid amount of atomic counter buffer binding points reported");
450e5c31af7Sopenharmony_ci				}
451e5c31af7Sopenharmony_ci
452e5c31af7Sopenharmony_ci				/* Check both resources and make sure they report separate atomic counters */
453e5c31af7Sopenharmony_ci				bool was_tc_atomic_counter_buffer_reported = false;
454e5c31af7Sopenharmony_ci				bool was_te_atomic_counter_buffer_reported = false;
455e5c31af7Sopenharmony_ci
456e5c31af7Sopenharmony_ci				for (int n_resource = 0; n_resource < n_active_resources; ++n_resource)
457e5c31af7Sopenharmony_ci				{
458e5c31af7Sopenharmony_ci					const glw::GLenum tc_property		= m_glExtTokens.REFERENCED_BY_TESS_CONTROL_SHADER;
459e5c31af7Sopenharmony_ci					glw::GLint		  tc_property_value = 0;
460e5c31af7Sopenharmony_ci					const glw::GLenum te_property		= m_glExtTokens.REFERENCED_BY_TESS_EVALUATION_SHADER;
461e5c31af7Sopenharmony_ci					glw::GLint		  te_property_value = 0;
462e5c31af7Sopenharmony_ci
463e5c31af7Sopenharmony_ci					gl.getProgramResourceiv(m_po_id, interface, n_resource, 1, /* propCount */
464e5c31af7Sopenharmony_ci											&tc_property, 1,				   /* bufSize */
465e5c31af7Sopenharmony_ci											NULL,							   /* length */
466e5c31af7Sopenharmony_ci											&tc_property_value);
467e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(
468e5c31af7Sopenharmony_ci						gl.getError(),
469e5c31af7Sopenharmony_ci						"glGetProgramResourceiv() failed for GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT property");
470e5c31af7Sopenharmony_ci
471e5c31af7Sopenharmony_ci					gl.getProgramResourceiv(m_po_id, interface, n_resource, 1, /* propCount */
472e5c31af7Sopenharmony_ci											&te_property, 1,				   /* bufSize */
473e5c31af7Sopenharmony_ci											NULL,							   /* length */
474e5c31af7Sopenharmony_ci											&te_property_value);
475e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(
476e5c31af7Sopenharmony_ci						gl.getError(),
477e5c31af7Sopenharmony_ci						"glGetProgramResourceiv() failed for GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT property");
478e5c31af7Sopenharmony_ci
479e5c31af7Sopenharmony_ci					if (tc_property_value == GL_TRUE)
480e5c31af7Sopenharmony_ci					{
481e5c31af7Sopenharmony_ci						if (was_tc_atomic_counter_buffer_reported)
482e5c31af7Sopenharmony_ci						{
483e5c31af7Sopenharmony_ci							TCU_FAIL("Tessellation control-specific atomic counter buffer is reported twice");
484e5c31af7Sopenharmony_ci						}
485e5c31af7Sopenharmony_ci
486e5c31af7Sopenharmony_ci						was_tc_atomic_counter_buffer_reported = true;
487e5c31af7Sopenharmony_ci					}
488e5c31af7Sopenharmony_ci
489e5c31af7Sopenharmony_ci					if (te_property_value == GL_TRUE)
490e5c31af7Sopenharmony_ci					{
491e5c31af7Sopenharmony_ci						if (was_te_atomic_counter_buffer_reported)
492e5c31af7Sopenharmony_ci						{
493e5c31af7Sopenharmony_ci							TCU_FAIL("Tessellation evaluation-specific atomic counter buffer is reported twice");
494e5c31af7Sopenharmony_ci						}
495e5c31af7Sopenharmony_ci
496e5c31af7Sopenharmony_ci						was_te_atomic_counter_buffer_reported = true;
497e5c31af7Sopenharmony_ci					}
498e5c31af7Sopenharmony_ci				} /* for (all active resources) */
499e5c31af7Sopenharmony_ci
500e5c31af7Sopenharmony_ci				if (!was_tc_atomic_counter_buffer_reported || !was_te_atomic_counter_buffer_reported)
501e5c31af7Sopenharmony_ci				{
502e5c31af7Sopenharmony_ci					TCU_FAIL("Either tessellation control or tessellation evaluation atomic counter buffer was not "
503e5c31af7Sopenharmony_ci							 "reported");
504e5c31af7Sopenharmony_ci				}
505e5c31af7Sopenharmony_ci			}
506e5c31af7Sopenharmony_ci			else
507e5c31af7Sopenharmony_ci			{
508e5c31af7Sopenharmony_ci				/* Retrieve resource index first, as long as the name is not NULL.
509e5c31af7Sopenharmony_ci				 * If it's NULL, the property's value is assumed to be GL_FALSE for
510e5c31af7Sopenharmony_ci				 * all reported active resources.
511e5c31af7Sopenharmony_ci				 **/
512e5c31af7Sopenharmony_ci				const char* resource_name = (n_iteration == 0) ? tc_resource_name : te_resource_name;
513e5c31af7Sopenharmony_ci
514e5c31af7Sopenharmony_ci				if (resource_name == DE_NULL)
515e5c31af7Sopenharmony_ci				{
516e5c31af7Sopenharmony_ci					/* Make sure the property has GL_FALSE value for any resources
517e5c31af7Sopenharmony_ci					 * reported for this interface. */
518e5c31af7Sopenharmony_ci					glw::GLint n_active_resources = 0;
519e5c31af7Sopenharmony_ci
520e5c31af7Sopenharmony_ci					gl.getProgramInterfaceiv(m_po_id, interface, GL_ACTIVE_RESOURCES, &n_active_resources);
521e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() failed.");
522e5c31af7Sopenharmony_ci
523e5c31af7Sopenharmony_ci					for (glw::GLint n_resource = 0; n_resource < n_active_resources; ++n_resource)
524e5c31af7Sopenharmony_ci					{
525e5c31af7Sopenharmony_ci						verifyPropertyValue(interface, property, n_resource, GL_FALSE);
526e5c31af7Sopenharmony_ci					} /* for (all resource indices) */
527e5c31af7Sopenharmony_ci				}
528e5c31af7Sopenharmony_ci				else
529e5c31af7Sopenharmony_ci				{
530e5c31af7Sopenharmony_ci					glw::GLuint resource_index = gl.getProgramResourceIndex(m_po_id, interface, resource_name);
531e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceIndex() failed");
532e5c31af7Sopenharmony_ci
533e5c31af7Sopenharmony_ci					if (resource_index == GL_INVALID_INDEX)
534e5c31af7Sopenharmony_ci					{
535e5c31af7Sopenharmony_ci						m_testCtx.getLog() << tcu::TestLog::Message << "Resource [" << resource_name
536e5c31af7Sopenharmony_ci										   << "] was not recognized." << tcu::TestLog::EndMessage;
537e5c31af7Sopenharmony_ci
538e5c31af7Sopenharmony_ci						TCU_FAIL("Resource not recognized.");
539e5c31af7Sopenharmony_ci					}
540e5c31af7Sopenharmony_ci
541e5c31af7Sopenharmony_ci					/* Now that we know the index, we can check the GL_REFERENCED_BY_...
542e5c31af7Sopenharmony_ci					 * property value */
543e5c31af7Sopenharmony_ci					verifyPropertyValue(interface, property, resource_index, GL_TRUE);
544e5c31af7Sopenharmony_ci				}
545e5c31af7Sopenharmony_ci			} /* (interface != GL_ATOMIC_COUNTER_BUFFER) */
546e5c31af7Sopenharmony_ci		}	 /* for (both iterations) */
547e5c31af7Sopenharmony_ci	}		  /* for (all interfaces) */
548e5c31af7Sopenharmony_ci
549e5c31af7Sopenharmony_ci	/* All done */
550e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
551e5c31af7Sopenharmony_ci	return STOP;
552e5c31af7Sopenharmony_ci}
553e5c31af7Sopenharmony_ci
554e5c31af7Sopenharmony_ci/** Checks if a property value reported for user-specified program object interface
555e5c31af7Sopenharmony_ci *  at given index is as expected.
556e5c31af7Sopenharmony_ci *
557e5c31af7Sopenharmony_ci *  NOTE: This function throws TestError exception if retrieved value does not
558e5c31af7Sopenharmony_ci *        match @param expected_value.
559e5c31af7Sopenharmony_ci *
560e5c31af7Sopenharmony_ci *  @param interface      Program object interface to use for the query;
561e5c31af7Sopenharmony_ci *  @param property       Interface property to check;
562e5c31af7Sopenharmony_ci *  @param index          Property index to use for the test;
563e5c31af7Sopenharmony_ci *  @param expected_value Value that is expected to be reported by ES implementation.
564e5c31af7Sopenharmony_ci **/
565e5c31af7Sopenharmony_civoid TessellationShaderProgramInterfaces::verifyPropertyValue(glw::GLenum interface, glw::GLenum property,
566e5c31af7Sopenharmony_ci															  glw::GLuint index, glw::GLint expected_value)
567e5c31af7Sopenharmony_ci{
568e5c31af7Sopenharmony_ci	const glw::Functions& gl			 = m_context.getRenderContext().getFunctions();
569e5c31af7Sopenharmony_ci	glw::GLint			  property_value = 0;
570e5c31af7Sopenharmony_ci
571e5c31af7Sopenharmony_ci	gl.getProgramResourceiv(m_po_id, interface, index, 1, /* propCount */
572e5c31af7Sopenharmony_ci							&property, 1,				  /* bufSize */
573e5c31af7Sopenharmony_ci							NULL,						  /* length */
574e5c31af7Sopenharmony_ci							&property_value);
575e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv() failed");
576e5c31af7Sopenharmony_ci
577e5c31af7Sopenharmony_ci	if (property_value != expected_value)
578e5c31af7Sopenharmony_ci	{
579e5c31af7Sopenharmony_ci		TCU_FAIL("Invalid GL_REFERENCED_BY_... property value reported");
580e5c31af7Sopenharmony_ci	}
581e5c31af7Sopenharmony_ci}
582e5c31af7Sopenharmony_ci
583e5c31af7Sopenharmony_ci} /* namespace glcts */
584