• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
defaultImageSize(TextureType type)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>
arrayStr(const T (& arr)[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>
arrayIndexOf(const T (& arr)[N],const T & e)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 
getTextureTypeName(TextureType type)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 
isFormatTypeUnsignedInteger(TextureFormat::ChannelType type)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 
isFormatTypeSignedInteger(TextureFormat::ChannelType type)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 
isFormatTypeInteger(TextureFormat::ChannelType type)149 static inline bool isFormatTypeInteger (TextureFormat::ChannelType type)
150 {
151 	return isFormatTypeUnsignedInteger(type) || isFormatTypeSignedInteger(type);
152 }
153 
isFormatTypeUnorm(TextureFormat::ChannelType type)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 
isFormatTypeSnorm(TextureFormat::ChannelType type)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 
isFormatSupportedForTextureBuffer(const TextureFormat & format)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 
getShaderImageFormatQualifier(const TextureFormat & format)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 
getShaderSamplerOrImageType(TextureFormat::ChannelType formatType,TextureType textureType,bool isSampler)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 
getShaderImageType(TextureFormat::ChannelType formatType,TextureType imageType)253 static inline string getShaderImageType (TextureFormat::ChannelType formatType, TextureType imageType)
254 {
255 	return getShaderSamplerOrImageType(formatType, imageType, false);
256 }
257 
getShaderSamplerType(TextureFormat::ChannelType formatType,TextureType imageType)258 static inline string getShaderSamplerType (TextureFormat::ChannelType formatType, TextureType imageType)
259 {
260 	return getShaderSamplerOrImageType(formatType, imageType, true);
261 }
262 
getGLTextureTarget(TextureType texType)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 
cubeFaceToGLFace(tcu::CubeFace face)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 
newOneLevelTexture1D(const tcu::TextureFormat & format,int w)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 
newOneLevelTexture2D(const tcu::TextureFormat & format,int w,int h)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 
newOneLevelTextureCube(const tcu::TextureFormat & format,int size)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 
newOneLevelTexture3D(const tcu::TextureFormat & format,int w,int h,int d)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 
newOneLevelTexture2DArray(const tcu::TextureFormat & format,int w,int h,int d)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 
textureLayerType(TextureType entireTextureType)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 
checkTextureTypeExtensions(const glu::ContextInfo & contextInfo,TextureType type,const RenderContext & renderContext)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 
textureTypeExtensionShaderRequires(TextureType type,const RenderContext & renderContext)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 
imageAtomicExtensionShaderRequires(const RenderContext & renderContext)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).
isOrderIndependentAtomicOperation(AtomicOperation op)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.
computeBinaryAtomicOperationResult(AtomicOperation op,int a,int b)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.
computeBinaryAtomicOperationResult(AtomicOperation op,float,float b)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 
getAtomicOperationCaseName(AtomicOperation op)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 
getAtomicOperationShaderFuncName(AtomicOperation op)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.
glslImageFuncZToCubeFace(int z)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:
BufferMemMap(const glw::Functions & gl,deUint32 target,int offset,int size,deUint32 access)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 
~BufferMemMap(void)503 	~BufferMemMap (void)
504 	{
505 		m_gl.unmapBuffer(m_target);
506 	}
507 
getPtr(void) const508 	void*	getPtr		(void) const { return m_ptr; }
operator *(void) const509 	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:
UniformAccessLogger(const glw::Functions & gl,TestLog & log,deUint32 programGL)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 
getLocation(const string & name)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 
assign1i(const string & name,int x)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 
assign3f(const string & name,float x,float y,float z)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 
getImageType(void) const576 	TextureType									getImageType				(void) const { return m_type; }
getSize(void) const577 	const IVec3&								getSize						(void) const { return m_size; }
getFormat(void) const578 	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;
getPixelUint(int x,int y,int z) const587 	UVec4										getPixelUint				(int x, int y, int z) const { return getPixelInt(x, y, z).asUint(); }
588 
getAccess(void)589 	PixelBufferAccess							getAccess					(void)							{ return getAccessInternal();				}
getSliceAccess(int slice)590 	PixelBufferAccess							getSliceAccess				(int slice)						{ return getSliceAccessInternal(slice);		}
getCubeFaceAccess(tcu::CubeFace face)591 	PixelBufferAccess							getCubeFaceAccess			(tcu::CubeFace face)			{ return getCubeFaceAccessInternal(face);	}
592 
getAccess(void) const593 	ConstPixelBufferAccess						getAccess					(void)					const	{ return getAccessInternal();				}
getSliceAccess(int slice) const594 	ConstPixelBufferAccess						getSliceAccess				(int slice)				const	{ return getSliceAccessInternal(slice);		}
getCubeFaceAccess(tcu::CubeFace face) const595 	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 
LayeredImage(TextureType type,const TextureFormat & format,int w,int h,int d)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>
setPixel(int x,int y,int z,const ColorT & color) const648 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 
getPixel(int x,int y,int z) const660 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 
getPixelInt(int x,int y,int z) const666 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 
getAccessInternal(void) const672 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 
getSliceAccessInternal(int slice) const683 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 
getCubeFaceAccessInternal(tcu::CubeFace face) const689 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.
setTextureStorage(glu::CallLogWrapper & glLog,TextureType imageType,deUint32 internalFormat,const IVec3 & imageSize,deUint32 textureBufGL)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 
uploadTexture(glu::CallLogWrapper & glLog,const LayeredImage & src,deUint32 textureBufGL)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 
readPixelsRGBAInteger32(const PixelBufferAccess & dst,int originX,int originY,glu::CallLogWrapper & glLog)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;
~ImageLayerVerifier(void)808 	virtual			~ImageLayerVerifier		(void) {}
809 };
810 
setTexParameteri(glu::CallLogWrapper & glLog,deUint32 target)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.
readIntegerTextureViaFBOAndVerify(const RenderContext & renderCtx,glu::CallLogWrapper & glLog,deUint32 textureGL,TextureType textureType,const TextureFormat & textureFormat,const IVec3 & textureSize,const ImageLayerVerifier & verifyLayer)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.
readFloatOrNormTextureWithLookupsAndVerify(const RenderContext & renderCtx,glu::CallLogWrapper & glLog,deUint32 textureGL,TextureType textureType,const TextureFormat & textureFormat,const IVec3 & textureSize,const ImageLayerVerifier & verifyLayer)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.
readBufferTextureWithMappingAndVerify(const RenderContext & renderCtx,glu::CallLogWrapper & glLog,deUint32 bufferGL,const TextureFormat & textureFormat,int imageSize,const ImageLayerVerifier & verifyLayer)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.
readTextureAndVerify(const RenderContext & renderCtx,glu::CallLogWrapper & glLog,deUint32 textureGL,deUint32 bufferGL,TextureType textureType,const TextureFormat & textureFormat,const IVec3 & imageSize,const ImageLayerVerifier & verifyLayer)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:
ImageLayerComparer(const LayeredImage & reference,const IVec2 & relevantRegion=IVec2 (0))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 
operator ()(TestLog & log,const tcu::ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const1082 	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 
ImageStoreCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType textureType,deUint32 caseFlags=0)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 
init(void)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 
iterate(void)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 
ImageLoadAndStoreCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType textureType,deUint32 caseFlags=0)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 
ImageLoadAndStoreCase(Context & context,const char * name,const char * description,const TextureFormat & textureFormat,const TextureFormat & imageFormat,TextureType textureType,deUint32 caseFlags=0)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 
init(void)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>
replaceBadFloatReinterpretValues(LayeredImage & image,const TextureFormat & imageFormat)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 
iterate(void)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:
BinaryAtomicOperationCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,AtomicOperation operation,AtomicOperationCaseType caseType)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 
getOperationInitialValue(AtomicOperation op)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 
getAtomicFuncArgument(AtomicOperation op,const IVec3 & invocationID,const IVec2 & dispatchSizeXY)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 
getAtomicFuncArgumentShaderStr(AtomicOperation op,const string & x,const string & y,const string & z,const IVec2 & dispatchSizeXY)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:
EndResultVerifier(AtomicOperation operation,TextureType imageType)1701 	EndResultVerifier (AtomicOperation operation, TextureType imageType) : m_operation(operation), m_imageType(imageType) {}
1702 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const1703 	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.
ReturnValueVerifier(AtomicOperation operation,TextureType imageType,const IVec2 & endResultImageLayerSize)1794 	ReturnValueVerifier (AtomicOperation operation, TextureType imageType, const IVec2& endResultImageLayerSize) : m_operation(operation), m_imageType(imageType), m_endResultImageLayerSize(endResultImageLayerSize) {}
1795 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const1796 	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>
verifyOperationAccumulationIntermediateValues(AtomicOperation operation,T init,const T (& args)[NUM_INVOCATIONS_PER_PIXEL],const T (& returnValues)[NUM_INVOCATIONS_PER_PIXEL])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 
compare(int a,int b)1891 	static bool compare (int a, int b)		{ return a == b; }
compare(float a,float 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>
verifyRecursive(AtomicOperation operation,int index,T valueSoFar,bool (& argsUsed)[NUM_INVOCATIONS_PER_PIXEL],const T (& args)[NUM_INVOCATIONS_PER_PIXEL],const T (& returnValues)[NUM_INVOCATIONS_PER_PIXEL])1896 	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 
init(void)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 
iterate(void)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:
AtomicCompSwapCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,AtomicOperationCaseType caseType)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 
getCompareArg(const IVec3 & invocationID,int imageWidth)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 
getAssignArg(const IVec3 & invocationID,int imageWidth)2142 int AtomicCompSwapCase::getAssignArg (const IVec3& invocationID, int imageWidth)
2143 {
2144 	return getCompareArg(IVec3(invocationID.x() + imageWidth, invocationID.y(), invocationID.z()), imageWidth);
2145 }
2146 
getCompareArgShaderStr(const string & x,const string & y,const string & z,int imageWidth)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 
getAssignArgShaderStr(const string & x,const string & y,const string & z,int imageWidth)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 
init(void)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:
EndResultVerifier(TextureType imageType,int imageWidth)2174 	EndResultVerifier (TextureType imageType, int imageWidth) : m_imageType(imageType), m_imageWidth(imageWidth) {}
2175 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const2176 	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.
ReturnValueVerifier(TextureType imageType,int endResultImageWidth)2233 	ReturnValueVerifier (TextureType imageType, int endResultImageWidth) : m_imageType(imageType), m_endResultImageWidth(endResultImageWidth) {}
2234 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int sliceOrFaceNdx) const2235 	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 
iterate(void)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 
CoherenceCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,Qualifier qualifier)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 
init(void)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 
iterate(void)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:
R32UIImageSingleValueVerifier(const deUint32 value)2711 	R32UIImageSingleValueVerifier (const deUint32 value)					: m_min(value),	m_max(value)	{}
R32UIImageSingleValueVerifier(const deUint32 min,const deUint32 max)2712 	R32UIImageSingleValueVerifier (const deUint32 min, const deUint32 max)	: m_min(min),	m_max(max)		{}
2713 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int) const2714 	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 
ImageSizeCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,const IVec3 & size,ImageAccess imageAccess)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 
init(void)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 
iterate(void)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 
EarlyFragmentTestsCase(Context & context,const char * name,const char * description,TestType type,bool useEarlyTests,RenderTargetType renderTarget)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 
init(void)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 
iterate(void)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 
ShaderImageLoadStoreTests(Context & context)3146 ShaderImageLoadStoreTests::ShaderImageLoadStoreTests (Context& context)
3147 	: TestCaseGroup(context, "image_load_store", "Shader Image Load & Store Tests")
3148 {
3149 }
3150 
~ShaderImageLoadStoreTests(void)3151 ShaderImageLoadStoreTests::~ShaderImageLoadStoreTests (void)
3152 {
3153 }
3154 
init(void)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