Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2 * drawElements Quality Program OpenGL ES 3.1 Module
      3 * -------------------------------------------------
      4 *
      5 * Copyright 2016 The Android Open Source Project
      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
     21 * \brief Negative Shader Storage Buffer Object (SSBO) tests.
     22 *//*--------------------------------------------------------------------*/
     23 #include "es31fNegativeSSBOBlockTests.hpp"
     24 #include "glwDefs.hpp"
     25 #include "glwEnums.hpp"
     26 #include "tcuStringTemplate.hpp"
     27 #include "gluShaderProgram.hpp"
     28 #include <map>
     29 
     30 namespace deqp
     31 {
     32 namespace gles31
     33 {
     34 namespace Functional
     35 {
     36 namespace NegativeTestShared
     37 {
     38 namespace
     39 {
     40 using tcu::TestLog;
     41 using glu::CallLogWrapper;
     42 using namespace glw;
     43 namespace args
     44 {
     45 enum ArgMember
     46 {
     47 	ARGMEMBER_FORMAT			=	0,
     48 	ARGMEMBER_BINDING_POINT,
     49 	ARGMEMBER_MATRIX_ORDER,
     50 	ARGMEMBER_MEMBER_TYPE,
     51 	ARGMEMBER_NAME,
     52 	ARGMEMBER_FIXED_ARRAY,
     53 	ARGMEMBER_VARIABLE_ARRAY,
     54 	ARGMEMBER_REORDER
     55 };
     56 
     57 // key pair ssbo arg data
     58 struct SsboArgData
     59 {
     60 	ArgMember	member;
     61 	std::string	data;
     62 
     63 	SsboArgData(const ArgMember& member_, const std::string& data_)
     64 	{
     65 		member	=	member_;
     66 		data	=	data_;
     67 	}
     68 };
     69 
     70 // class which manages string based argument used to build varying ssbo interface blocks and members
     71 class SsboArgs
     72 {
     73 public:
     74 					SsboArgs(const std::string version, tcu::TestLog& log);
     75 
     76 	void			setSingleValue						(const SsboArgData argData);
     77 	bool			setAllValues						(const std::vector<SsboArgData> argDataList);
     78 
     79 	bool				getMemberReorder				(void) const;
     80 
     81 	void				resetValues						(void);
     82 
     83 	std::map<std::string, std::string>	populateArgsMap	(void) const;
     84 
     85 private:
     86 	std::string		m_negativeContextVersion;
     87 	std::string		m_stdFormat;
     88 	std::string		m_bindingPoint;
     89 	std::string		m_matrixOrder;
     90 	std::string		m_memberType;
     91 	std::string		m_memberName;
     92 	std::string		m_memberFixedArrayerName;
     93 	std::string		m_memberVariableArray;
     94 	bool			m_memberReorder;
     95 	int				m_numberMembers;
     96 	tcu::TestLog&	m_testLog;
     97 
     98 	void			setDefaultValues					(void);
     99 };
    100 
    101 //constructor which ensure a proper context is passed into the struct
    102 SsboArgs::SsboArgs(const std::string version, tcu::TestLog& log)
    103 	: m_negativeContextVersion	(version)
    104 	, m_numberMembers			(8)
    105 	, m_testLog					(log)
    106 {
    107 	setDefaultValues();
    108 }
    109 
    110 void SsboArgs::setSingleValue (const SsboArgData argData)
    111 {
    112 	std::string message;
    113 
    114 	switch (argData.member)
    115 	{
    116 		case ARGMEMBER_FORMAT:
    117 			m_stdFormat					=	argData.data;
    118 			return;
    119 		case ARGMEMBER_BINDING_POINT:
    120 			m_bindingPoint				=	argData.data;
    121 			return;
    122 		case ARGMEMBER_MATRIX_ORDER:
    123 			m_matrixOrder				=	argData.data;
    124 			return;
    125 		case ARGMEMBER_MEMBER_TYPE:
    126 			m_memberType				=	argData.data;
    127 			return;
    128 		case ARGMEMBER_NAME:
    129 			m_memberName				=	argData.data;
    130 			return;
    131 		case ARGMEMBER_FIXED_ARRAY:
    132 			m_memberFixedArrayerName	=	argData.data;
    133 			return;
    134 		case ARGMEMBER_VARIABLE_ARRAY:
    135 			m_memberVariableArray		=	argData.data;
    136 			return;
    137 		case ARGMEMBER_REORDER:
    138 			if (argData.data == "true")
    139 			{
    140 				m_memberReorder			=	true;
    141 			}
    142 			return;
    143 		default:
    144 			message = "auto loop argument data member not recognised.";
    145 			m_testLog << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    146 	}
    147 }
    148 
    149 bool SsboArgs::setAllValues (const std::vector<SsboArgData> argDataList)
    150 {
    151 	std::string	message;
    152 
    153 	if ((argDataList.size() == 0) || (argDataList.size() > (size_t)m_numberMembers))
    154 	{
    155 		message = "set of args does not match the number of args struct changeable members.";
    156 		m_testLog << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    157 
    158 		return false;
    159 	}
    160 	else
    161 	{
    162 		for (unsigned int idx = 0; idx < argDataList.size(); idx++)
    163 		{
    164 			setSingleValue(argDataList[idx]);
    165 		}
    166 	}
    167 
    168 	return true;
    169 }
    170 
    171 bool SsboArgs::getMemberReorder (void) const
    172 {
    173 	return m_memberReorder;
    174 }
    175 
    176 void SsboArgs::resetValues (void)
    177 {
    178 	setDefaultValues();
    179 }
    180 
    181 //converts SsboArgs member variable into a map object to be used by tcu::StringTemplate
    182 std::map<std::string, std::string> SsboArgs::populateArgsMap (void) const
    183 {
    184 	std::map<std::string, std::string> argsMap;
    185 
    186 	// key placeholders located at specific points in the ssbo block
    187 	argsMap["NEGATIVE_CONTEXT_VERSION"]	=	m_negativeContextVersion;
    188 	argsMap["STD_FORMAT"]				=	m_stdFormat;
    189 	argsMap["BINDING_POINT"]			=	m_bindingPoint;
    190 	argsMap["MATRIX_ORDER"]				=	m_matrixOrder;
    191 	argsMap["MEMBER_TYPE"]				=	m_memberType;
    192 	argsMap["MEMBER_NAME"]				=	m_memberName;
    193 	argsMap["MEMBER_FIXED_ARRAY"]		=	m_memberFixedArrayerName;
    194 	argsMap["MEMBER_VARIABLE_ARRAY"]	=	m_memberVariableArray;
    195 
    196 	return argsMap;
    197 }
    198 
    199 // default values i.e. same shader template
    200 void SsboArgs::setDefaultValues (void)
    201 {
    202 	m_stdFormat					=	"std430";
    203 	m_bindingPoint				=	"0";
    204 	m_matrixOrder				=	"column_major";
    205 	m_memberType				=	"int";
    206 	m_memberName				=	"matrix";
    207 	m_memberFixedArrayerName	=	"10";
    208 	m_memberVariableArray		=	"";
    209 	m_memberReorder				=	false;
    210 }
    211 } // args
    212 
    213 std::string generateVaryingSSBOShader(const glw::GLenum shaderType, const args::SsboArgs& args, tcu::TestLog& log)
    214 {
    215 	std::map<std::string, std::string>	argsMap;
    216 	std::ostringstream					source;
    217 	std::string							sourceString;
    218 	std::stringstream					ssboString;
    219 	std::string							message;
    220 
    221 	if (args.getMemberReorder())
    222 	{
    223 		ssboString	<< "	mediump vec4 array_1[${MEMBER_FIXED_ARRAY}];\n"
    224 					<< "	highp mat4 ${MEMBER_NAME};\n"
    225 					<< "	lowp ${MEMBER_TYPE} data;\n"
    226 					<< "	mediump float array_2[${MEMBER_VARIABLE_ARRAY}];\n";
    227 	}
    228 	else
    229 	{
    230 		ssboString	<< "	lowp ${MEMBER_TYPE} data;\n"
    231 					<< "	highp mat4 ${MEMBER_NAME};\n"
    232 					<< "	mediump vec4 array_1[${MEMBER_FIXED_ARRAY}];\n"
    233 					<< "	mediump float array_2[${MEMBER_VARIABLE_ARRAY}];\n";
    234 	}
    235 
    236 	argsMap = args.populateArgsMap();
    237 
    238 	switch (shaderType)
    239 	{
    240 		case GL_VERTEX_SHADER:
    241 		{
    242 			source	<< "${NEGATIVE_CONTEXT_VERSION}\n"
    243 					<< "layout (location = 0) in highp vec4 position;\n"
    244 					<< "layout (location = 1) in mediump vec4 colour;\n"
    245 					<< "out mediump vec4 vertex_colour;\n"
    246 					<< "layout (${STD_FORMAT}, binding = ${BINDING_POINT}, ${MATRIX_ORDER}) buffer ssbo_block\n"
    247 					<< "{\n";
    248 
    249 			source << ssboString.str();
    250 
    251 			source	<< "} ssbo;\n"
    252 					<< "void main()\n"
    253 					<< "{\n"
    254 					<< "	mediump vec4 variable;\n"
    255 					<< "	gl_Position = ssbo.${MEMBER_NAME} * position;\n"
    256 					<< "	for (int idx = 0; idx < ${MEMBER_FIXED_ARRAY}; idx++)\n"
    257 					<< "	{\n"
    258 					<< "		variable += ssbo.array_1[idx];\n"
    259 					<< "	}\n"
    260 					<< "	vertex_colour = colour + variable;\n"
    261 					<< "}\n";
    262 
    263 			sourceString = source.str();
    264 			sourceString = tcu::StringTemplate(sourceString).specialize(argsMap);
    265 
    266 			return sourceString;
    267 		}
    268 
    269 		case GL_FRAGMENT_SHADER:
    270 		{
    271 			source	<< "${NEGATIVE_CONTEXT_VERSION}\n"
    272 					<< "in mediump vec4 vertex_colour;\n"
    273 					<< "layout (location = 0) out mediump vec4 fragment_colour;\n"
    274 					<< "layout (${STD_FORMAT}, binding = ${BINDING_POINT}, ${MATRIX_ORDER}) buffer ssbo_block\n"
    275 					<< "{\n";
    276 
    277 			source << ssboString.str();
    278 
    279 			source	<< "} ssbo;\n"
    280 					<< "void main()\n"
    281 					<< "{\n"
    282 					<< "	mediump vec4 variable;\n"
    283 					<< "	variable * ssbo.${MEMBER_NAME};\n"
    284 					<< "	for (int idx = 0; idx < ${MEMBER_FIXED_ARRAY}; idx++)\n"
    285 					<< "	{\n"
    286 					<< "		variable += ssbo.array_1[idx];\n"
    287 					<< "	}\n"
    288 					<< "	fragment_colour = vertex_colour + variable;\n"
    289 					<< "}\n";
    290 
    291 			sourceString = source.str();
    292 			sourceString = tcu::StringTemplate(sourceString).specialize(argsMap);
    293 
    294 			return sourceString;
    295 		}
    296 
    297 		case GL_GEOMETRY_SHADER:
    298 		{
    299 			// TODO:
    300 			return sourceString;
    301 		}
    302 
    303 		case GL_TESS_CONTROL_SHADER:
    304 		{
    305 			// TODO:
    306 			return sourceString;
    307 		}
    308 
    309 		case GL_TESS_EVALUATION_SHADER:
    310 		{
    311 			// TODO:
    312 			return sourceString;
    313 		}
    314 
    315 		case GL_COMPUTE_SHADER:
    316 		{
    317 			// TODO:
    318 			return sourceString;
    319 		}
    320 
    321 		default:
    322 		{
    323 			message = "shader type not recognised.";
    324 			log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    325 		}
    326 	}
    327 
    328 	return std::string();
    329 }
    330 
    331 void logProgramInfo(NegativeTestContext& ctx, GLint program)
    332 {
    333 	GLint			maxLength	=	0;
    334 	std::string		message;
    335 	tcu::TestLog&	log			=	ctx.getLog();
    336 
    337 	ctx.glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
    338 
    339 	message = "Program log:";
    340 	log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    341 
    342 	if (maxLength == 0)
    343 	{
    344 		message = "No available info log.";
    345 		log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    346 		return;
    347 	}
    348 
    349 	std::vector<GLchar> infoLog(maxLength);
    350 	ctx.glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
    351 
    352 	std::string programLogMessage(&infoLog[0], maxLength);
    353 	log << tcu::TestLog::Message << programLogMessage << tcu::TestLog::EndMessage;
    354 }
    355 
    356 void ssbo_block_matching(NegativeTestContext& ctx)
    357 {
    358 	const bool				isES32													=	contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
    359 	const glu::GLSLVersion	version													=	isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
    360 	tcu::TestLog&			log														=	ctx.getLog();
    361 	std::string				message;
    362 	std::string				versionString(glu::getGLSLVersionDeclaration(version));
    363 	args::SsboArgs			ssboArgs(versionString, log);
    364 	GLint					shaderVertexGL;
    365 	std::string				shaderVertexString;
    366 	const char*				shaderVertexCharPtr;
    367 
    368 	// List of arguments used to create varying ssbo objects in the fragment shader
    369 	const args::SsboArgData argDataArrayFrag[] = {	args::SsboArgData(args::ARGMEMBER_FORMAT,			"std140"),
    370 													args::SsboArgData(args::ARGMEMBER_BINDING_POINT,	"10"),
    371 													args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER,		"row_major"),
    372 													args::SsboArgData(args::ARGMEMBER_MEMBER_TYPE,		"vec2"),
    373 													args::SsboArgData(args::ARGMEMBER_NAME,				"name_changed"),
    374 													args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY,		"20"),
    375 													args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY,	"5"),
    376 													args::SsboArgData(args::ARGMEMBER_REORDER,			"true") };
    377 	std::vector<args::SsboArgData> argDataVectorFrag(argDataArrayFrag, argDataArrayFrag + sizeof(argDataArrayFrag) / sizeof(argDataArrayFrag[0]));
    378 
    379 	// create default vertex shader
    380 	shaderVertexString = generateVaryingSSBOShader(GL_VERTEX_SHADER, ssboArgs, log);
    381 	shaderVertexCharPtr = shaderVertexString.c_str();
    382 	shaderVertexGL = ctx.glCreateShader(GL_VERTEX_SHADER);
    383 
    384 	// log
    385 	message = shaderVertexString;
    386 	log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    387 
    388 	// compile
    389 	ctx.glShaderSource(shaderVertexGL, 1, &shaderVertexCharPtr, DE_NULL);
    390 	ctx.glCompileShader(shaderVertexGL);
    391 
    392 	for (std::size_t idx = 0; idx < argDataVectorFrag.size(); ++idx)
    393 	{
    394 		GLint			linkStatus				=	-1;
    395 		GLint			program;
    396 		GLint			shaderFragmentGL;
    397 		std::string		shaderFragmentString;
    398 		const char*		shaderFragmentCharPtr;
    399 
    400 		ctx.beginSection("Multiple shaders created using SSBO's sharing the same name but not matching layouts");
    401 
    402 		program = ctx.glCreateProgram();
    403 
    404 		// reset args to default and make a single change
    405 		ssboArgs.resetValues();
    406 		ssboArgs.setSingleValue(argDataVectorFrag[idx]);
    407 
    408 		// create fragment shader
    409 		shaderFragmentString = generateVaryingSSBOShader(GL_FRAGMENT_SHADER, ssboArgs, log);
    410 		shaderFragmentCharPtr = shaderFragmentString.c_str();
    411 		shaderFragmentGL = ctx.glCreateShader(GL_FRAGMENT_SHADER);
    412 
    413 		// log
    414 		message = shaderFragmentString;
    415 		log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    416 
    417 		// compile
    418 		ctx.glShaderSource(shaderFragmentGL, 1, &shaderFragmentCharPtr, DE_NULL);
    419 		ctx.glCompileShader(shaderFragmentGL);
    420 
    421 		// attach shaders to program and attempt to link
    422 		ctx.glAttachShader(program, shaderVertexGL);
    423 		ctx.glAttachShader(program, shaderFragmentGL);
    424 		ctx.glLinkProgram(program);
    425 		ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
    426 
    427 		logProgramInfo(ctx, program);
    428 
    429 		if (linkStatus == GL_TRUE)
    430 		{
    431 			ctx.fail("Program should not have linked");
    432 		}
    433 
    434 		// clean up resources
    435 		ctx.glDeleteShader(shaderFragmentGL);
    436 		ctx.glDeleteProgram(program);
    437 
    438 		ctx.endSection();
    439 	}
    440 
    441 	// clean up default resources
    442 	ctx.glDeleteShader(shaderVertexGL);
    443 }
    444 
    445 void ssbo_block_shared_qualifier(NegativeTestContext& ctx)
    446 {
    447 	const bool				isES32													=	contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
    448 	const glu::GLSLVersion	version													=	isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
    449 	tcu::TestLog&			log														=	ctx.getLog();
    450 	std::string				message;
    451 	std::string				versionString(glu::getGLSLVersionDeclaration(version));
    452 	args::SsboArgs			ssboArgs(versionString, log);
    453 	bool					result;
    454 	GLint					shaderVertexGL;
    455 	std::string				shaderVertexString;
    456 	const char*				shaderVertexCharPtr;
    457 
    458 	// default args used in vertex shader ssbo
    459 	const args::SsboArgData argDataArrayVert[] = {	args::SsboArgData(args::ARGMEMBER_FORMAT,			"shared"),
    460 													args::SsboArgData(args::ARGMEMBER_BINDING_POINT,	"0"),
    461 													args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER,		"column_major"),
    462 													args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY,		"10"),
    463 													args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY,	"10"),
    464 													args::SsboArgData(args::ARGMEMBER_REORDER,			"false") };
    465 	std::vector<args::SsboArgData> argDataVectorVert(argDataArrayVert, argDataArrayVert + sizeof(argDataArrayVert) / sizeof(argDataArrayVert[0]));
    466 
    467 	// args changed in fragment shader ssbo
    468 	const args::SsboArgData argDataArrayFrag[] = {	args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER,		"row_major"),
    469 													args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY,	""),
    470 													args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY,		"20") };
    471 	std::vector<args::SsboArgData> argDataVectorFrag(argDataArrayFrag, argDataArrayFrag + sizeof(argDataArrayFrag) / sizeof(argDataArrayFrag[0]));
    472 
    473 	// set default vertex ssbo args
    474 	result = ssboArgs.setAllValues(argDataVectorVert);
    475 
    476 	if (result == false)
    477 	{
    478 		message = "Invalid use of args.setAllValues()";
    479 		log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    480 		return;
    481 	}
    482 
    483 	// create default vertex shader
    484 	shaderVertexString = generateVaryingSSBOShader(GL_VERTEX_SHADER, ssboArgs, log);
    485 	shaderVertexCharPtr = shaderVertexString.c_str();
    486 	shaderVertexGL = ctx.glCreateShader(GL_VERTEX_SHADER);
    487 
    488 	// log
    489 	message = shaderVertexString;
    490 	log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    491 
    492 	// compile
    493 	ctx.glShaderSource(shaderVertexGL, 1, &shaderVertexCharPtr, DE_NULL);
    494 	ctx.glCompileShader(shaderVertexGL);
    495 
    496 	for (std::size_t idx = 0; idx < argDataVectorFrag.size(); idx++)
    497 	{
    498 		GLint		linkStatus				=	-1;
    499 		GLint		program;
    500 		GLint		shaderFragmentGL;
    501 		std::string	shaderFragmentString;
    502 		const char*	shaderFragmentCharPtr;
    503 
    504 		ctx.beginSection("Multiple shaders created using SSBO's sharing the same name but not matching layouts");
    505 
    506 		program = ctx.glCreateProgram();
    507 
    508 		// reset args to default and make a single change
    509 		ssboArgs.setAllValues(argDataVectorVert);
    510 		ssboArgs.setSingleValue(argDataVectorFrag[idx]);
    511 
    512 		// create fragment shader
    513 		shaderFragmentString = generateVaryingSSBOShader(GL_FRAGMENT_SHADER, ssboArgs, log);
    514 		shaderFragmentCharPtr = shaderFragmentString.c_str();
    515 		shaderFragmentGL = ctx.glCreateShader(GL_FRAGMENT_SHADER);
    516 
    517 		// log
    518 		message = shaderFragmentString;
    519 		log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
    520 
    521 		// compile
    522 		ctx.glShaderSource(shaderFragmentGL, 1, &shaderFragmentCharPtr, DE_NULL);
    523 		ctx.glCompileShader(shaderFragmentGL);
    524 
    525 		// attach shaders to the program and attempt to link
    526 		ctx.glAttachShader(program, shaderVertexGL);
    527 		ctx.glAttachShader(program, shaderFragmentGL);
    528 		ctx.glLinkProgram(program);
    529 		ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
    530 
    531 		logProgramInfo(ctx, program);
    532 
    533 		if (linkStatus == GL_TRUE)
    534 		{
    535 			ctx.fail("Program should not have linked");
    536 		}
    537 
    538 		// clean up resources
    539 		ctx.glDeleteShader(shaderFragmentGL);
    540 		ctx.glDeleteProgram(program);
    541 
    542 		ctx.endSection();
    543 	}
    544 
    545 	// clean up default resources
    546 	ctx.glDeleteShader(shaderVertexGL);
    547 }
    548 } // anonymous
    549 
    550 std::vector<FunctionContainer> getNegativeSSBOBlockTestFunctions (void)
    551 {
    552 	const FunctionContainer funcs[] =
    553 	{
    554 		{ ssbo_block_matching,			"ssbo_block_interface_matching_tests",	"Invalid Shader Linkage" },
    555 		{ ssbo_block_shared_qualifier,	"ssbo_using_shared_qualifier_tests",	"Invalid Shader Linkage" },
    556 	};
    557 
    558 	return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
    559 }
    560 } // NegativeTestShared
    561 } //Functional
    562 } //gles31
    563 } //deqp
    564