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, "")
171 , m_shaderData(shaderData)
172 , m_expectedValue(expectedValue)
173 {
174 }
175
iterate(void)176 tcu::TestNode::IterateResult SeparableProgramTFTestCase::iterate(void)
177 {
178 const Functions &gl = m_context.getRenderContext().getFunctions();
179 ContextType contextType = m_context.getRenderContext().getType();
180 GLSLVersion glslVersion = getContextTypeGLSLVersion(contextType);
181
182 /* For core GL gl_PerVertex interface block is combined from two parts.
183 * First part contains definition and the second part name, which is
184 * only specified for tess control stage (arrays are used here to avoid
185 * three branches in a loop). For ES both parts are empty string */
186 const char *blockName[STAGES_COUNT] = {"", ";\n", " gl_out[];\n", ";\n", ";\n"};
187 const char *blockEmptyName[STAGES_COUNT] = {"", "", "", "", ""};
188 std::string vertexBlock("");
189 const char **vertexBlockPostfix = blockEmptyName;
190 if (isContextTypeGLCore(contextType))
191 {
192 vertexBlock = "out gl_PerVertex"
193 "{\n"
194 " vec4 gl_Position;\n"
195 "}";
196 vertexBlockPostfix = blockName;
197 }
198
199 /* Construct specialization map - some specializations differ per stage */
200 std::map<std::string, std::string> specializationMap;
201 specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion);
202
203 /* Create separate programs - start from vertex stage to catch varying names */
204 std::vector<Utils::program> programs(STAGES_COUNT, Utils::program(m_context));
205 const char *code[STAGES_COUNT] = {0, 0, 0, 0, 0};
206 for (int stageIndex = VERTEX_STAGE; stageIndex > -1; --stageIndex)
207 {
208 StageData *stageData = m_shaderData.stage + stageIndex;
209 std::string source = stageData->source;
210 if (source.empty())
211 continue;
212 specializationMap["PERVERTEX_BLOCK"] = vertexBlock + vertexBlockPostfix[stageIndex];
213 std::string specializedShader = StringTemplate(source).specialize(specializationMap);
214
215 code[stageIndex] = specializedShader.c_str();
216 programs[stageIndex].build(0, code[0], code[1], code[2], code[3], code[4], stageData->tfVaryings,
217 stageData->tfVaryingsCount, true);
218 code[stageIndex] = 0;
219
220 /* Use varying name from current stage to specialize next stage */
221 if (stageData->tfVaryings)
222 specializationMap["IN_VARYING_NAME"] = stageData->tfVaryings[0];
223 }
224
225 /* Create program pipeline */
226 GLuint pipelineId;
227 gl.genProgramPipelines(1, &pipelineId);
228 gl.bindProgramPipeline(pipelineId);
229 for (int stageIndex = 0; stageIndex < STAGES_COUNT; ++stageIndex)
230 {
231 if (!programs[stageIndex].m_program_object_id)
232 continue;
233 gl.useProgramStages(pipelineId, StageTokens[stageIndex], programs[stageIndex].m_program_object_id);
234 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
235 }
236
237 /* Validate the pipeline */
238 GLint validateStatus = GL_FALSE;
239 gl.validateProgramPipeline(pipelineId);
240 GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed.");
241 gl.getProgramPipelineiv(pipelineId, GL_VALIDATE_STATUS, &validateStatus);
242 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed.");
243 if (validateStatus != GL_TRUE)
244 {
245 GLint logLength;
246 gl.getProgramPipelineiv(pipelineId, GL_INFO_LOG_LENGTH, &logLength);
247 if (logLength)
248 {
249 std::vector<GLchar> logBuffer(logLength + 1);
250 gl.getProgramPipelineInfoLog(pipelineId, logLength + 1, NULL, &logBuffer[0]);
251 m_context.getTestContext().getLog() << tcu::TestLog::Message << &logBuffer[0] << tcu::TestLog::EndMessage;
252 }
253 TCU_FAIL("Program pipeline has not been validated successfully.");
254 }
255
256 /* Generate buffer object to hold result XFB data */
257 Utils::buffer tfb(m_context);
258 GLsizeiptr tfbSize = 100;
259 tfb.generate(GL_TRANSFORM_FEEDBACK_BUFFER);
260 tfb.update(tfbSize, 0 /* data */, GL_DYNAMIC_COPY);
261 tfb.bindRange(0, 0, tfbSize);
262
263 /* Generate VAO to use for the draw calls */
264 Utils::vertexArray vao(m_context);
265 vao.generate();
266 vao.bind();
267
268 /* Generate query object */
269 GLuint queryId;
270 gl.genQueries(1, &queryId);
271
272 /* Check if tessellation stage is active */
273 GLenum drawMode = GL_POINTS;
274 if (strlen(m_shaderData.stage[TESSELLATION_CONTROL_STAGE].source) > 0)
275 drawMode = GL_PATCHES;
276
277 /* Draw and capture data */
278 gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, queryId);
279 gl.beginTransformFeedback(GL_POINTS);
280 gl.patchParameteri(GL_PATCH_VERTICES, 1);
281 gl.drawArrays(drawMode, 0 /* first */, 1 /* count */);
282 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
283 gl.endTransformFeedback();
284 gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
285
286 /* Get TF results */
287 GLuint writtenPrimitives = 0;
288 gl.getQueryObjectuiv(queryId, GL_QUERY_RESULT, &writtenPrimitives);
289 GLint *feedbackData = (GLint *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfbSize, GL_MAP_READ_BIT);
290 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer");
291
292 /* Verify if only values from upstream shader were captured */
293 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
294 if (writtenPrimitives != 0)
295 {
296 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
297 for (GLuint dataIndex = 0; dataIndex < writtenPrimitives; ++dataIndex)
298 {
299 if (feedbackData[dataIndex] == m_expectedValue)
300 continue;
301 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
302 break;
303 }
304 }
305
306 /* Cleanup */
307 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
308 gl.deleteQueries(1, &queryId);
309 gl.bindProgramPipeline(0);
310 gl.deleteProgramPipelines(1, &pipelineId);
311
312 return STOP;
313 }
314
315 /** Constructor.
316 *
317 * @param context Rendering context.
318 */
SeparableProgramsTransformFeedbackTests(deqp::Context & context)319 SeparableProgramsTransformFeedbackTests::SeparableProgramsTransformFeedbackTests(deqp::Context &context)
320 : deqp::TestCaseGroup(context, "separable_programs_tf", "")
321 {
322 }
323
324 /** Initializes the test group contents. */
init(void)325 void SeparableProgramsTransformFeedbackTests::init(void)
326 {
327 PerStageData tessellation_active = {{
328 {fs_code, NULL, 0}, // fragment stage
329 {"", NULL, 0}, // geometry stage
330 {tcs_code, NULL, 0}, // tesselation control stage
331 {tes_code, tes_tf_varyings, 1}, // tesselation evaluation stage
332 {vs_code, vs_tf_varyings, 1} // vertex_stage
333 }};
334 PerStageData geometry_active = {{
335 {fs_code, NULL, 0}, // fragment stage
336 {gs_code, gs_tf_varyings, 1}, // geometry stage
337 {tcs_code, NULL, 0}, // tesselation control stage
338 {tes_code, tes_tf_varyings, 1}, // tesselation evaluation stage
339 {vs_code, vs_tf_varyings, 1} // vertex_stage
340 }};
341
342 addChild(new SeparableProgramTFTestCase(m_context, "tessellation_active", tessellation_active, 2));
343 addChild(new SeparableProgramTFTestCase(m_context, "geometry_active", geometry_active, 3));
344 }
345
346 } // namespace glcts
347