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