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