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