1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * OpenGL Conformance Test Suite
3e5c31af7Sopenharmony_ci * -----------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright (c) 2015-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#include "esextcGeometryShaderAPI.hpp"
24e5c31af7Sopenharmony_ci
25e5c31af7Sopenharmony_ci#include "gluDefs.hpp"
26e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
27e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
28e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
29e5c31af7Sopenharmony_ci#include <cstring>
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_cinamespace glcts
32e5c31af7Sopenharmony_ci{
33e5c31af7Sopenharmony_ci
34e5c31af7Sopenharmony_cistatic const char* minimal_fs_code =
35e5c31af7Sopenharmony_ci								   "${VERSION}\n"
36e5c31af7Sopenharmony_ci								   "\n"
37e5c31af7Sopenharmony_ci								   "precision highp float;\n"
38e5c31af7Sopenharmony_ci								   "\n"
39e5c31af7Sopenharmony_ci								   "out vec4 result;\n"
40e5c31af7Sopenharmony_ci								   "\n"
41e5c31af7Sopenharmony_ci								   "void main()\n"
42e5c31af7Sopenharmony_ci								   "{\n"
43e5c31af7Sopenharmony_ci								   "    result = vec4(1.0);\n"
44e5c31af7Sopenharmony_ci								   "}\n";
45e5c31af7Sopenharmony_ci
46e5c31af7Sopenharmony_cistatic const char* minimal_gs_code =
47e5c31af7Sopenharmony_ci								   "${VERSION}\n"
48e5c31af7Sopenharmony_ci								   "${GEOMETRY_SHADER_REQUIRE}\n"
49e5c31af7Sopenharmony_ci								   "\n"
50e5c31af7Sopenharmony_ci								   "layout (points)                   in;\n"
51e5c31af7Sopenharmony_ci								   "layout (points, max_vertices = 1) out;\n"
52e5c31af7Sopenharmony_ci								   "\n"
53e5c31af7Sopenharmony_ci								   "${OUT_PER_VERTEX_DECL}"
54e5c31af7Sopenharmony_ci								   "${IN_DATA_DECL}"
55e5c31af7Sopenharmony_ci								   "void main()\n"
56e5c31af7Sopenharmony_ci								   "{\n"
57e5c31af7Sopenharmony_ci								   "${POSITION_WITH_IN_DATA}"
58e5c31af7Sopenharmony_ci								   "    EmitVertex();\n"
59e5c31af7Sopenharmony_ci								   "}\n";
60e5c31af7Sopenharmony_ci
61e5c31af7Sopenharmony_cistatic const char* minimal_vs_code =
62e5c31af7Sopenharmony_ci								   "${VERSION}\n"
63e5c31af7Sopenharmony_ci								   "\n"
64e5c31af7Sopenharmony_ci								   "${OUT_PER_VERTEX_DECL}"
65e5c31af7Sopenharmony_ci								   "\n"
66e5c31af7Sopenharmony_ci								   "void main()\n"
67e5c31af7Sopenharmony_ci								   "{\n"
68e5c31af7Sopenharmony_ci								   "    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
69e5c31af7Sopenharmony_ci								   "}\n";
70e5c31af7Sopenharmony_ci
71e5c31af7Sopenharmony_ci/* createShaderProgramv conformance test shaders */
72e5c31af7Sopenharmony_ciconst char* GeometryShaderCreateShaderProgramvTest::fs_code = "${VERSION}\n"
73e5c31af7Sopenharmony_ci															  "\n"
74e5c31af7Sopenharmony_ci															  "precision highp float;\n"
75e5c31af7Sopenharmony_ci															  "\n"
76e5c31af7Sopenharmony_ci															  "out vec4 result;\n"
77e5c31af7Sopenharmony_ci															  "\n"
78e5c31af7Sopenharmony_ci															  "void main()\n"
79e5c31af7Sopenharmony_ci															  "{\n"
80e5c31af7Sopenharmony_ci															  "    result = vec4(0.0, 1.0, 0.0, 0.0);\n"
81e5c31af7Sopenharmony_ci															  "}\n";
82e5c31af7Sopenharmony_ci
83e5c31af7Sopenharmony_ciconst char* GeometryShaderCreateShaderProgramvTest::gs_code = "${VERSION}\n"
84e5c31af7Sopenharmony_ci															  "${GEOMETRY_SHADER_REQUIRE}\n"
85e5c31af7Sopenharmony_ci															  "\n"
86e5c31af7Sopenharmony_ci															  "layout (points)                           in;\n"
87e5c31af7Sopenharmony_ci															  "layout (triangle_strip, max_vertices = 4) out;\n"
88e5c31af7Sopenharmony_ci															  "\n"
89e5c31af7Sopenharmony_ci															  "${OUT_PER_VERTEX_DECL}"
90e5c31af7Sopenharmony_ci															  "\n"
91e5c31af7Sopenharmony_ci															  "void main()\n"
92e5c31af7Sopenharmony_ci															  "{\n"
93e5c31af7Sopenharmony_ci															  "    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
94e5c31af7Sopenharmony_ci															  "    EmitVertex();\n"
95e5c31af7Sopenharmony_ci															  "\n"
96e5c31af7Sopenharmony_ci															  "    gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
97e5c31af7Sopenharmony_ci															  "    EmitVertex();\n"
98e5c31af7Sopenharmony_ci															  "\n"
99e5c31af7Sopenharmony_ci															  "    gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
100e5c31af7Sopenharmony_ci															  "    EmitVertex();\n"
101e5c31af7Sopenharmony_ci															  "\n"
102e5c31af7Sopenharmony_ci															  "    gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
103e5c31af7Sopenharmony_ci															  "    EmitVertex();\n"
104e5c31af7Sopenharmony_ci															  "    EndPrimitive();\n"
105e5c31af7Sopenharmony_ci															  "}\n";
106e5c31af7Sopenharmony_ci
107e5c31af7Sopenharmony_ciconst char* GeometryShaderCreateShaderProgramvTest::vs_code = "${VERSION}\n"
108e5c31af7Sopenharmony_ci															  "\n"
109e5c31af7Sopenharmony_ci															  "${OUT_PER_VERTEX_DECL}"
110e5c31af7Sopenharmony_ci															  "\n"
111e5c31af7Sopenharmony_ci															  "void main()\n"
112e5c31af7Sopenharmony_ci															  "{\n"
113e5c31af7Sopenharmony_ci															  "    gl_Position = vec4(-10.0, -10.0, -10.0, 0.0);\n"
114e5c31af7Sopenharmony_ci															  "}\n";
115e5c31af7Sopenharmony_ci
116e5c31af7Sopenharmony_ciconst unsigned int GeometryShaderCreateShaderProgramvTest::m_to_height = 4;
117e5c31af7Sopenharmony_ciconst unsigned int GeometryShaderCreateShaderProgramvTest::m_to_width  = 4;
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci/** Constructor
120e5c31af7Sopenharmony_ci *
121e5c31af7Sopenharmony_ci * @param context       Test context
122e5c31af7Sopenharmony_ci * @param extParams     Not used.
123e5c31af7Sopenharmony_ci * @param name          Test case's name
124e5c31af7Sopenharmony_ci * @param description   Test case's description
125e5c31af7Sopenharmony_ci **/
126e5c31af7Sopenharmony_ciGeometryShaderCreateShaderProgramvTest::GeometryShaderCreateShaderProgramvTest(Context&				context,
127e5c31af7Sopenharmony_ci																			   const ExtParameters& extParams,
128e5c31af7Sopenharmony_ci																			   const char*			name,
129e5c31af7Sopenharmony_ci																			   const char*			description)
130e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
131e5c31af7Sopenharmony_ci	, m_fbo_id(0)
132e5c31af7Sopenharmony_ci	, m_fs_po_id(0)
133e5c31af7Sopenharmony_ci	, m_gs_po_id(0)
134e5c31af7Sopenharmony_ci	, m_pipeline_object_id(0)
135e5c31af7Sopenharmony_ci	, m_to_id(0)
136e5c31af7Sopenharmony_ci	, m_vao_id(0)
137e5c31af7Sopenharmony_ci	, m_vs_po_id(0)
138e5c31af7Sopenharmony_ci{
139e5c31af7Sopenharmony_ci}
140e5c31af7Sopenharmony_ci
141e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
142e5c31af7Sopenharmony_civoid GeometryShaderCreateShaderProgramvTest::deinit()
143e5c31af7Sopenharmony_ci{
144e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
145e5c31af7Sopenharmony_ci
146e5c31af7Sopenharmony_ci	if (m_fbo_id != 0)
147e5c31af7Sopenharmony_ci	{
148e5c31af7Sopenharmony_ci		gl.deleteFramebuffers(1, &m_fbo_id);
149e5c31af7Sopenharmony_ci
150e5c31af7Sopenharmony_ci		m_fbo_id = 0;
151e5c31af7Sopenharmony_ci	}
152e5c31af7Sopenharmony_ci
153e5c31af7Sopenharmony_ci	if (m_fs_po_id != 0)
154e5c31af7Sopenharmony_ci	{
155e5c31af7Sopenharmony_ci		gl.deleteProgram(m_fs_po_id);
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_ci		m_fs_po_id = 0;
158e5c31af7Sopenharmony_ci	}
159e5c31af7Sopenharmony_ci
160e5c31af7Sopenharmony_ci	if (m_gs_po_id != 0)
161e5c31af7Sopenharmony_ci	{
162e5c31af7Sopenharmony_ci		gl.deleteProgram(m_gs_po_id);
163e5c31af7Sopenharmony_ci
164e5c31af7Sopenharmony_ci		m_gs_po_id = 0;
165e5c31af7Sopenharmony_ci	}
166e5c31af7Sopenharmony_ci
167e5c31af7Sopenharmony_ci	if (m_pipeline_object_id != 0)
168e5c31af7Sopenharmony_ci	{
169e5c31af7Sopenharmony_ci		gl.deleteProgramPipelines(1, &m_pipeline_object_id);
170e5c31af7Sopenharmony_ci
171e5c31af7Sopenharmony_ci		m_pipeline_object_id = 0;
172e5c31af7Sopenharmony_ci	}
173e5c31af7Sopenharmony_ci
174e5c31af7Sopenharmony_ci	if (m_to_id != 0)
175e5c31af7Sopenharmony_ci	{
176e5c31af7Sopenharmony_ci		gl.deleteTextures(1, &m_to_id);
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_ci		m_to_id = 0;
179e5c31af7Sopenharmony_ci	}
180e5c31af7Sopenharmony_ci
181e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
182e5c31af7Sopenharmony_ci	{
183e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
184e5c31af7Sopenharmony_ci
185e5c31af7Sopenharmony_ci		m_vao_id = 0;
186e5c31af7Sopenharmony_ci	}
187e5c31af7Sopenharmony_ci
188e5c31af7Sopenharmony_ci	if (m_vs_po_id != 0)
189e5c31af7Sopenharmony_ci	{
190e5c31af7Sopenharmony_ci		gl.deleteProgram(m_vs_po_id);
191e5c31af7Sopenharmony_ci
192e5c31af7Sopenharmony_ci		m_vs_po_id = 0;
193e5c31af7Sopenharmony_ci	}
194e5c31af7Sopenharmony_ci
195e5c31af7Sopenharmony_ci	/* Release base class */
196e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
197e5c31af7Sopenharmony_ci}
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ci/** Initializes a framebuffer object used by the conformance test. */
200e5c31af7Sopenharmony_civoid GeometryShaderCreateShaderProgramvTest::initFBO()
201e5c31af7Sopenharmony_ci{
202e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
203e5c31af7Sopenharmony_ci
204e5c31af7Sopenharmony_ci	/* Generate a FBO */
205e5c31af7Sopenharmony_ci	gl.genFramebuffers(1, &m_fbo_id);
206e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
207e5c31af7Sopenharmony_ci
208e5c31af7Sopenharmony_ci	/* Generate a TO */
209e5c31af7Sopenharmony_ci	gl.genTextures(1, &m_to_id);
210e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
211e5c31af7Sopenharmony_ci
212e5c31af7Sopenharmony_ci	/* Set the TO up */
213e5c31af7Sopenharmony_ci	gl.bindTexture(GL_TEXTURE_2D, m_to_id);
214e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
215e5c31af7Sopenharmony_ci
216e5c31af7Sopenharmony_ci	gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
217e5c31af7Sopenharmony_ci					GL_RGBA8, m_to_width, m_to_height);
218e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
219e5c31af7Sopenharmony_ci
220e5c31af7Sopenharmony_ci	/* Set up the FBO */
221e5c31af7Sopenharmony_ci	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
222e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
223e5c31af7Sopenharmony_ci
224e5c31af7Sopenharmony_ci	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); /* level */
225e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_ci	/* Set up the viewport */
228e5c31af7Sopenharmony_ci	gl.viewport(0, /* x */
229e5c31af7Sopenharmony_ci				0, /* y */
230e5c31af7Sopenharmony_ci				m_to_width, m_to_height);
231e5c31af7Sopenharmony_ci
232e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
233e5c31af7Sopenharmony_ci}
234e5c31af7Sopenharmony_ci
235e5c31af7Sopenharmony_ci/* Initializes a pipeline object used by the conformance test */
236e5c31af7Sopenharmony_civoid GeometryShaderCreateShaderProgramvTest::initPipelineObject()
237e5c31af7Sopenharmony_ci{
238e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci	DE_ASSERT(m_fs_po_id != 0 && m_gs_po_id != 0 && m_vs_po_id != 0);
241e5c31af7Sopenharmony_ci
242e5c31af7Sopenharmony_ci	gl.genProgramPipelines(1, &m_pipeline_object_id);
243e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
244e5c31af7Sopenharmony_ci
245e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_object_id, GL_FRAGMENT_SHADER_BIT, m_fs_po_id);
246e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_object_id, GL_GEOMETRY_SHADER_BIT, m_gs_po_id);
247e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_object_id, GL_VERTEX_SHADER_BIT, m_vs_po_id);
248e5c31af7Sopenharmony_ci
249e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed.");
250e5c31af7Sopenharmony_ci}
251e5c31af7Sopenharmony_ci
252e5c31af7Sopenharmony_ci/** Executes the test.
253e5c31af7Sopenharmony_ci *
254e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
255e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
256e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
257e5c31af7Sopenharmony_ci **/
258e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderCreateShaderProgramvTest::iterate()
259e5c31af7Sopenharmony_ci{
260e5c31af7Sopenharmony_ci	const glw::Functions& gl		  = m_context.getRenderContext().getFunctions();
261e5c31af7Sopenharmony_ci	const unsigned int	n_so_po_ids = 3;
262e5c31af7Sopenharmony_ci	bool				  result	  = true;
263e5c31af7Sopenharmony_ci	glw::GLuint			  so_po_ids[n_so_po_ids];
264e5c31af7Sopenharmony_ci
265e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
266e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
267e5c31af7Sopenharmony_ci	{
268e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
269e5c31af7Sopenharmony_ci	}
270e5c31af7Sopenharmony_ci
271e5c31af7Sopenharmony_ci	/* Initialize off-screen rendering */
272e5c31af7Sopenharmony_ci	initFBO();
273e5c31af7Sopenharmony_ci
274e5c31af7Sopenharmony_ci	/* Form shader sources */
275e5c31af7Sopenharmony_ci	std::string fs_specialized_code = specializeShader(1,
276e5c31af7Sopenharmony_ci													   /* parts */ &fs_code);
277e5c31af7Sopenharmony_ci	const char* fs_specialized_code_raw = fs_specialized_code.c_str();
278e5c31af7Sopenharmony_ci	std::string gs_specialized_code		= specializeShader(1,
279e5c31af7Sopenharmony_ci													   /* parts */ &gs_code);
280e5c31af7Sopenharmony_ci	const char* gs_specialized_code_raw = gs_specialized_code.c_str();
281e5c31af7Sopenharmony_ci	std::string vs_specialized_code		= specializeShader(1,
282e5c31af7Sopenharmony_ci													   /* parts */ &vs_code);
283e5c31af7Sopenharmony_ci	const char* vs_specialized_code_raw = vs_specialized_code.c_str();
284e5c31af7Sopenharmony_ci
285e5c31af7Sopenharmony_ci	/* Try to create an invalid geometry shader program first */
286e5c31af7Sopenharmony_ci	glw::GLint link_status = GL_TRUE;
287e5c31af7Sopenharmony_ci
288e5c31af7Sopenharmony_ci	m_gs_po_id = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1, /* count */
289e5c31af7Sopenharmony_ci										 &gs_code);
290e5c31af7Sopenharmony_ci
291e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
292e5c31af7Sopenharmony_ci
293e5c31af7Sopenharmony_ci	if (m_gs_po_id == 0)
294e5c31af7Sopenharmony_ci	{
295e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "glCreateShaderProgramv() call returned 0."
296e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
297e5c31af7Sopenharmony_ci
298e5c31af7Sopenharmony_ci		result = false;
299e5c31af7Sopenharmony_ci		goto end;
300e5c31af7Sopenharmony_ci	}
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_ci	gl.getProgramiv(m_gs_po_id, GL_LINK_STATUS, &link_status);
303e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_ci	if (link_status != GL_FALSE)
306e5c31af7Sopenharmony_ci	{
307e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "An invalid shader program was linked successfully."
308e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci		result = false;
311e5c31af7Sopenharmony_ci		goto end;
312e5c31af7Sopenharmony_ci	}
313e5c31af7Sopenharmony_ci
314e5c31af7Sopenharmony_ci	gl.deleteProgram(m_gs_po_id);
315e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram() call failed.");
316e5c31af7Sopenharmony_ci
317e5c31af7Sopenharmony_ci	/* Create shader programs */
318e5c31af7Sopenharmony_ci	m_fs_po_id = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1, /* count */
319e5c31af7Sopenharmony_ci										 &fs_specialized_code_raw);
320e5c31af7Sopenharmony_ci	m_gs_po_id = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1, /* count */
321e5c31af7Sopenharmony_ci										 &gs_specialized_code_raw);
322e5c31af7Sopenharmony_ci	m_vs_po_id = gl.createShaderProgramv(GL_VERTEX_SHADER, 1, /* count */
323e5c31af7Sopenharmony_ci										 &vs_specialized_code_raw);
324e5c31af7Sopenharmony_ci
325e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call(s) failed.");
326e5c31af7Sopenharmony_ci
327e5c31af7Sopenharmony_ci	if (m_fs_po_id == 0 || m_gs_po_id == 0 || m_vs_po_id == 0)
328e5c31af7Sopenharmony_ci	{
329e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "At least one glCreateShaderProgramv() call returned 0."
330e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
331e5c31af7Sopenharmony_ci
332e5c31af7Sopenharmony_ci		result = false;
333e5c31af7Sopenharmony_ci		goto end;
334e5c31af7Sopenharmony_ci	}
335e5c31af7Sopenharmony_ci
336e5c31af7Sopenharmony_ci	/* Make sure all shader programs were linked successfully */
337e5c31af7Sopenharmony_ci	so_po_ids[0] = m_fs_po_id;
338e5c31af7Sopenharmony_ci	so_po_ids[1] = m_gs_po_id;
339e5c31af7Sopenharmony_ci	so_po_ids[2] = m_vs_po_id;
340e5c31af7Sopenharmony_ci
341e5c31af7Sopenharmony_ci	for (unsigned int n_po_id = 0; n_po_id != n_so_po_ids; ++n_po_id)
342e5c31af7Sopenharmony_ci	{
343e5c31af7Sopenharmony_ci		gl.getProgramiv(so_po_ids[n_po_id], GL_LINK_STATUS, &link_status);
344e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
345e5c31af7Sopenharmony_ci
346e5c31af7Sopenharmony_ci		if (link_status != GL_TRUE)
347e5c31af7Sopenharmony_ci		{
348e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "A valid shader program with id [" << so_po_ids[n_po_id]
349e5c31af7Sopenharmony_ci							   << "] was not linked successfully." << tcu::TestLog::EndMessage;
350e5c31af7Sopenharmony_ci
351e5c31af7Sopenharmony_ci			result = false;
352e5c31af7Sopenharmony_ci			goto end;
353e5c31af7Sopenharmony_ci		}
354e5c31af7Sopenharmony_ci	}
355e5c31af7Sopenharmony_ci
356e5c31af7Sopenharmony_ci	/* Set up the vertex array object */
357e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
358e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
359e5c31af7Sopenharmony_ci
360e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
361e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
362e5c31af7Sopenharmony_ci
363e5c31af7Sopenharmony_ci	/* Set up the pipeline object */
364e5c31af7Sopenharmony_ci	initPipelineObject();
365e5c31af7Sopenharmony_ci
366e5c31af7Sopenharmony_ci	/* Render a full-screen quad */
367e5c31af7Sopenharmony_ci	gl.bindProgramPipeline(m_pipeline_object_id);
368e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0, /* first */
371e5c31af7Sopenharmony_ci				  1);			/* count */
372e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
373e5c31af7Sopenharmony_ci
374e5c31af7Sopenharmony_ci	/* Verify the rendering result */
375e5c31af7Sopenharmony_ci	unsigned char result_data[m_to_width * m_to_height * 4 /* rgba */];
376e5c31af7Sopenharmony_ci
377e5c31af7Sopenharmony_ci	gl.readPixels(0, /* x */
378e5c31af7Sopenharmony_ci				  0, /* y */
379e5c31af7Sopenharmony_ci				  m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, result_data);
380e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
381e5c31af7Sopenharmony_ci
382e5c31af7Sopenharmony_ci	for (unsigned int y = 0; y < m_to_height; ++y)
383e5c31af7Sopenharmony_ci	{
384e5c31af7Sopenharmony_ci		unsigned char* traveller_ptr = result_data + 4 * y;
385e5c31af7Sopenharmony_ci
386e5c31af7Sopenharmony_ci		for (unsigned int x = 0; x < m_to_width; ++x)
387e5c31af7Sopenharmony_ci		{
388e5c31af7Sopenharmony_ci			if (traveller_ptr[0] != 0 || traveller_ptr[1] != 255 || traveller_ptr[2] != 0 || traveller_ptr[3] != 0)
389e5c31af7Sopenharmony_ci			{
390e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result texel found at (" << x << ", " << y
391e5c31af7Sopenharmony_ci								   << ")." << tcu::TestLog::EndMessage;
392e5c31af7Sopenharmony_ci
393e5c31af7Sopenharmony_ci				result = false;
394e5c31af7Sopenharmony_ci			}
395e5c31af7Sopenharmony_ci
396e5c31af7Sopenharmony_ci			traveller_ptr += 4; /* rgba */
397e5c31af7Sopenharmony_ci		}
398e5c31af7Sopenharmony_ci	}
399e5c31af7Sopenharmony_ci
400e5c31af7Sopenharmony_ciend:
401e5c31af7Sopenharmony_ci	if (result)
402e5c31af7Sopenharmony_ci	{
403e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
404e5c31af7Sopenharmony_ci	}
405e5c31af7Sopenharmony_ci	else
406e5c31af7Sopenharmony_ci	{
407e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
408e5c31af7Sopenharmony_ci	}
409e5c31af7Sopenharmony_ci
410e5c31af7Sopenharmony_ci	return STOP;
411e5c31af7Sopenharmony_ci}
412e5c31af7Sopenharmony_ci
413e5c31af7Sopenharmony_ci/** Constructor
414e5c31af7Sopenharmony_ci *
415e5c31af7Sopenharmony_ci * @param context       Test context
416e5c31af7Sopenharmony_ci * @param extParams     Not used.
417e5c31af7Sopenharmony_ci * @param name          Test case's name
418e5c31af7Sopenharmony_ci * @param description   Test case's description
419e5c31af7Sopenharmony_ci **/
420e5c31af7Sopenharmony_ciGeometryShaderGetShaderivTest::GeometryShaderGetShaderivTest(Context& context, const ExtParameters& extParams,
421e5c31af7Sopenharmony_ci															 const char* name, const char* description)
422e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description), m_gs_id(0)
423e5c31af7Sopenharmony_ci{
424e5c31af7Sopenharmony_ci}
425e5c31af7Sopenharmony_ci
426e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
427e5c31af7Sopenharmony_civoid GeometryShaderGetShaderivTest::deinit()
428e5c31af7Sopenharmony_ci{
429e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
430e5c31af7Sopenharmony_ci
431e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
432e5c31af7Sopenharmony_ci	{
433e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
434e5c31af7Sopenharmony_ci
435e5c31af7Sopenharmony_ci		m_gs_id = 0;
436e5c31af7Sopenharmony_ci	}
437e5c31af7Sopenharmony_ci
438e5c31af7Sopenharmony_ci	/* Release base class */
439e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
440e5c31af7Sopenharmony_ci}
441e5c31af7Sopenharmony_ci
442e5c31af7Sopenharmony_ci/** Executes the test.
443e5c31af7Sopenharmony_ci *
444e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
445e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
446e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
447e5c31af7Sopenharmony_ci **/
448e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderGetShaderivTest::iterate()
449e5c31af7Sopenharmony_ci{
450e5c31af7Sopenharmony_ci	const glw::Functions& gl	 = m_context.getRenderContext().getFunctions();
451e5c31af7Sopenharmony_ci	bool				  result = true;
452e5c31af7Sopenharmony_ci
453e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
454e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
455e5c31af7Sopenharmony_ci	{
456e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
457e5c31af7Sopenharmony_ci	}
458e5c31af7Sopenharmony_ci
459e5c31af7Sopenharmony_ci	/* Create a GS */
460e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
461e5c31af7Sopenharmony_ci
462e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
463e5c31af7Sopenharmony_ci
464e5c31af7Sopenharmony_ci	/* Check the type reported for the SO */
465e5c31af7Sopenharmony_ci	glw::GLint shader_type = GL_NONE;
466e5c31af7Sopenharmony_ci
467e5c31af7Sopenharmony_ci	gl.getShaderiv(m_gs_id, GL_SHADER_TYPE, &shader_type);
468e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
469e5c31af7Sopenharmony_ci
470e5c31af7Sopenharmony_ci	if ((glw::GLenum)shader_type != m_glExtTokens.GEOMETRY_SHADER)
471e5c31af7Sopenharmony_ci	{
472e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid shader type [" << shader_type
473e5c31af7Sopenharmony_ci						   << "] reported for a Geometry Shader" << tcu::TestLog::EndMessage;
474e5c31af7Sopenharmony_ci
475e5c31af7Sopenharmony_ci		result = false;
476e5c31af7Sopenharmony_ci	}
477e5c31af7Sopenharmony_ci
478e5c31af7Sopenharmony_ci	if (result)
479e5c31af7Sopenharmony_ci	{
480e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
481e5c31af7Sopenharmony_ci	}
482e5c31af7Sopenharmony_ci	else
483e5c31af7Sopenharmony_ci	{
484e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
485e5c31af7Sopenharmony_ci	}
486e5c31af7Sopenharmony_ci
487e5c31af7Sopenharmony_ci	return STOP;
488e5c31af7Sopenharmony_ci}
489e5c31af7Sopenharmony_ci
490e5c31af7Sopenharmony_ci/** Constructor
491e5c31af7Sopenharmony_ci *
492e5c31af7Sopenharmony_ci * @param context       Test context
493e5c31af7Sopenharmony_ci * @param extParams     Not used.
494e5c31af7Sopenharmony_ci * @param name          Test case's name
495e5c31af7Sopenharmony_ci * @param description   Test case's description
496e5c31af7Sopenharmony_ci **/
497e5c31af7Sopenharmony_ciGeometryShaderGetProgramivTest::GeometryShaderGetProgramivTest(Context& context, const ExtParameters& extParams,
498e5c31af7Sopenharmony_ci															   const char* name, const char* description)
499e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description), m_po_id(0)
500e5c31af7Sopenharmony_ci{
501e5c31af7Sopenharmony_ci}
502e5c31af7Sopenharmony_ci
503e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
504e5c31af7Sopenharmony_civoid GeometryShaderGetProgramivTest::deinit()
505e5c31af7Sopenharmony_ci{
506e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
507e5c31af7Sopenharmony_ci
508e5c31af7Sopenharmony_ci	if (m_po_id != 0)
509e5c31af7Sopenharmony_ci	{
510e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
511e5c31af7Sopenharmony_ci
512e5c31af7Sopenharmony_ci		m_po_id = 0;
513e5c31af7Sopenharmony_ci	}
514e5c31af7Sopenharmony_ci
515e5c31af7Sopenharmony_ci	/* Release base class */
516e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
517e5c31af7Sopenharmony_ci}
518e5c31af7Sopenharmony_ci
519e5c31af7Sopenharmony_ci/** Executes the test.
520e5c31af7Sopenharmony_ci *
521e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
522e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
523e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
524e5c31af7Sopenharmony_ci **/
525e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderGetProgramivTest::iterate()
526e5c31af7Sopenharmony_ci{
527e5c31af7Sopenharmony_ci	const glw::Functions& gl	 = m_context.getRenderContext().getFunctions();
528e5c31af7Sopenharmony_ci	bool				  result = true;
529e5c31af7Sopenharmony_ci
530e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
531e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
532e5c31af7Sopenharmony_ci	{
533e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
534e5c31af7Sopenharmony_ci	}
535e5c31af7Sopenharmony_ci
536e5c31af7Sopenharmony_ci	/* Create a program object */
537e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
538e5c31af7Sopenharmony_ci
539e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
540e5c31af7Sopenharmony_ci
541e5c31af7Sopenharmony_ci	/* Verify that GS-specific queries cause a GL_INVALID_OPERATION error */
542e5c31af7Sopenharmony_ci	const glw::GLenum pnames[] = { m_glExtTokens.GEOMETRY_LINKED_VERTICES_OUT, m_glExtTokens.GEOMETRY_LINKED_INPUT_TYPE,
543e5c31af7Sopenharmony_ci								   m_glExtTokens.GEOMETRY_LINKED_OUTPUT_TYPE,
544e5c31af7Sopenharmony_ci								   m_glExtTokens.GEOMETRY_SHADER_INVOCATIONS };
545e5c31af7Sopenharmony_ci	const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]);
546e5c31af7Sopenharmony_ci
547e5c31af7Sopenharmony_ci	for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname)
548e5c31af7Sopenharmony_ci	{
549e5c31af7Sopenharmony_ci		glw::GLenum error_code = GL_NO_ERROR;
550e5c31af7Sopenharmony_ci		glw::GLenum pname	  = pnames[n_pname];
551e5c31af7Sopenharmony_ci		glw::GLint  rv		   = -1;
552e5c31af7Sopenharmony_ci
553e5c31af7Sopenharmony_ci		gl.getProgramiv(m_po_id, pname, &rv);
554e5c31af7Sopenharmony_ci
555e5c31af7Sopenharmony_ci		error_code = gl.getError();
556e5c31af7Sopenharmony_ci
557e5c31af7Sopenharmony_ci		if (error_code != GL_INVALID_OPERATION)
558e5c31af7Sopenharmony_ci		{
559e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "No error generated by glGetProgramiv() for pname [" << pname
560e5c31af7Sopenharmony_ci							   << "]" << tcu::TestLog::EndMessage;
561e5c31af7Sopenharmony_ci
562e5c31af7Sopenharmony_ci			result = false;
563e5c31af7Sopenharmony_ci		}
564e5c31af7Sopenharmony_ci	} /* for (all pnames) */
565e5c31af7Sopenharmony_ci
566e5c31af7Sopenharmony_ci	if (result)
567e5c31af7Sopenharmony_ci	{
568e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
569e5c31af7Sopenharmony_ci	}
570e5c31af7Sopenharmony_ci	else
571e5c31af7Sopenharmony_ci	{
572e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
573e5c31af7Sopenharmony_ci	}
574e5c31af7Sopenharmony_ci
575e5c31af7Sopenharmony_ci	return STOP;
576e5c31af7Sopenharmony_ci}
577e5c31af7Sopenharmony_ci
578e5c31af7Sopenharmony_ci/** Constructor
579e5c31af7Sopenharmony_ci *
580e5c31af7Sopenharmony_ci * @param context       Test context
581e5c31af7Sopenharmony_ci * @param extParams     Not used.
582e5c31af7Sopenharmony_ci * @param name          Test case's name
583e5c31af7Sopenharmony_ci * @param description   Test case's description
584e5c31af7Sopenharmony_ci **/
585e5c31af7Sopenharmony_ciGeometryShaderGetProgramiv2Test::GeometryShaderGetProgramiv2Test(Context& context, const ExtParameters& extParams,
586e5c31af7Sopenharmony_ci																 const char* name, const char* description)
587e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description), m_fs_id(0), m_po_id(0), m_vs_id(0)
588e5c31af7Sopenharmony_ci{
589e5c31af7Sopenharmony_ci}
590e5c31af7Sopenharmony_ci
591e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
592e5c31af7Sopenharmony_civoid GeometryShaderGetProgramiv2Test::deinit()
593e5c31af7Sopenharmony_ci{
594e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
595e5c31af7Sopenharmony_ci
596e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
597e5c31af7Sopenharmony_ci	{
598e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
599e5c31af7Sopenharmony_ci
600e5c31af7Sopenharmony_ci		m_fs_id = 0;
601e5c31af7Sopenharmony_ci	}
602e5c31af7Sopenharmony_ci
603e5c31af7Sopenharmony_ci	if (m_po_id != 0)
604e5c31af7Sopenharmony_ci	{
605e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
606e5c31af7Sopenharmony_ci
607e5c31af7Sopenharmony_ci		m_po_id = 0;
608e5c31af7Sopenharmony_ci	}
609e5c31af7Sopenharmony_ci
610e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
611e5c31af7Sopenharmony_ci	{
612e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
613e5c31af7Sopenharmony_ci
614e5c31af7Sopenharmony_ci		m_vs_id = 0;
615e5c31af7Sopenharmony_ci	}
616e5c31af7Sopenharmony_ci
617e5c31af7Sopenharmony_ci	/* Release base class */
618e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
619e5c31af7Sopenharmony_ci}
620e5c31af7Sopenharmony_ci
621e5c31af7Sopenharmony_ci/** Executes the test.
622e5c31af7Sopenharmony_ci *
623e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
624e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
625e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
626e5c31af7Sopenharmony_ci **/
627e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderGetProgramiv2Test::iterate()
628e5c31af7Sopenharmony_ci{
629e5c31af7Sopenharmony_ci	const glw::Functions& gl   = m_context.getRenderContext().getFunctions();
630e5c31af7Sopenharmony_ci	const glw::GLenum pnames[] = { m_glExtTokens.GEOMETRY_LINKED_VERTICES_OUT, m_glExtTokens.GEOMETRY_LINKED_INPUT_TYPE,
631e5c31af7Sopenharmony_ci								   m_glExtTokens.GEOMETRY_LINKED_OUTPUT_TYPE,
632e5c31af7Sopenharmony_ci								   m_glExtTokens.GEOMETRY_SHADER_INVOCATIONS };
633e5c31af7Sopenharmony_ci	const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]);
634e5c31af7Sopenharmony_ci	bool			   result   = true;
635e5c31af7Sopenharmony_ci
636e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
637e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
638e5c31af7Sopenharmony_ci	{
639e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
640e5c31af7Sopenharmony_ci	}
641e5c31af7Sopenharmony_ci
642e5c31af7Sopenharmony_ci	/* Initialize the program object */
643e5c31af7Sopenharmony_ci	std::string specialized_minimal_fs		= specializeShader(1,
644e5c31af7Sopenharmony_ci														/* parts */ &minimal_fs_code);
645e5c31af7Sopenharmony_ci	const char* specialized_minimal_fs_raw	= specialized_minimal_fs.c_str();
646e5c31af7Sopenharmony_ci	std::string specialized_minimal_vs		= specializeShader(1,
647e5c31af7Sopenharmony_ci														/* parts */ &minimal_vs_code);
648e5c31af7Sopenharmony_ci	const char* specialized_minimal_vs_raw	= specialized_minimal_vs.c_str();
649e5c31af7Sopenharmony_ci
650e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
651e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
652e5c31af7Sopenharmony_ci
653e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
654e5c31af7Sopenharmony_ci
655e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
656e5c31af7Sopenharmony_ci
657e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
658e5c31af7Sopenharmony_ci
659e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_po_id, m_fs_id, 1, &specialized_minimal_fs_raw, m_vs_id, 1,
660e5c31af7Sopenharmony_ci									&specialized_minimal_vs_raw))
661e5c31af7Sopenharmony_ci	{
662e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Failed to build a minimal test program object"
663e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
664e5c31af7Sopenharmony_ci
665e5c31af7Sopenharmony_ci		result = false;
666e5c31af7Sopenharmony_ci		goto end;
667e5c31af7Sopenharmony_ci	}
668e5c31af7Sopenharmony_ci
669e5c31af7Sopenharmony_ci	/* Verify that GS-specific queries cause a GL_INVALID_OPERATION error
670e5c31af7Sopenharmony_ci	 * for a linked PO lacking the GS stage.
671e5c31af7Sopenharmony_ci	 */
672e5c31af7Sopenharmony_ci	for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname)
673e5c31af7Sopenharmony_ci	{
674e5c31af7Sopenharmony_ci		glw::GLenum error_code = GL_NO_ERROR;
675e5c31af7Sopenharmony_ci		glw::GLenum pname	  = pnames[n_pname];
676e5c31af7Sopenharmony_ci		glw::GLint  rv		   = -1;
677e5c31af7Sopenharmony_ci
678e5c31af7Sopenharmony_ci		gl.getProgramiv(m_po_id, pname, &rv);
679e5c31af7Sopenharmony_ci
680e5c31af7Sopenharmony_ci		error_code = gl.getError();
681e5c31af7Sopenharmony_ci
682e5c31af7Sopenharmony_ci		if (error_code != GL_INVALID_OPERATION)
683e5c31af7Sopenharmony_ci		{
684e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "No error generated by glGetProgramiv() for pname [" << pname
685e5c31af7Sopenharmony_ci							   << "]" << tcu::TestLog::EndMessage;
686e5c31af7Sopenharmony_ci
687e5c31af7Sopenharmony_ci			result = false;
688e5c31af7Sopenharmony_ci		}
689e5c31af7Sopenharmony_ci	} /* for (all pnames) */
690e5c31af7Sopenharmony_ci
691e5c31af7Sopenharmony_ciend:
692e5c31af7Sopenharmony_ci	if (result)
693e5c31af7Sopenharmony_ci	{
694e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
695e5c31af7Sopenharmony_ci	}
696e5c31af7Sopenharmony_ci	else
697e5c31af7Sopenharmony_ci	{
698e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
699e5c31af7Sopenharmony_ci	}
700e5c31af7Sopenharmony_ci
701e5c31af7Sopenharmony_ci	return STOP;
702e5c31af7Sopenharmony_ci}
703e5c31af7Sopenharmony_ci
704e5c31af7Sopenharmony_ci/** Constructor
705e5c31af7Sopenharmony_ci *
706e5c31af7Sopenharmony_ci * @param context       Test context
707e5c31af7Sopenharmony_ci * @param extParams     Not used.
708e5c31af7Sopenharmony_ci * @param name          Test case's name
709e5c31af7Sopenharmony_ci * @param description   Test case's description
710e5c31af7Sopenharmony_ci **/
711e5c31af7Sopenharmony_ciGeometryShaderGetProgramiv3Test::GeometryShaderGetProgramiv3Test(Context& context, const ExtParameters& extParams,
712e5c31af7Sopenharmony_ci																 const char* name, const char* description)
713e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
714e5c31af7Sopenharmony_ci	, m_fs_id(0)
715e5c31af7Sopenharmony_ci	, m_fs_po_id(0)
716e5c31af7Sopenharmony_ci	, m_gs_id(0)
717e5c31af7Sopenharmony_ci	, m_gs_po_id(0)
718e5c31af7Sopenharmony_ci	, m_pipeline_object_id(0)
719e5c31af7Sopenharmony_ci	, m_po_id(0)
720e5c31af7Sopenharmony_ci	, m_vs_id(0)
721e5c31af7Sopenharmony_ci	, m_vs_po_id(0)
722e5c31af7Sopenharmony_ci{
723e5c31af7Sopenharmony_ci}
724e5c31af7Sopenharmony_ci
725e5c31af7Sopenharmony_ci/* Compiles a shader object using caller-specified data.
726e5c31af7Sopenharmony_ci *
727e5c31af7Sopenharmony_ci * @param so_id   ID of a Shader Object to compile.
728e5c31af7Sopenharmony_ci * @param so_body Body to use for the compilation process.
729e5c31af7Sopenharmony_ci *
730e5c31af7Sopenharmony_ci * @return true if the compilation succeeded, false otherwise */
731e5c31af7Sopenharmony_cibool GeometryShaderGetProgramiv3Test::buildShader(glw::GLuint so_id, const char* so_body)
732e5c31af7Sopenharmony_ci{
733e5c31af7Sopenharmony_ci	glw::GLint			  compile_status = GL_FALSE;
734e5c31af7Sopenharmony_ci	const glw::Functions& gl			 = m_context.getRenderContext().getFunctions();
735e5c31af7Sopenharmony_ci	bool				  result		 = false;
736e5c31af7Sopenharmony_ci
737e5c31af7Sopenharmony_ci	gl.shaderSource(so_id, 1,			/* count */
738e5c31af7Sopenharmony_ci					&so_body, DE_NULL); /* length */
739e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
740e5c31af7Sopenharmony_ci
741e5c31af7Sopenharmony_ci	gl.compileShader(so_id);
742e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
743e5c31af7Sopenharmony_ci
744e5c31af7Sopenharmony_ci	gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
745e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
746e5c31af7Sopenharmony_ci
747e5c31af7Sopenharmony_ci	result = (compile_status == GL_TRUE);
748e5c31af7Sopenharmony_ci
749e5c31af7Sopenharmony_ci	return result;
750e5c31af7Sopenharmony_ci}
751e5c31af7Sopenharmony_ci
752e5c31af7Sopenharmony_ci/** Builds a single shader program object using caller-specified data.
753e5c31af7Sopenharmony_ci *
754e5c31af7Sopenharmony_ci *  @param out_spo_id Deref will be set to the ID of the created shader program object.
755e5c31af7Sopenharmony_ci *                    Must not be NULL.
756e5c31af7Sopenharmony_ci *  @param spo_bits   Bits to be passed to the glCreateShaderProgramv() call.
757e5c31af7Sopenharmony_ci *  @param spo_body   Body to use for the glCreateShaderProgramv() call.
758e5c31af7Sopenharmony_ci *
759e5c31af7Sopenharmony_ci *  @return true if the shader program object was linked successfully, false otherwise.
760e5c31af7Sopenharmony_ci */
761e5c31af7Sopenharmony_cibool GeometryShaderGetProgramiv3Test::buildShaderProgram(glw::GLuint* out_spo_id, glw::GLenum spo_bits,
762e5c31af7Sopenharmony_ci														 const char* spo_body)
763e5c31af7Sopenharmony_ci{
764e5c31af7Sopenharmony_ci	const glw::Functions& gl		  = m_context.getRenderContext().getFunctions();
765e5c31af7Sopenharmony_ci	glw::GLint			  link_status = GL_FALSE;
766e5c31af7Sopenharmony_ci	bool				  result	  = true;
767e5c31af7Sopenharmony_ci
768e5c31af7Sopenharmony_ci	*out_spo_id = gl.createShaderProgramv(spo_bits, 1, /* count */
769e5c31af7Sopenharmony_ci										  &spo_body);
770e5c31af7Sopenharmony_ci
771e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
772e5c31af7Sopenharmony_ci
773e5c31af7Sopenharmony_ci	gl.getProgramiv(*out_spo_id, GL_LINK_STATUS, &link_status);
774e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
775e5c31af7Sopenharmony_ci
776e5c31af7Sopenharmony_ci	result = (link_status == GL_TRUE);
777e5c31af7Sopenharmony_ci
778e5c31af7Sopenharmony_ci	return result;
779e5c31af7Sopenharmony_ci}
780e5c31af7Sopenharmony_ci
781e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
782e5c31af7Sopenharmony_civoid GeometryShaderGetProgramiv3Test::deinit()
783e5c31af7Sopenharmony_ci{
784e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
785e5c31af7Sopenharmony_ci
786e5c31af7Sopenharmony_ci	deinitPO();
787e5c31af7Sopenharmony_ci	deinitSOs(true);
788e5c31af7Sopenharmony_ci	deinitSPOs(true);
789e5c31af7Sopenharmony_ci
790e5c31af7Sopenharmony_ci	if (m_pipeline_object_id != 0)
791e5c31af7Sopenharmony_ci	{
792e5c31af7Sopenharmony_ci		gl.deleteProgramPipelines(1, &m_pipeline_object_id);
793e5c31af7Sopenharmony_ci
794e5c31af7Sopenharmony_ci		m_pipeline_object_id = 0;
795e5c31af7Sopenharmony_ci	}
796e5c31af7Sopenharmony_ci
797e5c31af7Sopenharmony_ci	/* Release base class */
798e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
799e5c31af7Sopenharmony_ci}
800e5c31af7Sopenharmony_ci
801e5c31af7Sopenharmony_ci/** Deinitializes a program object created for the conformance test. */
802e5c31af7Sopenharmony_civoid GeometryShaderGetProgramiv3Test::deinitPO()
803e5c31af7Sopenharmony_ci{
804e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
805e5c31af7Sopenharmony_ci
806e5c31af7Sopenharmony_ci	if (m_po_id != 0)
807e5c31af7Sopenharmony_ci	{
808e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
809e5c31af7Sopenharmony_ci
810e5c31af7Sopenharmony_ci		m_po_id = 0;
811e5c31af7Sopenharmony_ci	}
812e5c31af7Sopenharmony_ci}
813e5c31af7Sopenharmony_ci
814e5c31af7Sopenharmony_ci/** Deinitializes shader objects created for the conformance test. */
815e5c31af7Sopenharmony_civoid GeometryShaderGetProgramiv3Test::deinitSOs(bool release_all_SOs)
816e5c31af7Sopenharmony_ci{
817e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
818e5c31af7Sopenharmony_ci
819e5c31af7Sopenharmony_ci	if (m_fs_id != 0 && release_all_SOs)
820e5c31af7Sopenharmony_ci	{
821e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
822e5c31af7Sopenharmony_ci
823e5c31af7Sopenharmony_ci		m_fs_id = 0;
824e5c31af7Sopenharmony_ci	}
825e5c31af7Sopenharmony_ci
826e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
827e5c31af7Sopenharmony_ci	{
828e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
829e5c31af7Sopenharmony_ci
830e5c31af7Sopenharmony_ci		m_gs_id = 0;
831e5c31af7Sopenharmony_ci	}
832e5c31af7Sopenharmony_ci
833e5c31af7Sopenharmony_ci	if (m_vs_id != 0 && release_all_SOs)
834e5c31af7Sopenharmony_ci	{
835e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
836e5c31af7Sopenharmony_ci
837e5c31af7Sopenharmony_ci		m_vs_id = 0;
838e5c31af7Sopenharmony_ci	}
839e5c31af7Sopenharmony_ci}
840e5c31af7Sopenharmony_ci
841e5c31af7Sopenharmony_ci/** Deinitializes shader program objects created for the conformance test. */
842e5c31af7Sopenharmony_civoid GeometryShaderGetProgramiv3Test::deinitSPOs(bool release_all_SPOs)
843e5c31af7Sopenharmony_ci{
844e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
845e5c31af7Sopenharmony_ci
846e5c31af7Sopenharmony_ci	if (m_fs_po_id != 0 && release_all_SPOs)
847e5c31af7Sopenharmony_ci	{
848e5c31af7Sopenharmony_ci		gl.deleteProgram(m_fs_po_id);
849e5c31af7Sopenharmony_ci
850e5c31af7Sopenharmony_ci		m_fs_po_id = 0;
851e5c31af7Sopenharmony_ci	}
852e5c31af7Sopenharmony_ci
853e5c31af7Sopenharmony_ci	if (m_gs_po_id != 0)
854e5c31af7Sopenharmony_ci	{
855e5c31af7Sopenharmony_ci		gl.deleteProgram(m_gs_po_id);
856e5c31af7Sopenharmony_ci
857e5c31af7Sopenharmony_ci		m_gs_po_id = 0;
858e5c31af7Sopenharmony_ci	}
859e5c31af7Sopenharmony_ci
860e5c31af7Sopenharmony_ci	if (m_vs_po_id != 0 && release_all_SPOs)
861e5c31af7Sopenharmony_ci	{
862e5c31af7Sopenharmony_ci		gl.deleteProgram(m_vs_po_id);
863e5c31af7Sopenharmony_ci
864e5c31af7Sopenharmony_ci		m_vs_po_id = 0;
865e5c31af7Sopenharmony_ci	}
866e5c31af7Sopenharmony_ci}
867e5c31af7Sopenharmony_ci
868e5c31af7Sopenharmony_ci/** Retrieves ES SL layout qualifier, corresponding to user-specified
869e5c31af7Sopenharmony_ci *  primitive type.
870e5c31af7Sopenharmony_ci *
871e5c31af7Sopenharmony_ci *  @param primitive_type Primitive type (described by a GLenum value)
872e5c31af7Sopenharmony_ci *                        to use for the query.
873e5c31af7Sopenharmony_ci *
874e5c31af7Sopenharmony_ci *  @return Requested layout qualifier.
875e5c31af7Sopenharmony_ci */
876e5c31af7Sopenharmony_cistd::string GeometryShaderGetProgramiv3Test::getLayoutQualifierForPrimitiveType(glw::GLenum primitive_type)
877e5c31af7Sopenharmony_ci{
878e5c31af7Sopenharmony_ci	std::string result;
879e5c31af7Sopenharmony_ci
880e5c31af7Sopenharmony_ci	switch (primitive_type)
881e5c31af7Sopenharmony_ci	{
882e5c31af7Sopenharmony_ci	case GL_LINE_STRIP:
883e5c31af7Sopenharmony_ci		result = "line_strip";
884e5c31af7Sopenharmony_ci		break;
885e5c31af7Sopenharmony_ci	case GL_LINES_ADJACENCY:
886e5c31af7Sopenharmony_ci		result = "lines_adjacency";
887e5c31af7Sopenharmony_ci		break;
888e5c31af7Sopenharmony_ci	case GL_POINTS:
889e5c31af7Sopenharmony_ci		result = "points";
890e5c31af7Sopenharmony_ci		break;
891e5c31af7Sopenharmony_ci	case GL_TRIANGLES:
892e5c31af7Sopenharmony_ci		result = "triangles";
893e5c31af7Sopenharmony_ci		break;
894e5c31af7Sopenharmony_ci	case GL_TRIANGLE_STRIP:
895e5c31af7Sopenharmony_ci		result = "triangle_strip";
896e5c31af7Sopenharmony_ci		break;
897e5c31af7Sopenharmony_ci
898e5c31af7Sopenharmony_ci	default:
899e5c31af7Sopenharmony_ci	{
900e5c31af7Sopenharmony_ci		DE_ASSERT(0);
901e5c31af7Sopenharmony_ci	}
902e5c31af7Sopenharmony_ci	} /* switch (primitive_type) */
903e5c31af7Sopenharmony_ci
904e5c31af7Sopenharmony_ci	return result;
905e5c31af7Sopenharmony_ci}
906e5c31af7Sopenharmony_ci
907e5c31af7Sopenharmony_ci/** Retrieves body of a geometry shadet to be used for the conformance test.
908e5c31af7Sopenharmony_ci *  The body is generated, according to the properties described by the
909e5c31af7Sopenharmony_ci *  run descriptor passed as an argument.
910e5c31af7Sopenharmony_ci *
911e5c31af7Sopenharmony_ci *  @param run Test run descriptor.
912e5c31af7Sopenharmony_ci *
913e5c31af7Sopenharmony_ci *  @return Requested string.
914e5c31af7Sopenharmony_ci */
915e5c31af7Sopenharmony_cistd::string GeometryShaderGetProgramiv3Test::getGSCode(const _run& run)
916e5c31af7Sopenharmony_ci{
917e5c31af7Sopenharmony_ci	std::stringstream code_sstream;
918e5c31af7Sopenharmony_ci
919e5c31af7Sopenharmony_ci	code_sstream << "${VERSION}\n"
920e5c31af7Sopenharmony_ci					"${GEOMETRY_SHADER_REQUIRE}\n"
921e5c31af7Sopenharmony_ci					"\n"
922e5c31af7Sopenharmony_ci					"layout("
923e5c31af7Sopenharmony_ci				 << getLayoutQualifierForPrimitiveType(run.input_primitive_type) << ", "
924e5c31af7Sopenharmony_ci																					"invocations = "
925e5c31af7Sopenharmony_ci				 << run.invocations << ") in;\n"
926e5c31af7Sopenharmony_ci									   "layout("
927e5c31af7Sopenharmony_ci				 << getLayoutQualifierForPrimitiveType(run.output_primitive_type) << ", "
928e5c31af7Sopenharmony_ci																					 "max_vertices = "
929e5c31af7Sopenharmony_ci				 << run.max_vertices << ") out;\n"
930e5c31af7Sopenharmony_ci										"\n"
931e5c31af7Sopenharmony_ci										"out gl_PerVertex {\n"
932e5c31af7Sopenharmony_ci										"    vec4 gl_Position;\n"
933e5c31af7Sopenharmony_ci										"};\n"
934e5c31af7Sopenharmony_ci										"\n"
935e5c31af7Sopenharmony_ci										"void main()\n"
936e5c31af7Sopenharmony_ci										"{\n"
937e5c31af7Sopenharmony_ci										"    for (int n = 0; n < "
938e5c31af7Sopenharmony_ci				 << run.max_vertices << "; ++n)\n"
939e5c31af7Sopenharmony_ci										"    {\n"
940e5c31af7Sopenharmony_ci										"        gl_Position = vec4(n, 0.0, 0.0, 1.0);\n"
941e5c31af7Sopenharmony_ci										"        EmitVertex();\n"
942e5c31af7Sopenharmony_ci										"    }\n"
943e5c31af7Sopenharmony_ci										"\n"
944e5c31af7Sopenharmony_ci										"    EndPrimitive();\n"
945e5c31af7Sopenharmony_ci										"}\n";
946e5c31af7Sopenharmony_ci
947e5c31af7Sopenharmony_ci	return code_sstream.str();
948e5c31af7Sopenharmony_ci}
949e5c31af7Sopenharmony_ci
950e5c31af7Sopenharmony_ci/** Initializes internal _runs member with test iteration settings for all test runs. */
951e5c31af7Sopenharmony_civoid GeometryShaderGetProgramiv3Test::initTestRuns()
952e5c31af7Sopenharmony_ci{
953e5c31af7Sopenharmony_ci	/*                   input primitive type | invocations | max vertices | output primitive type *
954e5c31af7Sopenharmony_ci	 *----------------------------------------+-------------+--------------+-----------------------*/
955e5c31af7Sopenharmony_ci	_runs.push_back(_run(GL_LINES_ADJACENCY, 3, 16, GL_POINTS));
956e5c31af7Sopenharmony_ci	_runs.push_back(_run(GL_TRIANGLES, 12, 37, GL_LINE_STRIP));
957e5c31af7Sopenharmony_ci	_runs.push_back(_run(GL_POINTS, 31, 75, GL_TRIANGLE_STRIP));
958e5c31af7Sopenharmony_ci}
959e5c31af7Sopenharmony_ci
960e5c31af7Sopenharmony_ci/** Executes the test.
961e5c31af7Sopenharmony_ci *
962e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
963e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
964e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
965e5c31af7Sopenharmony_ci **/
966e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderGetProgramiv3Test::iterate()
967e5c31af7Sopenharmony_ci{
968e5c31af7Sopenharmony_ci	const glw::Functions& gl					  = m_context.getRenderContext().getFunctions();
969e5c31af7Sopenharmony_ci	glw::GLint			  gs_spo_id				  = 0;
970e5c31af7Sopenharmony_ci	unsigned int		  n_run					  = 0;
971e5c31af7Sopenharmony_ci	unsigned int		  n_separable_object_case = 0;
972e5c31af7Sopenharmony_ci	bool				  result				  = true;
973e5c31af7Sopenharmony_ci
974e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
975e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
976e5c31af7Sopenharmony_ci	{
977e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
978e5c31af7Sopenharmony_ci	}
979e5c31af7Sopenharmony_ci
980e5c31af7Sopenharmony_ci	/* Prepare specialized versions of minimal fragment & vertex shaders */
981e5c31af7Sopenharmony_ci	std::string minimal_fs_specialized		= specializeShader(1,
982e5c31af7Sopenharmony_ci														/* parts */ &minimal_fs_code);
983e5c31af7Sopenharmony_ci	const char* minimal_fs_specialized_raw	= minimal_fs_specialized.c_str();
984e5c31af7Sopenharmony_ci	std::string minimal_vs_specialized		= specializeShader(1, &minimal_vs_code);
985e5c31af7Sopenharmony_ci	const char* minimal_vs_specialized_raw	= minimal_vs_specialized.c_str();
986e5c31af7Sopenharmony_ci
987e5c31af7Sopenharmony_ci	/* Set up the fragment & the vertex shaders */
988e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
989e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
990e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
991e5c31af7Sopenharmony_ci
992e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
993e5c31af7Sopenharmony_ci
994e5c31af7Sopenharmony_ci	if (!buildShader(m_fs_id, minimal_fs_specialized_raw) || !buildShader(m_vs_id, minimal_vs_specialized_raw))
995e5c31af7Sopenharmony_ci	{
996e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Either FS or VS failed to build." << tcu::TestLog::EndMessage;
997e5c31af7Sopenharmony_ci
998e5c31af7Sopenharmony_ci		result = false;
999e5c31af7Sopenharmony_ci		goto end;
1000e5c31af7Sopenharmony_ci	}
1001e5c31af7Sopenharmony_ci
1002e5c31af7Sopenharmony_ci	/* Set up the test program object */
1003e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
1004e5c31af7Sopenharmony_ci
1005e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
1006e5c31af7Sopenharmony_ci
1007e5c31af7Sopenharmony_ci	gl.attachShader(m_po_id, m_fs_id);
1008e5c31af7Sopenharmony_ci	gl.attachShader(m_po_id, m_gs_id);
1009e5c31af7Sopenharmony_ci	gl.attachShader(m_po_id, m_vs_id);
1010e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
1011e5c31af7Sopenharmony_ci
1012e5c31af7Sopenharmony_ci	/* Set up the fragment & the vertex shader programs */
1013e5c31af7Sopenharmony_ci	if (!buildShaderProgram(&m_fs_po_id, GL_FRAGMENT_SHADER, minimal_fs_specialized_raw) ||
1014e5c31af7Sopenharmony_ci		!buildShaderProgram(&m_vs_po_id, GL_VERTEX_SHADER, minimal_vs_specialized_raw))
1015e5c31af7Sopenharmony_ci	{
1016e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Either FS or VS SPOs failed to build."
1017e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
1018e5c31af7Sopenharmony_ci
1019e5c31af7Sopenharmony_ci		result = false;
1020e5c31af7Sopenharmony_ci		goto end;
1021e5c31af7Sopenharmony_ci	}
1022e5c31af7Sopenharmony_ci
1023e5c31af7Sopenharmony_ci	/* Set up test runs */
1024e5c31af7Sopenharmony_ci	initTestRuns();
1025e5c31af7Sopenharmony_ci
1026e5c31af7Sopenharmony_ci	/* The test should check both a geometry shader program object and a full-blown PO
1027e5c31af7Sopenharmony_ci	 * consisting of FS, GS and VS. */
1028e5c31af7Sopenharmony_ci	for (n_separable_object_case = 0; n_separable_object_case < 2; /* PO, SPO cases */
1029e5c31af7Sopenharmony_ci		 ++n_separable_object_case)
1030e5c31af7Sopenharmony_ci	{
1031e5c31af7Sopenharmony_ci		bool should_use_separable_object = (n_separable_object_case != 0);
1032e5c31af7Sopenharmony_ci
1033e5c31af7Sopenharmony_ci		/* Iterate over all test runs */
1034e5c31af7Sopenharmony_ci		for (n_run = 0; n_run < _runs.size(); ++n_run)
1035e5c31af7Sopenharmony_ci		{
1036e5c31af7Sopenharmony_ci			const _run& current_run			= _runs[n_run];
1037e5c31af7Sopenharmony_ci			std::string gs_code				= getGSCode(current_run);
1038e5c31af7Sopenharmony_ci			const char* gs_code_raw			= gs_code.c_str();
1039e5c31af7Sopenharmony_ci			std::string gs_code_specialized = specializeShader(1, /* parts */
1040e5c31af7Sopenharmony_ci															   &gs_code_raw);
1041e5c31af7Sopenharmony_ci			const char* gs_code_specialized_raw = gs_code_specialized.c_str();
1042e5c31af7Sopenharmony_ci
1043e5c31af7Sopenharmony_ci			if (should_use_separable_object)
1044e5c31af7Sopenharmony_ci			{
1045e5c31af7Sopenharmony_ci				/* Deinitialize any objects that may have been created in previous iterations */
1046e5c31af7Sopenharmony_ci				deinitSPOs(false);
1047e5c31af7Sopenharmony_ci
1048e5c31af7Sopenharmony_ci				/* Set up the geometry shader program object */
1049e5c31af7Sopenharmony_ci				if (!buildShaderProgram(&m_gs_po_id, GL_GEOMETRY_SHADER, gs_code_specialized_raw))
1050e5c31af7Sopenharmony_ci				{
1051e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "Failed to compile a geometry shader program object"
1052e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
1053e5c31af7Sopenharmony_ci
1054e5c31af7Sopenharmony_ci					result = false;
1055e5c31af7Sopenharmony_ci					goto end;
1056e5c31af7Sopenharmony_ci				}
1057e5c31af7Sopenharmony_ci			} /* if (should_use_pipeline_object) */
1058e5c31af7Sopenharmony_ci			else
1059e5c31af7Sopenharmony_ci			{
1060e5c31af7Sopenharmony_ci				gl.bindProgramPipeline(0);
1061e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
1062e5c31af7Sopenharmony_ci
1063e5c31af7Sopenharmony_ci				/* Set up the geometry shader object */
1064e5c31af7Sopenharmony_ci				if (!buildShader(m_gs_id, gs_code_specialized_raw))
1065e5c31af7Sopenharmony_ci				{
1066e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "Failed to compile a geometry shader object."
1067e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
1068e5c31af7Sopenharmony_ci
1069e5c31af7Sopenharmony_ci					result = false;
1070e5c31af7Sopenharmony_ci					goto end;
1071e5c31af7Sopenharmony_ci				}
1072e5c31af7Sopenharmony_ci
1073e5c31af7Sopenharmony_ci				/* Set up the program object */
1074e5c31af7Sopenharmony_ci				glw::GLint link_status = GL_FALSE;
1075e5c31af7Sopenharmony_ci
1076e5c31af7Sopenharmony_ci				gl.linkProgram(m_po_id);
1077e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
1078e5c31af7Sopenharmony_ci
1079e5c31af7Sopenharmony_ci				gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
1080e5c31af7Sopenharmony_ci
1081e5c31af7Sopenharmony_ci				if (link_status == GL_FALSE)
1082e5c31af7Sopenharmony_ci				{
1083e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "Test program object failed to link"
1084e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
1085e5c31af7Sopenharmony_ci
1086e5c31af7Sopenharmony_ci					result = false;
1087e5c31af7Sopenharmony_ci					goto end;
1088e5c31af7Sopenharmony_ci				}
1089e5c31af7Sopenharmony_ci
1090e5c31af7Sopenharmony_ci				/* Bind the PO to the rendering context */
1091e5c31af7Sopenharmony_ci				gl.useProgram(m_po_id);
1092e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
1093e5c31af7Sopenharmony_ci			}
1094e5c31af7Sopenharmony_ci
1095e5c31af7Sopenharmony_ci			/* Execute the queries */
1096e5c31af7Sopenharmony_ci			glw::GLuint po_id								= (should_use_separable_object) ? m_gs_po_id : m_po_id;
1097e5c31af7Sopenharmony_ci			glw::GLint  result_geometry_linked_vertices_out = 0;
1098e5c31af7Sopenharmony_ci			glw::GLint  result_geometry_linked_input_type   = 0;
1099e5c31af7Sopenharmony_ci			glw::GLint  result_geometry_linked_output_type  = 0;
1100e5c31af7Sopenharmony_ci			glw::GLint  result_geometry_shader_invocations  = 0;
1101e5c31af7Sopenharmony_ci
1102e5c31af7Sopenharmony_ci			gl.getProgramiv(po_id, m_glExtTokens.GEOMETRY_LINKED_VERTICES_OUT, &result_geometry_linked_vertices_out);
1103e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(),
1104e5c31af7Sopenharmony_ci								"glGetProgramiv() call failed for GL_GEOMETRY_LINKED_VERTICES_OUT_EXT query.");
1105e5c31af7Sopenharmony_ci
1106e5c31af7Sopenharmony_ci			gl.getProgramiv(po_id, m_glExtTokens.GEOMETRY_LINKED_INPUT_TYPE, &result_geometry_linked_input_type);
1107e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(),
1108e5c31af7Sopenharmony_ci								"glGetProgramiv() call failed for GL_GEOMETRY_LINKED_INPUT_TYPE_EXT query.");
1109e5c31af7Sopenharmony_ci
1110e5c31af7Sopenharmony_ci			gl.getProgramiv(po_id, m_glExtTokens.GEOMETRY_LINKED_OUTPUT_TYPE, &result_geometry_linked_output_type);
1111e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(),
1112e5c31af7Sopenharmony_ci								"glGetProgramiv() call failed for GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT query.");
1113e5c31af7Sopenharmony_ci
1114e5c31af7Sopenharmony_ci			gl.getProgramiv(po_id, m_glExtTokens.GEOMETRY_SHADER_INVOCATIONS, &result_geometry_shader_invocations);
1115e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(),
1116e5c31af7Sopenharmony_ci								"glGetProgramiv() call failed for GL_GEOMETRY_LINKED_INPUT_TYPE_EXT query.");
1117e5c31af7Sopenharmony_ci
1118e5c31af7Sopenharmony_ci			if (current_run.input_primitive_type != (glw::GLenum)result_geometry_linked_input_type)
1119e5c31af7Sopenharmony_ci			{
1120e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "GL_GEOMETRY_LINKED_INPUT_TYPE_EXT query value "
1121e5c31af7Sopenharmony_ci								   << "[" << result_geometry_linked_input_type
1122e5c31af7Sopenharmony_ci								   << "]"
1123e5c31af7Sopenharmony_ci									  " does not match the test run setting "
1124e5c31af7Sopenharmony_ci									  "["
1125e5c31af7Sopenharmony_ci								   << current_run.input_primitive_type << "]" << tcu::TestLog::EndMessage;
1126e5c31af7Sopenharmony_ci
1127e5c31af7Sopenharmony_ci				result = false;
1128e5c31af7Sopenharmony_ci			}
1129e5c31af7Sopenharmony_ci
1130e5c31af7Sopenharmony_ci			if (current_run.invocations != result_geometry_shader_invocations)
1131e5c31af7Sopenharmony_ci			{
1132e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "GL_GEOMETRY_SHADER_INVOCATIONS_EXT query value "
1133e5c31af7Sopenharmony_ci								   << "[" << result_geometry_shader_invocations
1134e5c31af7Sopenharmony_ci								   << "]"
1135e5c31af7Sopenharmony_ci									  " does not match the test run setting "
1136e5c31af7Sopenharmony_ci									  "["
1137e5c31af7Sopenharmony_ci								   << current_run.input_primitive_type << "]" << tcu::TestLog::EndMessage;
1138e5c31af7Sopenharmony_ci
1139e5c31af7Sopenharmony_ci				result = false;
1140e5c31af7Sopenharmony_ci			}
1141e5c31af7Sopenharmony_ci
1142e5c31af7Sopenharmony_ci			if (current_run.max_vertices != result_geometry_linked_vertices_out)
1143e5c31af7Sopenharmony_ci			{
1144e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "GL_GEOMETRY_LINKED_VERTICES_OUT query value "
1145e5c31af7Sopenharmony_ci								   << "[" << result_geometry_linked_vertices_out
1146e5c31af7Sopenharmony_ci								   << "]"
1147e5c31af7Sopenharmony_ci									  " does not match the test run setting "
1148e5c31af7Sopenharmony_ci									  "["
1149e5c31af7Sopenharmony_ci								   << current_run.max_vertices << "]" << tcu::TestLog::EndMessage;
1150e5c31af7Sopenharmony_ci
1151e5c31af7Sopenharmony_ci				result = false;
1152e5c31af7Sopenharmony_ci			}
1153e5c31af7Sopenharmony_ci
1154e5c31af7Sopenharmony_ci			if (current_run.output_primitive_type != (glw::GLenum)result_geometry_linked_output_type)
1155e5c31af7Sopenharmony_ci			{
1156e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT query value "
1157e5c31af7Sopenharmony_ci								   << "[" << result_geometry_linked_output_type
1158e5c31af7Sopenharmony_ci								   << "]"
1159e5c31af7Sopenharmony_ci									  " does not match the test run setting "
1160e5c31af7Sopenharmony_ci									  "["
1161e5c31af7Sopenharmony_ci								   << current_run.output_primitive_type << "]" << tcu::TestLog::EndMessage;
1162e5c31af7Sopenharmony_ci
1163e5c31af7Sopenharmony_ci				result = false;
1164e5c31af7Sopenharmony_ci			}
1165e5c31af7Sopenharmony_ci		} /* for (all test runs) */
1166e5c31af7Sopenharmony_ci	}	 /* for (PO & SPO cases) */
1167e5c31af7Sopenharmony_ci
1168e5c31af7Sopenharmony_ci	/* One more check: build a pipeline object which only defines a FS & VS stages,
1169e5c31af7Sopenharmony_ci	 *                 and check what GS SPO ID the object reports. */
1170e5c31af7Sopenharmony_ci	gl.genProgramPipelines(1, &m_pipeline_object_id);
1171e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
1172e5c31af7Sopenharmony_ci
1173e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_object_id, GL_FRAGMENT_SHADER_BIT, m_fs_po_id);
1174e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_object_id, GL_VERTEX_SHADER_BIT, m_vs_po_id);
1175e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
1176e5c31af7Sopenharmony_ci
1177e5c31af7Sopenharmony_ci	gl.getProgramPipelineiv(m_pipeline_object_id, m_glExtTokens.GEOMETRY_SHADER, &gs_spo_id);
1178e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed.");
1179e5c31af7Sopenharmony_ci
1180e5c31af7Sopenharmony_ci	if (gs_spo_id != 0)
1181e5c31af7Sopenharmony_ci	{
1182e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Pipeline object reported [" << gs_spo_id << "]"
1183e5c31af7Sopenharmony_ci						   << " for GL_GEOMETRY_SHADER_EXT query, even though no GS SPO was bound."
1184e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
1185e5c31af7Sopenharmony_ci
1186e5c31af7Sopenharmony_ci		result = false;
1187e5c31af7Sopenharmony_ci	}
1188e5c31af7Sopenharmony_ci
1189e5c31af7Sopenharmony_ciend:
1190e5c31af7Sopenharmony_ci	if (result)
1191e5c31af7Sopenharmony_ci	{
1192e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1193e5c31af7Sopenharmony_ci	}
1194e5c31af7Sopenharmony_ci	else
1195e5c31af7Sopenharmony_ci	{
1196e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1197e5c31af7Sopenharmony_ci	}
1198e5c31af7Sopenharmony_ci
1199e5c31af7Sopenharmony_ci	return STOP;
1200e5c31af7Sopenharmony_ci}
1201e5c31af7Sopenharmony_ci
1202e5c31af7Sopenharmony_ci/** Constructor
1203e5c31af7Sopenharmony_ci *
1204e5c31af7Sopenharmony_ci * @param context       Test context
1205e5c31af7Sopenharmony_ci * @param extParams     Not used.
1206e5c31af7Sopenharmony_ci * @param name          Test case's name
1207e5c31af7Sopenharmony_ci * @param description   Test case's description
1208e5c31af7Sopenharmony_ci **/
1209e5c31af7Sopenharmony_ciGeometryShaderDrawCallWithFSAndGS::GeometryShaderDrawCallWithFSAndGS(Context& context, const ExtParameters& extParams,
1210e5c31af7Sopenharmony_ci																	 const char* name, const char* description)
1211e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
1212e5c31af7Sopenharmony_ci	, m_fs_po_id(0)
1213e5c31af7Sopenharmony_ci	, m_gs_po_id(0)
1214e5c31af7Sopenharmony_ci	, m_pipeline_object_id(0)
1215e5c31af7Sopenharmony_ci	, m_vao_id(0)
1216e5c31af7Sopenharmony_ci{
1217e5c31af7Sopenharmony_ci}
1218e5c31af7Sopenharmony_ci
1219e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
1220e5c31af7Sopenharmony_civoid GeometryShaderDrawCallWithFSAndGS::deinit()
1221e5c31af7Sopenharmony_ci{
1222e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1223e5c31af7Sopenharmony_ci
1224e5c31af7Sopenharmony_ci	if (m_fs_po_id != 0)
1225e5c31af7Sopenharmony_ci	{
1226e5c31af7Sopenharmony_ci		gl.deleteProgram(m_fs_po_id);
1227e5c31af7Sopenharmony_ci
1228e5c31af7Sopenharmony_ci		m_fs_po_id = 0;
1229e5c31af7Sopenharmony_ci	}
1230e5c31af7Sopenharmony_ci
1231e5c31af7Sopenharmony_ci	if (m_gs_po_id != 0)
1232e5c31af7Sopenharmony_ci	{
1233e5c31af7Sopenharmony_ci		gl.deleteProgram(m_gs_po_id);
1234e5c31af7Sopenharmony_ci
1235e5c31af7Sopenharmony_ci		m_gs_po_id = 0;
1236e5c31af7Sopenharmony_ci	}
1237e5c31af7Sopenharmony_ci
1238e5c31af7Sopenharmony_ci	if (m_pipeline_object_id != 0)
1239e5c31af7Sopenharmony_ci	{
1240e5c31af7Sopenharmony_ci		gl.deleteProgramPipelines(1, &m_pipeline_object_id);
1241e5c31af7Sopenharmony_ci
1242e5c31af7Sopenharmony_ci		m_pipeline_object_id = 0;
1243e5c31af7Sopenharmony_ci	}
1244e5c31af7Sopenharmony_ci
1245e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
1246e5c31af7Sopenharmony_ci	{
1247e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
1248e5c31af7Sopenharmony_ci
1249e5c31af7Sopenharmony_ci		m_vao_id = 0;
1250e5c31af7Sopenharmony_ci	}
1251e5c31af7Sopenharmony_ci
1252e5c31af7Sopenharmony_ci	/* Release base class */
1253e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
1254e5c31af7Sopenharmony_ci}
1255e5c31af7Sopenharmony_ci
1256e5c31af7Sopenharmony_ci/** Executes the test.
1257e5c31af7Sopenharmony_ci *
1258e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1259e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
1260e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
1261e5c31af7Sopenharmony_ci **/
1262e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderDrawCallWithFSAndGS::iterate()
1263e5c31af7Sopenharmony_ci{
1264e5c31af7Sopenharmony_ci	glw::GLenum			  error_code = GL_NO_ERROR;
1265e5c31af7Sopenharmony_ci	const glw::Functions& gl		 = m_context.getRenderContext().getFunctions();
1266e5c31af7Sopenharmony_ci	bool				  result	 = true;
1267e5c31af7Sopenharmony_ci
1268e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
1269e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
1270e5c31af7Sopenharmony_ci	{
1271e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
1272e5c31af7Sopenharmony_ci	}
1273e5c31af7Sopenharmony_ci
1274e5c31af7Sopenharmony_ci	/* Create & bind a VAO */
1275e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
1276e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
1277e5c31af7Sopenharmony_ci
1278e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
1279e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
1280e5c31af7Sopenharmony_ci
1281e5c31af7Sopenharmony_ci	/* Create shader program objects */
1282e5c31af7Sopenharmony_ci	std::string code_fs_specialized		= specializeShader(1, /* parts */
1283e5c31af7Sopenharmony_ci													   &minimal_fs_code);
1284e5c31af7Sopenharmony_ci	const char* code_fs_specialized_raw = code_fs_specialized.c_str();
1285e5c31af7Sopenharmony_ci	std::string code_gs_specialized		= specializeShader(1, /* parts */
1286e5c31af7Sopenharmony_ci													   &minimal_gs_code);
1287e5c31af7Sopenharmony_ci	const char* code_gs_specialized_raw = code_gs_specialized.c_str();
1288e5c31af7Sopenharmony_ci	glw::GLint  link_status				= GL_FALSE;
1289e5c31af7Sopenharmony_ci
1290e5c31af7Sopenharmony_ci	m_fs_po_id = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1, /* count */
1291e5c31af7Sopenharmony_ci										 &code_fs_specialized_raw);
1292e5c31af7Sopenharmony_ci	m_gs_po_id = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1, /* count */
1293e5c31af7Sopenharmony_ci										 &code_gs_specialized_raw);
1294e5c31af7Sopenharmony_ci
1295e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call(s) failed.");
1296e5c31af7Sopenharmony_ci
1297e5c31af7Sopenharmony_ci	gl.getProgramiv(m_fs_po_id, GL_LINK_STATUS, &link_status);
1298e5c31af7Sopenharmony_ci
1299e5c31af7Sopenharmony_ci	if (link_status != GL_TRUE)
1300e5c31af7Sopenharmony_ci	{
1301e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Minimal fragment shader program failed to link."
1302e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
1303e5c31af7Sopenharmony_ci
1304e5c31af7Sopenharmony_ci		result = false;
1305e5c31af7Sopenharmony_ci		goto end;
1306e5c31af7Sopenharmony_ci	}
1307e5c31af7Sopenharmony_ci
1308e5c31af7Sopenharmony_ci	gl.getProgramiv(m_gs_po_id, GL_LINK_STATUS, &link_status);
1309e5c31af7Sopenharmony_ci
1310e5c31af7Sopenharmony_ci	if (link_status != GL_TRUE)
1311e5c31af7Sopenharmony_ci	{
1312e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Minimal geometry shader program failed to link."
1313e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
1314e5c31af7Sopenharmony_ci
1315e5c31af7Sopenharmony_ci		result = false;
1316e5c31af7Sopenharmony_ci		goto end;
1317e5c31af7Sopenharmony_ci	}
1318e5c31af7Sopenharmony_ci
1319e5c31af7Sopenharmony_ci	/* Create & set up a pipeline object */
1320e5c31af7Sopenharmony_ci	gl.genProgramPipelines(1, &m_pipeline_object_id);
1321e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
1322e5c31af7Sopenharmony_ci
1323e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_object_id, GL_FRAGMENT_SHADER_BIT, m_fs_po_id);
1324e5c31af7Sopenharmony_ci	gl.useProgramStages(m_pipeline_object_id, GL_GEOMETRY_SHADER_BIT, m_gs_po_id);
1325e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed.");
1326e5c31af7Sopenharmony_ci
1327e5c31af7Sopenharmony_ci	gl.bindProgramPipeline(m_pipeline_object_id);
1328e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
1329e5c31af7Sopenharmony_ci
1330e5c31af7Sopenharmony_ci	/* Try to do a draw call */
1331e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0, /* first */
1332e5c31af7Sopenharmony_ci				  1);			/* count */
1333e5c31af7Sopenharmony_ci
1334e5c31af7Sopenharmony_ci	error_code = gl.getError();
1335e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_OPERATION)
1336e5c31af7Sopenharmony_ci	{
1337e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid draw call generated an error code [" << error_code
1338e5c31af7Sopenharmony_ci						   << "]"
1339e5c31af7Sopenharmony_ci							  " which is different from the expected GL_INVALID_OPERATION."
1340e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
1341e5c31af7Sopenharmony_ci
1342e5c31af7Sopenharmony_ci		result = false;
1343e5c31af7Sopenharmony_ci	}
1344e5c31af7Sopenharmony_ci
1345e5c31af7Sopenharmony_ciend:
1346e5c31af7Sopenharmony_ci	// m_pipeline_object_id is generated in this function, need to be freed
1347e5c31af7Sopenharmony_ci	if (m_pipeline_object_id)
1348e5c31af7Sopenharmony_ci	{
1349e5c31af7Sopenharmony_ci		gl.deleteProgramPipelines(1, &m_pipeline_object_id);
1350e5c31af7Sopenharmony_ci		m_pipeline_object_id = 0;
1351e5c31af7Sopenharmony_ci	}
1352e5c31af7Sopenharmony_ci
1353e5c31af7Sopenharmony_ci	// m_gs_po_id is generated in this function, need to be freed
1354e5c31af7Sopenharmony_ci	if (m_gs_po_id)
1355e5c31af7Sopenharmony_ci	{
1356e5c31af7Sopenharmony_ci		gl.deleteProgram(m_gs_po_id);
1357e5c31af7Sopenharmony_ci		m_gs_po_id = 0;
1358e5c31af7Sopenharmony_ci	}
1359e5c31af7Sopenharmony_ci
1360e5c31af7Sopenharmony_ci	// m_fs_po_id is generated in this function, need to be freed
1361e5c31af7Sopenharmony_ci	if (m_fs_po_id)
1362e5c31af7Sopenharmony_ci	{
1363e5c31af7Sopenharmony_ci		gl.deleteProgram(m_fs_po_id);
1364e5c31af7Sopenharmony_ci		m_fs_po_id = 0;
1365e5c31af7Sopenharmony_ci	}
1366e5c31af7Sopenharmony_ci
1367e5c31af7Sopenharmony_ci	// m_vao_id is generated in this function, need to be freed
1368e5c31af7Sopenharmony_ci	if (m_vao_id)
1369e5c31af7Sopenharmony_ci	{
1370e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
1371e5c31af7Sopenharmony_ci		m_vao_id = 0;
1372e5c31af7Sopenharmony_ci	}
1373e5c31af7Sopenharmony_ci
1374e5c31af7Sopenharmony_ci	/* All done */
1375e5c31af7Sopenharmony_ci	if (result)
1376e5c31af7Sopenharmony_ci	{
1377e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1378e5c31af7Sopenharmony_ci	}
1379e5c31af7Sopenharmony_ci	else
1380e5c31af7Sopenharmony_ci	{
1381e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1382e5c31af7Sopenharmony_ci	}
1383e5c31af7Sopenharmony_ci
1384e5c31af7Sopenharmony_ci	return STOP;
1385e5c31af7Sopenharmony_ci}
1386e5c31af7Sopenharmony_ci
1387e5c31af7Sopenharmony_ci/** Constructor
1388e5c31af7Sopenharmony_ci *
1389e5c31af7Sopenharmony_ci * @param context       Test context
1390e5c31af7Sopenharmony_ci * @param extParams     Not used.
1391e5c31af7Sopenharmony_ci * @param name          Test case's name
1392e5c31af7Sopenharmony_ci * @param description   Test case's description
1393e5c31af7Sopenharmony_ci **/
1394e5c31af7Sopenharmony_ciGeometryShaderMaxImageUniformsTest::GeometryShaderMaxImageUniformsTest(Context& context, const ExtParameters& extParams,
1395e5c31af7Sopenharmony_ci																	   const char* name, const char* description)
1396e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
1397e5c31af7Sopenharmony_ci	, m_fs_id(0)
1398e5c31af7Sopenharmony_ci	, m_gl_max_geometry_image_uniforms_ext_value(0)
1399e5c31af7Sopenharmony_ci	, m_gs_id(0)
1400e5c31af7Sopenharmony_ci	, m_po_id(0)
1401e5c31af7Sopenharmony_ci	, m_texture_ids(NULL)
1402e5c31af7Sopenharmony_ci	, m_tfbo_id(0)
1403e5c31af7Sopenharmony_ci	, m_vao_id(0)
1404e5c31af7Sopenharmony_ci	, m_vs_id(0)
1405e5c31af7Sopenharmony_ci{
1406e5c31af7Sopenharmony_ci	//Bug-15063 Only GLSL 4.50 supports opaque types
1407e5c31af7Sopenharmony_ci	if (m_glslVersion >= glu::GLSL_VERSION_130)
1408e5c31af7Sopenharmony_ci	{
1409e5c31af7Sopenharmony_ci		m_glslVersion = glu::GLSL_VERSION_450;
1410e5c31af7Sopenharmony_ci	}
1411e5c31af7Sopenharmony_ci}
1412e5c31af7Sopenharmony_ci
1413e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
1414e5c31af7Sopenharmony_civoid GeometryShaderMaxImageUniformsTest::deinit()
1415e5c31af7Sopenharmony_ci{
1416e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1417e5c31af7Sopenharmony_ci
1418e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
1419e5c31af7Sopenharmony_ci	{
1420e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
1421e5c31af7Sopenharmony_ci
1422e5c31af7Sopenharmony_ci		m_fs_id = 0;
1423e5c31af7Sopenharmony_ci	}
1424e5c31af7Sopenharmony_ci
1425e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
1426e5c31af7Sopenharmony_ci	{
1427e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
1428e5c31af7Sopenharmony_ci
1429e5c31af7Sopenharmony_ci		m_gs_id = 0;
1430e5c31af7Sopenharmony_ci	}
1431e5c31af7Sopenharmony_ci
1432e5c31af7Sopenharmony_ci	if (m_po_id != 0)
1433e5c31af7Sopenharmony_ci	{
1434e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
1435e5c31af7Sopenharmony_ci
1436e5c31af7Sopenharmony_ci		m_po_id = 0;
1437e5c31af7Sopenharmony_ci	}
1438e5c31af7Sopenharmony_ci
1439e5c31af7Sopenharmony_ci	if (m_texture_ids != NULL)
1440e5c31af7Sopenharmony_ci	{
1441e5c31af7Sopenharmony_ci		gl.deleteTextures(m_gl_max_geometry_image_uniforms_ext_value, m_texture_ids);
1442e5c31af7Sopenharmony_ci
1443e5c31af7Sopenharmony_ci		delete[] m_texture_ids;
1444e5c31af7Sopenharmony_ci		m_texture_ids = NULL;
1445e5c31af7Sopenharmony_ci	}
1446e5c31af7Sopenharmony_ci
1447e5c31af7Sopenharmony_ci	if (m_tfbo_id != 0)
1448e5c31af7Sopenharmony_ci	{
1449e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_tfbo_id);
1450e5c31af7Sopenharmony_ci		m_tfbo_id = 0;
1451e5c31af7Sopenharmony_ci	}
1452e5c31af7Sopenharmony_ci
1453e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
1454e5c31af7Sopenharmony_ci	{
1455e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
1456e5c31af7Sopenharmony_ci		m_vao_id = 0;
1457e5c31af7Sopenharmony_ci	}
1458e5c31af7Sopenharmony_ci
1459e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
1460e5c31af7Sopenharmony_ci	{
1461e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
1462e5c31af7Sopenharmony_ci
1463e5c31af7Sopenharmony_ci		m_vs_id = 0;
1464e5c31af7Sopenharmony_ci	}
1465e5c31af7Sopenharmony_ci
1466e5c31af7Sopenharmony_ci	/* Set GL_PACK_ALIGNMENT to default value. */
1467e5c31af7Sopenharmony_ci	gl.pixelStorei(GL_PACK_ALIGNMENT, 4 /*default value taken from specification*/);
1468e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed for GL_PACK_ALIGNMENT pname.");
1469e5c31af7Sopenharmony_ci
1470e5c31af7Sopenharmony_ci	/* Release base class */
1471e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
1472e5c31af7Sopenharmony_ci}
1473e5c31af7Sopenharmony_ci
1474e5c31af7Sopenharmony_ci/* Retrieves test-specific geometry shader source code.
1475e5c31af7Sopenharmony_ci *
1476e5c31af7Sopenharmony_ci * @return Requested string.
1477e5c31af7Sopenharmony_ci */
1478e5c31af7Sopenharmony_cistd::string GeometryShaderMaxImageUniformsTest::getGSCode()
1479e5c31af7Sopenharmony_ci{
1480e5c31af7Sopenharmony_ci	std::stringstream code_sstream;
1481e5c31af7Sopenharmony_ci
1482e5c31af7Sopenharmony_ci	/* Form the GS */
1483e5c31af7Sopenharmony_ci	code_sstream << "${VERSION}\n"
1484e5c31af7Sopenharmony_ci					"${GEOMETRY_SHADER_REQUIRE}\n"
1485e5c31af7Sopenharmony_ci					"\n"
1486e5c31af7Sopenharmony_ci					"layout (points)                   in;\n"
1487e5c31af7Sopenharmony_ci					"layout (points, max_vertices = 1) out;\n"
1488e5c31af7Sopenharmony_ci					"\n"
1489e5c31af7Sopenharmony_ci					"precision highp iimage2D;\n"
1490e5c31af7Sopenharmony_ci					"\n"
1491e5c31af7Sopenharmony_ci					"ivec4 counter = ivec4(0);\n"
1492e5c31af7Sopenharmony_ci					"\n";
1493e5c31af7Sopenharmony_ci
1494e5c31af7Sopenharmony_ci	for (glw::GLint n_img = 0; n_img < (m_gl_max_geometry_image_uniforms_ext_value); ++n_img)
1495e5c31af7Sopenharmony_ci	{
1496e5c31af7Sopenharmony_ci		code_sstream << "layout(binding = " << n_img << ", r32i) uniform iimage2D img" << n_img << ";\n";
1497e5c31af7Sopenharmony_ci	}
1498e5c31af7Sopenharmony_ci
1499e5c31af7Sopenharmony_ci	code_sstream << "\n"
1500e5c31af7Sopenharmony_ci					"void main()\n"
1501e5c31af7Sopenharmony_ci					"{\n";
1502e5c31af7Sopenharmony_ci
1503e5c31af7Sopenharmony_ci	for (glw::GLint n_img = 0; n_img < (m_gl_max_geometry_image_uniforms_ext_value); ++n_img)
1504e5c31af7Sopenharmony_ci	{
1505e5c31af7Sopenharmony_ci		code_sstream << "    counter += imageLoad(img" << n_img << ", ivec2(0, 0));\n";
1506e5c31af7Sopenharmony_ci	}
1507e5c31af7Sopenharmony_ci
1508e5c31af7Sopenharmony_ci	code_sstream << "\n"
1509e5c31af7Sopenharmony_ci					"    gl_Position = vec4(float(counter.x), 0.0, 0.0, 1.0);\n"
1510e5c31af7Sopenharmony_ci					"    EmitVertex();\n"
1511e5c31af7Sopenharmony_ci					"}\n";
1512e5c31af7Sopenharmony_ci
1513e5c31af7Sopenharmony_ci	/* Form a specialized version of the GS source code */
1514e5c31af7Sopenharmony_ci	std::string gs_code				= code_sstream.str();
1515e5c31af7Sopenharmony_ci	const char* gs_code_raw			= gs_code.c_str();
1516e5c31af7Sopenharmony_ci	std::string gs_code_specialized = specializeShader(1 /* parts */, &gs_code_raw);
1517e5c31af7Sopenharmony_ci
1518e5c31af7Sopenharmony_ci	return gs_code_specialized;
1519e5c31af7Sopenharmony_ci}
1520e5c31af7Sopenharmony_ci
1521e5c31af7Sopenharmony_ci/** Executes the test.
1522e5c31af7Sopenharmony_ci *
1523e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1524e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
1525e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
1526e5c31af7Sopenharmony_ci **/
1527e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderMaxImageUniformsTest::iterate()
1528e5c31af7Sopenharmony_ci{
1529e5c31af7Sopenharmony_ci	glw::GLint		   counter						 = 0;
1530e5c31af7Sopenharmony_ci	glw::GLint		   expectedValue				 = 0;
1531e5c31af7Sopenharmony_ci	bool			   has_shader_compilation_failed = true;
1532e5c31af7Sopenharmony_ci	glw::GLfloat*	  ptr							 = DE_NULL;
1533e5c31af7Sopenharmony_ci	bool			   result						 = true;
1534e5c31af7Sopenharmony_ci	const glw::GLchar* feedbackVaryings[]			 = { "gl_Position" };
1535e5c31af7Sopenharmony_ci
1536e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= "";
1537e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = DE_NULL;
1538e5c31af7Sopenharmony_ci	std::string gs_code_specialized		= "";
1539e5c31af7Sopenharmony_ci	const char* gs_code_specialized_raw = DE_NULL;
1540e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= "";
1541e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = DE_NULL;
1542e5c31af7Sopenharmony_ci
1543e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
1544e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
1545e5c31af7Sopenharmony_ci	{
1546e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
1547e5c31af7Sopenharmony_ci	}
1548e5c31af7Sopenharmony_ci
1549e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1550e5c31af7Sopenharmony_ci
1551e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT pname value */
1552e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_IMAGE_UNIFORMS, &m_gl_max_geometry_image_uniforms_ext_value);
1553e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT pname");
1554e5c31af7Sopenharmony_ci
1555e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT pname value */
1556e5c31af7Sopenharmony_ci	glw::GLint m_gl_max_geometry_texture_image_units_ext_value = 0;
1557e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &m_gl_max_geometry_texture_image_units_ext_value);
1558e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT pname");
1559e5c31af7Sopenharmony_ci
1560e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_IMAGE_UNITS pname value */
1561e5c31af7Sopenharmony_ci	glw::GLint m_gl_max_image_units_value = 0;
1562e5c31af7Sopenharmony_ci	gl.getIntegerv(GL_MAX_IMAGE_UNITS, &m_gl_max_image_units_value);
1563e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_IMAGE_UNITS pname");
1564e5c31af7Sopenharmony_ci
1565e5c31af7Sopenharmony_ci	/* Check if m_gl_max_geometry_image_uniforms_value is less than or equal zero. */
1566e5c31af7Sopenharmony_ci	if (m_gl_max_geometry_image_uniforms_ext_value <= 0)
1567e5c31af7Sopenharmony_ci	{
1568e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT query value "
1569e5c31af7Sopenharmony_ci						   << "[" << m_gl_max_geometry_image_uniforms_ext_value
1570e5c31af7Sopenharmony_ci						   << "]"
1571e5c31af7Sopenharmony_ci							  " is less than or equal zero. Image uniforms in Geometry Shader"
1572e5c31af7Sopenharmony_ci							  " are not supported."
1573e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
1574e5c31af7Sopenharmony_ci
1575e5c31af7Sopenharmony_ci		if (m_gl_max_geometry_image_uniforms_ext_value == 0)
1576e5c31af7Sopenharmony_ci		{
1577e5c31af7Sopenharmony_ci			throw tcu::NotSupportedError("GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT is 0");
1578e5c31af7Sopenharmony_ci		}
1579e5c31af7Sopenharmony_ci		else
1580e5c31af7Sopenharmony_ci		{
1581e5c31af7Sopenharmony_ci			result = false;
1582e5c31af7Sopenharmony_ci			goto end;
1583e5c31af7Sopenharmony_ci		}
1584e5c31af7Sopenharmony_ci	}
1585e5c31af7Sopenharmony_ci
1586e5c31af7Sopenharmony_ci	/* Check if m_gl_max_image_units_value is less than m_gl_max_geometry_image_uniforms_value. */
1587e5c31af7Sopenharmony_ci	if (m_gl_max_image_units_value < m_gl_max_geometry_image_uniforms_ext_value)
1588e5c31af7Sopenharmony_ci	{
1589e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT query value "
1590e5c31af7Sopenharmony_ci						   << "[" << m_gl_max_geometry_image_uniforms_ext_value
1591e5c31af7Sopenharmony_ci						   << "]"
1592e5c31af7Sopenharmony_ci							  " is greater than GL_MAX_IMAGE_UNITS query value "
1593e5c31af7Sopenharmony_ci							  "["
1594e5c31af7Sopenharmony_ci						   << m_gl_max_image_units_value << "]." << tcu::TestLog::EndMessage;
1595e5c31af7Sopenharmony_ci
1596e5c31af7Sopenharmony_ci		result = false;
1597e5c31af7Sopenharmony_ci		goto end;
1598e5c31af7Sopenharmony_ci	}
1599e5c31af7Sopenharmony_ci
1600e5c31af7Sopenharmony_ci	/* Create a program object. */
1601e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
1602e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
1603e5c31af7Sopenharmony_ci
1604e5c31af7Sopenharmony_ci	/* Create shader objects. */
1605e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
1606e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
1607e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1608e5c31af7Sopenharmony_ci
1609e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
1610e5c31af7Sopenharmony_ci
1611e5c31af7Sopenharmony_ci	/* Configure which outputs should be captured by Transform Feedback. */
1612e5c31af7Sopenharmony_ci	gl.transformFeedbackVaryings(m_po_id, 1 /* varyings count */, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);
1613e5c31af7Sopenharmony_ci
1614e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
1615e5c31af7Sopenharmony_ci
1616e5c31af7Sopenharmony_ci	/* Try to link the test program object */
1617e5c31af7Sopenharmony_ci	fs_code_specialized		= specializeShader(1, &minimal_fs_code);
1618e5c31af7Sopenharmony_ci	fs_code_specialized_raw = fs_code_specialized.c_str();
1619e5c31af7Sopenharmony_ci
1620e5c31af7Sopenharmony_ci	gs_code_specialized		= getGSCode();
1621e5c31af7Sopenharmony_ci	gs_code_specialized_raw = gs_code_specialized.c_str();
1622e5c31af7Sopenharmony_ci
1623e5c31af7Sopenharmony_ci	vs_code_specialized		= specializeShader(1, &minimal_vs_code);
1624e5c31af7Sopenharmony_ci	vs_code_specialized_raw = vs_code_specialized.c_str();
1625e5c31af7Sopenharmony_ci
1626e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_po_id, m_gs_id, 1,				  /* n_sh1_body_parts */
1627e5c31af7Sopenharmony_ci									&gs_code_specialized_raw, m_vs_id, 1, /* n_sh2_body_parts */
1628e5c31af7Sopenharmony_ci									&vs_code_specialized_raw, m_fs_id, 1, /* n_sh3_body_parts */
1629e5c31af7Sopenharmony_ci									&fs_code_specialized_raw, &has_shader_compilation_failed))
1630e5c31af7Sopenharmony_ci	{
1631e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed." << tcu::TestLog::EndMessage;
1632e5c31af7Sopenharmony_ci
1633e5c31af7Sopenharmony_ci		result = false;
1634e5c31af7Sopenharmony_ci		goto end;
1635e5c31af7Sopenharmony_ci	}
1636e5c31af7Sopenharmony_ci
1637e5c31af7Sopenharmony_ci	/* Use program. */
1638e5c31af7Sopenharmony_ci	gl.useProgram(m_po_id);
1639e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
1640e5c31af7Sopenharmony_ci
1641e5c31af7Sopenharmony_ci	/* Allocate memory for m_max_image_units_value Texture Objects. */
1642e5c31af7Sopenharmony_ci	m_texture_ids = new glw::GLuint[m_gl_max_geometry_image_uniforms_ext_value];
1643e5c31af7Sopenharmony_ci
1644e5c31af7Sopenharmony_ci	/* Generate m_max_image_units_value Texture Objects. */
1645e5c31af7Sopenharmony_ci	gl.genTextures(m_gl_max_geometry_image_uniforms_ext_value, m_texture_ids);
1646e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
1647e5c31af7Sopenharmony_ci
1648e5c31af7Sopenharmony_ci	/* Set GL_PACK_ALIGNMENT to 1. */
1649e5c31af7Sopenharmony_ci	gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
1650e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed for GL_PACK_ALIGNMENT pname.");
1651e5c31af7Sopenharmony_ci
1652e5c31af7Sopenharmony_ci	/* Bind integer 2D texture objects of resolution 1x1 to image units. */
1653e5c31af7Sopenharmony_ci	for (glw::GLint n_img = 0; n_img < (m_gl_max_geometry_image_uniforms_ext_value); ++n_img)
1654e5c31af7Sopenharmony_ci	{
1655e5c31af7Sopenharmony_ci		glw::GLint texture = m_texture_ids[n_img];
1656e5c31af7Sopenharmony_ci		glw::GLint value   = n_img + 1;
1657e5c31af7Sopenharmony_ci
1658e5c31af7Sopenharmony_ci		gl.bindTexture(GL_TEXTURE_2D, texture);
1659e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
1660e5c31af7Sopenharmony_ci
1661e5c31af7Sopenharmony_ci		gl.texStorage2D(GL_TEXTURE_2D, 1 /*levels*/, GL_R32I, 1 /*width*/, 1 /*height*/);
1662e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
1663e5c31af7Sopenharmony_ci
1664e5c31af7Sopenharmony_ci		gl.texSubImage2D(GL_TEXTURE_2D, 0 /*level*/, 0 /*xoffset*/, 0 /*yoffset*/, 1 /*width*/, 1 /*height*/,
1665e5c31af7Sopenharmony_ci						 GL_RED_INTEGER, GL_INT, &value);
1666e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage2D() call failed.");
1667e5c31af7Sopenharmony_ci
1668e5c31af7Sopenharmony_ci		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1669e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri() call failed.");
1670e5c31af7Sopenharmony_ci
1671e5c31af7Sopenharmony_ci		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1672e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri() call failed.");
1673e5c31af7Sopenharmony_ci
1674e5c31af7Sopenharmony_ci		gl.bindImageTexture(n_img, texture, 0 /*level*/, GL_FALSE /*is layered?*/, 0 /*layer*/, GL_READ_ONLY, GL_R32I);
1675e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture() call failed.");
1676e5c31af7Sopenharmony_ci	}
1677e5c31af7Sopenharmony_ci
1678e5c31af7Sopenharmony_ci	/* Configure VAO. */
1679e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
1680e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
1681e5c31af7Sopenharmony_ci
1682e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
1683e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
1684e5c31af7Sopenharmony_ci
1685e5c31af7Sopenharmony_ci	/* Create a Buffer Object for Transform Feedback's outputs. */
1686e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_tfbo_id);
1687e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
1688e5c31af7Sopenharmony_ci
1689e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id);
1690e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
1691e5c31af7Sopenharmony_ci
1692e5c31af7Sopenharmony_ci	gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * 4 /* four float vector components */, NULL, GL_STATIC_READ);
1693e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
1694e5c31af7Sopenharmony_ci
1695e5c31af7Sopenharmony_ci	/* Bind Buffer Object m_tfbo_id to GL_TRANSFORM_FEEDBACK_BUFFER binding point. */
1696e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_tfbo_id);
1697e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
1698e5c31af7Sopenharmony_ci
1699e5c31af7Sopenharmony_ci	/* Disable rasterization and make a draw call. After that, turn on rasterization. */
1700e5c31af7Sopenharmony_ci	gl.enable(GL_RASTERIZER_DISCARD);
1701e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call failed for GL_RASTERIZER_DISCARD pname.");
1702e5c31af7Sopenharmony_ci
1703e5c31af7Sopenharmony_ci	gl.beginTransformFeedback(GL_POINTS);
1704e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
1705e5c31af7Sopenharmony_ci
1706e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0 /*starting index*/, 1 /*number of indices*/);
1707e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname.");
1708e5c31af7Sopenharmony_ci
1709e5c31af7Sopenharmony_ci	gl.endTransformFeedback();
1710e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
1711e5c31af7Sopenharmony_ci
1712e5c31af7Sopenharmony_ci	gl.disable(GL_RASTERIZER_DISCARD);
1713e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call failed for GL_RASTERIZER_DISCARD pname.");
1714e5c31af7Sopenharmony_ci
1715e5c31af7Sopenharmony_ci	/* Retrieve value from Transform Feedback. */
1716e5c31af7Sopenharmony_ci	counter = 0;
1717e5c31af7Sopenharmony_ci	ptr		= (glw::GLfloat*)gl.mapBufferRange(
1718e5c31af7Sopenharmony_ci		GL_ARRAY_BUFFER, 0, sizeof(glw::GLfloat) * 4 /* four float vector components */, GL_MAP_READ_BIT);
1719e5c31af7Sopenharmony_ci
1720e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
1721e5c31af7Sopenharmony_ci
1722e5c31af7Sopenharmony_ci	counter = int(ptr[0] + 0.5f);
1723e5c31af7Sopenharmony_ci
1724e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_ARRAY_BUFFER);
1725e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
1726e5c31af7Sopenharmony_ci
1727e5c31af7Sopenharmony_ci	/* Calculate expected value. */
1728e5c31af7Sopenharmony_ci	expectedValue = m_gl_max_geometry_image_uniforms_ext_value * (m_gl_max_geometry_image_uniforms_ext_value + 1) / 2;
1729e5c31af7Sopenharmony_ci
1730e5c31af7Sopenharmony_ci	if (counter != expectedValue)
1731e5c31af7Sopenharmony_ci	{
1732e5c31af7Sopenharmony_ci		result = false;
1733e5c31af7Sopenharmony_ci	}
1734e5c31af7Sopenharmony_ci
1735e5c31af7Sopenharmony_ciend:
1736e5c31af7Sopenharmony_ci	if (result)
1737e5c31af7Sopenharmony_ci	{
1738e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1739e5c31af7Sopenharmony_ci	}
1740e5c31af7Sopenharmony_ci	else
1741e5c31af7Sopenharmony_ci	{
1742e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1743e5c31af7Sopenharmony_ci	}
1744e5c31af7Sopenharmony_ci
1745e5c31af7Sopenharmony_ci	return STOP;
1746e5c31af7Sopenharmony_ci}
1747e5c31af7Sopenharmony_ci
1748e5c31af7Sopenharmony_ci/** Constructor
1749e5c31af7Sopenharmony_ci *
1750e5c31af7Sopenharmony_ci * @param context       Test context
1751e5c31af7Sopenharmony_ci * @param extParams     Not used.
1752e5c31af7Sopenharmony_ci * @param name          Test case's name
1753e5c31af7Sopenharmony_ci * @param description   Test case's description
1754e5c31af7Sopenharmony_ci **/
1755e5c31af7Sopenharmony_ciGeometryShaderMaxShaderStorageBlocksTest::GeometryShaderMaxShaderStorageBlocksTest(Context&				context,
1756e5c31af7Sopenharmony_ci																				   const ExtParameters& extParams,
1757e5c31af7Sopenharmony_ci																				   const char*			name,
1758e5c31af7Sopenharmony_ci																				   const char*			description)
1759e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
1760e5c31af7Sopenharmony_ci	, m_fs_id(0)
1761e5c31af7Sopenharmony_ci	, m_gl_max_geometry_shader_storage_blocks_ext_value(0)
1762e5c31af7Sopenharmony_ci	, m_gs_id(0)
1763e5c31af7Sopenharmony_ci	, m_po_id(0)
1764e5c31af7Sopenharmony_ci	, m_ssbo_id(0)
1765e5c31af7Sopenharmony_ci	, m_tfbo_id(0)
1766e5c31af7Sopenharmony_ci	, m_vao_id(0)
1767e5c31af7Sopenharmony_ci	, m_vs_id(0)
1768e5c31af7Sopenharmony_ci{
1769e5c31af7Sopenharmony_ci}
1770e5c31af7Sopenharmony_ci
1771e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
1772e5c31af7Sopenharmony_civoid GeometryShaderMaxShaderStorageBlocksTest::deinit()
1773e5c31af7Sopenharmony_ci{
1774e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1775e5c31af7Sopenharmony_ci
1776e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
1777e5c31af7Sopenharmony_ci	{
1778e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
1779e5c31af7Sopenharmony_ci		m_fs_id = 0;
1780e5c31af7Sopenharmony_ci	}
1781e5c31af7Sopenharmony_ci
1782e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
1783e5c31af7Sopenharmony_ci	{
1784e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
1785e5c31af7Sopenharmony_ci		m_gs_id = 0;
1786e5c31af7Sopenharmony_ci	}
1787e5c31af7Sopenharmony_ci
1788e5c31af7Sopenharmony_ci	if (m_po_id != 0)
1789e5c31af7Sopenharmony_ci	{
1790e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
1791e5c31af7Sopenharmony_ci		m_po_id = 0;
1792e5c31af7Sopenharmony_ci	}
1793e5c31af7Sopenharmony_ci
1794e5c31af7Sopenharmony_ci	if (m_ssbo_id != 0)
1795e5c31af7Sopenharmony_ci	{
1796e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_ssbo_id);
1797e5c31af7Sopenharmony_ci		m_ssbo_id = 0;
1798e5c31af7Sopenharmony_ci	}
1799e5c31af7Sopenharmony_ci
1800e5c31af7Sopenharmony_ci	if (m_tfbo_id != 0)
1801e5c31af7Sopenharmony_ci	{
1802e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_tfbo_id);
1803e5c31af7Sopenharmony_ci		m_tfbo_id = 0;
1804e5c31af7Sopenharmony_ci	}
1805e5c31af7Sopenharmony_ci
1806e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
1807e5c31af7Sopenharmony_ci	{
1808e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
1809e5c31af7Sopenharmony_ci		m_vao_id = 0;
1810e5c31af7Sopenharmony_ci	}
1811e5c31af7Sopenharmony_ci
1812e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
1813e5c31af7Sopenharmony_ci	{
1814e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
1815e5c31af7Sopenharmony_ci		m_vs_id = 0;
1816e5c31af7Sopenharmony_ci	}
1817e5c31af7Sopenharmony_ci
1818e5c31af7Sopenharmony_ci	/* Release base class */
1819e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
1820e5c31af7Sopenharmony_ci}
1821e5c31af7Sopenharmony_ci
1822e5c31af7Sopenharmony_ci/* Retrieves test-specific geometry shader source code.
1823e5c31af7Sopenharmony_ci *
1824e5c31af7Sopenharmony_ci * @return Requested string.
1825e5c31af7Sopenharmony_ci */
1826e5c31af7Sopenharmony_cistd::string GeometryShaderMaxShaderStorageBlocksTest::getGSCode()
1827e5c31af7Sopenharmony_ci{
1828e5c31af7Sopenharmony_ci	std::stringstream code_sstream;
1829e5c31af7Sopenharmony_ci
1830e5c31af7Sopenharmony_ci	/* Form the GS */
1831e5c31af7Sopenharmony_ci	code_sstream << "${VERSION}\n"
1832e5c31af7Sopenharmony_ci					"${GEOMETRY_SHADER_REQUIRE}\n"
1833e5c31af7Sopenharmony_ci					"\n"
1834e5c31af7Sopenharmony_ci					"layout (points)                   in;\n"
1835e5c31af7Sopenharmony_ci					"layout (points, max_vertices = 1) out;\n"
1836e5c31af7Sopenharmony_ci					"\n"
1837e5c31af7Sopenharmony_ci					"int counter = 0;\n"
1838e5c31af7Sopenharmony_ci					"\n";
1839e5c31af7Sopenharmony_ci
1840e5c31af7Sopenharmony_ci	for (glw::GLint n_ssb = 0; n_ssb < (m_gl_max_geometry_shader_storage_blocks_ext_value); ++n_ssb)
1841e5c31af7Sopenharmony_ci	{
1842e5c31af7Sopenharmony_ci		code_sstream << "layout(binding = " << n_ssb << ") buffer ssb" << n_ssb << " \n{\n"
1843e5c31af7Sopenharmony_ci					 << "    int value;\n"
1844e5c31af7Sopenharmony_ci					 << "} S_SSB" << n_ssb << ";\n\n";
1845e5c31af7Sopenharmony_ci	}
1846e5c31af7Sopenharmony_ci
1847e5c31af7Sopenharmony_ci	code_sstream << "\n"
1848e5c31af7Sopenharmony_ci					"void main()\n"
1849e5c31af7Sopenharmony_ci					"{\n";
1850e5c31af7Sopenharmony_ci
1851e5c31af7Sopenharmony_ci	for (glw::GLint n_ssb = 0; n_ssb < (m_gl_max_geometry_shader_storage_blocks_ext_value); ++n_ssb)
1852e5c31af7Sopenharmony_ci	{
1853e5c31af7Sopenharmony_ci		code_sstream << "    counter += S_SSB" << n_ssb << ".value++;\n";
1854e5c31af7Sopenharmony_ci	}
1855e5c31af7Sopenharmony_ci
1856e5c31af7Sopenharmony_ci	code_sstream << "\n"
1857e5c31af7Sopenharmony_ci					"    gl_Position = vec4(float(counter), 0.0, 0.0, 1.0);\n"
1858e5c31af7Sopenharmony_ci					"    EmitVertex();\n"
1859e5c31af7Sopenharmony_ci					"}\n";
1860e5c31af7Sopenharmony_ci
1861e5c31af7Sopenharmony_ci	/* Form a specialized version of the GS source code */
1862e5c31af7Sopenharmony_ci	std::string gs_code				= code_sstream.str();
1863e5c31af7Sopenharmony_ci	const char* gs_code_raw			= gs_code.c_str();
1864e5c31af7Sopenharmony_ci	std::string gs_code_specialized = specializeShader(1 /* parts */, &gs_code_raw);
1865e5c31af7Sopenharmony_ci
1866e5c31af7Sopenharmony_ci	return gs_code_specialized;
1867e5c31af7Sopenharmony_ci}
1868e5c31af7Sopenharmony_ci
1869e5c31af7Sopenharmony_ci/** Executes the test.
1870e5c31af7Sopenharmony_ci *
1871e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1872e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
1873e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
1874e5c31af7Sopenharmony_ci **/
1875e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderMaxShaderStorageBlocksTest::iterate()
1876e5c31af7Sopenharmony_ci{
1877e5c31af7Sopenharmony_ci	glw::GLint		   counter						 = 0;
1878e5c31af7Sopenharmony_ci	glw::GLint		   expectedValue				 = 0;
1879e5c31af7Sopenharmony_ci	const glw::GLchar* feedbackVaryings[]			 = { "gl_Position" };
1880e5c31af7Sopenharmony_ci	bool			   has_shader_compilation_failed = true;
1881e5c31af7Sopenharmony_ci	const glw::GLfloat initial_buffer_data[4]		 = { 0.0f, 0.0f, 0.0f, 0.0f };
1882e5c31af7Sopenharmony_ci	glw::GLint		   int_alignment				 = 0;
1883e5c31af7Sopenharmony_ci	const glw::GLint   int_size						 = sizeof(glw::GLint);
1884e5c31af7Sopenharmony_ci	glw::GLint*		   ptrSSBO_data					 = DE_NULL;
1885e5c31af7Sopenharmony_ci	glw::GLfloat*	  ptrTF_data					 = DE_NULL;
1886e5c31af7Sopenharmony_ci	bool			   result						 = true;
1887e5c31af7Sopenharmony_ci	glw::GLint		   ssbo_alignment				 = 0;
1888e5c31af7Sopenharmony_ci	glw::GLint*		   ssbo_data					 = DE_NULL;
1889e5c31af7Sopenharmony_ci	glw::GLint		   ssbo_data_size				 = 0;
1890e5c31af7Sopenharmony_ci
1891e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= "";
1892e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = DE_NULL;
1893e5c31af7Sopenharmony_ci	std::string gs_code_specialized		= "";
1894e5c31af7Sopenharmony_ci	const char* gs_code_specialized_raw = DE_NULL;
1895e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= "";
1896e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = DE_NULL;
1897e5c31af7Sopenharmony_ci
1898e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
1899e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
1900e5c31af7Sopenharmony_ci	{
1901e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
1902e5c31af7Sopenharmony_ci	}
1903e5c31af7Sopenharmony_ci
1904e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1905e5c31af7Sopenharmony_ci
1906e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT pname value */
1907e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
1908e5c31af7Sopenharmony_ci				   &m_gl_max_geometry_shader_storage_blocks_ext_value);
1909e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT pname");
1910e5c31af7Sopenharmony_ci
1911e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS pname value */
1912e5c31af7Sopenharmony_ci	glw::GLint m_gl_max_shader_storage_buffer_bindings_value = 0;
1913e5c31af7Sopenharmony_ci
1914e5c31af7Sopenharmony_ci	gl.getIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &m_gl_max_shader_storage_buffer_bindings_value);
1915e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS pname");
1916e5c31af7Sopenharmony_ci
1917e5c31af7Sopenharmony_ci	/* Check if m_gl_max_shader_storage_blocks_value is less than or equal zero. */
1918e5c31af7Sopenharmony_ci	if (m_gl_max_geometry_shader_storage_blocks_ext_value <= 0)
1919e5c31af7Sopenharmony_ci	{
1920e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT query value "
1921e5c31af7Sopenharmony_ci						   << "[" << m_gl_max_geometry_shader_storage_blocks_ext_value
1922e5c31af7Sopenharmony_ci						   << "]"
1923e5c31af7Sopenharmony_ci							  " is less than or equal zero. Shader Storage Blocks"
1924e5c31af7Sopenharmony_ci							  " in Geometry Shader are not supported."
1925e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
1926e5c31af7Sopenharmony_ci
1927e5c31af7Sopenharmony_ci		if (m_gl_max_geometry_shader_storage_blocks_ext_value == 0)
1928e5c31af7Sopenharmony_ci		{
1929e5c31af7Sopenharmony_ci			throw tcu::NotSupportedError("GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT is 0");
1930e5c31af7Sopenharmony_ci		}
1931e5c31af7Sopenharmony_ci		else
1932e5c31af7Sopenharmony_ci		{
1933e5c31af7Sopenharmony_ci			result = false;
1934e5c31af7Sopenharmony_ci			goto end;
1935e5c31af7Sopenharmony_ci		}
1936e5c31af7Sopenharmony_ci	}
1937e5c31af7Sopenharmony_ci
1938e5c31af7Sopenharmony_ci	/* Check if m_gl_max_shader_storage_buffer_bindings_value is less than m_gl_max_shader_storage_blocks_value. */
1939e5c31af7Sopenharmony_ci	if (m_gl_max_shader_storage_buffer_bindings_value < m_gl_max_geometry_shader_storage_blocks_ext_value)
1940e5c31af7Sopenharmony_ci	{
1941e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT query value "
1942e5c31af7Sopenharmony_ci						   << "[" << m_gl_max_geometry_shader_storage_blocks_ext_value
1943e5c31af7Sopenharmony_ci						   << "]"
1944e5c31af7Sopenharmony_ci							  " is greater than GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS query value "
1945e5c31af7Sopenharmony_ci							  "["
1946e5c31af7Sopenharmony_ci						   << m_gl_max_shader_storage_buffer_bindings_value << "]." << tcu::TestLog::EndMessage;
1947e5c31af7Sopenharmony_ci
1948e5c31af7Sopenharmony_ci		result = false;
1949e5c31af7Sopenharmony_ci		goto end;
1950e5c31af7Sopenharmony_ci	}
1951e5c31af7Sopenharmony_ci
1952e5c31af7Sopenharmony_ci	/* Create a program object. */
1953e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
1954e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
1955e5c31af7Sopenharmony_ci
1956e5c31af7Sopenharmony_ci	/* Create shader objects. */
1957e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
1958e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
1959e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1960e5c31af7Sopenharmony_ci
1961e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
1962e5c31af7Sopenharmony_ci
1963e5c31af7Sopenharmony_ci	/* Configure which outputs should be captured by Transform Feedback. */
1964e5c31af7Sopenharmony_ci	gl.transformFeedbackVaryings(m_po_id, 1 /* varyings count */, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);
1965e5c31af7Sopenharmony_ci
1966e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
1967e5c31af7Sopenharmony_ci
1968e5c31af7Sopenharmony_ci	/* Try to link the test program object */
1969e5c31af7Sopenharmony_ci	fs_code_specialized		= specializeShader(1, &minimal_fs_code);
1970e5c31af7Sopenharmony_ci	fs_code_specialized_raw = fs_code_specialized.c_str();
1971e5c31af7Sopenharmony_ci
1972e5c31af7Sopenharmony_ci	gs_code_specialized		= getGSCode();
1973e5c31af7Sopenharmony_ci	gs_code_specialized_raw = gs_code_specialized.c_str();
1974e5c31af7Sopenharmony_ci
1975e5c31af7Sopenharmony_ci	vs_code_specialized		= specializeShader(1, &minimal_vs_code);
1976e5c31af7Sopenharmony_ci	vs_code_specialized_raw = vs_code_specialized.c_str();
1977e5c31af7Sopenharmony_ci
1978e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_po_id, m_gs_id, 1,				  /* n_sh1_body_parts */
1979e5c31af7Sopenharmony_ci									&gs_code_specialized_raw, m_vs_id, 1, /* n_sh2_body_parts */
1980e5c31af7Sopenharmony_ci									&vs_code_specialized_raw, m_fs_id, 1, /* n_sh3_body_parts */
1981e5c31af7Sopenharmony_ci									&fs_code_specialized_raw, &has_shader_compilation_failed))
1982e5c31af7Sopenharmony_ci	{
1983e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed." << tcu::TestLog::EndMessage;
1984e5c31af7Sopenharmony_ci
1985e5c31af7Sopenharmony_ci		result = false;
1986e5c31af7Sopenharmony_ci		goto end;
1987e5c31af7Sopenharmony_ci	}
1988e5c31af7Sopenharmony_ci
1989e5c31af7Sopenharmony_ci	/* Prepare data for Shader Storage Buffer Object. */
1990e5c31af7Sopenharmony_ci	gl.getIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &ssbo_alignment);
1991e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
1992e5c31af7Sopenharmony_ci
1993e5c31af7Sopenharmony_ci	int_alignment  = ssbo_alignment / int_size;
1994e5c31af7Sopenharmony_ci	ssbo_data_size = m_gl_max_geometry_shader_storage_blocks_ext_value * ssbo_alignment;
1995e5c31af7Sopenharmony_ci	ssbo_data	  = new glw::GLint[ssbo_data_size];
1996e5c31af7Sopenharmony_ci
1997e5c31af7Sopenharmony_ci	if ((ssbo_alignment % int_size) != 0)
1998e5c31af7Sopenharmony_ci	{
1999e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT query value "
2000e5c31af7Sopenharmony_ci													   "["
2001e5c31af7Sopenharmony_ci						   << ssbo_alignment << "]"
2002e5c31af7Sopenharmony_ci												"divide with remainder by the size of GLint "
2003e5c31af7Sopenharmony_ci												"["
2004e5c31af7Sopenharmony_ci						   << int_size << "]" << tcu::TestLog::EndMessage;
2005e5c31af7Sopenharmony_ci
2006e5c31af7Sopenharmony_ci		result = false;
2007e5c31af7Sopenharmony_ci		goto end;
2008e5c31af7Sopenharmony_ci	}
2009e5c31af7Sopenharmony_ci
2010e5c31af7Sopenharmony_ci	for (int i = 0; i < m_gl_max_geometry_shader_storage_blocks_ext_value; ++i)
2011e5c31af7Sopenharmony_ci	{
2012e5c31af7Sopenharmony_ci		ssbo_data[i * int_alignment] = i + 1;
2013e5c31af7Sopenharmony_ci	}
2014e5c31af7Sopenharmony_ci
2015e5c31af7Sopenharmony_ci	/* Create Shader Storage Buffer Object. */
2016e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_ssbo_id);
2017e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2018e5c31af7Sopenharmony_ci
2019e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo_id);
2020e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed for GL_SHADER_STORAGE_BUFFER pname.");
2021e5c31af7Sopenharmony_ci
2022e5c31af7Sopenharmony_ci	gl.bufferData(GL_SHADER_STORAGE_BUFFER, ssbo_data_size, ssbo_data, GL_DYNAMIC_COPY);
2023e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2024e5c31af7Sopenharmony_ci
2025e5c31af7Sopenharmony_ci	/* Free unused memory. */
2026e5c31af7Sopenharmony_ci	delete[] ssbo_data;
2027e5c31af7Sopenharmony_ci	ssbo_data = NULL;
2028e5c31af7Sopenharmony_ci
2029e5c31af7Sopenharmony_ci	/* Bind specific m_ssbo_id buffer region to a specific Shader Storage Buffer binding point. */
2030e5c31af7Sopenharmony_ci	for (glw::GLint n_ssb = 0; n_ssb < (m_gl_max_geometry_shader_storage_blocks_ext_value); ++n_ssb)
2031e5c31af7Sopenharmony_ci	{
2032e5c31af7Sopenharmony_ci		glw::GLuint offset = n_ssb * ssbo_alignment;
2033e5c31af7Sopenharmony_ci
2034e5c31af7Sopenharmony_ci		gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, n_ssb /*binding index*/, m_ssbo_id, offset, int_size);
2035e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferRange() call failed.");
2036e5c31af7Sopenharmony_ci	}
2037e5c31af7Sopenharmony_ci
2038e5c31af7Sopenharmony_ci	/* Configure VAO. */
2039e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
2040e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2041e5c31af7Sopenharmony_ci
2042e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
2043e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2044e5c31af7Sopenharmony_ci
2045e5c31af7Sopenharmony_ci	/* Create a Buffer Object for Transform Feedback's outputs. */
2046e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_tfbo_id);
2047e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2048e5c31af7Sopenharmony_ci
2049e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id);
2050e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2051e5c31af7Sopenharmony_ci
2052e5c31af7Sopenharmony_ci	gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * 4 /* four float vector components */, initial_buffer_data,
2053e5c31af7Sopenharmony_ci				  GL_STATIC_READ);
2054e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2055e5c31af7Sopenharmony_ci
2056e5c31af7Sopenharmony_ci	/* Bind Buffer Object m_tfbo_id to GL_TRANSFORM_FEEDBACK_BUFFER binding point. */
2057e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*binding index*/, m_tfbo_id);
2058e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
2059e5c31af7Sopenharmony_ci
2060e5c31af7Sopenharmony_ci	/* Use program. */
2061e5c31af7Sopenharmony_ci	gl.useProgram(m_po_id);
2062e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2063e5c31af7Sopenharmony_ci
2064e5c31af7Sopenharmony_ci	/* Disable rasterization and make a draw call. After that, turn on rasterization. */
2065e5c31af7Sopenharmony_ci	gl.enable(GL_RASTERIZER_DISCARD);
2066e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call failed for GL_RASTERIZER_DISCARD pname.");
2067e5c31af7Sopenharmony_ci
2068e5c31af7Sopenharmony_ci	gl.beginTransformFeedback(GL_POINTS);
2069e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
2070e5c31af7Sopenharmony_ci
2071e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0 /*starting index*/, 1 /*number of indices*/);
2072e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname.");
2073e5c31af7Sopenharmony_ci
2074e5c31af7Sopenharmony_ci	gl.endTransformFeedback();
2075e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
2076e5c31af7Sopenharmony_ci
2077e5c31af7Sopenharmony_ci	gl.disable(GL_RASTERIZER_DISCARD);
2078e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call failed for GL_RASTERIZER_DISCARD pname.");
2079e5c31af7Sopenharmony_ci
2080e5c31af7Sopenharmony_ci	/* Retrieve value from Transform Feedback. */
2081e5c31af7Sopenharmony_ci	ptrTF_data = (glw::GLfloat*)gl.mapBufferRange(
2082e5c31af7Sopenharmony_ci		GL_ARRAY_BUFFER, 0 /*offset*/, sizeof(glw::GLfloat) * 4 /* four float vector components */, GL_MAP_READ_BIT);
2083e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
2084e5c31af7Sopenharmony_ci
2085e5c31af7Sopenharmony_ci	counter = int(ptrTF_data[0] + 0.5f);
2086e5c31af7Sopenharmony_ci
2087e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_ARRAY_BUFFER);
2088e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
2089e5c31af7Sopenharmony_ci
2090e5c31af7Sopenharmony_ci	ptrTF_data = NULL;
2091e5c31af7Sopenharmony_ci
2092e5c31af7Sopenharmony_ci	/* Retrieve values from Shader Storage Buffer Object. */
2093e5c31af7Sopenharmony_ci	ptrSSBO_data =
2094e5c31af7Sopenharmony_ci		(glw::GLint*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0 /*offset*/, ssbo_data_size, GL_MAP_READ_BIT);
2095e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
2096e5c31af7Sopenharmony_ci
2097e5c31af7Sopenharmony_ci	for (int i = 0; i < m_gl_max_geometry_shader_storage_blocks_ext_value; ++i)
2098e5c31af7Sopenharmony_ci	{
2099e5c31af7Sopenharmony_ci		if (ptrSSBO_data[i * int_alignment] != i + 2)
2100e5c31af7Sopenharmony_ci		{
2101e5c31af7Sopenharmony_ci			result = false;
2102e5c31af7Sopenharmony_ci
2103e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "Value read from Shader Storage Buffer "
2104e5c31af7Sopenharmony_ci														   "["
2105e5c31af7Sopenharmony_ci							   << ptrSSBO_data[i * int_alignment] << "] "
2106e5c31af7Sopenharmony_ci																	 "at index "
2107e5c31af7Sopenharmony_ci																	 "["
2108e5c31af7Sopenharmony_ci							   << i * int_alignment << "]"
2109e5c31af7Sopenharmony_ci													   "is not equal to expected value "
2110e5c31af7Sopenharmony_ci													   "["
2111e5c31af7Sopenharmony_ci							   << i + 2 << "]" << tcu::TestLog::EndMessage;
2112e5c31af7Sopenharmony_ci
2113e5c31af7Sopenharmony_ci			break;
2114e5c31af7Sopenharmony_ci		}
2115e5c31af7Sopenharmony_ci	}
2116e5c31af7Sopenharmony_ci
2117e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
2118e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
2119e5c31af7Sopenharmony_ci
2120e5c31af7Sopenharmony_ci	ptrSSBO_data = NULL;
2121e5c31af7Sopenharmony_ci
2122e5c31af7Sopenharmony_ci	/* Calculate expected value. */
2123e5c31af7Sopenharmony_ci	expectedValue =
2124e5c31af7Sopenharmony_ci		m_gl_max_geometry_shader_storage_blocks_ext_value * (m_gl_max_geometry_shader_storage_blocks_ext_value + 1) / 2;
2125e5c31af7Sopenharmony_ci
2126e5c31af7Sopenharmony_ci	if (counter != expectedValue)
2127e5c31af7Sopenharmony_ci	{
2128e5c31af7Sopenharmony_ci		result = false;
2129e5c31af7Sopenharmony_ci	}
2130e5c31af7Sopenharmony_ci
2131e5c31af7Sopenharmony_ciend:
2132e5c31af7Sopenharmony_ci	if (result)
2133e5c31af7Sopenharmony_ci	{
2134e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2135e5c31af7Sopenharmony_ci	}
2136e5c31af7Sopenharmony_ci	else
2137e5c31af7Sopenharmony_ci	{
2138e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2139e5c31af7Sopenharmony_ci	}
2140e5c31af7Sopenharmony_ci
2141e5c31af7Sopenharmony_ci	return STOP;
2142e5c31af7Sopenharmony_ci}
2143e5c31af7Sopenharmony_ci
2144e5c31af7Sopenharmony_ci/** Constructor
2145e5c31af7Sopenharmony_ci *
2146e5c31af7Sopenharmony_ci * @param context       Test context
2147e5c31af7Sopenharmony_ci * @param extParams     Not used.
2148e5c31af7Sopenharmony_ci * @param name          Test case's name
2149e5c31af7Sopenharmony_ci * @param description   Test case's description
2150e5c31af7Sopenharmony_ci **/
2151e5c31af7Sopenharmony_ciGeometryShaderMaxAtomicCountersTest::GeometryShaderMaxAtomicCountersTest(Context&			  context,
2152e5c31af7Sopenharmony_ci																		 const ExtParameters& extParams,
2153e5c31af7Sopenharmony_ci																		 const char* name, const char* description)
2154e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
2155e5c31af7Sopenharmony_ci	, m_acbo_id(0)
2156e5c31af7Sopenharmony_ci	, m_fs_id(0)
2157e5c31af7Sopenharmony_ci	, m_gl_max_geometry_atomic_counters_ext_value(0)
2158e5c31af7Sopenharmony_ci	, m_gs_id(0)
2159e5c31af7Sopenharmony_ci	, m_po_id(0)
2160e5c31af7Sopenharmony_ci	, m_vao_id(0)
2161e5c31af7Sopenharmony_ci	, m_vs_id(0)
2162e5c31af7Sopenharmony_ci{
2163e5c31af7Sopenharmony_ci}
2164e5c31af7Sopenharmony_ci
2165e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
2166e5c31af7Sopenharmony_civoid GeometryShaderMaxAtomicCountersTest::deinit()
2167e5c31af7Sopenharmony_ci{
2168e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2169e5c31af7Sopenharmony_ci
2170e5c31af7Sopenharmony_ci	if (m_acbo_id != 0)
2171e5c31af7Sopenharmony_ci	{
2172e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_acbo_id);
2173e5c31af7Sopenharmony_ci		m_acbo_id = 0;
2174e5c31af7Sopenharmony_ci	}
2175e5c31af7Sopenharmony_ci
2176e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
2177e5c31af7Sopenharmony_ci	{
2178e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
2179e5c31af7Sopenharmony_ci		m_fs_id = 0;
2180e5c31af7Sopenharmony_ci	}
2181e5c31af7Sopenharmony_ci
2182e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
2183e5c31af7Sopenharmony_ci	{
2184e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
2185e5c31af7Sopenharmony_ci		m_gs_id = 0;
2186e5c31af7Sopenharmony_ci	}
2187e5c31af7Sopenharmony_ci
2188e5c31af7Sopenharmony_ci	if (m_po_id != 0)
2189e5c31af7Sopenharmony_ci	{
2190e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
2191e5c31af7Sopenharmony_ci		m_po_id = 0;
2192e5c31af7Sopenharmony_ci	}
2193e5c31af7Sopenharmony_ci
2194e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
2195e5c31af7Sopenharmony_ci	{
2196e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
2197e5c31af7Sopenharmony_ci		m_vao_id = 0;
2198e5c31af7Sopenharmony_ci	}
2199e5c31af7Sopenharmony_ci
2200e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
2201e5c31af7Sopenharmony_ci	{
2202e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
2203e5c31af7Sopenharmony_ci		m_vs_id = 0;
2204e5c31af7Sopenharmony_ci	}
2205e5c31af7Sopenharmony_ci
2206e5c31af7Sopenharmony_ci	/* Release base class */
2207e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
2208e5c31af7Sopenharmony_ci}
2209e5c31af7Sopenharmony_ci
2210e5c31af7Sopenharmony_ci/* Retrieves test-specific geometry shader source code.
2211e5c31af7Sopenharmony_ci *
2212e5c31af7Sopenharmony_ci * @return Requested string.
2213e5c31af7Sopenharmony_ci */
2214e5c31af7Sopenharmony_cistd::string GeometryShaderMaxAtomicCountersTest::getGSCode()
2215e5c31af7Sopenharmony_ci{
2216e5c31af7Sopenharmony_ci	std::stringstream code_sstream;
2217e5c31af7Sopenharmony_ci
2218e5c31af7Sopenharmony_ci	/* Form the GS */
2219e5c31af7Sopenharmony_ci	code_sstream << "${VERSION}\n"
2220e5c31af7Sopenharmony_ci					"${GEOMETRY_SHADER_REQUIRE}\n"
2221e5c31af7Sopenharmony_ci					"\n"
2222e5c31af7Sopenharmony_ci					"layout (points)                   in;\n"
2223e5c31af7Sopenharmony_ci					"layout (points, max_vertices = 1) out;\n"
2224e5c31af7Sopenharmony_ci					"\n"
2225e5c31af7Sopenharmony_ci					"uniform int n_loop_iterations;\n"
2226e5c31af7Sopenharmony_ci					"flat in int vertex_id[];\n"
2227e5c31af7Sopenharmony_ci					"\n";
2228e5c31af7Sopenharmony_ci
2229e5c31af7Sopenharmony_ci	code_sstream << "layout(binding = 0) uniform atomic_uint acs[" << m_gl_max_geometry_atomic_counters_ext_value
2230e5c31af7Sopenharmony_ci				 << "];\n"
2231e5c31af7Sopenharmony_ci				 << "\n"
2232e5c31af7Sopenharmony_ci					"void main()\n"
2233e5c31af7Sopenharmony_ci					"{\n"
2234e5c31af7Sopenharmony_ci					"    for (int counter_id = 1;\n"
2235e5c31af7Sopenharmony_ci					"             counter_id <= n_loop_iterations;\n"
2236e5c31af7Sopenharmony_ci					"           ++counter_id)\n"
2237e5c31af7Sopenharmony_ci					"    {\n"
2238e5c31af7Sopenharmony_ci					"        if ((vertex_id[0] % counter_id) == 0)\n"
2239e5c31af7Sopenharmony_ci					"        {\n"
2240e5c31af7Sopenharmony_ci					"            atomicCounterIncrement(acs[counter_id - 1]);\n"
2241e5c31af7Sopenharmony_ci					"        }\n"
2242e5c31af7Sopenharmony_ci					"    }\n"
2243e5c31af7Sopenharmony_ci					"\n"
2244e5c31af7Sopenharmony_ci					"    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
2245e5c31af7Sopenharmony_ci					"    EmitVertex();\n"
2246e5c31af7Sopenharmony_ci					"}\n";
2247e5c31af7Sopenharmony_ci
2248e5c31af7Sopenharmony_ci	/* Form a specialized version of the GS source code */
2249e5c31af7Sopenharmony_ci	std::string gs_code				= code_sstream.str();
2250e5c31af7Sopenharmony_ci	const char* gs_code_raw			= gs_code.c_str();
2251e5c31af7Sopenharmony_ci	std::string gs_code_specialized = specializeShader(1, /* parts */ &gs_code_raw);
2252e5c31af7Sopenharmony_ci
2253e5c31af7Sopenharmony_ci	return gs_code_specialized;
2254e5c31af7Sopenharmony_ci}
2255e5c31af7Sopenharmony_ci
2256e5c31af7Sopenharmony_ci/** Executes the test.
2257e5c31af7Sopenharmony_ci *
2258e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2259e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
2260e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
2261e5c31af7Sopenharmony_ci **/
2262e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderMaxAtomicCountersTest::iterate()
2263e5c31af7Sopenharmony_ci{
2264e5c31af7Sopenharmony_ci	/* Define Vertex Shader's code for the purpose of this test. */
2265e5c31af7Sopenharmony_ci	const char* vs_code = "${VERSION}\n"
2266e5c31af7Sopenharmony_ci						  "\n"
2267e5c31af7Sopenharmony_ci						  "flat out int vertex_id;\n"
2268e5c31af7Sopenharmony_ci						  "\n"
2269e5c31af7Sopenharmony_ci						  "void main()\n"
2270e5c31af7Sopenharmony_ci						  "{\n"
2271e5c31af7Sopenharmony_ci						  "    vertex_id    = gl_VertexID;\n"
2272e5c31af7Sopenharmony_ci						  "    gl_Position  = vec4(1.0, 0.0, 0.0, 1.0);\n"
2273e5c31af7Sopenharmony_ci						  "}\n";
2274e5c31af7Sopenharmony_ci
2275e5c31af7Sopenharmony_ci	bool			   has_shader_compilation_failed	  = true;
2276e5c31af7Sopenharmony_ci	glw::GLuint*	   initial_ac_data					  = DE_NULL;
2277e5c31af7Sopenharmony_ci	const unsigned int n_draw_call_vertices				  = 4;
2278e5c31af7Sopenharmony_ci	glw::GLint		   n_loop_iterations_uniform_location = -1;
2279e5c31af7Sopenharmony_ci	glw::GLuint*	   ptrACBO_data						  = DE_NULL;
2280e5c31af7Sopenharmony_ci	bool			   result							  = true;
2281e5c31af7Sopenharmony_ci
2282e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= "";
2283e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = DE_NULL;
2284e5c31af7Sopenharmony_ci	std::string gs_code_specialized		= "";
2285e5c31af7Sopenharmony_ci	const char* gs_code_specialized_raw = DE_NULL;
2286e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= "";
2287e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = DE_NULL;
2288e5c31af7Sopenharmony_ci
2289e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
2290e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
2291e5c31af7Sopenharmony_ci	{
2292e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
2293e5c31af7Sopenharmony_ci	}
2294e5c31af7Sopenharmony_ci
2295e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2296e5c31af7Sopenharmony_ci
2297e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT pname value */
2298e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_ATOMIC_COUNTERS, &m_gl_max_geometry_atomic_counters_ext_value);
2299e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT pname");
2300e5c31af7Sopenharmony_ci
2301e5c31af7Sopenharmony_ci	/* Check if m_gl_max_atomic_counters_value is less than or equal zero. */
2302e5c31af7Sopenharmony_ci	if (m_gl_max_geometry_atomic_counters_ext_value <= 0)
2303e5c31af7Sopenharmony_ci	{
2304e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT query value "
2305e5c31af7Sopenharmony_ci						   << "[" << m_gl_max_geometry_atomic_counters_ext_value
2306e5c31af7Sopenharmony_ci						   << "]"
2307e5c31af7Sopenharmony_ci							  " is less than or equal to zero. Atomic Counters"
2308e5c31af7Sopenharmony_ci							  " in Geometry Shader are not supported."
2309e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
2310e5c31af7Sopenharmony_ci
2311e5c31af7Sopenharmony_ci		if (m_gl_max_geometry_atomic_counters_ext_value == 0)
2312e5c31af7Sopenharmony_ci		{
2313e5c31af7Sopenharmony_ci			throw tcu::NotSupportedError("GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT is 0");
2314e5c31af7Sopenharmony_ci		}
2315e5c31af7Sopenharmony_ci		else
2316e5c31af7Sopenharmony_ci		{
2317e5c31af7Sopenharmony_ci			result = false;
2318e5c31af7Sopenharmony_ci			goto end;
2319e5c31af7Sopenharmony_ci		}
2320e5c31af7Sopenharmony_ci	}
2321e5c31af7Sopenharmony_ci
2322e5c31af7Sopenharmony_ci	/* Create a program object. */
2323e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
2324e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
2325e5c31af7Sopenharmony_ci
2326e5c31af7Sopenharmony_ci	/* Create shader objects. */
2327e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2328e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
2329e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
2330e5c31af7Sopenharmony_ci
2331e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
2332e5c31af7Sopenharmony_ci
2333e5c31af7Sopenharmony_ci	/* Try to link the test program object */
2334e5c31af7Sopenharmony_ci	fs_code_specialized		= specializeShader(1, &minimal_fs_code);
2335e5c31af7Sopenharmony_ci	fs_code_specialized_raw = fs_code_specialized.c_str();
2336e5c31af7Sopenharmony_ci
2337e5c31af7Sopenharmony_ci	gs_code_specialized		= getGSCode();
2338e5c31af7Sopenharmony_ci	gs_code_specialized_raw = gs_code_specialized.c_str();
2339e5c31af7Sopenharmony_ci
2340e5c31af7Sopenharmony_ci	vs_code_specialized		= specializeShader(1, &vs_code);
2341e5c31af7Sopenharmony_ci	vs_code_specialized_raw = vs_code_specialized.c_str();
2342e5c31af7Sopenharmony_ci
2343e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_po_id, m_gs_id, 1,				  /* n_sh1_body_parts */
2344e5c31af7Sopenharmony_ci									&gs_code_specialized_raw, m_vs_id, 1, /* n_sh2_body_parts */
2345e5c31af7Sopenharmony_ci									&vs_code_specialized_raw, m_fs_id, 1, /* n_sh3_body_parts */
2346e5c31af7Sopenharmony_ci									&fs_code_specialized_raw, &has_shader_compilation_failed))
2347e5c31af7Sopenharmony_ci	{
2348e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed." << tcu::TestLog::EndMessage;
2349e5c31af7Sopenharmony_ci
2350e5c31af7Sopenharmony_ci		result = false;
2351e5c31af7Sopenharmony_ci		goto end;
2352e5c31af7Sopenharmony_ci	}
2353e5c31af7Sopenharmony_ci
2354e5c31af7Sopenharmony_ci	/* Create Atomic Counter Buffer Objects. */
2355e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_acbo_id);
2356e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2357e5c31af7Sopenharmony_ci
2358e5c31af7Sopenharmony_ci	/* Prepare initial data - zeroes - to fill the Atomic Counter Buffer Object. */
2359e5c31af7Sopenharmony_ci	initial_ac_data = new glw::GLuint[m_gl_max_geometry_atomic_counters_ext_value];
2360e5c31af7Sopenharmony_ci	memset(initial_ac_data, 0, sizeof(glw::GLuint) * m_gl_max_geometry_atomic_counters_ext_value);
2361e5c31af7Sopenharmony_ci
2362e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo_id);
2363e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed for GL_SHADER_STORAGE_BUFFER pname.");
2364e5c31af7Sopenharmony_ci
2365e5c31af7Sopenharmony_ci	gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(glw::GLuint) * m_gl_max_geometry_atomic_counters_ext_value, NULL,
2366e5c31af7Sopenharmony_ci				  GL_DYNAMIC_COPY);
2367e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2368e5c31af7Sopenharmony_ci
2369e5c31af7Sopenharmony_ci	gl.bufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0 /*offset*/,
2370e5c31af7Sopenharmony_ci					 sizeof(glw::GLuint) * m_gl_max_geometry_atomic_counters_ext_value,
2371e5c31af7Sopenharmony_ci					 initial_ac_data /*initialize with zeroes*/);
2372e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
2373e5c31af7Sopenharmony_ci
2374e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0 /*binding index*/, m_acbo_id /*buffer*/);
2375e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferRange() call failed.");
2376e5c31af7Sopenharmony_ci
2377e5c31af7Sopenharmony_ci	/* Configure VAO. */
2378e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
2379e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2380e5c31af7Sopenharmony_ci
2381e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
2382e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2383e5c31af7Sopenharmony_ci
2384e5c31af7Sopenharmony_ci	/* Use program. */
2385e5c31af7Sopenharmony_ci	n_loop_iterations_uniform_location = gl.getUniformLocation(m_po_id, "n_loop_iterations");
2386e5c31af7Sopenharmony_ci
2387e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call failed.");
2388e5c31af7Sopenharmony_ci	if (n_loop_iterations_uniform_location == -1)
2389e5c31af7Sopenharmony_ci	{
2390e5c31af7Sopenharmony_ci		TCU_FAIL("n_loop_iterations uniform is considered inactive");
2391e5c31af7Sopenharmony_ci	}
2392e5c31af7Sopenharmony_ci	else
2393e5c31af7Sopenharmony_ci	{
2394e5c31af7Sopenharmony_ci		gl.useProgram(m_po_id);
2395e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2396e5c31af7Sopenharmony_ci
2397e5c31af7Sopenharmony_ci		gl.uniform1i(n_loop_iterations_uniform_location, m_gl_max_geometry_atomic_counters_ext_value);
2398e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed.");
2399e5c31af7Sopenharmony_ci	}
2400e5c31af7Sopenharmony_ci
2401e5c31af7Sopenharmony_ci	/* Issue the draw call */
2402e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0, n_draw_call_vertices);
2403e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname.");
2404e5c31af7Sopenharmony_ci
2405e5c31af7Sopenharmony_ci	/* Retrieve values from Atomic Counter Buffer Objects and check if these values are valid. */
2406e5c31af7Sopenharmony_ci	ptrACBO_data = (glw::GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0 /*offset*/,
2407e5c31af7Sopenharmony_ci												   sizeof(glw::GLuint) * m_gl_max_geometry_atomic_counters_ext_value,
2408e5c31af7Sopenharmony_ci												   GL_MAP_READ_BIT);
2409e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
2410e5c31af7Sopenharmony_ci
2411e5c31af7Sopenharmony_ci	for (glw::GLint n_ac = 0; n_ac < m_gl_max_geometry_atomic_counters_ext_value; ++n_ac)
2412e5c31af7Sopenharmony_ci	{
2413e5c31af7Sopenharmony_ci		unsigned int expected_value = 0;
2414e5c31af7Sopenharmony_ci
2415e5c31af7Sopenharmony_ci		for (unsigned int n_draw_call_vertex = 0; n_draw_call_vertex < n_draw_call_vertices; ++n_draw_call_vertex)
2416e5c31af7Sopenharmony_ci		{
2417e5c31af7Sopenharmony_ci			if ((n_draw_call_vertex % (n_ac + 1)) == 0)
2418e5c31af7Sopenharmony_ci			{
2419e5c31af7Sopenharmony_ci				++expected_value;
2420e5c31af7Sopenharmony_ci			}
2421e5c31af7Sopenharmony_ci		}
2422e5c31af7Sopenharmony_ci
2423e5c31af7Sopenharmony_ci		if (ptrACBO_data[n_ac] != expected_value)
2424e5c31af7Sopenharmony_ci		{
2425e5c31af7Sopenharmony_ci			result = false;
2426e5c31af7Sopenharmony_ci			break;
2427e5c31af7Sopenharmony_ci		}
2428e5c31af7Sopenharmony_ci	}
2429e5c31af7Sopenharmony_ci
2430e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2431e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
2432e5c31af7Sopenharmony_ci
2433e5c31af7Sopenharmony_ci	ptrACBO_data = NULL;
2434e5c31af7Sopenharmony_ci
2435e5c31af7Sopenharmony_ciend:
2436e5c31af7Sopenharmony_ci	if (result)
2437e5c31af7Sopenharmony_ci	{
2438e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2439e5c31af7Sopenharmony_ci	}
2440e5c31af7Sopenharmony_ci	else
2441e5c31af7Sopenharmony_ci	{
2442e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2443e5c31af7Sopenharmony_ci	}
2444e5c31af7Sopenharmony_ci
2445e5c31af7Sopenharmony_ci	return STOP;
2446e5c31af7Sopenharmony_ci}
2447e5c31af7Sopenharmony_ci
2448e5c31af7Sopenharmony_ci/** Constructor
2449e5c31af7Sopenharmony_ci *
2450e5c31af7Sopenharmony_ci * @param context       Test context
2451e5c31af7Sopenharmony_ci * @param extParams     Not used.
2452e5c31af7Sopenharmony_ci * @param name          Test case's name
2453e5c31af7Sopenharmony_ci * @param description   Test case's description
2454e5c31af7Sopenharmony_ci **/
2455e5c31af7Sopenharmony_ciGeometryShaderMaxAtomicCounterBuffersTest::GeometryShaderMaxAtomicCounterBuffersTest(Context&			  context,
2456e5c31af7Sopenharmony_ci																					 const ExtParameters& extParams,
2457e5c31af7Sopenharmony_ci																					 const char*		  name,
2458e5c31af7Sopenharmony_ci																					 const char*		  description)
2459e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
2460e5c31af7Sopenharmony_ci	, m_acbo_ids(NULL)
2461e5c31af7Sopenharmony_ci	, m_fs_id(0)
2462e5c31af7Sopenharmony_ci	, m_gl_max_atomic_counter_buffer_bindings_value(0)
2463e5c31af7Sopenharmony_ci	, m_gl_max_geometry_atomic_counter_buffers_ext_value(0)
2464e5c31af7Sopenharmony_ci	, m_gs_id(0)
2465e5c31af7Sopenharmony_ci	, m_po_id(0)
2466e5c31af7Sopenharmony_ci	, m_vao_id(0)
2467e5c31af7Sopenharmony_ci	, m_vs_id(0)
2468e5c31af7Sopenharmony_ci{
2469e5c31af7Sopenharmony_ci}
2470e5c31af7Sopenharmony_ci
2471e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
2472e5c31af7Sopenharmony_civoid GeometryShaderMaxAtomicCounterBuffersTest::deinit()
2473e5c31af7Sopenharmony_ci{
2474e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2475e5c31af7Sopenharmony_ci
2476e5c31af7Sopenharmony_ci	if (m_acbo_ids != NULL)
2477e5c31af7Sopenharmony_ci	{
2478e5c31af7Sopenharmony_ci		if (m_gl_max_geometry_atomic_counter_buffers_ext_value > 0)
2479e5c31af7Sopenharmony_ci		{
2480e5c31af7Sopenharmony_ci			gl.deleteBuffers(m_gl_max_geometry_atomic_counter_buffers_ext_value, m_acbo_ids);
2481e5c31af7Sopenharmony_ci
2482e5c31af7Sopenharmony_ci			delete[] m_acbo_ids;
2483e5c31af7Sopenharmony_ci			m_acbo_ids = NULL;
2484e5c31af7Sopenharmony_ci		}
2485e5c31af7Sopenharmony_ci	}
2486e5c31af7Sopenharmony_ci
2487e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
2488e5c31af7Sopenharmony_ci	{
2489e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
2490e5c31af7Sopenharmony_ci		m_fs_id = 0;
2491e5c31af7Sopenharmony_ci	}
2492e5c31af7Sopenharmony_ci
2493e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
2494e5c31af7Sopenharmony_ci	{
2495e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
2496e5c31af7Sopenharmony_ci		m_gs_id = 0;
2497e5c31af7Sopenharmony_ci	}
2498e5c31af7Sopenharmony_ci
2499e5c31af7Sopenharmony_ci	if (m_po_id != 0)
2500e5c31af7Sopenharmony_ci	{
2501e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
2502e5c31af7Sopenharmony_ci		m_po_id = 0;
2503e5c31af7Sopenharmony_ci	}
2504e5c31af7Sopenharmony_ci
2505e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
2506e5c31af7Sopenharmony_ci	{
2507e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
2508e5c31af7Sopenharmony_ci		m_vao_id = 0;
2509e5c31af7Sopenharmony_ci	}
2510e5c31af7Sopenharmony_ci
2511e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
2512e5c31af7Sopenharmony_ci	{
2513e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
2514e5c31af7Sopenharmony_ci		m_vs_id = 0;
2515e5c31af7Sopenharmony_ci	}
2516e5c31af7Sopenharmony_ci
2517e5c31af7Sopenharmony_ci	/* Release base class */
2518e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
2519e5c31af7Sopenharmony_ci}
2520e5c31af7Sopenharmony_ci
2521e5c31af7Sopenharmony_ci/* Retrieves test-specific geometry shader source code.
2522e5c31af7Sopenharmony_ci *
2523e5c31af7Sopenharmony_ci * @return Requested string.
2524e5c31af7Sopenharmony_ci */
2525e5c31af7Sopenharmony_cistd::string GeometryShaderMaxAtomicCounterBuffersTest::getGSCode()
2526e5c31af7Sopenharmony_ci{
2527e5c31af7Sopenharmony_ci	std::stringstream code_sstream;
2528e5c31af7Sopenharmony_ci
2529e5c31af7Sopenharmony_ci	/* Form the GS */
2530e5c31af7Sopenharmony_ci	code_sstream << "${VERSION}\n"
2531e5c31af7Sopenharmony_ci					"${GEOMETRY_SHADER_REQUIRE}\n"
2532e5c31af7Sopenharmony_ci					"\n"
2533e5c31af7Sopenharmony_ci					"layout (points)                   in;\n"
2534e5c31af7Sopenharmony_ci					"layout (points, max_vertices = 1) out;\n"
2535e5c31af7Sopenharmony_ci					"\n"
2536e5c31af7Sopenharmony_ci					"flat in int vertex_id[];\n"
2537e5c31af7Sopenharmony_ci					"\n";
2538e5c31af7Sopenharmony_ci
2539e5c31af7Sopenharmony_ci	for (glw::GLint n_ac = 0; n_ac < (m_gl_max_geometry_atomic_counter_buffers_ext_value); ++n_ac)
2540e5c31af7Sopenharmony_ci	{
2541e5c31af7Sopenharmony_ci		code_sstream << "layout(binding = " << n_ac << ") uniform atomic_uint ac" << n_ac << ";\n";
2542e5c31af7Sopenharmony_ci	}
2543e5c31af7Sopenharmony_ci
2544e5c31af7Sopenharmony_ci	code_sstream << "\n"
2545e5c31af7Sopenharmony_ci					"void main()\n"
2546e5c31af7Sopenharmony_ci					"{\n"
2547e5c31af7Sopenharmony_ci					"    for(int counter_id = 1; counter_id <= "
2548e5c31af7Sopenharmony_ci				 << m_gl_max_geometry_atomic_counter_buffers_ext_value
2549e5c31af7Sopenharmony_ci				 << "; ++counter_id)\n"
2550e5c31af7Sopenharmony_ci					"    {\n"
2551e5c31af7Sopenharmony_ci					"        if((vertex_id[0] % counter_id) == 0)\n"
2552e5c31af7Sopenharmony_ci					"        {\n";
2553e5c31af7Sopenharmony_ci
2554e5c31af7Sopenharmony_ci	for (glw::GLint n_ac = 0; n_ac < (m_gl_max_geometry_atomic_counter_buffers_ext_value); ++n_ac)
2555e5c31af7Sopenharmony_ci	{
2556e5c31af7Sopenharmony_ci		code_sstream << "            atomicCounterIncrement(ac" << n_ac << ");\n";
2557e5c31af7Sopenharmony_ci	}
2558e5c31af7Sopenharmony_ci
2559e5c31af7Sopenharmony_ci	code_sstream << "        }\n"
2560e5c31af7Sopenharmony_ci					"    }\n";
2561e5c31af7Sopenharmony_ci
2562e5c31af7Sopenharmony_ci	code_sstream << "\n"
2563e5c31af7Sopenharmony_ci					"    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
2564e5c31af7Sopenharmony_ci					"    EmitVertex();\n"
2565e5c31af7Sopenharmony_ci					"}\n";
2566e5c31af7Sopenharmony_ci
2567e5c31af7Sopenharmony_ci	/* Form a specialized version of the GS source code */
2568e5c31af7Sopenharmony_ci	std::string gs_code				= code_sstream.str();
2569e5c31af7Sopenharmony_ci	const char* gs_code_raw			= gs_code.c_str();
2570e5c31af7Sopenharmony_ci	std::string gs_code_specialized = specializeShader(1, /* parts */ &gs_code_raw);
2571e5c31af7Sopenharmony_ci
2572e5c31af7Sopenharmony_ci	return gs_code_specialized;
2573e5c31af7Sopenharmony_ci}
2574e5c31af7Sopenharmony_ci
2575e5c31af7Sopenharmony_ci/** Executes the test.
2576e5c31af7Sopenharmony_ci *
2577e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2578e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
2579e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
2580e5c31af7Sopenharmony_ci **/
2581e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderMaxAtomicCounterBuffersTest::iterate()
2582e5c31af7Sopenharmony_ci{
2583e5c31af7Sopenharmony_ci	/* Define Vertex Shader's code for the purpose of this test. */
2584e5c31af7Sopenharmony_ci	const char* vs_code = "${VERSION}\n"
2585e5c31af7Sopenharmony_ci						  "\n"
2586e5c31af7Sopenharmony_ci						  "flat out int vertex_id;\n"
2587e5c31af7Sopenharmony_ci						  "\n"
2588e5c31af7Sopenharmony_ci						  "void main()\n"
2589e5c31af7Sopenharmony_ci						  "{\n"
2590e5c31af7Sopenharmony_ci						  "    vertex_id    = gl_VertexID;\n"
2591e5c31af7Sopenharmony_ci						  "    gl_Position  = vec4(1.0, 0.0, 0.0, 1.0);\n"
2592e5c31af7Sopenharmony_ci						  "}\n";
2593e5c31af7Sopenharmony_ci
2594e5c31af7Sopenharmony_ci	unsigned int		  expected_value				= 0;
2595e5c31af7Sopenharmony_ci	const glw::Functions& gl							= m_context.getRenderContext().getFunctions();
2596e5c31af7Sopenharmony_ci	bool				  has_shader_compilation_failed = true;
2597e5c31af7Sopenharmony_ci	const glw::GLuint	 initial_ac_data				= 0;
2598e5c31af7Sopenharmony_ci	const glw::GLuint	 number_of_indices				= 128 * m_gl_max_geometry_atomic_counter_buffers_ext_value;
2599e5c31af7Sopenharmony_ci	bool				  result						= true;
2600e5c31af7Sopenharmony_ci
2601e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= "";
2602e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = DE_NULL;
2603e5c31af7Sopenharmony_ci	std::string gs_code_specialized		= "";
2604e5c31af7Sopenharmony_ci	const char* gs_code_specialized_raw = DE_NULL;
2605e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= "";
2606e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = DE_NULL;
2607e5c31af7Sopenharmony_ci
2608e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
2609e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
2610e5c31af7Sopenharmony_ci	{
2611e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
2612e5c31af7Sopenharmony_ci	}
2613e5c31af7Sopenharmony_ci
2614e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT pname value */
2615e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,
2616e5c31af7Sopenharmony_ci				   &m_gl_max_geometry_atomic_counter_buffers_ext_value);
2617e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT pname");
2618e5c31af7Sopenharmony_ci
2619e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS pname value */
2620e5c31af7Sopenharmony_ci	gl.getIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &m_gl_max_atomic_counter_buffer_bindings_value);
2621e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS pname");
2622e5c31af7Sopenharmony_ci
2623e5c31af7Sopenharmony_ci	/* Check if m_gl_max_geometry_atomic_counter_buffers_ext_value is less than or equal zero. */
2624e5c31af7Sopenharmony_ci	if (m_gl_max_geometry_atomic_counter_buffers_ext_value <= 0)
2625e5c31af7Sopenharmony_ci	{
2626e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT query value "
2627e5c31af7Sopenharmony_ci						   << "[" << m_gl_max_geometry_atomic_counter_buffers_ext_value
2628e5c31af7Sopenharmony_ci						   << "]"
2629e5c31af7Sopenharmony_ci							  " is less than or equal to zero. Atomic Counter Buffers"
2630e5c31af7Sopenharmony_ci							  " are not supported."
2631e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
2632e5c31af7Sopenharmony_ci
2633e5c31af7Sopenharmony_ci		if (m_gl_max_geometry_atomic_counter_buffers_ext_value == 0)
2634e5c31af7Sopenharmony_ci		{
2635e5c31af7Sopenharmony_ci			throw tcu::NotSupportedError("GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT is 0");
2636e5c31af7Sopenharmony_ci		}
2637e5c31af7Sopenharmony_ci		else
2638e5c31af7Sopenharmony_ci		{
2639e5c31af7Sopenharmony_ci			result = false;
2640e5c31af7Sopenharmony_ci			goto end;
2641e5c31af7Sopenharmony_ci		}
2642e5c31af7Sopenharmony_ci	}
2643e5c31af7Sopenharmony_ci
2644e5c31af7Sopenharmony_ci	/* Check if m_gl_max_atomic_counter_buffer_bindings_value is less than m_gl_max_shader_storage_blocks_value. */
2645e5c31af7Sopenharmony_ci	if (m_gl_max_atomic_counter_buffer_bindings_value < m_gl_max_geometry_atomic_counter_buffers_ext_value)
2646e5c31af7Sopenharmony_ci	{
2647e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT query value "
2648e5c31af7Sopenharmony_ci						   << "[" << m_gl_max_geometry_atomic_counter_buffers_ext_value
2649e5c31af7Sopenharmony_ci						   << "]"
2650e5c31af7Sopenharmony_ci							  " is greater than GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS query value "
2651e5c31af7Sopenharmony_ci							  "["
2652e5c31af7Sopenharmony_ci						   << m_gl_max_atomic_counter_buffer_bindings_value << "]." << tcu::TestLog::EndMessage;
2653e5c31af7Sopenharmony_ci
2654e5c31af7Sopenharmony_ci		result = false;
2655e5c31af7Sopenharmony_ci		goto end;
2656e5c31af7Sopenharmony_ci	}
2657e5c31af7Sopenharmony_ci
2658e5c31af7Sopenharmony_ci	/* Create a program object. */
2659e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
2660e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
2661e5c31af7Sopenharmony_ci
2662e5c31af7Sopenharmony_ci	/* Create shader objects. */
2663e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2664e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
2665e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
2666e5c31af7Sopenharmony_ci
2667e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
2668e5c31af7Sopenharmony_ci
2669e5c31af7Sopenharmony_ci	/* Try to link the test program object */
2670e5c31af7Sopenharmony_ci	fs_code_specialized		= specializeShader(1, &minimal_fs_code);
2671e5c31af7Sopenharmony_ci	fs_code_specialized_raw = fs_code_specialized.c_str();
2672e5c31af7Sopenharmony_ci
2673e5c31af7Sopenharmony_ci	gs_code_specialized		= getGSCode();
2674e5c31af7Sopenharmony_ci	gs_code_specialized_raw = gs_code_specialized.c_str();
2675e5c31af7Sopenharmony_ci
2676e5c31af7Sopenharmony_ci	vs_code_specialized		= specializeShader(1, &vs_code);
2677e5c31af7Sopenharmony_ci	vs_code_specialized_raw = vs_code_specialized.c_str();
2678e5c31af7Sopenharmony_ci
2679e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_po_id, m_gs_id, 1,				  /* n_sh1_body_parts */
2680e5c31af7Sopenharmony_ci									&gs_code_specialized_raw, m_vs_id, 1, /* n_sh2_body_parts */
2681e5c31af7Sopenharmony_ci									&vs_code_specialized_raw, m_fs_id, 1, /* n_sh3_body_parts */
2682e5c31af7Sopenharmony_ci									&fs_code_specialized_raw, &has_shader_compilation_failed))
2683e5c31af7Sopenharmony_ci	{
2684e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed." << tcu::TestLog::EndMessage;
2685e5c31af7Sopenharmony_ci
2686e5c31af7Sopenharmony_ci		result = false;
2687e5c31af7Sopenharmony_ci		goto end;
2688e5c31af7Sopenharmony_ci	}
2689e5c31af7Sopenharmony_ci
2690e5c31af7Sopenharmony_ci	/* Create Atomic Counter Buffer Objects. */
2691e5c31af7Sopenharmony_ci	m_acbo_ids = new glw::GLuint[m_gl_max_geometry_atomic_counter_buffers_ext_value];
2692e5c31af7Sopenharmony_ci
2693e5c31af7Sopenharmony_ci	gl.genBuffers(m_gl_max_geometry_atomic_counter_buffers_ext_value, m_acbo_ids);
2694e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2695e5c31af7Sopenharmony_ci
2696e5c31af7Sopenharmony_ci	for (glw::GLint n_acb = 0; n_acb < m_gl_max_geometry_atomic_counter_buffers_ext_value; ++n_acb)
2697e5c31af7Sopenharmony_ci	{
2698e5c31af7Sopenharmony_ci		gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo_ids[n_acb]);
2699e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed for GL_SHADER_STORAGE_BUFFER pname.");
2700e5c31af7Sopenharmony_ci
2701e5c31af7Sopenharmony_ci		gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(glw::GLuint), &initial_ac_data /*initialize with zeroes*/,
2702e5c31af7Sopenharmony_ci					  GL_DYNAMIC_COPY);
2703e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2704e5c31af7Sopenharmony_ci
2705e5c31af7Sopenharmony_ci		gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, n_acb /*binding index*/, m_acbo_ids[n_acb] /*buffer*/);
2706e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferRange() call failed.");
2707e5c31af7Sopenharmony_ci	}
2708e5c31af7Sopenharmony_ci
2709e5c31af7Sopenharmony_ci	/* Configure VAO. */
2710e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
2711e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2712e5c31af7Sopenharmony_ci
2713e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
2714e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2715e5c31af7Sopenharmony_ci
2716e5c31af7Sopenharmony_ci	/* Use program. */
2717e5c31af7Sopenharmony_ci	gl.useProgram(m_po_id);
2718e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2719e5c31af7Sopenharmony_ci
2720e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0 /*starting index*/, number_of_indices);
2721e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname.");
2722e5c31af7Sopenharmony_ci
2723e5c31af7Sopenharmony_ci	/* Calculate expected value. */
2724e5c31af7Sopenharmony_ci	/* For each point being processed by Geometry Shader. */
2725e5c31af7Sopenharmony_ci	for (glw::GLuint vertex_id = 0; vertex_id < number_of_indices; ++vertex_id)
2726e5c31af7Sopenharmony_ci	{
2727e5c31af7Sopenharmony_ci		/* And for each atomic counter ID. */
2728e5c31af7Sopenharmony_ci		for (int atomic_counter_id = 1; atomic_counter_id <= m_gl_max_geometry_atomic_counter_buffers_ext_value;
2729e5c31af7Sopenharmony_ci			 ++atomic_counter_id)
2730e5c31af7Sopenharmony_ci		{
2731e5c31af7Sopenharmony_ci			/* Check if (vertex_id % atomic_counter_id) == 0. If it is true, increment expected_value. */
2732e5c31af7Sopenharmony_ci			if (vertex_id % atomic_counter_id == 0)
2733e5c31af7Sopenharmony_ci			{
2734e5c31af7Sopenharmony_ci				++expected_value;
2735e5c31af7Sopenharmony_ci			}
2736e5c31af7Sopenharmony_ci		}
2737e5c31af7Sopenharmony_ci	}
2738e5c31af7Sopenharmony_ci
2739e5c31af7Sopenharmony_ci	/* Retrieve values from Atomic Counter Buffer Objects and check if these values are valid. */
2740e5c31af7Sopenharmony_ci	for (glw::GLint n_acb = 0; n_acb < m_gl_max_geometry_atomic_counter_buffers_ext_value; ++n_acb)
2741e5c31af7Sopenharmony_ci	{
2742e5c31af7Sopenharmony_ci		gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo_ids[n_acb]);
2743e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2744e5c31af7Sopenharmony_ci
2745e5c31af7Sopenharmony_ci		glw::GLuint* ptrABO_data = (glw::GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0 /*offset*/,
2746e5c31af7Sopenharmony_ci																   sizeof(glw::GLuint) /*length*/, GL_MAP_READ_BIT);
2747e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
2748e5c31af7Sopenharmony_ci
2749e5c31af7Sopenharmony_ci		if (ptrABO_data[0] != expected_value)
2750e5c31af7Sopenharmony_ci		{
2751e5c31af7Sopenharmony_ci			result = false;
2752e5c31af7Sopenharmony_ci			break;
2753e5c31af7Sopenharmony_ci		}
2754e5c31af7Sopenharmony_ci
2755e5c31af7Sopenharmony_ci		gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2756e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
2757e5c31af7Sopenharmony_ci
2758e5c31af7Sopenharmony_ci		ptrABO_data = NULL;
2759e5c31af7Sopenharmony_ci	}
2760e5c31af7Sopenharmony_ci
2761e5c31af7Sopenharmony_ciend:
2762e5c31af7Sopenharmony_ci	if (result)
2763e5c31af7Sopenharmony_ci	{
2764e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2765e5c31af7Sopenharmony_ci	}
2766e5c31af7Sopenharmony_ci	else
2767e5c31af7Sopenharmony_ci	{
2768e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2769e5c31af7Sopenharmony_ci	}
2770e5c31af7Sopenharmony_ci
2771e5c31af7Sopenharmony_ci	return STOP;
2772e5c31af7Sopenharmony_ci}
2773e5c31af7Sopenharmony_ci
2774e5c31af7Sopenharmony_ci/** Constructor
2775e5c31af7Sopenharmony_ci *
2776e5c31af7Sopenharmony_ci * @param context       Test context
2777e5c31af7Sopenharmony_ci * @param extParams     Not used.
2778e5c31af7Sopenharmony_ci * @param name          Test case's name
2779e5c31af7Sopenharmony_ci * @param description   Test case's description
2780e5c31af7Sopenharmony_ci **/
2781e5c31af7Sopenharmony_ciGeometryShaderPiplineProgramObjectWithoutActiveVSProgramTest::
2782e5c31af7Sopenharmony_ci	GeometryShaderPiplineProgramObjectWithoutActiveVSProgramTest(Context& context, const ExtParameters& extParams,
2783e5c31af7Sopenharmony_ci																 const char* name, const char* description)
2784e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
2785e5c31af7Sopenharmony_ci	, m_fs_id(0)
2786e5c31af7Sopenharmony_ci	, m_fs_po_id(0)
2787e5c31af7Sopenharmony_ci	, m_gs_id(0)
2788e5c31af7Sopenharmony_ci	, m_gs_po_id(0)
2789e5c31af7Sopenharmony_ci	, m_ppo_id(0)
2790e5c31af7Sopenharmony_ci	, m_vao_id(0)
2791e5c31af7Sopenharmony_ci{
2792e5c31af7Sopenharmony_ci}
2793e5c31af7Sopenharmony_ci
2794e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
2795e5c31af7Sopenharmony_civoid GeometryShaderPiplineProgramObjectWithoutActiveVSProgramTest::deinit()
2796e5c31af7Sopenharmony_ci{
2797e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2798e5c31af7Sopenharmony_ci
2799e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
2800e5c31af7Sopenharmony_ci	{
2801e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
2802e5c31af7Sopenharmony_ci		m_fs_id = 0;
2803e5c31af7Sopenharmony_ci	}
2804e5c31af7Sopenharmony_ci
2805e5c31af7Sopenharmony_ci	if (m_fs_po_id != 0)
2806e5c31af7Sopenharmony_ci	{
2807e5c31af7Sopenharmony_ci		gl.deleteProgram(m_fs_po_id);
2808e5c31af7Sopenharmony_ci		m_fs_po_id = 0;
2809e5c31af7Sopenharmony_ci	}
2810e5c31af7Sopenharmony_ci
2811e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
2812e5c31af7Sopenharmony_ci	{
2813e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
2814e5c31af7Sopenharmony_ci		m_gs_id = 0;
2815e5c31af7Sopenharmony_ci	}
2816e5c31af7Sopenharmony_ci
2817e5c31af7Sopenharmony_ci	if (m_gs_po_id != 0)
2818e5c31af7Sopenharmony_ci	{
2819e5c31af7Sopenharmony_ci		gl.deleteProgram(m_gs_po_id);
2820e5c31af7Sopenharmony_ci		m_gs_po_id = 0;
2821e5c31af7Sopenharmony_ci	}
2822e5c31af7Sopenharmony_ci
2823e5c31af7Sopenharmony_ci	if (m_ppo_id != 0)
2824e5c31af7Sopenharmony_ci	{
2825e5c31af7Sopenharmony_ci		gl.deleteProgramPipelines(1, &m_ppo_id);
2826e5c31af7Sopenharmony_ci		m_ppo_id = 0;
2827e5c31af7Sopenharmony_ci	}
2828e5c31af7Sopenharmony_ci
2829e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
2830e5c31af7Sopenharmony_ci	{
2831e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
2832e5c31af7Sopenharmony_ci		m_vao_id = 0;
2833e5c31af7Sopenharmony_ci	}
2834e5c31af7Sopenharmony_ci
2835e5c31af7Sopenharmony_ci	/* Release base class */
2836e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
2837e5c31af7Sopenharmony_ci}
2838e5c31af7Sopenharmony_ci
2839e5c31af7Sopenharmony_ci/** Executes the test.
2840e5c31af7Sopenharmony_ci *
2841e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2842e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
2843e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
2844e5c31af7Sopenharmony_ci **/
2845e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderPiplineProgramObjectWithoutActiveVSProgramTest::iterate()
2846e5c31af7Sopenharmony_ci{
2847e5c31af7Sopenharmony_ci	bool		has_shader_compilation_failed = true;
2848e5c31af7Sopenharmony_ci	bool		result						  = true;
2849e5c31af7Sopenharmony_ci	glw::GLenum error						  = GL_NO_ERROR;
2850e5c31af7Sopenharmony_ci
2851e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
2852e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
2853e5c31af7Sopenharmony_ci	{
2854e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
2855e5c31af7Sopenharmony_ci	}
2856e5c31af7Sopenharmony_ci
2857e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2858e5c31af7Sopenharmony_ci
2859e5c31af7Sopenharmony_ci	/* Create separable program objects. */
2860e5c31af7Sopenharmony_ci	m_fs_po_id = gl.createProgram();
2861e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
2862e5c31af7Sopenharmony_ci
2863e5c31af7Sopenharmony_ci	gl.programParameteri(m_fs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
2864e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed.");
2865e5c31af7Sopenharmony_ci
2866e5c31af7Sopenharmony_ci	m_gs_po_id = gl.createProgram();
2867e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
2868e5c31af7Sopenharmony_ci
2869e5c31af7Sopenharmony_ci	gl.programParameteri(m_gs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
2870e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed.");
2871e5c31af7Sopenharmony_ci
2872e5c31af7Sopenharmony_ci	/* Create shader objects. */
2873e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2874e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
2875e5c31af7Sopenharmony_ci
2876e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
2877e5c31af7Sopenharmony_ci
2878e5c31af7Sopenharmony_ci	/* Try to link the test program object */
2879e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= specializeShader(1, &minimal_fs_code);
2880e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = fs_code_specialized.c_str();
2881e5c31af7Sopenharmony_ci	std::string gs_code_specialized		= specializeShader(1, &minimal_gs_code);
2882e5c31af7Sopenharmony_ci	const char* gs_code_specialized_raw = gs_code_specialized.c_str();
2883e5c31af7Sopenharmony_ci
2884e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_fs_po_id, m_fs_id, 1,			/* n_sh1_body_parts */
2885e5c31af7Sopenharmony_ci									&fs_code_specialized_raw, 0, 0, /* n_sh2_body_parts */
2886e5c31af7Sopenharmony_ci									NULL, 0, 0,						/* n_sh3_body_parts */
2887e5c31af7Sopenharmony_ci									NULL, &has_shader_compilation_failed))
2888e5c31af7Sopenharmony_ci	{
2889e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Fragment Shader Program object linking failed."
2890e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
2891e5c31af7Sopenharmony_ci
2892e5c31af7Sopenharmony_ci		result = false;
2893e5c31af7Sopenharmony_ci		goto end;
2894e5c31af7Sopenharmony_ci	}
2895e5c31af7Sopenharmony_ci
2896e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_gs_po_id, m_gs_id, 1,			/* n_sh1_body_parts */
2897e5c31af7Sopenharmony_ci									&gs_code_specialized_raw, 0, 0, /* n_sh2_body_parts */
2898e5c31af7Sopenharmony_ci									NULL, 0, 0,						/* n_sh3_body_parts */
2899e5c31af7Sopenharmony_ci									NULL, &has_shader_compilation_failed))
2900e5c31af7Sopenharmony_ci	{
2901e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Geometry Shader Program object linking failed."
2902e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
2903e5c31af7Sopenharmony_ci
2904e5c31af7Sopenharmony_ci		result = false;
2905e5c31af7Sopenharmony_ci		goto end;
2906e5c31af7Sopenharmony_ci	}
2907e5c31af7Sopenharmony_ci
2908e5c31af7Sopenharmony_ci	/* Configure Pipeline Object. */
2909e5c31af7Sopenharmony_ci	gl.genProgramPipelines(1, &m_ppo_id);
2910e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
2911e5c31af7Sopenharmony_ci
2912e5c31af7Sopenharmony_ci	gl.useProgramStages(m_ppo_id, GL_FRAGMENT_SHADER_BIT, m_fs_po_id);
2913e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
2914e5c31af7Sopenharmony_ci
2915e5c31af7Sopenharmony_ci	gl.useProgramStages(m_ppo_id, GL_GEOMETRY_SHADER_BIT, m_gs_po_id);
2916e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
2917e5c31af7Sopenharmony_ci
2918e5c31af7Sopenharmony_ci	/* Configure VAO. */
2919e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
2920e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2921e5c31af7Sopenharmony_ci
2922e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
2923e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2924e5c31af7Sopenharmony_ci
2925e5c31af7Sopenharmony_ci	/* Use Program Pipeline Object. */
2926e5c31af7Sopenharmony_ci	gl.bindProgramPipeline(m_ppo_id);
2927e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
2928e5c31af7Sopenharmony_ci
2929e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0 /*starting index*/, 1 /*number of indices*/);
2930e5c31af7Sopenharmony_ci
2931e5c31af7Sopenharmony_ci	error = gl.getError();
2932e5c31af7Sopenharmony_ci
2933e5c31af7Sopenharmony_ci	/* Check if correct error was generated. */
2934e5c31af7Sopenharmony_ci	if (GL_INVALID_OPERATION != error)
2935e5c31af7Sopenharmony_ci	{
2936e5c31af7Sopenharmony_ci		result = false;
2937e5c31af7Sopenharmony_ci
2938e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated."
2939e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
2940e5c31af7Sopenharmony_ci	}
2941e5c31af7Sopenharmony_ci
2942e5c31af7Sopenharmony_ciend:
2943e5c31af7Sopenharmony_ci	if (result)
2944e5c31af7Sopenharmony_ci	{
2945e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2946e5c31af7Sopenharmony_ci	}
2947e5c31af7Sopenharmony_ci	else
2948e5c31af7Sopenharmony_ci	{
2949e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2950e5c31af7Sopenharmony_ci	}
2951e5c31af7Sopenharmony_ci
2952e5c31af7Sopenharmony_ci	return STOP;
2953e5c31af7Sopenharmony_ci}
2954e5c31af7Sopenharmony_ci
2955e5c31af7Sopenharmony_ci/** Constructor
2956e5c31af7Sopenharmony_ci *
2957e5c31af7Sopenharmony_ci * @param context       Test context
2958e5c31af7Sopenharmony_ci * @param extParams     Not used.
2959e5c31af7Sopenharmony_ci * @param name          Test case's name
2960e5c31af7Sopenharmony_ci * @param description   Test case's description
2961e5c31af7Sopenharmony_ci **/
2962e5c31af7Sopenharmony_ciGeometryShaderIncompatibleDrawCallModeTest::GeometryShaderIncompatibleDrawCallModeTest(Context&				context,
2963e5c31af7Sopenharmony_ci																					   const ExtParameters& extParams,
2964e5c31af7Sopenharmony_ci																					   const char*			name,
2965e5c31af7Sopenharmony_ci																					   const char*			description)
2966e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
2967e5c31af7Sopenharmony_ci	, m_fs_id(0)
2968e5c31af7Sopenharmony_ci	, m_gs_ids(NULL)
2969e5c31af7Sopenharmony_ci	, m_number_of_gs(5 /*taken from test spec*/)
2970e5c31af7Sopenharmony_ci	, m_po_ids(NULL)
2971e5c31af7Sopenharmony_ci{
2972e5c31af7Sopenharmony_ci	m_vao_id = 0;
2973e5c31af7Sopenharmony_ci	m_vs_id  = 0;
2974e5c31af7Sopenharmony_ci}
2975e5c31af7Sopenharmony_ci
2976e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
2977e5c31af7Sopenharmony_civoid GeometryShaderIncompatibleDrawCallModeTest::deinit()
2978e5c31af7Sopenharmony_ci{
2979e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2980e5c31af7Sopenharmony_ci
2981e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
2982e5c31af7Sopenharmony_ci	{
2983e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
2984e5c31af7Sopenharmony_ci		m_fs_id = 0;
2985e5c31af7Sopenharmony_ci	}
2986e5c31af7Sopenharmony_ci
2987e5c31af7Sopenharmony_ci	if (m_gs_ids != 0)
2988e5c31af7Sopenharmony_ci	{
2989e5c31af7Sopenharmony_ci		for (glw::GLuint i = 0; i < m_number_of_gs; ++i)
2990e5c31af7Sopenharmony_ci		{
2991e5c31af7Sopenharmony_ci			gl.deleteShader(m_gs_ids[i]);
2992e5c31af7Sopenharmony_ci			m_gs_ids[i] = 0;
2993e5c31af7Sopenharmony_ci		}
2994e5c31af7Sopenharmony_ci
2995e5c31af7Sopenharmony_ci		delete[] m_gs_ids;
2996e5c31af7Sopenharmony_ci		m_gs_ids = NULL;
2997e5c31af7Sopenharmony_ci	}
2998e5c31af7Sopenharmony_ci
2999e5c31af7Sopenharmony_ci	if (m_po_ids != 0)
3000e5c31af7Sopenharmony_ci	{
3001e5c31af7Sopenharmony_ci		for (glw::GLuint i = 0; i < m_number_of_gs; ++i)
3002e5c31af7Sopenharmony_ci		{
3003e5c31af7Sopenharmony_ci			gl.deleteProgram(m_po_ids[i]);
3004e5c31af7Sopenharmony_ci			m_po_ids[i] = 0;
3005e5c31af7Sopenharmony_ci		}
3006e5c31af7Sopenharmony_ci
3007e5c31af7Sopenharmony_ci		delete[] m_po_ids;
3008e5c31af7Sopenharmony_ci		m_po_ids = NULL;
3009e5c31af7Sopenharmony_ci	}
3010e5c31af7Sopenharmony_ci
3011e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
3012e5c31af7Sopenharmony_ci	{
3013e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
3014e5c31af7Sopenharmony_ci		m_vao_id = 0;
3015e5c31af7Sopenharmony_ci	}
3016e5c31af7Sopenharmony_ci
3017e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
3018e5c31af7Sopenharmony_ci	{
3019e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
3020e5c31af7Sopenharmony_ci		m_vs_id = 0;
3021e5c31af7Sopenharmony_ci	}
3022e5c31af7Sopenharmony_ci
3023e5c31af7Sopenharmony_ci	/* Release base class */
3024e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
3025e5c31af7Sopenharmony_ci}
3026e5c31af7Sopenharmony_ci
3027e5c31af7Sopenharmony_ci/** Executes the test.
3028e5c31af7Sopenharmony_ci *
3029e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
3030e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
3031e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
3032e5c31af7Sopenharmony_ci **/
3033e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderIncompatibleDrawCallModeTest::iterate()
3034e5c31af7Sopenharmony_ci{
3035e5c31af7Sopenharmony_ci	/* Define 5 Geometry Shaders for purpose of this test. */
3036e5c31af7Sopenharmony_ci	const char* gs_code_points = "${VERSION}\n"
3037e5c31af7Sopenharmony_ci								 "${GEOMETRY_SHADER_REQUIRE}\n"
3038e5c31af7Sopenharmony_ci								 "\n"
3039e5c31af7Sopenharmony_ci								 "layout (points)                   in;\n"
3040e5c31af7Sopenharmony_ci								 "layout (points, max_vertices = 1) out;\n"
3041e5c31af7Sopenharmony_ci								 "\n"
3042e5c31af7Sopenharmony_ci								 "${IN_PER_VERTEX_DECL_ARRAY}"
3043e5c31af7Sopenharmony_ci								 "\n"
3044e5c31af7Sopenharmony_ci								 "void main()\n"
3045e5c31af7Sopenharmony_ci								 "{\n"
3046e5c31af7Sopenharmony_ci								 "    gl_Position = gl_in[0].gl_Position;\n"
3047e5c31af7Sopenharmony_ci								 "    EmitVertex();\n"
3048e5c31af7Sopenharmony_ci								 "}\n";
3049e5c31af7Sopenharmony_ci
3050e5c31af7Sopenharmony_ci	const char* gs_code_lines = "${VERSION}\n"
3051e5c31af7Sopenharmony_ci								"${GEOMETRY_SHADER_REQUIRE}\n"
3052e5c31af7Sopenharmony_ci								"\n"
3053e5c31af7Sopenharmony_ci								"layout (lines)                    in;\n"
3054e5c31af7Sopenharmony_ci								"layout (points, max_vertices = 1) out;\n"
3055e5c31af7Sopenharmony_ci								"\n"
3056e5c31af7Sopenharmony_ci								"${IN_PER_VERTEX_DECL_ARRAY}"
3057e5c31af7Sopenharmony_ci								"\n"
3058e5c31af7Sopenharmony_ci								"void main()\n"
3059e5c31af7Sopenharmony_ci								"{\n"
3060e5c31af7Sopenharmony_ci								"    gl_Position = gl_in[0].gl_Position;\n"
3061e5c31af7Sopenharmony_ci								"    EmitVertex();\n"
3062e5c31af7Sopenharmony_ci								"}\n";
3063e5c31af7Sopenharmony_ci
3064e5c31af7Sopenharmony_ci	const char* gs_code_lines_adjacency = "${VERSION}\n"
3065e5c31af7Sopenharmony_ci										  "${GEOMETRY_SHADER_REQUIRE}\n"
3066e5c31af7Sopenharmony_ci										  "\n"
3067e5c31af7Sopenharmony_ci										  "layout (lines_adjacency)          in;\n"
3068e5c31af7Sopenharmony_ci										  "layout (points, max_vertices = 1) out;\n"
3069e5c31af7Sopenharmony_ci										  "\n"
3070e5c31af7Sopenharmony_ci										  "${IN_PER_VERTEX_DECL_ARRAY}"
3071e5c31af7Sopenharmony_ci										  "\n"
3072e5c31af7Sopenharmony_ci										  "void main()\n"
3073e5c31af7Sopenharmony_ci										  "{\n"
3074e5c31af7Sopenharmony_ci										  "    gl_Position = gl_in[0].gl_Position;\n"
3075e5c31af7Sopenharmony_ci										  "    EmitVertex();\n"
3076e5c31af7Sopenharmony_ci										  "}\n";
3077e5c31af7Sopenharmony_ci
3078e5c31af7Sopenharmony_ci	const char* gs_code_triangles = "${VERSION}\n"
3079e5c31af7Sopenharmony_ci									"${GEOMETRY_SHADER_REQUIRE}\n"
3080e5c31af7Sopenharmony_ci									"\n"
3081e5c31af7Sopenharmony_ci									"layout (triangles)                in;\n"
3082e5c31af7Sopenharmony_ci									"layout (points, max_vertices = 1) out;\n"
3083e5c31af7Sopenharmony_ci									"\n"
3084e5c31af7Sopenharmony_ci									"${IN_PER_VERTEX_DECL_ARRAY}"
3085e5c31af7Sopenharmony_ci									"\n"
3086e5c31af7Sopenharmony_ci									"void main()\n"
3087e5c31af7Sopenharmony_ci									"{\n"
3088e5c31af7Sopenharmony_ci									"    gl_Position = gl_in[0].gl_Position;\n"
3089e5c31af7Sopenharmony_ci									"    EmitVertex();\n"
3090e5c31af7Sopenharmony_ci									"}\n";
3091e5c31af7Sopenharmony_ci
3092e5c31af7Sopenharmony_ci	const char* gs_code_triangles_adjacency = "${VERSION}\n"
3093e5c31af7Sopenharmony_ci											  "${GEOMETRY_SHADER_REQUIRE}\n"
3094e5c31af7Sopenharmony_ci											  "\n"
3095e5c31af7Sopenharmony_ci											  "layout (triangles_adjacency)      in;\n"
3096e5c31af7Sopenharmony_ci											  "layout (points, max_vertices = 1) out;\n"
3097e5c31af7Sopenharmony_ci											  "\n"
3098e5c31af7Sopenharmony_ci											  "${IN_PER_VERTEX_DECL_ARRAY}"
3099e5c31af7Sopenharmony_ci											  "\n"
3100e5c31af7Sopenharmony_ci											  "void main()\n"
3101e5c31af7Sopenharmony_ci											  "{\n"
3102e5c31af7Sopenharmony_ci											  "    gl_Position = gl_in[0].gl_Position;\n"
3103e5c31af7Sopenharmony_ci											  "    EmitVertex();\n"
3104e5c31af7Sopenharmony_ci											  "}\n";
3105e5c31af7Sopenharmony_ci
3106e5c31af7Sopenharmony_ci	bool has_shader_compilation_failed = true;
3107e5c31af7Sopenharmony_ci	bool result						   = true;
3108e5c31af7Sopenharmony_ci
3109e5c31af7Sopenharmony_ci	m_gs_ids = new glw::GLuint[m_number_of_gs];
3110e5c31af7Sopenharmony_ci	m_po_ids = new glw::GLuint[m_number_of_gs];
3111e5c31af7Sopenharmony_ci
3112e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
3113e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
3114e5c31af7Sopenharmony_ci	{
3115e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
3116e5c31af7Sopenharmony_ci	}
3117e5c31af7Sopenharmony_ci
3118e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3119e5c31af7Sopenharmony_ci
3120e5c31af7Sopenharmony_ci	/* Create program objects & geometry shader objects. */
3121e5c31af7Sopenharmony_ci	for (glw::GLuint i = 0; i < m_number_of_gs; ++i)
3122e5c31af7Sopenharmony_ci	{
3123e5c31af7Sopenharmony_ci		m_gs_ids[i] = gl.createShader(GL_GEOMETRY_SHADER);
3124e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
3125e5c31af7Sopenharmony_ci
3126e5c31af7Sopenharmony_ci		m_po_ids[i] = gl.createProgram();
3127e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
3128e5c31af7Sopenharmony_ci	}
3129e5c31af7Sopenharmony_ci
3130e5c31af7Sopenharmony_ci	/* Create shader object. */
3131e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3132e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
3133e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
3134e5c31af7Sopenharmony_ci
3135e5c31af7Sopenharmony_ci	/* Try to link the test program object */
3136e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= specializeShader(1, &minimal_fs_code);
3137e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = fs_code_specialized.c_str();
3138e5c31af7Sopenharmony_ci
3139e5c31af7Sopenharmony_ci	std::string gs_codes_specialized[] = { specializeShader(1, &gs_code_points), specializeShader(1, &gs_code_lines),
3140e5c31af7Sopenharmony_ci										   specializeShader(1, &gs_code_lines_adjacency),
3141e5c31af7Sopenharmony_ci										   specializeShader(1, &gs_code_triangles),
3142e5c31af7Sopenharmony_ci										   specializeShader(1, &gs_code_triangles_adjacency) };
3143e5c31af7Sopenharmony_ci
3144e5c31af7Sopenharmony_ci	const char* gs_codes_specialized_raw[] = { gs_codes_specialized[0].c_str(), gs_codes_specialized[1].c_str(),
3145e5c31af7Sopenharmony_ci											   gs_codes_specialized[2].c_str(), gs_codes_specialized[3].c_str(),
3146e5c31af7Sopenharmony_ci											   gs_codes_specialized[4].c_str() };
3147e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= specializeShader(1, &minimal_vs_code);
3148e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = vs_code_specialized.c_str();
3149e5c31af7Sopenharmony_ci
3150e5c31af7Sopenharmony_ci	for (glw::GLuint i = 0; i < m_number_of_gs; ++i)
3151e5c31af7Sopenharmony_ci	{
3152e5c31af7Sopenharmony_ci		if (!TestCaseBase::buildProgram(m_po_ids[i], m_fs_id, 1,				  /* n_sh1_body_parts */
3153e5c31af7Sopenharmony_ci										&fs_code_specialized_raw, m_gs_ids[i], 1, /* n_sh2_body_parts */
3154e5c31af7Sopenharmony_ci										&gs_codes_specialized_raw[i], m_vs_id, 1, /* n_sh3_body_parts */
3155e5c31af7Sopenharmony_ci										&vs_code_specialized_raw, &has_shader_compilation_failed))
3156e5c31af7Sopenharmony_ci		{
3157e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed for i = "
3158e5c31af7Sopenharmony_ci							   << "[" << i << "]." << tcu::TestLog::EndMessage;
3159e5c31af7Sopenharmony_ci
3160e5c31af7Sopenharmony_ci			result = false;
3161e5c31af7Sopenharmony_ci			break;
3162e5c31af7Sopenharmony_ci		}
3163e5c31af7Sopenharmony_ci	}
3164e5c31af7Sopenharmony_ci
3165e5c31af7Sopenharmony_ci	if (result)
3166e5c31af7Sopenharmony_ci	{
3167e5c31af7Sopenharmony_ci		/* Configure VAO. */
3168e5c31af7Sopenharmony_ci		gl.genVertexArrays(1, &m_vao_id);
3169e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
3170e5c31af7Sopenharmony_ci
3171e5c31af7Sopenharmony_ci		gl.bindVertexArray(m_vao_id);
3172e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
3173e5c31af7Sopenharmony_ci
3174e5c31af7Sopenharmony_ci		for (glw::GLuint po = 0; po < m_number_of_gs; ++po)
3175e5c31af7Sopenharmony_ci		{
3176e5c31af7Sopenharmony_ci			/* Use Program Object. */
3177e5c31af7Sopenharmony_ci			gl.useProgram(m_po_ids[po]);
3178e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
3179e5c31af7Sopenharmony_ci
3180e5c31af7Sopenharmony_ci			if (po != 0)
3181e5c31af7Sopenharmony_ci			{
3182e5c31af7Sopenharmony_ci				gl.drawArrays(GL_POINTS, 0 /*starting index*/, 1 /*number of indices*/);
3183e5c31af7Sopenharmony_ci
3184e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3185e5c31af7Sopenharmony_ci				{
3186e5c31af7Sopenharmony_ci					result = false;
3187e5c31af7Sopenharmony_ci
3188e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3189e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3190e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3191e5c31af7Sopenharmony_ci
3192e5c31af7Sopenharmony_ci					break;
3193e5c31af7Sopenharmony_ci				}
3194e5c31af7Sopenharmony_ci			}
3195e5c31af7Sopenharmony_ci
3196e5c31af7Sopenharmony_ci			if (po != 1)
3197e5c31af7Sopenharmony_ci			{
3198e5c31af7Sopenharmony_ci				gl.drawArrays(GL_LINES, 0 /*starting index*/, 2 /*number of indices*/);
3199e5c31af7Sopenharmony_ci
3200e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3201e5c31af7Sopenharmony_ci				{
3202e5c31af7Sopenharmony_ci					result = false;
3203e5c31af7Sopenharmony_ci
3204e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3205e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3206e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3207e5c31af7Sopenharmony_ci
3208e5c31af7Sopenharmony_ci					break;
3209e5c31af7Sopenharmony_ci				}
3210e5c31af7Sopenharmony_ci
3211e5c31af7Sopenharmony_ci				gl.drawArrays(GL_LINE_LOOP, 0 /*starting index*/, 2 /*number of indices*/);
3212e5c31af7Sopenharmony_ci
3213e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3214e5c31af7Sopenharmony_ci				{
3215e5c31af7Sopenharmony_ci					result = false;
3216e5c31af7Sopenharmony_ci
3217e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3218e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3219e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3220e5c31af7Sopenharmony_ci
3221e5c31af7Sopenharmony_ci					break;
3222e5c31af7Sopenharmony_ci				}
3223e5c31af7Sopenharmony_ci
3224e5c31af7Sopenharmony_ci				gl.drawArrays(GL_LINE_STRIP, 0 /*starting index*/, 2 /*number of indices*/);
3225e5c31af7Sopenharmony_ci
3226e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3227e5c31af7Sopenharmony_ci				{
3228e5c31af7Sopenharmony_ci					result = false;
3229e5c31af7Sopenharmony_ci
3230e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3231e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3232e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3233e5c31af7Sopenharmony_ci
3234e5c31af7Sopenharmony_ci					break;
3235e5c31af7Sopenharmony_ci				}
3236e5c31af7Sopenharmony_ci			}
3237e5c31af7Sopenharmony_ci
3238e5c31af7Sopenharmony_ci			if (po != 2)
3239e5c31af7Sopenharmony_ci			{
3240e5c31af7Sopenharmony_ci				gl.drawArrays(GL_LINES_ADJACENCY_EXT, 0 /*starting index*/, 4 /*number of indices*/);
3241e5c31af7Sopenharmony_ci
3242e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3243e5c31af7Sopenharmony_ci				{
3244e5c31af7Sopenharmony_ci					result = false;
3245e5c31af7Sopenharmony_ci
3246e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3247e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3248e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3249e5c31af7Sopenharmony_ci
3250e5c31af7Sopenharmony_ci					break;
3251e5c31af7Sopenharmony_ci				}
3252e5c31af7Sopenharmony_ci
3253e5c31af7Sopenharmony_ci				gl.drawArrays(GL_LINE_STRIP_ADJACENCY_EXT, 0 /*starting index*/, 4 /*number of indices*/);
3254e5c31af7Sopenharmony_ci
3255e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3256e5c31af7Sopenharmony_ci				{
3257e5c31af7Sopenharmony_ci					result = false;
3258e5c31af7Sopenharmony_ci
3259e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3260e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3261e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3262e5c31af7Sopenharmony_ci
3263e5c31af7Sopenharmony_ci					break;
3264e5c31af7Sopenharmony_ci				}
3265e5c31af7Sopenharmony_ci			}
3266e5c31af7Sopenharmony_ci
3267e5c31af7Sopenharmony_ci			if (po != 3)
3268e5c31af7Sopenharmony_ci			{
3269e5c31af7Sopenharmony_ci				gl.drawArrays(GL_TRIANGLES, 0 /*starting index*/, 3 /*number of indices*/);
3270e5c31af7Sopenharmony_ci
3271e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3272e5c31af7Sopenharmony_ci				{
3273e5c31af7Sopenharmony_ci					result = false;
3274e5c31af7Sopenharmony_ci
3275e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3276e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3277e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3278e5c31af7Sopenharmony_ci
3279e5c31af7Sopenharmony_ci					break;
3280e5c31af7Sopenharmony_ci				}
3281e5c31af7Sopenharmony_ci
3282e5c31af7Sopenharmony_ci				gl.drawArrays(GL_TRIANGLE_FAN, 0 /*starting index*/, 3 /*number of indices*/);
3283e5c31af7Sopenharmony_ci
3284e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3285e5c31af7Sopenharmony_ci				{
3286e5c31af7Sopenharmony_ci					result = false;
3287e5c31af7Sopenharmony_ci
3288e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3289e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3290e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3291e5c31af7Sopenharmony_ci
3292e5c31af7Sopenharmony_ci					break;
3293e5c31af7Sopenharmony_ci				}
3294e5c31af7Sopenharmony_ci
3295e5c31af7Sopenharmony_ci				gl.drawArrays(GL_TRIANGLE_STRIP, 0 /*starting index*/, 3 /*number of indices*/);
3296e5c31af7Sopenharmony_ci
3297e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3298e5c31af7Sopenharmony_ci				{
3299e5c31af7Sopenharmony_ci					result = false;
3300e5c31af7Sopenharmony_ci
3301e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3302e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3303e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3304e5c31af7Sopenharmony_ci
3305e5c31af7Sopenharmony_ci					break;
3306e5c31af7Sopenharmony_ci				}
3307e5c31af7Sopenharmony_ci			}
3308e5c31af7Sopenharmony_ci
3309e5c31af7Sopenharmony_ci			if (po != 4)
3310e5c31af7Sopenharmony_ci			{
3311e5c31af7Sopenharmony_ci				gl.drawArrays(GL_TRIANGLES_ADJACENCY_EXT, 0 /*starting index*/, 6 /*number of indices*/);
3312e5c31af7Sopenharmony_ci
3313e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3314e5c31af7Sopenharmony_ci				{
3315e5c31af7Sopenharmony_ci					result = false;
3316e5c31af7Sopenharmony_ci
3317e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3318e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3319e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3320e5c31af7Sopenharmony_ci
3321e5c31af7Sopenharmony_ci					break;
3322e5c31af7Sopenharmony_ci				}
3323e5c31af7Sopenharmony_ci
3324e5c31af7Sopenharmony_ci				gl.drawArrays(GL_TRIANGLE_STRIP_ADJACENCY_EXT, 0 /*starting index*/, 6 /*number of indices*/);
3325e5c31af7Sopenharmony_ci
3326e5c31af7Sopenharmony_ci				if (GL_INVALID_OPERATION != gl.getError())
3327e5c31af7Sopenharmony_ci				{
3328e5c31af7Sopenharmony_ci					result = false;
3329e5c31af7Sopenharmony_ci
3330e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
3331e5c31af7Sopenharmony_ci									   << "Error different than GL_INVALID_OPEARATION was generated."
3332e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
3333e5c31af7Sopenharmony_ci
3334e5c31af7Sopenharmony_ci					break;
3335e5c31af7Sopenharmony_ci				}
3336e5c31af7Sopenharmony_ci			}
3337e5c31af7Sopenharmony_ci		}
3338e5c31af7Sopenharmony_ci	}
3339e5c31af7Sopenharmony_ci
3340e5c31af7Sopenharmony_ci	if (result)
3341e5c31af7Sopenharmony_ci	{
3342e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3343e5c31af7Sopenharmony_ci	}
3344e5c31af7Sopenharmony_ci	else
3345e5c31af7Sopenharmony_ci	{
3346e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3347e5c31af7Sopenharmony_ci	}
3348e5c31af7Sopenharmony_ci
3349e5c31af7Sopenharmony_ci	return STOP;
3350e5c31af7Sopenharmony_ci}
3351e5c31af7Sopenharmony_ci
3352e5c31af7Sopenharmony_ci/** Constructor
3353e5c31af7Sopenharmony_ci *
3354e5c31af7Sopenharmony_ci * @param context       Test context
3355e5c31af7Sopenharmony_ci * @param extParams     Not used.
3356e5c31af7Sopenharmony_ci * @param name          Test case's name
3357e5c31af7Sopenharmony_ci * @param description   Test case's description
3358e5c31af7Sopenharmony_ci **/
3359e5c31af7Sopenharmony_ciGeometryShaderInsufficientEmittedVerticesTest::GeometryShaderInsufficientEmittedVerticesTest(
3360e5c31af7Sopenharmony_ci	Context& context, const ExtParameters& extParams, const char* name, const char* description)
3361e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
3362e5c31af7Sopenharmony_ci	, m_fbo_id(0)
3363e5c31af7Sopenharmony_ci	, m_fs_id(0)
3364e5c31af7Sopenharmony_ci	, m_gs_ids(NULL)
3365e5c31af7Sopenharmony_ci	, m_number_of_color_components(4)
3366e5c31af7Sopenharmony_ci	, m_number_of_gs(2 /*taken from test spec*/)
3367e5c31af7Sopenharmony_ci	, m_po_ids(NULL)
3368e5c31af7Sopenharmony_ci	, m_texture_height(16)
3369e5c31af7Sopenharmony_ci	, m_texture_id(0)
3370e5c31af7Sopenharmony_ci	, m_texture_width(16)
3371e5c31af7Sopenharmony_ci{
3372e5c31af7Sopenharmony_ci	m_vao_id = 0;
3373e5c31af7Sopenharmony_ci	m_vs_id  = 0;
3374e5c31af7Sopenharmony_ci
3375e5c31af7Sopenharmony_ci	/* Allocate enough memory for glReadPixels() data which is respectively: width, height, RGBA components number. */
3376e5c31af7Sopenharmony_ci	m_pixels = new glw::GLubyte[m_texture_height * m_texture_width * m_number_of_color_components];
3377e5c31af7Sopenharmony_ci}
3378e5c31af7Sopenharmony_ci
3379e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
3380e5c31af7Sopenharmony_civoid GeometryShaderInsufficientEmittedVerticesTest::deinit()
3381e5c31af7Sopenharmony_ci{
3382e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3383e5c31af7Sopenharmony_ci
3384e5c31af7Sopenharmony_ci	gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
3385e5c31af7Sopenharmony_ci
3386e5c31af7Sopenharmony_ci	if (m_pixels != NULL)
3387e5c31af7Sopenharmony_ci	{
3388e5c31af7Sopenharmony_ci		delete[] m_pixels;
3389e5c31af7Sopenharmony_ci		m_pixels = NULL;
3390e5c31af7Sopenharmony_ci	}
3391e5c31af7Sopenharmony_ci
3392e5c31af7Sopenharmony_ci	if (m_fbo_id != 0)
3393e5c31af7Sopenharmony_ci	{
3394e5c31af7Sopenharmony_ci		gl.deleteFramebuffers(1, &m_fbo_id);
3395e5c31af7Sopenharmony_ci		m_fbo_id = 0;
3396e5c31af7Sopenharmony_ci	}
3397e5c31af7Sopenharmony_ci
3398e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
3399e5c31af7Sopenharmony_ci	{
3400e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
3401e5c31af7Sopenharmony_ci		m_fs_id = 0;
3402e5c31af7Sopenharmony_ci	}
3403e5c31af7Sopenharmony_ci
3404e5c31af7Sopenharmony_ci	if (m_gs_ids != 0)
3405e5c31af7Sopenharmony_ci	{
3406e5c31af7Sopenharmony_ci		for (glw::GLuint i = 0; i < m_number_of_gs; ++i)
3407e5c31af7Sopenharmony_ci		{
3408e5c31af7Sopenharmony_ci			gl.deleteShader(m_gs_ids[i]);
3409e5c31af7Sopenharmony_ci			m_gs_ids[i] = 0;
3410e5c31af7Sopenharmony_ci		}
3411e5c31af7Sopenharmony_ci
3412e5c31af7Sopenharmony_ci		delete[] m_gs_ids;
3413e5c31af7Sopenharmony_ci		m_gs_ids = NULL;
3414e5c31af7Sopenharmony_ci	}
3415e5c31af7Sopenharmony_ci
3416e5c31af7Sopenharmony_ci	if (m_po_ids != 0)
3417e5c31af7Sopenharmony_ci	{
3418e5c31af7Sopenharmony_ci		for (glw::GLuint i = 0; i < m_number_of_gs; ++i)
3419e5c31af7Sopenharmony_ci		{
3420e5c31af7Sopenharmony_ci			gl.deleteProgram(m_po_ids[i]);
3421e5c31af7Sopenharmony_ci			m_po_ids[i] = 0;
3422e5c31af7Sopenharmony_ci		}
3423e5c31af7Sopenharmony_ci
3424e5c31af7Sopenharmony_ci		delete[] m_po_ids;
3425e5c31af7Sopenharmony_ci		m_po_ids = NULL;
3426e5c31af7Sopenharmony_ci	}
3427e5c31af7Sopenharmony_ci
3428e5c31af7Sopenharmony_ci	if (m_texture_id != 0)
3429e5c31af7Sopenharmony_ci	{
3430e5c31af7Sopenharmony_ci		gl.deleteTextures(1, &m_texture_id);
3431e5c31af7Sopenharmony_ci		m_texture_id = 0;
3432e5c31af7Sopenharmony_ci	}
3433e5c31af7Sopenharmony_ci
3434e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
3435e5c31af7Sopenharmony_ci	{
3436e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
3437e5c31af7Sopenharmony_ci		m_vao_id = 0;
3438e5c31af7Sopenharmony_ci	}
3439e5c31af7Sopenharmony_ci
3440e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
3441e5c31af7Sopenharmony_ci	{
3442e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
3443e5c31af7Sopenharmony_ci		m_vs_id = 0;
3444e5c31af7Sopenharmony_ci	}
3445e5c31af7Sopenharmony_ci
3446e5c31af7Sopenharmony_ci	/* Release base class */
3447e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
3448e5c31af7Sopenharmony_ci}
3449e5c31af7Sopenharmony_ci
3450e5c31af7Sopenharmony_ci/** Executes the test.
3451e5c31af7Sopenharmony_ci *
3452e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
3453e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
3454e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
3455e5c31af7Sopenharmony_ci **/
3456e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderInsufficientEmittedVerticesTest::iterate()
3457e5c31af7Sopenharmony_ci{
3458e5c31af7Sopenharmony_ci	/* Define Fragment Shader for purpose of this test. */
3459e5c31af7Sopenharmony_ci	const char* fs_code = "${VERSION}\n"
3460e5c31af7Sopenharmony_ci						  "\n"
3461e5c31af7Sopenharmony_ci						  "precision highp float;\n"
3462e5c31af7Sopenharmony_ci						  "\n"
3463e5c31af7Sopenharmony_ci						  "out vec4 result;\n"
3464e5c31af7Sopenharmony_ci						  "\n"
3465e5c31af7Sopenharmony_ci						  "void main()\n"
3466e5c31af7Sopenharmony_ci						  "{\n"
3467e5c31af7Sopenharmony_ci						  "    result = vec4(1.0, 0.0, 0.0, 0.0);\n"
3468e5c31af7Sopenharmony_ci						  "}\n";
3469e5c31af7Sopenharmony_ci
3470e5c31af7Sopenharmony_ci	/* Define 2 Geometry Shaders for purpose of this test. */
3471e5c31af7Sopenharmony_ci	const char* gs_line_strip = "${VERSION}\n"
3472e5c31af7Sopenharmony_ci								"${GEOMETRY_SHADER_REQUIRE}\n"
3473e5c31af7Sopenharmony_ci								"\n"
3474e5c31af7Sopenharmony_ci								"layout (points)                       in;\n"
3475e5c31af7Sopenharmony_ci								"layout (line_strip, max_vertices = 2) out;\n"
3476e5c31af7Sopenharmony_ci								"\n"
3477e5c31af7Sopenharmony_ci								"${IN_PER_VERTEX_DECL_ARRAY}"
3478e5c31af7Sopenharmony_ci								"\n"
3479e5c31af7Sopenharmony_ci								"void main()\n"
3480e5c31af7Sopenharmony_ci								"{\n"
3481e5c31af7Sopenharmony_ci								"    gl_Position    = gl_in[0].gl_Position;\n"
3482e5c31af7Sopenharmony_ci								"    gl_Position.zw = vec2(0.0, 1.0);\n"
3483e5c31af7Sopenharmony_ci								"    EmitVertex();\n"
3484e5c31af7Sopenharmony_ci								"}\n";
3485e5c31af7Sopenharmony_ci
3486e5c31af7Sopenharmony_ci	const char* gs_triangle_strip = "${VERSION}\n"
3487e5c31af7Sopenharmony_ci									"${GEOMETRY_SHADER_REQUIRE}\n"
3488e5c31af7Sopenharmony_ci									"\n"
3489e5c31af7Sopenharmony_ci									"layout (points)                           in;\n"
3490e5c31af7Sopenharmony_ci									"layout (triangle_strip, max_vertices = 3) out;\n"
3491e5c31af7Sopenharmony_ci									"\n"
3492e5c31af7Sopenharmony_ci									"${IN_PER_VERTEX_DECL_ARRAY}"
3493e5c31af7Sopenharmony_ci									"\n"
3494e5c31af7Sopenharmony_ci									"void main()\n"
3495e5c31af7Sopenharmony_ci									"{\n"
3496e5c31af7Sopenharmony_ci									"    gl_Position    = gl_in[0].gl_Position;\n"
3497e5c31af7Sopenharmony_ci									"    gl_Position.zw = vec2(0.0, 1.0);\n"
3498e5c31af7Sopenharmony_ci									"    EmitVertex();\n"
3499e5c31af7Sopenharmony_ci
3500e5c31af7Sopenharmony_ci									"    gl_Position    = gl_in[0].gl_Position;\n"
3501e5c31af7Sopenharmony_ci									"    gl_Position.zw = vec2(0.0, 1.0);\n"
3502e5c31af7Sopenharmony_ci									"    EmitVertex();\n"
3503e5c31af7Sopenharmony_ci									"}\n";
3504e5c31af7Sopenharmony_ci
3505e5c31af7Sopenharmony_ci	bool has_shader_compilation_failed = true;
3506e5c31af7Sopenharmony_ci	bool result						   = true;
3507e5c31af7Sopenharmony_ci
3508e5c31af7Sopenharmony_ci	m_gs_ids = new glw::GLuint[m_number_of_gs];
3509e5c31af7Sopenharmony_ci	m_po_ids = new glw::GLuint[m_number_of_gs];
3510e5c31af7Sopenharmony_ci
3511e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
3512e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
3513e5c31af7Sopenharmony_ci	{
3514e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
3515e5c31af7Sopenharmony_ci	}
3516e5c31af7Sopenharmony_ci
3517e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3518e5c31af7Sopenharmony_ci
3519e5c31af7Sopenharmony_ci	/* Create program objects & geometry shader objects. */
3520e5c31af7Sopenharmony_ci	for (glw::GLuint i = 0; i < m_number_of_gs; ++i)
3521e5c31af7Sopenharmony_ci	{
3522e5c31af7Sopenharmony_ci		m_gs_ids[i] = gl.createShader(GL_GEOMETRY_SHADER);
3523e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
3524e5c31af7Sopenharmony_ci
3525e5c31af7Sopenharmony_ci		m_po_ids[i] = gl.createProgram();
3526e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
3527e5c31af7Sopenharmony_ci	}
3528e5c31af7Sopenharmony_ci
3529e5c31af7Sopenharmony_ci	/* Create shader object. */
3530e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3531e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
3532e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
3533e5c31af7Sopenharmony_ci
3534e5c31af7Sopenharmony_ci	/* Try to link the test program object */
3535e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= specializeShader(1, &fs_code);
3536e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = fs_code_specialized.c_str();
3537e5c31af7Sopenharmony_ci
3538e5c31af7Sopenharmony_ci	std::string gs_codes_specialized[] = { specializeShader(1, &gs_line_strip),
3539e5c31af7Sopenharmony_ci										   specializeShader(1, &gs_triangle_strip) };
3540e5c31af7Sopenharmony_ci
3541e5c31af7Sopenharmony_ci	const char* gs_codes_specialized_raw[] = { gs_codes_specialized[0].c_str(), gs_codes_specialized[1].c_str() };
3542e5c31af7Sopenharmony_ci
3543e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= specializeShader(1, &minimal_vs_code);
3544e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = vs_code_specialized.c_str();
3545e5c31af7Sopenharmony_ci
3546e5c31af7Sopenharmony_ci	for (glw::GLuint i = 0; i < m_number_of_gs; ++i)
3547e5c31af7Sopenharmony_ci	{
3548e5c31af7Sopenharmony_ci		if (!TestCaseBase::buildProgram(m_po_ids[i], m_fs_id, 1,				  /* n_sh1_body_parts */
3549e5c31af7Sopenharmony_ci										&fs_code_specialized_raw, m_gs_ids[i], 1, /* n_sh2_body_parts */
3550e5c31af7Sopenharmony_ci										&gs_codes_specialized_raw[i], m_vs_id, 1, /* n_sh3_body_parts */
3551e5c31af7Sopenharmony_ci										&vs_code_specialized_raw, &has_shader_compilation_failed))
3552e5c31af7Sopenharmony_ci		{
3553e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed for i = "
3554e5c31af7Sopenharmony_ci							   << "[" << i << "]." << tcu::TestLog::EndMessage;
3555e5c31af7Sopenharmony_ci
3556e5c31af7Sopenharmony_ci			result = false;
3557e5c31af7Sopenharmony_ci			break;
3558e5c31af7Sopenharmony_ci		}
3559e5c31af7Sopenharmony_ci	}
3560e5c31af7Sopenharmony_ci
3561e5c31af7Sopenharmony_ci	if (result)
3562e5c31af7Sopenharmony_ci	{
3563e5c31af7Sopenharmony_ci		/* Create a 2D texture. */
3564e5c31af7Sopenharmony_ci		gl.genTextures(1, &m_texture_id);
3565e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
3566e5c31af7Sopenharmony_ci
3567e5c31af7Sopenharmony_ci		gl.bindTexture(GL_TEXTURE_2D, m_texture_id);
3568e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
3569e5c31af7Sopenharmony_ci
3570e5c31af7Sopenharmony_ci		gl.texStorage2D(GL_TEXTURE_2D, 1 /*levels*/, GL_RGBA8, 16 /*width taken from spec*/,
3571e5c31af7Sopenharmony_ci						16 /*height taken from spec*/);
3572e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
3573e5c31af7Sopenharmony_ci
3574e5c31af7Sopenharmony_ci		/* Configure FBO. */
3575e5c31af7Sopenharmony_ci		gl.genFramebuffers(1, &m_fbo_id);
3576e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
3577e5c31af7Sopenharmony_ci
3578e5c31af7Sopenharmony_ci		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
3579e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
3580e5c31af7Sopenharmony_ci
3581e5c31af7Sopenharmony_ci		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0 /*level*/);
3582e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
3583e5c31af7Sopenharmony_ci
3584e5c31af7Sopenharmony_ci		/* Configure VAO. */
3585e5c31af7Sopenharmony_ci		gl.genVertexArrays(1, &m_vao_id);
3586e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
3587e5c31af7Sopenharmony_ci
3588e5c31af7Sopenharmony_ci		gl.bindVertexArray(m_vao_id);
3589e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
3590e5c31af7Sopenharmony_ci
3591e5c31af7Sopenharmony_ci		gl.clearColor(0.0f, 1.0f, 0.0f, 0.0f);
3592e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed.");
3593e5c31af7Sopenharmony_ci
3594e5c31af7Sopenharmony_ci		for (glw::GLuint po = 0; po < m_number_of_gs; ++po)
3595e5c31af7Sopenharmony_ci		{
3596e5c31af7Sopenharmony_ci			/* Use Program Object. */
3597e5c31af7Sopenharmony_ci			gl.useProgram(m_po_ids[po]);
3598e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
3599e5c31af7Sopenharmony_ci
3600e5c31af7Sopenharmony_ci			gl.clear(GL_COLOR_BUFFER_BIT);
3601e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
3602e5c31af7Sopenharmony_ci
3603e5c31af7Sopenharmony_ci			gl.drawArrays(GL_POINTS, 0 /*first*/, 1 /*count*/);
3604e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed for GL_POINTS pname.");
3605e5c31af7Sopenharmony_ci
3606e5c31af7Sopenharmony_ci			gl.readPixels(0 /*x*/, 0 /*y*/, m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels);
3607e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
3608e5c31af7Sopenharmony_ci
3609e5c31af7Sopenharmony_ci			for (glw::GLuint pixel = 0; pixel < (m_texture_width * m_texture_height * m_number_of_color_components -
3610e5c31af7Sopenharmony_ci												 m_number_of_color_components);
3611e5c31af7Sopenharmony_ci				 pixel += m_number_of_color_components)
3612e5c31af7Sopenharmony_ci			{
3613e5c31af7Sopenharmony_ci				if (m_pixels[pixel] != 0 && m_pixels[pixel + 1] != 255 && m_pixels[pixel + 2] != 0 &&
3614e5c31af7Sopenharmony_ci					m_pixels[pixel + 3] != 0)
3615e5c31af7Sopenharmony_ci				{
3616e5c31af7Sopenharmony_ci					result = false;
3617e5c31af7Sopenharmony_ci
3618e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "Pixel [" << pixel << "] has color = ["
3619e5c31af7Sopenharmony_ci									   << m_pixels[pixel] << ", " << m_pixels[pixel + 1] << ", " << m_pixels[pixel + 2]
3620e5c31af7Sopenharmony_ci									   << ", " << m_pixels[pixel + 3] << "] "
3621e5c31af7Sopenharmony_ci									   << "instead of [0, 255, 0, 0]." << tcu::TestLog::EndMessage;
3622e5c31af7Sopenharmony_ci
3623e5c31af7Sopenharmony_ci					break;
3624e5c31af7Sopenharmony_ci				}
3625e5c31af7Sopenharmony_ci			}
3626e5c31af7Sopenharmony_ci		}
3627e5c31af7Sopenharmony_ci	}
3628e5c31af7Sopenharmony_ci
3629e5c31af7Sopenharmony_ci	if (result)
3630e5c31af7Sopenharmony_ci	{
3631e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3632e5c31af7Sopenharmony_ci	}
3633e5c31af7Sopenharmony_ci	else
3634e5c31af7Sopenharmony_ci	{
3635e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3636e5c31af7Sopenharmony_ci	}
3637e5c31af7Sopenharmony_ci
3638e5c31af7Sopenharmony_ci	return STOP;
3639e5c31af7Sopenharmony_ci}
3640e5c31af7Sopenharmony_ci
3641e5c31af7Sopenharmony_ci/** Constructor
3642e5c31af7Sopenharmony_ci *
3643e5c31af7Sopenharmony_ci * @param context       Test context
3644e5c31af7Sopenharmony_ci * @param extParams     Not used.
3645e5c31af7Sopenharmony_ci * @param name          Test case's name
3646e5c31af7Sopenharmony_ci * @param description   Test case's description
3647e5c31af7Sopenharmony_ci **/
3648e5c31af7Sopenharmony_ciGeometryShaderPipelineObjectTransformFeedbackVertexAndGeometryShaderCaptureTest::
3649e5c31af7Sopenharmony_ci	GeometryShaderPipelineObjectTransformFeedbackVertexAndGeometryShaderCaptureTest(Context&			 context,
3650e5c31af7Sopenharmony_ci																					const ExtParameters& extParams,
3651e5c31af7Sopenharmony_ci																					const char*			 name,
3652e5c31af7Sopenharmony_ci																					const char*			 description)
3653e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
3654e5c31af7Sopenharmony_ci	, m_gs_id(0)
3655e5c31af7Sopenharmony_ci	, m_gs_po_id(0)
3656e5c31af7Sopenharmony_ci	, m_ppo_id(0)
3657e5c31af7Sopenharmony_ci	, m_tfbo_id(0)
3658e5c31af7Sopenharmony_ci	, m_vao_id(0)
3659e5c31af7Sopenharmony_ci	, m_vs_id(0)
3660e5c31af7Sopenharmony_ci	, m_vs_po_id(0)
3661e5c31af7Sopenharmony_ci{
3662e5c31af7Sopenharmony_ci}
3663e5c31af7Sopenharmony_ci
3664e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
3665e5c31af7Sopenharmony_civoid GeometryShaderPipelineObjectTransformFeedbackVertexAndGeometryShaderCaptureTest::deinit()
3666e5c31af7Sopenharmony_ci{
3667e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3668e5c31af7Sopenharmony_ci
3669e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
3670e5c31af7Sopenharmony_ci	{
3671e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
3672e5c31af7Sopenharmony_ci		m_gs_id = 0;
3673e5c31af7Sopenharmony_ci	}
3674e5c31af7Sopenharmony_ci
3675e5c31af7Sopenharmony_ci	if (m_gs_po_id != 0)
3676e5c31af7Sopenharmony_ci	{
3677e5c31af7Sopenharmony_ci		gl.deleteProgram(m_gs_po_id);
3678e5c31af7Sopenharmony_ci		m_gs_po_id = 0;
3679e5c31af7Sopenharmony_ci	}
3680e5c31af7Sopenharmony_ci
3681e5c31af7Sopenharmony_ci	if (m_ppo_id != 0)
3682e5c31af7Sopenharmony_ci	{
3683e5c31af7Sopenharmony_ci		gl.deleteProgramPipelines(1, &m_ppo_id);
3684e5c31af7Sopenharmony_ci		m_ppo_id = 0;
3685e5c31af7Sopenharmony_ci	}
3686e5c31af7Sopenharmony_ci
3687e5c31af7Sopenharmony_ci	if (m_tfbo_id != 0)
3688e5c31af7Sopenharmony_ci	{
3689e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_tfbo_id);
3690e5c31af7Sopenharmony_ci		m_tfbo_id = 0;
3691e5c31af7Sopenharmony_ci	}
3692e5c31af7Sopenharmony_ci
3693e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
3694e5c31af7Sopenharmony_ci	{
3695e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
3696e5c31af7Sopenharmony_ci		m_vao_id = 0;
3697e5c31af7Sopenharmony_ci	}
3698e5c31af7Sopenharmony_ci
3699e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
3700e5c31af7Sopenharmony_ci	{
3701e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
3702e5c31af7Sopenharmony_ci		m_vs_id = 0;
3703e5c31af7Sopenharmony_ci	}
3704e5c31af7Sopenharmony_ci
3705e5c31af7Sopenharmony_ci	if (m_vs_po_id != 0)
3706e5c31af7Sopenharmony_ci	{
3707e5c31af7Sopenharmony_ci		gl.deleteProgram(m_vs_po_id);
3708e5c31af7Sopenharmony_ci		m_vs_po_id = 0;
3709e5c31af7Sopenharmony_ci	}
3710e5c31af7Sopenharmony_ci
3711e5c31af7Sopenharmony_ci	/* Release base class */
3712e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
3713e5c31af7Sopenharmony_ci}
3714e5c31af7Sopenharmony_ci
3715e5c31af7Sopenharmony_ci/** Executes the test.
3716e5c31af7Sopenharmony_ci *
3717e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
3718e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
3719e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
3720e5c31af7Sopenharmony_ci **/
3721e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderPipelineObjectTransformFeedbackVertexAndGeometryShaderCaptureTest::iterate()
3722e5c31af7Sopenharmony_ci{
3723e5c31af7Sopenharmony_ci	/* Define Geometry Shader for purpose of this test. */
3724e5c31af7Sopenharmony_ci	const char* gs_code =
3725e5c31af7Sopenharmony_ci		"${VERSION}\n"
3726e5c31af7Sopenharmony_ci		"${GEOMETRY_SHADER_REQUIRE}\n"
3727e5c31af7Sopenharmony_ci		"${IN_PER_VERTEX_DECL_ARRAY}\n"
3728e5c31af7Sopenharmony_ci		"${OUT_PER_VERTEX_DECL}\n"
3729e5c31af7Sopenharmony_ci		"\n"
3730e5c31af7Sopenharmony_ci		"layout (points)                   in;\n"
3731e5c31af7Sopenharmony_ci		"layout (points, max_vertices = 1) out;\n"
3732e5c31af7Sopenharmony_ci		"\n"
3733e5c31af7Sopenharmony_ci		"flat in int   vertexID[];\n"
3734e5c31af7Sopenharmony_ci		"flat in ivec4 out_vs_1[];\n"
3735e5c31af7Sopenharmony_ci		"\n"
3736e5c31af7Sopenharmony_ci		"out vec4 out_gs_1;\n"
3737e5c31af7Sopenharmony_ci		"\n"
3738e5c31af7Sopenharmony_ci		"void main()\n"
3739e5c31af7Sopenharmony_ci		"{\n"
3740e5c31af7Sopenharmony_ci		"    out_gs_1 = vec4(vertexID[0] * 2, vertexID[0] * 2 + 1, vertexID[0] * 2 + 2, vertexID[0] * 2 + 3);\n"
3741e5c31af7Sopenharmony_ci		"    gl_Position = vec4(0, 0, 0, 1);\n"
3742e5c31af7Sopenharmony_ci		"    EmitVertex();\n"
3743e5c31af7Sopenharmony_ci		"}\n";
3744e5c31af7Sopenharmony_ci
3745e5c31af7Sopenharmony_ci	/* Define Vertex Shader for purpose of this test. */
3746e5c31af7Sopenharmony_ci	const char* vs_code = "${VERSION}\n"
3747e5c31af7Sopenharmony_ci						  "${OUT_PER_VERTEX_DECL}\n"
3748e5c31af7Sopenharmony_ci						  "\n"
3749e5c31af7Sopenharmony_ci						  "flat out ivec4 out_vs_1;\n"
3750e5c31af7Sopenharmony_ci						  "flat out int vertexID;\n"
3751e5c31af7Sopenharmony_ci						  "\n"
3752e5c31af7Sopenharmony_ci						  "void main()\n"
3753e5c31af7Sopenharmony_ci						  "{\n"
3754e5c31af7Sopenharmony_ci						  "    vertexID = gl_VertexID;\n"
3755e5c31af7Sopenharmony_ci						  "    out_vs_1 = ivec4(gl_VertexID, gl_VertexID + 1, gl_VertexID + 2, gl_VertexID + 3);\n"
3756e5c31af7Sopenharmony_ci						  "    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
3757e5c31af7Sopenharmony_ci						  "}\n";
3758e5c31af7Sopenharmony_ci
3759e5c31af7Sopenharmony_ci	bool		  has_shader_compilation_failed = true;
3760e5c31af7Sopenharmony_ci	bool		  result						= true;
3761e5c31af7Sopenharmony_ci	glw::GLfloat* ptrTF_data_f					= NULL;
3762e5c31af7Sopenharmony_ci	glw::GLuint*  ptrTF_data_ui					= NULL;
3763e5c31af7Sopenharmony_ci	glw::GLfloat  expected_geom_results[]		= { 0.0f, 1.0f, 2.0f, 3.0f };
3764e5c31af7Sopenharmony_ci	glw::GLuint   expected_vertex_results[]		= { 0, 1, 2, 3 };
3765e5c31af7Sopenharmony_ci	glw::GLfloat  epsilon						= 1e-5f;
3766e5c31af7Sopenharmony_ci
3767e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
3768e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
3769e5c31af7Sopenharmony_ci	{
3770e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
3771e5c31af7Sopenharmony_ci	}
3772e5c31af7Sopenharmony_ci
3773e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3774e5c31af7Sopenharmony_ci
3775e5c31af7Sopenharmony_ci	/* Create separable program objects. */
3776e5c31af7Sopenharmony_ci	m_gs_po_id = gl.createProgram();
3777e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
3778e5c31af7Sopenharmony_ci
3779e5c31af7Sopenharmony_ci	gl.programParameteri(m_gs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
3780e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed.");
3781e5c31af7Sopenharmony_ci
3782e5c31af7Sopenharmony_ci	m_vs_po_id = gl.createProgram();
3783e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
3784e5c31af7Sopenharmony_ci
3785e5c31af7Sopenharmony_ci	gl.programParameteri(m_vs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
3786e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed.");
3787e5c31af7Sopenharmony_ci
3788e5c31af7Sopenharmony_ci	/* Create shader objects. */
3789e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
3790e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
3791e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
3792e5c31af7Sopenharmony_ci
3793e5c31af7Sopenharmony_ci	/* Try to link the test program object */
3794e5c31af7Sopenharmony_ci	std::string gs_code_specialized		= specializeShader(1, &gs_code);
3795e5c31af7Sopenharmony_ci	const char* gs_code_specialized_raw = gs_code_specialized.c_str();
3796e5c31af7Sopenharmony_ci
3797e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= specializeShader(1, &vs_code);
3798e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = vs_code_specialized.c_str();
3799e5c31af7Sopenharmony_ci
3800e5c31af7Sopenharmony_ci	/* Specify output variables to be captured. */
3801e5c31af7Sopenharmony_ci	const char* tf_varyings[2] = { "out_gs_1", "out_vs_1" };
3802e5c31af7Sopenharmony_ci
3803e5c31af7Sopenharmony_ci	gl.transformFeedbackVaryings(m_gs_po_id, 1 /*count*/, &tf_varyings[0], GL_INTERLEAVED_ATTRIBS);
3804e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call(s) failed.");
3805e5c31af7Sopenharmony_ci
3806e5c31af7Sopenharmony_ci	gl.transformFeedbackVaryings(m_vs_po_id, 1 /*count*/, &tf_varyings[1], GL_INTERLEAVED_ATTRIBS);
3807e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call(s) failed.");
3808e5c31af7Sopenharmony_ci
3809e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_gs_po_id, m_gs_id, 1,			/* n_sh1_body_parts */
3810e5c31af7Sopenharmony_ci									&gs_code_specialized_raw, 0, 0, /* n_sh2_body_parts */
3811e5c31af7Sopenharmony_ci									NULL, 0, 0,						/* n_sh3_body_parts */
3812e5c31af7Sopenharmony_ci									NULL, &has_shader_compilation_failed))
3813e5c31af7Sopenharmony_ci	{
3814e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Geometry Shader Program object linking failed."
3815e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
3816e5c31af7Sopenharmony_ci
3817e5c31af7Sopenharmony_ci		result = false;
3818e5c31af7Sopenharmony_ci		goto end;
3819e5c31af7Sopenharmony_ci	}
3820e5c31af7Sopenharmony_ci
3821e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_vs_po_id, m_vs_id, 1,			/* n_sh1_body_parts */
3822e5c31af7Sopenharmony_ci									&vs_code_specialized_raw, 0, 0, /* n_sh2_body_parts */
3823e5c31af7Sopenharmony_ci									NULL, 0, 0,						/* n_sh3_body_parts */
3824e5c31af7Sopenharmony_ci									NULL, &has_shader_compilation_failed))
3825e5c31af7Sopenharmony_ci	{
3826e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Geometry Shader Program object linking failed."
3827e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
3828e5c31af7Sopenharmony_ci
3829e5c31af7Sopenharmony_ci		result = false;
3830e5c31af7Sopenharmony_ci		goto end;
3831e5c31af7Sopenharmony_ci	}
3832e5c31af7Sopenharmony_ci
3833e5c31af7Sopenharmony_ci	/* Create and configure Program Pipeline Object. */
3834e5c31af7Sopenharmony_ci	gl.genProgramPipelines(1, &m_ppo_id);
3835e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call(s) failed.");
3836e5c31af7Sopenharmony_ci
3837e5c31af7Sopenharmony_ci	gl.useProgramStages(m_ppo_id, GL_GEOMETRY_SHADER_BIT, m_gs_po_id);
3838e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed.");
3839e5c31af7Sopenharmony_ci
3840e5c31af7Sopenharmony_ci	gl.useProgramStages(m_ppo_id, GL_VERTEX_SHADER_BIT, m_vs_po_id);
3841e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed.");
3842e5c31af7Sopenharmony_ci
3843e5c31af7Sopenharmony_ci	/* Create Vertex Array Object. */
3844e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
3845e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call(s) failed.");
3846e5c31af7Sopenharmony_ci
3847e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
3848e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call(s) failed.");
3849e5c31af7Sopenharmony_ci
3850e5c31af7Sopenharmony_ci	/* Create Buffer Object for Transform Feedback data. */
3851e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_tfbo_id);
3852e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed.");
3853e5c31af7Sopenharmony_ci
3854e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id);
3855e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed.");
3856e5c31af7Sopenharmony_ci
3857e5c31af7Sopenharmony_ci	gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * 4, NULL, GL_STREAM_READ);
3858e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call(s) failed.");
3859e5c31af7Sopenharmony_ci
3860e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*binding index*/, m_tfbo_id);
3861e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call(s) failed.");
3862e5c31af7Sopenharmony_ci
3863e5c31af7Sopenharmony_ci	/* Ensure that there is no program object already bound and bind program pipeline. */
3864e5c31af7Sopenharmony_ci	gl.useProgram(0);
3865e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed.");
3866e5c31af7Sopenharmony_ci
3867e5c31af7Sopenharmony_ci	gl.bindProgramPipeline(m_ppo_id);
3868e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call(s) failed.");
3869e5c31af7Sopenharmony_ci
3870e5c31af7Sopenharmony_ci	gl.enable(GL_RASTERIZER_DISCARD);
3871e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call(s) failed.");
3872e5c31af7Sopenharmony_ci
3873e5c31af7Sopenharmony_ci	/* First pass - Vertex and Geometry Shaders On. */
3874e5c31af7Sopenharmony_ci	gl.beginTransformFeedback(GL_POINTS);
3875e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call(s) failed.");
3876e5c31af7Sopenharmony_ci
3877e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0 /*first*/, 1 /*count*/);
3878e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call(s) failed.");
3879e5c31af7Sopenharmony_ci
3880e5c31af7Sopenharmony_ci	gl.endTransformFeedback();
3881e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call(s) failed.");
3882e5c31af7Sopenharmony_ci
3883e5c31af7Sopenharmony_ci	/* Retrieve data and check if it is correct. */
3884e5c31af7Sopenharmony_ci	ptrTF_data_f =
3885e5c31af7Sopenharmony_ci		(glw::GLfloat*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*offset*/,
3886e5c31af7Sopenharmony_ci										 sizeof(glw::GLfloat) * 4 /* four float vector components */, GL_MAP_READ_BIT);
3887e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
3888e5c31af7Sopenharmony_ci
3889e5c31af7Sopenharmony_ci	for (size_t i = 0; i < 4; ++i)
3890e5c31af7Sopenharmony_ci	{
3891e5c31af7Sopenharmony_ci		if (fabs(ptrTF_data_f[i] - expected_geom_results[i]) >= epsilon)
3892e5c31af7Sopenharmony_ci		{
3893e5c31af7Sopenharmony_ci			result = false;
3894e5c31af7Sopenharmony_ci			break;
3895e5c31af7Sopenharmony_ci		}
3896e5c31af7Sopenharmony_ci	}
3897e5c31af7Sopenharmony_ci
3898e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3899e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
3900e5c31af7Sopenharmony_ci
3901e5c31af7Sopenharmony_ci	ptrTF_data_f = NULL;
3902e5c31af7Sopenharmony_ci
3903e5c31af7Sopenharmony_ci	if (!result)
3904e5c31af7Sopenharmony_ci	{
3905e5c31af7Sopenharmony_ci		goto end;
3906e5c31af7Sopenharmony_ci	}
3907e5c31af7Sopenharmony_ci
3908e5c31af7Sopenharmony_ci	/* Deactivate Geometry Shader Program Object from Program Pipeline Object. */
3909e5c31af7Sopenharmony_ci	gl.useProgramStages(m_ppo_id, GL_GEOMETRY_SHADER_BIT, 0 /* program */);
3910e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed.");
3911e5c31af7Sopenharmony_ci
3912e5c31af7Sopenharmony_ci	/* Second pass - only Vertex Shader Program On. */
3913e5c31af7Sopenharmony_ci	gl.beginTransformFeedback(GL_POINTS);
3914e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call(s) failed.");
3915e5c31af7Sopenharmony_ci
3916e5c31af7Sopenharmony_ci	gl.drawArrays(GL_POINTS, 0 /*first*/, 1 /*count*/);
3917e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call(s) failed.");
3918e5c31af7Sopenharmony_ci
3919e5c31af7Sopenharmony_ci	gl.endTransformFeedback();
3920e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call(s) failed.");
3921e5c31af7Sopenharmony_ci
3922e5c31af7Sopenharmony_ci	gl.disable(GL_RASTERIZER_DISCARD);
3923e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call(s) failed.");
3924e5c31af7Sopenharmony_ci
3925e5c31af7Sopenharmony_ci	/* Retrieve data and check if it is correct. */
3926e5c31af7Sopenharmony_ci	ptrTF_data_ui =
3927e5c31af7Sopenharmony_ci		(glw::GLuint*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*offset*/,
3928e5c31af7Sopenharmony_ci										sizeof(glw::GLuint) * 4 /* four float vector components */, GL_MAP_READ_BIT);
3929e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
3930e5c31af7Sopenharmony_ci
3931e5c31af7Sopenharmony_ci	for (size_t i = 0; i < 4; ++i)
3932e5c31af7Sopenharmony_ci	{
3933e5c31af7Sopenharmony_ci		if (ptrTF_data_ui[i] != expected_vertex_results[i])
3934e5c31af7Sopenharmony_ci		{
3935e5c31af7Sopenharmony_ci			result = false;
3936e5c31af7Sopenharmony_ci			break;
3937e5c31af7Sopenharmony_ci		}
3938e5c31af7Sopenharmony_ci	}
3939e5c31af7Sopenharmony_ci
3940e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3941e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
3942e5c31af7Sopenharmony_ci
3943e5c31af7Sopenharmony_ci	ptrTF_data_ui = NULL;
3944e5c31af7Sopenharmony_ci
3945e5c31af7Sopenharmony_ciend:
3946e5c31af7Sopenharmony_ci	if (result)
3947e5c31af7Sopenharmony_ci	{
3948e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3949e5c31af7Sopenharmony_ci	}
3950e5c31af7Sopenharmony_ci	else
3951e5c31af7Sopenharmony_ci	{
3952e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3953e5c31af7Sopenharmony_ci	}
3954e5c31af7Sopenharmony_ci
3955e5c31af7Sopenharmony_ci	return STOP;
3956e5c31af7Sopenharmony_ci}
3957e5c31af7Sopenharmony_ci
3958e5c31af7Sopenharmony_ci/** Constructor
3959e5c31af7Sopenharmony_ci *
3960e5c31af7Sopenharmony_ci * @param context       Test context
3961e5c31af7Sopenharmony_ci * @param extParams     Not used.
3962e5c31af7Sopenharmony_ci * @param name          Test case's name
3963e5c31af7Sopenharmony_ci * @param description   Test case's description
3964e5c31af7Sopenharmony_ci **/
3965e5c31af7Sopenharmony_ciGeometryShaderDrawPrimitivesDoNotMatchOutputPrimitives::GeometryShaderDrawPrimitivesDoNotMatchOutputPrimitives(
3966e5c31af7Sopenharmony_ci	Context& context, const ExtParameters& extParams, const char* name, const char* description)
3967e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description), m_fs_id(0), m_gs_id(0), m_po_id(0), m_tfbo_id(0)
3968e5c31af7Sopenharmony_ci{
3969e5c31af7Sopenharmony_ci	m_vao_id = 0;
3970e5c31af7Sopenharmony_ci	m_vs_id  = 0;
3971e5c31af7Sopenharmony_ci}
3972e5c31af7Sopenharmony_ci
3973e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
3974e5c31af7Sopenharmony_civoid GeometryShaderDrawPrimitivesDoNotMatchOutputPrimitives::deinit()
3975e5c31af7Sopenharmony_ci{
3976e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3977e5c31af7Sopenharmony_ci
3978e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
3979e5c31af7Sopenharmony_ci	{
3980e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
3981e5c31af7Sopenharmony_ci		m_fs_id = 0;
3982e5c31af7Sopenharmony_ci	}
3983e5c31af7Sopenharmony_ci
3984e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
3985e5c31af7Sopenharmony_ci	{
3986e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
3987e5c31af7Sopenharmony_ci		m_gs_id = 0;
3988e5c31af7Sopenharmony_ci	}
3989e5c31af7Sopenharmony_ci
3990e5c31af7Sopenharmony_ci	if (m_po_id != 0)
3991e5c31af7Sopenharmony_ci	{
3992e5c31af7Sopenharmony_ci		gl.deleteProgram(m_po_id);
3993e5c31af7Sopenharmony_ci		m_po_id = 0;
3994e5c31af7Sopenharmony_ci	}
3995e5c31af7Sopenharmony_ci
3996e5c31af7Sopenharmony_ci	if (m_tfbo_id != 0)
3997e5c31af7Sopenharmony_ci	{
3998e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_tfbo_id);
3999e5c31af7Sopenharmony_ci		m_tfbo_id = 0;
4000e5c31af7Sopenharmony_ci	}
4001e5c31af7Sopenharmony_ci
4002e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
4003e5c31af7Sopenharmony_ci	{
4004e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
4005e5c31af7Sopenharmony_ci		m_vao_id = 0;
4006e5c31af7Sopenharmony_ci	}
4007e5c31af7Sopenharmony_ci
4008e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
4009e5c31af7Sopenharmony_ci	{
4010e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
4011e5c31af7Sopenharmony_ci		m_vs_id = 0;
4012e5c31af7Sopenharmony_ci	}
4013e5c31af7Sopenharmony_ci
4014e5c31af7Sopenharmony_ci	/* Release base class */
4015e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
4016e5c31af7Sopenharmony_ci}
4017e5c31af7Sopenharmony_ci
4018e5c31af7Sopenharmony_ci/** Executes the test.
4019e5c31af7Sopenharmony_ci *
4020e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
4021e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
4022e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
4023e5c31af7Sopenharmony_ci **/
4024e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderDrawPrimitivesDoNotMatchOutputPrimitives::iterate()
4025e5c31af7Sopenharmony_ci{
4026e5c31af7Sopenharmony_ci	/* Define Geometry Shader for purpose of this test. */
4027e5c31af7Sopenharmony_ci	const char* gs_code = "${VERSION}\n"
4028e5c31af7Sopenharmony_ci						  "${GEOMETRY_SHADER_REQUIRE}\n"
4029e5c31af7Sopenharmony_ci						  "\n"
4030e5c31af7Sopenharmony_ci						  "layout (lines)                            in;\n"
4031e5c31af7Sopenharmony_ci						  "layout (triangle_strip, max_vertices = 3) out;\n"
4032e5c31af7Sopenharmony_ci						  "\n"
4033e5c31af7Sopenharmony_ci						  "out vec4 out_gs_1;\n"
4034e5c31af7Sopenharmony_ci						  "\n"
4035e5c31af7Sopenharmony_ci						  "void main()\n"
4036e5c31af7Sopenharmony_ci						  "{\n"
4037e5c31af7Sopenharmony_ci						  "    out_gs_1 = vec4(4.0, 3.0, 2.0, 1.0);\n"
4038e5c31af7Sopenharmony_ci						  "\n"
4039e5c31af7Sopenharmony_ci						  "    gl_Position = vec4(0, 0, 0, 1);\n"
4040e5c31af7Sopenharmony_ci						  "    EmitVertex();\n"
4041e5c31af7Sopenharmony_ci						  "\n"
4042e5c31af7Sopenharmony_ci						  "    gl_Position = vec4(1, 0, 0, 1);\n"
4043e5c31af7Sopenharmony_ci						  "    EmitVertex();\n"
4044e5c31af7Sopenharmony_ci						  "\n"
4045e5c31af7Sopenharmony_ci						  "    gl_Position = vec4(1, 1, 0, 1);\n"
4046e5c31af7Sopenharmony_ci						  "    EmitVertex();\n"
4047e5c31af7Sopenharmony_ci						  "\n"
4048e5c31af7Sopenharmony_ci						  "    EndPrimitive();"
4049e5c31af7Sopenharmony_ci						  "}\n";
4050e5c31af7Sopenharmony_ci
4051e5c31af7Sopenharmony_ci	bool		has_shader_compilation_failed = true;
4052e5c31af7Sopenharmony_ci	bool		result						  = true;
4053e5c31af7Sopenharmony_ci	glw::GLenum error						  = GL_NO_ERROR;
4054e5c31af7Sopenharmony_ci
4055e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
4056e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
4057e5c31af7Sopenharmony_ci	{
4058e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
4059e5c31af7Sopenharmony_ci	}
4060e5c31af7Sopenharmony_ci
4061e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4062e5c31af7Sopenharmony_ci
4063e5c31af7Sopenharmony_ci	/* Create program object. */
4064e5c31af7Sopenharmony_ci	m_po_id = gl.createProgram();
4065e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
4066e5c31af7Sopenharmony_ci
4067e5c31af7Sopenharmony_ci	/* Specify output variables to be captured. */
4068e5c31af7Sopenharmony_ci	const char* tf_varyings[] = { "out_gs_1" };
4069e5c31af7Sopenharmony_ci
4070e5c31af7Sopenharmony_ci	gl.transformFeedbackVaryings(m_po_id, 1 /*count*/, tf_varyings, GL_INTERLEAVED_ATTRIBS);
4071e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call(s) failed.");
4072e5c31af7Sopenharmony_ci
4073e5c31af7Sopenharmony_ci	/* Create shader objects. */
4074e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
4075e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
4076e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
4077e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
4078e5c31af7Sopenharmony_ci
4079e5c31af7Sopenharmony_ci	/* Try to link the test program object */
4080e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= specializeShader(1, &minimal_fs_code);
4081e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = fs_code_specialized.c_str();
4082e5c31af7Sopenharmony_ci
4083e5c31af7Sopenharmony_ci	std::string gs_code_specialized		= specializeShader(1, &gs_code);
4084e5c31af7Sopenharmony_ci	const char* gs_code_specialized_raw = gs_code_specialized.c_str();
4085e5c31af7Sopenharmony_ci
4086e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= specializeShader(1, &minimal_vs_code);
4087e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = vs_code_specialized.c_str();
4088e5c31af7Sopenharmony_ci
4089e5c31af7Sopenharmony_ci	if (!TestCaseBase::buildProgram(m_po_id, m_fs_id, 1,				  /* n_sh1_body_parts */
4090e5c31af7Sopenharmony_ci									&fs_code_specialized_raw, m_gs_id, 1, /* n_sh2_body_parts */
4091e5c31af7Sopenharmony_ci									&gs_code_specialized_raw, m_vs_id, 1, /* n_sh3_body_parts */
4092e5c31af7Sopenharmony_ci									&vs_code_specialized_raw, &has_shader_compilation_failed))
4093e5c31af7Sopenharmony_ci	{
4094e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Program object linking failed whereas a success was expected."
4095e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
4096e5c31af7Sopenharmony_ci
4097e5c31af7Sopenharmony_ci		result = false;
4098e5c31af7Sopenharmony_ci		goto end;
4099e5c31af7Sopenharmony_ci	}
4100e5c31af7Sopenharmony_ci
4101e5c31af7Sopenharmony_ci	/* Create Vertex Array Object. */
4102e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
4103e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call(s) failed.");
4104e5c31af7Sopenharmony_ci
4105e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
4106e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call(s) failed.");
4107e5c31af7Sopenharmony_ci
4108e5c31af7Sopenharmony_ci	/* Create Buffer Object for Transform Feedback data. */
4109e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_tfbo_id);
4110e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed.");
4111e5c31af7Sopenharmony_ci
4112e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id);
4113e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed.");
4114e5c31af7Sopenharmony_ci
4115e5c31af7Sopenharmony_ci	gl.bufferData(GL_ARRAY_BUFFER,
4116e5c31af7Sopenharmony_ci				  sizeof(glw::GLfloat) * 4 * 3 /* capture 4 float vector components times 3 triangle vertices */, NULL,
4117e5c31af7Sopenharmony_ci				  GL_STREAM_READ);
4118e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call(s) failed.");
4119e5c31af7Sopenharmony_ci
4120e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*binding index*/, m_tfbo_id);
4121e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call(s) failed.");
4122e5c31af7Sopenharmony_ci
4123e5c31af7Sopenharmony_ci	/* Turn on program object. */
4124e5c31af7Sopenharmony_ci	gl.useProgram(m_po_id);
4125e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed.");
4126e5c31af7Sopenharmony_ci
4127e5c31af7Sopenharmony_ci	gl.enable(GL_RASTERIZER_DISCARD);
4128e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call(s) failed.");
4129e5c31af7Sopenharmony_ci
4130e5c31af7Sopenharmony_ci	gl.beginTransformFeedback(GL_LINES);
4131e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call(s) failed.");
4132e5c31af7Sopenharmony_ci
4133e5c31af7Sopenharmony_ci	gl.drawArrays(GL_TRIANGLES, 0 /*first*/, 3 /*count*/);
4134e5c31af7Sopenharmony_ci
4135e5c31af7Sopenharmony_ci	error = gl.getError();
4136e5c31af7Sopenharmony_ci
4137e5c31af7Sopenharmony_ci	if (error != GL_INVALID_OPERATION)
4138e5c31af7Sopenharmony_ci	{
4139e5c31af7Sopenharmony_ci		result = false;
4140e5c31af7Sopenharmony_ci
4141e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Error different than GL_INVALID_OPEARATION was generated."
4142e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
4143e5c31af7Sopenharmony_ci	}
4144e5c31af7Sopenharmony_ci
4145e5c31af7Sopenharmony_ci	gl.endTransformFeedback();
4146e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call(s) failed.");
4147e5c31af7Sopenharmony_ci
4148e5c31af7Sopenharmony_ci	gl.disable(GL_RASTERIZER_DISCARD);
4149e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call(s) failed.");
4150e5c31af7Sopenharmony_ci
4151e5c31af7Sopenharmony_ciend:
4152e5c31af7Sopenharmony_ci
4153e5c31af7Sopenharmony_ci	if (result)
4154e5c31af7Sopenharmony_ci	{
4155e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4156e5c31af7Sopenharmony_ci	}
4157e5c31af7Sopenharmony_ci	else
4158e5c31af7Sopenharmony_ci	{
4159e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4160e5c31af7Sopenharmony_ci	}
4161e5c31af7Sopenharmony_ci
4162e5c31af7Sopenharmony_ci	return STOP;
4163e5c31af7Sopenharmony_ci}
4164e5c31af7Sopenharmony_ci
4165e5c31af7Sopenharmony_ci/** Constructor
4166e5c31af7Sopenharmony_ci *
4167e5c31af7Sopenharmony_ci * @param context       Test context
4168e5c31af7Sopenharmony_ci * @param extParams     Not used.
4169e5c31af7Sopenharmony_ci * @param name          Test case's name
4170e5c31af7Sopenharmony_ci * @param description   Test case's description
4171e5c31af7Sopenharmony_ci **/
4172e5c31af7Sopenharmony_ciGeometryShaderDrawCallsWhileTFPaused::GeometryShaderDrawCallsWhileTFPaused(Context&				context,
4173e5c31af7Sopenharmony_ci																		   const ExtParameters& extParams,
4174e5c31af7Sopenharmony_ci																		   const char* name, const char* description)
4175e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description), m_fs_id(0), m_gs_id(0), m_tfbo_id(0)
4176e5c31af7Sopenharmony_ci{
4177e5c31af7Sopenharmony_ci	m_vao_id = 0;
4178e5c31af7Sopenharmony_ci	m_vs_id  = 0;
4179e5c31af7Sopenharmony_ci}
4180e5c31af7Sopenharmony_ci
4181e5c31af7Sopenharmony_ci/** Deinitializes GLES objects created during the test. */
4182e5c31af7Sopenharmony_civoid GeometryShaderDrawCallsWhileTFPaused::deinit()
4183e5c31af7Sopenharmony_ci{
4184e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4185e5c31af7Sopenharmony_ci
4186e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
4187e5c31af7Sopenharmony_ci	{
4188e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
4189e5c31af7Sopenharmony_ci		m_fs_id = 0;
4190e5c31af7Sopenharmony_ci	}
4191e5c31af7Sopenharmony_ci
4192e5c31af7Sopenharmony_ci	if (m_gs_id != 0)
4193e5c31af7Sopenharmony_ci	{
4194e5c31af7Sopenharmony_ci		gl.deleteShader(m_gs_id);
4195e5c31af7Sopenharmony_ci		m_gs_id = 0;
4196e5c31af7Sopenharmony_ci	}
4197e5c31af7Sopenharmony_ci
4198e5c31af7Sopenharmony_ci	for (int i = 0; i < 15 /* All combinations of possible inputs and outputs in GS */; ++i)
4199e5c31af7Sopenharmony_ci	{
4200e5c31af7Sopenharmony_ci		if (m_po_ids[i] != 0)
4201e5c31af7Sopenharmony_ci		{
4202e5c31af7Sopenharmony_ci			gl.deleteProgram(m_po_ids[i]);
4203e5c31af7Sopenharmony_ci			m_po_ids[i] = 0;
4204e5c31af7Sopenharmony_ci		}
4205e5c31af7Sopenharmony_ci	}
4206e5c31af7Sopenharmony_ci
4207e5c31af7Sopenharmony_ci	if (m_tfbo_id != 0)
4208e5c31af7Sopenharmony_ci	{
4209e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_tfbo_id);
4210e5c31af7Sopenharmony_ci		m_tfbo_id = 0;
4211e5c31af7Sopenharmony_ci	}
4212e5c31af7Sopenharmony_ci
4213e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
4214e5c31af7Sopenharmony_ci	{
4215e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
4216e5c31af7Sopenharmony_ci		m_vao_id = 0;
4217e5c31af7Sopenharmony_ci	}
4218e5c31af7Sopenharmony_ci
4219e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
4220e5c31af7Sopenharmony_ci	{
4221e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
4222e5c31af7Sopenharmony_ci		m_vs_id = 0;
4223e5c31af7Sopenharmony_ci	}
4224e5c31af7Sopenharmony_ci
4225e5c31af7Sopenharmony_ci	/* Release base class */
4226e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
4227e5c31af7Sopenharmony_ci}
4228e5c31af7Sopenharmony_ci
4229e5c31af7Sopenharmony_ci/** Executes the test.
4230e5c31af7Sopenharmony_ci *
4231e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
4232e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
4233e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
4234e5c31af7Sopenharmony_ci **/
4235e5c31af7Sopenharmony_citcu::TestNode::IterateResult GeometryShaderDrawCallsWhileTFPaused::iterate()
4236e5c31af7Sopenharmony_ci{
4237e5c31af7Sopenharmony_ci	/* Define 15 (all combinations of possible inputs and outputs in geometry shader) Geometry Shaders for purpose of this test. */
4238e5c31af7Sopenharmony_ci	const std::string gs_inputs[]  = { "points", "lines", "lines_adjacency", "triangles", "triangles_adjacency" };
4239e5c31af7Sopenharmony_ci	const std::string gs_outputs[] = { "points", "line_strip", "triangle_strip" };
4240e5c31af7Sopenharmony_ci	const std::string gs_max_output_vertices[] = { "1", "2", "3" };
4241e5c31af7Sopenharmony_ci
4242e5c31af7Sopenharmony_ci	const unsigned short number_of_combinations =
4243e5c31af7Sopenharmony_ci		(sizeof(gs_inputs) / sizeof(gs_inputs[0]) * (sizeof(gs_outputs) / sizeof(gs_outputs[0])));
4244e5c31af7Sopenharmony_ci
4245e5c31af7Sopenharmony_ci	std::string gs_codes[number_of_combinations];
4246e5c31af7Sopenharmony_ci	glw::GLenum errorCode;
4247e5c31af7Sopenharmony_ci
4248e5c31af7Sopenharmony_ci	for (size_t i = 0; i < (sizeof(gs_inputs) / sizeof(gs_inputs[0])) /*5 possible GS inputs*/; ++i)
4249e5c31af7Sopenharmony_ci	{
4250e5c31af7Sopenharmony_ci		for (size_t j = 0; j < (sizeof(gs_outputs) / sizeof(gs_outputs[0])) /*3 possible GS outputs*/; ++j)
4251e5c31af7Sopenharmony_ci		{
4252e5c31af7Sopenharmony_ci			/* This shader will not emit primitives for anything but points.
4253e5c31af7Sopenharmony_ci			 * We do so, because we just need to make sure that, while transform feedback
4254e5c31af7Sopenharmony_ci			 * is paused, all draw calls executed with an active program object which
4255e5c31af7Sopenharmony_ci			 * includes a geometry shader, are valid.
4256e5c31af7Sopenharmony_ci			 */
4257e5c31af7Sopenharmony_ci			gs_codes[j + 3 * i] = "${VERSION}\n"
4258e5c31af7Sopenharmony_ci								  "${GEOMETRY_SHADER_REQUIRE}\n"
4259e5c31af7Sopenharmony_ci								  "\n"
4260e5c31af7Sopenharmony_ci								  "layout (" +
4261e5c31af7Sopenharmony_ci								  gs_inputs[i] + ") in;\n"
4262e5c31af7Sopenharmony_ci												 "layout (" +
4263e5c31af7Sopenharmony_ci								  gs_outputs[j] + ", max_vertices = " + gs_max_output_vertices[j] +
4264e5c31af7Sopenharmony_ci								  ") out;\n"
4265e5c31af7Sopenharmony_ci								  "\n"
4266e5c31af7Sopenharmony_ci								  "out vec2 out_gs_1;\n"
4267e5c31af7Sopenharmony_ci								  "\n"
4268e5c31af7Sopenharmony_ci								  "void main()\n"
4269e5c31af7Sopenharmony_ci								  "{\n"
4270e5c31af7Sopenharmony_ci								  "    out_gs_1    = vec2(1.0, 2.0);\n"
4271e5c31af7Sopenharmony_ci								  "    gl_Position = vec4(0, 0, 0, 1);\n"
4272e5c31af7Sopenharmony_ci								  "    EmitVertex();\n"
4273e5c31af7Sopenharmony_ci								  "}\n";
4274e5c31af7Sopenharmony_ci		}
4275e5c31af7Sopenharmony_ci	}
4276e5c31af7Sopenharmony_ci
4277e5c31af7Sopenharmony_ci	bool			  has_shader_compilation_failed = true;
4278e5c31af7Sopenharmony_ci	bool			  result						= true;
4279e5c31af7Sopenharmony_ci	const glw::GLuint tf_modes[3]					= { GL_POINTS, GL_LINES, GL_TRIANGLES };
4280e5c31af7Sopenharmony_ci	const glw::GLuint draw_call_modes[5]			= { GL_POINTS, GL_LINES, GL_LINES_ADJACENCY, GL_TRIANGLES,
4281e5c31af7Sopenharmony_ci											 GL_TRIANGLES_ADJACENCY };
4282e5c31af7Sopenharmony_ci
4283e5c31af7Sopenharmony_ci	/* This test should only run if EXT_geometry_shader is supported. */
4284e5c31af7Sopenharmony_ci	if (!m_is_geometry_shader_extension_supported)
4285e5c31af7Sopenharmony_ci	{
4286e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
4287e5c31af7Sopenharmony_ci	}
4288e5c31af7Sopenharmony_ci
4289e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4290e5c31af7Sopenharmony_ci
4291e5c31af7Sopenharmony_ci	/* Create program objects. */
4292e5c31af7Sopenharmony_ci	for (int i = 0; i < number_of_combinations; ++i)
4293e5c31af7Sopenharmony_ci	{
4294e5c31af7Sopenharmony_ci		m_po_ids[i] = gl.createProgram();
4295e5c31af7Sopenharmony_ci	}
4296e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed.");
4297e5c31af7Sopenharmony_ci
4298e5c31af7Sopenharmony_ci	/* Specify output variables to be captured. */
4299e5c31af7Sopenharmony_ci	const char* tf_varyings[] = { "out_gs_1" };
4300e5c31af7Sopenharmony_ci
4301e5c31af7Sopenharmony_ci	for (int i = 0; i < number_of_combinations; ++i)
4302e5c31af7Sopenharmony_ci	{
4303e5c31af7Sopenharmony_ci		gl.transformFeedbackVaryings(m_po_ids[i], 1 /*count*/, tf_varyings, GL_INTERLEAVED_ATTRIBS);
4304e5c31af7Sopenharmony_ci	}
4305e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call(s) failed.");
4306e5c31af7Sopenharmony_ci
4307e5c31af7Sopenharmony_ci	/* Create shader objects. */
4308e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
4309e5c31af7Sopenharmony_ci	m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
4310e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
4311e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
4312e5c31af7Sopenharmony_ci
4313e5c31af7Sopenharmony_ci	/* Try to link the test program object */
4314e5c31af7Sopenharmony_ci	std::string fs_code_specialized		= specializeShader(1, &minimal_fs_code);
4315e5c31af7Sopenharmony_ci	const char* fs_code_specialized_raw = fs_code_specialized.c_str();
4316e5c31af7Sopenharmony_ci
4317e5c31af7Sopenharmony_ci	std::string vs_code_specialized		= specializeShader(1, &minimal_vs_code);
4318e5c31af7Sopenharmony_ci	const char* vs_code_specialized_raw = vs_code_specialized.c_str();
4319e5c31af7Sopenharmony_ci
4320e5c31af7Sopenharmony_ci	for (int i = 0; i < number_of_combinations; ++i)
4321e5c31af7Sopenharmony_ci	{
4322e5c31af7Sopenharmony_ci		const char* gs_code					= gs_codes[i].c_str();
4323e5c31af7Sopenharmony_ci		std::string gs_code_specialized		= specializeShader(1, &gs_code);
4324e5c31af7Sopenharmony_ci		const char* gs_code_specialized_raw = gs_code_specialized.c_str();
4325e5c31af7Sopenharmony_ci
4326e5c31af7Sopenharmony_ci		if (!TestCaseBase::buildProgram(m_po_ids[i], m_fs_id, 1,			  /* n_sh1_body_parts */
4327e5c31af7Sopenharmony_ci										&fs_code_specialized_raw, m_gs_id, 1, /* n_sh2_body_parts */
4328e5c31af7Sopenharmony_ci										&gs_code_specialized_raw, m_vs_id, 1, /* n_sh3_body_parts */
4329e5c31af7Sopenharmony_ci										&vs_code_specialized_raw, &has_shader_compilation_failed))
4330e5c31af7Sopenharmony_ci		{
4331e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message
4332e5c31af7Sopenharmony_ci							   << "Program object linking failed whereas a success was expected."
4333e5c31af7Sopenharmony_ci							   << tcu::TestLog::EndMessage;
4334e5c31af7Sopenharmony_ci
4335e5c31af7Sopenharmony_ci			result = false;
4336e5c31af7Sopenharmony_ci		}
4337e5c31af7Sopenharmony_ci	}
4338e5c31af7Sopenharmony_ci
4339e5c31af7Sopenharmony_ci	if (!result)
4340e5c31af7Sopenharmony_ci	{
4341e5c31af7Sopenharmony_ci		goto end;
4342e5c31af7Sopenharmony_ci	}
4343e5c31af7Sopenharmony_ci
4344e5c31af7Sopenharmony_ci	/* Create Vertex Array Object. */
4345e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
4346e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call(s) failed.");
4347e5c31af7Sopenharmony_ci
4348e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
4349e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call(s) failed.");
4350e5c31af7Sopenharmony_ci
4351e5c31af7Sopenharmony_ci	/* Create Buffer Object for Transform Feedback data. */
4352e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_tfbo_id);
4353e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed.");
4354e5c31af7Sopenharmony_ci
4355e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_tfbo_id);
4356e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call(s) failed.");
4357e5c31af7Sopenharmony_ci
4358e5c31af7Sopenharmony_ci	gl.bufferData(GL_ARRAY_BUFFER,
4359e5c31af7Sopenharmony_ci				  sizeof(glw::GLfloat) * 2 * 3 /* capture 2 float vector components times 3 triangle vertices */, NULL,
4360e5c31af7Sopenharmony_ci				  GL_STREAM_READ);
4361e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call(s) failed.");
4362e5c31af7Sopenharmony_ci
4363e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /*binding index*/, m_tfbo_id);
4364e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call(s) failed.");
4365e5c31af7Sopenharmony_ci
4366e5c31af7Sopenharmony_ci	gl.enable(GL_RASTERIZER_DISCARD);
4367e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable() call(s) failed.");
4368e5c31af7Sopenharmony_ci
4369e5c31af7Sopenharmony_ci	for (int i = 0; i < 3 /* number of TF modes */ && result; ++i)
4370e5c31af7Sopenharmony_ci	{
4371e5c31af7Sopenharmony_ci		for (int j = 0; j < 5 /*number of draw call modes*/ && result; ++j)
4372e5c31af7Sopenharmony_ci		{
4373e5c31af7Sopenharmony_ci			for (int k = 0; k < 3 /* number of output GS primitive types */; ++k)
4374e5c31af7Sopenharmony_ci			{
4375e5c31af7Sopenharmony_ci				/* Turn on program object. */
4376e5c31af7Sopenharmony_ci				gl.useProgram(m_po_ids[k + 3 * j]);
4377e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed.");
4378e5c31af7Sopenharmony_ci
4379e5c31af7Sopenharmony_ci				gl.beginTransformFeedback(tf_modes[i]);
4380e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call(s) failed.");
4381e5c31af7Sopenharmony_ci
4382e5c31af7Sopenharmony_ci				gl.pauseTransformFeedback();
4383e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glPauseTransformFeedback() call(s) failed.");
4384e5c31af7Sopenharmony_ci
4385e5c31af7Sopenharmony_ci				gl.drawArrays(draw_call_modes[j], 0 /*first*/, 3 /*count*/);
4386e5c31af7Sopenharmony_ci				errorCode = gl.getError();
4387e5c31af7Sopenharmony_ci
4388e5c31af7Sopenharmony_ci				gl.resumeTransformFeedback();
4389e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glResumeTransformFeedback() call(s) failed.");
4390e5c31af7Sopenharmony_ci
4391e5c31af7Sopenharmony_ci				gl.endTransformFeedback();
4392e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call(s) failed.");
4393e5c31af7Sopenharmony_ci
4394e5c31af7Sopenharmony_ci				/* If draw call fails stop test execution. */
4395e5c31af7Sopenharmony_ci				if (GL_NO_ERROR != errorCode)
4396e5c31af7Sopenharmony_ci				{
4397e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
4398e5c31af7Sopenharmony_ci									   << "glDrawArrays() call generated an error while transform feedback was paused."
4399e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
4400e5c31af7Sopenharmony_ci
4401e5c31af7Sopenharmony_ci					result = false;
4402e5c31af7Sopenharmony_ci					break;
4403e5c31af7Sopenharmony_ci				}
4404e5c31af7Sopenharmony_ci			}
4405e5c31af7Sopenharmony_ci		}
4406e5c31af7Sopenharmony_ci	}
4407e5c31af7Sopenharmony_ci
4408e5c31af7Sopenharmony_ci	gl.disable(GL_RASTERIZER_DISCARD);
4409e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() call(s) failed.");
4410e5c31af7Sopenharmony_ci
4411e5c31af7Sopenharmony_ciend:
4412e5c31af7Sopenharmony_ci
4413e5c31af7Sopenharmony_ci	if (result)
4414e5c31af7Sopenharmony_ci	{
4415e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4416e5c31af7Sopenharmony_ci	}
4417e5c31af7Sopenharmony_ci	else
4418e5c31af7Sopenharmony_ci	{
4419e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4420e5c31af7Sopenharmony_ci	}
4421e5c31af7Sopenharmony_ci
4422e5c31af7Sopenharmony_ci	return STOP;
4423e5c31af7Sopenharmony_ci}
4424e5c31af7Sopenharmony_ci
4425e5c31af7Sopenharmony_ci} // namespace glcts
4426