• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Opaque type (sampler, buffer, atomic counter, ...) indexing tests.
22  *
23  * \todo [2014-03-05 pyry] Extend with following:
24  *  + sampler: different filtering modes, multiple sizes, incomplete textures
25  *  + SSBO: write, atomic op, unsized array .length()
26  *//*--------------------------------------------------------------------*/
27 
28 #include "es31fOpaqueTypeIndexingTests.hpp"
29 #include "tcuTexture.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuFormatUtil.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "gluShaderUtil.hpp"
34 #include "gluShaderProgram.hpp"
35 #include "gluObjectWrapper.hpp"
36 #include "gluTextureUtil.hpp"
37 #include "gluRenderContext.hpp"
38 #include "gluProgramInterfaceQuery.hpp"
39 #include "gluContextInfo.hpp"
40 #include "glsShaderExecUtil.hpp"
41 #include "glwFunctions.hpp"
42 #include "glwEnums.hpp"
43 #include "deUniquePtr.hpp"
44 #include "deStringUtil.hpp"
45 #include "deRandom.hpp"
46 
47 #include <sstream>
48 
49 namespace deqp
50 {
51 namespace gles31
52 {
53 namespace Functional
54 {
55 
56 namespace
57 {
58 
59 using namespace gls::ShaderExecUtil;
60 using namespace glu;
61 using std::string;
62 using std::vector;
63 using tcu::TextureFormat;
64 using tcu::TestLog;
65 
66 typedef de::UniquePtr<ShaderExecutor> ShaderExecutorPtr;
67 
68 enum IndexExprType
69 {
70 	INDEX_EXPR_TYPE_CONST_LITERAL	= 0,
71 	INDEX_EXPR_TYPE_CONST_EXPRESSION,
72 	INDEX_EXPR_TYPE_UNIFORM,
73 	INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,
74 
75 	INDEX_EXPR_TYPE_LAST
76 };
77 
78 enum TextureType
79 {
80 	TEXTURE_TYPE_1D = 0,
81 	TEXTURE_TYPE_2D,
82 	TEXTURE_TYPE_CUBE,
83 	TEXTURE_TYPE_2D_ARRAY,
84 	TEXTURE_TYPE_3D,
85 
86 	TEXTURE_TYPE_LAST
87 };
88 
declareUniformIndexVars(std::ostream & str,const char * varPrefix,int numVars)89 static void declareUniformIndexVars (std::ostream& str, const char* varPrefix, int numVars)
90 {
91 	for (int varNdx = 0; varNdx < numVars; varNdx++)
92 		str << "uniform highp int " << varPrefix << varNdx << ";\n";
93 }
94 
uploadUniformIndices(const glw::Functions & gl,deUint32 program,const char * varPrefix,int numIndices,const int * indices)95 static void uploadUniformIndices (const glw::Functions& gl, deUint32 program, const char* varPrefix, int numIndices, const int* indices)
96 {
97 	for (int varNdx = 0; varNdx < numIndices; varNdx++)
98 	{
99 		const string	varName		= varPrefix + de::toString(varNdx);
100 		const int		loc			= gl.getUniformLocation(program, varName.c_str());
101 		TCU_CHECK_MSG(loc >= 0, ("No location assigned for uniform '" + varName + "'").c_str());
102 
103 		gl.uniform1i(loc, indices[varNdx]);
104 	}
105 }
106 
107 template<typename T>
maxElement(const std::vector<T> & elements)108 static T maxElement (const std::vector<T>& elements)
109 {
110 	T maxElem = elements[0];
111 
112 	for (size_t ndx = 1; ndx < elements.size(); ndx++)
113 		maxElem = de::max(maxElem, elements[ndx]);
114 
115 	return maxElem;
116 }
117 
getTextureType(glu::DataType samplerType)118 static TextureType getTextureType (glu::DataType samplerType)
119 {
120 	switch (samplerType)
121 	{
122 		case glu::TYPE_SAMPLER_1D:
123 		case glu::TYPE_INT_SAMPLER_1D:
124 		case glu::TYPE_UINT_SAMPLER_1D:
125 		case glu::TYPE_SAMPLER_1D_SHADOW:
126 			return TEXTURE_TYPE_1D;
127 
128 		case glu::TYPE_SAMPLER_2D:
129 		case glu::TYPE_INT_SAMPLER_2D:
130 		case glu::TYPE_UINT_SAMPLER_2D:
131 		case glu::TYPE_SAMPLER_2D_SHADOW:
132 			return TEXTURE_TYPE_2D;
133 
134 		case glu::TYPE_SAMPLER_CUBE:
135 		case glu::TYPE_INT_SAMPLER_CUBE:
136 		case glu::TYPE_UINT_SAMPLER_CUBE:
137 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
138 			return TEXTURE_TYPE_CUBE;
139 
140 		case glu::TYPE_SAMPLER_2D_ARRAY:
141 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
142 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
143 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
144 			return TEXTURE_TYPE_2D_ARRAY;
145 
146 		case glu::TYPE_SAMPLER_3D:
147 		case glu::TYPE_INT_SAMPLER_3D:
148 		case glu::TYPE_UINT_SAMPLER_3D:
149 			return TEXTURE_TYPE_3D;
150 
151 		default:
152 			throw tcu::InternalError("Invalid sampler type");
153 	}
154 }
155 
isShadowSampler(glu::DataType samplerType)156 static bool isShadowSampler (glu::DataType samplerType)
157 {
158 	return samplerType == glu::TYPE_SAMPLER_1D_SHADOW		||
159 		   samplerType == glu::TYPE_SAMPLER_2D_SHADOW		||
160 		   samplerType == glu::TYPE_SAMPLER_2D_ARRAY_SHADOW	||
161 		   samplerType == glu::TYPE_SAMPLER_CUBE_SHADOW;
162 }
163 
getSamplerOutputType(glu::DataType samplerType)164 static glu::DataType getSamplerOutputType (glu::DataType samplerType)
165 {
166 	switch (samplerType)
167 	{
168 		case glu::TYPE_SAMPLER_1D:
169 		case glu::TYPE_SAMPLER_2D:
170 		case glu::TYPE_SAMPLER_CUBE:
171 		case glu::TYPE_SAMPLER_2D_ARRAY:
172 		case glu::TYPE_SAMPLER_3D:
173 			return glu::TYPE_FLOAT_VEC4;
174 
175 		case glu::TYPE_SAMPLER_1D_SHADOW:
176 		case glu::TYPE_SAMPLER_2D_SHADOW:
177 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
178 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
179 			return glu::TYPE_FLOAT;
180 
181 		case glu::TYPE_INT_SAMPLER_1D:
182 		case glu::TYPE_INT_SAMPLER_2D:
183 		case glu::TYPE_INT_SAMPLER_CUBE:
184 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
185 		case glu::TYPE_INT_SAMPLER_3D:
186 			return glu::TYPE_INT_VEC4;
187 
188 		case glu::TYPE_UINT_SAMPLER_1D:
189 		case glu::TYPE_UINT_SAMPLER_2D:
190 		case glu::TYPE_UINT_SAMPLER_CUBE:
191 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
192 		case glu::TYPE_UINT_SAMPLER_3D:
193 			return glu::TYPE_UINT_VEC4;
194 
195 		default:
196 			throw tcu::InternalError("Invalid sampler type");
197 	}
198 }
199 
getSamplerTextureFormat(glu::DataType samplerType)200 static tcu::TextureFormat getSamplerTextureFormat (glu::DataType samplerType)
201 {
202 	const glu::DataType		outType			= getSamplerOutputType(samplerType);
203 	const glu::DataType		outScalarType	= glu::getDataTypeScalarType(outType);
204 
205 	switch (outScalarType)
206 	{
207 		case glu::TYPE_FLOAT:
208 			if (isShadowSampler(samplerType))
209 				return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
210 			else
211 				return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
212 
213 		case glu::TYPE_INT:		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8);
214 		case glu::TYPE_UINT:	return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8);
215 
216 		default:
217 			throw tcu::InternalError("Invalid sampler type");
218 	}
219 }
220 
getSamplerCoordType(glu::DataType samplerType)221 static glu::DataType getSamplerCoordType (glu::DataType samplerType)
222 {
223 	const TextureType	texType		= getTextureType(samplerType);
224 	int					numCoords	= 0;
225 
226 	switch (texType)
227 	{
228 		case TEXTURE_TYPE_1D:		numCoords = 1;	break;
229 		case TEXTURE_TYPE_2D:		numCoords = 2;	break;
230 		case TEXTURE_TYPE_2D_ARRAY:	numCoords = 3;	break;
231 		case TEXTURE_TYPE_CUBE:		numCoords = 3;	break;
232 		case TEXTURE_TYPE_3D:		numCoords = 3;	break;
233 		default:
234 			DE_ASSERT(false);
235 	}
236 
237 	if (isShadowSampler(samplerType))
238 		numCoords += 1;
239 
240 	DE_ASSERT(de::inRange(numCoords, 1, 4));
241 
242 	return numCoords == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(numCoords);
243 }
244 
getGLTextureTarget(TextureType texType)245 static deUint32 getGLTextureTarget (TextureType texType)
246 {
247 	switch (texType)
248 	{
249 		case TEXTURE_TYPE_1D:		return GL_TEXTURE_1D;
250 		case TEXTURE_TYPE_2D:		return GL_TEXTURE_2D;
251 		case TEXTURE_TYPE_2D_ARRAY:	return GL_TEXTURE_2D_ARRAY;
252 		case TEXTURE_TYPE_CUBE:		return GL_TEXTURE_CUBE_MAP;
253 		case TEXTURE_TYPE_3D:		return GL_TEXTURE_3D;
254 		default:
255 			DE_ASSERT(false);
256 			return 0;
257 	}
258 }
259 
setupTexture(const glw::Functions & gl,deUint32 texture,glu::DataType samplerType,tcu::TextureFormat texFormat,const void * color)260 static void setupTexture (const glw::Functions&	gl,
261 						  deUint32				texture,
262 						  glu::DataType			samplerType,
263 						  tcu::TextureFormat	texFormat,
264 						  const void*			color)
265 {
266 	const TextureType			texType		= getTextureType(samplerType);
267 	const deUint32				texTarget	= getGLTextureTarget(texType);
268 	const deUint32				intFormat	= glu::getInternalFormat(texFormat);
269 	const glu::TransferFormat	transferFmt	= glu::getTransferFormat(texFormat);
270 
271 	// \todo [2014-03-04 pyry] Use larger than 1x1 textures?
272 
273 	gl.bindTexture(texTarget, texture);
274 
275 	switch (texType)
276 	{
277 		case TEXTURE_TYPE_1D:
278 			gl.texStorage1D(texTarget, 1, intFormat, 1);
279 			gl.texSubImage1D(texTarget, 0, 0, 1, transferFmt.format, transferFmt.dataType, color);
280 			break;
281 
282 		case TEXTURE_TYPE_2D:
283 			gl.texStorage2D(texTarget, 1, intFormat, 1, 1);
284 			gl.texSubImage2D(texTarget, 0, 0, 0, 1, 1, transferFmt.format, transferFmt.dataType, color);
285 			break;
286 
287 		case TEXTURE_TYPE_2D_ARRAY:
288 		case TEXTURE_TYPE_3D:
289 			gl.texStorage3D(texTarget, 1, intFormat, 1, 1, 1);
290 			gl.texSubImage3D(texTarget, 0, 0, 0, 0, 1, 1, 1, transferFmt.format, transferFmt.dataType, color);
291 			break;
292 
293 		case TEXTURE_TYPE_CUBE:
294 			gl.texStorage2D(texTarget, 1, intFormat, 1, 1);
295 			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
296 				gl.texSubImage2D(glu::getGLCubeFace((tcu::CubeFace)face), 0, 0, 0, 1, 1, transferFmt.format, transferFmt.dataType, color);
297 			break;
298 
299 		default:
300 			DE_ASSERT(false);
301 	}
302 
303 	gl.texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
304 	gl.texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
305 
306 	if (isShadowSampler(samplerType))
307 		gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
308 
309 	GLU_EXPECT_NO_ERROR(gl.getError(), "Texture setup failed");
310 }
311 
312 class SamplerIndexingCase : public TestCase
313 {
314 public:
315 							SamplerIndexingCase			(Context& context, const char* name, const char* description, glu::ShaderType shaderType, glu::DataType samplerType, IndexExprType indexExprType);
316 							~SamplerIndexingCase		(void);
317 
318 	void					init						(void);
319 	IterateResult			iterate						(void);
320 
321 private:
322 							SamplerIndexingCase			(const SamplerIndexingCase&);
323 	SamplerIndexingCase&	operator=					(const SamplerIndexingCase&);
324 
325 	void					getShaderSpec				(ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices) const;
326 
327 	const glu::ShaderType	m_shaderType;
328 	const glu::DataType		m_samplerType;
329 	const IndexExprType		m_indexExprType;
330 };
331 
SamplerIndexingCase(Context & context,const char * name,const char * description,glu::ShaderType shaderType,glu::DataType samplerType,IndexExprType indexExprType)332 SamplerIndexingCase::SamplerIndexingCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType, glu::DataType samplerType, IndexExprType indexExprType)
333 	: TestCase			(context, name, description)
334 	, m_shaderType		(shaderType)
335 	, m_samplerType		(samplerType)
336 	, m_indexExprType	(indexExprType)
337 {
338 }
339 
~SamplerIndexingCase(void)340 SamplerIndexingCase::~SamplerIndexingCase (void)
341 {
342 }
343 
init(void)344 void SamplerIndexingCase::init (void)
345 {
346 	const char* extName = "GL_EXT_gpu_shader5";
347 
348 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
349 		!m_context.getContextInfo().isExtensionSupported(extName))
350 		throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of sampler arrays");
351 }
352 
getShaderSpec(ShaderSpec * spec,int numSamplers,int numLookups,const int * lookupIndices) const353 void SamplerIndexingCase::getShaderSpec (ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices) const
354 {
355 	const char*			samplersName	= "sampler";
356 	const char*			coordsName		= "coords";
357 	const char*			indicesPrefix	= "index";
358 	const char*			resultPrefix	= "result";
359 	const DataType		coordType		= getSamplerCoordType(m_samplerType);
360 	const DataType		outType			= getSamplerOutputType(m_samplerType);
361 	std::ostringstream	global, code;
362 
363 	spec->inputs.push_back(Symbol(coordsName, VarType(coordType, PRECISION_HIGHP)));
364 
365 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
366 		global << "#extension GL_EXT_gpu_shader5 : require\n";
367 
368 	if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
369 		global << "const highp int indexBase = 1;\n";
370 
371 	global <<
372 		"uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << numSamplers << "];\n";
373 
374 	if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
375 	{
376 		for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
377 		{
378 			const string varName = indicesPrefix + de::toString(lookupNdx);
379 			spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
380 		}
381 	}
382 	else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
383 		declareUniformIndexVars(global, indicesPrefix, numLookups);
384 
385 	for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
386 	{
387 		const string varName = resultPrefix + de::toString(lookupNdx);
388 		spec->outputs.push_back(Symbol(varName, VarType(outType, PRECISION_HIGHP)));
389 	}
390 
391 	for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
392 	{
393 		code << resultPrefix << "" << lookupNdx << " = texture(" << samplersName << "[";
394 
395 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
396 			code << lookupIndices[lookupNdx];
397 		else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
398 			code << "indexBase + " << (lookupIndices[lookupNdx]-1);
399 		else
400 			code << indicesPrefix << lookupNdx;
401 
402 		code << "], " << coordsName << ");\n";
403 	}
404 
405 	spec->version				= GLSL_VERSION_310_ES;
406 	spec->globalDeclarations	= global.str();
407 	spec->source				= code.str();
408 }
409 
fillTextureData(const tcu::PixelBufferAccess & access,de::Random & rnd)410 static void fillTextureData (const tcu::PixelBufferAccess& access, de::Random& rnd)
411 {
412 	DE_ASSERT(access.getHeight() == 1 && access.getDepth() == 1);
413 
414 	if (access.getFormat().order == TextureFormat::D)
415 	{
416 		// \note Texture uses odd values, lookup even values to avoid precision issues.
417 		const float values[] = { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f };
418 
419 		for (int ndx = 0; ndx < access.getWidth(); ndx++)
420 			access.setPixDepth(rnd.choose<float>(DE_ARRAY_BEGIN(values), DE_ARRAY_END(values)), ndx, 0);
421 	}
422 	else
423 	{
424 		TCU_CHECK_INTERNAL(access.getFormat().order == TextureFormat::RGBA && access.getFormat().getPixelSize() == 4);
425 
426 		for (int ndx = 0; ndx < access.getWidth(); ndx++)
427 			*((deUint32*)access.getDataPtr() + ndx) = rnd.getUint32();
428 	}
429 }
430 
iterate(void)431 SamplerIndexingCase::IterateResult SamplerIndexingCase::iterate (void)
432 {
433 	const int						numInvocations		= 64;
434 	const int						numSamplers			= 8;
435 	const int						numLookups			= 4;
436 	const DataType					coordType			= getSamplerCoordType(m_samplerType);
437 	const DataType					outputType			= getSamplerOutputType(m_samplerType);
438 	const TextureFormat				texFormat			= getSamplerTextureFormat(m_samplerType);
439 	const int						outLookupStride		= numInvocations*getDataTypeScalarSize(outputType);
440 	vector<int>						lookupIndices		(numLookups);
441 	vector<float>					coords;
442 	vector<deUint32>				outData;
443 	vector<deUint8>					texData				(numSamplers * texFormat.getPixelSize());
444 	const tcu::PixelBufferAccess	refTexAccess		(texFormat, numSamplers, 1, 1, &texData[0]);
445 	ShaderSpec						shaderSpec;
446 	de::Random						rnd					(deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
447 
448 	for (int ndx = 0; ndx < numLookups; ndx++)
449 		lookupIndices[ndx] = rnd.getInt(0, numSamplers-1);
450 
451 	getShaderSpec(&shaderSpec, numSamplers, numLookups, &lookupIndices[0]);
452 
453 	coords.resize(numInvocations * getDataTypeScalarSize(coordType));
454 
455 	if (isShadowSampler(m_samplerType))
456 	{
457 		// Use different comparison value per invocation.
458 		// \note Texture uses odd values, comparison even values.
459 		const int	numCoordComps	= getDataTypeScalarSize(coordType);
460 		const float	cmpValues[]		= { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
461 
462 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
463 			coords[invocationNdx*numCoordComps + (numCoordComps-1)] = rnd.choose<float>(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues));
464 	}
465 
466 	fillTextureData(refTexAccess, rnd);
467 
468 	outData.resize(numLookups*outLookupStride);
469 
470 	{
471 		const RenderContext&	renderCtx		= m_context.getRenderContext();
472 		const glw::Functions&	gl				= renderCtx.getFunctions();
473 		ShaderExecutorPtr		executor		(createExecutor(m_context.getRenderContext(), m_shaderType, shaderSpec));
474 		TextureVector			textures		(renderCtx, numSamplers);
475 		vector<void*>			inputs;
476 		vector<void*>			outputs;
477 		vector<int>				expandedIndices;
478 		const int				maxIndex		= maxElement(lookupIndices);
479 
480 		m_testCtx.getLog() << *executor;
481 
482 		if (!executor->isOk())
483 			TCU_FAIL("Compile failed");
484 
485 		executor->useProgram();
486 
487 		// \todo [2014-03-05 pyry] Do we want to randomize tex unit assignments?
488 		for (int samplerNdx = 0; samplerNdx < numSamplers; samplerNdx++)
489 		{
490 			const string	samplerName	= string("sampler[") + de::toString(samplerNdx) + "]";
491 			const int		samplerLoc	= gl.getUniformLocation(executor->getProgram(), samplerName.c_str());
492 
493 			if (samplerNdx > maxIndex && samplerLoc < 0)
494 				continue; // Unused uniform eliminated by compiler
495 
496 			TCU_CHECK_MSG(samplerLoc >= 0, (string("No location for uniform '") + samplerName + "' found").c_str());
497 
498 			gl.activeTexture(GL_TEXTURE0 + samplerNdx);
499 			setupTexture(gl, textures[samplerNdx], m_samplerType, texFormat, &texData[samplerNdx*texFormat.getPixelSize()]);
500 
501 			gl.uniform1i(samplerLoc, samplerNdx);
502 		}
503 
504 		inputs.push_back(&coords[0]);
505 
506 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
507 		{
508 			expandedIndices.resize(numInvocations * lookupIndices.size());
509 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
510 			{
511 				for (int invNdx = 0; invNdx < numInvocations; invNdx++)
512 					expandedIndices[lookupNdx*numInvocations + invNdx] = lookupIndices[lookupNdx];
513 			}
514 
515 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
516 				inputs.push_back(&expandedIndices[lookupNdx*numInvocations]);
517 		}
518 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
519 			uploadUniformIndices(gl, executor->getProgram(), "index", numLookups, &lookupIndices[0]);
520 
521 		for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
522 			outputs.push_back(&outData[outLookupStride*lookupNdx]);
523 
524 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
525 
526 		executor->execute(numInvocations, &inputs[0], &outputs[0]);
527 	}
528 
529 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
530 
531 	if (isShadowSampler(m_samplerType))
532 	{
533 		const tcu::Sampler	refSampler		(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
534 											 tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0.0f, false /* non-normalized */,
535 											 tcu::Sampler::COMPAREMODE_LESS);
536 		const int			numCoordComps	= getDataTypeScalarSize(coordType);
537 
538 		TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 1);
539 
540 		// Each invocation may have different results.
541 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
542 		{
543 			const float	coord	= coords[invocationNdx*numCoordComps + (numCoordComps-1)];
544 
545 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
546 			{
547 				const int		texNdx		= lookupIndices[lookupNdx];
548 				const float		result		= *((const float*)(const deUint8*)&outData[lookupNdx*outLookupStride + invocationNdx]);
549 				const float		reference	= refTexAccess.sample2DCompare(refSampler, tcu::Sampler::NEAREST, coord, (float)texNdx, 0.0f, tcu::IVec3(0));
550 
551 				if (de::abs(result-reference) > 0.005f)
552 				{
553 					m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx << ", lookup " << lookupNdx << ": expected "
554 														   << reference << ", got " << result
555 									   << TestLog::EndMessage;
556 
557 					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
558 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result");
559 				}
560 			}
561 		}
562 	}
563 	else
564 	{
565 		TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 4);
566 
567 		// Validate results from first invocation
568 		for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
569 		{
570 			const int		texNdx	= lookupIndices[lookupNdx];
571 			const deUint8*	resPtr	= (const deUint8*)&outData[lookupNdx*outLookupStride];
572 			bool			isOk;
573 
574 			if (outputType == TYPE_FLOAT_VEC4)
575 			{
576 				const float			threshold		= 1.0f / 256.0f;
577 				const tcu::Vec4		reference		= refTexAccess.getPixel(texNdx, 0);
578 				const float*		floatPtr		= (const float*)resPtr;
579 				const tcu::Vec4		result			(floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3]);
580 
581 				isOk = boolAll(lessThanEqual(abs(reference-result), tcu::Vec4(threshold)));
582 
583 				if (!isOk)
584 				{
585 					m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
586 														   << reference << ", got " << result
587 									   << TestLog::EndMessage;
588 				}
589 			}
590 			else
591 			{
592 				const tcu::UVec4	reference		= refTexAccess.getPixelUint(texNdx, 0);
593 				const deUint32*		uintPtr			= (const deUint32*)resPtr;
594 				const tcu::UVec4	result			(uintPtr[0], uintPtr[1], uintPtr[2], uintPtr[3]);
595 
596 				isOk = boolAll(equal(reference, result));
597 
598 				if (!isOk)
599 				{
600 					m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
601 														   << reference << ", got " << result
602 									   << TestLog::EndMessage;
603 				}
604 			}
605 
606 			if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
607 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result");
608 		}
609 
610 		// Check results of other invocations against first one
611 		for (int invocationNdx = 1; invocationNdx < numInvocations; invocationNdx++)
612 		{
613 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
614 			{
615 				const deUint32*		refPtr		= &outData[lookupNdx*outLookupStride];
616 				const deUint32*		resPtr		= refPtr + invocationNdx*4;
617 				bool				isOk		= true;
618 
619 				for (int ndx = 0; ndx < 4; ndx++)
620 					isOk = isOk && (refPtr[ndx] == resPtr[ndx]);
621 
622 				if (!isOk)
623 				{
624 					m_testCtx.getLog() << TestLog::Message << "ERROR: invocation " << invocationNdx << " result "
625 														   << tcu::formatArray(tcu::Format::HexIterator<deUint32>(resPtr), tcu::Format::HexIterator<deUint32>(resPtr+4))
626 														   << " for lookup " << lookupNdx << " doesn't match result from first invocation "
627 														   << tcu::formatArray(tcu::Format::HexIterator<deUint32>(refPtr), tcu::Format::HexIterator<deUint32>(refPtr+4))
628 									   << TestLog::EndMessage;
629 
630 					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
631 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsistent lookup results");
632 				}
633 			}
634 		}
635 	}
636 
637 	return STOP;
638 }
639 
640 class BlockArrayIndexingCase : public TestCase
641 {
642 public:
643 	enum BlockType
644 	{
645 		BLOCKTYPE_UNIFORM = 0,
646 		BLOCKTYPE_BUFFER,
647 
648 		BLOCKTYPE_LAST
649 	};
650 								BlockArrayIndexingCase		(Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType);
651 								~BlockArrayIndexingCase		(void);
652 
653 	void						init						(void);
654 	IterateResult				iterate						(void);
655 
656 private:
657 								BlockArrayIndexingCase		(const BlockArrayIndexingCase&);
658 	BlockArrayIndexingCase&		operator=					(const BlockArrayIndexingCase&);
659 
660 	void						getShaderSpec				(ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const;
661 
662 	const BlockType				m_blockType;
663 	const IndexExprType			m_indexExprType;
664 	const ShaderType			m_shaderType;
665 
666 	const int					m_numInstances;
667 };
668 
BlockArrayIndexingCase(Context & context,const char * name,const char * description,BlockType blockType,IndexExprType indexExprType,ShaderType shaderType)669 BlockArrayIndexingCase::BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType)
670 	: TestCase			(context, name, description)
671 	, m_blockType		(blockType)
672 	, m_indexExprType	(indexExprType)
673 	, m_shaderType		(shaderType)
674 	, m_numInstances	(4)
675 {
676 }
677 
~BlockArrayIndexingCase(void)678 BlockArrayIndexingCase::~BlockArrayIndexingCase (void)
679 {
680 }
681 
init(void)682 void BlockArrayIndexingCase::init (void)
683 {
684 	const char* extName = "GL_EXT_gpu_shader5";
685 
686 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
687 		!m_context.getContextInfo().isExtensionSupported(extName))
688 		throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of interface blocks");
689 
690 	if (m_blockType == BLOCKTYPE_BUFFER)
691 	{
692 		const deUint32 limitPnames[] =
693 		{
694 			GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,
695 			GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,
696 			GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
697 			GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
698 			GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
699 			GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS
700 		};
701 
702 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
703 		int						maxBlocks	= 0;
704 
705 		gl.getIntegerv(limitPnames[m_shaderType], &maxBlocks);
706 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()");
707 
708 		if (maxBlocks < m_numInstances)
709 			throw tcu::NotSupportedError("Not enough shader storage blocks supported for shader type");
710 	}
711 }
712 
getShaderSpec(ShaderSpec * spec,int numInstances,int numReads,const int * readIndices) const713 void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const
714 {
715 	const int			binding			= 2;
716 	const char*			blockName		= "Block";
717 	const char*			instanceName	= "block";
718 	const char*			indicesPrefix	= "index";
719 	const char*			resultPrefix	= "result";
720 	const char*			interfaceName	= m_blockType == BLOCKTYPE_UNIFORM ? "uniform" : "buffer";
721 	const char*			layout			= m_blockType == BLOCKTYPE_UNIFORM ? "std140" : "std430";
722 	std::ostringstream	global, code;
723 
724 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
725 		global << "#extension GL_EXT_gpu_shader5 : require\n";
726 
727 	if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
728 		global << "const highp int indexBase = 1;\n";
729 
730 	global <<
731 		"layout(" << layout << ", binding = " << binding << ") " << interfaceName << " " << blockName << "\n"
732 		"{\n"
733 		"	uint value;\n"
734 		"} " << instanceName << "[" << numInstances << "];\n";
735 
736 	if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
737 	{
738 		for (int readNdx = 0; readNdx < numReads; readNdx++)
739 		{
740 			const string varName = indicesPrefix + de::toString(readNdx);
741 			spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
742 		}
743 	}
744 	else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
745 		declareUniformIndexVars(global, indicesPrefix, numReads);
746 
747 	for (int readNdx = 0; readNdx < numReads; readNdx++)
748 	{
749 		const string varName = resultPrefix + de::toString(readNdx);
750 		spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP)));
751 	}
752 
753 	for (int readNdx = 0; readNdx < numReads; readNdx++)
754 	{
755 		code << resultPrefix << readNdx << " = " << instanceName << "[";
756 
757 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
758 			code << readIndices[readNdx];
759 		else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
760 			code << "indexBase + " << (readIndices[readNdx]-1);
761 		else
762 			code << indicesPrefix << readNdx;
763 
764 		code << "].value;\n";
765 	}
766 
767 	spec->version				= GLSL_VERSION_310_ES;
768 	spec->globalDeclarations	= global.str();
769 	spec->source				= code.str();
770 }
771 
iterate(void)772 BlockArrayIndexingCase::IterateResult BlockArrayIndexingCase::iterate (void)
773 {
774 	const int			numInvocations		= 32;
775 	const int			numInstances		= m_numInstances;
776 	const int			numReads			= 4;
777 	vector<int>			readIndices			(numReads);
778 	vector<deUint32>	inValues			(numInstances);
779 	vector<deUint32>	outValues			(numInvocations*numReads);
780 	ShaderSpec			shaderSpec;
781 	de::Random			rnd					(deInt32Hash(m_shaderType) ^ deInt32Hash(m_blockType) ^ deInt32Hash(m_indexExprType));
782 
783 	for (int readNdx = 0; readNdx < numReads; readNdx++)
784 		readIndices[readNdx] = rnd.getInt(0, numInstances-1);
785 
786 	for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
787 		inValues[instanceNdx] = rnd.getUint32();
788 
789 	getShaderSpec(&shaderSpec, numInstances, numReads, &readIndices[0]);
790 
791 	{
792 		const RenderContext&	renderCtx		= m_context.getRenderContext();
793 		const glw::Functions&	gl				= renderCtx.getFunctions();
794 		const int				baseBinding		= 2;
795 		const BufferVector		buffers			(renderCtx, numInstances);
796 		const deUint32			bufTarget		= m_blockType == BLOCKTYPE_BUFFER ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER;
797 		ShaderExecutorPtr		shaderExecutor	(createExecutor(renderCtx, m_shaderType, shaderSpec));
798 		vector<int>				expandedIndices;
799 		vector<void*>			inputs;
800 		vector<void*>			outputs;
801 
802 		m_testCtx.getLog() << *shaderExecutor;
803 
804 		if (!shaderExecutor->isOk())
805 			TCU_FAIL("Compile failed");
806 
807 		shaderExecutor->useProgram();
808 
809 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
810 		{
811 			gl.bindBuffer(bufTarget, buffers[instanceNdx]);
812 			gl.bufferData(bufTarget, (glw::GLsizeiptr)sizeof(deUint32), &inValues[instanceNdx], GL_STATIC_DRAW);
813 			gl.bindBufferBase(bufTarget, baseBinding+instanceNdx, buffers[instanceNdx]);
814 		}
815 
816 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
817 		{
818 			expandedIndices.resize(numInvocations * readIndices.size());
819 
820 			for (int readNdx = 0; readNdx < numReads; readNdx++)
821 			{
822 				int* dst = &expandedIndices[numInvocations*readNdx];
823 				std::fill(dst, dst+numInvocations, readIndices[readNdx]);
824 			}
825 
826 			for (int readNdx = 0; readNdx < numReads; readNdx++)
827 				inputs.push_back(&expandedIndices[readNdx*numInvocations]);
828 		}
829 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
830 			uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numReads, &readIndices[0]);
831 
832 		for (int readNdx = 0; readNdx < numReads; readNdx++)
833 			outputs.push_back(&outValues[readNdx*numInvocations]);
834 
835 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
836 
837 		shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
838 	}
839 
840 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
841 
842 	for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
843 	{
844 		for (int readNdx = 0; readNdx < numReads; readNdx++)
845 		{
846 			const deUint32	refValue	= inValues[readIndices[readNdx]];
847 			const deUint32	resValue	= outValues[readNdx*numInvocations + invocationNdx];
848 
849 			if (refValue != resValue)
850 			{
851 				m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx
852 													   << ", read " << readNdx << ": expected "
853 													   << tcu::toHex(refValue) << ", got " << tcu::toHex(resValue)
854 								   << TestLog::EndMessage;
855 
856 				if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
857 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value");
858 			}
859 		}
860 	}
861 
862 	return STOP;
863 }
864 
865 class AtomicCounterIndexingCase : public TestCase
866 {
867 public:
868 								AtomicCounterIndexingCase		(Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType);
869 								~AtomicCounterIndexingCase		(void);
870 
871 	void						init							(void);
872 	IterateResult				iterate							(void);
873 
874 private:
875 								AtomicCounterIndexingCase		(const AtomicCounterIndexingCase&);
876 	AtomicCounterIndexingCase&	operator=						(const AtomicCounterIndexingCase&);
877 
878 	void						getShaderSpec					(ShaderSpec* spec, int numCounters, int numOps, const int* opIndices) const;
879 
880 	const IndexExprType			m_indexExprType;
881 	const glu::ShaderType		m_shaderType;
882 };
883 
AtomicCounterIndexingCase(Context & context,const char * name,const char * description,IndexExprType indexExprType,ShaderType shaderType)884 AtomicCounterIndexingCase::AtomicCounterIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType)
885 	: TestCase			(context, name, description)
886 	, m_indexExprType	(indexExprType)
887 	, m_shaderType		(shaderType)
888 {
889 }
890 
~AtomicCounterIndexingCase(void)891 AtomicCounterIndexingCase::~AtomicCounterIndexingCase (void)
892 {
893 }
894 
init(void)895 void AtomicCounterIndexingCase::init (void)
896 {
897 	const char* extName = "GL_EXT_gpu_shader5";
898 
899 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
900 		!m_context.getContextInfo().isExtensionSupported(extName))
901 		throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of atomic counters");
902 
903 	if (m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT)
904 	{
905 		int numAtomicCounterBuffers = 0;
906 		m_context.getRenderContext().getFunctions().getIntegerv(m_shaderType == glu::SHADERTYPE_VERTEX ? GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS
907 																									   : GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,
908 																&numAtomicCounterBuffers);
909 
910 		if (numAtomicCounterBuffers == 0)
911 			throw tcu::NotSupportedError(string("Atomic counters not supported in ") + glu::getShaderTypeName(m_shaderType) + " shader");
912 	}
913 }
914 
getShaderSpec(ShaderSpec * spec,int numCounters,int numOps,const int * opIndices) const915 void AtomicCounterIndexingCase::getShaderSpec (ShaderSpec* spec, int numCounters, int numOps, const int* opIndices) const
916 {
917 	const char*			indicesPrefix	= "index";
918 	const char*			resultPrefix	= "result";
919 	std::ostringstream	global, code;
920 
921 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
922 		global << "#extension GL_EXT_gpu_shader5 : require\n";
923 
924 	if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
925 		global << "const highp int indexBase = 1;\n";
926 
927 	global <<
928 		"layout(binding = 0) uniform atomic_uint counter[" << numCounters << "];\n";
929 
930 	if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
931 	{
932 		for (int opNdx = 0; opNdx < numOps; opNdx++)
933 		{
934 			const string varName = indicesPrefix + de::toString(opNdx);
935 			spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
936 		}
937 	}
938 	else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
939 		declareUniformIndexVars(global, indicesPrefix, numOps);
940 
941 	for (int opNdx = 0; opNdx < numOps; opNdx++)
942 	{
943 		const string varName = resultPrefix + de::toString(opNdx);
944 		spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP)));
945 	}
946 
947 	for (int opNdx = 0; opNdx < numOps; opNdx++)
948 	{
949 		code << resultPrefix << opNdx << " = atomicCounterIncrement(counter[";
950 
951 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
952 			code << opIndices[opNdx];
953 		else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
954 			code << "indexBase + " << (opIndices[opNdx]-1);
955 		else
956 			code << indicesPrefix << opNdx;
957 
958 		code << "]);\n";
959 	}
960 
961 	spec->version				= GLSL_VERSION_310_ES;
962 	spec->globalDeclarations	= global.str();
963 	spec->source				= code.str();
964 }
965 
iterate(void)966 AtomicCounterIndexingCase::IterateResult AtomicCounterIndexingCase::iterate (void)
967 {
968 	const RenderContext&	renderCtx			= m_context.getRenderContext();
969 	const glw::Functions&	gl					= renderCtx.getFunctions();
970 	const Buffer			counterBuffer		(renderCtx);
971 
972 	const int				numInvocations		= 32;
973 	const int				numCounters			= 4;
974 	const int				numOps				= 4;
975 	vector<int>				opIndices			(numOps);
976 	vector<deUint32>		outValues			(numInvocations*numOps);
977 	ShaderSpec				shaderSpec;
978 	de::Random				rnd					(deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
979 
980 	for (int opNdx = 0; opNdx < numOps; opNdx++)
981 		opIndices[opNdx] = rnd.getInt(0, numOps-1);
982 
983 	getShaderSpec(&shaderSpec, numCounters, numOps, &opIndices[0]);
984 
985 	{
986 		const BufferVector		buffers			(renderCtx, numCounters);
987 		ShaderExecutorPtr		shaderExecutor	(createExecutor(renderCtx, m_shaderType, shaderSpec));
988 		vector<int>				expandedIndices;
989 		vector<void*>			inputs;
990 		vector<void*>			outputs;
991 
992 		m_testCtx.getLog() << *shaderExecutor;
993 
994 		if (!shaderExecutor->isOk())
995 			TCU_FAIL("Compile failed");
996 
997 		{
998 			const int				bufSize		= getProgramResourceInt(gl, shaderExecutor->getProgram(), GL_ATOMIC_COUNTER_BUFFER, 0, GL_BUFFER_DATA_SIZE);
999 			const int				maxNdx		= maxElement(opIndices);
1000 			std::vector<deUint8>	emptyData	(numCounters*4, 0);
1001 
1002 			if (bufSize < (maxNdx+1)*4)
1003 				TCU_FAIL((string("GL reported invalid buffer size " + de::toString(bufSize)).c_str()));
1004 
1005 			gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *counterBuffer);
1006 			gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_DRAW);
1007 			gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, *counterBuffer);
1008 			GLU_EXPECT_NO_ERROR(gl.getError(), "Atomic counter buffer initialization failed");
1009 		}
1010 
1011 		shaderExecutor->useProgram();
1012 
1013 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
1014 		{
1015 			expandedIndices.resize(numInvocations * opIndices.size());
1016 
1017 			for (int opNdx = 0; opNdx < numOps; opNdx++)
1018 			{
1019 				int* dst = &expandedIndices[numInvocations*opNdx];
1020 				std::fill(dst, dst+numInvocations, opIndices[opNdx]);
1021 			}
1022 
1023 			for (int opNdx = 0; opNdx < numOps; opNdx++)
1024 				inputs.push_back(&expandedIndices[opNdx*numInvocations]);
1025 		}
1026 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
1027 			uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numOps, &opIndices[0]);
1028 
1029 		for (int opNdx = 0; opNdx < numOps; opNdx++)
1030 			outputs.push_back(&outValues[opNdx*numInvocations]);
1031 
1032 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
1033 
1034 		shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
1035 	}
1036 
1037 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1038 
1039 	{
1040 		vector<int>				numHits			(numCounters, 0);	// Number of hits per counter.
1041 		vector<deUint32>		counterValues	(numCounters);
1042 		vector<vector<bool> >	counterMasks	(numCounters);
1043 
1044 		for (int opNdx = 0; opNdx < numOps; opNdx++)
1045 			numHits[opIndices[opNdx]] += 1;
1046 
1047 		// Read counter values
1048 		{
1049 			const void* mapPtr = DE_NULL;
1050 
1051 			try
1052 			{
1053 				mapPtr = gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, numCounters*4, GL_MAP_READ_BIT);
1054 				GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER)");
1055 				TCU_CHECK(mapPtr);
1056 				std::copy((const deUint32*)mapPtr, (const deUint32*)mapPtr + numCounters, &counterValues[0]);
1057 				gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1058 			}
1059 			catch (...)
1060 			{
1061 				if (mapPtr)
1062 					gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1063 				throw;
1064 			}
1065 		}
1066 
1067 		// Verify counter values
1068 		for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
1069 		{
1070 			const deUint32		refCount	= (deUint32)(numHits[counterNdx]*numInvocations);
1071 			const deUint32		resCount	= counterValues[counterNdx];
1072 
1073 			if (refCount != resCount)
1074 			{
1075 				m_testCtx.getLog() << TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount
1076 													   << ", expected " << refCount
1077 								   << TestLog::EndMessage;
1078 
1079 				if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1080 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid atomic counter value");
1081 			}
1082 		}
1083 
1084 		// Allocate bitmasks - one bit per each valid result value
1085 		for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
1086 		{
1087 			const int	counterValue	= numHits[counterNdx]*numInvocations;
1088 			counterMasks[counterNdx].resize(counterValue, false);
1089 		}
1090 
1091 		// Verify result values from shaders
1092 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
1093 		{
1094 			for (int opNdx = 0; opNdx < numOps; opNdx++)
1095 			{
1096 				const int		counterNdx	= opIndices[opNdx];
1097 				const deUint32	resValue	= outValues[opNdx*numInvocations + invocationNdx];
1098 				const bool		rangeOk		= de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size());
1099 				const bool		notSeen		= rangeOk && !counterMasks[counterNdx][resValue];
1100 				const bool		isOk		= rangeOk && notSeen;
1101 
1102 				if (!isOk)
1103 				{
1104 					m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx
1105 														   << ", op " << opNdx << ": got invalid result value "
1106 														   << resValue
1107 									   << TestLog::EndMessage;
1108 
1109 					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1110 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value");
1111 				}
1112 				else
1113 				{
1114 					// Mark as used - no other invocation should see this value from same counter.
1115 					counterMasks[counterNdx][resValue] = true;
1116 				}
1117 			}
1118 		}
1119 
1120 		if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1121 		{
1122 			// Consistency check - all masks should be 1 now
1123 			for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
1124 			{
1125 				for (vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++)
1126 					TCU_CHECK_INTERNAL(*i);
1127 			}
1128 		}
1129 	}
1130 
1131 	return STOP;
1132 }
1133 
1134 } // anonymous
1135 
OpaqueTypeIndexingTests(Context & context)1136 OpaqueTypeIndexingTests::OpaqueTypeIndexingTests (Context& context)
1137 	: TestCaseGroup(context, "opaque_type_indexing", "Opaque Type Indexing Tests")
1138 {
1139 }
1140 
~OpaqueTypeIndexingTests(void)1141 OpaqueTypeIndexingTests::~OpaqueTypeIndexingTests (void)
1142 {
1143 }
1144 
init(void)1145 void OpaqueTypeIndexingTests::init (void)
1146 {
1147 	static const struct
1148 	{
1149 		IndexExprType	type;
1150 		const char*		name;
1151 		const char*		description;
1152 	} indexingTypes[] =
1153 	{
1154 		{ INDEX_EXPR_TYPE_CONST_LITERAL,	"const_literal",		"Indexing by constant literal"					},
1155 		{ INDEX_EXPR_TYPE_CONST_EXPRESSION,	"const_expression",		"Indexing by constant expression"				},
1156 		{ INDEX_EXPR_TYPE_UNIFORM,			"uniform",				"Indexing by uniform value"						},
1157 		{ INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,	"dynamically_uniform",	"Indexing by dynamically uniform expression"	}
1158 	};
1159 
1160 	static const struct
1161 	{
1162 		ShaderType		type;
1163 		const char*		name;
1164 	} shaderTypes[] =
1165 	{
1166 		{ SHADERTYPE_VERTEX,		"vertex"	},
1167 		{ SHADERTYPE_FRAGMENT,		"fragment"	},
1168 		{ SHADERTYPE_COMPUTE,		"compute"	}
1169 	};
1170 
1171 	// .sampler
1172 	{
1173 		static const DataType samplerTypes[] =
1174 		{
1175 			// \note 1D images will be added by a later extension.
1176 //			TYPE_SAMPLER_1D,
1177 			TYPE_SAMPLER_2D,
1178 			TYPE_SAMPLER_CUBE,
1179 			TYPE_SAMPLER_2D_ARRAY,
1180 			TYPE_SAMPLER_3D,
1181 //			TYPE_SAMPLER_1D_SHADOW,
1182 			TYPE_SAMPLER_2D_SHADOW,
1183 			TYPE_SAMPLER_CUBE_SHADOW,
1184 			TYPE_SAMPLER_2D_ARRAY_SHADOW,
1185 //			TYPE_INT_SAMPLER_1D,
1186 			TYPE_INT_SAMPLER_2D,
1187 			TYPE_INT_SAMPLER_CUBE,
1188 			TYPE_INT_SAMPLER_2D_ARRAY,
1189 			TYPE_INT_SAMPLER_3D,
1190 //			TYPE_UINT_SAMPLER_1D,
1191 			TYPE_UINT_SAMPLER_2D,
1192 			TYPE_UINT_SAMPLER_CUBE,
1193 			TYPE_UINT_SAMPLER_2D_ARRAY,
1194 			TYPE_UINT_SAMPLER_3D,
1195 		};
1196 
1197 		tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler Array Indexing Tests");
1198 		addChild(samplerGroup);
1199 
1200 		for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
1201 		{
1202 			const IndexExprType			indexExprType	= indexingTypes[indexTypeNdx].type;
1203 			tcu::TestCaseGroup* const	indexGroup		= new tcu::TestCaseGroup(m_testCtx, indexingTypes[indexTypeNdx].name, indexingTypes[indexTypeNdx].description);
1204 			samplerGroup->addChild(indexGroup);
1205 
1206 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
1207 			{
1208 				const ShaderType			shaderType		= shaderTypes[shaderTypeNdx].type;
1209 				tcu::TestCaseGroup* const	shaderGroup		= new tcu::TestCaseGroup(m_testCtx, shaderTypes[shaderTypeNdx].name, "");
1210 				indexGroup->addChild(shaderGroup);
1211 
1212 				for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); samplerTypeNdx++)
1213 				{
1214 					const DataType	samplerType	= samplerTypes[samplerTypeNdx];
1215 					const char*		samplerName	= getDataTypeName(samplerType);
1216 					const string	caseName	= de::toLower(samplerName);
1217 
1218 					shaderGroup->addChild(new SamplerIndexingCase(m_context, caseName.c_str(), "", shaderType, samplerType, indexExprType));
1219 				}
1220 			}
1221 		}
1222 	}
1223 
1224 	// .ubo / .ssbo / .atomic_counter
1225 	{
1226 		tcu::TestCaseGroup* const	uboGroup	= new tcu::TestCaseGroup(m_testCtx, "ubo",				"Uniform Block Instance Array Indexing Tests");
1227 		tcu::TestCaseGroup* const	ssboGroup	= new tcu::TestCaseGroup(m_testCtx, "ssbo",				"Buffer Block Instance Array Indexing Tests");
1228 		tcu::TestCaseGroup* const	acGroup		= new tcu::TestCaseGroup(m_testCtx, "atomic_counter",	"Atomic Counter Array Indexing Tests");
1229 		addChild(uboGroup);
1230 		addChild(ssboGroup);
1231 		addChild(acGroup);
1232 
1233 		for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
1234 		{
1235 			const IndexExprType		indexExprType		= indexingTypes[indexTypeNdx].type;
1236 			const char*				indexExprName		= indexingTypes[indexTypeNdx].name;
1237 			const char*				indexExprDesc		= indexingTypes[indexTypeNdx].description;
1238 
1239 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
1240 			{
1241 				const ShaderType		shaderType		= shaderTypes[shaderTypeNdx].type;
1242 				const string			name			= string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name;
1243 
1244 				uboGroup->addChild	(new BlockArrayIndexingCase		(m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_UNIFORM,	indexExprType, shaderType));
1245 				acGroup->addChild	(new AtomicCounterIndexingCase	(m_context, name.c_str(), indexExprDesc, indexExprType, shaderType));
1246 
1247 				if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
1248 					ssboGroup->addChild	(new BlockArrayIndexingCase		(m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_BUFFER,	indexExprType, shaderType));
1249 			}
1250 		}
1251 	}
1252 }
1253 
1254 } // Functional
1255 } // gles31
1256 } // deqp
1257