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