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