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