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