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 */ 345