Home | History | Annotate | Download | only in common
      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