1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2017 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * \file glcSeparableProgramXFBTests.cpp
22 */ /*-------------------------------------------------------------------*/
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"
37 using namespace glcts::ViewportArray;
43 * @brief The StageIndex enum. Stages order coresponds to order
44 * in which shader sources are specified in Utils::program::build.
48 FRAGMENT_STAGE_INDEX = 0,
50 TESSELLATION_CONTROL_STAGE,
51 TESSELLATION_EVALUATION_STAGE,
57 * @brief The StageTokens array. Stages order coresponds to order
58 * in which shader sources are specified in Utils::program::build.
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 };
65 * @brief The StageData structure.
70 const GLchar* const* tfVaryings;
71 const GLuint tfVaryingsCount;
75 * @brief The PerStageData structure containimg shader data per all stages.
79 StageData stage[STAGES_COUNT];
82 static const GLchar* vs_code = "${VERSION}\n"
83 "flat out highp int o_vert;\n"
84 "${PERVERTEX_BLOCK}\n"
88 " gl_Position = vec4(1, 0, 0, 1);\n"
91 static const GLchar* vs_tf_varyings[] = { "o_vert" };
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"
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"
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"
114 " gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n"
117 static const GLchar* tes_tf_varyings[] = { "o_tess" };
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"
128 " gl_Position = vec4(-1, -1, 0, 1);\n"
131 " gl_Position = vec4(-1, 1, 0, 1);\n"
134 " gl_Position = vec4(1, -1, 0, 1);\n"
138 static const GLchar* gs_tf_varyings[] = { "o_geom" };
140 static const GLchar* fs_code = "${VERSION}\n"
141 "flat in highp int ${IN_VARYING_NAME};"
142 "out highp vec4 o_color;\n"
145 " o_color = vec4(1.0);\n"
148 class SeparableProgramTFTestCase : public deqp::TestCase
152 SeparableProgramTFTestCase(deqp::Context& context, const char* name, PerStageData shaderData, GLint expectedValue);
154 tcu::TestNode::IterateResult iterate(void);
157 /* Protected attributes */
158 PerStageData m_shaderData;
159 GLint m_expectedValue;
164 * @param context Rendering context
165 * @param name Test name
166 * @param description Test description
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)
174 tcu::TestNode::IterateResult SeparableProgramTFTestCase::iterate(void)
176 const Functions& gl = m_context.getRenderContext().getFunctions();
177 ContextType contextType = m_context.getRenderContext().getType();
178 GLSLVersion glslVersion = getContextTypeGLSLVersion(contextType);
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))
190 vertexBlock = "out gl_PerVertex"
192 " vec4 gl_Position;\n"
194 vertexBlockPostfix = blockName;
197 /* Construct specialization map - some specializations differ per stage */
198 std::map<std::string, std::string> specializationMap;
199 specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion);
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)
206 StageData* stageData = m_shaderData.stage + stageIndex;
207 std::string source = stageData->source;
210 specializationMap["PERVERTEX_BLOCK"] = vertexBlock + vertexBlockPostfix[stageIndex];
211 std::string specializedShader = StringTemplate(source).specialize(specializationMap);
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;
218 /* Use varying name from current stage to specialize next stage */
219 if (stageData->tfVaryings)
220 specializationMap["IN_VARYING_NAME"] = stageData->tfVaryings[0];
223 /* Create program pipeline */
225 gl.genProgramPipelines(1, &pipelineId);
226 gl.bindProgramPipeline(pipelineId);
227 for (int stageIndex = 0; stageIndex < STAGES_COUNT; ++stageIndex)
229 if (!programs[stageIndex].m_program_object_id)
231 gl.useProgramStages(pipelineId, StageTokens[stageIndex], programs[stageIndex].m_program_object_id);
232 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
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)
244 gl.getProgramPipelineiv(pipelineId, GL_INFO_LOG_LENGTH, &logLength);
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;
251 TCU_FAIL("Program pipeline has not been validated successfully.");
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);
261 /* Generate VAO to use for the draw calls */
262 Utils::vertexArray vao(m_context);
266 /* Generate query object */
268 gl.genQueries(1, &queryId);
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;
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);
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");
290 /* Verify if only values from upstream shader were captured */
291 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
292 if (writtenPrimitives != 0)
294 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
295 for (GLuint dataIndex = 0; dataIndex < writtenPrimitives; ++dataIndex)
297 if (feedbackData[dataIndex] == m_expectedValue)
299 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
305 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
306 gl.deleteQueries(1, &queryId);
307 gl.bindProgramPipeline(0);
308 gl.deleteProgramPipelines(1, &pipelineId);
315 * @param context Rendering context.
317 SeparableProgramsTransformFeedbackTests::SeparableProgramsTransformFeedbackTests(deqp::Context& context)
318 : deqp::TestCaseGroup(context, "separable_programs_tf", "")
322 /** Initializes the test group contents. */
323 void SeparableProgramsTransformFeedbackTests::init(void)
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
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
340 addChild(new SeparableProgramTFTestCase(m_context, "tessellation_active", tessellation_active, 2));
341 addChild(new SeparableProgramTFTestCase(m_context, "geometry_active", geometry_active, 3));
344 } /* glcts namespace */