1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 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
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23#include "es31cLayoutBindingTests.hpp"
24
25#include "tcuRenderTarget.hpp"
26#include "tcuStringTemplate.hpp"
27#include "tcuSurface.hpp"
28#include "tcuTestLog.hpp"
29#include "tcuTexture.hpp"
30#include "tcuTextureUtil.hpp"
31
32#include "deRandom.hpp"
33#include "deStringUtil.hpp"
34
35#include "glwDefs.hpp"
36#include "glwEnums.hpp"
37#include "glwFunctions.hpp"
38
39#include "gluDrawUtil.hpp"
40#include "gluPixelTransfer.hpp"
41#include "gluShaderProgram.hpp"
42#include "gluTexture.hpp"
43#include "gluTextureUtil.hpp"
44
45namespace glcts
46{
47
48//=========================================================================
49//= typedefs
50//=========================================================================
51typedef std::string String;
52typedef std::map<String, String>		 StringMap;
53typedef std::map<String, glw::GLint>	 StringIntMap;
54typedef std::map<glw::GLint, glw::GLint> IntIntMap;
55typedef std::vector<String> StringVector;
56typedef std::vector<int>	IntVector;
57
58typedef std::map<int, glu::Texture2D*>		Texture2DMap;
59typedef std::map<int, glu::Texture2DArray*> Texture2DArrayMap;
60typedef std::map<int, glu::Texture3D*>		Texture3DMap;
61
62//=========================================================================
63//= utility classes
64//=========================================================================
65
66//= string stream that saves some typing
67class StringStream : public std::ostringstream
68{
69public:
70	void reset()
71	{
72		clear();
73		str("");
74	}
75};
76
77class LayoutBindingProgram;
78
79class IProgramContextSupplier
80{
81public:
82	virtual ~IProgramContextSupplier()
83	{
84	}
85	virtual Context&					   getContext()		   = 0;
86	virtual const LayoutBindingParameters& getTestParameters() = 0;
87	virtual eStageType					   getStage()		   = 0;
88	virtual const String& getSource(eStageType stage)		   = 0;
89	virtual LayoutBindingProgram* createProgram()			   = 0;
90};
91
92class LayoutBindingProgram
93{
94public:
95	LayoutBindingProgram(IProgramContextSupplier& contextSupplier)
96		: m_contextSupplier(contextSupplier)
97		, m_context(contextSupplier.getContext().getRenderContext())
98		, m_stage(contextSupplier.getStage())
99		, m_testParams(contextSupplier.getTestParameters())
100		, m_gl(contextSupplier.getContext().getRenderContext().getFunctions())
101	{
102		if (getStage() != ComputeShader)
103			m_program = new glu::ShaderProgram(
104				m_context, glu::makeVtxFragSources(m_contextSupplier.getSource(VertexShader).c_str(),
105												   m_contextSupplier.getSource(FragmentShader).c_str()));
106		else
107			m_program = new glu::ShaderProgram(
108				m_context,
109				glu::ProgramSources() << glu::ComputeSource(m_contextSupplier.getSource(ComputeShader).c_str()));
110	}
111	virtual ~LayoutBindingProgram()
112	{
113		delete m_program;
114	}
115
116	class LayoutBindingProgramAutoPtr
117	{
118	public:
119		LayoutBindingProgramAutoPtr(IProgramContextSupplier& contextSupplier)
120		{
121			m_program = contextSupplier.createProgram();
122		}
123		~LayoutBindingProgramAutoPtr()
124		{
125			delete m_program;
126		}
127		LayoutBindingProgram* operator->()
128		{
129			return m_program;
130		}
131
132	private:
133		LayoutBindingProgram* m_program;
134	};
135
136	String getErrorLog(bool dumpShaders = false)
137	{
138		StringStream errLog;
139
140		if (getStage() != ComputeShader)
141		{
142			const glu::ShaderInfo& fragmentShaderInfo = m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT);
143			const glu::ShaderInfo& vertexShaderInfo   = m_program->getShaderInfo(glu::SHADERTYPE_VERTEX);
144
145			if (!fragmentShaderInfo.compileOk || !m_program->getProgramInfo().linkOk || dumpShaders)
146			{
147				errLog << "### dump of " << stageToName(FragmentShader) << "###\n";
148				String msg((dumpShaders ? "Fragment shader should not have compiled" :
149										  "Vertex shader compile failed while testing "));
150				errLog << "Fragment shader compile failed while testing " << stageToName(getStage()) << ": "
151					   << fragmentShaderInfo.infoLog << "\n";
152				errLog << m_contextSupplier.getSource(FragmentShader);
153			}
154			if (!vertexShaderInfo.compileOk || !m_program->getProgramInfo().linkOk || dumpShaders)
155			{
156				errLog << "### dump of " << stageToName(VertexShader) << "###\n";
157				String msg((dumpShaders ? "Vertex shader should not have compiled" :
158										  "Vertex shader compile failed while testing "));
159				errLog << msg << stageToName(getStage()) << ": " << vertexShaderInfo.infoLog << "\n";
160				errLog << m_contextSupplier.getSource(VertexShader);
161			}
162		}
163		else
164		{
165			const glu::ShaderInfo& computeShaderInfo = m_program->getShaderInfo(glu::SHADERTYPE_COMPUTE);
166
167			if (!computeShaderInfo.compileOk || !m_program->getProgramInfo().linkOk || dumpShaders)
168			{
169				errLog << "### dump of " << stageToName(ComputeShader) << "###\n";
170				String msg((dumpShaders ? "Compute shader should not have compiled" :
171										  "Compute shader compile failed while testing "));
172				errLog << msg << stageToName(ComputeShader) << ": " << computeShaderInfo.infoLog << "\n";
173				errLog << m_contextSupplier.getSource(ComputeShader);
174			}
175		}
176		if (!m_program->getProgramInfo().linkOk)
177		{
178			getStage();
179			errLog << "Linking failed while testing " << stageToName(getStage()) << ": "
180				   << m_program->getProgramInfo().infoLog << "\n";
181			errLog << "### other stages ###\n";
182			switch (getStage())
183			{
184			case FragmentShader:
185				errLog << "### dump of " << stageToName(VertexShader) << "###\n";
186				errLog << m_contextSupplier.getSource(VertexShader);
187				break;
188			case VertexShader:
189				errLog << "### dump of " << stageToName(FragmentShader) << "###\n";
190				errLog << stageToName(FragmentShader) << "\n";
191				errLog << m_contextSupplier.getSource(FragmentShader);
192				break;
193			case ComputeShader:
194				errLog << "### dump of " << stageToName(ComputeShader) << "###\n";
195				errLog << stageToName(ComputeShader) << "\n";
196				errLog << m_contextSupplier.getSource(ComputeShader);
197				break;
198			default:
199				DE_ASSERT(0);
200				break;
201			}
202		}
203		return errLog.str();
204	}
205
206private:
207	IProgramContextSupplier& m_contextSupplier;
208
209	const glu::RenderContext&	  m_context;
210	const eStageType			   m_stage;		 // shader stage currently tested
211	const LayoutBindingParameters& m_testParams; // parameters for shader generation (table at end of file)
212	const glw::Functions&		   m_gl;
213
214	glu::ShaderProgram* m_program;
215
216private:
217	StringIntMap getUniformLocations(StringVector args) const
218	{
219		StringVector::iterator it;
220		StringIntMap		   locations;
221		bool				   passed = true;
222
223		for (it = args.begin(); it != args.end(); it++)
224		{
225			const char* name	 = (*it).c_str();
226			glw::GLint  location = m_gl.getUniformLocation(getProgram(), name);
227			passed &= (0 <= location);
228			if (passed)
229			{
230				locations[name] = location;
231			}
232		}
233
234		return locations;
235	}
236
237public:
238	glw::GLint getProgram() const
239	{
240		return m_program->getProgram();
241	}
242
243	const glw::Functions& gl() const
244	{
245		return m_gl;
246	}
247
248	virtual eStageType getStage() const
249	{
250		return m_stage;
251	}
252
253	String stageToName(eStageType stage) const
254	{
255		switch (stage)
256		{
257		case FragmentShader:
258			return "FragmentShader";
259		case VertexShader:
260			return "VertexShader";
261		case ComputeShader:
262			return "ComputeShader";
263		default:
264			DE_ASSERT(0);
265			break;
266		}
267		return String();
268	}
269
270	bool error() const
271	{
272		return (m_gl.getError() == GL_NO_ERROR);
273	}
274
275	bool compiledAndLinked() const
276	{
277		if (getStage() != ComputeShader)
278			return m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk &&
279				   m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk && m_program->getProgramInfo().linkOk;
280
281		return m_program->getShaderInfo(glu::SHADERTYPE_COMPUTE).compileOk && m_program->getProgramInfo().linkOk;
282	}
283
284	virtual StringIntMap getBindingPoints(StringVector args) const
285	{
286		StringIntMap bindingPoints;
287
288		StringIntMap locations = getUniformLocations(args);
289		if (!locations.empty())
290		{
291			glw::GLint bindingPoint;
292			for (StringIntMap::iterator it = locations.begin(); it != locations.end(); it++)
293			{
294				glw::GLint location = it->second;
295				m_gl.getUniformiv(getProgram(), location, &bindingPoint);
296				bool hasNoError = (GL_NO_ERROR == m_gl.getError());
297				if (hasNoError)
298				{
299					bindingPoints[it->first] = bindingPoint;
300				}
301			}
302		}
303		return bindingPoints;
304	}
305
306	virtual bool setBindingPoints(StringVector list, glw::GLint bindingPoint) const
307	{
308		bool bNoError = true;
309
310		StringIntMap locations = getUniformLocations(list);
311		if (!locations.empty())
312		{
313			for (StringIntMap::iterator it = locations.begin(); it != locations.end(); it++)
314			{
315				m_gl.uniform1i(it->second, bindingPoint);
316				bNoError &= (GL_NO_ERROR == m_gl.getError());
317			}
318		}
319		return bNoError;
320	}
321
322	virtual StringIntMap getOffsets(StringVector /*args*/) const
323	{
324		return StringIntMap();
325	}
326};
327
328class LayoutBindingTestResult
329{
330public:
331	LayoutBindingTestResult(bool passed = true, const String& reason = String(), bool notRunforThisContext = false)
332		: m_passed(passed), m_notRunForThisContext(notRunforThisContext), m_reason(reason)
333	{
334	}
335
336public:
337	bool testPassed() const
338	{
339		return m_passed;
340	}
341
342	String getReason() const
343	{
344		return m_reason;
345	}
346
347	bool runForThisContext() const
348	{
349		return !m_notRunForThisContext;
350	}
351
352private:
353	bool   m_passed;
354	bool   m_notRunForThisContext;
355	String m_reason;
356};
357
358class IntegerConstant
359{
360public:
361	enum Literals
362	{
363		decimal = 0,
364		decimal_u,
365		decimal_U,
366		octal,
367		octal_u,
368		octal_U,
369		hex_x,
370		hex_X,
371		hex_u,
372		hex_u_X,
373		hex_U,
374		hex_U_X,
375		last
376	};
377
378public:
379	IntegerConstant(Literals lit, int ai) : asInt(ai)
380	{
381		StringStream s;
382		switch (lit)
383		{
384		case decimal:
385			s << asInt;
386			break;
387		case decimal_u:
388			s << asInt << "u";
389			break;
390		case decimal_U:
391			s << asInt << "U";
392			break;
393		case octal:
394			s << "0" << std::oct << asInt;
395			break;
396		case octal_u:
397			s << "0" << std::oct << asInt << "u";
398			break;
399		case octal_U:
400			s << "0" << std::oct << asInt << "U";
401			break;
402		case hex_x:
403			s << "0x" << std::hex << asInt;
404			break;
405		case hex_X:
406			s << "0X" << std::hex << asInt;
407			break;
408		case hex_u:
409			s << "0x" << std::hex << asInt << "u";
410			break;
411		case hex_u_X:
412			s << "0X" << std::hex << asInt << "u";
413			break;
414		case hex_U:
415			s << "0x" << std::hex << asInt << "U";
416			break;
417		case hex_U_X:
418			s << "0X" << std::hex << asInt << "U";
419			break;
420		case last:
421		default:
422			DE_ASSERT(0);
423		}
424
425		asString = s.str();
426	}
427
428public:
429	String asString;
430	int	asInt;
431};
432
433//*****************************************************************************
434class LayoutBindingBaseCase : public TestCase, public IProgramContextSupplier
435{
436public:
437	LayoutBindingBaseCase(Context& context, const char* name, const char* description, StageType stage,
438						  LayoutBindingParameters& samplerType, glu::GLSLVersion glslVersion);
439	virtual ~LayoutBindingBaseCase(void);
440
441	IterateResult iterate(void);
442
443	// overrideable subtests
444	virtual LayoutBindingTestResult binding_basic_default(void);
445	virtual LayoutBindingTestResult binding_basic_explicit(void);
446	virtual LayoutBindingTestResult binding_basic_multiple(void);
447	virtual LayoutBindingTestResult binding_basic_render(void);
448	virtual LayoutBindingTestResult binding_integer_constant(void);
449	virtual LayoutBindingTestResult binding_integer_constant_expression(void);
450	virtual LayoutBindingTestResult binding_array_size(void);
451	virtual LayoutBindingTestResult binding_array_implicit(void);
452	virtual LayoutBindingTestResult binding_array_multiple(void);
453	virtual LayoutBindingTestResult binding_api_update(void);
454	virtual LayoutBindingTestResult binding_compilation_errors(void);
455	virtual LayoutBindingTestResult binding_link_errors(void);
456	virtual LayoutBindingTestResult binding_examples(void);
457	virtual LayoutBindingTestResult binding_mixed_order(void);
458
459private:
460	// drawTest normal vs. compute
461	typedef LayoutBindingTestResult (LayoutBindingBaseCase::*LayoutBindingDrawTestPtr)(glw::GLint program, int binding);
462
463	LayoutBindingDrawTestPtr m_drawTest;
464
465	// pointer type for subtests
466	typedef LayoutBindingTestResult (LayoutBindingBaseCase::*LayoutBindingSubTestPtr)();
467
468	// test table entry
469	struct LayoutBindingSubTest
470	{
471		char const*				name;
472		char const*				description;
473		LayoutBindingSubTestPtr test;
474	};
475
476	// IProgramContextSupplier interface
477protected:
478	const LayoutBindingParameters& getTestParameters()
479	{
480		return m_testParams;
481	}
482
483	const glu::RenderContext& getRenderContext()
484	{
485		return m_context.getRenderContext();
486	}
487
488	virtual eStageType getStage()
489	{
490		return m_stage.type;
491	}
492
493	const String& getSource(eStageType stage)
494	{
495		return m_sources[stage];
496	}
497
498	Context& getContext()
499	{
500		return m_context;
501	}
502
503	const glw::Functions& gl()
504	{
505		return m_context.getRenderContext().getFunctions();
506	}
507
508	bool needsPrecision() const
509	{
510		if (isContextTypeES(m_context.getRenderContext().getType()) || m_glslVersion == glu::GLSL_VERSION_450)
511		{
512			return (m_testParams.surface_type != UniformBlock) && (m_testParams.surface_type != ShaderStorageBuffer);
513		}
514		else
515		{
516			return (m_testParams.surface_type != UniformBlock) && (m_testParams.surface_type != ShaderStorageBuffer) &&
517				   (m_testParams.surface_type != AtomicCounter) && (m_testParams.surface_type != Image);
518		}
519	}
520
521protected:
522	std::vector<int> makeSparseRange(int maxElement, int minElement = 0) const
523	{
524		static float	   rangeT[]		 = { 0.0f, 0.1f, 0.5f, 0.6f, 0.9f, 1.0f };
525		std::vector<float> rangeTemplate = makeVector(rangeT);
526		float			   max			 = rangeTemplate.back();
527		float			   range		 = (float)((maxElement - 1) - minElement);
528
529		std::vector<int> result;
530		for (std::vector<float>::iterator it = rangeTemplate.begin(); it != rangeTemplate.end(); it++)
531		{
532			float e = *it;
533			e		= (e * range) / max;
534			result.insert(result.end(), minElement + (int)e);
535		}
536		return result;
537	}
538
539	glu::GLSLVersion getGLSLVersion()
540	{
541		return m_glslVersion;
542	}
543
544	bool isStage(eStageType stage)
545	{
546		return (stage == m_stage.type);
547	}
548
549	void setTemplateParam(eStageType stage, const char* param, const String& value)
550	{
551		m_templateParams[stage][param] = value.c_str();
552	}
553
554	void setTemplateParam(const char* param, const String& value)
555	{
556		setTemplateParam(m_stage.type, param, value);
557	}
558
559	void updateTemplate(eStageType stage)
560	{
561		m_sources[stage] = tcu::StringTemplate(m_templates[stage]).specialize(m_templateParams[stage]);
562	}
563
564	void updateTemplate()
565	{
566		updateTemplate(m_stage.type);
567	}
568
569	template <class T0, class T1>
570	String generateLog(const String& msg, T0 result, T1 expected)
571	{
572		StringStream s;
573		s << msg << " expected: " << expected << " actual: " << result << "\n";
574		s << getSource(VertexShader) << "\n";
575		s << getSource(FragmentShader) << "\n";
576		return s.str();
577	}
578
579private:
580	std::vector<LayoutBindingSubTest> m_tests;
581
582	void init(void)
583	{
584		m_drawTest =
585			(getStage() == ComputeShader) ? &LayoutBindingBaseCase::drawTestCompute : &LayoutBindingBaseCase::drawTest;
586
587#define MAKE_TEST_ENTRY(__subtest_name__) { #__subtest_name__, "", &LayoutBindingBaseCase::__subtest_name__ }
588		LayoutBindingSubTest tests[] = {
589			MAKE_TEST_ENTRY(binding_basic_default),		 MAKE_TEST_ENTRY(binding_basic_explicit),
590			MAKE_TEST_ENTRY(binding_basic_multiple),	 MAKE_TEST_ENTRY(binding_basic_render),
591			MAKE_TEST_ENTRY(binding_integer_constant),   MAKE_TEST_ENTRY(binding_integer_constant_expression),
592			MAKE_TEST_ENTRY(binding_array_size),		 MAKE_TEST_ENTRY(binding_array_implicit),
593			MAKE_TEST_ENTRY(binding_array_multiple),	 MAKE_TEST_ENTRY(binding_api_update),
594			MAKE_TEST_ENTRY(binding_compilation_errors), MAKE_TEST_ENTRY(binding_link_errors),
595			MAKE_TEST_ENTRY(binding_examples),			 MAKE_TEST_ENTRY(binding_mixed_order)
596		};
597		m_tests = makeVector(tests);
598
599		m_uniformDeclTemplate = "${LAYOUT}${KEYWORD}${UNIFORM_TYPE}${UNIFORM_BLOCK_NAME}${UNIFORM_BLOCK}${UNIFORM_"
600								"INSTANCE_NAME}${UNIFORM_ARRAY};\n";
601
602		m_expectedColor = tcu::Vec4(0.0, 1.0f, 0.0f, 1.0f);
603
604		switch (getTestParameters().texture_type)
605		{
606		case TwoD:
607		{
608			// 2D
609			glu::ImmutableTexture2D* texture2D =
610				new glu::ImmutableTexture2D(getContext().getRenderContext(), GL_RGBA8, 2, 2);
611
612			texture2D->getRefTexture().allocLevel(0);
613			tcu::clear(texture2D->getRefTexture().getLevel(0), m_expectedColor);
614			texture2D->upload();
615
616			if (m_textures2D.find(0) != m_textures2D.end())
617			{
618				delete m_textures2D[0];
619			}
620
621			m_textures2D[0] = texture2D;
622		}
623		break;
624		case TwoDArray:
625		{
626			// 2DArray
627			glu::Texture2DArray* texture2DArray =
628				new glu::Texture2DArray(getContext().getRenderContext(), GL_RGBA8, 2, 2, 1);
629
630			texture2DArray->getRefTexture().allocLevel(0);
631			tcu::clear(texture2DArray->getRefTexture().getLevel(0), m_expectedColor);
632			texture2DArray->upload();
633
634			if (m_textures2DArray.find(0) != m_textures2DArray.end())
635			{
636				delete m_textures2DArray[0];
637			}
638
639			m_textures2DArray[0] = texture2DArray;
640		}
641		break;
642		// 3D
643		case ThreeD:
644		{
645			glu::Texture3D* texture3D = new glu::Texture3D(getContext().getRenderContext(), GL_RGBA8, 2, 2, 1);
646
647			texture3D->getRefTexture().allocLevel(0);
648			tcu::clear(texture3D->getRefTexture().getLevel(0), m_expectedColor);
649			texture3D->upload();
650
651			if (m_textures3D.find(0) != m_textures3D.end())
652			{
653				delete m_textures3D[0];
654			}
655
656			m_textures3D[0] = texture3D;
657		}
658		break;
659		case None:
660			// test case where no texture allocation is needed
661			break;
662		default:
663			DE_ASSERT(0);
664			break;
665		}
666	}
667
668	String initDefaultVSContext()
669	{
670		m_templates[VertexShader] = "${VERSION}"
671									"layout(location=0) in vec2 inPosition;\n"
672									"${UNIFORM_DECL}\n"
673									"flat out ${OUT_VAR_TYPE} fragColor;\n"
674									"${OPTIONAL_FUNCTION_BLOCK}\n"
675									"void main(void)\n"
676									"{\n"
677									"  ${OUT_ASSIGNMENT} ${UNIFORM_ACCESS}\n"
678									"  gl_Position = vec4(inPosition, 0.0, 1.0);\n"
679									"}\n";
680
681		StringMap& args = m_templateParams[VertexShader];
682		// some samplers and all images don't have default precision qualifier (sampler3D)
683		// so append a precision default in all sampler and image cases.
684		StringStream s;
685		s << glu::getGLSLVersionDeclaration(m_glslVersion) << "\n";
686		s << "precision highp float;\n";
687		if (needsPrecision())
688		{
689			s << "precision highp " << getTestParameters().uniform_type << ";\n";
690		}
691
692		args["VERSION"]					= s.str();
693		args["UNIFORM_DECL"]			= "";
694		args["OPTIONAL_FUNCTION_BLOCK"] = "";
695		args["UNIFORM_ACCESS"]			= "";
696		args["OUT_ASSIGNMENT"]			= "fragColor =";
697		args["OUT_VAR_TYPE"]			= getTestParameters().vector_type;
698		args["OUT_VAR"]					= "fragColor";
699		if (m_stage.type != VertexShader)
700		{
701			args["OUT_ASSIGNMENT"] = "";
702		}
703		return tcu::StringTemplate(m_templates[VertexShader]).specialize(args);
704	}
705
706	String initDefaultFSContext()
707	{
708		// build fragment shader
709		m_templates[FragmentShader] = "${VERSION}"
710									  "layout(location=0) out ${OUT_VAR_TYPE} ${OUT_VAR};\n"
711									  "flat in ${OUT_VAR_TYPE} fragColor;\n"
712									  "${UNIFORM_DECL}\n"
713									  "${OPTIONAL_FUNCTION_BLOCK}\n"
714									  "void main(void)\n"
715									  "{\n"
716									  "  ${OUT_ASSIGNMENT} ${UNIFORM_ACCESS}\n"
717									  "}\n";
718
719		StringMap& args = m_templateParams[FragmentShader];
720		// samplers and images don't have default precision qualifier
721		StringStream s;
722		s << glu::getGLSLVersionDeclaration(m_glslVersion) << "\n";
723		s << "precision highp float;\n";
724		if (needsPrecision())
725		{
726			s << "precision highp " << getTestParameters().uniform_type << ";\n";
727		}
728		args["VERSION"]					= s.str();
729		args["OUT_VAR_TYPE"]			= getTestParameters().vector_type;
730		args["UNIFORM_ACCESS"]			= "vec4(0.0,0.0,0.0,0.0);";
731		args["UNIFORM_DECL"]			= "";
732		args["OPTIONAL_FUNCTION_BLOCK"] = "";
733		args["OUT_ASSIGNMENT"]			= "outColor =";
734		args["OUT_VAR"]					= "outColor";
735		// must have a linkage between stage and fragment shader
736		// that the compiler can't optimize away
737		if (FragmentShader != m_stage.type)
738		{
739			args["UNIFORM_ACCESS"] = "fragColor;";
740		}
741		return tcu::StringTemplate(m_templates[FragmentShader]).specialize(args);
742	}
743
744	String initDefaultCSContext()
745	{
746		// build compute shader
747		m_templates[ComputeShader] = "${VERSION}"
748									 "${UNIFORM_DECL}\n"
749									 "${OPTIONAL_FUNCTION_BLOCK}\n"
750									 "void main(void)\n"
751									 "{\n"
752									 "  ${OUT_VAR_TYPE} tmp = ${UNIFORM_ACCESS}\n"
753									 "  ${OUT_ASSIGNMENT} tmp ${OUT_END}\n"
754									 "}\n";
755
756		StringMap& args = m_templateParams[ComputeShader];
757		// images don't have default precision qualifier
758		StringStream s;
759		s << glu::getGLSLVersionDeclaration(m_glslVersion) << "\n";
760		s << "layout (local_size_x = 1) in;\n"
761			 "precision highp float;\n";
762		if (needsPrecision())
763		{
764			s << "precision highp " << getTestParameters().uniform_type << ";\n";
765		}
766
767		// bindings are per uniform type...
768		if (getTestParameters().surface_type == Image)
769		{
770			s << "layout(binding=0, std430) buffer outData {\n"
771				 "    "
772			  << getTestParameters().vector_type << " outColor;\n"
773													"};\n";
774			args["OUT_ASSIGNMENT"] = "outColor =";
775			args["OUT_END"]		   = ";";
776		}
777		else
778		{
779			s << "layout(binding=0, rgba8) uniform highp writeonly image2D outImage;\n";
780			args["OUT_ASSIGNMENT"] = "imageStore(outImage, ivec2(0), ";
781			args["OUT_END"]		   = ");";
782		}
783		args["VERSION"]					= s.str();
784		args["OUT_VAR_TYPE"]			= getTestParameters().vector_type;
785		args["UNIFORM_ACCESS"]			= "vec4(0.0,0.0,0.0,0.0);";
786		args["UNIFORM_DECL"]			= "";
787		args["OPTIONAL_FUNCTION_BLOCK"] = "";
788
789		return tcu::StringTemplate(m_templates[ComputeShader]).specialize(args);
790	}
791
792protected:
793	String buildUniformDecl(const String& keyword, const String& layout, const String& uniform_type,
794							const String& uniform_block_name, const String& uniform_block,
795							const String& uniform_instance, const String& uniform_array) const
796	{
797		StringMap args;
798		setArg(args["LAYOUT"], layout);
799		setArg(args["KEYWORD"], keyword);
800		if (uniform_block_name.empty())
801			setArg(args["UNIFORM_TYPE"], uniform_type);
802		else
803			args["UNIFORM_TYPE"] = "";
804		if (!uniform_instance.empty() && !uniform_block_name.empty())
805			setArg(args["UNIFORM_BLOCK_NAME"], uniform_block_name + "_block");
806		else
807			setArg(args["UNIFORM_BLOCK_NAME"], uniform_block_name);
808		setArg(args["UNIFORM_BLOCK"], uniform_block);
809		if ((uniform_block_name.empty() && uniform_block.empty()) || !uniform_array.empty())
810			args["UNIFORM_INSTANCE_NAME"] = uniform_instance;
811		else
812			args["UNIFORM_INSTANCE_NAME"] = "";
813		args["UNIFORM_ARRAY"]			  = uniform_array;
814		return tcu::StringTemplate(m_uniformDeclTemplate).specialize(args);
815	}
816
817	virtual String getDefaultUniformName(int idx = 0)
818	{
819		StringStream s;
820		s << "uniform" << idx;
821		return s.str();
822	}
823
824	virtual String buildUniformName(String& var)
825	{
826		std::ostringstream s;
827		s << var;
828		return s.str();
829	}
830
831	virtual String buildLayout(const String& binding)
832	{
833		std::ostringstream s;
834		if (!binding.empty())
835			s << "layout(binding=" << binding << ") ";
836		return s.str();
837	}
838
839	virtual String buildLayout(int binding)
840	{
841		std::ostringstream bindingStr;
842		bindingStr << binding;
843		return buildLayout(bindingStr.str());
844	}
845
846	virtual String buildAccess(const String& var)
847	{
848		std::ostringstream s;
849		s << getTestParameters().access_function << "(" << var << "," << getTestParameters().coord_vector_type << "(0)"
850		  << ")";
851		return s.str();
852	}
853
854	virtual String buildBlockName(const String& /*name*/)
855	{
856		return String();
857	}
858
859	virtual String buildBlock(const String& /*name*/, const String& /*type*/ = String("float"))
860	{
861		return String();
862	}
863
864	virtual String buildArray(int idx)
865	{
866		StringStream s;
867		s << "[" << idx << "]";
868		return s.str();
869	}
870
871	virtual String buildArrayAccess(int uniform, int idx)
872	{
873		StringStream s;
874		s << getDefaultUniformName(uniform) << buildArray(idx);
875		if (!buildBlockName(getDefaultUniformName()).empty())
876		{
877			s << "." << getDefaultUniformName(uniform);
878		}
879		return s.str();
880	}
881
882	// return max. binding point allowed
883	virtual int maxBindings()
884	{
885		int units = 0;
886
887		if (getTestParameters().surface_type == Image)
888		{
889			gl().getIntegerv(GL_MAX_IMAGE_UNITS, &units);
890		}
891		else
892		{
893			gl().getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &units);
894		}
895
896		return units;
897	}
898
899	// return max. array size allowed
900	virtual int maxArraySize()
901	{
902		int units = 0;
903
904		if (getTestParameters().surface_type == Image)
905		{
906			switch (m_stage.type)
907			{
908			case VertexShader:
909				gl().getIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &units);
910				break;
911			case FragmentShader:
912				gl().getIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &units);
913				break;
914			default:
915				DE_ASSERT(0);
916				break;
917			}
918		}
919		else
920		{
921			switch (m_stage.type)
922			{
923			case VertexShader:
924				gl().getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &units);
925				break;
926			case FragmentShader:
927				gl().getIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &units);
928				break;
929			default:
930				DE_ASSERT(0);
931				break;
932			}
933		}
934
935		return units;
936	}
937
938	virtual bool isSupported()
939	{
940		return (maxArraySize() > 0);
941	}
942
943	virtual void bind(int binding)
944	{
945		glw::GLint texTarget = 0;
946		glw::GLint texName   = 0;
947
948		switch (getTestParameters().texture_type)
949		{
950		case TwoD:
951			texTarget = GL_TEXTURE_2D;
952			texName   = m_textures2D[0]->getGLTexture();
953			break;
954		case TwoDArray:
955			texTarget = GL_TEXTURE_2D_ARRAY;
956			texName   = m_textures2DArray[0]->getGLTexture();
957			break;
958		case ThreeD:
959			texTarget = GL_TEXTURE_3D;
960			texName   = m_textures3D[0]->getGLTexture();
961			break;
962		default:
963			DE_ASSERT(0);
964			break;
965		}
966
967		switch (getTestParameters().surface_type)
968		{
969		case Texture:
970			gl().activeTexture(GL_TEXTURE0 + binding);
971			gl().bindTexture(texTarget, texName);
972			gl().texParameteri(texTarget, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(tcu::Sampler::CLAMP_TO_EDGE));
973			gl().texParameteri(texTarget, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(tcu::Sampler::CLAMP_TO_EDGE));
974			gl().texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(tcu::Sampler::NEAREST));
975			gl().texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(tcu::Sampler::NEAREST));
976			break;
977		case Image:
978			gl().bindImageTexture(binding, texName, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
979			break;
980		default:
981			DE_ASSERT(0);
982			break;
983		}
984	}
985
986	virtual void unbind(int binding)
987	{
988		glw::GLint texTarget = 0;
989
990		switch (getTestParameters().texture_type)
991		{
992		case TwoD:
993			texTarget = GL_TEXTURE_2D;
994			break;
995		case TwoDArray:
996			texTarget = GL_TEXTURE_2D_ARRAY;
997			break;
998		case ThreeD:
999			texTarget = GL_TEXTURE_3D;
1000			break;
1001		default:
1002			DE_ASSERT(0);
1003			break;
1004		}
1005
1006		switch (getTestParameters().surface_type)
1007		{
1008		case Texture:
1009			gl().activeTexture(GL_TEXTURE0 + binding);
1010			gl().bindTexture(texTarget, 0);
1011			break;
1012		case Image:
1013			gl().bindImageTexture(binding, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32F);
1014			break;
1015		default:
1016			DE_ASSERT(0);
1017			break;
1018		}
1019	}
1020
1021	virtual LayoutBindingTestResult drawTest(glw::GLint program, int binding);
1022	virtual LayoutBindingTestResult drawTestCompute(glw::GLint program, int binding);
1023
1024	// allocate resources needed for all subtests, i.e. textures
1025	virtual void setupTest()
1026	{
1027	}
1028
1029	// cleanup resources needed for all subtests
1030	virtual void teardownTest()
1031	{
1032		for (Texture2DMap::iterator it = m_textures2D.begin(); it != m_textures2D.end(); it++)
1033		{
1034			delete it->second;
1035		}
1036		m_textures2D.clear();
1037
1038		for (Texture2DArrayMap::iterator it = m_textures2DArray.begin(); it != m_textures2DArray.end(); it++)
1039		{
1040			delete it->second;
1041		}
1042		m_textures2DArray.clear();
1043
1044		for (Texture3DMap::iterator it = m_textures3D.begin(); it != m_textures3D.end(); it++)
1045		{
1046			delete it->second;
1047		}
1048		m_textures3D.clear();
1049	}
1050
1051private:
1052	// appends a space to the argument (make shader source pretty)
1053	void setArg(String& arg, const String& value) const
1054	{
1055		if (!value.empty())
1056			arg = value + String(" ");
1057		else
1058			arg = String();
1059	}
1060
1061private:
1062	LayoutBindingParameters m_testParams;
1063	StageType				m_stage;
1064
1065	std::map<eStageType, String>	  m_sources;
1066	std::map<eStageType, StringMap>   m_templateParams;
1067	std::map<eStageType, const char*> m_templates;
1068
1069	Texture2DMap	  m_textures2D;
1070	Texture2DArrayMap m_textures2DArray;
1071	Texture3DMap	  m_textures3D;
1072	tcu::Vec4		  m_expectedColor;
1073
1074	const char* m_uniformDeclTemplate;
1075
1076	glu::GLSLVersion m_glslVersion;
1077};
1078
1079LayoutBindingBaseCase::LayoutBindingBaseCase(Context& context, const char* name, const char* description,
1080											 StageType stage, LayoutBindingParameters& samplerType,
1081											 glu::GLSLVersion glslVersion)
1082	: TestCase(context, name, description)
1083	, m_drawTest(DE_NULL)
1084	, m_testParams(samplerType)
1085	, m_stage(stage)
1086	, m_uniformDeclTemplate(DE_NULL)
1087	, m_glslVersion(glslVersion)
1088{
1089}
1090
1091LayoutBindingBaseCase::~LayoutBindingBaseCase(void)
1092{
1093	teardownTest();
1094}
1095
1096LayoutBindingBaseCase::IterateResult LayoutBindingBaseCase::iterate(void)
1097{
1098	tcu::TestLog& log	= m_context.getTestContext().getLog();
1099	bool		  passed = true;
1100
1101	if (!isSupported())
1102	{
1103		log << tcu::TestLog::Section("NotSupported", "");
1104		log << tcu::TestLog::Message << "This test was not run as minimum requirements were not met."
1105			<< tcu::TestLog::EndMessage;
1106		log << tcu::TestLog::EndSection;
1107		getContext().getTestContext().setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "NotSupported");
1108		return STOP;
1109	}
1110
1111	// init test case (create shader templates and textures)
1112	init();
1113
1114	// allocate resources for all subtests
1115	setupTest();
1116
1117	for (std::vector<LayoutBindingSubTest>::iterator it = m_tests.begin(); it != m_tests.end(); it++)
1118	{
1119		// need to reset templates and their args to a clean state before every
1120		// test to avoid bleeding.
1121		m_sources[VertexShader]   = initDefaultVSContext();
1122		m_sources[FragmentShader] = initDefaultFSContext();
1123		m_sources[ComputeShader]  = initDefaultCSContext();
1124
1125		LayoutBindingTestResult result = ((*this).*((*it).test))();
1126		if (!result.testPassed())
1127		{
1128			log << tcu::TestLog::Section((*it).name, (*it).description);
1129			log << tcu::TestLog::Message << result.getReason() << tcu::TestLog::EndMessage;
1130			log << tcu::TestLog::EndSection;
1131		}
1132		if (!result.runForThisContext())
1133		{
1134			log << tcu::TestLog::Section((*it).name, (*it).description);
1135			log << tcu::TestLog::Message << "This test was not run for this context as it does not apply."
1136				<< tcu::TestLog::EndMessage;
1137			log << tcu::TestLog::EndSection;
1138		}
1139		passed &= result.testPassed();
1140	}
1141
1142	// cleanup resources
1143	teardownTest();
1144
1145	/*=========================================================================
1146	 TEST results
1147	 =========================================================================*/
1148
1149	getContext().getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
1150												passed ? "Pass" : "Fail");
1151
1152	return STOP;
1153}
1154
1155/*=========================================================================
1156 // bind resource to specified binding point and program and
1157 // dispatch a computation, read back image at (0,0)
1158 =========================================================================*/
1159LayoutBindingTestResult LayoutBindingBaseCase::drawTestCompute(glw::GLint program, int binding)
1160{
1161	const glw::Functions& l_gl   = getContext().getRenderContext().getFunctions();
1162	bool				  passed = true;
1163
1164	DE_TEST_ASSERT(getStage() == ComputeShader);
1165
1166	l_gl.useProgram(program);
1167
1168	deUint32 fb_or_ssb;
1169
1170	if (getTestParameters().surface_type == Image)
1171	{
1172		bind(binding);
1173
1174		glw::GLfloat buffer[4] = { 0.1f, 0.2f, 0.3f, 0.4f };
1175		l_gl.genBuffers(1, &fb_or_ssb);
1176		l_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, fb_or_ssb);
1177
1178		l_gl.bufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(glw::GLfloat), buffer, GL_DYNAMIC_COPY);
1179
1180		l_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, fb_or_ssb);
1181
1182		l_gl.dispatchCompute(1, 1, 1);
1183		l_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1184
1185		tcu::Vec4 pixel =
1186			*(tcu::Vec4*)l_gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * sizeof(glw::GLfloat), GL_MAP_READ_BIT);
1187		l_gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1188
1189		l_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1190		l_gl.deleteBuffers(1, &fb_or_ssb);
1191
1192		unbind(binding);
1193
1194		tcu::Vec4 expected(0.0f, 1.0f, 0.0f, 1.0f);
1195		passed = (pixel == expected);
1196		if (!passed)
1197		{
1198			return LayoutBindingTestResult(passed, generateLog(String("drawTestCompute failed"), expected, pixel));
1199		}
1200	}
1201	else
1202	{
1203		deUint32 something = 0x01020304, tex;
1204
1205		l_gl.genTextures(1, &tex);
1206		l_gl.bindTexture(GL_TEXTURE_2D, tex);
1207		l_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1208		l_gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1209		l_gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &something);
1210
1211		bind(binding);
1212
1213		l_gl.bindImageTexture(0, tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
1214
1215		l_gl.dispatchCompute(1, 1, 1);
1216		l_gl.memoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1217
1218		l_gl.bindImageTexture(0, 0, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
1219
1220		l_gl.genFramebuffers(1, &fb_or_ssb);
1221		l_gl.bindFramebuffer(GL_FRAMEBUFFER, fb_or_ssb);
1222		l_gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
1223
1224		l_gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &something);
1225
1226		l_gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1227		l_gl.deleteFramebuffers(1, &fb_or_ssb);
1228		l_gl.deleteTextures(1, &tex);
1229
1230		unbind(binding);
1231
1232		const deUint32 expected = 0xff00ff00;
1233		passed					= (expected == something);
1234		if (!passed)
1235		{
1236			return LayoutBindingTestResult(
1237				passed, generateLog(String("drawTestCompute failed"), tcu::RGBA(expected), tcu::RGBA(something)));
1238		}
1239	}
1240
1241	return passed;
1242}
1243
1244/*=========================================================================
1245 // bind resource to specified binding point and program and
1246 // return result of comparison of rendered pixel at (0,0) with expected
1247 =========================================================================*/
1248LayoutBindingTestResult LayoutBindingBaseCase::drawTest(glw::GLint program, int binding)
1249{
1250	const glw::Functions&	GL			  = getContext().getRenderContext().getFunctions();
1251	const tcu::RenderTarget& renderTarget = getContext().getRenderContext().getRenderTarget();
1252	glw::GLuint				 viewportW	= renderTarget.getWidth();
1253	glw::GLuint				 viewportH	= renderTarget.getHeight();
1254	tcu::Surface			 renderedFrame(viewportW, viewportH);
1255	bool					 passed = true;
1256
1257	DE_TEST_ASSERT(getStage() != ComputeShader);
1258
1259	GL.viewport(0, 0, viewportW, viewportH);
1260	GL.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1261	GL.clear(GL_COLOR_BUFFER_BIT);
1262
1263	static const float position[] = {
1264		-1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
1265	};
1266	static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
1267
1268	GL.useProgram(program);
1269
1270	bind(binding);
1271
1272	static const glu::VertexArrayBinding vertexArrays[] = {
1273		glu::va::Float("inPosition", 2, 4, 0, &position[0]),
1274	};
1275	glu::draw(getContext().getRenderContext(), program, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
1276			  glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
1277
1278	glu::readPixels(getContext().getRenderContext(), 0, 0, renderedFrame.getAccess());
1279
1280	tcu::RGBA pixel = renderedFrame.getPixel(0, 0);
1281
1282	passed = (pixel == tcu::RGBA(m_expectedColor));
1283
1284	unbind(binding);
1285
1286	if (!passed)
1287	{
1288		return LayoutBindingTestResult(passed,
1289									   generateLog(String("drawTest failed"), m_expectedColor, pixel.getPacked()));
1290	}
1291
1292	return true;
1293}
1294
1295//== verify that binding point is default w/o layout binding
1296LayoutBindingTestResult LayoutBindingBaseCase::binding_basic_default()
1297{
1298	bool passed = true;
1299
1300	StringStream s;
1301	s << buildAccess(getDefaultUniformName()) << ";\n";
1302	setTemplateParam("UNIFORM_ACCESS", s.str());
1303
1304	String decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(String()),
1305								   String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1306								   buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1307	setTemplateParam("UNIFORM_DECL", decl);
1308	updateTemplate();
1309
1310	LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1311	passed &= program->compiledAndLinked();
1312	if (!passed)
1313	{
1314		return LayoutBindingTestResult(passed, program->getErrorLog());
1315	}
1316
1317	StringVector  list;
1318	const String& u = buildBlockName(getDefaultUniformName());
1319	if (!u.empty())
1320		list.push_back(u + "_block");
1321	else
1322		list.push_back(getDefaultUniformName());
1323
1324	StringIntMap bindingPoints = program->getBindingPoints(list);
1325
1326	passed &= bindingPoints.size() == list.size() && (bindingPoints[u] == 0);
1327	if (!passed)
1328	{
1329		return LayoutBindingTestResult(passed,
1330									   generateLog(String("binding point did not match default"), bindingPoints[u], 0));
1331	}
1332
1333	return true;
1334}
1335
1336//== verify that binding point has specified value
1337LayoutBindingTestResult LayoutBindingBaseCase::binding_basic_explicit()
1338{
1339	bool passed = true;
1340
1341	{
1342		StringStream s;
1343		s << buildAccess(getDefaultUniformName()) << ";\n";
1344		setTemplateParam("UNIFORM_ACCESS", s.str());
1345	}
1346
1347	std::vector<int> bindings = makeSparseRange(maxBindings());
1348	for (std::vector<int>::iterator it = bindings.begin(); it < bindings.end(); it++)
1349	{
1350		int	binding = *it;
1351		String decl =
1352			buildUniformDecl(String(getTestParameters().keyword), buildLayout(binding),
1353							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1354							 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1355		setTemplateParam("UNIFORM_DECL", decl);
1356		updateTemplate();
1357
1358		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1359		passed &= program->compiledAndLinked();
1360		if (!passed)
1361		{
1362			return LayoutBindingTestResult(passed, program->getErrorLog());
1363		}
1364
1365		StringVector  list;
1366		const String& s = buildBlockName(getDefaultUniformName());
1367		if (!s.empty())
1368			list.push_back(s + "_block");
1369		else
1370			list.push_back(getDefaultUniformName());
1371
1372		StringIntMap bindingPoints = program->getBindingPoints(list);
1373		passed &= bindingPoints.size() == list.size() && (binding == bindingPoints[list[0]]);
1374		if (!passed)
1375		{
1376			return LayoutBindingTestResult(
1377				passed, generateLog(String("binding point did not match default"), bindingPoints[list[0]], binding));
1378		}
1379	}
1380	return true;
1381}
1382
1383//== verify that binding works with multiple samplers (same binding points)
1384LayoutBindingTestResult LayoutBindingBaseCase::binding_basic_multiple()
1385{
1386	bool passed = true;
1387
1388	glw::GLint baseBindingPoint = maxBindings() - 1;
1389
1390	String decl0 = buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1391									String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1392									buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1393	String decl1 = buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1394									String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName(1)),
1395									buildBlock(getDefaultUniformName(1)), getDefaultUniformName(1), String());
1396	setTemplateParam("UNIFORM_DECL", decl0 + decl1);
1397
1398	StringStream s;
1399	s << buildAccess(getDefaultUniformName()) << " + " << buildAccess(getDefaultUniformName(1)) << ";\n";
1400	setTemplateParam("UNIFORM_ACCESS", s.str());
1401	updateTemplate();
1402
1403	LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1404	passed &= program->compiledAndLinked();
1405	if (!passed)
1406	{
1407		return LayoutBindingTestResult(passed, program->getErrorLog());
1408	}
1409
1410	StringVector list;
1411	String		 u = buildBlockName(getDefaultUniformName());
1412	if (!u.empty())
1413		list.push_back(u + "_block");
1414	else
1415		list.push_back(getDefaultUniformName());
1416
1417	u = buildBlockName(getDefaultUniformName(1));
1418	if (!u.empty())
1419		list.push_back(u + "_block");
1420	else
1421		list.push_back(getDefaultUniformName(1));
1422
1423	StringIntMap bindingPoints = program->getBindingPoints(list);
1424	passed &= (baseBindingPoint == bindingPoints[list[0]]) && (baseBindingPoint == bindingPoints[list[1]]);
1425	if (!passed)
1426	{
1427		String err;
1428		err = generateLog(String("binding point did not match default"), bindingPoints[list[0]], baseBindingPoint);
1429		err += generateLog(String("binding point did not match default"), bindingPoints[list[1]], baseBindingPoint);
1430		return LayoutBindingTestResult(passed, err);
1431	}
1432
1433	return true;
1434}
1435
1436//== verify that binding point has specified value
1437LayoutBindingTestResult LayoutBindingBaseCase::binding_basic_render()
1438{
1439	bool passed = true;
1440
1441	StringStream s;
1442	s << buildAccess(getDefaultUniformName()) << ";\n";
1443	setTemplateParam("UNIFORM_ACCESS", s.str());
1444
1445	std::vector<int> bindings = makeSparseRange(maxBindings());
1446	for (std::vector<int>::iterator it = bindings.begin(); it < bindings.end(); it++)
1447	{
1448		int	binding = *it;
1449		String decl =
1450			buildUniformDecl(String(getTestParameters().keyword), buildLayout(binding),
1451							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1452							 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1453		setTemplateParam("UNIFORM_DECL", decl);
1454		updateTemplate();
1455
1456		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1457		passed &= program->compiledAndLinked();
1458		if (!passed)
1459		{
1460			return LayoutBindingTestResult(passed, program->getErrorLog());
1461		}
1462
1463		LayoutBindingTestResult drawTestResult = ((*this).*(m_drawTest))(program->getProgram(), binding);
1464		if (!drawTestResult.testPassed())
1465		{
1466			return LayoutBindingTestResult(drawTestResult.testPassed(), drawTestResult.getReason());
1467		}
1468	}
1469	return true;
1470}
1471
1472LayoutBindingTestResult LayoutBindingBaseCase::binding_integer_constant()
1473{
1474	bool			 passed   = true;
1475	std::vector<int> integers = makeSparseRange(maxBindings(), 0);
1476
1477	std::vector<IntegerConstant> integerConstants;
1478	for (int idx = 0; idx < IntegerConstant::last; idx++)
1479	{
1480		for (IntVector::iterator it = integers.begin(); it != integers.end(); it++)
1481		{
1482			integerConstants.push_back(IntegerConstant((IntegerConstant::Literals)idx, (*it)));
1483		}
1484	}
1485
1486	//== verify that binding point can be set with integer constant
1487	for (std::vector<IntegerConstant>::iterator it = integerConstants.begin(); it != integerConstants.end(); it++)
1488	{
1489		String& intConst = (*it).asString;
1490
1491		String decl =
1492			buildUniformDecl(String(getTestParameters().keyword), buildLayout(intConst),
1493							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1494							 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1495		setTemplateParam("UNIFORM_DECL", decl);
1496
1497		StringStream s;
1498		s << buildAccess(getDefaultUniformName()) << ";\n";
1499		setTemplateParam("UNIFORM_ACCESS", s.str());
1500		updateTemplate();
1501
1502		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1503		passed &= program->compiledAndLinked();
1504		if (!passed)
1505		{
1506			return LayoutBindingTestResult(passed, program->getErrorLog());
1507		}
1508
1509		StringVector  list;
1510		const String& u = buildBlockName(getDefaultUniformName());
1511		if (!u.empty())
1512			list.push_back(u + "_block");
1513		else
1514			list.push_back(getDefaultUniformName());
1515
1516		StringIntMap bindingPoints = program->getBindingPoints(list);
1517		passed &= ((*it).asInt == bindingPoints[list[0]]);
1518		if (!passed)
1519		{
1520			return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1521															   bindingPoints[list[0]], (*it).asInt));
1522		}
1523	}
1524
1525	//== verify that binding point can be set with integer constant resulting from a preprocessor substitution
1526	for (std::vector<IntegerConstant>::iterator it = integerConstants.begin(); it != integerConstants.end(); it++)
1527	{
1528		String& intConst = (*it).asString;
1529
1530		StringStream s;
1531		s << "#define INT_CONST " << intConst << std::endl;
1532
1533		String decl =
1534			buildUniformDecl(String(getTestParameters().keyword), buildLayout(String("INT_CONST")),
1535							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1536							 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1537		setTemplateParam("UNIFORM_DECL", s.str() + decl);
1538
1539		s.reset();
1540		s << buildAccess(getDefaultUniformName()) << ";\n";
1541		setTemplateParam("UNIFORM_ACCESS", s.str());
1542		updateTemplate();
1543
1544		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1545		passed &= program->compiledAndLinked();
1546		if (!passed)
1547		{
1548			return LayoutBindingTestResult(passed, program->getErrorLog());
1549		}
1550
1551		StringVector  list;
1552		const String& u = buildBlockName(getDefaultUniformName());
1553		if (!u.empty())
1554			list.push_back(u + "_block");
1555		else
1556			list.push_back(getDefaultUniformName());
1557
1558		StringIntMap bindingPoints = program->getBindingPoints(list);
1559		passed &= ((*it).asInt == bindingPoints[list[0]]);
1560		if (!passed)
1561		{
1562			return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1563															   bindingPoints[list[0]], (*it).asInt));
1564		}
1565	}
1566
1567	return true;
1568}
1569
1570//== test integer constant expressions
1571//== only for GL
1572LayoutBindingTestResult LayoutBindingBaseCase::binding_integer_constant_expression()
1573{
1574	bool passed = true;
1575	if (getGLSLVersion() == glu::GLSL_VERSION_310_ES)
1576		return LayoutBindingTestResult(passed, String(), true);
1577
1578	return LayoutBindingTestResult(passed, String(), true);
1579}
1580
1581//== test different sized arrays
1582LayoutBindingTestResult LayoutBindingBaseCase::binding_array_size(void)
1583{
1584	bool passed = true;
1585
1586	std::vector<int> arraySizes = makeSparseRange(maxArraySize(), 1);
1587	for (std::vector<int>::iterator it = arraySizes.begin(); it < arraySizes.end(); it++)
1588	{
1589		int	arraySize = *it;
1590		String decl =
1591			buildUniformDecl(String(getTestParameters().keyword), buildLayout(maxBindings() - arraySize - 1),
1592							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1593							 buildBlock(getDefaultUniformName()), getDefaultUniformName(), buildArray(arraySize));
1594		setTemplateParam("UNIFORM_DECL", decl);
1595
1596		StringStream s;
1597		for (int idx = 0; idx < arraySize; idx++)
1598		{
1599			s << (idx ? " + " : "") << buildAccess(buildArrayAccess(0, idx));
1600		}
1601		s << ";\n";
1602		setTemplateParam("UNIFORM_ACCESS", s.str());
1603		updateTemplate();
1604
1605		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1606		passed &= program->compiledAndLinked();
1607		if (!passed)
1608		{
1609			return LayoutBindingTestResult(passed, program->getErrorLog());
1610		}
1611
1612		StringVector list;
1613		for (int idx = 0; idx < arraySize; idx++)
1614		{
1615			std::ostringstream texUnitStr;
1616			texUnitStr << getDefaultUniformName();
1617			const String& u = buildBlockName(getDefaultUniformName());
1618			if (!u.empty())
1619				texUnitStr << "_block";
1620			texUnitStr << buildArray(idx);
1621			list.push_back(texUnitStr.str());
1622		}
1623
1624		StringIntMap bindingPoints = program->getBindingPoints(list);
1625		for (int idx = 0; idx < arraySize; idx++)
1626		{
1627			passed &= (((maxBindings() - arraySize - 1) + idx) == bindingPoints[list[idx]]);
1628			if (!passed)
1629			{
1630				return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1631																   bindingPoints[list[idx]],
1632																   (maxBindings() - arraySize - 1) + idx));
1633			}
1634		}
1635	}
1636
1637	return LayoutBindingTestResult(passed, String());
1638}
1639
1640//== verify first element takes binding point specified in binding and
1641//== subsequent entries take the next consecutive units
1642LayoutBindingTestResult LayoutBindingBaseCase::binding_array_implicit(void)
1643{
1644	bool passed = true;
1645
1646	std::vector<int> bindings = makeSparseRange(maxBindings(), 0);
1647	for (std::vector<int>::iterator it = bindings.begin(); it < bindings.end(); it++)
1648	{
1649		int baseBindingPoint = *it;
1650		int arraySize		 = std::min(maxBindings() - baseBindingPoint, 4);
1651
1652		String decl =
1653			buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1654							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1655							 buildBlock(getDefaultUniformName()), getDefaultUniformName(), buildArray(arraySize));
1656		setTemplateParam("UNIFORM_DECL", decl);
1657
1658		StringStream s;
1659		for (int idx = 0; idx < arraySize; idx++)
1660		{
1661			s << (idx ? " + " : "") << buildAccess(buildArrayAccess(0, idx));
1662		}
1663		s << ";\n";
1664		setTemplateParam("UNIFORM_ACCESS", s.str());
1665		updateTemplate();
1666
1667		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1668		passed &= program->compiledAndLinked();
1669		if (!passed)
1670		{
1671			return LayoutBindingTestResult(passed, program->getErrorLog());
1672		}
1673		StringVector list;
1674		for (int idx = 0; idx < arraySize; idx++)
1675		{
1676			std::ostringstream texUnitStr;
1677			texUnitStr << getDefaultUniformName();
1678			const String& u = buildBlockName(getDefaultUniformName());
1679			if (!u.empty())
1680				texUnitStr << "_block";
1681			texUnitStr << buildArray(idx);
1682			list.push_back(texUnitStr.str());
1683		}
1684
1685		StringIntMap bindingPoints = program->getBindingPoints(list);
1686		for (int idx = 0; idx < arraySize; idx++)
1687		{
1688			passed &= ((baseBindingPoint + idx) == bindingPoints[list[idx]]);
1689			if (!passed)
1690			{
1691				return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1692																   bindingPoints[list[idx]], (baseBindingPoint + idx)));
1693			}
1694		}
1695	}
1696	return LayoutBindingTestResult(passed, String());
1697}
1698
1699//== multiple arrays :verify first element takes binding point specified in binding and
1700//== subsequent entries take the next consecutive units
1701LayoutBindingTestResult LayoutBindingBaseCase::binding_array_multiple(void)
1702{
1703	bool passed = true;
1704
1705	// two arrays, limit max. binding to one
1706	std::vector<int> bindings = makeSparseRange(maxBindings() - 2, 0);
1707	for (std::vector<int>::iterator it = bindings.begin(); it < bindings.end(); it++)
1708	{
1709		int baseBindingPoint = *it;
1710
1711		// total distance from current binding point to end of binding range
1712		// split over two arrays, making sure that the array sizes don't
1713		// exceed max. array sizes per stage
1714		int arraySize = (maxBindings() - baseBindingPoint - 1) / 2;
1715		arraySize	 = std::min(arraySize, maxArraySize() / 2);
1716
1717		StringStream s;
1718		String		 decl =
1719			buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1720							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1721							 buildBlock(getDefaultUniformName()), getDefaultUniformName(), buildArray(arraySize));
1722		String another_decl =
1723			buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1724							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName(1)),
1725							 buildBlock(getDefaultUniformName(1)), getDefaultUniformName(1), buildArray(arraySize));
1726		setTemplateParam("UNIFORM_DECL", decl + another_decl);
1727
1728		s.reset();
1729		for (int uniform = 0; uniform < 2; uniform++)
1730		{
1731			for (int idx = 0; idx < arraySize; idx++)
1732			{
1733				s << ((idx | uniform) ? " + " : "") << buildAccess(buildArrayAccess(uniform, idx));
1734			}
1735		}
1736		s << ";\n";
1737		setTemplateParam("UNIFORM_ACCESS", s.str());
1738		updateTemplate();
1739
1740		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1741		passed &= program->compiledAndLinked();
1742		if (!passed)
1743		{
1744			return LayoutBindingTestResult(passed, program->getErrorLog());
1745		}
1746
1747		StringVector list;
1748		for (int uniform = 0; uniform < 2; uniform++)
1749		{
1750			list.clear();
1751			for (int idx = 0; idx < arraySize; idx++)
1752			{
1753				std::ostringstream texUnitStr;
1754				texUnitStr << getDefaultUniformName(uniform);
1755				const String& u = buildBlockName(getDefaultUniformName(uniform));
1756				if (!u.empty())
1757					texUnitStr << "_block";
1758				texUnitStr << buildArray(idx);
1759				list.push_back(texUnitStr.str());
1760			}
1761
1762			StringIntMap bindingPoints = program->getBindingPoints(list);
1763			for (int idx = 0; idx < arraySize; idx++)
1764			{
1765				passed &= ((baseBindingPoint + idx) == bindingPoints[list[idx]]);
1766				if (!passed)
1767				{
1768					return LayoutBindingTestResult(passed,
1769												   generateLog(String("binding point did not match default"),
1770															   bindingPoints[list[idx]], (baseBindingPoint + idx)));
1771				}
1772			}
1773		}
1774	}
1775	return LayoutBindingTestResult(passed, String());
1776}
1777
1778//== verify that explicit binding point can be changed via API
1779LayoutBindingTestResult LayoutBindingBaseCase::binding_api_update(void)
1780{
1781	bool passed = true;
1782
1783	String decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(1),
1784								   String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1785								   buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1786	setTemplateParam("UNIFORM_DECL", decl);
1787
1788	StringStream s;
1789	s << buildAccess(getDefaultUniformName()) << ";\n";
1790	setTemplateParam("UNIFORM_ACCESS", s.str());
1791	updateTemplate();
1792
1793	LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1794	passed &= program->compiledAndLinked();
1795	if (!passed)
1796	{
1797		return LayoutBindingTestResult(passed, program->getErrorLog());
1798	}
1799
1800	StringVector  list;
1801	const String& u = buildBlockName(getDefaultUniformName());
1802	if (!u.empty())
1803		list.push_back(u + "_block");
1804	else
1805		list.push_back(getDefaultUniformName());
1806
1807	StringIntMap bindingPoints = program->getBindingPoints(list);
1808
1809	gl().useProgram(program->getProgram());
1810	program->setBindingPoints(list, maxBindings() - 1);
1811	gl().useProgram(0);
1812
1813	bindingPoints = program->getBindingPoints(list);
1814
1815	passed &= bindingPoints[list[0]] == (maxBindings() - 1);
1816	if (!passed)
1817	{
1818		return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1819														   bindingPoints[list[0]], maxBindings() - 1));
1820	}
1821
1822	return LayoutBindingTestResult(passed, String());
1823}
1824
1825LayoutBindingTestResult LayoutBindingBaseCase::binding_compilation_errors(void)
1826{
1827	bool   passed = true;
1828	String decl;
1829
1830	// verify "uniform float var;" doesn't compile
1831	{
1832		StringStream s;
1833		s << getTestParameters().vector_type << "(0.0);";
1834
1835		setTemplateParam("UNIFORM_ACCESS", s.str());
1836		s.reset();
1837		s << "layout(binding=0) "
1838		  << "uniform float tex0;";
1839		setTemplateParam("UNIFORM_DECL", s.str());
1840		updateTemplate();
1841
1842		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1843		passed &= !program->compiledAndLinked();
1844		if (!passed)
1845		{
1846			return LayoutBindingTestResult(passed, program->getErrorLog(true));
1847		}
1848	}
1849
1850	// verify that non-constant integer expression in binding fails
1851	{
1852		decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(String("0.0")),
1853								String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1854								buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1855		setTemplateParam("UNIFORM_DECL", decl);
1856		updateTemplate();
1857
1858		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1859		passed &= !program->compiledAndLinked();
1860		if (!passed)
1861		{
1862			return LayoutBindingTestResult(passed, program->getErrorLog(true));
1863		}
1864	}
1865
1866	{
1867		decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(String("-1")),
1868								String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1869								buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1870		setTemplateParam("UNIFORM_DECL", decl);
1871		updateTemplate();
1872
1873		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1874		passed &= !program->compiledAndLinked();
1875		if (!passed)
1876		{
1877			return LayoutBindingTestResult(passed, program->getErrorLog(true));
1878		}
1879	}
1880	{
1881		decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(maxBindings()),
1882								String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1883								buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1884		setTemplateParam("UNIFORM_DECL", decl);
1885		updateTemplate();
1886
1887		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1888		passed &= !program->compiledAndLinked();
1889		if (!passed)
1890		{
1891			return LayoutBindingTestResult(passed, program->getErrorLog(true));
1892		}
1893	}
1894	{
1895		decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(maxBindings()),
1896								String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1897								buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1898		setTemplateParam("UNIFORM_DECL", decl);
1899
1900		StringStream s;
1901		s << "vec4(0.0);\n";
1902		setTemplateParam("UNIFORM_ACCESS", s.str());
1903		updateTemplate();
1904
1905		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1906		passed &= !program->compiledAndLinked();
1907		if (!passed)
1908		{
1909			return LayoutBindingTestResult(passed, program->getErrorLog(true));
1910		}
1911	}
1912	return LayoutBindingTestResult(passed, String());
1913}
1914
1915LayoutBindingTestResult LayoutBindingBaseCase::binding_link_errors(void)
1916{
1917	bool passed = true;
1918
1919	// same sampler with different binding in two compilation units
1920	if (isStage(VertexShader))
1921	{
1922		String decl =
1923			buildUniformDecl(String(getTestParameters().keyword), buildLayout(1),
1924							 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1925							 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1926		setTemplateParam(VertexShader, "UNIFORM_DECL", decl);
1927
1928		setTemplateParam(VertexShader, "OUT_ASSIGNMENT", String("fragColor ="));
1929
1930		StringStream s;
1931		s << buildAccess(getDefaultUniformName()) << ";\n";
1932		setTemplateParam(VertexShader, "UNIFORM_ACCESS", s.str());
1933		updateTemplate(VertexShader);
1934
1935		decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(3),
1936								String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1937								buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1938		setTemplateParam(FragmentShader, "UNIFORM_DECL", decl);
1939
1940		s.reset();
1941		s << "fragColor + " << buildAccess(getDefaultUniformName()) << ";\n";
1942		setTemplateParam(FragmentShader, "UNIFORM_ACCESS", s.str());
1943		updateTemplate(FragmentShader);
1944
1945		LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1946		passed = !program->compiledAndLinked();
1947		if (!passed)
1948		{
1949			return LayoutBindingTestResult(passed, program->getErrorLog(true));
1950		}
1951	}
1952
1953	return LayoutBindingTestResult(passed, String());
1954}
1955
1956// this subtest is generically empty. Overwritten in test cases as needed.
1957LayoutBindingTestResult LayoutBindingBaseCase::binding_examples(void)
1958{
1959	return true;
1960}
1961
1962// just for image and atomic counter cases
1963LayoutBindingTestResult LayoutBindingBaseCase::binding_mixed_order(void)
1964{
1965	return true;
1966}
1967
1968//=========================================================================
1969// test case Sampler layout binding
1970//=========================================================================
1971class SamplerLayoutBindingCase : public LayoutBindingBaseCase
1972
1973{
1974public:
1975	SamplerLayoutBindingCase(Context& context, const char* name, const char* description, StageType stage,
1976							 LayoutBindingParameters& samplerType, glu::GLSLVersion glslVersion);
1977	~SamplerLayoutBindingCase(void);
1978
1979private:
1980	/*virtual*/
1981	LayoutBindingProgram* createProgram()
1982	{
1983		return new LayoutBindingProgram(*this);
1984	}
1985
1986	/*virtual*/
1987	String getDefaultUniformName(int idx = 0)
1988	{
1989		StringStream s;
1990
1991		s << "sampler" << idx;
1992		return s.str();
1993	}
1994
1995	/*virtual*/
1996	String buildLayout(const String& binding)
1997	{
1998		std::ostringstream s;
1999		if (!binding.empty())
2000			s << "layout(binding=" << binding << ") ";
2001		return s.str();
2002	}
2003
2004	virtual int maxBindings()
2005	{
2006		int units = 0;
2007		gl().getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &units);
2008		return units;
2009	}
2010
2011	// return max. array size allowed
2012	virtual int maxArraySize()
2013	{
2014		int units = 0;
2015
2016		switch (getStage())
2017		{
2018		case VertexShader:
2019			gl().getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &units);
2020			break;
2021		case FragmentShader:
2022			gl().getIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &units);
2023			break;
2024		case ComputeShader:
2025			gl().getIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &units);
2026			break;
2027		default:
2028			DE_ASSERT(0);
2029			break;
2030		}
2031
2032		return units;
2033	}
2034};
2035
2036SamplerLayoutBindingCase::SamplerLayoutBindingCase(Context& context, const char* name, const char* description,
2037												   StageType stage, LayoutBindingParameters& samplerType,
2038												   glu::GLSLVersion glslVersion)
2039	: LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion)
2040{
2041}
2042
2043SamplerLayoutBindingCase::~SamplerLayoutBindingCase(void)
2044{
2045}
2046
2047//=========================================================================
2048// test case Image layout binding
2049//=========================================================================
2050class ImageLayoutBindingCase : public LayoutBindingBaseCase
2051
2052{
2053public:
2054	ImageLayoutBindingCase(Context& context, const char* name, const char* description, StageType stage,
2055						   LayoutBindingParameters& samplerType, glu::GLSLVersion glslVersion);
2056	~ImageLayoutBindingCase(void);
2057
2058private:
2059	class ImageLayoutBindingProgram : public LayoutBindingProgram
2060	{
2061	public:
2062		ImageLayoutBindingProgram(IProgramContextSupplier& contextSupplier) : LayoutBindingProgram(contextSupplier)
2063		{
2064		}
2065	};
2066
2067private:
2068	// IProgramContextSupplier
2069	/*virtual*/
2070	LayoutBindingProgram* createProgram()
2071	{
2072		return new ImageLayoutBindingProgram(*this);
2073	}
2074
2075private:
2076	/*virtual*/
2077	String getDefaultUniformName(int idx = 0)
2078	{
2079		StringStream s;
2080		s << "image" << idx;
2081		return s.str();
2082	}
2083
2084	/*virtual*/
2085	String buildLayout(const String& binding)
2086	{
2087		std::ostringstream s;
2088		if (!binding.empty())
2089			s << "layout(binding=" << binding << ", rgba8) readonly ";
2090		else
2091			s << "layout(rgba8) readonly ";
2092		return s.str();
2093	}
2094
2095	/*virtual*/
2096	int maxBindings()
2097	{
2098		int units = 0;
2099		gl().getIntegerv(GL_MAX_IMAGE_UNITS, &units);
2100		return units;
2101	}
2102
2103	/*virtual*/
2104	int maxArraySize()
2105	{
2106		int units = 0;
2107		switch (getStage())
2108		{
2109		case VertexShader:
2110			gl().getIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &units);
2111			break;
2112		case FragmentShader:
2113			gl().getIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &units);
2114			break;
2115		case ComputeShader:
2116			gl().getIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &units);
2117			break;
2118		default:
2119			DE_ASSERT(0);
2120			break;
2121		}
2122		return units;
2123	}
2124
2125private:
2126	//virtual LayoutBindingTestResult        binding_basic_default               (void);
2127	//virtual LayoutBindingTestResult        binding_basic_explicit              (void);
2128	//virtual LayoutBindingTestResult        binding_basic_multiple              (void);
2129	//virtual LayoutBindingTestResult        binding_basic_render                (void);
2130	//virtual LayoutBindingTestResult        binding_integer_constant            (void);
2131	//virtual LayoutBindingTestResult        binding_integer_constant_expression (void);
2132	//virtual LayoutBindingTestResult        binding_array_size                  (void);
2133	//virtual LayoutBindingTestResult        binding_array_implicit              (void);
2134	//virtual LayoutBindingTestResult        binding_array_multiple              (void);
2135	/*virtual*/
2136	LayoutBindingTestResult binding_api_update(void)
2137	{
2138		// only for GL
2139		if (getGLSLVersion() == glu::GLSL_VERSION_310_ES)
2140			return LayoutBindingTestResult(true, String(), true);
2141
2142		return LayoutBindingBaseCase::binding_api_update();
2143	}
2144	//virtual LayoutBindingTestResult        binding_compilation_errors          (void);
2145	//virtual LayoutBindingTestResult        binding_link_errors                 (void);
2146	//virtual LayoutBindingTestResult        binding_link_examples               (void);
2147	/*virtual*/
2148	LayoutBindingTestResult binding_mixed_order(void)
2149	{
2150		bool passed = true;
2151
2152		{
2153			StringStream s;
2154			s << buildAccess(getDefaultUniformName()) << ";\n";
2155			setTemplateParam("UNIFORM_ACCESS", s.str());
2156
2157			String decl =
2158				buildUniformDecl(String(getTestParameters().keyword), String("layout(binding=0, rgba8) readonly"),
2159								 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2160								 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
2161			setTemplateParam("UNIFORM_DECL", decl);
2162			updateTemplate();
2163
2164			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2165			passed &= program->compiledAndLinked();
2166			if (!passed)
2167			{
2168				return LayoutBindingTestResult(passed, program->getErrorLog());
2169			}
2170		}
2171		{
2172			String decl =
2173				buildUniformDecl(String(getTestParameters().keyword), String("layout(r32f, binding=0) readonly"),
2174								 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2175								 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
2176			setTemplateParam("UNIFORM_DECL", decl);
2177			updateTemplate();
2178
2179			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2180			passed &= program->compiledAndLinked();
2181			if (!passed)
2182			{
2183				return LayoutBindingTestResult(passed, program->getErrorLog());
2184			}
2185		}
2186
2187		return true;
2188	}
2189};
2190
2191ImageLayoutBindingCase::ImageLayoutBindingCase(Context& context, const char* name, const char* description,
2192											   StageType stage, LayoutBindingParameters& samplerType,
2193											   glu::GLSLVersion glslVersion)
2194	: LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion)
2195{
2196}
2197
2198ImageLayoutBindingCase::~ImageLayoutBindingCase(void)
2199{
2200}
2201
2202//=========================================================================
2203// test case Atomic counter binding
2204//=========================================================================
2205class AtomicCounterLayoutBindingCase : public LayoutBindingBaseCase
2206
2207{
2208public:
2209	AtomicCounterLayoutBindingCase(Context& context, const char* name, const char* description, StageType stage,
2210								   LayoutBindingParameters& samplerType, glu::GLSLVersion glslVersion);
2211	~AtomicCounterLayoutBindingCase(void)
2212	{
2213	}
2214
2215private:
2216	class AtomicCounterLayoutBindingProgram : public LayoutBindingProgram
2217	{
2218	public:
2219		AtomicCounterLayoutBindingProgram(IProgramContextSupplier& contextSupplier)
2220			: LayoutBindingProgram(contextSupplier)
2221		{
2222		}
2223
2224	private:
2225		/*virtual*/
2226		StringIntMap getBindingPoints(StringVector args) const
2227		{
2228			StringIntMap bindingPoints;
2229
2230			for (StringVector::iterator it = args.begin(); it != args.end(); it++)
2231			{
2232				glw::GLuint idx = gl().getProgramResourceIndex(getProgram(), GL_UNIFORM, (*it).c_str());
2233				if (idx != GL_INVALID_INDEX)
2234				{
2235					glw::GLenum param					  = GL_ATOMIC_COUNTER_BUFFER_INDEX;
2236					glw::GLint  atomic_counter_buffer_idx = -1;
2237					gl().getProgramResourceiv(getProgram(), GL_UNIFORM, idx, 1, &param, 1, NULL,
2238											  &atomic_counter_buffer_idx);
2239					bool hasNoError = (GL_NO_ERROR == gl().getError()) && (-1 != atomic_counter_buffer_idx);
2240					if (!hasNoError)
2241						continue;
2242
2243					param			 = GL_BUFFER_BINDING;
2244					glw::GLint value = -1;
2245					gl().getProgramResourceiv(getProgram(), GL_ATOMIC_COUNTER_BUFFER, atomic_counter_buffer_idx, 1,
2246											  &param, 1, NULL, &value);
2247					hasNoError = (GL_NO_ERROR == gl().getError()) && (-1 != value);
2248					if (!hasNoError)
2249						continue;
2250
2251					bindingPoints[*it] = value;
2252				}
2253			}
2254			return bindingPoints;
2255		}
2256
2257		/*virtual*/
2258		StringIntMap getOffsets(StringVector args) const
2259		{
2260			StringIntMap bindingPoints;
2261
2262			for (StringVector::iterator it = args.begin(); it != args.end(); it++)
2263			{
2264				glw::GLuint idx = gl().getProgramResourceIndex(getProgram(), GL_UNIFORM, (*it).c_str());
2265				if (idx != GL_INVALID_INDEX)
2266				{
2267					glw::GLenum param = GL_OFFSET;
2268					glw::GLint  value = -1;
2269					gl().getProgramResourceiv(getProgram(), GL_UNIFORM, idx, 1, &param, 1, NULL, &value);
2270					bool hasNoError = (GL_NO_ERROR == gl().getError());
2271					if (hasNoError)
2272					{
2273						bindingPoints[*it] = value;
2274					}
2275				}
2276			}
2277			return bindingPoints;
2278		}
2279	};
2280
2281private:
2282	// IProgramContextSupplier
2283	/*virtual*/
2284	LayoutBindingProgram* createProgram()
2285	{
2286		return new AtomicCounterLayoutBindingProgram(*this);
2287	}
2288
2289private:
2290	/*virtual*/
2291	String getDefaultUniformName(int idx = 0)
2292	{
2293		StringStream s;
2294		s << "atomic" << idx;
2295		return s.str();
2296	}
2297
2298	/*virtual*/
2299	String buildAccess(const String& var)
2300	{
2301		std::ostringstream s;
2302		s << "vec4(float(atomicCounter(" << var << ")), 1.0, 0.0, 1.0)";
2303		return s.str();
2304	}
2305
2306	int maxBindings()
2307	{
2308		int units = 0;
2309		gl().getIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &units);
2310		return units;
2311	}
2312
2313	// return max. array size allowed
2314	int maxArraySize()
2315	{
2316		int units = 0;
2317		switch (getStage())
2318		{
2319		case FragmentShader:
2320			gl().getIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &units);
2321			break;
2322		case VertexShader:
2323			gl().getIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &units);
2324			break;
2325		case ComputeShader:
2326			gl().getIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &units);
2327			break;
2328		default:
2329			DE_ASSERT(0);
2330			break;
2331		}
2332		return units;
2333	}
2334
2335	//=========================================================================
2336	// sub-tests overrides
2337	//=========================================================================
2338private:
2339	LayoutBindingTestResult binding_basic_default(void)
2340	{
2341		return true;
2342	}
2343	//virtual LayoutBindingTestResult binding_basic_explicit          (void);
2344	//virtual LayoutBindingTestResult binding_basic_multiple          (void);
2345	LayoutBindingTestResult binding_basic_render(void)
2346	{
2347		return true;
2348	}
2349	//virtual LayoutBindingTestResult binding_integer_constant        (void);
2350	/*virtual*/
2351	LayoutBindingTestResult binding_array_size(void)
2352	{
2353		bool passed = true;
2354
2355		//== test different sized arrays
2356		std::vector<int> arraySizes = makeSparseRange(maxArraySize(), 1);
2357		for (std::vector<int>::iterator it = arraySizes.begin(); it < arraySizes.end(); it++)
2358		{
2359			int			 arraySize = *it;
2360			StringStream s;
2361			s << "[" << arraySize << "]";
2362			String decl =
2363				buildUniformDecl(String(getTestParameters().keyword), buildLayout(0),
2364								 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2365								 buildBlock(getDefaultUniformName()), getDefaultUniformName(), buildArray(arraySize));
2366			setTemplateParam("UNIFORM_DECL", decl);
2367
2368			s.reset();
2369			// build a function that accesses the whole array
2370			s << "float accumulate(void)\n";
2371			s << "{\n";
2372			s << "  float acc = 0.0;\n";
2373			s << "  for(int i=0; i < " << arraySize << " ; i++)\n";
2374			s << "    acc = float(atomicCounter(" << getDefaultUniformName() << "[i]));\n";
2375			s << "  return acc;\n";
2376			s << "}\n";
2377
2378			setTemplateParam("OPTIONAL_FUNCTION_BLOCK", s.str());
2379
2380			s.reset();
2381			s << "vec4(accumulate(), 1.0, 0.0, 1.0);\n";
2382			setTemplateParam("UNIFORM_ACCESS", s.str());
2383			updateTemplate();
2384
2385			setTemplateParam("OPTIONAL_FUNCTION_BLOCK", String());
2386
2387			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2388			passed &= program->compiledAndLinked();
2389			if (!passed)
2390			{
2391				return LayoutBindingTestResult(passed, program->getErrorLog());
2392			}
2393
2394			StringVector	   list;
2395			std::ostringstream texUnitStr;
2396			texUnitStr << getDefaultUniformName() << "[0]";
2397			list.push_back(texUnitStr.str());
2398
2399			StringIntMap bindingPoints = program->getBindingPoints(list);
2400			passed &= (0 == bindingPoints[list[0]]);
2401			if (!passed)
2402			{
2403				return LayoutBindingTestResult(
2404					passed, generateLog(String("binding point did not match default"), bindingPoints[list[0]], 1));
2405			}
2406		}
2407
2408		return LayoutBindingTestResult(passed, String());
2409	}
2410	LayoutBindingTestResult binding_array_implicit(void)
2411	{
2412		return true;
2413	}
2414	LayoutBindingTestResult binding_array_multiple(void)
2415	{
2416		return true;
2417	}
2418	LayoutBindingTestResult binding_api_update(void)
2419	{
2420		return true;
2421	}
2422	//virtual LayoutBindingTestResult binding_compilation_errors      (void);
2423	//virtual LayoutBindingTestResult binding_link_errors             (void);
2424
2425	LayoutBindingTestResult binding_examples_many_bindings(void)
2426	{
2427		int max_bindings = 0;
2428
2429		if (isStage(VertexShader))
2430		{
2431			gl().getIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &max_bindings);
2432		}
2433		else if (isStage(FragmentShader))
2434		{
2435			gl().getIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &max_bindings);
2436		}
2437		else
2438		{
2439			gl().getIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &max_bindings);
2440		}
2441
2442		// example 1 in atomic counter CTS spec ac-binding-examples
2443		{
2444			bool		 passed = true;
2445			StringStream s;
2446			s << buildAccess(getDefaultUniformName()) << ";\n";
2447			setTemplateParam("UNIFORM_ACCESS", s.str());
2448
2449			s.reset();
2450			s << "layout(binding=2, offset=4) uniform atomic_uint;\n";
2451			s << "layout(binding=2) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2452			setTemplateParam("UNIFORM_DECL", s.str());
2453			updateTemplate();
2454
2455			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2456			passed &= program->compiledAndLinked();
2457			if (!passed)
2458			{
2459				return LayoutBindingTestResult(passed, program->getErrorLog());
2460			}
2461
2462			StringVector list;
2463			list.push_back(getDefaultUniformName());
2464
2465			StringIntMap offsets = program->getOffsets(list);
2466			passed &= (4 == offsets[list[0]]);
2467			if (!passed)
2468			{
2469				return LayoutBindingTestResult(
2470					passed, generateLog(String("offset did not match requested"), offsets[list[0]], 1));
2471			}
2472		}
2473
2474		// example 2 in atomic counter CTS spec ac-binding-examples
2475		if (max_bindings >= 2)
2476		{
2477			bool		 passed = true;
2478			StringStream s;
2479			s << buildAccess(getDefaultUniformName()) << ";\n";
2480			s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2481			s << "+" << buildAccess(getDefaultUniformName(2)) << ";\n";
2482			s << "+" << buildAccess(getDefaultUniformName(3)) << ";\n";
2483			setTemplateParam("UNIFORM_ACCESS", s.str());
2484
2485			s.reset();
2486			s << "layout(binding=3, offset=4) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2487			s << "layout(binding=2) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2488			s << "layout(binding=3) uniform atomic_uint " << getDefaultUniformName(2) << ";\n";
2489			s << "layout(binding=2) uniform atomic_uint " << getDefaultUniformName(3) << ";\n";
2490			setTemplateParam("UNIFORM_DECL", s.str());
2491			updateTemplate();
2492
2493			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2494			passed &= program->compiledAndLinked();
2495			if (!passed)
2496			{
2497				return LayoutBindingTestResult(passed, program->getErrorLog());
2498			}
2499
2500			StringVector list;
2501			list.push_back(getDefaultUniformName());
2502			list.push_back(getDefaultUniformName(1));
2503			list.push_back(getDefaultUniformName(2));
2504			list.push_back(getDefaultUniformName(3));
2505
2506			StringIntMap offsets = program->getOffsets(list);
2507			IntVector	expected;
2508			expected.insert(expected.end(), 4);
2509			expected.insert(expected.end(), 0);
2510			expected.insert(expected.end(), 8);
2511			expected.insert(expected.end(), 4);
2512			for (unsigned int idx = 0; idx < list.size(); idx++)
2513			{
2514				passed &= (expected[idx] == offsets[list[idx]]);
2515				if (!passed)
2516				{
2517					return LayoutBindingTestResult(
2518						passed, generateLog(String("offset of") + String(list[idx]) + String("did not match requested"),
2519											offsets[list[idx]], 4));
2520				}
2521			}
2522		}
2523
2524		// example 3 in atomic counter CTS spec ac-binding-examples
2525		{
2526			bool		 passed = true;
2527			StringStream s;
2528			s << buildAccess(getDefaultUniformName()) << ";\n";
2529			setTemplateParam("UNIFORM_ACCESS", s.str());
2530
2531			s.reset();
2532			s << "layout(binding=2, offset=4) uniform atomic_uint;\n";
2533			s << "layout(offset=8) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2534			setTemplateParam("UNIFORM_DECL", s.str());
2535			updateTemplate();
2536
2537			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2538			passed &= program->compiledAndLinked();
2539			if (passed)
2540			{
2541				return LayoutBindingTestResult(!passed, String("should not compile"));
2542			}
2543		}
2544
2545		// example 4 in atomic counter CTS spec ac-binding-examples
2546		{
2547			bool		 passed = true;
2548			StringStream s;
2549			s << buildAccess(getDefaultUniformName()) << ";\n";
2550			setTemplateParam("UNIFORM_ACCESS", s.str());
2551
2552			s.reset();
2553			s << "layout(offset=4) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2554			setTemplateParam("UNIFORM_DECL", s.str());
2555			updateTemplate();
2556
2557			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2558			passed &= program->compiledAndLinked();
2559			if (passed)
2560			{
2561				return LayoutBindingTestResult(!passed, String("should not compile"));
2562			}
2563		}
2564
2565		// example 5 in atomic counter CTS spec ac-binding-examples
2566		// first check working example, then amend it with an error
2567		if (max_bindings >= 2)
2568		{
2569			for (int pass = 0; pass < 2; pass++)
2570			{
2571				bool passed = true;
2572
2573				StringStream s;
2574				s << buildAccess(getDefaultUniformName()) << ";\n";
2575				s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2576				if (pass)
2577					s << "+" << buildAccess(getDefaultUniformName(2)) << ";\n";
2578				setTemplateParam("UNIFORM_ACCESS", s.str());
2579
2580				s.reset();
2581				s << "layout(binding=1, offset=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2582				s << "layout(binding=2, offset=0) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2583				if (pass)
2584					s << "layout(binding=1, offset=0) uniform atomic_uint " << getDefaultUniformName(2) << ";\n";
2585				setTemplateParam("UNIFORM_DECL", s.str());
2586				updateTemplate();
2587
2588				LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2589				passed &= program->compiledAndLinked();
2590				if (pass != 0)
2591				{
2592					if (passed)
2593					{
2594						return LayoutBindingTestResult(passed, program->getErrorLog());
2595					}
2596				}
2597				else
2598				{
2599					if (!passed)
2600					{
2601						return LayoutBindingTestResult(passed, String("should not compile"));
2602					}
2603				}
2604			}
2605		}
2606
2607		// example 6 in atomic counter CTS spec ac-binding-examples
2608		// first check working example, then amend it with an error
2609		if (max_bindings >= 2)
2610		{
2611			for (int pass = 0; pass < 2; pass++)
2612			{
2613				bool passed = true;
2614
2615				StringStream s;
2616				s << buildAccess(getDefaultUniformName()) << ";\n";
2617				s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2618				if (pass)
2619					s << "+" << buildAccess(getDefaultUniformName(2)) << ";\n";
2620				setTemplateParam("UNIFORM_ACCESS", s.str());
2621
2622				s.reset();
2623				s << "layout(binding=1, offset=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2624				s << "layout(binding=2, offset=0) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2625				if (pass)
2626					s << "layout(binding=1, offset=2) uniform atomic_uint " << getDefaultUniformName(2) << ";\n";
2627				setTemplateParam("UNIFORM_DECL", s.str());
2628				updateTemplate();
2629
2630				LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2631				passed &= program->compiledAndLinked();
2632				if (pass != 0)
2633				{
2634					if (passed)
2635					{
2636						return LayoutBindingTestResult(passed, program->getErrorLog());
2637					}
2638				}
2639				else
2640				{
2641					if (!passed)
2642					{
2643						return LayoutBindingTestResult(passed, String("should not compile"));
2644					}
2645				}
2646			}
2647		}
2648
2649		return true;
2650	}
2651
2652	LayoutBindingTestResult binding_examples_one_binding(void)
2653	{
2654		// example 1 in atomic counter CTS spec ac-binding-examples
2655		{
2656			bool		 passed = true;
2657			StringStream s;
2658			s << buildAccess(getDefaultUniformName()) << ";\n";
2659			setTemplateParam("UNIFORM_ACCESS", s.str());
2660
2661			s.reset();
2662			s << "layout(binding=0, offset=4) uniform atomic_uint;\n";
2663			s << "layout(binding=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2664			setTemplateParam("UNIFORM_DECL", s.str());
2665			updateTemplate();
2666
2667			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2668			passed &= program->compiledAndLinked();
2669			if (!passed)
2670			{
2671				return LayoutBindingTestResult(passed, program->getErrorLog());
2672			}
2673
2674			StringVector list;
2675			list.push_back(getDefaultUniformName());
2676
2677			StringIntMap offsets = program->getOffsets(list);
2678			passed &= (4 == offsets[list[0]]);
2679			if (!passed)
2680			{
2681				return LayoutBindingTestResult(
2682					passed, generateLog(String("offset did not match requested"), offsets[list[0]], 1));
2683			}
2684		}
2685
2686		// example 2 in atomic counter CTS spec ac-binding-examples
2687		{
2688			bool		 passed = true;
2689			StringStream s;
2690			s << buildAccess(getDefaultUniformName()) << ";\n";
2691			s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2692			s << "+" << buildAccess(getDefaultUniformName(2)) << ";\n";
2693			s << "+" << buildAccess(getDefaultUniformName(3)) << ";\n";
2694			setTemplateParam("UNIFORM_ACCESS", s.str());
2695
2696			s.reset();
2697			s << "layout(binding=0, offset=4) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2698			s << "layout(binding=0) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2699			s << "layout(binding=0) uniform atomic_uint " << getDefaultUniformName(2) << ";\n";
2700			s << "layout(binding=0) uniform atomic_uint " << getDefaultUniformName(3) << ";\n";
2701			setTemplateParam("UNIFORM_DECL", s.str());
2702			updateTemplate();
2703
2704			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2705			passed &= program->compiledAndLinked();
2706			if (!passed)
2707			{
2708				return LayoutBindingTestResult(passed, program->getErrorLog());
2709			}
2710
2711			StringVector list;
2712			list.push_back(getDefaultUniformName());
2713			list.push_back(getDefaultUniformName(1));
2714			list.push_back(getDefaultUniformName(2));
2715			list.push_back(getDefaultUniformName(3));
2716
2717			StringIntMap offsets = program->getOffsets(list);
2718			IntVector	expected;
2719			expected.insert(expected.end(), 4);
2720			expected.insert(expected.end(), 8);
2721			expected.insert(expected.end(), 12);
2722			expected.insert(expected.end(), 16);
2723			for (unsigned int idx = 0; idx < list.size(); idx++)
2724			{
2725				passed &= (expected[idx] == offsets[list[idx]]);
2726				if (!passed)
2727				{
2728					return LayoutBindingTestResult(
2729						passed, generateLog(String("offset of") + String(list[idx]) + String("did not match requested"),
2730											offsets[list[idx]], expected[idx]));
2731				}
2732			}
2733		}
2734
2735		// example 3 in atomic counter CTS spec ac-binding-examples
2736		{
2737			bool		 passed = true;
2738			StringStream s;
2739			s << buildAccess(getDefaultUniformName()) << ";\n";
2740			setTemplateParam("UNIFORM_ACCESS", s.str());
2741
2742			s.reset();
2743			s << "layout(binding=0, offset=4) uniform atomic_uint;\n";
2744			s << "layout(offset=8) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2745			setTemplateParam("UNIFORM_DECL", s.str());
2746			updateTemplate();
2747
2748			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2749			passed &= program->compiledAndLinked();
2750			if (passed)
2751			{
2752				return LayoutBindingTestResult(!passed, String("should not compile"));
2753			}
2754		}
2755
2756		// example 4 in atomic counter CTS spec ac-binding-examples
2757		{
2758			bool		 passed = true;
2759			StringStream s;
2760			s << buildAccess(getDefaultUniformName()) << ";\n";
2761			setTemplateParam("UNIFORM_ACCESS", s.str());
2762
2763			s.reset();
2764			s << "layout(offset=4) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2765			setTemplateParam("UNIFORM_DECL", s.str());
2766			updateTemplate();
2767
2768			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2769			passed &= program->compiledAndLinked();
2770			if (passed)
2771			{
2772				return LayoutBindingTestResult(!passed, String("should not compile"));
2773			}
2774		}
2775
2776		// example 5 in atomic counter CTS spec ac-binding-examples
2777		// first check working example, then amend it with an error
2778		for (int pass = 0; pass < 2; pass++)
2779		{
2780			bool passed = true;
2781
2782			StringStream s;
2783			s << buildAccess(getDefaultUniformName()) << ";\n";
2784			if (pass)
2785				s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2786			setTemplateParam("UNIFORM_ACCESS", s.str());
2787
2788			s.reset();
2789			s << "layout(binding=0, offset=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2790			if (pass)
2791				s << "layout(binding=0, offset=0) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2792			setTemplateParam("UNIFORM_DECL", s.str());
2793			updateTemplate();
2794
2795			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2796			passed &= program->compiledAndLinked();
2797			if (pass != 0)
2798			{
2799				if (passed)
2800				{
2801					return LayoutBindingTestResult(passed, program->getErrorLog());
2802				}
2803			}
2804			else
2805			{
2806				if (!passed)
2807				{
2808					return LayoutBindingTestResult(passed, String("should not compile"));
2809				}
2810			}
2811		}
2812
2813		// example 6 in atomic counter CTS spec ac-binding-examples
2814		// first check working example, then amend it with an error
2815		for (int pass = 0; pass < 2; pass++)
2816		{
2817			bool passed = true;
2818
2819			StringStream s;
2820			s << buildAccess(getDefaultUniformName()) << ";\n";
2821			if (pass)
2822				s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2823			setTemplateParam("UNIFORM_ACCESS", s.str());
2824
2825			s.reset();
2826			s << "layout(binding=0, offset=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2827			if (pass)
2828				s << "layout(binding=0, offset=2) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2829			setTemplateParam("UNIFORM_DECL", s.str());
2830			updateTemplate();
2831
2832			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2833			passed &= program->compiledAndLinked();
2834			if (pass != 0)
2835			{
2836				if (passed)
2837				{
2838					return LayoutBindingTestResult(passed, program->getErrorLog());
2839				}
2840			}
2841			else
2842			{
2843				if (!passed)
2844				{
2845					return LayoutBindingTestResult(passed, String("should not compile"));
2846				}
2847			}
2848		}
2849
2850		return true;
2851	}
2852
2853	/*virtual*/
2854	LayoutBindingTestResult binding_examples(void)
2855	{
2856		if (maxBindings() >= 4)
2857		{
2858			return binding_examples_many_bindings();
2859		}
2860		else
2861		{
2862			return binding_examples_one_binding();
2863		}
2864	}
2865
2866	/*virtual*/
2867	LayoutBindingTestResult binding_mixed_order(void)
2868	{
2869		bool passed = true;
2870
2871		{
2872			StringStream s;
2873			s << buildAccess(getDefaultUniformName()) << ";\n";
2874			setTemplateParam("UNIFORM_ACCESS", s.str());
2875
2876			String decl =
2877				buildUniformDecl(String(getTestParameters().keyword), String("layout(binding=0, offset=0)"),
2878								 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2879								 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
2880			setTemplateParam("UNIFORM_DECL", decl);
2881			updateTemplate();
2882
2883			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2884			passed &= program->compiledAndLinked();
2885			if (!passed)
2886			{
2887				return LayoutBindingTestResult(passed, program->getErrorLog());
2888			}
2889		}
2890		{
2891			String decl =
2892				buildUniformDecl(String(getTestParameters().keyword), String("layout(offset=0, binding=0)"),
2893								 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2894								 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
2895			setTemplateParam("UNIFORM_DECL", decl);
2896			updateTemplate();
2897
2898			LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2899			passed &= program->compiledAndLinked();
2900			if (!passed)
2901			{
2902				return LayoutBindingTestResult(passed, program->getErrorLog());
2903			}
2904		}
2905
2906		return true;
2907	}
2908};
2909
2910AtomicCounterLayoutBindingCase::AtomicCounterLayoutBindingCase(Context& context, const char* name,
2911															   const char* description, StageType stage,
2912															   LayoutBindingParameters& samplerType,
2913															   glu::GLSLVersion			glslVersion)
2914	: LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion)
2915{
2916}
2917
2918//=========================================================================
2919// test case Uniform blocks binding
2920//=========================================================================
2921class UniformBlocksLayoutBindingCase : public LayoutBindingBaseCase
2922
2923{
2924public:
2925	UniformBlocksLayoutBindingCase(Context& context, const char* name, const char* description, StageType stage,
2926								   LayoutBindingParameters& samplerType, glu::GLSLVersion glslVersion);
2927	~UniformBlocksLayoutBindingCase(void);
2928
2929private:
2930	class UniformBlocksLayoutBindingProgram : public LayoutBindingProgram
2931	{
2932	public:
2933		UniformBlocksLayoutBindingProgram(IProgramContextSupplier& contextSupplier)
2934			: LayoutBindingProgram(contextSupplier)
2935		{
2936		}
2937
2938		~UniformBlocksLayoutBindingProgram()
2939		{
2940		}
2941
2942	private:
2943		/*virtual*/
2944		StringIntMap getBindingPoints(StringVector args) const
2945		{
2946			StringIntMap bindingPoints;
2947
2948			for (StringVector::iterator it = args.begin(); it != args.end(); it++)
2949			{
2950				glw::GLuint idx = gl().getProgramResourceIndex(getProgram(), GL_UNIFORM_BLOCK, (*it).c_str());
2951				if (idx != glw::GLuint(-1))
2952				{
2953					glw::GLenum param = GL_BUFFER_BINDING;
2954					glw::GLint  value = -1;
2955					gl().getProgramResourceiv(getProgram(), GL_UNIFORM_BLOCK, idx, 1, &param, 1, NULL, &value);
2956					bool hasNoError = (GL_NO_ERROR == gl().getError());
2957					if (hasNoError)
2958					{
2959						bindingPoints[*it] = value;
2960					}
2961				}
2962			}
2963
2964			return bindingPoints;
2965		}
2966
2967		/*virtual*/
2968		bool setBindingPoints(StringVector list, glw::GLint bindingPoint) const
2969		{
2970			bool bNoError = true;
2971
2972			for (StringVector::iterator it = list.begin(); it != list.end(); it++)
2973			{
2974				glw::GLuint blockIndex = gl().getUniformBlockIndex(getProgram(), (*it).c_str());
2975				if (blockIndex == GL_INVALID_INDEX)
2976
2977				{
2978					return false;
2979				}
2980				gl().uniformBlockBinding(getProgram(), blockIndex, bindingPoint);
2981			}
2982			return bNoError;
2983		}
2984	};
2985
2986private:
2987	// IProgramContextSupplier
2988	/*virtual*/
2989	LayoutBindingProgram* createProgram()
2990	{
2991		return new UniformBlocksLayoutBindingProgram(*this);
2992	}
2993
2994private:
2995	/*virtual*/
2996	String buildBlockName(const String& name)
2997	{
2998
2999		return name;
3000	}
3001
3002	/*virtual*/
3003	String buildBlock(const String& name, const String& type)
3004	{
3005
3006		std::ostringstream s;
3007		s << "{";
3008		s << type << " " << name << "_a; ";
3009		s << type << " " << name << "_b; ";
3010		s << "}";
3011		return s.str();
3012	}
3013
3014	/*virtual*/
3015	String buildAccess(const String& var)
3016	{
3017		std::ostringstream s;
3018		s << "vec4(0.0, " << var << "_a, 0.0, 1.0) + vec4(0.0, " << var << "_b, 0.0, 1.0)";
3019		return s.str();
3020	}
3021
3022	/*virtual*/
3023	String buildLayout(const String& binding)
3024	{
3025		std::ostringstream s;
3026		if (!binding.empty())
3027			s << "layout(binding=" << binding << ", std140) ";
3028		else
3029			s << "layout(std140) ";
3030		return s.str();
3031	}
3032
3033	/*virtual*/
3034	int maxBindings()
3035	{
3036		int units = 0;
3037		gl().getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &units);
3038		return units;
3039	}
3040
3041	// return max. array size allowed
3042	/*virtual*/
3043	int maxArraySize()
3044	{
3045		int units = 0;
3046		switch (getStage())
3047		{
3048		case FragmentShader:
3049			gl().getIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &units);
3050			break;
3051		case VertexShader:
3052			gl().getIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &units);
3053			break;
3054		case ComputeShader:
3055			gl().getIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &units);
3056			break;
3057		default:
3058			DE_ASSERT(0);
3059			break;
3060		}
3061		return units;
3062	}
3063
3064	/*virtual*/
3065	void bind(int binding)
3066	{
3067		gl().bindBufferBase(GL_UNIFORM_BUFFER, binding, m_buffername);
3068	}
3069
3070	/*virtual*/
3071	void unbind(int binding)
3072	{
3073		gl().bindBufferBase(GL_UNIFORM_BUFFER, binding, 0);
3074	}
3075
3076	/*virtual*/
3077	void setupTest(void)
3078	{
3079		const float f[2] = { 0.25f, 0.75f };
3080		gl().genBuffers(1, &m_buffername);
3081		gl().bindBuffer(GL_UNIFORM_BUFFER, m_buffername);
3082		gl().bufferData(GL_UNIFORM_BUFFER, sizeof(f), f, GL_STATIC_DRAW);
3083	}
3084
3085	/*virtual*/
3086	void teardownTest(void)
3087	{
3088		gl().bindBuffer(GL_UNIFORM_BUFFER, 0);
3089		gl().deleteBuffers(1, &m_buffername);
3090	}
3091
3092private:
3093	glw::GLuint m_buffername;
3094};
3095
3096UniformBlocksLayoutBindingCase::UniformBlocksLayoutBindingCase(Context& context, const char* name,
3097															   const char* description, StageType stage,
3098															   LayoutBindingParameters& samplerType,
3099															   glu::GLSLVersion			glslVersion)
3100	: LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion), m_buffername(0)
3101{
3102}
3103
3104UniformBlocksLayoutBindingCase::~UniformBlocksLayoutBindingCase()
3105{
3106}
3107
3108//*****************************************************************************
3109
3110//=========================================================================
3111// test case Shader storage buffer binding
3112//=========================================================================
3113class ShaderStorageBufferLayoutBindingCase : public LayoutBindingBaseCase
3114{
3115public:
3116	ShaderStorageBufferLayoutBindingCase(Context& context, const char* name, const char* description, StageType stage,
3117										 LayoutBindingParameters& samplerType, glu::GLSLVersion glslVersion);
3118	~ShaderStorageBufferLayoutBindingCase(void);
3119
3120private:
3121	class ShaderStorageBufferLayoutBindingProgram : public LayoutBindingProgram
3122	{
3123	public:
3124		ShaderStorageBufferLayoutBindingProgram(IProgramContextSupplier& contextSupplier)
3125			: LayoutBindingProgram(contextSupplier)
3126		{
3127		}
3128
3129		~ShaderStorageBufferLayoutBindingProgram()
3130		{
3131		}
3132		//*******************************************************************************
3133		// overwritten virtual methods
3134	private:
3135		/*virtual*/
3136		StringIntMap getBindingPoints(StringVector args) const
3137		{
3138			StringIntMap bindingPoints;
3139
3140			for (StringVector::iterator it = args.begin(); it != args.end(); it++)
3141			{
3142				glw::GLuint idx = gl().getProgramResourceIndex(getProgram(), GL_SHADER_STORAGE_BLOCK, (*it).c_str());
3143				if (idx != GL_INVALID_INDEX)
3144				{
3145					glw::GLenum param = GL_BUFFER_BINDING;
3146					glw::GLint  value = -1;
3147					gl().getProgramResourceiv(getProgram(), GL_SHADER_STORAGE_BLOCK, idx, 1, &param, 1, NULL, &value);
3148					bool hasNoError = (GL_NO_ERROR == gl().getError());
3149					if (hasNoError)
3150					{
3151						bindingPoints[*it] = value;
3152					}
3153				}
3154			}
3155
3156			return bindingPoints;
3157		}
3158
3159		/*virtual*/
3160		bool setBindingPoints(StringVector list, glw::GLint bindingPoint) const
3161		{
3162			for (StringVector::iterator it = list.begin(); it != list.end(); it++)
3163			{
3164				glw::GLuint blockIndex =
3165					gl().getProgramResourceIndex(getProgram(), GL_SHADER_STORAGE_BLOCK, (*it).c_str());
3166				if (blockIndex == GL_INVALID_INDEX)
3167				{
3168					return false;
3169				}
3170				gl().shaderStorageBlockBinding(getProgram(), blockIndex, bindingPoint);
3171			}
3172			return true;
3173		}
3174	};
3175
3176private:
3177	// IProgramContextSupplier
3178	/*virtual*/
3179	LayoutBindingProgram* createProgram()
3180	{
3181		return new ShaderStorageBufferLayoutBindingProgram(*this);
3182	}
3183
3184private:
3185	/*virtual*/
3186	String buildLayout(const String& binding)
3187	{
3188		std::ostringstream s;
3189		if (!binding.empty())
3190			s << "layout(binding=" << binding << ", std430) ";
3191		else
3192			s << "layout(std430) ";
3193		return s.str();
3194	}
3195
3196	/*virtual*/
3197	String getDefaultUniformName(int idx = 0)
3198	{
3199		StringStream s;
3200
3201		s << "buffer" << idx;
3202		return s.str();
3203	}
3204	/*virtual*/
3205	String buildBlockName(const String& name)
3206	{
3207		return name;
3208	}
3209
3210	/*virtual*/
3211	String buildBlock(const String& name, const String& type)
3212	{
3213		std::ostringstream s;
3214		s << "{";
3215		s << type << " " << name << "_a[2];\n";
3216		s << "}";
3217		return s.str();
3218	}
3219
3220	/*virtual*/
3221	String buildAccess(const String& var)
3222	{
3223		std::ostringstream s;
3224		s << "vec4(0.0, " << var << "_a[0] + " << var << "_a[1], 0.0, 1.0)";
3225		return s.str();
3226	}
3227
3228	int maxBindings()
3229	{
3230		int units = 0;
3231		gl().getIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &units);
3232		return units;
3233	}
3234
3235	// return max. array size allowed
3236	int maxArraySize()
3237	{
3238		int units = 0;
3239		switch (getStage())
3240		{
3241		case FragmentShader:
3242			gl().getIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &units);
3243			break;
3244		case VertexShader:
3245			gl().getIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &units);
3246			break;
3247		case ComputeShader:
3248			gl().getIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &units);
3249			break;
3250		default:
3251			DE_ASSERT(0);
3252			break;
3253		}
3254		return units;
3255	}
3256
3257	/*virtual*/
3258	void bind(int binding)
3259	{
3260		gl().bindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, m_buffername);
3261	}
3262
3263	/*virtual*/
3264	void unbind(int binding)
3265	{
3266		gl().bindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, 0);
3267	}
3268
3269	/*virtual*/
3270	void setupTest(void)
3271	{
3272		const float f[2] = { 0.25f, 0.75f };
3273		gl().genBuffers(1, &m_buffername);
3274		gl().bindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffername);
3275		gl().bufferData(GL_SHADER_STORAGE_BUFFER, sizeof(f), f, GL_STATIC_DRAW);
3276	}
3277
3278	/*virtual*/
3279	void teardownTest(void)
3280	{
3281		gl().bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3282		gl().deleteBuffers(1, &m_buffername);
3283	}
3284
3285	//=========================================================================
3286	// sub-tests overrides
3287	//=========================================================================
3288private:
3289private:
3290	//virtual LayoutBindingTestResult        binding_basic_default               (void);
3291	//virtual LayoutBindingTestResult        binding_basic_explicit              (void);
3292	//virtual LayoutBindingTestResult        binding_basic_multiple              (void);
3293	//virtual LayoutBindingTestResult        binding_basic_render                (void);
3294	//virtual LayoutBindingTestResult        binding_integer_constant            (void);
3295	//virtual LayoutBindingTestResult        binding_integer_constant_expression (void);
3296	//virtual LayoutBindingTestResult        binding_array_size                  (void);
3297	//virtual LayoutBindingTestResult        binding_array_implicit              (void);
3298	//virtual LayoutBindingTestResult        binding_array_multiple              (void);
3299	/*virtual*/
3300	LayoutBindingTestResult binding_api_update(void)
3301	{
3302		// only for GL
3303		if (getGLSLVersion() == glu::GLSL_VERSION_310_ES)
3304			return LayoutBindingTestResult(true, String(), true);
3305
3306		return LayoutBindingBaseCase::binding_api_update();
3307	}
3308	//virtual LayoutBindingTestResult        binding_compilation_errors          (void);
3309	//virtual LayoutBindingTestResult        binding_link_errors                 (void);
3310	//virtual LayoutBindingTestResult        binding_examples                    (void);
3311
3312private:
3313	glw::GLuint m_buffername;
3314};
3315
3316ShaderStorageBufferLayoutBindingCase::ShaderStorageBufferLayoutBindingCase(Context& context, const char* name,
3317																		   const char* description, StageType stage,
3318																		   LayoutBindingParameters& samplerType,
3319																		   glu::GLSLVersion			glslVersion)
3320	: LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion), m_buffername(0)
3321{
3322}
3323
3324ShaderStorageBufferLayoutBindingCase::~ShaderStorageBufferLayoutBindingCase()
3325{
3326}
3327
3328//*****************************************************************************
3329
3330LayoutBindingTests::LayoutBindingTests(Context& context, glu::GLSLVersion glslVersion)
3331	: TestCaseGroup(context, "layout_binding", "Layout Binding LayoutBindingSubTest"), m_glslVersion(glslVersion)
3332{
3333}
3334
3335LayoutBindingTests::~LayoutBindingTests(void)
3336{
3337}
3338
3339StageType LayoutBindingTests::stageTypes[] = {
3340	{ "ComputeShader", ComputeShader },
3341	{ "FragmentShader", FragmentShader },
3342	{ "VertexShader", VertexShader },
3343};
3344
3345// uniform_type must match vector_type, i.e. isampler2D=>ivec4
3346LayoutBindingParameters LayoutBindingTests::test_args[] = {
3347	{ "uniform", Texture, TwoD, "vec4", "sampler2D", "vec2", "texture" },
3348	{ "uniform", Texture, ThreeD, "vec4", "sampler3D", "vec3", "texture" },
3349	{ "uniform", Texture, TwoDArray, "vec4", "sampler2DArray", "vec3", "texture" },
3350	{ "uniform", Image, TwoD, "vec4", "image2D", "ivec2", "imageLoad" },
3351	{ "uniform", AtomicCounter, TwoD, "vec4", "atomic_uint", "vec3", "atomic" },
3352	{ "uniform", UniformBlock, None, "vec4", "block", "vec3", "block" },
3353	{ "buffer", ShaderStorageBuffer, None, "vec4", "buffer", "vec3", "atomicAdd" },
3354};
3355
3356// create test name which must be unique or dEQP framework will throw
3357// example: sampler2D_layout_binding_vec4_texture_0
3358String LayoutBindingTests::createTestName(const StageType& stageType, const LayoutBindingParameters& testArgs)
3359{
3360	StringStream s;
3361	s << testArgs.uniform_type;
3362	s << "_layout_binding_";
3363	s << testArgs.access_function << "_";
3364	s << stageType.name;
3365	return s.str();
3366}
3367
3368void LayoutBindingTests::init(void)
3369{
3370	std::vector<StageType>				 stages   = makeVector(stageTypes);
3371	std::vector<LayoutBindingParameters> samplers = makeVector(test_args);
3372	for (std::vector<StageType>::iterator stagesIter = stages.begin(); stagesIter != stages.end(); stagesIter++)
3373	{
3374		for (std::vector<LayoutBindingParameters>::iterator testArgsIter = samplers.begin();
3375			 testArgsIter != samplers.end(); testArgsIter++)
3376		{
3377			String testName = createTestName(*stagesIter, *testArgsIter);
3378			switch ((*testArgsIter).surface_type)
3379			{
3380			case Texture:
3381				addChild(new SamplerLayoutBindingCase(m_context, testName.c_str(),
3382													  "test sampler layout binding functionality", *stagesIter,
3383													  *testArgsIter, m_glslVersion));
3384				break;
3385			case Image:
3386				addChild(new ImageLayoutBindingCase(m_context, testName.c_str(),
3387													"test image layout binding functionality", *stagesIter,
3388													*testArgsIter, m_glslVersion));
3389				break;
3390			case AtomicCounter:
3391				addChild(new AtomicCounterLayoutBindingCase(m_context, testName.c_str(),
3392															"test atomic counters layout binding functionality",
3393															*stagesIter, *testArgsIter, m_glslVersion));
3394				break;
3395			case UniformBlock:
3396				addChild(new UniformBlocksLayoutBindingCase(m_context, testName.c_str(),
3397															"test uniform block layout binding functionality",
3398															*stagesIter, *testArgsIter, m_glslVersion));
3399				break;
3400			case ShaderStorageBuffer:
3401				addChild(new ShaderStorageBufferLayoutBindingCase(
3402					m_context, testName.c_str(), "test shader storage buffer layout binding functionality", *stagesIter,
3403					*testArgsIter, m_glslVersion));
3404				break;
3405			default:
3406				DE_ASSERT(0);
3407				break;
3408			}
3409		}
3410	}
3411}
3412
3413} // glcts
3414