Block/non-block uniforms match
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / common / glcSeparableProgramsTransformFeedbackTests.cpp
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          */
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
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          */
317 SeparableProgramsTransformFeedbackTests::SeparableProgramsTransformFeedbackTests(deqp::Context& context)
318         : deqp::TestCaseGroup(context, "separable_programs_tf", "")
319 {
320 }
321
322 /** Initializes the test group contents. */
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 */