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