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 
SsboArgDatadeqp::gles31::Functional::NegativeTestShared::__anon48126c2d0111::args::SsboArgData63 	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
SsboArgs(const std::string version,tcu::TestLog & log)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 
setSingleValue(const SsboArgData argData)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 
setAllValues(const std::vector<SsboArgData> argDataList)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 
getContextVersion(void) const180 const std::string& SsboArgs::getContextVersion (void) const
181 {
182 	return m_negativeContextVersion;
183 }
184 
getStdFormat(void) const185 const std::string& SsboArgs::getStdFormat (void) const
186 {
187 	return m_stdFormat;
188 }
189 
getBindingPoint(void) const190 const std::string& SsboArgs::getBindingPoint (void) const
191 {
192 	return m_bindingPoint;
193 }
194 
getMatrixOrder(void) const195 const std::string& SsboArgs::getMatrixOrder (void) const
196 {
197 	return m_matrixOrder;
198 }
199 
getMemberType(void) const200 const std::string& SsboArgs::getMemberType (void) const
201 {
202 	return m_memberType;
203 }
204 
getMemberName(void) const205 const std::string& SsboArgs::getMemberName (void) const
206 {
207 	return m_memberName;
208 }
209 
getMemberFixedArrayName(void) const210 const std::string& SsboArgs::getMemberFixedArrayName (void) const
211 {
212 	return m_memberFixedArrayerName;
213 }
214 
getMemberVariableArray(void) const215 const std::string& SsboArgs::getMemberVariableArray (void) const
216 {
217 	return m_memberVariableArray;
218 }
219 
getMemberReorder(void) const220 bool SsboArgs::getMemberReorder (void) const
221 {
222 	return m_memberReorder;
223 }
224 
getNumberMembers(void) const225 int SsboArgs::getNumberMembers (void) const
226 {
227 	return m_numberMembers;
228 }
229 
resetValues(void)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
populateArgsMap(void) const236 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
setDefaultValues(void)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 
generateVaryingSSBOShader(const glw::GLenum shaderType,const args::SsboArgs & args,tcu::TestLog & log)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 
logProgramInfo(NegativeTestContext & ctx,GLint program)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 
ssbo_block_matching(NegativeTestContext & ctx)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 
ssbo_block_shared_qualifier(NegativeTestContext & ctx)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 
getNegativeSSBOBlockTestFunctions(void)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