1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */ /*!
20  * \file glcSeparableProgramXFBTests.cpp
21  * \brief
22  */ /*-------------------------------------------------------------------*/
23 
24 #include "glcSeparableProgramsTransformFeedbackTests.hpp"
25 #include "glcViewportArrayTests.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "glwFunctions.hpp"
30 #include "tcuCommandLine.hpp"
31 #include "tcuStringTemplate.hpp"
32 #include "tcuTestLog.hpp"
33 
34 using namespace tcu;
35 using namespace glu;
36 using namespace glw;
37 using namespace glcts::ViewportArray;
38 
39 namespace glcts
40 {
41 
42 /**
43  * @brief The StageIndex enum. Stages order coresponds to order
44  * in which shader sources are specified in Utils::program::build.
45  */
46 enum StageIndex
47 {
48 	FRAGMENT_STAGE_INDEX = 0,
49 	GEOMETRY_STAGE_INDEX,
50 	TESSELLATION_CONTROL_STAGE,
51 	TESSELLATION_EVALUATION_STAGE,
52 	VERTEX_STAGE,
53 	STAGES_COUNT
54 };
55 
56 /**
57  * @brief The StageTokens array. Stages order coresponds to order
58  * in which shader sources are specified in Utils::program::build.
59  */
60 static const GLenum StageTokens[STAGES_COUNT] = { GL_FRAGMENT_SHADER_BIT, GL_GEOMETRY_SHADER_BIT,
61 												  GL_TESS_CONTROL_SHADER_BIT, GL_TESS_EVALUATION_SHADER_BIT,
62 												  GL_VERTEX_SHADER_BIT };
63 
64 /**
65  * @brief The StageData structure.
66  */
67 struct StageData
68 {
69 	const GLchar*		 source;
70 	const GLchar* const* tfVaryings;
71 	const GLuint		 tfVaryingsCount;
72 };
73 
74 /**
75  * @brief The PerStageData structure containimg shader data per all stages.
76  */
77 struct PerStageData
78 {
79 	StageData stage[STAGES_COUNT];
80 };
81 
82 static const GLchar* vs_code = "${VERSION}\n"
83 							   "flat out highp int o_vert;\n"
84 							   "${PERVERTEX_BLOCK}\n"
85 							   "void main()\n"
86 							   "{\n"
87 							   "    o_vert = 1;\n"
88 							   "    gl_Position = vec4(1, 0, 0, 1);\n"
89 							   "}\n";
90 
91 static const GLchar* vs_tf_varyings[] = { "o_vert" };
92 
93 static const GLchar* tcs_code = "${VERSION}\n"
94 								"layout(vertices = 1) out;\n"
95 								"flat in highp int o_vert[];\n"
96 								"${PERVERTEX_BLOCK}\n"
97 								"void main()\n"
98 								"{\n"
99 								"    gl_TessLevelInner[0] = 1.0;\n"
100 								"    gl_TessLevelInner[1] = 1.0;\n"
101 								"    gl_TessLevelOuter[0] = 1.0;\n"
102 								"    gl_TessLevelOuter[1] = 1.0;\n"
103 								"    gl_TessLevelOuter[2] = 1.0;\n"
104 								"    gl_TessLevelOuter[3] = 1.0;\n"
105 								"}\n";
106 
107 static const GLchar* tes_code = "${VERSION}\n"
108 								"layout (triangles, point_mode) in;\n"
109 								"flat out highp int o_tess;\n"
110 								"${PERVERTEX_BLOCK}\n"
111 								"void main()\n"
112 								"{\n"
113 								"    o_tess = 2;\n"
114 								"    gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n"
115 								"}\n";
116 
117 static const GLchar* tes_tf_varyings[] = { "o_tess" };
118 
119 static const GLchar* gs_code = "${VERSION}\n"
120 							   "layout (points) in;\n"
121 							   "layout (points, max_vertices = 3) out;\n"
122 							   "${PERVERTEX_BLOCK}\n"
123 							   "flat in highp int ${IN_VARYING_NAME}[];\n"
124 							   "flat out highp int o_geom;\n"
125 							   "void main()\n"
126 							   "{\n"
127 							   "    o_geom = 3;\n"
128 							   "    gl_Position  = vec4(-1, -1, 0, 1);\n"
129 							   "    EmitVertex();\n"
130 							   "    o_geom = 3;\n"
131 							   "    gl_Position  = vec4(-1, 1, 0, 1);\n"
132 							   "    EmitVertex();\n"
133 							   "    o_geom = 3;\n"
134 							   "    gl_Position  = vec4(1, -1, 0, 1);\n"
135 							   "    EmitVertex();\n"
136 							   "}\n";
137 
138 static const GLchar* gs_tf_varyings[] = { "o_geom" };
139 
140 static const GLchar* fs_code = "${VERSION}\n"
141 							   "flat in highp int ${IN_VARYING_NAME};"
142 							   "out highp vec4 o_color;\n"
143 							   "void main()\n"
144 							   "{\n"
145 							   "    o_color = vec4(1.0);\n"
146 							   "}\n";
147 
148 class SeparableProgramTFTestCase : public deqp::TestCase
149 {
150 public:
151 	/* Public methods */
152 	SeparableProgramTFTestCase(deqp::Context& context, const char* name, PerStageData shaderData, GLint expectedValue);
153 
154 	tcu::TestNode::IterateResult iterate(void);
155 
156 protected:
157 	/* Protected attributes */
158 	PerStageData m_shaderData;
159 	GLint		 m_expectedValue;
160 };
161 
162 /** Constructor.
163 	 *
164 	 *  @param context     Rendering context
165 	 *  @param name        Test name
166 	 *  @param description Test description
167 	 */
SeparableProgramTFTestCase(deqp::Context& context, const char* name, PerStageData shaderData, GLint expectedValue)168 SeparableProgramTFTestCase::SeparableProgramTFTestCase(deqp::Context& context, const char* name,
169 													   PerStageData shaderData, GLint expectedValue)
170 	: deqp::TestCase(context, name, ""), m_shaderData(shaderData), m_expectedValue(expectedValue)
171 {
172 }
173 
iterate(void)174 tcu::TestNode::IterateResult SeparableProgramTFTestCase::iterate(void)
175 {
176 	const Functions& gl			 = m_context.getRenderContext().getFunctions();
177 	ContextType		 contextType = m_context.getRenderContext().getType();
178 	GLSLVersion		 glslVersion = getContextTypeGLSLVersion(contextType);
179 
180 	/* For core GL gl_PerVertex interface block is combined from two parts.
181 	 * First part contains definition and the second part name, which is
182 	 * only specified for tess control stage (arrays are used here to avoid
183 	 * three branches in a loop). For ES both parts are empty string */
184 	const char*  blockName[STAGES_COUNT]	  = { "", ";\n", " gl_out[];\n", ";\n", ";\n" };
185 	const char*  blockEmptyName[STAGES_COUNT] = { "", "", "", "", "" };
186 	std::string  vertexBlock("");
187 	const char** vertexBlockPostfix = blockEmptyName;
188 	if (isContextTypeGLCore(contextType))
189 	{
190 		vertexBlock = "out gl_PerVertex"
191 					  "{\n"
192 					  "    vec4 gl_Position;\n"
193 					  "}";
194 		vertexBlockPostfix = blockName;
195 	}
196 
197 	/* Construct specialization map - some specializations differ per stage */
198 	std::map<std::string, std::string> specializationMap;
199 	specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion);
200 
201 	/* Create separate programs - start from vertex stage to catch varying names */
202 	std::vector<Utils::program> programs(STAGES_COUNT, Utils::program(m_context));
203 	const char*					code[STAGES_COUNT] = { 0, 0, 0, 0, 0 };
204 	for (int stageIndex = VERTEX_STAGE; stageIndex > -1; --stageIndex)
205 	{
206 		StageData*  stageData = m_shaderData.stage + stageIndex;
207 		std::string source	= stageData->source;
208 		if (source.empty())
209 			continue;
210 		specializationMap["PERVERTEX_BLOCK"] = vertexBlock + vertexBlockPostfix[stageIndex];
211 		std::string specializedShader		 = StringTemplate(source).specialize(specializationMap);
212 
213 		code[stageIndex] = specializedShader.c_str();
214 		programs[stageIndex].build(0, code[0], code[1], code[2], code[3], code[4], stageData->tfVaryings,
215 								   stageData->tfVaryingsCount, true);
216 		code[stageIndex] = 0;
217 
218 		/* Use varying name from current stage to specialize next stage */
219 		if (stageData->tfVaryings)
220 			specializationMap["IN_VARYING_NAME"] = stageData->tfVaryings[0];
221 	}
222 
223 	/* Create program pipeline */
224 	GLuint pipelineId;
225 	gl.genProgramPipelines(1, &pipelineId);
226 	gl.bindProgramPipeline(pipelineId);
227 	for (int stageIndex = 0; stageIndex < STAGES_COUNT; ++stageIndex)
228 	{
229 		if (!programs[stageIndex].m_program_object_id)
230 			continue;
231 		gl.useProgramStages(pipelineId, StageTokens[stageIndex], programs[stageIndex].m_program_object_id);
232 		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
233 	}
234 
235 	/* Validate the pipeline */
236 	GLint validateStatus = GL_FALSE;
237 	gl.validateProgramPipeline(pipelineId);
238 	GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed.");
239 	gl.getProgramPipelineiv(pipelineId, GL_VALIDATE_STATUS, &validateStatus);
240 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed.");
241 	if (validateStatus != GL_TRUE)
242 	{
243 		GLint logLength;
244 		gl.getProgramPipelineiv(pipelineId, GL_INFO_LOG_LENGTH, &logLength);
245 		if (logLength)
246 		{
247 			std::vector<GLchar> logBuffer(logLength + 1);
248 			gl.getProgramPipelineInfoLog(pipelineId, logLength + 1, NULL, &logBuffer[0]);
249 			m_context.getTestContext().getLog() << tcu::TestLog::Message << &logBuffer[0] << tcu::TestLog::EndMessage;
250 		}
251 		TCU_FAIL("Program pipeline has not been validated successfully.");
252 	}
253 
254 	/* Generate buffer object to hold result XFB data */
255 	Utils::buffer tfb(m_context);
256 	GLsizeiptr	tfbSize = 100;
257 	tfb.generate(GL_TRANSFORM_FEEDBACK_BUFFER);
258 	tfb.update(tfbSize, 0 /* data */, GL_DYNAMIC_COPY);
259 	tfb.bindRange(0, 0, tfbSize);
260 
261 	/* Generate VAO to use for the draw calls */
262 	Utils::vertexArray vao(m_context);
263 	vao.generate();
264 	vao.bind();
265 
266 	/* Generate query object */
267 	GLuint queryId;
268 	gl.genQueries(1, &queryId);
269 
270 	/* Check if tessellation stage is active */
271 	GLenum drawMode = GL_POINTS;
272 	if (strlen(m_shaderData.stage[TESSELLATION_CONTROL_STAGE].source) > 0)
273 		drawMode = GL_PATCHES;
274 
275 	/* Draw and capture data */
276 	gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, queryId);
277 	gl.beginTransformFeedback(GL_POINTS);
278 	gl.patchParameteri(GL_PATCH_VERTICES, 1);
279 	gl.drawArrays(drawMode, 0 /* first */, 1 /* count */);
280 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
281 	gl.endTransformFeedback();
282 	gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
283 
284 	/* Get TF results */
285 	GLuint writtenPrimitives = 0;
286 	gl.getQueryObjectuiv(queryId, GL_QUERY_RESULT, &writtenPrimitives);
287 	GLint* feedbackData = (GLint*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfbSize, GL_MAP_READ_BIT);
288 	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer");
289 
290 	/* Verify if only values from upstream shader were captured */
291 	m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
292 	if (writtenPrimitives != 0)
293 	{
294 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
295 		for (GLuint dataIndex = 0; dataIndex < writtenPrimitives; ++dataIndex)
296 		{
297 			if (feedbackData[dataIndex] == m_expectedValue)
298 				continue;
299 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
300 			break;
301 		}
302 	}
303 
304 	/* Cleanup */
305 	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
306 	gl.deleteQueries(1, &queryId);
307 	gl.bindProgramPipeline(0);
308 	gl.deleteProgramPipelines(1, &pipelineId);
309 
310 	return STOP;
311 }
312 
313 /** Constructor.
314 	 *
315 	 *  @param context Rendering context.
316 	 */
SeparableProgramsTransformFeedbackTests(deqp::Context& context)317 SeparableProgramsTransformFeedbackTests::SeparableProgramsTransformFeedbackTests(deqp::Context& context)
318 	: deqp::TestCaseGroup(context, "separable_programs_tf", "")
319 {
320 }
321 
322 /** Initializes the test group contents. */
init(void)323 void SeparableProgramsTransformFeedbackTests::init(void)
324 {
325 	PerStageData tessellation_active = { {
326 		{ fs_code, NULL, 0 },			  // fragment stage
327 		{ "", NULL, 0 },				  // geometry stage
328 		{ tcs_code, NULL, 0 },			  // tesselation control stage
329 		{ tes_code, tes_tf_varyings, 1 }, // tesselation evaluation stage
330 		{ vs_code, vs_tf_varyings, 1 }	// vertex_stage
331 	} };
332 	PerStageData geometry_active = { {
333 		{ fs_code, NULL, 0 },			  // fragment stage
334 		{ gs_code, gs_tf_varyings, 1 },   // geometry stage
335 		{ tcs_code, NULL, 0 },			  // tesselation control stage
336 		{ tes_code, tes_tf_varyings, 1 }, // tesselation evaluation stage
337 		{ vs_code, vs_tf_varyings, 1 }	// vertex_stage
338 	} };
339 
340 	addChild(new SeparableProgramTFTestCase(m_context, "tessellation_active", tessellation_active, 2));
341 	addChild(new SeparableProgramTFTestCase(m_context, "geometry_active", geometry_active, 3));
342 }
343 
344 } /* glcts namespace */
345