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 Shader Image Load & Store Tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fShaderImageLoadStoreTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluRenderContext.hpp"
28 #include "gluShaderProgram.hpp"
29 #include "gluObjectWrapper.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluTextureUtil.hpp"
32 #include "gluStrUtil.hpp"
33 #include "gluCallLogWrapper.hpp"
34 #include "gluProgramInterfaceQuery.hpp"
35 #include "gluDrawUtil.hpp"
36 #include "tcuTestLog.hpp"
37 #include "tcuTextureUtil.hpp"
38 #include "tcuVector.hpp"
39 #include "tcuImageCompare.hpp"
40 #include "tcuFloat.hpp"
41 #include "tcuVectorUtil.hpp"
42 #include "deStringUtil.hpp"
43 #include "deSharedPtr.hpp"
44 #include "deUniquePtr.hpp"
45 #include "deRandom.hpp"
46 #include "deMemory.h"
47 #include "glwFunctions.hpp"
48 #include "glwDefs.hpp"
49 #include "glwEnums.hpp"
50 
51 #include <vector>
52 #include <string>
53 #include <algorithm>
54 #include <map>
55 
56 using glu::RenderContext;
57 using tcu::TestLog;
58 using tcu::Vec2;
59 using tcu::Vec3;
60 using tcu::Vec4;
61 using tcu::IVec2;
62 using tcu::IVec3;
63 using tcu::IVec4;
64 using tcu::UVec2;
65 using tcu::UVec3;
66 using tcu::UVec4;
67 using tcu::TextureFormat;
68 using tcu::ConstPixelBufferAccess;
69 using tcu::PixelBufferAccess;
70 using de::toString;
71 using de::SharedPtr;
72 using de::UniquePtr;
73 
74 using std::vector;
75 using std::string;
76 
77 namespace deqp
78 {
79 
80 using namespace gls::TextureTestUtil;
81 
82 namespace gles31
83 {
84 namespace Functional
85 {
86 
87 //! Default image sizes used in most test cases.
defaultImageSize(TextureType type)88 static inline IVec3 defaultImageSize (TextureType type)
89 {
90 	switch (type)
91 	{
92 		case TEXTURETYPE_BUFFER:	return IVec3(64,	1,		1);
93 		case TEXTURETYPE_2D:		return IVec3(64,	64,		1);
94 		case TEXTURETYPE_CUBE:		return IVec3(64,	64,		1);
95 		case TEXTURETYPE_3D:		return IVec3(64,	64,		8);
96 		case TEXTURETYPE_2D_ARRAY:	return IVec3(64,	64,		8);
97 		default:
98 			DE_ASSERT(false);
99 			return IVec3(-1);
100 	}
101 }
102 
103 template <typename T, int Size>
arrayStr(const T (& arr)[Size])104 static string arrayStr (const T (&arr)[Size])
105 {
106 	string result = "{ ";
107 	for (int i = 0; i < Size; i++)
108 		result += (i > 0 ? ", " : "") + toString(arr[i]);
109 	result += " }";
110 	return result;
111 }
112 
113 template <typename T, int N>
arrayIndexOf(const T (& arr)[N],const T & e)114 static int arrayIndexOf (const T (&arr)[N], const T& e)
115 {
116 	return (int)(std::find(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr), e) - DE_ARRAY_BEGIN(arr));
117 }
118 
getTextureTypeName(TextureType type)119 static const char* getTextureTypeName (TextureType type)
120 {
121 	switch (type)
122 	{
123 		case TEXTURETYPE_BUFFER:	return "buffer";
124 		case TEXTURETYPE_2D:		return "2d";
125 		case TEXTURETYPE_CUBE:		return "cube";
126 		case TEXTURETYPE_3D:		return "3d";
127 		case TEXTURETYPE_2D_ARRAY:	return "2d_array";
128 		default:
129 			DE_ASSERT(false);
130 			return DE_NULL;
131 	}
132 }
133 
isFormatTypeUnsignedInteger(TextureFormat::ChannelType type)134 static inline bool isFormatTypeUnsignedInteger (TextureFormat::ChannelType type)
135 {
136 	return type == TextureFormat::UNSIGNED_INT8		||
137 		   type == TextureFormat::UNSIGNED_INT16	||
138 		   type == TextureFormat::UNSIGNED_INT32;
139 }
140 
isFormatTypeSignedInteger(TextureFormat::ChannelType type)141 static inline bool isFormatTypeSignedInteger (TextureFormat::ChannelType type)
142 {
143 	return type == TextureFormat::SIGNED_INT8	||
144 		   type == TextureFormat::SIGNED_INT16	||
145 		   type == TextureFormat::SIGNED_INT32;
146 }
147 
isFormatTypeInteger(TextureFormat::ChannelType type)148 static inline bool isFormatTypeInteger (TextureFormat::ChannelType type)
149 {
150 	return isFormatTypeUnsignedInteger(type) || isFormatTypeSignedInteger(type);
151 }
152 
isFormatTypeUnorm(TextureFormat::ChannelType type)153 static inline bool isFormatTypeUnorm (TextureFormat::ChannelType type)
154 {
155 	return type == TextureFormat::UNORM_INT8	||
156 		   type == TextureFormat::UNORM_INT16	||
157 		   type == TextureFormat::UNORM_INT32;
158 }
159 
isFormatTypeSnorm(TextureFormat::ChannelType type)160 static inline bool isFormatTypeSnorm (TextureFormat::ChannelType type)
161 {
162 	return type == TextureFormat::SNORM_INT8	||
163 		   type == TextureFormat::SNORM_INT16	||
164 		   type == TextureFormat::SNORM_INT32;
165 }
166 
isFormatSupportedForTextureBuffer(const TextureFormat & format)167 static inline bool isFormatSupportedForTextureBuffer (const TextureFormat& format)
168 {
169 	switch (format.order)
170 	{
171 		case TextureFormat::RGB:
172 			return format.type == TextureFormat::FLOAT				||
173 				   format.type == TextureFormat::SIGNED_INT32		||
174 				   format.type == TextureFormat::UNSIGNED_INT32;
175 
176 		// \note Fallthroughs.
177 		case TextureFormat::R:
178 		case TextureFormat::RG:
179 		case TextureFormat::RGBA:
180 			return format.type == TextureFormat::UNORM_INT8			||
181 				   format.type == TextureFormat::HALF_FLOAT			||
182 				   format.type == TextureFormat::FLOAT				||
183 				   format.type == TextureFormat::SIGNED_INT8		||
184 				   format.type == TextureFormat::SIGNED_INT16		||
185 				   format.type == TextureFormat::SIGNED_INT32		||
186 				   format.type == TextureFormat::UNSIGNED_INT8		||
187 				   format.type == TextureFormat::UNSIGNED_INT16		||
188 				   format.type == TextureFormat::UNSIGNED_INT32;
189 
190 		default:
191 			return false;
192 	}
193 }
194 
getShaderImageFormatQualifier(const TextureFormat & format)195 static inline string getShaderImageFormatQualifier (const TextureFormat& format)
196 {
197 	const char* orderPart;
198 	const char* typePart;
199 
200 	switch (format.order)
201 	{
202 		case TextureFormat::R:		orderPart = "r";		break;
203 		case TextureFormat::RGBA:	orderPart = "rgba";		break;
204 		default:
205 			DE_ASSERT(false);
206 			orderPart = DE_NULL;
207 	}
208 
209 	switch (format.type)
210 	{
211 		case TextureFormat::FLOAT:				typePart = "32f";			break;
212 		case TextureFormat::HALF_FLOAT:			typePart = "16f";			break;
213 
214 		case TextureFormat::UNSIGNED_INT32:		typePart = "32ui";			break;
215 		case TextureFormat::UNSIGNED_INT16:		typePart = "16ui";			break;
216 		case TextureFormat::UNSIGNED_INT8:		typePart = "8ui";			break;
217 
218 		case TextureFormat::SIGNED_INT32:		typePart = "32i";			break;
219 		case TextureFormat::SIGNED_INT16:		typePart = "16i";			break;
220 		case TextureFormat::SIGNED_INT8:		typePart = "8i";			break;
221 
222 		case TextureFormat::UNORM_INT16:		typePart = "16";			break;
223 		case TextureFormat::UNORM_INT8:			typePart = "8";				break;
224 
225 		case TextureFormat::SNORM_INT16:		typePart = "16_snorm";		break;
226 		case TextureFormat::SNORM_INT8:			typePart = "8_snorm";		break;
227 
228 		default:
229 			DE_ASSERT(false);
230 			typePart = DE_NULL;
231 	}
232 
233 	return string() + orderPart + typePart;
234 }
235 
getShaderSamplerOrImageType(TextureFormat::ChannelType formatType,TextureType textureType,bool isSampler)236 static inline string getShaderSamplerOrImageType (TextureFormat::ChannelType formatType, TextureType textureType, bool isSampler)
237 {
238 	const char* const formatPart		= isFormatTypeUnsignedInteger(formatType)	? "u"
239 										: isFormatTypeSignedInteger(formatType)		? "i"
240 										: "";
241 
242 	const char* const imageTypePart		= textureType == TEXTURETYPE_BUFFER		? "Buffer"
243 										: textureType == TEXTURETYPE_2D			? "2D"
244 										: textureType == TEXTURETYPE_3D			? "3D"
245 										: textureType == TEXTURETYPE_CUBE		? "Cube"
246 										: textureType == TEXTURETYPE_2D_ARRAY	? "2DArray"
247 										: DE_NULL;
248 
249 	return string() + formatPart + (isSampler ? "sampler" : "image") + imageTypePart;
250 }
251 
getShaderImageType(TextureFormat::ChannelType formatType,TextureType imageType)252 static inline string getShaderImageType (TextureFormat::ChannelType formatType, TextureType imageType)
253 {
254 	return getShaderSamplerOrImageType(formatType, imageType, false);
255 }
256 
getShaderSamplerType(TextureFormat::ChannelType formatType,TextureType imageType)257 static inline string getShaderSamplerType (TextureFormat::ChannelType formatType, TextureType imageType)
258 {
259 	return getShaderSamplerOrImageType(formatType, imageType, true);
260 }
261 
getGLTextureTarget(TextureType texType)262 static inline deUint32 getGLTextureTarget (TextureType texType)
263 {
264 	switch (texType)
265 	{
266 		case TEXTURETYPE_BUFFER:	return GL_TEXTURE_BUFFER;
267 		case TEXTURETYPE_2D:		return GL_TEXTURE_2D;
268 		case TEXTURETYPE_3D:		return GL_TEXTURE_3D;
269 		case TEXTURETYPE_CUBE:		return GL_TEXTURE_CUBE_MAP;
270 		case TEXTURETYPE_2D_ARRAY:	return GL_TEXTURE_2D_ARRAY;
271 		default:
272 			DE_ASSERT(false);
273 			return (deUint32)-1;
274 	}
275 }
276 
cubeFaceToGLFace(tcu::CubeFace face)277 static deUint32 cubeFaceToGLFace (tcu::CubeFace face)
278 {
279 	switch (face)
280 	{
281 		case tcu::CUBEFACE_NEGATIVE_X: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
282 		case tcu::CUBEFACE_POSITIVE_X: return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
283 		case tcu::CUBEFACE_NEGATIVE_Y: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
284 		case tcu::CUBEFACE_POSITIVE_Y: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
285 		case tcu::CUBEFACE_NEGATIVE_Z: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
286 		case tcu::CUBEFACE_POSITIVE_Z: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
287 		default:
288 			DE_ASSERT(false);
289 			return GL_NONE;
290 	}
291 }
292 
newOneLevelTexture1D(const tcu::TextureFormat & format,int w)293 static inline tcu::Texture1D* newOneLevelTexture1D (const tcu::TextureFormat& format, int w)
294 {
295 	tcu::Texture1D* const res = new tcu::Texture1D(format, w);
296 	res->allocLevel(0);
297 	return res;
298 }
299 
newOneLevelTexture2D(const tcu::TextureFormat & format,int w,int h)300 static inline tcu::Texture2D* newOneLevelTexture2D (const tcu::TextureFormat& format, int w, int h)
301 {
302 	tcu::Texture2D* const res = new tcu::Texture2D(format, w, h);
303 	res->allocLevel(0);
304 	return res;
305 }
306 
newOneLevelTextureCube(const tcu::TextureFormat & format,int size)307 static inline tcu::TextureCube* newOneLevelTextureCube (const tcu::TextureFormat& format, int size)
308 {
309 	tcu::TextureCube* const res = new tcu::TextureCube(format, size);
310 	for (int i = 0; i < tcu::CUBEFACE_LAST; i++)
311 		res->allocLevel((tcu::CubeFace)i, 0);
312 	return res;
313 }
314 
newOneLevelTexture3D(const tcu::TextureFormat & format,int w,int h,int d)315 static inline tcu::Texture3D* newOneLevelTexture3D (const tcu::TextureFormat& format, int w, int h, int d)
316 {
317 	tcu::Texture3D* const res = new tcu::Texture3D(format, w, h, d);
318 	res->allocLevel(0);
319 	return res;
320 }
321 
newOneLevelTexture2DArray(const tcu::TextureFormat & format,int w,int h,int d)322 static inline tcu::Texture2DArray* newOneLevelTexture2DArray (const tcu::TextureFormat& format, int w, int h, int d)
323 {
324 	tcu::Texture2DArray* const res = new tcu::Texture2DArray(format, w, h, d);
325 	res->allocLevel(0);
326 	return res;
327 }
328 
textureLayerType(TextureType entireTextureType)329 static inline TextureType textureLayerType (TextureType entireTextureType)
330 {
331 	switch (entireTextureType)
332 	{
333 		// Single-layer types.
334 		// \note Fallthrough.
335 		case TEXTURETYPE_BUFFER:
336 		case TEXTURETYPE_2D:
337 			return entireTextureType;
338 
339 		// Multi-layer types with 2d layers.
340 		case TEXTURETYPE_3D:
341 		case TEXTURETYPE_CUBE:
342 		case TEXTURETYPE_2D_ARRAY:
343 			return TEXTURETYPE_2D;
344 
345 		default:
346 			DE_ASSERT(false);
347 			return TEXTURETYPE_LAST;
348 	}
349 }
350 
351 static const char* const s_texBufExtString = "GL_EXT_texture_buffer";
352 
checkTextureTypeExtensions(const glu::ContextInfo & contextInfo,TextureType type,const RenderContext & renderContext)353 static inline void checkTextureTypeExtensions (const glu::ContextInfo& contextInfo, TextureType type, const RenderContext& renderContext)
354 {
355 	if (type == TEXTURETYPE_BUFFER && !contextInfo.isExtensionSupported(s_texBufExtString) && !glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)))
356 		throw tcu::NotSupportedError("Test requires " + string(s_texBufExtString) + " extension");
357 }
358 
textureTypeExtensionShaderRequires(TextureType type,const RenderContext & renderContext)359 static inline string textureTypeExtensionShaderRequires (TextureType type, const RenderContext& renderContext)
360 {
361 	if (!glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)) && (type == TEXTURETYPE_BUFFER))
362 		return "#extension " + string(s_texBufExtString) + " : require\n";
363 	else
364 		return "";
365 }
366 
367 static const char* const s_imageAtomicExtString = "GL_OES_shader_image_atomic";
368 
imageAtomicExtensionShaderRequires(const RenderContext & renderContext)369 static inline string imageAtomicExtensionShaderRequires (const RenderContext& renderContext)
370 {
371 	if (!glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)))
372 		return "#extension " + string(s_imageAtomicExtString) + " : require\n";
373 	else
374 		return "";
375 }
376 
377 namespace
378 {
379 
380 enum AtomicOperation
381 {
382 	ATOMIC_OPERATION_ADD = 0,
383 	ATOMIC_OPERATION_MIN,
384 	ATOMIC_OPERATION_MAX,
385 	ATOMIC_OPERATION_AND,
386 	ATOMIC_OPERATION_OR,
387 	ATOMIC_OPERATION_XOR,
388 	ATOMIC_OPERATION_EXCHANGE,
389 	ATOMIC_OPERATION_COMP_SWAP,
390 
391 	ATOMIC_OPERATION_LAST
392 };
393 
394 //! An order-independent operation is one for which the end result doesn't depend on the order in which the operations are carried (i.e. is both commutative and associative).
isOrderIndependentAtomicOperation(AtomicOperation op)395 static bool isOrderIndependentAtomicOperation (AtomicOperation op)
396 {
397 	return op == ATOMIC_OPERATION_ADD	||
398 		   op == ATOMIC_OPERATION_MIN	||
399 		   op == ATOMIC_OPERATION_MAX	||
400 		   op == ATOMIC_OPERATION_AND	||
401 		   op == ATOMIC_OPERATION_OR	||
402 		   op == ATOMIC_OPERATION_XOR;
403 }
404 
405 //! Computes the result of an atomic operation where "a" is the data operated on and "b" is the parameter to the atomic function.
computeBinaryAtomicOperationResult(AtomicOperation op,int a,int b)406 int computeBinaryAtomicOperationResult (AtomicOperation op, int a, int b)
407 {
408 	switch (op)
409 	{
410 		case ATOMIC_OPERATION_ADD:			return a + b;
411 		case ATOMIC_OPERATION_MIN:			return de::min(a, b);
412 		case ATOMIC_OPERATION_MAX:			return de::max(a, b);
413 		case ATOMIC_OPERATION_AND:			return a & b;
414 		case ATOMIC_OPERATION_OR:			return a | b;
415 		case ATOMIC_OPERATION_XOR:			return a ^ b;
416 		case ATOMIC_OPERATION_EXCHANGE:		return b;
417 		default:
418 			DE_ASSERT(false);
419 			return -1;
420 	}
421 }
422 
423 //! \note For floats, only the exchange operation is supported.
computeBinaryAtomicOperationResult(AtomicOperation op,float,float b)424 float computeBinaryAtomicOperationResult (AtomicOperation op, float /*a*/, float b)
425 {
426 	switch (op)
427 	{
428 		case ATOMIC_OPERATION_EXCHANGE: return b;
429 		default:
430 			DE_ASSERT(false);
431 			return -1;
432 	}
433 }
434 
getAtomicOperationCaseName(AtomicOperation op)435 static const char* getAtomicOperationCaseName (AtomicOperation op)
436 {
437 	switch (op)
438 	{
439 		case ATOMIC_OPERATION_ADD:			return "add";
440 		case ATOMIC_OPERATION_MIN:			return "min";
441 		case ATOMIC_OPERATION_MAX:			return "max";
442 		case ATOMIC_OPERATION_AND:			return "and";
443 		case ATOMIC_OPERATION_OR:			return "or";
444 		case ATOMIC_OPERATION_XOR:			return "xor";
445 		case ATOMIC_OPERATION_EXCHANGE:		return "exchange";
446 		case ATOMIC_OPERATION_COMP_SWAP:	return "comp_swap";
447 		default:
448 			DE_ASSERT(false);
449 			return DE_NULL;
450 	}
451 }
452 
getAtomicOperationShaderFuncName(AtomicOperation op)453 static const char* getAtomicOperationShaderFuncName (AtomicOperation op)
454 {
455 	switch (op)
456 	{
457 		case ATOMIC_OPERATION_ADD:			return "imageAtomicAdd";
458 		case ATOMIC_OPERATION_MIN:			return "imageAtomicMin";
459 		case ATOMIC_OPERATION_MAX:			return "imageAtomicMax";
460 		case ATOMIC_OPERATION_AND:			return "imageAtomicAnd";
461 		case ATOMIC_OPERATION_OR:			return "imageAtomicOr";
462 		case ATOMIC_OPERATION_XOR:			return "imageAtomicXor";
463 		case ATOMIC_OPERATION_EXCHANGE:		return "imageAtomicExchange";
464 		case ATOMIC_OPERATION_COMP_SWAP:	return "imageAtomicCompSwap";
465 		default:
466 			DE_ASSERT(false);
467 			return DE_NULL;
468 	}
469 }
470 
471 //! In GLSL, when accessing cube images, the z coordinate is mapped to a cube face.
472 //! \note This is _not_ the same as casting the z to a tcu::CubeFace.
glslImageFuncZToCubeFace(int z)473 static inline tcu::CubeFace glslImageFuncZToCubeFace (int z)
474 {
475 	static const tcu::CubeFace faces[6] =
476 	{
477 		tcu::CUBEFACE_POSITIVE_X,
478 		tcu::CUBEFACE_NEGATIVE_X,
479 		tcu::CUBEFACE_POSITIVE_Y,
480 		tcu::CUBEFACE_NEGATIVE_Y,
481 		tcu::CUBEFACE_POSITIVE_Z,
482 		tcu::CUBEFACE_NEGATIVE_Z
483 	};
484 
485 	DE_ASSERT(de::inBounds(z, 0, DE_LENGTH_OF_ARRAY(faces)));
486 	return faces[z];
487 }
488 
489 class BufferMemMap
490 {
491 public:
BufferMemMap(const glw::Functions & gl,deUint32 target,int offset,int size,deUint32 access)492 	BufferMemMap (const glw::Functions& gl, deUint32 target, int offset, int size, deUint32 access)
493 		: m_gl		(gl)
494 		, m_target	(target)
495 		, m_ptr		(DE_NULL)
496 	{
497 		m_ptr = gl.mapBufferRange(target, offset, size, access);
498 		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
499 		TCU_CHECK(m_ptr);
500 	}
501 
~BufferMemMap(void)502 	~BufferMemMap (void)
503 	{
504 		m_gl.unmapBuffer(m_target);
505 	}
506 
getPtr(void) const507 	void*	getPtr		(void) const { return m_ptr; }
operator *(void) const508 	void*	operator*	(void) const { return m_ptr; }
509 
510 private:
511 							BufferMemMap			(const BufferMemMap& other);
512 	BufferMemMap&			operator=				(const BufferMemMap& other);
513 
514 	const glw::Functions&	m_gl;
515 	const deUint32			m_target;
516 	void*					m_ptr;
517 };
518 
519 //! Utility for more readable uniform assignment logging; logs the name of the uniform when assigning. Handles the locations, querying them the first time they're assigned
520 //  \note Assumes that the appropriate program is in use when assigning uniforms.
521 class UniformAccessLogger
522 {
523 public:
UniformAccessLogger(const glw::Functions & gl,TestLog & log,deUint32 programGL)524 	UniformAccessLogger (const glw::Functions& gl, TestLog& log, deUint32 programGL)
525 		: m_gl			(gl)
526 		, m_log			(log)
527 		, m_programGL	(programGL)
528 	{
529 	}
530 
531 	void						assign1i (const string& name, int x);
532 	void						assign3f (const string& name, float x, float y, float z);
533 
534 private:
535 	int							getLocation (const string& name);
536 
537 	const glw::Functions&		m_gl;
538 	TestLog&					m_log;
539 	const deUint32				m_programGL;
540 
541 	std::map<string, int>		m_uniformLocations;
542 };
543 
getLocation(const string & name)544 int UniformAccessLogger::getLocation (const string& name)
545 {
546 	if (m_uniformLocations.find(name) == m_uniformLocations.end())
547 	{
548 		const int loc = m_gl.getUniformLocation(m_programGL, name.c_str());
549 		TCU_CHECK(loc != -1);
550 		m_uniformLocations[name] = loc;
551 	}
552 	return m_uniformLocations[name];
553 }
554 
assign1i(const string & name,int x)555 void UniformAccessLogger::assign1i (const string& name, int x)
556 {
557 	const int loc = getLocation(name);
558 	m_log << TestLog::Message << "// Assigning to uniform " << name << ": " << x << TestLog::EndMessage;
559 	m_gl.uniform1i(loc, x);
560 }
561 
assign3f(const string & name,float x,float y,float z)562 void UniformAccessLogger::assign3f (const string& name, float x, float y, float z)
563 {
564 	const int loc = getLocation(name);
565 	m_log << TestLog::Message << "// Assigning to uniform " << name << ": " << Vec3(x, y, z) << TestLog::EndMessage;
566 	m_gl.uniform3f(loc, x, y, z);
567 }
568 
569 //! Class containing a (single-level) texture of a given type. Supports accessing pixels with coordinate convention similar to that in imageStore() and imageLoad() in shaders; useful especially for cube maps.
570 class LayeredImage
571 {
572 public:
573 												LayeredImage				(TextureType type, const TextureFormat& format, int w, int h, int d);
574 
getImageType(void) const575 	TextureType									getImageType				(void) const { return m_type; }
getSize(void) const576 	const IVec3&								getSize						(void) const { return m_size; }
getFormat(void) const577 	const TextureFormat&						getFormat					(void) const { return m_format; }
578 
579 	// \note For cube maps, set/getPixel's z parameter specifies the cube face in the same manner as in imageStore/imageLoad in GL shaders (see glslImageFuncZToCubeFace), instead of directly as a tcu::CubeFace.
580 
581 	template <typename ColorT>
582 	void										setPixel					(int x, int y, int z, const ColorT& color) const;
583 
584 	Vec4										getPixel					(int x, int y, int z) const;
585 	IVec4										getPixelInt					(int x, int y, int z) const;
getPixelUint(int x,int y,int z) const586 	UVec4										getPixelUint				(int x, int y, int z) const { return getPixelInt(x, y, z).asUint(); }
587 
getAccess(void)588 	PixelBufferAccess							getAccess					(void)							{ return getAccessInternal();				}
getSliceAccess(int slice)589 	PixelBufferAccess							getSliceAccess				(int slice)						{ return getSliceAccessInternal(slice);		}
getCubeFaceAccess(tcu::CubeFace face)590 	PixelBufferAccess							getCubeFaceAccess			(tcu::CubeFace face)			{ return getCubeFaceAccessInternal(face);	}
591 
getAccess(void) const592 	ConstPixelBufferAccess						getAccess					(void)					const	{ return getAccessInternal();				}
getSliceAccess(int slice) const593 	ConstPixelBufferAccess						getSliceAccess				(int slice)				const	{ return getSliceAccessInternal(slice);		}
getCubeFaceAccess(tcu::CubeFace face) const594 	ConstPixelBufferAccess						getCubeFaceAccess			(tcu::CubeFace face)	const	{ return getCubeFaceAccessInternal(face);	}
595 
596 private:
597 												LayeredImage				(const LayeredImage&);
598 	LayeredImage&								operator=					(const LayeredImage&);
599 
600 	// Some helpers to reduce code duplication between const/non-const versions of getAccess and others.
601 	PixelBufferAccess							getAccessInternal			(void) const;
602 	PixelBufferAccess							getSliceAccessInternal		(int slice) const;
603 	PixelBufferAccess							getCubeFaceAccessInternal	(tcu::CubeFace face) const;
604 
605 	const TextureType							m_type;
606 	const IVec3									m_size;
607 	const TextureFormat							m_format;
608 
609 	// \note Depending on m_type, exactly one of the following will contain non-null.
610 	const SharedPtr<tcu::Texture1D>				m_texBuffer;
611 	const SharedPtr<tcu::Texture2D>				m_tex2D;
612 	const SharedPtr<tcu::TextureCube>			m_texCube;
613 	const SharedPtr<tcu::Texture3D>				m_tex3D;
614 	const SharedPtr<tcu::Texture2DArray>		m_tex2DArray;
615 };
616 
LayeredImage(TextureType type,const TextureFormat & format,int w,int h,int d)617 LayeredImage::LayeredImage (TextureType type, const TextureFormat& format, int w, int h, int d)
618 	: m_type		(type)
619 	, m_size		(w, h, d)
620 	, m_format		(format)
621 	, m_texBuffer	(type == TEXTURETYPE_BUFFER		? SharedPtr<tcu::Texture1D>			(newOneLevelTexture1D		(format, w))		: SharedPtr<tcu::Texture1D>())
622 	, m_tex2D		(type == TEXTURETYPE_2D			? SharedPtr<tcu::Texture2D>			(newOneLevelTexture2D		(format, w, h))		: SharedPtr<tcu::Texture2D>())
623 	, m_texCube		(type == TEXTURETYPE_CUBE		? SharedPtr<tcu::TextureCube>		(newOneLevelTextureCube		(format, w))		: SharedPtr<tcu::TextureCube>())
624 	, m_tex3D		(type == TEXTURETYPE_3D			? SharedPtr<tcu::Texture3D>			(newOneLevelTexture3D		(format, w, h, d))	: SharedPtr<tcu::Texture3D>())
625 	, m_tex2DArray	(type == TEXTURETYPE_2D_ARRAY	? SharedPtr<tcu::Texture2DArray>	(newOneLevelTexture2DArray	(format, w, h, d))	: SharedPtr<tcu::Texture2DArray>())
626 {
627 	DE_ASSERT(m_size.z() == 1					||
628 			  m_type == TEXTURETYPE_3D			||
629 			  m_type == TEXTURETYPE_2D_ARRAY);
630 
631 	DE_ASSERT(m_size.y() == 1					||
632 			  m_type == TEXTURETYPE_2D			||
633 			  m_type == TEXTURETYPE_CUBE		||
634 			  m_type == TEXTURETYPE_3D			||
635 			  m_type == TEXTURETYPE_2D_ARRAY);
636 
637 	DE_ASSERT(w == h || type != TEXTURETYPE_CUBE);
638 
639 	DE_ASSERT(m_texBuffer	!= DE_NULL ||
640 			  m_tex2D		!= DE_NULL ||
641 			  m_texCube		!= DE_NULL ||
642 			  m_tex3D		!= DE_NULL ||
643 			  m_tex2DArray	!= DE_NULL);
644 }
645 
646 template <typename ColorT>
setPixel(int x,int y,int z,const ColorT & color) const647 void LayeredImage::setPixel (int x, int y, int z, const ColorT& color) const
648 {
649 	const PixelBufferAccess access = m_type == TEXTURETYPE_BUFFER		? m_texBuffer->getLevel(0)
650 								   : m_type == TEXTURETYPE_2D			? m_tex2D->getLevel(0)
651 								   : m_type == TEXTURETYPE_CUBE			? m_texCube->getLevelFace(0, glslImageFuncZToCubeFace(z))
652 								   : m_type == TEXTURETYPE_3D			? m_tex3D->getLevel(0)
653 								   : m_type == TEXTURETYPE_2D_ARRAY		? m_tex2DArray->getLevel(0)
654 								   : PixelBufferAccess();
655 
656 	access.setPixel(color, x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
657 }
658 
getPixel(int x,int y,int z) const659 Vec4 LayeredImage::getPixel (int x, int y, int z) const
660 {
661 	const ConstPixelBufferAccess access = m_type == TEXTURETYPE_CUBE ? getCubeFaceAccess(glslImageFuncZToCubeFace(z)) : getAccess();
662 	return access.getPixel(x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
663 }
664 
getPixelInt(int x,int y,int z) const665 IVec4 LayeredImage::getPixelInt (int x, int y, int z) const
666 {
667 	const ConstPixelBufferAccess access = m_type == TEXTURETYPE_CUBE ? getCubeFaceAccess(glslImageFuncZToCubeFace(z)) : getAccess();
668 	return access.getPixelInt(x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
669 }
670 
getAccessInternal(void) const671 PixelBufferAccess LayeredImage::getAccessInternal (void) const
672 {
673 	DE_ASSERT(m_type == TEXTURETYPE_BUFFER || m_type == TEXTURETYPE_2D || m_type == TEXTURETYPE_3D || m_type == TEXTURETYPE_2D_ARRAY);
674 
675 	return m_type == TEXTURETYPE_BUFFER		? m_texBuffer->getLevel(0)
676 		 : m_type == TEXTURETYPE_2D			? m_tex2D->getLevel(0)
677 		 : m_type == TEXTURETYPE_3D			? m_tex3D->getLevel(0)
678 		 : m_type == TEXTURETYPE_2D_ARRAY	? m_tex2DArray->getLevel(0)
679 		 : PixelBufferAccess();
680 }
681 
getSliceAccessInternal(int slice) const682 PixelBufferAccess LayeredImage::getSliceAccessInternal (int slice) const
683 {
684 	const PixelBufferAccess srcAccess = getAccessInternal();
685 	return tcu::getSubregion(srcAccess, 0, 0, slice, srcAccess.getWidth(), srcAccess.getHeight(), 1);
686 }
687 
getCubeFaceAccessInternal(tcu::CubeFace face) const688 PixelBufferAccess LayeredImage::getCubeFaceAccessInternal (tcu::CubeFace face) const
689 {
690 	DE_ASSERT(m_type == TEXTURETYPE_CUBE);
691 	return m_texCube->getLevelFace(0, face);
692 }
693 
694 //! Set texture storage or, if using buffer texture, setup buffer and attach to texture.
setTextureStorage(glu::CallLogWrapper & glLog,TextureType imageType,deUint32 internalFormat,const IVec3 & imageSize,deUint32 textureBufGL)695 static void setTextureStorage (glu::CallLogWrapper& glLog, TextureType imageType, deUint32 internalFormat, const IVec3& imageSize, deUint32 textureBufGL)
696 {
697 	const deUint32 textureTarget = getGLTextureTarget(imageType);
698 
699 	switch (imageType)
700 	{
701 		case TEXTURETYPE_BUFFER:
702 		{
703 			const TextureFormat		format		= glu::mapGLInternalFormat(internalFormat);
704 			const int				numBytes	= format.getPixelSize() * imageSize.x();
705 			DE_ASSERT(isFormatSupportedForTextureBuffer(format));
706 			glLog.glBindBuffer(GL_TEXTURE_BUFFER, textureBufGL);
707 			glLog.glBufferData(GL_TEXTURE_BUFFER, numBytes, DE_NULL, GL_STATIC_DRAW);
708 			glLog.glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, textureBufGL);
709 			DE_ASSERT(imageSize.y() == 1 && imageSize.z() == 1);
710 			break;
711 		}
712 
713 		// \note Fall-throughs.
714 
715 		case TEXTURETYPE_2D:
716 		case TEXTURETYPE_CUBE:
717 			glLog.glTexStorage2D(textureTarget, 1, internalFormat, imageSize.x(), imageSize.y());
718 			DE_ASSERT(imageSize.z() == 1);
719 			break;
720 
721 		case TEXTURETYPE_3D:
722 		case TEXTURETYPE_2D_ARRAY:
723 			glLog.glTexStorage3D(textureTarget, 1, internalFormat, imageSize.x(), imageSize.y(), imageSize.z());
724 			break;
725 
726 		default:
727 			DE_ASSERT(false);
728 	}
729 }
730 
uploadTexture(glu::CallLogWrapper & glLog,const LayeredImage & src,deUint32 textureBufGL)731 static void uploadTexture (glu::CallLogWrapper& glLog, const LayeredImage& src, deUint32 textureBufGL)
732 {
733 	const deUint32				internalFormat	= glu::getInternalFormat(src.getFormat());
734 	const glu::TransferFormat	transferFormat	= glu::getTransferFormat(src.getFormat());
735 	const IVec3&				imageSize		= src.getSize();
736 
737 	setTextureStorage(glLog, src.getImageType(), internalFormat, imageSize, textureBufGL);
738 
739 	{
740 		const int	pixelSize = src.getFormat().getPixelSize();
741 		int			unpackAlignment;
742 
743 		if (deIsPowerOfTwo32(pixelSize))
744 			unpackAlignment = 8;
745 		else
746 			unpackAlignment = 1;
747 
748 		glLog.glPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlignment);
749 	}
750 
751 	if (src.getImageType() == TEXTURETYPE_BUFFER)
752 	{
753 		glLog.glBindBuffer(GL_TEXTURE_BUFFER, textureBufGL);
754 		glLog.glBufferData(GL_TEXTURE_BUFFER, src.getFormat().getPixelSize() * imageSize.x(), src.getAccess().getDataPtr(), GL_STATIC_DRAW);
755 	}
756 	else if (src.getImageType() == TEXTURETYPE_2D)
757 		glLog.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageSize.x(), imageSize.y(), transferFormat.format, transferFormat.dataType, src.getAccess().getDataPtr());
758 	else if (src.getImageType() == TEXTURETYPE_CUBE)
759 	{
760 		for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++)
761 		{
762 			const tcu::CubeFace face = (tcu::CubeFace)faceI;
763 			glLog.glTexSubImage2D(cubeFaceToGLFace(face), 0, 0, 0, imageSize.x(), imageSize.y(), transferFormat.format, transferFormat.dataType, src.getCubeFaceAccess(face).getDataPtr());
764 		}
765 	}
766 	else
767 	{
768 		DE_ASSERT(src.getImageType() == TEXTURETYPE_3D || src.getImageType() == TEXTURETYPE_2D_ARRAY);
769 		const deUint32 textureTarget = getGLTextureTarget(src.getImageType());
770 		glLog.glTexSubImage3D(textureTarget, 0, 0, 0, 0, imageSize.x(), imageSize.y(), imageSize.z(), transferFormat.format, transferFormat.dataType, src.getAccess().getDataPtr());
771 	}
772 }
773 
readPixelsRGBAInteger32(const PixelBufferAccess & dst,int originX,int originY,glu::CallLogWrapper & glLog)774 static void readPixelsRGBAInteger32 (const PixelBufferAccess& dst, int originX, int originY, glu::CallLogWrapper& glLog)
775 {
776 	DE_ASSERT(dst.getDepth() == 1);
777 
778 	if (isFormatTypeUnsignedInteger(dst.getFormat().type))
779 	{
780 		vector<UVec4> data(dst.getWidth()*dst.getHeight());
781 
782 		glLog.glReadPixels(originX, originY, dst.getWidth(), dst.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]);
783 
784 		for (int y = 0; y < dst.getHeight(); y++)
785 		for (int x = 0; x < dst.getWidth(); x++)
786 			dst.setPixel(data[y*dst.getWidth() + x], x, y);
787 	}
788 	else if (isFormatTypeSignedInteger(dst.getFormat().type))
789 	{
790 		vector<IVec4> data(dst.getWidth()*dst.getHeight());
791 
792 		glLog.glReadPixels(originX, originY, dst.getWidth(), dst.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]);
793 
794 		for (int y = 0; y < dst.getHeight(); y++)
795 		for (int x = 0; x < dst.getWidth(); x++)
796 			dst.setPixel(data[y*dst.getWidth() + x], x, y);
797 	}
798 	else
799 		DE_ASSERT(false);
800 }
801 
802 //! Base for a functor for verifying and logging a 2d texture layer (2d image, cube face, 3d slice, 2d layer).
803 class ImageLayerVerifier
804 {
805 public:
806 	virtual bool	operator()				(TestLog&, const ConstPixelBufferAccess&, int sliceOrFaceNdx) const = 0;
~ImageLayerVerifier(void)807 	virtual			~ImageLayerVerifier		(void) {}
808 };
809 
setTexParameteri(glu::CallLogWrapper & glLog,deUint32 target)810 static void setTexParameteri (glu::CallLogWrapper& glLog, deUint32 target)
811 {
812 	if (target != GL_TEXTURE_BUFFER)
813 	{
814 		glLog.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
815 		glLog.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
816 	}
817 }
818 
819 //! Binds texture (one layer at a time) to color attachment of FBO and does glReadPixels(). Calls the verifier for each layer.
820 //! \note Not for buffer textures.
readIntegerTextureViaFBOAndVerify(const RenderContext & renderCtx,glu::CallLogWrapper & glLog,deUint32 textureGL,TextureType textureType,const TextureFormat & textureFormat,const IVec3 & textureSize,const ImageLayerVerifier & verifyLayer)821 static bool readIntegerTextureViaFBOAndVerify (const RenderContext&			renderCtx,
822 											   glu::CallLogWrapper&			glLog,
823 											   deUint32						textureGL,
824 											   TextureType					textureType,
825 											   const TextureFormat&			textureFormat,
826 											   const IVec3&					textureSize,
827 											   const ImageLayerVerifier&	verifyLayer)
828 {
829 	DE_ASSERT(isFormatTypeInteger(textureFormat.type));
830 	DE_ASSERT(textureType != TEXTURETYPE_BUFFER);
831 
832 	TestLog& log = glLog.getLog();
833 
834 	const tcu::ScopedLogSection section(log, "Verification", "Result verification (bind texture layer-by-layer to FBO, read with glReadPixels())");
835 
836 	const int			numSlicesOrFaces	= textureType == TEXTURETYPE_CUBE ? 6 : textureSize.z();
837 	const deUint32		textureTargetGL		= getGLTextureTarget(textureType);
838 	glu::Framebuffer	fbo					(renderCtx);
839 	tcu::TextureLevel	resultSlice			(textureFormat, textureSize.x(), textureSize.y());
840 
841 	glLog.glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
842 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Bind FBO");
843 
844 	glLog.glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
845 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glMemoryBarrier");
846 
847 	glLog.glActiveTexture(GL_TEXTURE0);
848 	glLog.glBindTexture(textureTargetGL, textureGL);
849 	setTexParameteri(glLog, textureTargetGL);
850 
851 	for (int sliceOrFaceNdx = 0; sliceOrFaceNdx < numSlicesOrFaces; sliceOrFaceNdx++)
852 	{
853 		if (textureType == TEXTURETYPE_CUBE)
854 			glLog.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx)), textureGL, 0);
855 		else if (textureType == TEXTURETYPE_2D)
856 			glLog.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureGL, 0);
857 		else if (textureType == TEXTURETYPE_3D || textureType == TEXTURETYPE_2D_ARRAY)
858 			glLog.glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureGL, 0, sliceOrFaceNdx);
859 		else
860 			DE_ASSERT(false);
861 
862 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Bind texture to framebuffer color attachment 0");
863 
864 		TCU_CHECK(glLog.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
865 
866 		readPixelsRGBAInteger32(resultSlice.getAccess(), 0, 0, glLog);
867 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glReadPixels");
868 
869 		if (!verifyLayer(log, resultSlice, sliceOrFaceNdx))
870 			return false;
871 	}
872 
873 	return true;
874 }
875 
876 //! Reads texture with texture() in compute shader, one layer at a time, putting values into a SSBO and reading with a mapping. Calls the verifier for each layer.
877 //! \note Not for buffer textures.
readFloatOrNormTextureWithLookupsAndVerify(const RenderContext & renderCtx,glu::CallLogWrapper & glLog,deUint32 textureGL,TextureType textureType,const TextureFormat & textureFormat,const IVec3 & textureSize,const ImageLayerVerifier & verifyLayer)878 static bool readFloatOrNormTextureWithLookupsAndVerify (const RenderContext&		renderCtx,
879 														glu::CallLogWrapper&		glLog,
880 														deUint32					textureGL,
881 														TextureType					textureType,
882 														const TextureFormat&		textureFormat,
883 														const IVec3&				textureSize,
884 														const ImageLayerVerifier&	verifyLayer)
885 {
886 	DE_ASSERT(!isFormatTypeInteger(textureFormat.type));
887 	DE_ASSERT(textureType != TEXTURETYPE_BUFFER);
888 
889 	TestLog& log = glLog.getLog();
890 
891 	const tcu::ScopedLogSection section(log, "Verification", "Result verification (read texture layer-by-layer in compute shader with texture() into SSBO)");
892 	const std::string			glslVersionDeclaration = getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
893 
894 	const glu::ShaderProgram program(renderCtx,
895 		glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
896 													"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
897 													"layout (binding = 0) buffer Output\n"
898 													"{\n"
899 													"	vec4 color[" + toString(textureSize.x()*textureSize.y()) + "];\n"
900 													"} sb_out;\n"
901 													"\n"
902 													"precision highp " + getShaderSamplerType(textureFormat.type, textureType) + ";\n"
903 													"\n"
904 													"uniform highp " + getShaderSamplerType(textureFormat.type, textureType) + " u_texture;\n"
905 													"uniform highp vec3 u_texCoordLD;\n"
906 													"uniform highp vec3 u_texCoordRD;\n"
907 													"uniform highp vec3 u_texCoordLU;\n"
908 													"uniform highp vec3 u_texCoordRU;\n"
909 													"\n"
910 													"void main (void)\n"
911 													"{\n"
912 													"	int gx = int(gl_GlobalInvocationID.x);\n"
913 													"	int gy = int(gl_GlobalInvocationID.y);\n"
914 													"	highp float s = (float(gx) + 0.5) / float(" + toString(textureSize.x()) + ");\n"
915 													"	highp float t = (float(gy) + 0.5) / float(" + toString(textureType == TEXTURETYPE_CUBE ? textureSize.x() : textureSize.y()) + ");\n"
916 													"	highp vec3 texCoord = u_texCoordLD*(1.0-s)*(1.0-t)\n"
917 													"	                    + u_texCoordRD*(    s)*(1.0-t)\n"
918 													"	                    + u_texCoordLU*(1.0-s)*(    t)\n"
919 													"	                    + u_texCoordRU*(    s)*(    t);\n"
920 													"	int ndx = gy*" + toString(textureSize.x()) + " + gx;\n"
921 													"	sb_out.color[ndx] = texture(u_texture, texCoord" + (textureType == TEXTURETYPE_2D ? ".xy" : "") + ");\n"
922 													"}\n"));
923 
924 	glLog.glUseProgram(program.getProgram());
925 
926 	log << program;
927 
928 	if (!program.isOk())
929 	{
930 		log << TestLog::Message << "// Failure: failed to compile program" << TestLog::EndMessage;
931 		TCU_FAIL("Program compilation failed");
932 	}
933 
934 	{
935 		const deUint32			textureTargetGL		= getGLTextureTarget(textureType);
936 		const glu::Buffer		outputBuffer		(renderCtx);
937 		UniformAccessLogger		uniforms			(renderCtx.getFunctions(), log, program.getProgram());
938 
939 		// Setup texture.
940 
941 		glLog.glActiveTexture(GL_TEXTURE0);
942 		glLog.glBindTexture(textureTargetGL, textureGL);
943 		setTexParameteri(glLog, textureTargetGL);
944 
945 		uniforms.assign1i("u_texture", 0);
946 
947 		// Setup output buffer.
948 		{
949 			const deUint32		blockIndex		= glLog.glGetProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output");
950 			const int			blockSize		= glu::getProgramResourceInt(renderCtx.getFunctions(), program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, GL_BUFFER_DATA_SIZE);
951 
952 			log << TestLog::Message << "// Got buffer data size = " << blockSize << TestLog::EndMessage;
953 			TCU_CHECK(blockSize > 0);
954 
955 			glLog.glBindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer);
956 			glLog.glBufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ);
957 			glLog.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer);
958 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "SSB setup failed");
959 		}
960 
961 		// Dispatch one layer at a time, read back and verify.
962 		{
963 			const int							numSlicesOrFaces	= textureType == TEXTURETYPE_CUBE ? 6 : textureSize.z();
964 			tcu::TextureLevel					resultSlice			(textureFormat, textureSize.x(), textureSize.y());
965 			const PixelBufferAccess				resultSliceAccess	= resultSlice.getAccess();
966 			const deUint32						blockIndex			= glLog.glGetProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output");
967 			const int							blockSize			= glu::getProgramResourceInt(renderCtx.getFunctions(), program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, GL_BUFFER_DATA_SIZE);
968 			const deUint32						valueIndex			= glLog.glGetProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.color");
969 			const glu::InterfaceVariableInfo	valueInfo			= glu::getProgramInterfaceVariableInfo(renderCtx.getFunctions(), program.getProgram(), GL_BUFFER_VARIABLE, valueIndex);
970 
971 			TCU_CHECK(valueInfo.arraySize == (deUint32)(textureSize.x()*textureSize.y()));
972 
973 			glLog.glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
974 
975 			for (int sliceOrFaceNdx = 0; sliceOrFaceNdx < numSlicesOrFaces; sliceOrFaceNdx++)
976 			{
977 				if (textureType == TEXTURETYPE_CUBE)
978 				{
979 					vector<float> coords;
980 					computeQuadTexCoordCube(coords, glslImageFuncZToCubeFace(sliceOrFaceNdx));
981 					uniforms.assign3f("u_texCoordLD", coords[3*0 + 0], coords[3*0 + 1], coords[3*0 + 2]);
982 					uniforms.assign3f("u_texCoordRD", coords[3*2 + 0], coords[3*2 + 1], coords[3*2 + 2]);
983 					uniforms.assign3f("u_texCoordLU", coords[3*1 + 0], coords[3*1 + 1], coords[3*1 + 2]);
984 					uniforms.assign3f("u_texCoordRU", coords[3*3 + 0], coords[3*3 + 1], coords[3*3 + 2]);
985 				}
986 				else
987 				{
988 					const float z = textureType == TEXTURETYPE_3D ?
989 										((float)sliceOrFaceNdx + 0.5f) / (float)numSlicesOrFaces :
990 										(float)sliceOrFaceNdx;
991 					uniforms.assign3f("u_texCoordLD", 0.0f, 0.0f, z);
992 					uniforms.assign3f("u_texCoordRD", 1.0f, 0.0f, z);
993 					uniforms.assign3f("u_texCoordLU", 0.0f, 1.0f, z);
994 					uniforms.assign3f("u_texCoordRU", 1.0f, 1.0f, z);
995 				}
996 
997 				glLog.glDispatchCompute(textureSize.x(), textureSize.y(), 1);
998 
999 				{
1000 					log << TestLog::Message << "// Note: mapping buffer and reading color values written" << TestLog::EndMessage;
1001 
1002 					const BufferMemMap bufMap(renderCtx.getFunctions(), GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT);
1003 
1004 					for (int y = 0; y < textureSize.y(); y++)
1005 					for (int x = 0; x < textureSize.x(); x++)
1006 					{
1007 						const int				ndx			= y*textureSize.x() + x;
1008 						const float* const		clrData		= (const float*)((const deUint8*)bufMap.getPtr() + valueInfo.offset + valueInfo.arrayStride*ndx);
1009 
1010 						switch (textureFormat.order)
1011 						{
1012 							case TextureFormat::R:		resultSliceAccess.setPixel(Vec4(clrData[0]),											x, y); break;
1013 							case TextureFormat::RGBA:	resultSliceAccess.setPixel(Vec4(clrData[0], clrData[1], clrData[2], clrData[3]),		x, y); break;
1014 							default:
1015 								DE_ASSERT(false);
1016 						}
1017 					}
1018 				}
1019 
1020 				if (!verifyLayer(log, resultSliceAccess, sliceOrFaceNdx))
1021 					return false;
1022 			}
1023 		}
1024 
1025 		return true;
1026 	}
1027 }
1028 
1029 //! Read buffer texture by reading the corresponding buffer with a mapping.
readBufferTextureWithMappingAndVerify(const RenderContext & renderCtx,glu::CallLogWrapper & glLog,deUint32 bufferGL,const TextureFormat & textureFormat,int imageSize,const ImageLayerVerifier & verifyLayer)1030 static bool readBufferTextureWithMappingAndVerify (const RenderContext&			renderCtx,
1031 												   glu::CallLogWrapper&			glLog,
1032 												   deUint32						bufferGL,
1033 												   const TextureFormat&			textureFormat,
1034 												   int							imageSize,
1035 												   const ImageLayerVerifier&	verifyLayer)
1036 {
1037 	tcu::TextureLevel			result			(textureFormat, imageSize, 1);
1038 	const PixelBufferAccess		resultAccess	= result.getAccess();
1039 	const int					dataSize		= imageSize * textureFormat.getPixelSize();
1040 
1041 	const tcu::ScopedLogSection section(glLog.getLog(), "Verification", "Result verification (read texture's buffer with a mapping)");
1042 	glLog.glBindBuffer(GL_TEXTURE_BUFFER, bufferGL);
1043 
1044 	{
1045 		const BufferMemMap bufMap(renderCtx.getFunctions(), GL_TEXTURE_BUFFER, 0, dataSize, GL_MAP_READ_BIT);
1046 		deMemcpy(resultAccess.getDataPtr(), bufMap.getPtr(), dataSize);
1047 	}
1048 
1049 	return verifyLayer(glLog.getLog(), resultAccess, 0);
1050 }
1051 
1052 //! Calls the appropriate texture verification function depending on texture format or type.
readTextureAndVerify(const RenderContext & renderCtx,glu::CallLogWrapper & glLog,deUint32 textureGL,deUint32 bufferGL,TextureType textureType,const TextureFormat & textureFormat,const IVec3 & imageSize,const ImageLayerVerifier & verifyLayer)1053 static bool readTextureAndVerify (const RenderContext&			renderCtx,
1054 								  glu::CallLogWrapper&			glLog,
1055 								  deUint32						textureGL,
1056 								  deUint32						bufferGL,
1057 								  TextureType					textureType,
1058 								  const TextureFormat&			textureFormat,
1059 								  const IVec3&					imageSize,
1060 								  const ImageLayerVerifier&		verifyLayer)
1061 {
1062 	if (textureType == TEXTURETYPE_BUFFER)
1063 		return readBufferTextureWithMappingAndVerify(renderCtx, glLog, bufferGL, textureFormat, imageSize.x(), verifyLayer);
1064 	else
1065 		return isFormatTypeInteger(textureFormat.type) ? readIntegerTextureViaFBOAndVerify				(renderCtx, glLog, textureGL, textureType, textureFormat, imageSize, verifyLayer)
1066 													   : readFloatOrNormTextureWithLookupsAndVerify		(renderCtx, glLog, textureGL, textureType, textureFormat, imageSize, verifyLayer);
1067 }
1068 
1069 //! An ImageLayerVerifier that simply compares the result slice to a slice in a reference image.
1070 //! \note Holds the reference image as a reference (no pun intended) instead of a copy; caller must be aware of lifetime issues.
1071 class ImageLayerComparer : public ImageLayerVerifier
1072 {
1073 public:
ImageLayerComparer(const LayeredImage & reference,const IVec2 & relevantRegion=IVec2 (0))1074 	ImageLayerComparer (const LayeredImage& reference,
1075 						const IVec2& relevantRegion = IVec2(0) /* If given, only check this region of each slice. */)
1076 		: m_reference		(reference)
1077 		, m_relevantRegion	(relevantRegion.x() > 0 && relevantRegion.y() > 0 ? relevantRegion : reference.getSize().swizzle(0, 1))
1078 	{
1079 	}
1080 
operator ()(TestLog & log,const tcu::ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const1081 	bool operator() (TestLog& log, const tcu::ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
1082 	{
1083 		const bool						isCube				= m_reference.getImageType() == TEXTURETYPE_CUBE;
1084 		const ConstPixelBufferAccess	referenceSlice		= tcu::getSubregion(isCube ? m_reference.getCubeFaceAccess(glslImageFuncZToCubeFace(sliceOrFaceNdx))
1085 																					   : m_reference.getSliceAccess(sliceOrFaceNdx),
1086 																				0, 0, m_relevantRegion.x(), m_relevantRegion.y());
1087 
1088 		const string comparisonName = "Comparison" + toString(sliceOrFaceNdx);
1089 		const string comparisonDesc = "Image Comparison, "
1090 									+ (isCube ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
1091 											  : "slice " + toString(sliceOrFaceNdx));
1092 
1093 		if (isFormatTypeInteger(m_reference.getFormat().type))
1094 			return tcu::intThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), referenceSlice, resultSlice, UVec4(0), tcu::COMPARE_LOG_RESULT);
1095 		else
1096 			return tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), referenceSlice, resultSlice, Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
1097 	}
1098 
1099 private:
1100 	const LayeredImage&		m_reference;
1101 	const IVec2				m_relevantRegion;
1102 };
1103 
1104 //! Case that just stores some computation results into an image.
1105 class ImageStoreCase : public TestCase
1106 {
1107 public:
1108 	enum CaseFlag
1109 	{
1110 		CASEFLAG_SINGLE_LAYER_BIND = 1 << 0 //!< If given, glBindImageTexture() is called with GL_FALSE <layered> argument, and for each layer the compute shader is separately dispatched.
1111 	};
1112 
ImageStoreCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType textureType,deUint32 caseFlags=0)1113 	ImageStoreCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType textureType, deUint32 caseFlags = 0)
1114 		: TestCase				(context, name, description)
1115 		, m_format				(format)
1116 		, m_textureType			(textureType)
1117 		, m_singleLayerBind		((caseFlags & CASEFLAG_SINGLE_LAYER_BIND) != 0)
1118 	{
1119 	}
1120 
init(void)1121 	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_textureType, m_context.getRenderContext()); }
1122 	IterateResult	iterate		(void);
1123 
1124 private:
1125 	const TextureFormat		m_format;
1126 	const TextureType		m_textureType;
1127 	const bool				m_singleLayerBind;
1128 };
1129 
iterate(void)1130 ImageStoreCase::IterateResult ImageStoreCase::iterate (void)
1131 {
1132 	const RenderContext&		renderCtx				= m_context.getRenderContext();
1133 	TestLog&					log						(m_testCtx.getLog());
1134 	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
1135 	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
1136 	const deUint32				textureTargetGL			= getGLTextureTarget(m_textureType);
1137 	const IVec3&				imageSize				= defaultImageSize(m_textureType);
1138 	const int					numSlicesOrFaces		= m_textureType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
1139 	const int					maxImageDimension		= de::max(imageSize.x(), de::max(imageSize.y(), imageSize.z()));
1140 	const float					storeColorScale			= isFormatTypeUnorm(m_format.type) ? 1.0f / (float)(maxImageDimension - 1)
1141 														: isFormatTypeSnorm(m_format.type) ? 2.0f / (float)(maxImageDimension - 1)
1142 														: 1.0f;
1143 	const float					storeColorBias			= isFormatTypeSnorm(m_format.type) ? -1.0f : 0.0f;
1144 	const glu::Buffer			textureBuf				(renderCtx); // \note Only really used if using buffer texture.
1145 	const glu::Texture			texture					(renderCtx);
1146 
1147 	glLog.enableLogging(true);
1148 
1149 	// Setup texture.
1150 
1151 	log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
1152 	if (m_textureType == TEXTURETYPE_BUFFER)
1153 		log << TestLog::Message << "// Created a buffer for the texture (name " << *textureBuf << ")" << TestLog::EndMessage;
1154 
1155 	glLog.glActiveTexture(GL_TEXTURE0);
1156 	glLog.glBindTexture(textureTargetGL, *texture);
1157 	setTexParameteri(glLog, textureTargetGL);
1158 	setTextureStorage(glLog, m_textureType, internalFormatGL, imageSize, *textureBuf);
1159 
1160 	// Perform image stores in compute shader.
1161 
1162 	{
1163 		// Generate compute shader.
1164 
1165 		const string		shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
1166 		const TextureType	shaderImageType			= m_singleLayerBind ? textureLayerType(m_textureType) : m_textureType;
1167 		const string		shaderImageTypeStr		= getShaderImageType(m_format.type, shaderImageType);
1168 		const bool			isUintFormat			= isFormatTypeUnsignedInteger(m_format.type);
1169 		const bool			isIntFormat				= isFormatTypeSignedInteger(m_format.type);
1170 		const string		colorBaseExpr			= string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4(gx^gy^gz, "
1171 																												 "(" + toString(imageSize.x()-1) + "-gx)^gy^gz, "
1172 																												 "gx^(" + toString(imageSize.y()-1) + "-gy)^gz, "
1173 																												 "(" + toString(imageSize.x()-1) + "-gx)^(" + toString(imageSize.y()-1) + "-gy)^gz)";
1174 		const string		colorExpr				= colorBaseExpr + (storeColorScale == 1.0f ? "" : "*" + toString(storeColorScale))
1175 																	+ (storeColorBias == 0.0f ? "" : " + float(" + toString(storeColorBias) + ")");
1176 		const std::string	glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
1177 
1178 		const glu::ShaderProgram program(renderCtx,
1179 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
1180 														+ textureTypeExtensionShaderRequires(shaderImageType, renderCtx) +
1181 														"\n"
1182 														"precision highp " + shaderImageTypeStr + ";\n"
1183 														"\n"
1184 														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
1185 														"layout (" + shaderImageFormatStr + ", binding=0) writeonly uniform " + shaderImageTypeStr + " u_image;\n"
1186 														+ (m_singleLayerBind ? "uniform int u_layerNdx;\n" : "") +
1187 														"\n"
1188 														"void main (void)\n"
1189 														"{\n"
1190 														"	int gx = int(gl_GlobalInvocationID.x);\n"
1191 														"	int gy = int(gl_GlobalInvocationID.y);\n"
1192 														"	int gz = " + (m_singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") + ";\n"
1193 														+ (shaderImageType == TEXTURETYPE_BUFFER ?
1194 															"	imageStore(u_image, gx, " + colorExpr + ");\n"
1195 														 : shaderImageType == TEXTURETYPE_2D ?
1196 															"	imageStore(u_image, ivec2(gx, gy), " + colorExpr + ");\n"
1197 														 : shaderImageType == TEXTURETYPE_3D || shaderImageType == TEXTURETYPE_CUBE || shaderImageType == TEXTURETYPE_2D_ARRAY ?
1198 															"	imageStore(u_image, ivec3(gx, gy, gz), " + colorExpr + ");\n"
1199 														 : DE_NULL) +
1200 														"}\n"));
1201 
1202 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
1203 
1204 		log << program;
1205 
1206 		if (!program.isOk())
1207 		{
1208 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
1209 			return STOP;
1210 		}
1211 
1212 		// Setup and dispatch.
1213 
1214 		glLog.glUseProgram(program.getProgram());
1215 
1216 		if (m_singleLayerBind)
1217 		{
1218 			for (int layerNdx = 0; layerNdx < numSlicesOrFaces; layerNdx++)
1219 			{
1220 				if (layerNdx > 0)
1221 					glLog.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1222 
1223 				uniforms.assign1i("u_layerNdx", layerNdx);
1224 
1225 				glLog.glBindImageTexture(0, *texture, 0, GL_FALSE, layerNdx, GL_WRITE_ONLY, internalFormatGL);
1226 				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1227 
1228 				glLog.glDispatchCompute(imageSize.x(), imageSize.y(), 1);
1229 				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
1230 			}
1231 		}
1232 		else
1233 		{
1234 			glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
1235 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1236 
1237 			glLog.glDispatchCompute(imageSize.x(), imageSize.y(), numSlicesOrFaces);
1238 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
1239 		}
1240 	}
1241 
1242 	// Create reference, read texture and compare to reference.
1243 	{
1244 		const int		isIntegerFormat		= isFormatTypeInteger(m_format.type);
1245 		LayeredImage	reference			(m_textureType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
1246 
1247 		DE_ASSERT(!isIntegerFormat || (storeColorScale == 1.0f && storeColorBias == 0.0f));
1248 
1249 		for (int z = 0; z < numSlicesOrFaces; z++)
1250 		for (int y = 0; y < imageSize.y(); y++)
1251 		for (int x = 0; x < imageSize.x(); x++)
1252 		{
1253 			const IVec4 color(x^y^z, (imageSize.x()-1-x)^y^z, x^(imageSize.y()-1-y)^z, (imageSize.x()-1-x)^(imageSize.y()-1-y)^z);
1254 
1255 			if (isIntegerFormat)
1256 				reference.setPixel(x, y, z, color);
1257 			else
1258 				reference.setPixel(x, y, z, color.asFloat()*storeColorScale + storeColorBias);
1259 		}
1260 
1261 		const bool compareOk = readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_textureType, m_format, imageSize, ImageLayerComparer(reference));
1262 
1263 		m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, compareOk ? "Pass" : "Image comparison failed");
1264 		return STOP;
1265 	}
1266 }
1267 
1268 //! Case that copies an image to another, using imageLoad() and imageStore(). Texture formats don't necessarily match image formats.
1269 class ImageLoadAndStoreCase : public TestCase
1270 {
1271 public:
1272 	enum CaseFlag
1273 	{
1274 		CASEFLAG_SINGLE_LAYER_BIND	= 1 << 0,	//!< If given, glBindImageTexture() is called with GL_FALSE <layered> argument, and for each layer the compute shader is separately dispatched.
1275 		CASEFLAG_RESTRICT_IMAGES	= 1 << 1	//!< If given, images in shader will be qualified with "restrict".
1276 	};
1277 
ImageLoadAndStoreCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType textureType,deUint32 caseFlags=0)1278 	ImageLoadAndStoreCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType textureType, deUint32 caseFlags = 0)
1279 		: TestCase				(context, name, description)
1280 		, m_textureFormat		(format)
1281 		, m_imageFormat			(format)
1282 		, m_textureType			(textureType)
1283 		, m_restrictImages		((caseFlags & CASEFLAG_RESTRICT_IMAGES)		!= 0)
1284 		, m_singleLayerBind		((caseFlags & CASEFLAG_SINGLE_LAYER_BIND)	!= 0)
1285 	{
1286 	}
1287 
ImageLoadAndStoreCase(Context & context,const char * name,const char * description,const TextureFormat & textureFormat,const TextureFormat & imageFormat,TextureType textureType,deUint32 caseFlags=0)1288 	ImageLoadAndStoreCase (Context& context, const char* name, const char* description, const TextureFormat& textureFormat, const TextureFormat& imageFormat, TextureType textureType, deUint32 caseFlags = 0)
1289 		: TestCase				(context, name, description)
1290 		, m_textureFormat		(textureFormat)
1291 		, m_imageFormat			(imageFormat)
1292 		, m_textureType			(textureType)
1293 		, m_restrictImages		((caseFlags & CASEFLAG_RESTRICT_IMAGES)		!= 0)
1294 		, m_singleLayerBind		((caseFlags & CASEFLAG_SINGLE_LAYER_BIND)	!= 0)
1295 	{
1296 		DE_ASSERT(textureFormat.getPixelSize() == imageFormat.getPixelSize());
1297 	}
1298 
init(void)1299 	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_textureType, m_context.getRenderContext()); }
1300 	IterateResult	iterate		(void);
1301 
1302 private:
1303 	template <TextureFormat::ChannelType ImageFormatType, typename TcuFloatType, typename TcuFloatStorageType>
1304 	static void					replaceBadFloatReinterpretValues (LayeredImage& image, const TextureFormat& imageFormat);
1305 
1306 	const TextureFormat			m_textureFormat;
1307 	const TextureFormat			m_imageFormat;
1308 	const TextureType			m_textureType;
1309 	const bool					m_restrictImages;
1310 	const bool					m_singleLayerBind;
1311 };
1312 
1313 template <TextureFormat::ChannelType ImageFormatType, typename TcuFloatType, typename TcuFloatTypeStorageType>
replaceBadFloatReinterpretValues(LayeredImage & image,const TextureFormat & imageFormat)1314 void ImageLoadAndStoreCase::replaceBadFloatReinterpretValues (LayeredImage& image, const TextureFormat& imageFormat)
1315 {
1316 	// Find potential bad values, such as nan or inf, and replace with something else.
1317 	const int		pixelSize			= imageFormat.getPixelSize();
1318 	const int		imageNumChannels	= imageFormat.order == tcu::TextureFormat::R	? 1
1319 										: imageFormat.order == tcu::TextureFormat::RGBA	? 4
1320 										: 0;
1321 	const IVec3		imageSize			= image.getSize();
1322 	const int		numSlicesOrFaces	= image.getImageType() == TEXTURETYPE_CUBE ? 6 : imageSize.z();
1323 
1324 	DE_ASSERT(pixelSize % imageNumChannels == 0);
1325 
1326 	for (int z = 0; z < numSlicesOrFaces; z++)
1327 	{
1328 		const PixelBufferAccess		sliceAccess		= image.getImageType() == TEXTURETYPE_CUBE ? image.getCubeFaceAccess((tcu::CubeFace)z) : image.getSliceAccess(z);
1329 		const int					rowPitch		= sliceAccess.getRowPitch();
1330 		void *const					data			= sliceAccess.getDataPtr();
1331 
1332 		for (int y = 0; y < imageSize.y(); y++)
1333 		for (int x = 0; x < imageSize.x(); x++)
1334 		{
1335 			void *const pixelData = (deUint8*)data + y*rowPitch + x*pixelSize;
1336 
1337 			for (int c = 0; c < imageNumChannels; c++)
1338 			{
1339 				void *const			channelData		= (deUint8*)pixelData + c*pixelSize/imageNumChannels;
1340 				const TcuFloatType	f				(*(TcuFloatTypeStorageType*)channelData);
1341 
1342 				if (f.isDenorm() || f.isInf() || f.isNaN())
1343 					*(TcuFloatTypeStorageType*)channelData = TcuFloatType(0.0f).bits();
1344 			}
1345 		}
1346 	}
1347 }
1348 
iterate(void)1349 ImageLoadAndStoreCase::IterateResult ImageLoadAndStoreCase::iterate (void)
1350 {
1351 	const RenderContext&		renderCtx					= m_context.getRenderContext();
1352 	TestLog&					log							(m_testCtx.getLog());
1353 	glu::CallLogWrapper			glLog						(renderCtx.getFunctions(), log);
1354 	const deUint32				textureInternalFormatGL		= glu::getInternalFormat(m_textureFormat);
1355 	const deUint32				imageInternalFormatGL		= glu::getInternalFormat(m_imageFormat);
1356 	const deUint32				textureTargetGL				= getGLTextureTarget(m_textureType);
1357 	const IVec3&				imageSize					= defaultImageSize(m_textureType);
1358 	const int					maxImageDimension			= de::max(imageSize.x(), de::max(imageSize.y(), imageSize.z()));
1359 	const float					storeColorScale				= isFormatTypeUnorm(m_textureFormat.type) ? 1.0f / (float)(maxImageDimension - 1)
1360 															: isFormatTypeSnorm(m_textureFormat.type) ? 2.0f / (float)(maxImageDimension - 1)
1361 															: 1.0f;
1362 	const float					storeColorBias				= isFormatTypeSnorm(m_textureFormat.type) ? -1.0f : 0.0f;
1363 	const int					numSlicesOrFaces			= m_textureType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
1364 	const bool					isIntegerTextureFormat		= isFormatTypeInteger(m_textureFormat.type);
1365 	const glu::Buffer			texture0Buf					(renderCtx);
1366 	const glu::Buffer			texture1Buf					(renderCtx);
1367 	const glu::Texture			texture0					(renderCtx);
1368 	const glu::Texture			texture1					(renderCtx);
1369 	LayeredImage				reference					(m_textureType, m_textureFormat, imageSize.x(), imageSize.y(), imageSize.z());
1370 
1371 	glLog.enableLogging(true);
1372 
1373 	// Setup textures.
1374 
1375 	log << TestLog::Message << "// Created 2 textures (names " << *texture0 << " and " << *texture1 << ")" << TestLog::EndMessage;
1376 	if (m_textureType == TEXTURETYPE_BUFFER)
1377 		log << TestLog::Message << "// Created buffers for the textures (names " << *texture0Buf << " and " << *texture1Buf << ")" << TestLog::EndMessage;
1378 
1379 	// First, fill reference with (a fairly arbitrary) initial pattern. This will be used as texture upload source data as well as for actual reference computation later on.
1380 
1381 	DE_ASSERT(!isIntegerTextureFormat || (storeColorScale == 1.0f && storeColorBias == 0.0f));
1382 
1383 	for (int z = 0; z < numSlicesOrFaces; z++)
1384 	for (int y = 0; y < imageSize.y(); y++)
1385 	for (int x = 0; x < imageSize.x(); x++)
1386 	{
1387 		const IVec4 color(x^y^z, (imageSize.x()-1-x)^y^z, x^(imageSize.y()-1-y)^z, (imageSize.x()-1-x)^(imageSize.y()-1-y)^z);
1388 
1389 		if (isIntegerTextureFormat)
1390 			reference.setPixel(x, y, z, color);
1391 		else
1392 			reference.setPixel(x, y, z, color.asFloat()*storeColorScale + storeColorBias);
1393 	}
1394 
1395 	// If re-interpreting the texture contents as floating point values, need to get rid of inf, nan etc.
1396 	if (m_imageFormat.type == TextureFormat::HALF_FLOAT && m_textureFormat.type != TextureFormat::HALF_FLOAT)
1397 		replaceBadFloatReinterpretValues<TextureFormat::HALF_FLOAT, tcu::Float16, deUint16>(reference, m_imageFormat);
1398 	else if (m_imageFormat.type == TextureFormat::FLOAT && m_textureFormat.type != TextureFormat::FLOAT)
1399 		replaceBadFloatReinterpretValues<TextureFormat::FLOAT, tcu::Float32, deUint32>(reference, m_imageFormat);
1400 
1401 	// Upload initial pattern to texture 0.
1402 
1403 	glLog.glActiveTexture(GL_TEXTURE0);
1404 	glLog.glBindTexture(textureTargetGL, *texture0);
1405 	setTexParameteri(glLog, textureTargetGL);
1406 
1407 	log << TestLog::Message << "// Filling texture " << *texture0 << " with xor pattern" << TestLog::EndMessage;
1408 
1409 	uploadTexture(glLog, reference, *texture0Buf);
1410 
1411 	// Set storage for texture 1.
1412 
1413 	glLog.glActiveTexture(GL_TEXTURE1);
1414 	glLog.glBindTexture(textureTargetGL, *texture1);
1415 	setTexParameteri(glLog, textureTargetGL);
1416 	setTextureStorage(glLog, m_textureType, textureInternalFormatGL, imageSize, *texture1Buf);
1417 
1418 	// Perform image loads and stores in compute shader and finalize reference computation.
1419 
1420 	{
1421 		// Generate compute shader.
1422 
1423 		const char* const		maybeRestrict			= m_restrictImages ? "restrict" : "";
1424 		const string			shaderImageFormatStr	= getShaderImageFormatQualifier(m_imageFormat);
1425 		const TextureType		shaderImageType			= m_singleLayerBind ? textureLayerType(m_textureType) : m_textureType;
1426 		const string			shaderImageTypeStr		= getShaderImageType(m_imageFormat.type, shaderImageType);
1427 		const std::string		glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
1428 
1429 		const glu::ShaderProgram program(renderCtx,
1430 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
1431 														+ textureTypeExtensionShaderRequires(shaderImageType, renderCtx) +
1432 														"\n"
1433 														"precision highp " + shaderImageTypeStr + ";\n"
1434 														"\n"
1435 														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
1436 														"layout (" + shaderImageFormatStr + ", binding=0) " + maybeRestrict + " readonly uniform " + shaderImageTypeStr + " u_image0;\n"
1437 														"layout (" + shaderImageFormatStr + ", binding=1) " + maybeRestrict + " writeonly uniform " + shaderImageTypeStr + " u_image1;\n"
1438 														"\n"
1439 														"void main (void)\n"
1440 														"{\n"
1441 														+ (shaderImageType == TEXTURETYPE_BUFFER ?
1442 															"	int pos = int(gl_GlobalInvocationID.x);\n"
1443 															"	imageStore(u_image1, pos, imageLoad(u_image0, " + toString(imageSize.x()-1) + "-pos));\n"
1444 														 : shaderImageType == TEXTURETYPE_2D ?
1445 															"	ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n"
1446 															"	imageStore(u_image1, pos, imageLoad(u_image0, ivec2(" + toString(imageSize.x()-1) + "-pos.x, pos.y)));\n"
1447 														 : shaderImageType == TEXTURETYPE_3D || shaderImageType == TEXTURETYPE_CUBE || shaderImageType == TEXTURETYPE_2D_ARRAY ?
1448 															"	ivec3 pos = ivec3(gl_GlobalInvocationID);\n"
1449 															"	imageStore(u_image1, pos, imageLoad(u_image0, ivec3(" + toString(imageSize.x()-1) + "-pos.x, pos.y, pos.z)));\n"
1450 														 : DE_NULL) +
1451 														"}\n"));
1452 
1453 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
1454 
1455 		log << program;
1456 
1457 		if (!program.isOk())
1458 		{
1459 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
1460 			return STOP;
1461 		}
1462 
1463 		// Setup and dispatch.
1464 
1465 		glLog.glUseProgram(program.getProgram());
1466 
1467 		if (m_singleLayerBind)
1468 		{
1469 			for (int layerNdx = 0; layerNdx < numSlicesOrFaces; layerNdx++)
1470 			{
1471 				if (layerNdx > 0)
1472 					glLog.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1473 
1474 				glLog.glBindImageTexture(0, *texture0, 0, GL_FALSE, layerNdx, GL_READ_ONLY, imageInternalFormatGL);
1475 				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1476 
1477 				glLog.glBindImageTexture(1, *texture1, 0, GL_FALSE, layerNdx, GL_WRITE_ONLY, imageInternalFormatGL);
1478 				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1479 
1480 				glLog.glDispatchCompute(imageSize.x(), imageSize.y(), 1);
1481 				GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
1482 			}
1483 		}
1484 		else
1485 		{
1486 			glLog.glBindImageTexture(0, *texture0, 0, GL_TRUE, 0, GL_READ_ONLY, imageInternalFormatGL);
1487 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1488 
1489 			glLog.glBindImageTexture(1, *texture1, 0, GL_TRUE, 0, GL_WRITE_ONLY, imageInternalFormatGL);
1490 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1491 
1492 			glLog.glDispatchCompute(imageSize.x(), imageSize.y(), numSlicesOrFaces);
1493 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
1494 		}
1495 
1496 		// Finalize reference.
1497 
1498 		if (m_textureFormat != m_imageFormat)
1499 		{
1500 			// Format re-interpretation case. Read data with image format and write back, with the same image format.
1501 			// We do this because the data may change a little during lookups (e.g. unorm8 -> float; not all unorms can be exactly represented as floats).
1502 
1503 			const int					pixelSize		= m_imageFormat.getPixelSize();
1504 			tcu::TextureLevel			scratch			(m_imageFormat, 1, 1);
1505 			const PixelBufferAccess		scratchAccess	= scratch.getAccess();
1506 
1507 			for (int z = 0; z < numSlicesOrFaces; z++)
1508 			{
1509 				const PixelBufferAccess		sliceAccess		= m_textureType == TEXTURETYPE_CUBE ? reference.getCubeFaceAccess((tcu::CubeFace)z) : reference.getSliceAccess(z);
1510 				const int					rowPitch		= sliceAccess.getRowPitch();
1511 				void *const					data			= sliceAccess.getDataPtr();
1512 
1513 				for (int y = 0; y < imageSize.y(); y++)
1514 				for (int x = 0; x < imageSize.x(); x++)
1515 				{
1516 					void *const pixelData = (deUint8*)data + y*rowPitch + x*pixelSize;
1517 
1518 					deMemcpy(scratchAccess.getDataPtr(), pixelData, pixelSize);
1519 
1520 					if (isFormatTypeInteger(m_imageFormat.type))
1521 						scratchAccess.setPixel(scratchAccess.getPixelUint(0, 0), 0, 0);
1522 					else
1523 						scratchAccess.setPixel(scratchAccess.getPixel(0, 0), 0, 0);
1524 
1525 					deMemcpy(pixelData, scratchAccess.getDataPtr(), pixelSize);
1526 				}
1527 			}
1528 		}
1529 
1530 		for (int z = 0; z < numSlicesOrFaces; z++)
1531 		for (int y = 0; y < imageSize.y(); y++)
1532 		for (int x = 0; x < imageSize.x()/2; x++)
1533 		{
1534 			if (isIntegerTextureFormat)
1535 			{
1536 				const UVec4 temp = reference.getPixelUint(imageSize.x()-1-x, y, z);
1537 				reference.setPixel(imageSize.x()-1-x, y, z, reference.getPixelUint(x, y, z));
1538 				reference.setPixel(x, y, z, temp);
1539 			}
1540 			else
1541 			{
1542 				const Vec4 temp = reference.getPixel(imageSize.x()-1-x, y, z);
1543 				reference.setPixel(imageSize.x()-1-x, y, z, reference.getPixel(x, y, z));
1544 				reference.setPixel(x, y, z, temp);
1545 			}
1546 		}
1547 	}
1548 
1549 	// Read texture 1 and compare to reference.
1550 
1551 	const bool compareOk = readTextureAndVerify(renderCtx, glLog, *texture1, *texture1Buf, m_textureType, m_textureFormat, imageSize, ImageLayerComparer(reference));
1552 
1553 	m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, compareOk ? "Pass" : "Image comparison failed");
1554 	return STOP;
1555 }
1556 
1557 enum AtomicOperationCaseType
1558 {
1559 	ATOMIC_OPERATION_CASE_TYPE_END_RESULT = 0,	//!< Atomic case checks the end result of the operations, and not the return values.
1560 	ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES,	//!< Atomic case checks the return values of the atomic function, and not the end result.
1561 
1562 	ATOMIC_OPERATION_CASE_TYPE_LAST
1563 };
1564 
1565 /*--------------------------------------------------------------------*//*!
1566  * \brief Binary atomic operation case.
1567  *
1568  * Case that performs binary atomic operations (i.e. any but compSwap) and
1569  * verifies according to the given AtomicOperationCaseType.
1570  *
1571  * For the "end result" case type, a single texture (and image) is created,
1572  * upon which the atomic operations operate. A compute shader is dispatched
1573  * with dimensions equal to the image size, except with a bigger X size
1574  * so that every pixel is operated on by multiple invocations. The end
1575  * results are verified in BinaryAtomicOperationCase::EndResultVerifier.
1576  * The return values of the atomic function calls are ignored.
1577  *
1578  * For the "return value" case type, the case does much the same operations
1579  * as in the "end result" case, but also creates an additional texture,
1580  * of size equal to the dispatch size, into which the return values of the
1581  * atomic functions are stored (with imageStore()). The return values are
1582  * verified in BinaryAtomicOperationCase::ReturnValueVerifier.
1583  * The end result values are not checked.
1584  *
1585  * The compute shader invocations contributing to a pixel (X, Y, Z) in the
1586  * end result image are the invocations with global IDs
1587  * (X, Y, Z), (X+W, Y, Z), (X+2*W, Y, Z), ..., (X+(N-1)*W, Y, W), where W
1588  * is the width of the end result image and N is
1589  * BinaryAtomicOperationCase::NUM_INVOCATIONS_PER_PIXEL.
1590  *//*--------------------------------------------------------------------*/
1591 class BinaryAtomicOperationCase : public TestCase
1592 {
1593 public:
BinaryAtomicOperationCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,AtomicOperation operation,AtomicOperationCaseType caseType)1594 									BinaryAtomicOperationCase		(Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, AtomicOperation operation, AtomicOperationCaseType caseType)
1595 		: TestCase		(context, name, description)
1596 		, m_format		(format)
1597 		, m_imageType	(imageType)
1598 		, m_operation	(operation)
1599 		, m_caseType	(caseType)
1600 	{
1601 		DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32)	||
1602 				  m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32)		||
1603 				  (m_format == TextureFormat(TextureFormat::R, TextureFormat::FLOAT) && m_operation == ATOMIC_OPERATION_EXCHANGE));
1604 
1605 		DE_ASSERT(m_operation != ATOMIC_OPERATION_COMP_SWAP);
1606 	}
1607 
1608 	void							init							(void);
1609 	IterateResult					iterate							(void);
1610 
1611 private:
1612 	class EndResultVerifier;
1613 	class ReturnValueVerifier;
1614 
1615 	static int						getOperationInitialValue		(AtomicOperation op); //!< Appropriate value with which to initialize the texture.
1616 	//! Compute the argument given to the atomic function at the given invocation ID, when the entire dispatch has the given width and height.
1617 	static int						getAtomicFuncArgument			(AtomicOperation op, const IVec3& invocationID, const IVec2& dispatchSizeXY);
1618 	//! Generate the shader expression for the argument given to the atomic function. x, y and z are the identifiers for the invocation ID components.
1619 	static string					getAtomicFuncArgumentShaderStr	(AtomicOperation op, const string& x, const string& y, const string& z, const IVec2& dispatchSizeXY);
1620 
1621 	static const int				NUM_INVOCATIONS_PER_PIXEL = 5;
1622 
1623 	const TextureFormat				m_format;
1624 	const TextureType				m_imageType;
1625 	const AtomicOperation			m_operation;
1626 	const AtomicOperationCaseType	m_caseType;
1627 };
1628 
getOperationInitialValue(AtomicOperation op)1629 int BinaryAtomicOperationCase::getOperationInitialValue (AtomicOperation op)
1630 {
1631 	switch (op)
1632 	{
1633 		// \note 18 is just an arbitrary small nonzero value.
1634 		case ATOMIC_OPERATION_ADD:			return 18;
1635 		case ATOMIC_OPERATION_MIN:			return (1<<15) - 1;
1636 		case ATOMIC_OPERATION_MAX:			return 18;
1637 		case ATOMIC_OPERATION_AND:			return (1<<15) - 1;
1638 		case ATOMIC_OPERATION_OR:			return 18;
1639 		case ATOMIC_OPERATION_XOR:			return 18;
1640 		case ATOMIC_OPERATION_EXCHANGE:		return 18;
1641 		default:
1642 			DE_ASSERT(false);
1643 			return -1;
1644 	}
1645 }
1646 
getAtomicFuncArgument(AtomicOperation op,const IVec3 & invocationID,const IVec2 & dispatchSizeXY)1647 int BinaryAtomicOperationCase::getAtomicFuncArgument (AtomicOperation op, const IVec3& invocationID, const IVec2& dispatchSizeXY)
1648 {
1649 	const int x		= invocationID.x();
1650 	const int y		= invocationID.y();
1651 	const int z		= invocationID.z();
1652 	const int wid	= dispatchSizeXY.x();
1653 	const int hei	= dispatchSizeXY.y();
1654 
1655 	switch (op)
1656 	{
1657 		// \note Fall-throughs.
1658 		case ATOMIC_OPERATION_ADD:
1659 		case ATOMIC_OPERATION_MIN:
1660 		case ATOMIC_OPERATION_MAX:
1661 		case ATOMIC_OPERATION_AND:
1662 		case ATOMIC_OPERATION_OR:
1663 		case ATOMIC_OPERATION_XOR:
1664 			return x*x + y*y + z*z;
1665 
1666 		case ATOMIC_OPERATION_EXCHANGE:
1667 			return (z*wid + x)*hei + y;
1668 
1669 		default:
1670 			DE_ASSERT(false);
1671 			return -1;
1672 	}
1673 }
1674 
getAtomicFuncArgumentShaderStr(AtomicOperation op,const string & x,const string & y,const string & z,const IVec2 & dispatchSizeXY)1675 string BinaryAtomicOperationCase::getAtomicFuncArgumentShaderStr (AtomicOperation op, const string& x, const string& y, const string& z, const IVec2& dispatchSizeXY)
1676 {
1677 	switch (op)
1678 	{
1679 		// \note Fall-throughs.
1680 		case ATOMIC_OPERATION_ADD:
1681 		case ATOMIC_OPERATION_MIN:
1682 		case ATOMIC_OPERATION_MAX:
1683 		case ATOMIC_OPERATION_AND:
1684 		case ATOMIC_OPERATION_OR:
1685 		case ATOMIC_OPERATION_XOR:
1686 			return "("+ x+"*"+x +" + "+ y+"*"+y +" + "+ z+"*"+z +")";
1687 
1688 		case ATOMIC_OPERATION_EXCHANGE:
1689 			return "((" + z + "*" + toString(dispatchSizeXY.x()) + " + " + x + ")*" + toString(dispatchSizeXY.y()) + " + " + y + ")";
1690 
1691 		default:
1692 			DE_ASSERT(false);
1693 			return DE_NULL;
1694 	}
1695 }
1696 
1697 class BinaryAtomicOperationCase::EndResultVerifier : public ImageLayerVerifier
1698 {
1699 public:
EndResultVerifier(AtomicOperation operation,TextureType imageType)1700 	EndResultVerifier (AtomicOperation operation, TextureType imageType) : m_operation(operation), m_imageType(imageType) {}
1701 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const1702 	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
1703 	{
1704 		const bool		isIntegerFormat		= isFormatTypeInteger(resultSlice.getFormat().type);
1705 		const IVec2		dispatchSizeXY		(NUM_INVOCATIONS_PER_PIXEL*resultSlice.getWidth(), resultSlice.getHeight());
1706 
1707 		log << TestLog::Image("EndResults" + toString(sliceOrFaceNdx),
1708 							  "Result Values, " + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
1709 																				   : "slice " + toString(sliceOrFaceNdx)),
1710 							  resultSlice);
1711 
1712 		for (int y = 0; y < resultSlice.getHeight(); y++)
1713 		for (int x = 0; x < resultSlice.getWidth(); x++)
1714 		{
1715 			union
1716 			{
1717 				int		i;
1718 				float	f;
1719 			} result;
1720 
1721 			if (isIntegerFormat)
1722 				result.i = resultSlice.getPixelInt(x, y).x();
1723 			else
1724 				result.f = resultSlice.getPixel(x, y).x();
1725 
1726 			// Compute the arguments that were given to the atomic function in the invocations that contribute to this pixel.
1727 
1728 			IVec3	invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
1729 			int		atomicArgs[NUM_INVOCATIONS_PER_PIXEL];
1730 
1731 			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
1732 			{
1733 				const IVec3 gid(x + i*resultSlice.getWidth(), y, sliceOrFaceNdx);
1734 
1735 				invocationGlobalIDs[i]	= gid;
1736 				atomicArgs[i]			= getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
1737 			}
1738 
1739 			if (isOrderIndependentAtomicOperation(m_operation))
1740 			{
1741 				// Just accumulate the atomic args (and the initial value) according to the operation, and compare.
1742 
1743 				DE_ASSERT(isIntegerFormat);
1744 
1745 				int reference = getOperationInitialValue(m_operation);
1746 
1747 				for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
1748 					reference = computeBinaryAtomicOperationResult(m_operation, reference, atomicArgs[i]);
1749 
1750 				if (result.i != reference)
1751 				{
1752 					log << TestLog::Message << "// Failure: end result at pixel " << IVec2(x, y) << " of current layer is " << result.i << TestLog::EndMessage
1753 						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
1754 						<< TestLog::Message << "// Note: data expression values for the IDs are " << arrayStr(atomicArgs) << TestLog::EndMessage
1755 						<< TestLog::Message << "// Note: reference value is " << reference << TestLog::EndMessage;
1756 					return false;
1757 				}
1758 			}
1759 			else if (m_operation == ATOMIC_OPERATION_EXCHANGE)
1760 			{
1761 				// Check that the end result equals one of the atomic args.
1762 
1763 				bool matchFound = false;
1764 
1765 				for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL && !matchFound; i++)
1766 					matchFound = isIntegerFormat ? result.i == atomicArgs[i]
1767 												 : de::abs(result.f - (float)atomicArgs[i]) <= 0.01f;
1768 
1769 				if (!matchFound)
1770 				{
1771 					log << TestLog::Message << "// Failure: invalid value at pixel " << IVec2(x, y) << ": got " << (isIntegerFormat ? toString(result.i) : toString(result.f)) << TestLog::EndMessage
1772 											<< TestLog::Message << "// Note: expected one of " << arrayStr(atomicArgs) << TestLog::EndMessage;
1773 
1774 					return false;
1775 				}
1776 			}
1777 			else
1778 				DE_ASSERT(false);
1779 		}
1780 
1781 		return true;
1782 	}
1783 
1784 private:
1785 	const AtomicOperation	m_operation;
1786 	const TextureType		m_imageType;
1787 };
1788 
1789 class BinaryAtomicOperationCase::ReturnValueVerifier : public ImageLayerVerifier
1790 {
1791 public:
1792 	//! \note endResultImageLayerSize is (width, height) of the image operated on by the atomic ops, and not the size of the image where the return values are stored.
ReturnValueVerifier(AtomicOperation operation,TextureType imageType,const IVec2 & endResultImageLayerSize)1793 	ReturnValueVerifier (AtomicOperation operation, TextureType imageType, const IVec2& endResultImageLayerSize) : m_operation(operation), m_imageType(imageType), m_endResultImageLayerSize(endResultImageLayerSize) {}
1794 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const1795 	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
1796 	{
1797 		const bool		isIntegerFormat		(isFormatTypeInteger(resultSlice.getFormat().type));
1798 		const IVec2		dispatchSizeXY	(resultSlice.getWidth(), resultSlice.getHeight());
1799 
1800 		DE_ASSERT(resultSlice.getWidth()	== NUM_INVOCATIONS_PER_PIXEL*m_endResultImageLayerSize.x()	&&
1801 				  resultSlice.getHeight()	== m_endResultImageLayerSize.y()							&&
1802 				  resultSlice.getDepth()	== 1);
1803 
1804 		log << TestLog::Image("ReturnValues" + toString(sliceOrFaceNdx),
1805 							  "Per-Invocation Return Values, "
1806 								   + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
1807 																	  : "slice " + toString(sliceOrFaceNdx)),
1808 							  resultSlice);
1809 
1810 		for (int y = 0; y < m_endResultImageLayerSize.y(); y++)
1811 		for (int x = 0; x < m_endResultImageLayerSize.x(); x++)
1812 		{
1813 			union IntFloatArr
1814 			{
1815 				int		i[NUM_INVOCATIONS_PER_PIXEL];
1816 				float	f[NUM_INVOCATIONS_PER_PIXEL];
1817 			};
1818 
1819 			// Get the atomic function args and return values for all the invocations that contribute to the pixel (x, y) in the current end result slice.
1820 
1821 			IntFloatArr		returnValues;
1822 			IntFloatArr		atomicArgs;
1823 			IVec3			invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
1824 			IVec2			pixelCoords[NUM_INVOCATIONS_PER_PIXEL];
1825 
1826 			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
1827 			{
1828 				const IVec2 pixCoord	(x + i*m_endResultImageLayerSize.x(), y);
1829 				const IVec3 gid			(pixCoord.x(), pixCoord.y(), sliceOrFaceNdx);
1830 
1831 				invocationGlobalIDs[i]	= gid;
1832 				pixelCoords[i]			= pixCoord;
1833 
1834 				if (isIntegerFormat)
1835 				{
1836 					returnValues.i[i]	= resultSlice.getPixelInt(gid.x(), y).x();
1837 					atomicArgs.i[i]		= getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
1838 				}
1839 				else
1840 				{
1841 					returnValues.f[i]	= resultSlice.getPixel(gid.x(), y).x();
1842 					atomicArgs.f[i]		= (float)getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
1843 				}
1844 			}
1845 
1846 			// Verify that the return values form a valid sequence.
1847 
1848 			{
1849 				const bool success = isIntegerFormat ? verifyOperationAccumulationIntermediateValues(m_operation,
1850 																									 getOperationInitialValue(m_operation),
1851 																									 atomicArgs.i,
1852 																									 returnValues.i)
1853 
1854 													 : verifyOperationAccumulationIntermediateValues(m_operation,
1855 																									 (float)getOperationInitialValue(m_operation),
1856 																									 atomicArgs.f,
1857 																									 returnValues.f);
1858 
1859 				if (!success)
1860 				{
1861 					log << TestLog::Message << "// Failure: intermediate return values at pixels " << arrayStr(pixelCoords) << " of current layer are "
1862 											<< (isIntegerFormat ? arrayStr(returnValues.i) : arrayStr(returnValues.f)) << TestLog::EndMessage
1863 						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
1864 						<< TestLog::Message << "// Note: data expression values for the IDs are "
1865 											<< (isIntegerFormat ? arrayStr(atomicArgs.i) : arrayStr(atomicArgs.f))
1866 											<< "; return values are not a valid result for any order of operations" << TestLog::EndMessage;
1867 					return false;
1868 				}
1869 			}
1870 		}
1871 
1872 		return true;
1873 	}
1874 
1875 private:
1876 	const AtomicOperation	m_operation;
1877 	const TextureType		m_imageType;
1878 	const IVec2				m_endResultImageLayerSize;
1879 
1880 	//! Check whether there exists an ordering of args such that { init*A", init*A*B, ..., init*A*B*...*LAST } is the "returnValues" sequence, where { A, B, ..., LAST } is args, and * denotes the operation.
1881 	//	That is, whether "returnValues" is a valid sequence of intermediate return values when "operation" has been accumulated on "args" (and "init") in some arbitrary order.
1882 	template <typename T>
verifyOperationAccumulationIntermediateValues(AtomicOperation operation,T init,const T (& args)[NUM_INVOCATIONS_PER_PIXEL],const T (& returnValues)[NUM_INVOCATIONS_PER_PIXEL])1883 	static bool verifyOperationAccumulationIntermediateValues (AtomicOperation operation, T init, const T (&args)[NUM_INVOCATIONS_PER_PIXEL], const T (&returnValues)[NUM_INVOCATIONS_PER_PIXEL])
1884 	{
1885 		bool argsUsed[NUM_INVOCATIONS_PER_PIXEL] = { false };
1886 
1887 		return verifyRecursive(operation, 0, init, argsUsed, args, returnValues);
1888 	}
1889 
compare(int a,int b)1890 	static bool compare (int a, int b)		{ return a == b; }
compare(float a,float b)1891 	static bool compare (float a, float b)	{ return de::abs(a - b) <= 0.01f; }
1892 
1893 	//! Depth-first search for verifying the return value sequence.
1894 	template <typename T>
verifyRecursive(AtomicOperation operation,int index,T valueSoFar,bool (& argsUsed)[NUM_INVOCATIONS_PER_PIXEL],const T (& args)[NUM_INVOCATIONS_PER_PIXEL],const T (& returnValues)[NUM_INVOCATIONS_PER_PIXEL])1895 	static bool verifyRecursive (AtomicOperation operation, int index, T valueSoFar, bool (&argsUsed)[NUM_INVOCATIONS_PER_PIXEL], const T (&args)[NUM_INVOCATIONS_PER_PIXEL], const T (&returnValues)[NUM_INVOCATIONS_PER_PIXEL])
1896 	{
1897 		if (index < NUM_INVOCATIONS_PER_PIXEL)
1898 		{
1899 			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
1900 			{
1901 				if (!argsUsed[i] && compare(returnValues[i], valueSoFar))
1902 				{
1903 					argsUsed[i] = true;
1904 					if (verifyRecursive(operation, index+1, computeBinaryAtomicOperationResult(operation, valueSoFar, args[i]), argsUsed, args, returnValues))
1905 						return true;
1906 					argsUsed[i] = false;
1907 				}
1908 			}
1909 
1910 			return false;
1911 		}
1912 		else
1913 			return true;
1914 	}
1915 };
1916 
init(void)1917 void BinaryAtomicOperationCase::init (void)
1918 {
1919 	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
1920 		throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension");
1921 
1922 	checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext());
1923 }
1924 
iterate(void)1925 BinaryAtomicOperationCase::IterateResult BinaryAtomicOperationCase::iterate (void)
1926 {
1927 	const RenderContext&		renderCtx				= m_context.getRenderContext();
1928 	TestLog&					log						(m_testCtx.getLog());
1929 	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
1930 	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
1931 	const deUint32				textureTargetGL			= getGLTextureTarget(m_imageType);
1932 	const IVec3&				imageSize				= defaultImageSize(m_imageType);
1933 	const int					numSlicesOrFaces		= m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
1934 	const bool					isUintFormat			= isFormatTypeUnsignedInteger(m_format.type);
1935 	const bool					isIntFormat				= isFormatTypeSignedInteger(m_format.type);
1936 	const glu::Buffer			endResultTextureBuf		(renderCtx);
1937 	const glu::Buffer			returnValueTextureBuf	(renderCtx);
1938 	const glu::Texture			endResultTexture		(renderCtx); //!< Texture for the final result; i.e. the texture on which the atomic operations are done. Size imageSize.
1939 	const glu::Texture			returnValueTexture		(renderCtx); //!< Texture into which the return values are stored if m_caseType == CASETYPE_RETURN_VALUES.
1940 																	 //	  Size imageSize*IVec3(N, 1, 1) or, for cube maps, imageSize*IVec3(N, N, 1) where N is NUM_INVOCATIONS_PER_PIXEL.
1941 
1942 	glLog.enableLogging(true);
1943 
1944 	// Setup textures.
1945 
1946 	log << TestLog::Message << "// Created a texture (name " << *endResultTexture << ") to act as the target of atomic operations" << TestLog::EndMessage;
1947 	if (m_imageType == TEXTURETYPE_BUFFER)
1948 		log << TestLog::Message << "// Created a buffer for the texture (name " << *endResultTextureBuf << ")" << TestLog::EndMessage;
1949 
1950 	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
1951 	{
1952 		log << TestLog::Message << "// Created a texture (name " << *returnValueTexture << ") to which the intermediate return values of the atomic operation are stored" << TestLog::EndMessage;
1953 		if (m_imageType == TEXTURETYPE_BUFFER)
1954 			log << TestLog::Message << "// Created a buffer for the texture (name " << *returnValueTextureBuf << ")" << TestLog::EndMessage;
1955 	}
1956 
1957 	// Fill endResultTexture with initial pattern.
1958 
1959 	{
1960 		const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
1961 
1962 		{
1963 			const IVec4 initial(getOperationInitialValue(m_operation));
1964 
1965 			for (int z = 0; z < numSlicesOrFaces; z++)
1966 			for (int y = 0; y < imageSize.y(); y++)
1967 			for (int x = 0; x < imageSize.x(); x++)
1968 				imageData.setPixel(x, y, z, initial);
1969 		}
1970 
1971 		// Upload initial pattern to endResultTexture and bind to image.
1972 
1973 		glLog.glActiveTexture(GL_TEXTURE0);
1974 		glLog.glBindTexture(textureTargetGL, *endResultTexture);
1975 		setTexParameteri(glLog, textureTargetGL);
1976 
1977 		log << TestLog::Message << "// Filling end-result texture with initial pattern (initial value " << getOperationInitialValue(m_operation) << ")" << TestLog::EndMessage;
1978 
1979 		uploadTexture(glLog, imageData, *endResultTextureBuf);
1980 	}
1981 
1982 	glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
1983 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1984 
1985 	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
1986 	{
1987 		// Set storage for returnValueTexture and bind to image.
1988 
1989 		glLog.glActiveTexture(GL_TEXTURE1);
1990 		glLog.glBindTexture(textureTargetGL, *returnValueTexture);
1991 		setTexParameteri(glLog, textureTargetGL);
1992 
1993 		log << TestLog::Message << "// Setting storage of return-value texture" << TestLog::EndMessage;
1994 		setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize * (m_imageType == TEXTURETYPE_CUBE ? IVec3(NUM_INVOCATIONS_PER_PIXEL, NUM_INVOCATIONS_PER_PIXEL,	1)
1995 																											 : IVec3(NUM_INVOCATIONS_PER_PIXEL, 1,							1)),
1996 						  *returnValueTextureBuf);
1997 
1998 		glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
1999 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2000 	}
2001 
2002 	// Perform image stores in compute shader and finalize reference computation.
2003 
2004 	{
2005 		// Generate compute shader.
2006 
2007 		const string colorVecTypeName		= string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4";
2008 		const string atomicCoord			= m_imageType == TEXTURETYPE_BUFFER		? "gx % " + toString(imageSize.x())
2009 											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx % " + toString(imageSize.x()) + ", gy)"
2010 											: "ivec3(gx % " + toString(imageSize.x()) + ", gy, gz)";
2011 		const string invocationCoord		= m_imageType == TEXTURETYPE_BUFFER		? "gx"
2012 											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx, gy)"
2013 											: "ivec3(gx, gy, gz)";
2014 		const string atomicArgExpr			= (isUintFormat		? "uint"
2015 											 : isIntFormat		? ""
2016 											 : "float")
2017 												+ getAtomicFuncArgumentShaderStr(m_operation, "gx", "gy", "gz", IVec2(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y()));
2018 		const string atomicInvocation		= string() + getAtomicOperationShaderFuncName(m_operation) + "(u_results, " + atomicCoord + ", " + atomicArgExpr + ")";
2019 		const string shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
2020 		const string shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2021 		const std::string		glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
2022 
2023 		const glu::ShaderProgram program(renderCtx,
2024 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2025 														+ imageAtomicExtensionShaderRequires(renderCtx)
2026 														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2027 														"\n"
2028 														"precision highp " + shaderImageTypeStr + ";\n"
2029 														"\n"
2030 														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2031 														"layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_results;\n"
2032 														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
2033 															  "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_returnValues;\n"
2034 															: "") +
2035 														"\n"
2036 														"void main (void)\n"
2037 														"{\n"
2038 														"	int gx = int(gl_GlobalInvocationID.x);\n"
2039 														"	int gy = int(gl_GlobalInvocationID.y);\n"
2040 														"	int gz = int(gl_GlobalInvocationID.z);\n"
2041 														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
2042 															"	imageStore(u_returnValues, " + invocationCoord + ", " + colorVecTypeName + "(" + atomicInvocation + "));\n"
2043 														 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ?
2044 															"	" + atomicInvocation + ";\n"
2045 														 : DE_NULL) +
2046 														"}\n"));
2047 
2048 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2049 
2050 		log << program;
2051 
2052 		if (!program.isOk())
2053 		{
2054 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2055 			return STOP;
2056 		}
2057 
2058 		// Setup and dispatch.
2059 
2060 		glLog.glUseProgram(program.getProgram());
2061 
2062 		glLog.glDispatchCompute(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y(), numSlicesOrFaces);
2063 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2064 	}
2065 
2066 	// Read texture and check.
2067 
2068 	{
2069 		const deUint32								textureToCheckGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTexture
2070 																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTexture
2071 																		: (deUint32)-1;
2072 		const deUint32								textureToCheckBufGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTextureBuf
2073 																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTextureBuf
2074 																		: (deUint32)-1;
2075 
2076 		const IVec3									textureToCheckSize	= imageSize * IVec3(m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? 1 : NUM_INVOCATIONS_PER_PIXEL, 1, 1);
2077 		const UniquePtr<const ImageLayerVerifier>	verifier			(m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? new EndResultVerifier(m_operation, m_imageType)
2078 																	   : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES		? new ReturnValueVerifier(m_operation, m_imageType, imageSize.swizzle(0, 1))
2079 																	   : (ImageLayerVerifier*)DE_NULL);
2080 
2081 		if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, textureToCheckSize, *verifier))
2082 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2083 		else
2084 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
2085 
2086 		return STOP;
2087 	}
2088 }
2089 
2090 /*--------------------------------------------------------------------*//*!
2091  * \brief Atomic compSwap operation case.
2092  *
2093  * Similar in principle to BinaryAtomicOperationCase, but separated for
2094  * convenience, since the atomic function is somewhat different. Like
2095  * BinaryAtomicOperationCase, this has separate cases for checking end
2096  * result and return values.
2097  *//*--------------------------------------------------------------------*/
2098 class AtomicCompSwapCase : public TestCase
2099 {
2100 public:
AtomicCompSwapCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,AtomicOperationCaseType caseType)2101 									AtomicCompSwapCase		(Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, AtomicOperationCaseType caseType)
2102 		: TestCase		(context, name, description)
2103 		, m_format		(format)
2104 		, m_imageType	(imageType)
2105 		, m_caseType	(caseType)
2106 	{
2107 		DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32)	||
2108 				  m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32));
2109 	}
2110 
2111 	void							init					(void);
2112 	IterateResult					iterate					(void);
2113 
2114 private:
2115 	class EndResultVerifier;
2116 	class ReturnValueVerifier;
2117 
2118 	static int						getCompareArg			(const IVec3& invocationID, int imageWidth);
2119 	static int						getAssignArg			(const IVec3& invocationID, int imageWidth);
2120 	static string					getCompareArgShaderStr	(const string& x, const string& y, const string& z, int imageWidth);
2121 	static string					getAssignArgShaderStr	(const string& x, const string& y, const string& z, int imageWidth);
2122 
2123 	static const int				NUM_INVOCATIONS_PER_PIXEL = 5;
2124 
2125 	const TextureFormat				m_format;
2126 	const TextureType				m_imageType;
2127 	const AtomicOperationCaseType	m_caseType;
2128 };
2129 
getCompareArg(const IVec3 & invocationID,int imageWidth)2130 int AtomicCompSwapCase::getCompareArg (const IVec3& invocationID, int imageWidth)
2131 {
2132 	const int x							= invocationID.x();
2133 	const int y							= invocationID.y();
2134 	const int z							= invocationID.z();
2135 	const int wrapX						= x % imageWidth;
2136 	const int curPixelInvocationNdx		= x / imageWidth;
2137 
2138 	return wrapX*wrapX + y*y + z*z + curPixelInvocationNdx*42;
2139 }
2140 
getAssignArg(const IVec3 & invocationID,int imageWidth)2141 int AtomicCompSwapCase::getAssignArg (const IVec3& invocationID, int imageWidth)
2142 {
2143 	return getCompareArg(IVec3(invocationID.x() + imageWidth, invocationID.y(), invocationID.z()), imageWidth);
2144 }
2145 
getCompareArgShaderStr(const string & x,const string & y,const string & z,int imageWidth)2146 string AtomicCompSwapCase::getCompareArgShaderStr (const string& x, const string& y, const string& z, int imageWidth)
2147 {
2148 	const string wrapX					= "(" + x + "%" + toString(imageWidth) + ")";
2149 	const string curPixelInvocationNdx	= "(" + x + "/" + toString(imageWidth) + ")";
2150 
2151 	return "(" +wrapX+"*"+wrapX+ " + " +y+"*"+y+ " + " +z+"*"+z+ " + " + curPixelInvocationNdx + "*42)";
2152 }
2153 
getAssignArgShaderStr(const string & x,const string & y,const string & z,int imageWidth)2154 string AtomicCompSwapCase::getAssignArgShaderStr (const string& x, const string& y, const string& z, int imageWidth)
2155 {
2156 	const string wrapX					= "(" + x + "%" + toString(imageWidth) + ")";
2157 	const string curPixelInvocationNdx	= "(" + x + "/" + toString(imageWidth) + " + 1)";
2158 
2159 	return "(" +wrapX+"*"+wrapX+ " + " +y+"*"+y+ " + " +z+"*"+z+ " + " + curPixelInvocationNdx + "*42)";
2160 }
2161 
init(void)2162 void AtomicCompSwapCase::init (void)
2163 {
2164 	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
2165 		throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension");
2166 
2167 	checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext());
2168 }
2169 
2170 class AtomicCompSwapCase::EndResultVerifier : public ImageLayerVerifier
2171 {
2172 public:
EndResultVerifier(TextureType imageType,int imageWidth)2173 	EndResultVerifier (TextureType imageType, int imageWidth) : m_imageType(imageType), m_imageWidth(imageWidth) {}
2174 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const2175 	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
2176 	{
2177 		DE_ASSERT(isFormatTypeInteger(resultSlice.getFormat().type));
2178 		DE_ASSERT(resultSlice.getWidth() == m_imageWidth);
2179 
2180 		log << TestLog::Image("EndResults" + toString(sliceOrFaceNdx),
2181 							  "Result Values, " + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
2182 																				   : "slice " + toString(sliceOrFaceNdx)),
2183 							  resultSlice);
2184 
2185 		for (int y = 0; y < resultSlice.getHeight(); y++)
2186 		for (int x = 0; x < resultSlice.getWidth(); x++)
2187 		{
2188 			// Compute the value-to-assign arguments that were given to the atomic function in the invocations that contribute to this pixel.
2189 			// One of those should be the result.
2190 
2191 			const int	result = resultSlice.getPixelInt(x, y).x();
2192 			IVec3		invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
2193 			int			assignArgs[NUM_INVOCATIONS_PER_PIXEL];
2194 
2195 			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
2196 			{
2197 				const IVec3 gid(x + i*resultSlice.getWidth(), y, sliceOrFaceNdx);
2198 
2199 				invocationGlobalIDs[i]	= gid;
2200 				assignArgs[i]			= getAssignArg(gid, m_imageWidth);
2201 			}
2202 
2203 			{
2204 				bool matchFound = false;
2205 				for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL && !matchFound; i++)
2206 					matchFound = result == assignArgs[i];
2207 
2208 				if (!matchFound)
2209 				{
2210 					log << TestLog::Message << "// Failure: invalid value at pixel " << IVec2(x, y) << ": got " << result << TestLog::EndMessage
2211 						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
2212 						<< TestLog::Message << "// Note: expected one of " << arrayStr(assignArgs)
2213 											<< " (those are the values given as the 'data' argument in the invocations that contribute to this pixel)"
2214 											<< TestLog::EndMessage;
2215 					return false;
2216 				}
2217 			}
2218 		}
2219 
2220 		return true;
2221 	}
2222 
2223 private:
2224 	const TextureType	m_imageType;
2225 	const int			m_imageWidth;
2226 };
2227 
2228 class AtomicCompSwapCase::ReturnValueVerifier : public ImageLayerVerifier
2229 {
2230 public:
2231 	//! \note endResultImageLayerSize is (width, height) of the image operated on by the atomic ops, and not the size of the image where the return values are stored.
ReturnValueVerifier(TextureType imageType,int endResultImageWidth)2232 	ReturnValueVerifier (TextureType imageType, int endResultImageWidth) : m_imageType(imageType), m_endResultImageWidth(endResultImageWidth) {}
2233 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const2234 	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
2235 	{
2236 		DE_ASSERT(isFormatTypeInteger(resultSlice.getFormat().type));
2237 		DE_ASSERT(resultSlice.getWidth() == NUM_INVOCATIONS_PER_PIXEL*m_endResultImageWidth);
2238 
2239 		log << TestLog::Image("ReturnValues" + toString(sliceOrFaceNdx),
2240 							  "Per-Invocation Return Values, "
2241 								   + (m_imageType == TEXTURETYPE_CUBE ? "face " + string(glu::getCubeMapFaceName(cubeFaceToGLFace(glslImageFuncZToCubeFace(sliceOrFaceNdx))))
2242 																	  : "slice " + toString(sliceOrFaceNdx)),
2243 							  resultSlice);
2244 
2245 		for (int y = 0; y < resultSlice.getHeight(); y++)
2246 		for (int x = 0; x < m_endResultImageWidth; x++)
2247 		{
2248 			// Get the atomic function args and return values for all the invocations that contribute to the pixel (x, y) in the current end result slice.
2249 
2250 			int		returnValues[NUM_INVOCATIONS_PER_PIXEL];
2251 			int		compareArgs[NUM_INVOCATIONS_PER_PIXEL];
2252 			IVec3	invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
2253 			IVec2	pixelCoords[NUM_INVOCATIONS_PER_PIXEL];
2254 
2255 			for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
2256 			{
2257 				const IVec2 pixCoord	(x + i*m_endResultImageWidth, y);
2258 				const IVec3 gid			(pixCoord.x(), pixCoord.y(), sliceOrFaceNdx);
2259 
2260 				pixelCoords[i]			= pixCoord;
2261 				invocationGlobalIDs[i]	= gid;
2262 				returnValues[i]			= resultSlice.getPixelInt(gid.x(), y).x();
2263 				compareArgs[i]			= getCompareArg(gid, m_endResultImageWidth);
2264 			}
2265 
2266 			// Verify that the return values form a valid sequence.
2267 			// Due to the way the compare and assign arguments to the atomic calls are organized
2268 			// among the different invocations contributing to the same pixel -- i.e. one invocation
2269 			// compares to A and assigns B, another compares to B and assigns C, and so on, where
2270 			// A<B<C etc -- the first value in the return value sequence must be A, and each following
2271 			// value must be either the same as or the smallest value (among A, B, C, ...) bigger than
2272 			// the one just before it. E.g. sequences A A A A A A A A, A B C D E F G H and
2273 			// A A B B B C D E are all valid sequences (if there were 8 invocations contributing
2274 			// to each pixel).
2275 
2276 			{
2277 				int failingNdx = -1;
2278 
2279 				{
2280 					int currentAtomicValueNdx = 0;
2281 					for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
2282 					{
2283 						if (returnValues[i] == compareArgs[currentAtomicValueNdx])
2284 							continue;
2285 						if (i > 0 && returnValues[i] == compareArgs[currentAtomicValueNdx+1])
2286 						{
2287 							currentAtomicValueNdx++;
2288 							continue;
2289 						}
2290 						failingNdx = i;
2291 						break;
2292 					}
2293 				}
2294 
2295 				if (failingNdx >= 0)
2296 				{
2297 					log << TestLog::Message << "// Failure: intermediate return values at pixels " << arrayStr(pixelCoords) << " of current layer are "
2298 											<< arrayStr(returnValues) << TestLog::EndMessage
2299 						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
2300 						<< TestLog::Message << "// Note: 'compare' argument values for the IDs are " << arrayStr(compareArgs) << TestLog::EndMessage
2301 						<< TestLog::Message << "// Note: expected the return value sequence to fulfill the following conditions:\n"
2302 											<< "// - first value is " << compareArgs[0] << "\n"
2303 											<< "// - each value other than the first is either the same as the one just before it, or the smallest value (in the sequence "
2304 											<< arrayStr(compareArgs) << ") bigger than the one just before it" << TestLog::EndMessage;
2305 					if (failingNdx == 0)
2306 						log << TestLog::Message << "// Note: the first return value (" << returnValues[0] << ") isn't " << compareArgs[0] << TestLog::EndMessage;
2307 					else
2308 						log << TestLog::Message << "// Note: the return value at index " << failingNdx << " (value " << returnValues[failingNdx] << ") "
2309 												<< "is neither " << returnValues[failingNdx-1] << " (the one just before it) "
2310 												<< "nor " << compareArgs[arrayIndexOf(compareArgs, returnValues[failingNdx-1])+1] << " (the smallest value bigger than the one just before it)"
2311 												<< TestLog::EndMessage;
2312 
2313 					return false;
2314 				}
2315 			}
2316 		}
2317 
2318 		return true;
2319 	}
2320 
2321 private:
2322 	const TextureType	m_imageType;
2323 	const int			m_endResultImageWidth;
2324 };
2325 
iterate(void)2326 AtomicCompSwapCase::IterateResult AtomicCompSwapCase::iterate (void)
2327 {
2328 	const RenderContext&		renderCtx				= m_context.getRenderContext();
2329 	TestLog&					log						(m_testCtx.getLog());
2330 	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
2331 	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
2332 	const deUint32				textureTargetGL			= getGLTextureTarget(m_imageType);
2333 	const IVec3&				imageSize				= defaultImageSize(m_imageType);
2334 	const int					numSlicesOrFaces		= m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
2335 	const bool					isUintFormat			= isFormatTypeUnsignedInteger(m_format.type);
2336 	const bool					isIntFormat				= isFormatTypeSignedInteger(m_format.type);
2337 	const glu::Buffer			endResultTextureBuf		(renderCtx);
2338 	const glu::Buffer			returnValueTextureBuf	(renderCtx);
2339 	const glu::Texture			endResultTexture		(renderCtx); //!< Texture for the final result; i.e. the texture on which the atomic operations are done. Size imageSize.
2340 	const glu::Texture			returnValueTexture		(renderCtx); //!< Texture into which the return values are stored if m_caseType == CASETYPE_RETURN_VALUES.
2341 																	 //	  Size imageSize*IVec3(N, 1, 1) or, for cube maps, imageSize*IVec3(N, N, 1) where N is NUM_INVOCATIONS_PER_PIXEL.
2342 
2343 	DE_ASSERT(isUintFormat || isIntFormat);
2344 
2345 	glLog.enableLogging(true);
2346 
2347 	// Setup textures.
2348 
2349 	log << TestLog::Message << "// Created a texture (name " << *endResultTexture << ") to act as the target of atomic operations" << TestLog::EndMessage;
2350 	if (m_imageType == TEXTURETYPE_BUFFER)
2351 		log << TestLog::Message << "// Created a buffer for the texture (name " << *endResultTextureBuf << ")" << TestLog::EndMessage;
2352 
2353 	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
2354 	{
2355 		log << TestLog::Message << "// Created a texture (name " << *returnValueTexture << ") to which the intermediate return values of the atomic operation are stored" << TestLog::EndMessage;
2356 		if (m_imageType == TEXTURETYPE_BUFFER)
2357 			log << TestLog::Message << "// Created a buffer for the texture (name " << *returnValueTextureBuf << ")" << TestLog::EndMessage;
2358 	}
2359 
2360 	// Fill endResultTexture with initial pattern.
2361 
2362 	{
2363 		const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
2364 
2365 		{
2366 			for (int z = 0; z < numSlicesOrFaces; z++)
2367 			for (int y = 0; y < imageSize.y(); y++)
2368 			for (int x = 0; x < imageSize.x(); x++)
2369 				imageData.setPixel(x, y, z, IVec4(getCompareArg(IVec3(x, y, z), imageSize.x())));
2370 		}
2371 
2372 		// Upload initial pattern to endResultTexture and bind to image.
2373 
2374 		glLog.glActiveTexture(GL_TEXTURE0);
2375 		glLog.glBindTexture(textureTargetGL, *endResultTexture);
2376 		setTexParameteri(glLog, textureTargetGL);
2377 
2378 		log << TestLog::Message << "// Filling end-result texture with initial pattern" << TestLog::EndMessage;
2379 
2380 		uploadTexture(glLog, imageData, *endResultTextureBuf);
2381 	}
2382 
2383 	glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
2384 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2385 
2386 	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
2387 	{
2388 		// Set storage for returnValueTexture and bind to image.
2389 
2390 		glLog.glActiveTexture(GL_TEXTURE1);
2391 		glLog.glBindTexture(textureTargetGL, *returnValueTexture);
2392 		setTexParameteri(glLog, textureTargetGL);
2393 
2394 		log << TestLog::Message << "// Setting storage of return-value texture" << TestLog::EndMessage;
2395 		setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize * (m_imageType == TEXTURETYPE_CUBE ? IVec3(NUM_INVOCATIONS_PER_PIXEL, NUM_INVOCATIONS_PER_PIXEL,	1)
2396 																											 : IVec3(NUM_INVOCATIONS_PER_PIXEL, 1,							1)),
2397 						  *returnValueTextureBuf);
2398 
2399 		glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
2400 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2401 	}
2402 
2403 	// Perform atomics in compute shader.
2404 
2405 	{
2406 		// Generate compute shader.
2407 
2408 		const string colorScalarTypeName	= isUintFormat ? "uint" : isIntFormat ? "int" : DE_NULL;
2409 		const string colorVecTypeName		= string(isUintFormat ? "u" : isIntFormat ? "i" : DE_NULL) + "vec4";
2410 		const string atomicCoord			= m_imageType == TEXTURETYPE_BUFFER		? "gx % " + toString(imageSize.x())
2411 											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx % " + toString(imageSize.x()) + ", gy)"
2412 											: "ivec3(gx % " + toString(imageSize.x()) + ", gy, gz)";
2413 		const string invocationCoord		= m_imageType == TEXTURETYPE_BUFFER		? "gx"
2414 											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx, gy)"
2415 											: "ivec3(gx, gy, gz)";
2416 		const string shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
2417 		const string shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2418 		const string glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
2419 
2420 		const glu::ShaderProgram program(renderCtx,
2421 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2422 														+ imageAtomicExtensionShaderRequires(renderCtx)
2423 														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2424 														"\n"
2425 														"precision highp " + shaderImageTypeStr + ";\n"
2426 														"\n"
2427 														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2428 														"layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_results;\n"
2429 														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
2430 															  "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_returnValues;\n"
2431 															: "") +
2432 														"\n"
2433 														"void main (void)\n"
2434 														"{\n"
2435 														"	int gx = int(gl_GlobalInvocationID.x);\n"
2436 														"	int gy = int(gl_GlobalInvocationID.y);\n"
2437 														"	int gz = int(gl_GlobalInvocationID.z);\n"
2438 														"	" + colorScalarTypeName + " compare = " + colorScalarTypeName + getCompareArgShaderStr("gx", "gy", "gz", imageSize.x()) + ";\n"
2439 														"	" + colorScalarTypeName + " data    = " + colorScalarTypeName + getAssignArgShaderStr("gx", "gy", "gz", imageSize.x()) + ";\n"
2440 														"	" + colorScalarTypeName + " status  = " + colorScalarTypeName + "(-1);\n"
2441 														"	status = imageAtomicCompSwap(u_results, " + atomicCoord + ", compare, data);\n"
2442 														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
2443 															"	imageStore(u_returnValues, " + invocationCoord + ", " + colorVecTypeName + "(status));\n" :
2444 															"") +
2445 														"}\n"));
2446 
2447 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2448 
2449 		log << program;
2450 
2451 		if (!program.isOk())
2452 		{
2453 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2454 			return STOP;
2455 		}
2456 
2457 		// Setup and dispatch.
2458 
2459 		glLog.glUseProgram(program.getProgram());
2460 
2461 		glLog.glDispatchCompute(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y(), numSlicesOrFaces);
2462 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2463 	}
2464 
2465 	// Create reference, read texture and compare.
2466 
2467 	{
2468 		const deUint32								textureToCheckGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTexture
2469 																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTexture
2470 																		: (deUint32)-1;
2471 
2472 		const deUint32								textureToCheckBufGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTextureBuf
2473 																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTextureBuf
2474 																		: (deUint32)-1;
2475 
2476 		// The relevant region of the texture being checked (potentially
2477 		// different from actual texture size for cube maps, because cube maps
2478 		// may have unused pixels due to square size restriction).
2479 		const IVec3									relevantRegion		= imageSize * (m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT	? IVec3(1,							1,							1)
2480 																					 :														  IVec3(NUM_INVOCATIONS_PER_PIXEL,	1,							1));
2481 
2482 		const UniquePtr<const ImageLayerVerifier>	verifier			(m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? new EndResultVerifier(m_imageType, imageSize.x())
2483 																	   : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES		? new ReturnValueVerifier(m_imageType, imageSize.x())
2484 																	   : (ImageLayerVerifier*)DE_NULL);
2485 
2486 		if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, relevantRegion, *verifier))
2487 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2488 		else
2489 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
2490 
2491 		return STOP;
2492 	}
2493 }
2494 
2495 //! Case testing the "coherent" or "volatile" qualifier, along with memoryBarrier() and barrier().
2496 class CoherenceCase : public TestCase
2497 {
2498 public:
2499 	enum Qualifier
2500 	{
2501 		QUALIFIER_COHERENT = 0,
2502 		QUALIFIER_VOLATILE,
2503 
2504 		QUALIFIER_LAST
2505 	};
2506 
CoherenceCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,Qualifier qualifier)2507 	CoherenceCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, Qualifier qualifier)
2508 		: TestCase		(context, name, description)
2509 		, m_format		(format)
2510 		, m_imageType	(imageType)
2511 		, m_qualifier	(qualifier)
2512 	{
2513 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_Y) == DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_X) &&
2514 						 DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_Z) == DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_X));
2515 
2516 		DE_ASSERT(qualifier == QUALIFIER_COHERENT || qualifier == QUALIFIER_VOLATILE);
2517 
2518 		DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32)	||
2519 				  m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32)		||
2520 				  m_format == TextureFormat(TextureFormat::R, TextureFormat::FLOAT));
2521 	}
2522 
init(void)2523 	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext()); }
2524 	IterateResult	iterate		(void);
2525 
2526 private:
2527 	static const int			SHADER_READ_OFFSETS_X[4];
2528 	static const int			SHADER_READ_OFFSETS_Y[4];
2529 	static const int			SHADER_READ_OFFSETS_Z[4];
2530 	static const char* const	SHADER_READ_OFFSETS_X_STR;
2531 	static const char* const	SHADER_READ_OFFSETS_Y_STR;
2532 	static const char* const	SHADER_READ_OFFSETS_Z_STR;
2533 
2534 	const TextureFormat		m_format;
2535 	const TextureType		m_imageType;
2536 	const Qualifier			m_qualifier;
2537 };
2538 
2539 const int			CoherenceCase::SHADER_READ_OFFSETS_X[4]		=		{ 1, 4, 7, 10 };
2540 const int			CoherenceCase::SHADER_READ_OFFSETS_Y[4]		=		{ 2, 5, 8, 11 };
2541 const int			CoherenceCase::SHADER_READ_OFFSETS_Z[4]		=		{ 3, 6, 9, 12 };
2542 const char* const	CoherenceCase::SHADER_READ_OFFSETS_X_STR	= "int[]( 1, 4, 7, 10 )";
2543 const char* const	CoherenceCase::SHADER_READ_OFFSETS_Y_STR	= "int[]( 2, 5, 8, 11 )";
2544 const char* const	CoherenceCase::SHADER_READ_OFFSETS_Z_STR	= "int[]( 3, 6, 9, 12 )";
2545 
iterate(void)2546 CoherenceCase::IterateResult CoherenceCase::iterate (void)
2547 {
2548 	const RenderContext&		renderCtx					= m_context.getRenderContext();
2549 	TestLog&					log							(m_testCtx.getLog());
2550 	glu::CallLogWrapper			glLog						(renderCtx.getFunctions(), log);
2551 	const deUint32				internalFormatGL			= glu::getInternalFormat(m_format);
2552 	const deUint32				textureTargetGL				= getGLTextureTarget(m_imageType);
2553 	const IVec3&				imageSize					= defaultImageSize(m_imageType);
2554 	const int					numSlicesOrFaces			= m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
2555 	const bool					isUintFormat				= isFormatTypeUnsignedInteger(m_format.type);
2556 	const bool					isIntFormat					= isFormatTypeSignedInteger(m_format.type);
2557 	const char* const			qualifierName				= m_qualifier == QUALIFIER_COHERENT ? "coherent"
2558 															: m_qualifier == QUALIFIER_VOLATILE ? "volatile"
2559 															: DE_NULL;
2560 	const glu::Buffer			textureBuf					(renderCtx);
2561 	const glu::Texture			texture						(renderCtx);
2562 	const IVec3					numGroups					= IVec3(16, de::min(16, imageSize.y()), de::min(2, numSlicesOrFaces));
2563 	const IVec3					workItemSize				= IVec3(imageSize.x(), imageSize.y(), numSlicesOrFaces);
2564 	const IVec3					localSize					= workItemSize / numGroups;
2565 	const IVec3					minReqMaxLocalSize			= IVec3(128, 128, 64);
2566 	const int					minReqMaxLocalInvocations	= 128;
2567 
2568 	DE_ASSERT(workItemSize == localSize*numGroups);
2569 	DE_ASSERT(tcu::boolAll(tcu::lessThanEqual(localSize, minReqMaxLocalSize)));
2570 	DE_ASSERT(localSize.x()*localSize.y()*localSize.z() <= minReqMaxLocalInvocations);
2571 	DE_UNREF(minReqMaxLocalSize);
2572 	DE_UNREF(minReqMaxLocalInvocations);
2573 
2574 	glLog.enableLogging(true);
2575 
2576 	// Setup texture.
2577 
2578 	log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
2579 	if (m_imageType == TEXTURETYPE_BUFFER)
2580 		log << TestLog::Message << "// Created a buffer for the texture (name " << *textureBuf << ")" << TestLog::EndMessage;
2581 
2582 	glLog.glActiveTexture(GL_TEXTURE0);
2583 	glLog.glBindTexture(textureTargetGL, *texture);
2584 	setTexParameteri(glLog, textureTargetGL);
2585 	setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize, *textureBuf);
2586 	glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
2587 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2588 
2589 	// Perform computations in compute shader.
2590 
2591 	{
2592 		// Generate compute shader.
2593 
2594 		const string		colorVecTypeName		= string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4";
2595 		const char* const	colorScalarTypeName		= isUintFormat ? "uint" : isIntFormat ? "int" : "float";
2596 		const string		invocationCoord			= m_imageType == TEXTURETYPE_BUFFER		? "gx"
2597 													: m_imageType == TEXTURETYPE_2D			? "ivec2(gx, gy)"
2598 													: "ivec3(gx, gy, gz)";
2599 		const string		shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
2600 		const string		shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2601 		const string		localSizeX				= de::toString(localSize.x());
2602 		const string		localSizeY				= de::toString(localSize.y());
2603 		const string		localSizeZ				= de::toString(localSize.z());
2604 		const std::string	glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
2605 
2606 
2607 		const glu::ShaderProgram program(renderCtx,
2608 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2609 														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2610 														"\n"
2611 														"precision highp " + shaderImageTypeStr + ";\n"
2612 														"\n"
2613 														"layout (local_size_x = " + localSizeX
2614 															+ ", local_size_y = " + localSizeY
2615 															+ ", local_size_z = " + localSizeZ
2616 															+ ") in;\n"
2617 														"layout (" + shaderImageFormatStr + ", binding=0) " + qualifierName + " uniform " + shaderImageTypeStr + " u_image;\n"
2618 														"void main (void)\n"
2619 														"{\n"
2620 														"	int gx = int(gl_GlobalInvocationID.x);\n"
2621 														"	int gy = int(gl_GlobalInvocationID.y);\n"
2622 														"	int gz = int(gl_GlobalInvocationID.z);\n"
2623 														"	imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(gx^gy^gz));\n"
2624 														"\n"
2625 														"	memoryBarrier();\n"
2626 														"	barrier();\n"
2627 														"\n"
2628 														"	" + colorScalarTypeName + " sum = " + colorScalarTypeName + "(0);\n"
2629 														"	int groupBaseX = gx/" + localSizeX + "*" + localSizeX + ";\n"
2630 														"	int groupBaseY = gy/" + localSizeY + "*" + localSizeY + ";\n"
2631 														"	int groupBaseZ = gz/" + localSizeZ + "*" + localSizeZ + ";\n"
2632 														"	int xOffsets[] = " + SHADER_READ_OFFSETS_X_STR + ";\n"
2633 														"	int yOffsets[] = " + SHADER_READ_OFFSETS_Y_STR + ";\n"
2634 														"	int zOffsets[] = " + SHADER_READ_OFFSETS_Z_STR + ";\n"
2635 														"	for (int i = 0; i < " + toString(DE_LENGTH_OF_ARRAY(SHADER_READ_OFFSETS_X)) + "; i++)\n"
2636 														"	{\n"
2637 														"		int readX = groupBaseX + (gx + xOffsets[i]) % " + localSizeX + ";\n"
2638 														"		int readY = groupBaseY + (gy + yOffsets[i]) % " + localSizeY + ";\n"
2639 														"		int readZ = groupBaseZ + (gz + zOffsets[i]) % " + localSizeZ + ";\n"
2640 														"		sum += imageLoad(u_image, " + (m_imageType == TEXTURETYPE_BUFFER	? "readX"
2641 																							 : m_imageType == TEXTURETYPE_2D		? "ivec2(readX, readY)"
2642 																							 : "ivec3(readX, readY, readZ)") + ").x;\n"
2643 														"	}\n"
2644 														"\n"
2645 														"	memoryBarrier();\n"
2646 														"	barrier();\n"
2647 														"\n"
2648 														"	imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(sum));\n"
2649 														"}\n"));
2650 
2651 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2652 
2653 		log << program;
2654 
2655 		if (!program.isOk())
2656 		{
2657 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2658 			return STOP;
2659 		}
2660 
2661 		// Setup and dispatch.
2662 
2663 		glLog.glUseProgram(program.getProgram());
2664 
2665 		glLog.glDispatchCompute(numGroups.x(), numGroups.y(), numGroups.z());
2666 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2667 	}
2668 
2669 	// Create reference, read texture and compare.
2670 
2671 	{
2672 		LayeredImage reference(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
2673 
2674 		{
2675 			LayeredImage base(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
2676 			for (int z = 0; z < numSlicesOrFaces; z++)
2677 			for (int y = 0; y < imageSize.y(); y++)
2678 			for (int x = 0; x < imageSize.x(); x++)
2679 				base.setPixel(x, y, z, IVec4(x^y^z));
2680 
2681 			for (int z = 0; z < numSlicesOrFaces; z++)
2682 			for (int y = 0; y < imageSize.y(); y++)
2683 			for (int x = 0; x < imageSize.x(); x++)
2684 			{
2685 				const int	groupBaseX	= x / localSize.x() * localSize.x();
2686 				const int	groupBaseY	= y / localSize.y() * localSize.y();
2687 				const int	groupBaseZ	= z / localSize.z() * localSize.z();
2688 				int			sum			= 0;
2689 				for (int i = 0; i < DE_LENGTH_OF_ARRAY(SHADER_READ_OFFSETS_X); i++)
2690 					sum += base.getPixelInt(groupBaseX + (x + SHADER_READ_OFFSETS_X[i]) % localSize.x(),
2691 											groupBaseY + (y + SHADER_READ_OFFSETS_Y[i]) % localSize.y(),
2692 											groupBaseZ + (z + SHADER_READ_OFFSETS_Z[i]) % localSize.z()).x();
2693 
2694 				reference.setPixel(x, y, z, IVec4(sum));
2695 			}
2696 		}
2697 
2698 		if (readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_imageType, m_format, imageSize, ImageLayerComparer(reference)))
2699 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2700 		else
2701 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2702 
2703 		return STOP;
2704 	}
2705 }
2706 
2707 class R32UIImageSingleValueVerifier : public ImageLayerVerifier
2708 {
2709 public:
R32UIImageSingleValueVerifier(const deUint32 value)2710 	R32UIImageSingleValueVerifier (const deUint32 value)					: m_min(value),	m_max(value)	{}
R32UIImageSingleValueVerifier(const deUint32 min,const deUint32 max)2711 	R32UIImageSingleValueVerifier (const deUint32 min, const deUint32 max)	: m_min(min),	m_max(max)		{}
2712 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int) const2713 	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int) const
2714 	{
2715 		DE_ASSERT(resultSlice.getWidth() == 1 && resultSlice.getHeight() == 1 && resultSlice.getDepth() == 1);
2716 		DE_ASSERT(resultSlice.getFormat() == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32));
2717 
2718 		log << TestLog::Message << "// Note: expecting to get value " << (m_min == m_max ? toString(m_min) : "in range [" + toString(m_min) + ", " + toString(m_max) + "]") << TestLog::EndMessage;
2719 
2720 		const deUint32 resultValue = resultSlice.getPixelUint(0, 0).x();
2721 		if (!de::inRange(resultValue, m_min, m_max))
2722 		{
2723 			log << TestLog::Message << "// Failure: got value " << resultValue << TestLog::EndMessage;
2724 			return false;
2725 		}
2726 		else
2727 		{
2728 			log << TestLog::Message << "// Success: got value " << resultValue << TestLog::EndMessage;
2729 			return true;
2730 		}
2731 	}
2732 
2733 private:
2734 	const deUint32 m_min;
2735 	const deUint32 m_max;
2736 };
2737 
2738 //! Tests the imageSize() GLSL function. Stores result in a 1x1 R32UI image. The image with which imageSize() is called isn't read or written, and
2739 //  can thus be qualifier readonly, writeonly, or both.
2740 class ImageSizeCase : public TestCase
2741 {
2742 public:
2743 	enum ImageAccess
2744 	{
2745 		IMAGEACCESS_READ_ONLY = 0,
2746 		IMAGEACCESS_WRITE_ONLY,
2747 		IMAGEACCESS_READ_ONLY_WRITE_ONLY,
2748 
2749 		IMAGEACCESS_LAST
2750 	};
2751 
ImageSizeCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,const IVec3 & size,ImageAccess imageAccess)2752 	ImageSizeCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, const IVec3& size, ImageAccess imageAccess)
2753 		: TestCase			(context, name, description)
2754 		, m_format			(format)
2755 		, m_imageType		(imageType)
2756 		, m_imageSize		(size)
2757 		, m_imageAccess		(imageAccess)
2758 	{
2759 	}
2760 
init(void)2761 	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext()); }
2762 	IterateResult	iterate		(void);
2763 
2764 private:
2765 	const TextureFormat		m_format;
2766 	const TextureType		m_imageType;
2767 	const IVec3				m_imageSize;
2768 	const ImageAccess		m_imageAccess;
2769 };
2770 
iterate(void)2771 ImageSizeCase::IterateResult ImageSizeCase::iterate (void)
2772 {
2773 	const RenderContext&		renderCtx				= m_context.getRenderContext();
2774 	TestLog&					log						(m_testCtx.getLog());
2775 	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
2776 	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
2777 	const deUint32				textureTargetGL			= getGLTextureTarget(m_imageType);
2778 	const glu::Buffer			mainTextureBuf			(renderCtx);
2779 	const glu::Texture			mainTexture				(renderCtx);
2780 	const glu::Texture			shaderOutResultTexture	(renderCtx);
2781 
2782 	glLog.enableLogging(true);
2783 
2784 	// Setup textures.
2785 
2786 	log << TestLog::Message << "// Created a texture (name " << *mainTexture << ")" << TestLog::EndMessage;
2787 	if (m_imageType == TEXTURETYPE_BUFFER)
2788 		log << TestLog::Message << "// Created a buffer for the texture (name " << *mainTextureBuf << ")" << TestLog::EndMessage;
2789 	log << TestLog::Message << "// Created a texture (name " << *shaderOutResultTexture << ") for storing the shader output" << TestLog::EndMessage;
2790 
2791 	glLog.glActiveTexture(GL_TEXTURE0);
2792 	glLog.glBindTexture(textureTargetGL, *mainTexture);
2793 	setTexParameteri(glLog, textureTargetGL);
2794 	setTextureStorage(glLog, m_imageType, internalFormatGL, m_imageSize, *mainTextureBuf);
2795 	glLog.glBindImageTexture(0, *mainTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
2796 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2797 
2798 	glLog.glActiveTexture(GL_TEXTURE1);
2799 	glLog.glBindTexture(GL_TEXTURE_2D, *shaderOutResultTexture);
2800 	setTexParameteri(glLog, GL_TEXTURE_2D);
2801 	setTextureStorage(glLog, TEXTURETYPE_2D, GL_R32UI, IVec3(1, 1, 1), 0 /* always 2d texture, no buffer needed */);
2802 	glLog.glBindImageTexture(1, *shaderOutResultTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
2803 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2804 
2805 	// Read texture size in compute shader.
2806 
2807 	{
2808 		// Generate compute shader.
2809 
2810 		const char* const	shaderImageAccessStr	= m_imageAccess == IMAGEACCESS_READ_ONLY			? "readonly"
2811 													: m_imageAccess == IMAGEACCESS_WRITE_ONLY			? "writeonly"
2812 													: m_imageAccess == IMAGEACCESS_READ_ONLY_WRITE_ONLY	? "readonly writeonly"
2813 													: DE_NULL;
2814 		const string		shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
2815 		const string		shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2816 		const string		glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
2817 
2818 		const glu::ShaderProgram program(renderCtx,
2819 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2820 														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2821 														"\n"
2822 														"precision highp " + shaderImageTypeStr + ";\n"
2823 														"precision highp uimage2D;\n"
2824 														"\n"
2825 														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2826 														"layout (" + shaderImageFormatStr + ", binding=0) " + shaderImageAccessStr + " uniform " + shaderImageTypeStr + " u_image;\n"
2827 														"layout (r32ui, binding=1) writeonly uniform uimage2D u_result;\n"
2828 														"void main (void)\n"
2829 														"{\n"
2830 														+ (m_imageType == TEXTURETYPE_BUFFER ?
2831 															"	int result = imageSize(u_image);\n"
2832 														 : m_imageType == TEXTURETYPE_2D || m_imageType == TEXTURETYPE_CUBE ?
2833 															"	ivec2 size = imageSize(u_image);\n"
2834 															"	int result = size.y*1000 + size.x;\n"
2835 														 : m_imageType == TEXTURETYPE_3D || m_imageType == TEXTURETYPE_2D_ARRAY ?
2836 															"	ivec3 size = imageSize(u_image);\n"
2837 															"	int result = size.z*1000000 + size.y*1000 + size.x;\n"
2838 														 : DE_NULL) +
2839 														"	imageStore(u_result, ivec2(0, 0), uvec4(result));\n"
2840 														"}\n"));
2841 
2842 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2843 
2844 		log << program;
2845 
2846 		if (!program.isOk())
2847 		{
2848 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2849 			return STOP;
2850 		}
2851 
2852 		// Setup and dispatch.
2853 
2854 		glLog.glUseProgram(program.getProgram());
2855 
2856 		glLog.glDispatchCompute(1, 1, 1);
2857 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2858 	}
2859 
2860 	// Read texture and compare to reference.
2861 
2862 	{
2863 		const deUint32	referenceOutput		= m_imageType == TEXTURETYPE_BUFFER										? (deUint32)(												  m_imageSize.x())
2864 											: m_imageType == TEXTURETYPE_2D || m_imageType == TEXTURETYPE_CUBE		? (deUint32)(						   m_imageSize.y()*1000 + m_imageSize.x())
2865 											: m_imageType == TEXTURETYPE_3D || m_imageType == TEXTURETYPE_2D_ARRAY	? (deUint32)(m_imageSize.z()*1000000 + m_imageSize.y()*1000 + m_imageSize.x())
2866 											: (deUint32)-1;
2867 
2868 		if (readIntegerTextureViaFBOAndVerify(renderCtx, glLog, *shaderOutResultTexture, TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32),
2869 											  IVec3(1, 1, 1), R32UIImageSingleValueVerifier(referenceOutput)))
2870 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2871 		else
2872 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value");
2873 
2874 		return STOP;
2875 	}
2876 }
2877 
2878 //! Case testing the control over early/late fragment tests.
2879 class EarlyFragmentTestsCase : public TestCase
2880 {
2881 public:
2882 	enum TestType
2883 	{
2884 		TESTTYPE_DEPTH = 0,
2885 		TESTTYPE_STENCIL,
2886 
2887 		TESTTYPE_LAST
2888 	};
2889 
2890 	enum RenderTargetType
2891 	{
2892 		RENDERTARGET_DEFAULT = 0,
2893 		RENDERTARGET_FBO,
2894 		RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT,
2895 
2896 		RENDERTARGET_LAST
2897 	};
2898 
2899 
EarlyFragmentTestsCase(Context & context,const char * name,const char * description,TestType type,bool useEarlyTests,RenderTargetType renderTarget)2900 	EarlyFragmentTestsCase (Context& context, const char* name, const char* description, TestType type, bool useEarlyTests, RenderTargetType renderTarget)
2901 		: TestCase			(context, name, description)
2902 		, m_type			(type)
2903 		, m_useEarlyTests	(useEarlyTests)
2904 		, m_renderTarget	(renderTarget)
2905 	{
2906 	}
2907 
init(void)2908 	void init (void)
2909 	{
2910 		if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) == 0)
2911 			throw tcu::NotSupportedError("GL_MAX_FRAGMENT_IMAGE_UNIFORMS is zero");
2912 
2913 		if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
2914 			throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension");
2915 
2916 		if (m_type == TESTTYPE_DEPTH 				&&
2917 			m_renderTarget == RENDERTARGET_DEFAULT	&&
2918 			m_context.getRenderTarget().getDepthBits() == 0)
2919 		{
2920 			throw tcu::NotSupportedError("Test requires depth buffer");
2921 		}
2922 
2923 		if (m_type == TESTTYPE_STENCIL 				&&
2924 			m_renderTarget == RENDERTARGET_DEFAULT	&&
2925 			m_context.getRenderTarget().getStencilBits() == 0)
2926 		{
2927 			throw tcu::NotSupportedError("Test requires stencil buffer");
2928 		}
2929 
2930 		if (m_renderTarget == RENDERTARGET_DEFAULT	&&
2931 			(m_context.getRenderTarget().getWidth() < RENDER_SIZE || m_context.getRenderTarget().getHeight() < RENDER_SIZE))
2932 			throw tcu::NotSupportedError("Render target must have at least " + toString(RENDER_SIZE) + " width and height");
2933 	}
2934 
2935 	IterateResult iterate (void);
2936 
2937 private:
2938 	static const int 		RENDER_SIZE;
2939 
2940 	const TestType			m_type;
2941 	const bool				m_useEarlyTests;
2942 	const RenderTargetType 	m_renderTarget;
2943 };
2944 
2945 const int EarlyFragmentTestsCase::RENDER_SIZE = 32;
2946 
iterate(void)2947 EarlyFragmentTestsCase::IterateResult EarlyFragmentTestsCase::iterate (void)
2948 {
2949 	const RenderContext&			renderCtx			= m_context.getRenderContext();
2950 	TestLog&						log					(m_testCtx.getLog());
2951 	glu::CallLogWrapper				glLog				(renderCtx.getFunctions(), log);
2952 	de::Random						rnd					(deStringHash(getName()));
2953 	const bool						expectPartialResult	= m_useEarlyTests && m_renderTarget != RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT;
2954 	const int						viewportWidth		= RENDER_SIZE;
2955 	const int						viewportHeight		= RENDER_SIZE;
2956 	const int						viewportX			= (m_renderTarget == RENDERTARGET_DEFAULT) ? (rnd.getInt(0, renderCtx.getRenderTarget().getWidth() - viewportWidth))	: (0);
2957 	const int						viewportY			= (m_renderTarget == RENDERTARGET_DEFAULT) ? (rnd.getInt(0, renderCtx.getRenderTarget().getHeight() - viewportHeight))	: (0);
2958 	const glu::Texture				texture				(renderCtx);
2959 	de::MovePtr<glu::Framebuffer>	fbo;
2960 	de::MovePtr<glu::Renderbuffer> 	colorAttachment;
2961 	de::MovePtr<glu::Renderbuffer> 	testAttachment;
2962 
2963 	glLog.enableLogging(true);
2964 
2965 	// Setup texture.
2966 
2967 	log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
2968 
2969 	glLog.glActiveTexture(GL_TEXTURE0);
2970 	glLog.glBindTexture(GL_TEXTURE_2D, *texture);
2971 	setTexParameteri(glLog, GL_TEXTURE_2D);
2972 	{
2973 		LayeredImage src(TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32), 1, 1, 1);
2974 		src.setPixel(0, 0, 0, IVec4(0));
2975 		uploadTexture(glLog, src, 0 /* always 2d texture, no buffer needed */);
2976 	}
2977 	glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32UI);
2978 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2979 
2980 	// Set up framebuffer
2981 	if (m_renderTarget == RENDERTARGET_FBO ||
2982 		m_renderTarget == RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT)
2983 	{
2984 		fbo 			= de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(renderCtx));
2985 		colorAttachment	= de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx));
2986 		testAttachment	= de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx));
2987 
2988 		glLog.glBindRenderbuffer(GL_RENDERBUFFER, **colorAttachment);
2989 		glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE);
2990 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen color attachment rb");
2991 
2992 		glLog.glBindFramebuffer(GL_FRAMEBUFFER, **fbo);
2993 		glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **colorAttachment);
2994 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo color attachment");
2995 
2996 		if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_DEPTH)
2997 		{
2998 			glLog.glBindRenderbuffer(GL_RENDERBUFFER, **testAttachment);
2999 			glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, RENDER_SIZE, RENDER_SIZE);
3000 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen depth attachment rb");
3001 
3002 			glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, **testAttachment);
3003 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo depth attachment");
3004 		}
3005 		else if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_STENCIL)
3006 		{
3007 			glLog.glBindRenderbuffer(GL_RENDERBUFFER, **testAttachment);
3008 			glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, RENDER_SIZE, RENDER_SIZE);
3009 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen stencil attachment rb");
3010 
3011 			glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, **testAttachment);
3012 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo stencil attachment");
3013 		}
3014 
3015 		glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **colorAttachment);
3016 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "setup fbo");
3017 		TCU_CHECK(glLog.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
3018 	}
3019 
3020 	// Set up appropriate conditions for the test.
3021 
3022 	glLog.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
3023 	glLog.glClear(GL_COLOR_BUFFER_BIT);
3024 
3025 	if (m_type == TESTTYPE_DEPTH)
3026 	{
3027 		glLog.glClearDepthf(0.5f);
3028 		glLog.glClear(GL_DEPTH_BUFFER_BIT);
3029 		glLog.glEnable(GL_DEPTH_TEST);
3030 	}
3031 	else if (m_type == TESTTYPE_STENCIL)
3032 	{
3033 		glLog.glClearStencil(0);
3034 		glLog.glClear(GL_STENCIL_BUFFER_BIT);
3035 		glLog.glScissor(viewportX, viewportY, viewportWidth/2, viewportHeight);
3036 		glLog.glEnable(GL_SCISSOR_TEST);
3037 		glLog.glClearStencil(1);
3038 		glLog.glClear(GL_STENCIL_BUFFER_BIT);
3039 		glLog.glDisable(GL_SCISSOR_TEST);
3040 		glLog.glStencilFunc(GL_EQUAL, 1, 1);
3041 		glLog.glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3042 		glLog.glEnable(GL_STENCIL_TEST);
3043 	}
3044 	else
3045 		DE_ASSERT(false);
3046 
3047 	// Perform image stores in fragment shader.
3048 
3049 	{
3050 		const std::string glslVersionDeclaration = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
3051 
3052 		// Generate fragment shader.
3053 
3054 		const glu::ShaderProgram program(renderCtx,
3055 			glu::ProgramSources() << glu::VertexSource(		glslVersionDeclaration + "\n"
3056 															"\n"
3057 															"highp in vec3 a_position;\n"
3058 															"\n"
3059 															"void main (void)\n"
3060 															"{\n"
3061 															"	gl_Position = vec4(a_position, 1.0);\n"
3062 															"}\n")
3063 
3064 								  << glu::FragmentSource(	glslVersionDeclaration + "\n"
3065 															+ imageAtomicExtensionShaderRequires(renderCtx) +
3066 															"\n"
3067 															+ string(m_useEarlyTests ? "layout (early_fragment_tests) in;\n\n" : "") +
3068 															"layout (location = 0) out highp vec4 o_color;\n"
3069 															"\n"
3070 															"precision highp uimage2D;\n"
3071 															"\n"
3072 															"layout (r32ui, binding=0) coherent uniform uimage2D u_image;\n"
3073 															"\n"
3074 															"void main (void)\n"
3075 															"{\n"
3076 															"	imageAtomicAdd(u_image, ivec2(0, 0), uint(1));\n"
3077 															"	o_color = vec4(1.0);\n"
3078 															"}\n"));
3079 
3080 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
3081 
3082 		log << program;
3083 
3084 		if (!program.isOk())
3085 		{
3086 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
3087 			return STOP;
3088 		}
3089 
3090 		// Setup and draw full-viewport quad.
3091 
3092 		glLog.glUseProgram(program.getProgram());
3093 
3094 		{
3095 			static const float vertexPositions[4*3] =
3096 			{
3097 				-1.0, -1.0, -1.0f,
3098 				 1.0, -1.0,  0.0f,
3099 				-1.0,  1.0,  0.0f,
3100 				 1.0,  1.0,  1.0f,
3101 			};
3102 
3103 			static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 };
3104 
3105 			const glu::VertexArrayBinding attrBindings[] =
3106 			{
3107 				glu::va::Float("a_position", 3, 4, 0, &vertexPositions[0])
3108 			};
3109 
3110 			glLog.glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
3111 
3112 			glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3113 				glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
3114 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Draw failed");
3115 		}
3116 	}
3117 
3118 	// Log rendered result for convenience.
3119 	{
3120 		tcu::Surface rendered(viewportWidth, viewportHeight);
3121 		glu::readPixels(renderCtx, viewportX, viewportY, rendered.getAccess());
3122 		log << TestLog::Image("Rendered", "Rendered image", rendered);
3123 	}
3124 
3125 	// Read counter value and check.
3126 	{
3127 		const int numSamples		= de::max(1, renderCtx.getRenderTarget().getNumSamples());
3128 		const int expectedCounter	= expectPartialResult ? viewportWidth*viewportHeight/2				: viewportWidth*viewportHeight;
3129 		const int tolerance			= expectPartialResult ? de::max(viewportWidth, viewportHeight)*3	: 0;
3130 		const int expectedMin		= de::max(0, expectedCounter - tolerance);
3131 		const int expectedMax		= (expectedCounter + tolerance) * numSamples;
3132 
3133 		if (readIntegerTextureViaFBOAndVerify(renderCtx, glLog, *texture, TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32),
3134 											  IVec3(1, 1, 1), R32UIImageSingleValueVerifier(expectedMin, expectedMax)))
3135 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3136 		else
3137 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value");
3138 
3139 		return STOP;
3140 	}
3141 }
3142 
3143 } // anonymous
3144 
ShaderImageLoadStoreTests(Context & context)3145 ShaderImageLoadStoreTests::ShaderImageLoadStoreTests (Context& context)
3146 	: TestCaseGroup(context, "image_load_store", "Shader Image Load & Store Tests")
3147 {
3148 }
3149 
~ShaderImageLoadStoreTests(void)3150 ShaderImageLoadStoreTests::~ShaderImageLoadStoreTests (void)
3151 {
3152 }
3153 
init(void)3154 void ShaderImageLoadStoreTests::init (void)
3155 {
3156 	// Per-image-type tests.
3157 
3158 	{
3159 		static const TextureType imageTypes[] =
3160 		{
3161 			TEXTURETYPE_2D,
3162 			TEXTURETYPE_CUBE,
3163 			TEXTURETYPE_3D,
3164 			TEXTURETYPE_2D_ARRAY,
3165 			TEXTURETYPE_BUFFER
3166 		};
3167 
3168 		static const TextureFormat formats[] =
3169 		{
3170 			TextureFormat(TextureFormat::RGBA,	TextureFormat::FLOAT),
3171 			TextureFormat(TextureFormat::RGBA,	TextureFormat::HALF_FLOAT),
3172 			TextureFormat(TextureFormat::R,		TextureFormat::FLOAT),
3173 
3174 			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT32),
3175 			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT16),
3176 			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT8),
3177 			TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT32),
3178 
3179 			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT32),
3180 			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT16),
3181 			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT8),
3182 			TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT32),
3183 
3184 			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8),
3185 
3186 			TextureFormat(TextureFormat::RGBA,	TextureFormat::SNORM_INT8)
3187 		};
3188 
3189 		for (int imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageTypes); imageTypeNdx++)
3190 		{
3191 			const TextureType		imageType			= imageTypes[imageTypeNdx];
3192 			TestCaseGroup* const	imageTypeGroup		= new TestCaseGroup(m_context, getTextureTypeName(imageType), "");
3193 			addChild(imageTypeGroup);
3194 
3195 			TestCaseGroup* const	storeGroup			= new TestCaseGroup(m_context, "store",					"Plain imageStore() cases");
3196 			TestCaseGroup* const	loadStoreGroup		= new TestCaseGroup(m_context, "load_store",			"Cases with imageLoad() followed by imageStore()");
3197 			TestCaseGroup* const	atomicGroup			= new TestCaseGroup(m_context, "atomic",				"Atomic image operation cases");
3198 			TestCaseGroup* const	qualifierGroup		= new TestCaseGroup(m_context, "qualifiers",			"Coherent, volatile and restrict");
3199 			TestCaseGroup* const	reinterpretGroup	= new TestCaseGroup(m_context, "format_reinterpret",	"Cases with differing texture and image formats");
3200 			TestCaseGroup* const	imageSizeGroup		= new TestCaseGroup(m_context, "image_size",			"imageSize() cases");
3201 			imageTypeGroup->addChild(storeGroup);
3202 			imageTypeGroup->addChild(loadStoreGroup);
3203 			imageTypeGroup->addChild(atomicGroup);
3204 			imageTypeGroup->addChild(qualifierGroup);
3205 			imageTypeGroup->addChild(reinterpretGroup);
3206 			imageTypeGroup->addChild(imageSizeGroup);
3207 
3208 			for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
3209 			{
3210 				const TextureFormat&	format		= formats[formatNdx];
3211 				const string			formatName	= getShaderImageFormatQualifier(formats[formatNdx]);
3212 
3213 				if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(format))
3214 					continue;
3215 
3216 				// Store cases.
3217 
3218 				storeGroup->addChild(new ImageStoreCase(m_context, formatName.c_str(), "", format, imageType));
3219 				if (textureLayerType(imageType) != imageType)
3220 					storeGroup->addChild(new ImageStoreCase(m_context, (formatName + "_single_layer").c_str(), "", format, imageType, ImageStoreCase::CASEFLAG_SINGLE_LAYER_BIND));
3221 
3222 				// Load & store.
3223 
3224 				loadStoreGroup->addChild(new ImageLoadAndStoreCase(m_context, formatName.c_str(), "", format, imageType));
3225 				if (textureLayerType(imageType) != imageType)
3226 					loadStoreGroup->addChild(new ImageLoadAndStoreCase(m_context, (formatName + "_single_layer").c_str(), "", format, imageType, ImageLoadAndStoreCase::CASEFLAG_SINGLE_LAYER_BIND));
3227 
3228 				if (format.order == TextureFormat::R)
3229 				{
3230 					// Atomic operations.
3231 
3232 					for (int operationI = 0; operationI < ATOMIC_OPERATION_LAST; operationI++)
3233 					{
3234 						for (int atomicCaseTypeI = 0; atomicCaseTypeI < ATOMIC_OPERATION_CASE_TYPE_LAST; atomicCaseTypeI++)
3235 						{
3236 							const AtomicOperation operation = (AtomicOperation)operationI;
3237 
3238 							if (format.type == TextureFormat::FLOAT && operation != ATOMIC_OPERATION_EXCHANGE)
3239 								continue;
3240 
3241 							const AtomicOperationCaseType	caseType		= (AtomicOperationCaseType)atomicCaseTypeI;
3242 							const string					caseTypeName	= caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? "result"
3243 																			: caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? "return_value"
3244 																			: DE_NULL;
3245 							const string					caseName		= string() + getAtomicOperationCaseName(operation) + "_" + formatName + "_" + caseTypeName;
3246 
3247 							if (operation == ATOMIC_OPERATION_COMP_SWAP)
3248 								atomicGroup->addChild(new AtomicCompSwapCase(m_context, caseName.c_str(), "", format, imageType, caseType));
3249 							else
3250 								atomicGroup->addChild(new BinaryAtomicOperationCase(m_context, caseName.c_str(), "", format, imageType, operation, caseType));
3251 						}
3252 					}
3253 
3254 					// Coherence.
3255 
3256 					for (int coherenceQualifierI = 0; coherenceQualifierI < CoherenceCase::QUALIFIER_LAST; coherenceQualifierI++)
3257 					{
3258 						const CoherenceCase::Qualifier	coherenceQualifier		= (CoherenceCase::Qualifier)coherenceQualifierI;
3259 						const char* const				coherenceQualifierName	= coherenceQualifier == CoherenceCase::QUALIFIER_COHERENT ? "coherent"
3260 																				: coherenceQualifier == CoherenceCase::QUALIFIER_VOLATILE ? "volatile"
3261 																				: DE_NULL;
3262 						const string					caseName				= string() + coherenceQualifierName + "_" + formatName;
3263 
3264 						qualifierGroup->addChild(new CoherenceCase(m_context, caseName.c_str(), "", format, imageType, coherenceQualifier));
3265 					}
3266 				}
3267 			}
3268 
3269 			// Restrict.
3270 			qualifierGroup->addChild(new ImageLoadAndStoreCase(m_context, "restrict", "", TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), imageType, ImageLoadAndStoreCase::CASEFLAG_RESTRICT_IMAGES));
3271 
3272 			// Format re-interpretation.
3273 
3274 			for (int texFmtNdx = 0; texFmtNdx < DE_LENGTH_OF_ARRAY(formats); texFmtNdx++)
3275 			for (int imgFmtNdx = 0; imgFmtNdx < DE_LENGTH_OF_ARRAY(formats); imgFmtNdx++)
3276 			{
3277 				const TextureFormat& texFmt = formats[texFmtNdx];
3278 				const TextureFormat& imgFmt = formats[imgFmtNdx];
3279 
3280 				if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(texFmt))
3281 					continue;
3282 
3283 				if (texFmt != imgFmt && texFmt.getPixelSize() == imgFmt.getPixelSize())
3284 					reinterpretGroup->addChild(new ImageLoadAndStoreCase(m_context,
3285 																		 (getShaderImageFormatQualifier(texFmt) + "_" + getShaderImageFormatQualifier(imgFmt)).c_str(), "",
3286 																		 texFmt, imgFmt, imageType));
3287 			}
3288 
3289 			// imageSize().
3290 
3291 			{
3292 				static const IVec3 baseImageSizes[] =
3293 				{
3294 					IVec3(32, 32, 32),
3295 					IVec3(12, 34, 56),
3296 					IVec3(1,   1,  1),
3297 					IVec3(7,   1,  1)
3298 				};
3299 
3300 				for (int imageAccessI = 0; imageAccessI < ImageSizeCase::IMAGEACCESS_LAST; imageAccessI++)
3301 				{
3302 					const ImageSizeCase::ImageAccess	imageAccess		= (ImageSizeCase::ImageAccess)imageAccessI;
3303 					const char* const					imageAccessStr	= imageAccess == ImageSizeCase::IMAGEACCESS_READ_ONLY				? "readonly"
3304 																		: imageAccess == ImageSizeCase::IMAGEACCESS_WRITE_ONLY				? "writeonly"
3305 																		: imageAccess == ImageSizeCase::IMAGEACCESS_READ_ONLY_WRITE_ONLY	? "readonly_writeonly"
3306 																		: DE_NULL;
3307 
3308 					for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(baseImageSizes); imageSizeNdx++)
3309 					{
3310 						const IVec3&	baseSize	= baseImageSizes[imageSizeNdx];
3311 						const IVec3		imageSize	= imageType == TEXTURETYPE_BUFFER		? IVec3(baseSize.x(), 1, 1)
3312 													: imageType == TEXTURETYPE_2D			? IVec3(baseSize.x(), baseSize.y(), 1)
3313 													: imageType == TEXTURETYPE_CUBE			? IVec3(baseSize.x(), baseSize.x(), 1)
3314 													: imageType == TEXTURETYPE_3D			? baseSize
3315 													: imageType == TEXTURETYPE_2D_ARRAY		? baseSize
3316 													: IVec3(-1, -1, -1);
3317 
3318 						const string	sizeStr		= imageType == TEXTURETYPE_BUFFER		? toString(imageSize.x())
3319 													: imageType == TEXTURETYPE_2D			? toString(imageSize.x()) + "x" + toString(imageSize.y())
3320 													: imageType == TEXTURETYPE_CUBE			? toString(imageSize.x()) + "x" + toString(imageSize.y())
3321 													: imageType == TEXTURETYPE_3D			? toString(imageSize.x()) + "x" + toString(imageSize.y()) + "x" + toString(imageSize.z())
3322 													: imageType == TEXTURETYPE_2D_ARRAY		? toString(imageSize.x()) + "x" + toString(imageSize.y()) + "x" + toString(imageSize.z())
3323 													: DE_NULL;
3324 
3325 						const string	caseName	= string() + imageAccessStr + "_" + sizeStr;
3326 
3327 						imageSizeGroup->addChild(new ImageSizeCase(m_context, caseName.c_str(), "", TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), imageType, imageSize, imageAccess));
3328 					}
3329 				}
3330 			}
3331 		}
3332 	}
3333 
3334 	// early_fragment_tests cases.
3335 
3336 	{
3337 		TestCaseGroup* const earlyTestsGroup = new TestCaseGroup(m_context, "early_fragment_tests", "");
3338 		addChild(earlyTestsGroup);
3339 
3340 		for (int testRenderTargetI = 0; testRenderTargetI < EarlyFragmentTestsCase::RENDERTARGET_LAST; testRenderTargetI++)
3341 		for (int useEarlyTestsI = 0; useEarlyTestsI <= 1; useEarlyTestsI++)
3342 		for (int testTypeI = 0; testTypeI < EarlyFragmentTestsCase::TESTTYPE_LAST; testTypeI++)
3343 		{
3344 			const EarlyFragmentTestsCase::RenderTargetType	targetType		= (EarlyFragmentTestsCase::RenderTargetType)testRenderTargetI;
3345 			const bool 										useEarlyTests 	= useEarlyTestsI != 0;
3346 			const EarlyFragmentTestsCase::TestType			testType		= (EarlyFragmentTestsCase::TestType)testTypeI;
3347 
3348 			const string									testTypeName	= testType == EarlyFragmentTestsCase::TESTTYPE_DEPTH	? "depth"
3349 																			: testType == EarlyFragmentTestsCase::TESTTYPE_STENCIL	? "stencil"
3350 																			: DE_NULL;
3351 
3352 			const string									targetName		= targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO 							? (std::string("_fbo"))
3353 																			: targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT	? (std::string("_fbo_with_no_") + testTypeName)
3354 																			: std::string("");
3355 
3356 			const string									caseName		= string(useEarlyTests ? "" : "no_") + "early_fragment_tests_" + testTypeName + targetName;
3357 
3358 			const string									caseDesc		= string(useEarlyTests ? "Specify" : "Don't specify")
3359 																			+ " early_fragment_tests, use the " + testTypeName + " test"
3360 																			+ ((targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO) 							? (", render to fbo")
3361 																			   : (targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT) 	? (", render to fbo without relevant buffer")
3362 																			   : (""));
3363 
3364 			earlyTestsGroup->addChild(new EarlyFragmentTestsCase(m_context, caseName.c_str(), caseDesc.c_str(), testType, useEarlyTests, targetType));
3365 		}
3366 	}
3367 }
3368 
3369 } // Functional
3370 } // gles31
3371 } // deqp
3372