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