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