• 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 either the same as or the smallest value (among A, B, C, ...) bigger than
2330 			// the one just before it. E.g. sequences A A A A A A A A, A B C D E F G H and
2331 			// A A B B B C D E are all valid sequences (if there were 8 invocations contributing
2332 			// to each pixel).
2333 
2334 			{
2335 				int failingNdx = -1;
2336 
2337 				{
2338 					int currentAtomicValueNdx = 0;
2339 					for (int i = 0; i < m_numInvocationsPerPixel; i++)
2340 					{
2341 						if (returnValues[i] == compareArgs[currentAtomicValueNdx])
2342 							continue;
2343 						if (i > 0 && returnValues[i] == compareArgs[currentAtomicValueNdx+1])
2344 						{
2345 							currentAtomicValueNdx++;
2346 							continue;
2347 						}
2348 						failingNdx = i;
2349 						break;
2350 					}
2351 				}
2352 
2353 				if (failingNdx >= 0)
2354 				{
2355 					log << TestLog::Message << "// Failure: intermediate return values at pixels " << arrayStr(pixelCoords) << " of current layer are "
2356 											<< arrayStr(returnValues) << TestLog::EndMessage
2357 						<< TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
2358 						<< TestLog::Message << "// Note: 'compare' argument values for the IDs are " << arrayStr(compareArgs) << TestLog::EndMessage
2359 						<< TestLog::Message << "// Note: expected the return value sequence to fulfill the following conditions:\n"
2360 											<< "// - first value is " << compareArgs[0] << "\n"
2361 											<< "// - each value other than the first is either the same as the one just before it, or the smallest value (in the sequence "
2362 											<< arrayStr(compareArgs) << ") bigger than the one just before it" << TestLog::EndMessage;
2363 					if (failingNdx == 0)
2364 						log << TestLog::Message << "// Note: the first return value (" << returnValues[0] << ") isn't " << compareArgs[0] << TestLog::EndMessage;
2365 					else
2366 						log << TestLog::Message << "// Note: the return value at index " << failingNdx << " (value " << returnValues[failingNdx] << ") "
2367 												<< "is neither " << returnValues[failingNdx-1] << " (the one just before it) "
2368 												<< "nor " << compareArgs[arrayIndexOf(compareArgs, returnValues[failingNdx-1])+1] << " (the smallest value bigger than the one just before it)"
2369 												<< TestLog::EndMessage;
2370 
2371 					return false;
2372 				}
2373 			}
2374 		}
2375 
2376 		return true;
2377 	}
2378 
2379 private:
2380 	const TextureType	m_imageType;
2381 	const int			m_endResultImageWidth;
2382 	const int			m_numInvocationsPerPixel;
2383 };
2384 
iterate(void)2385 AtomicCompSwapCase::IterateResult AtomicCompSwapCase::iterate (void)
2386 {
2387 	const RenderContext&		renderCtx				= m_context.getRenderContext();
2388 	TestLog&					log						(m_testCtx.getLog());
2389 	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
2390 	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
2391 	const deUint32				textureTargetGL			= getGLTextureTarget(m_imageType);
2392 	const IVec3&				imageSize				= defaultImageSize(m_imageType);
2393 	const int					numSlicesOrFaces		= m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
2394 	const bool					isUintFormat			= isFormatTypeUnsignedInteger(m_format.type);
2395 	const bool					isIntFormat				= isFormatTypeSignedInteger(m_format.type);
2396 	const glu::Buffer			endResultTextureBuf		(renderCtx);
2397 	const glu::Buffer			returnValueTextureBuf	(renderCtx);
2398 	const glu::Texture			endResultTexture		(renderCtx); //!< Texture for the final result; i.e. the texture on which the atomic operations are done. Size imageSize.
2399 	const glu::Texture			returnValueTexture		(renderCtx); //!< Texture into which the return values are stored if m_caseType == CASETYPE_RETURN_VALUES.
2400 																	 //	  Size imageSize*IVec3(N, 1, 1) or, for cube maps, imageSize*IVec3(N, N, 1) where N is NUM_INVOCATIONS_PER_PIXEL.
2401 
2402 	DE_ASSERT(isUintFormat || isIntFormat);
2403 
2404 	glLog.enableLogging(true);
2405 
2406 	// Adjust result image size for result image
2407 	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
2408 	{
2409 		int maxWidth = getGLTextureMaxSize(glLog, m_imageType);
2410 
2411 		while (maxWidth < m_numInvocationsPerPixel * imageSize.x())
2412 		{
2413 			int* numInvocationsPerPixel = const_cast<int*>(&m_numInvocationsPerPixel);
2414 			(*numInvocationsPerPixel) -= 1;
2415 		}
2416 	}
2417 
2418 	// Setup textures.
2419 
2420 	log << TestLog::Message << "// Created a texture (name " << *endResultTexture << ") to act as the target of atomic operations" << TestLog::EndMessage;
2421 	if (m_imageType == TEXTURETYPE_BUFFER)
2422 		log << TestLog::Message << "// Created a buffer for the texture (name " << *endResultTextureBuf << ")" << TestLog::EndMessage;
2423 
2424 	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
2425 	{
2426 		log << TestLog::Message << "// Created a texture (name " << *returnValueTexture << ") to which the intermediate return values of the atomic operation are stored" << TestLog::EndMessage;
2427 		if (m_imageType == TEXTURETYPE_BUFFER)
2428 			log << TestLog::Message << "// Created a buffer for the texture (name " << *returnValueTextureBuf << ")" << TestLog::EndMessage;
2429 	}
2430 
2431 	// Fill endResultTexture with initial pattern.
2432 
2433 	{
2434 		const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
2435 
2436 		{
2437 			for (int z = 0; z < numSlicesOrFaces; z++)
2438 			for (int y = 0; y < imageSize.y(); y++)
2439 			for (int x = 0; x < imageSize.x(); x++)
2440 				imageData.setPixel(x, y, z, IVec4(getCompareArg(IVec3(x, y, z), imageSize.x())));
2441 		}
2442 
2443 		// Upload initial pattern to endResultTexture and bind to image.
2444 
2445 		glLog.glActiveTexture(GL_TEXTURE0);
2446 		glLog.glBindTexture(textureTargetGL, *endResultTexture);
2447 		setTexParameteri(glLog, textureTargetGL);
2448 
2449 		log << TestLog::Message << "// Filling end-result texture with initial pattern" << TestLog::EndMessage;
2450 
2451 		uploadTexture(glLog, imageData, *endResultTextureBuf);
2452 	}
2453 
2454 	glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
2455 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2456 
2457 	if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
2458 	{
2459 		// Set storage for returnValueTexture and bind to image.
2460 
2461 		glLog.glActiveTexture(GL_TEXTURE1);
2462 		glLog.glBindTexture(textureTargetGL, *returnValueTexture);
2463 		setTexParameteri(glLog, textureTargetGL);
2464 
2465 		log << TestLog::Message << "// Setting storage of return-value texture" << TestLog::EndMessage;
2466 		setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize * (m_imageType == TEXTURETYPE_CUBE ? IVec3(m_numInvocationsPerPixel, m_numInvocationsPerPixel,	1)
2467 																											 : IVec3(m_numInvocationsPerPixel, 1,							1)),
2468 						  *returnValueTextureBuf);
2469 
2470 		glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
2471 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2472 	}
2473 
2474 	// Perform atomics in compute shader.
2475 
2476 	{
2477 		// Generate compute shader.
2478 
2479 		const string colorScalarTypeName	= isUintFormat ? "uint" : isIntFormat ? "int" : DE_NULL;
2480 		const string colorVecTypeName		= string(isUintFormat ? "u" : isIntFormat ? "i" : DE_NULL) + "vec4";
2481 		const string atomicCoord			= m_imageType == TEXTURETYPE_BUFFER		? "gx % " + toString(imageSize.x())
2482 											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx % " + toString(imageSize.x()) + ", gy)"
2483 											: "ivec3(gx % " + toString(imageSize.x()) + ", gy, gz)";
2484 		const string invocationCoord		= m_imageType == TEXTURETYPE_BUFFER		? "gx"
2485 											: m_imageType == TEXTURETYPE_2D			? "ivec2(gx, gy)"
2486 											: "ivec3(gx, gy, gz)";
2487 		const string shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
2488 		const string shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2489 		const string glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
2490 
2491 		const glu::ShaderProgram program(renderCtx,
2492 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2493 														+ imageAtomicExtensionShaderRequires(renderCtx)
2494 														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2495 														"\n"
2496 														"precision highp " + shaderImageTypeStr + ";\n"
2497 														"\n"
2498 														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2499 														"layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_results;\n"
2500 														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
2501 															  "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_returnValues;\n"
2502 															: "") +
2503 														"\n"
2504 														"void main (void)\n"
2505 														"{\n"
2506 														"	int gx = int(gl_GlobalInvocationID.x);\n"
2507 														"	int gy = int(gl_GlobalInvocationID.y);\n"
2508 														"	int gz = int(gl_GlobalInvocationID.z);\n"
2509 														"	" + colorScalarTypeName + " compare = " + colorScalarTypeName + getCompareArgShaderStr("gx", "gy", "gz", imageSize.x()) + ";\n"
2510 														"	" + colorScalarTypeName + " data    = " + colorScalarTypeName + getAssignArgShaderStr("gx", "gy", "gz", imageSize.x()) + ";\n"
2511 														"	" + colorScalarTypeName + " status  = " + colorScalarTypeName + "(-1);\n"
2512 														"	status = imageAtomicCompSwap(u_results, " + atomicCoord + ", compare, data);\n"
2513 														+ (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ?
2514 															"	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 		glLog.glDispatchCompute(m_numInvocationsPerPixel*imageSize.x(), imageSize.y(), numSlicesOrFaces);
2533 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2534 	}
2535 
2536 	// Create reference, read texture and compare.
2537 
2538 	{
2539 		const deUint32								textureToCheckGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTexture
2540 																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTexture
2541 																		: (deUint32)-1;
2542 
2543 		const deUint32								textureToCheckBufGL	= m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? *endResultTextureBuf
2544 																		: m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? *returnValueTextureBuf
2545 																		: (deUint32)-1;
2546 
2547 		// The relevant region of the texture being checked (potentially
2548 		// different from actual texture size for cube maps, because cube maps
2549 		// may have unused pixels due to square size restriction).
2550 		const IVec3									relevantRegion		= imageSize * (m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT	? IVec3(1,							1,							1)
2551 																					 :														  IVec3(m_numInvocationsPerPixel,	1,							1));
2552 
2553 		const UniquePtr<const ImageLayerVerifier>	verifier			(m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? new EndResultVerifier(m_imageType, imageSize.x(), m_numInvocationsPerPixel)
2554 																	   : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES		? new ReturnValueVerifier(m_imageType, imageSize.x(), m_numInvocationsPerPixel)
2555 																	   : (ImageLayerVerifier*)DE_NULL);
2556 
2557 		if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, relevantRegion, *verifier))
2558 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2559 		else
2560 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
2561 
2562 		return STOP;
2563 	}
2564 }
2565 
2566 //! Case testing the "coherent" or "volatile" qualifier, along with memoryBarrier() and barrier().
2567 class CoherenceCase : public TestCase
2568 {
2569 public:
2570 	enum Qualifier
2571 	{
2572 		QUALIFIER_COHERENT = 0,
2573 		QUALIFIER_VOLATILE,
2574 
2575 		QUALIFIER_LAST
2576 	};
2577 
CoherenceCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,Qualifier qualifier)2578 	CoherenceCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, Qualifier qualifier)
2579 		: TestCase		(context, name, description)
2580 		, m_format		(format)
2581 		, m_imageType	(imageType)
2582 		, m_qualifier	(qualifier)
2583 	{
2584 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_Y) == DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_X) &&
2585 						 DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_Z) == DE_LENGTH_OF_ARRAY(CoherenceCase::SHADER_READ_OFFSETS_X));
2586 
2587 		DE_ASSERT(qualifier == QUALIFIER_COHERENT || qualifier == QUALIFIER_VOLATILE);
2588 
2589 		DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32)	||
2590 				  m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32)		||
2591 				  m_format == TextureFormat(TextureFormat::R, TextureFormat::FLOAT));
2592 	}
2593 
init(void)2594 	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext()); }
2595 	IterateResult	iterate		(void);
2596 
2597 private:
2598 	static const int			SHADER_READ_OFFSETS_X[4];
2599 	static const int			SHADER_READ_OFFSETS_Y[4];
2600 	static const int			SHADER_READ_OFFSETS_Z[4];
2601 	static const char* const	SHADER_READ_OFFSETS_X_STR;
2602 	static const char* const	SHADER_READ_OFFSETS_Y_STR;
2603 	static const char* const	SHADER_READ_OFFSETS_Z_STR;
2604 
2605 	const TextureFormat		m_format;
2606 	const TextureType		m_imageType;
2607 	const Qualifier			m_qualifier;
2608 };
2609 
2610 const int			CoherenceCase::SHADER_READ_OFFSETS_X[4]		=		{ 1, 4, 7, 10 };
2611 const int			CoherenceCase::SHADER_READ_OFFSETS_Y[4]		=		{ 2, 5, 8, 11 };
2612 const int			CoherenceCase::SHADER_READ_OFFSETS_Z[4]		=		{ 3, 6, 9, 12 };
2613 const char* const	CoherenceCase::SHADER_READ_OFFSETS_X_STR	= "int[]( 1, 4, 7, 10 )";
2614 const char* const	CoherenceCase::SHADER_READ_OFFSETS_Y_STR	= "int[]( 2, 5, 8, 11 )";
2615 const char* const	CoherenceCase::SHADER_READ_OFFSETS_Z_STR	= "int[]( 3, 6, 9, 12 )";
2616 
iterate(void)2617 CoherenceCase::IterateResult CoherenceCase::iterate (void)
2618 {
2619 	const RenderContext&		renderCtx					= m_context.getRenderContext();
2620 	TestLog&					log							(m_testCtx.getLog());
2621 	glu::CallLogWrapper			glLog						(renderCtx.getFunctions(), log);
2622 	const deUint32				internalFormatGL			= glu::getInternalFormat(m_format);
2623 	const deUint32				textureTargetGL				= getGLTextureTarget(m_imageType);
2624 	const IVec3&				imageSize					= defaultImageSize(m_imageType);
2625 	const int					numSlicesOrFaces			= m_imageType == TEXTURETYPE_CUBE ? 6 : imageSize.z();
2626 	const bool					isUintFormat				= isFormatTypeUnsignedInteger(m_format.type);
2627 	const bool					isIntFormat					= isFormatTypeSignedInteger(m_format.type);
2628 	const char* const			qualifierName				= m_qualifier == QUALIFIER_COHERENT ? "coherent"
2629 															: m_qualifier == QUALIFIER_VOLATILE ? "volatile"
2630 															: DE_NULL;
2631 	const glu::Buffer			textureBuf					(renderCtx);
2632 	const glu::Texture			texture						(renderCtx);
2633 	const IVec3					numGroups					= IVec3(16, de::min(16, imageSize.y()), de::min(2, numSlicesOrFaces));
2634 	const IVec3					workItemSize				= IVec3(imageSize.x(), imageSize.y(), numSlicesOrFaces);
2635 	const IVec3					localSize					= workItemSize / numGroups;
2636 	const IVec3					minReqMaxLocalSize			= IVec3(128, 128, 64);
2637 	const int					minReqMaxLocalInvocations	= 128;
2638 
2639 	DE_ASSERT(workItemSize == localSize*numGroups);
2640 	DE_ASSERT(tcu::boolAll(tcu::lessThanEqual(localSize, minReqMaxLocalSize)));
2641 	DE_ASSERT(localSize.x()*localSize.y()*localSize.z() <= minReqMaxLocalInvocations);
2642 	DE_UNREF(minReqMaxLocalSize);
2643 	DE_UNREF(minReqMaxLocalInvocations);
2644 
2645 	glLog.enableLogging(true);
2646 
2647 	// Setup texture.
2648 
2649 	log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
2650 	if (m_imageType == TEXTURETYPE_BUFFER)
2651 		log << TestLog::Message << "// Created a buffer for the texture (name " << *textureBuf << ")" << TestLog::EndMessage;
2652 
2653 	glLog.glActiveTexture(GL_TEXTURE0);
2654 	glLog.glBindTexture(textureTargetGL, *texture);
2655 	setTexParameteri(glLog, textureTargetGL);
2656 	setTextureStorage(glLog, m_imageType, internalFormatGL, imageSize, *textureBuf);
2657 	glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
2658 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2659 
2660 	// Perform computations in compute shader.
2661 
2662 	{
2663 		// Generate compute shader.
2664 
2665 		const string		colorVecTypeName		= string(isUintFormat ? "u" : isIntFormat ? "i" : "") + "vec4";
2666 		const char* const	colorScalarTypeName		= isUintFormat ? "uint" : isIntFormat ? "int" : "float";
2667 		const string		invocationCoord			= m_imageType == TEXTURETYPE_BUFFER		? "gx"
2668 													: m_imageType == TEXTURETYPE_2D			? "ivec2(gx, gy)"
2669 													: "ivec3(gx, gy, gz)";
2670 		const string		shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
2671 		const string		shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2672 		const string		localSizeX				= de::toString(localSize.x());
2673 		const string		localSizeY				= de::toString(localSize.y());
2674 		const string		localSizeZ				= de::toString(localSize.z());
2675 		const std::string	glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
2676 
2677 
2678 		const glu::ShaderProgram program(renderCtx,
2679 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2680 														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2681 														"\n"
2682 														"precision highp " + shaderImageTypeStr + ";\n"
2683 														"\n"
2684 														"layout (local_size_x = " + localSizeX
2685 															+ ", local_size_y = " + localSizeY
2686 															+ ", local_size_z = " + localSizeZ
2687 															+ ") in;\n"
2688 														"layout (" + shaderImageFormatStr + ", binding=0) " + qualifierName + " uniform " + shaderImageTypeStr + " u_image;\n"
2689 														"void main (void)\n"
2690 														"{\n"
2691 														"	int gx = int(gl_GlobalInvocationID.x);\n"
2692 														"	int gy = int(gl_GlobalInvocationID.y);\n"
2693 														"	int gz = int(gl_GlobalInvocationID.z);\n"
2694 														"	imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(gx^gy^gz));\n"
2695 														"\n"
2696 														"	memoryBarrier();\n"
2697 														"	barrier();\n"
2698 														"\n"
2699 														"	" + colorScalarTypeName + " sum = " + colorScalarTypeName + "(0);\n"
2700 														"	int groupBaseX = gx/" + localSizeX + "*" + localSizeX + ";\n"
2701 														"	int groupBaseY = gy/" + localSizeY + "*" + localSizeY + ";\n"
2702 														"	int groupBaseZ = gz/" + localSizeZ + "*" + localSizeZ + ";\n"
2703 														"	int xOffsets[] = " + SHADER_READ_OFFSETS_X_STR + ";\n"
2704 														"	int yOffsets[] = " + SHADER_READ_OFFSETS_Y_STR + ";\n"
2705 														"	int zOffsets[] = " + SHADER_READ_OFFSETS_Z_STR + ";\n"
2706 														"	for (int i = 0; i < " + toString(DE_LENGTH_OF_ARRAY(SHADER_READ_OFFSETS_X)) + "; i++)\n"
2707 														"	{\n"
2708 														"		int readX = groupBaseX + (gx + xOffsets[i]) % " + localSizeX + ";\n"
2709 														"		int readY = groupBaseY + (gy + yOffsets[i]) % " + localSizeY + ";\n"
2710 														"		int readZ = groupBaseZ + (gz + zOffsets[i]) % " + localSizeZ + ";\n"
2711 														"		sum += imageLoad(u_image, " + (m_imageType == TEXTURETYPE_BUFFER	? "readX"
2712 																							 : m_imageType == TEXTURETYPE_2D		? "ivec2(readX, readY)"
2713 																							 : "ivec3(readX, readY, readZ)") + ").x;\n"
2714 														"	}\n"
2715 														"\n"
2716 														"	memoryBarrier();\n"
2717 														"	barrier();\n"
2718 														"\n"
2719 														"	imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(sum));\n"
2720 														"}\n"));
2721 
2722 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2723 
2724 		log << program;
2725 
2726 		if (!program.isOk())
2727 		{
2728 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2729 			return STOP;
2730 		}
2731 
2732 		// Setup and dispatch.
2733 
2734 		glLog.glUseProgram(program.getProgram());
2735 
2736 		glLog.glDispatchCompute(numGroups.x(), numGroups.y(), numGroups.z());
2737 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2738 	}
2739 
2740 	// Create reference, read texture and compare.
2741 
2742 	{
2743 		LayeredImage reference(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
2744 
2745 		{
2746 			LayeredImage base(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
2747 			for (int z = 0; z < numSlicesOrFaces; z++)
2748 			for (int y = 0; y < imageSize.y(); y++)
2749 			for (int x = 0; x < imageSize.x(); x++)
2750 				base.setPixel(x, y, z, IVec4(x^y^z));
2751 
2752 			for (int z = 0; z < numSlicesOrFaces; z++)
2753 			for (int y = 0; y < imageSize.y(); y++)
2754 			for (int x = 0; x < imageSize.x(); x++)
2755 			{
2756 				const int	groupBaseX	= x / localSize.x() * localSize.x();
2757 				const int	groupBaseY	= y / localSize.y() * localSize.y();
2758 				const int	groupBaseZ	= z / localSize.z() * localSize.z();
2759 				int			sum			= 0;
2760 				for (int i = 0; i < DE_LENGTH_OF_ARRAY(SHADER_READ_OFFSETS_X); i++)
2761 					sum += base.getPixelInt(groupBaseX + (x + SHADER_READ_OFFSETS_X[i]) % localSize.x(),
2762 											groupBaseY + (y + SHADER_READ_OFFSETS_Y[i]) % localSize.y(),
2763 											groupBaseZ + (z + SHADER_READ_OFFSETS_Z[i]) % localSize.z()).x();
2764 
2765 				reference.setPixel(x, y, z, IVec4(sum));
2766 			}
2767 		}
2768 
2769 		if (readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_imageType, m_format, imageSize, ImageLayerComparer(reference)))
2770 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2771 		else
2772 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2773 
2774 		return STOP;
2775 	}
2776 }
2777 
2778 class R32UIImageSingleValueVerifier : public ImageLayerVerifier
2779 {
2780 public:
R32UIImageSingleValueVerifier(const deUint32 value)2781 	R32UIImageSingleValueVerifier (const deUint32 value)					: m_min(value),	m_max(value)	{}
R32UIImageSingleValueVerifier(const deUint32 min,const deUint32 max)2782 	R32UIImageSingleValueVerifier (const deUint32 min, const deUint32 max)	: m_min(min),	m_max(max)		{}
2783 
operator ()(TestLog & log,const ConstPixelBufferAccess & resultSlice,int) const2784 	bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int) const
2785 	{
2786 		DE_ASSERT(resultSlice.getWidth() == 1 && resultSlice.getHeight() == 1 && resultSlice.getDepth() == 1);
2787 		DE_ASSERT(resultSlice.getFormat() == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32));
2788 
2789 		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;
2790 
2791 		const deUint32 resultValue = resultSlice.getPixelUint(0, 0).x();
2792 		if (!de::inRange(resultValue, m_min, m_max))
2793 		{
2794 			log << TestLog::Message << "// Failure: got value " << resultValue << TestLog::EndMessage;
2795 			return false;
2796 		}
2797 		else
2798 		{
2799 			log << TestLog::Message << "// Success: got value " << resultValue << TestLog::EndMessage;
2800 			return true;
2801 		}
2802 	}
2803 
2804 private:
2805 	const deUint32 m_min;
2806 	const deUint32 m_max;
2807 };
2808 
2809 //! 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
2810 //  can thus be qualifier readonly, writeonly, or both.
2811 class ImageSizeCase : public TestCase
2812 {
2813 public:
2814 	enum ImageAccess
2815 	{
2816 		IMAGEACCESS_READ_ONLY = 0,
2817 		IMAGEACCESS_WRITE_ONLY,
2818 		IMAGEACCESS_READ_ONLY_WRITE_ONLY,
2819 
2820 		IMAGEACCESS_LAST
2821 	};
2822 
ImageSizeCase(Context & context,const char * name,const char * description,const TextureFormat & format,TextureType imageType,const IVec3 & size,ImageAccess imageAccess)2823 	ImageSizeCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, const IVec3& size, ImageAccess imageAccess)
2824 		: TestCase			(context, name, description)
2825 		, m_format			(format)
2826 		, m_imageType		(imageType)
2827 		, m_imageSize		(size)
2828 		, m_imageAccess		(imageAccess)
2829 	{
2830 	}
2831 
init(void)2832 	void			init		(void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext()); }
2833 	IterateResult	iterate		(void);
2834 
2835 private:
2836 	const TextureFormat		m_format;
2837 	const TextureType		m_imageType;
2838 	const IVec3				m_imageSize;
2839 	const ImageAccess		m_imageAccess;
2840 };
2841 
iterate(void)2842 ImageSizeCase::IterateResult ImageSizeCase::iterate (void)
2843 {
2844 	const RenderContext&		renderCtx				= m_context.getRenderContext();
2845 	TestLog&					log						(m_testCtx.getLog());
2846 	glu::CallLogWrapper			glLog					(renderCtx.getFunctions(), log);
2847 	const deUint32				internalFormatGL		= glu::getInternalFormat(m_format);
2848 	const deUint32				textureTargetGL			= getGLTextureTarget(m_imageType);
2849 	const glu::Buffer			mainTextureBuf			(renderCtx);
2850 	const glu::Texture			mainTexture				(renderCtx);
2851 	const glu::Texture			shaderOutResultTexture	(renderCtx);
2852 
2853 	glLog.enableLogging(true);
2854 
2855 	// Setup textures.
2856 
2857 	log << TestLog::Message << "// Created a texture (name " << *mainTexture << ")" << TestLog::EndMessage;
2858 	if (m_imageType == TEXTURETYPE_BUFFER)
2859 		log << TestLog::Message << "// Created a buffer for the texture (name " << *mainTextureBuf << ")" << TestLog::EndMessage;
2860 	log << TestLog::Message << "// Created a texture (name " << *shaderOutResultTexture << ") for storing the shader output" << TestLog::EndMessage;
2861 
2862 	glLog.glActiveTexture(GL_TEXTURE0);
2863 	glLog.glBindTexture(textureTargetGL, *mainTexture);
2864 	setTexParameteri(glLog, textureTargetGL);
2865 	setTextureStorage(glLog, m_imageType, internalFormatGL, m_imageSize, *mainTextureBuf);
2866 	glLog.glBindImageTexture(0, *mainTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
2867 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2868 
2869 	glLog.glActiveTexture(GL_TEXTURE1);
2870 	glLog.glBindTexture(GL_TEXTURE_2D, *shaderOutResultTexture);
2871 	setTexParameteri(glLog, GL_TEXTURE_2D);
2872 	setTextureStorage(glLog, TEXTURETYPE_2D, GL_R32UI, IVec3(1, 1, 1), 0 /* always 2d texture, no buffer needed */);
2873 	glLog.glBindImageTexture(1, *shaderOutResultTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
2874 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2875 
2876 	// Read texture size in compute shader.
2877 
2878 	{
2879 		// Generate compute shader.
2880 
2881 		const char* const	shaderImageAccessStr	= m_imageAccess == IMAGEACCESS_READ_ONLY			? "readonly"
2882 													: m_imageAccess == IMAGEACCESS_WRITE_ONLY			? "writeonly"
2883 													: m_imageAccess == IMAGEACCESS_READ_ONLY_WRITE_ONLY	? "readonly writeonly"
2884 													: DE_NULL;
2885 		const string		shaderImageFormatStr	= getShaderImageFormatQualifier(m_format);
2886 		const string		shaderImageTypeStr		= getShaderImageType(m_format.type, m_imageType);
2887 		const string		glslVersionDeclaration	= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
2888 
2889 		const glu::ShaderProgram program(renderCtx,
2890 			glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2891 														+ textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2892 														"\n"
2893 														"precision highp " + shaderImageTypeStr + ";\n"
2894 														"precision highp uimage2D;\n"
2895 														"\n"
2896 														"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2897 														"layout (" + shaderImageFormatStr + ", binding=0) " + shaderImageAccessStr + " uniform " + shaderImageTypeStr + " u_image;\n"
2898 														"layout (r32ui, binding=1) writeonly uniform uimage2D u_result;\n"
2899 														"void main (void)\n"
2900 														"{\n"
2901 														+ (m_imageType == TEXTURETYPE_BUFFER ?
2902 															"	int result = imageSize(u_image);\n"
2903 														 : m_imageType == TEXTURETYPE_2D || m_imageType == TEXTURETYPE_CUBE ?
2904 															"	ivec2 size = imageSize(u_image);\n"
2905 															"	int result = size.y*1000 + size.x;\n"
2906 														 : m_imageType == TEXTURETYPE_3D || m_imageType == TEXTURETYPE_2D_ARRAY ?
2907 															"	ivec3 size = imageSize(u_image);\n"
2908 															"	int result = size.z*1000000 + size.y*1000 + size.x;\n"
2909 														 : DE_NULL) +
2910 														"	imageStore(u_result, ivec2(0, 0), uvec4(result));\n"
2911 														"}\n"));
2912 
2913 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2914 
2915 		log << program;
2916 
2917 		if (!program.isOk())
2918 		{
2919 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2920 			return STOP;
2921 		}
2922 
2923 		// Setup and dispatch.
2924 
2925 		glLog.glUseProgram(program.getProgram());
2926 
2927 		glLog.glDispatchCompute(1, 1, 1);
2928 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2929 	}
2930 
2931 	// Read texture and compare to reference.
2932 
2933 	{
2934 		const deUint32	referenceOutput		= m_imageType == TEXTURETYPE_BUFFER										? (deUint32)(												  m_imageSize.x())
2935 											: m_imageType == TEXTURETYPE_2D || m_imageType == TEXTURETYPE_CUBE		? (deUint32)(						   m_imageSize.y()*1000 + m_imageSize.x())
2936 											: m_imageType == TEXTURETYPE_3D || m_imageType == TEXTURETYPE_2D_ARRAY	? (deUint32)(m_imageSize.z()*1000000 + m_imageSize.y()*1000 + m_imageSize.x())
2937 											: (deUint32)-1;
2938 
2939 		if (readIntegerTextureViaFBOAndVerify(renderCtx, glLog, *shaderOutResultTexture, TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32),
2940 											  IVec3(1, 1, 1), R32UIImageSingleValueVerifier(referenceOutput)))
2941 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2942 		else
2943 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value");
2944 
2945 		return STOP;
2946 	}
2947 }
2948 
2949 //! Case testing the control over early/late fragment tests.
2950 class EarlyFragmentTestsCase : public TestCase
2951 {
2952 public:
2953 	enum TestType
2954 	{
2955 		TESTTYPE_DEPTH = 0,
2956 		TESTTYPE_STENCIL,
2957 
2958 		TESTTYPE_LAST
2959 	};
2960 
2961 	enum RenderTargetType
2962 	{
2963 		RENDERTARGET_DEFAULT = 0,
2964 		RENDERTARGET_FBO,
2965 		RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT,
2966 
2967 		RENDERTARGET_LAST
2968 	};
2969 
2970 
EarlyFragmentTestsCase(Context & context,const char * name,const char * description,TestType type,bool useEarlyTests,RenderTargetType renderTarget)2971 	EarlyFragmentTestsCase (Context& context, const char* name, const char* description, TestType type, bool useEarlyTests, RenderTargetType renderTarget)
2972 		: TestCase			(context, name, description)
2973 		, m_type			(type)
2974 		, m_useEarlyTests	(useEarlyTests)
2975 		, m_renderTarget	(renderTarget)
2976 	{
2977 	}
2978 
init(void)2979 	void init (void)
2980 	{
2981 		if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) == 0)
2982 			throw tcu::NotSupportedError("GL_MAX_FRAGMENT_IMAGE_UNIFORMS is zero");
2983 
2984 		if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic") && !supportsES32orGL45(m_context.getRenderContext()))
2985 			throw tcu::NotSupportedError("Test requires OES_shader_image_atomic extension");
2986 
2987 		if (m_type == TESTTYPE_DEPTH				&&
2988 			m_renderTarget == RENDERTARGET_DEFAULT	&&
2989 			m_context.getRenderTarget().getDepthBits() == 0)
2990 		{
2991 			throw tcu::NotSupportedError("Test requires depth buffer");
2992 		}
2993 
2994 		if (m_type == TESTTYPE_STENCIL				&&
2995 			m_renderTarget == RENDERTARGET_DEFAULT	&&
2996 			m_context.getRenderTarget().getStencilBits() == 0)
2997 		{
2998 			throw tcu::NotSupportedError("Test requires stencil buffer");
2999 		}
3000 
3001 		if (m_renderTarget == RENDERTARGET_DEFAULT	&&
3002 			(m_context.getRenderTarget().getWidth() < RENDER_SIZE || m_context.getRenderTarget().getHeight() < RENDER_SIZE))
3003 			throw tcu::NotSupportedError("Render target must have at least " + toString(RENDER_SIZE) + " width and height");
3004 	}
3005 
3006 	IterateResult iterate (void);
3007 
3008 private:
3009 	static const int		RENDER_SIZE;
3010 
3011 	const TestType			m_type;
3012 	const bool				m_useEarlyTests;
3013 	const RenderTargetType	m_renderTarget;
3014 };
3015 
3016 const int EarlyFragmentTestsCase::RENDER_SIZE = 32;
3017 
iterate(void)3018 EarlyFragmentTestsCase::IterateResult EarlyFragmentTestsCase::iterate (void)
3019 {
3020 	const RenderContext&			renderCtx			= m_context.getRenderContext();
3021 	TestLog&						log					(m_testCtx.getLog());
3022 	glu::CallLogWrapper				glLog				(renderCtx.getFunctions(), log);
3023 	de::Random						rnd					(deStringHash(getName()));
3024 	const bool						expectPartialResult	= m_useEarlyTests && m_renderTarget != RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT;
3025 	const int						viewportWidth		= RENDER_SIZE;
3026 	const int						viewportHeight		= RENDER_SIZE;
3027 	const int						viewportX			= (m_renderTarget == RENDERTARGET_DEFAULT) ? (rnd.getInt(0, renderCtx.getRenderTarget().getWidth() - viewportWidth))	: (0);
3028 	const int						viewportY			= (m_renderTarget == RENDERTARGET_DEFAULT) ? (rnd.getInt(0, renderCtx.getRenderTarget().getHeight() - viewportHeight))	: (0);
3029 	const glu::Texture				texture				(renderCtx);
3030 	de::MovePtr<glu::Framebuffer>	fbo;
3031 	de::MovePtr<glu::Renderbuffer>	colorAttachment;
3032 	de::MovePtr<glu::Renderbuffer>	testAttachment;
3033 
3034 	glLog.enableLogging(true);
3035 
3036 	// Setup texture.
3037 
3038 	log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
3039 
3040 	glLog.glActiveTexture(GL_TEXTURE0);
3041 	glLog.glBindTexture(GL_TEXTURE_2D, *texture);
3042 	setTexParameteri(glLog, GL_TEXTURE_2D);
3043 	{
3044 		LayeredImage src(TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32), 1, 1, 1);
3045 		src.setPixel(0, 0, 0, IVec4(0));
3046 		uploadTexture(glLog, src, 0 /* always 2d texture, no buffer needed */);
3047 	}
3048 	glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32UI);
3049 	GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
3050 
3051 	// Set up framebuffer
3052 	if (m_renderTarget == RENDERTARGET_FBO ||
3053 		m_renderTarget == RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT)
3054 	{
3055 		fbo				= de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(renderCtx));
3056 		colorAttachment	= de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx));
3057 		testAttachment	= de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx));
3058 
3059 		glLog.glBindRenderbuffer(GL_RENDERBUFFER, **colorAttachment);
3060 		glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE);
3061 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen color attachment rb");
3062 
3063 		glLog.glBindFramebuffer(GL_FRAMEBUFFER, **fbo);
3064 		glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **colorAttachment);
3065 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo color attachment");
3066 
3067 		if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_DEPTH)
3068 		{
3069 			glLog.glBindRenderbuffer(GL_RENDERBUFFER, **testAttachment);
3070 			glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, RENDER_SIZE, RENDER_SIZE);
3071 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen depth attachment rb");
3072 
3073 			glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, **testAttachment);
3074 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo depth attachment");
3075 		}
3076 		else if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_STENCIL)
3077 		{
3078 			glLog.glBindRenderbuffer(GL_RENDERBUFFER, **testAttachment);
3079 			glLog.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, RENDER_SIZE, RENDER_SIZE);
3080 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "gen stencil attachment rb");
3081 
3082 			glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, **testAttachment);
3083 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo stencil attachment");
3084 		}
3085 
3086 		glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **colorAttachment);
3087 		GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "setup fbo");
3088 		TCU_CHECK(glLog.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
3089 	}
3090 
3091 	// Set up appropriate conditions for the test.
3092 
3093 	glLog.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
3094 	glLog.glClear(GL_COLOR_BUFFER_BIT);
3095 
3096 	if (m_type == TESTTYPE_DEPTH)
3097 	{
3098 		glLog.glClearDepthf(0.5f);
3099 		glLog.glClear(GL_DEPTH_BUFFER_BIT);
3100 		glLog.glEnable(GL_DEPTH_TEST);
3101 	}
3102 	else if (m_type == TESTTYPE_STENCIL)
3103 	{
3104 		glLog.glClearStencil(0);
3105 		glLog.glClear(GL_STENCIL_BUFFER_BIT);
3106 		glLog.glScissor(viewportX, viewportY, viewportWidth/2, viewportHeight);
3107 		glLog.glEnable(GL_SCISSOR_TEST);
3108 		glLog.glClearStencil(1);
3109 		glLog.glClear(GL_STENCIL_BUFFER_BIT);
3110 		glLog.glDisable(GL_SCISSOR_TEST);
3111 		glLog.glStencilFunc(GL_EQUAL, 1, 1);
3112 		glLog.glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3113 		glLog.glEnable(GL_STENCIL_TEST);
3114 	}
3115 	else
3116 		DE_ASSERT(false);
3117 
3118 	// Perform image stores in fragment shader.
3119 
3120 	{
3121 		const std::string glslVersionDeclaration = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
3122 
3123 		// Generate fragment shader.
3124 
3125 		const glu::ShaderProgram program(renderCtx,
3126 			glu::ProgramSources() << glu::VertexSource(		glslVersionDeclaration + "\n"
3127 															"\n"
3128 															"highp in vec3 a_position;\n"
3129 															"\n"
3130 															"void main (void)\n"
3131 															"{\n"
3132 															"	gl_Position = vec4(a_position, 1.0);\n"
3133 															"}\n")
3134 
3135 								  << glu::FragmentSource(	glslVersionDeclaration + "\n"
3136 															+ imageAtomicExtensionShaderRequires(renderCtx) +
3137 															"\n"
3138 															+ string(m_useEarlyTests ? "layout (early_fragment_tests) in;\n\n" : "") +
3139 															"layout (location = 0) out highp vec4 o_color;\n"
3140 															"\n"
3141 															"precision highp uimage2D;\n"
3142 															"\n"
3143 															"layout (r32ui, binding=0) coherent uniform uimage2D u_image;\n"
3144 															"\n"
3145 															"void main (void)\n"
3146 															"{\n"
3147 															"	imageAtomicAdd(u_image, ivec2(0, 0), uint(1));\n"
3148 															"	o_color = vec4(1.0);\n"
3149 															"}\n"));
3150 
3151 		UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
3152 
3153 		log << program;
3154 
3155 		if (!program.isOk())
3156 		{
3157 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
3158 			return STOP;
3159 		}
3160 
3161 		// Setup and draw full-viewport quad.
3162 
3163 		glLog.glUseProgram(program.getProgram());
3164 
3165 		{
3166 			static const float vertexPositions[4*3] =
3167 			{
3168 				-1.0, -1.0, -1.0f,
3169 				 1.0, -1.0,  0.0f,
3170 				-1.0,  1.0,  0.0f,
3171 				 1.0,  1.0,  1.0f,
3172 			};
3173 
3174 			static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 };
3175 
3176 			const glu::VertexArrayBinding attrBindings[] =
3177 			{
3178 				glu::va::Float("a_position", 3, 4, 0, &vertexPositions[0])
3179 			};
3180 
3181 			glLog.glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
3182 
3183 			glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3184 				glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
3185 			GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Draw failed");
3186 		}
3187 	}
3188 
3189 	// Log rendered result for convenience.
3190 	{
3191 		tcu::Surface rendered(viewportWidth, viewportHeight);
3192 		glu::readPixels(renderCtx, viewportX, viewportY, rendered.getAccess());
3193 		log << TestLog::Image("Rendered", "Rendered image", rendered);
3194 	}
3195 
3196 	// Read counter value and check.
3197 	{
3198 		const int numSamples		= de::max(1, renderCtx.getRenderTarget().getNumSamples());
3199 		const int expectedCounter	= expectPartialResult ? viewportWidth*viewportHeight/2				: viewportWidth*viewportHeight;
3200 		const int tolerance			= expectPartialResult ? de::max(viewportWidth, viewportHeight)*3	: 0;
3201 		const int expectedMin		= de::max(0, expectedCounter - tolerance);
3202 		const int expectedMax		= (expectedCounter + tolerance) * numSamples;
3203 
3204 		if (readIntegerTextureViaFBOAndVerify(renderCtx, glLog, *texture, TEXTURETYPE_2D, TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32),
3205 											  IVec3(1, 1, 1), R32UIImageSingleValueVerifier(expectedMin, expectedMax)))
3206 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3207 		else
3208 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value");
3209 
3210 		return STOP;
3211 	}
3212 }
3213 
3214 } // anonymous
3215 
ShaderImageLoadStoreTests(Context & context)3216 ShaderImageLoadStoreTests::ShaderImageLoadStoreTests (Context& context)
3217 	: TestCaseGroup(context, "image_load_store", "Shader Image Load & Store Tests")
3218 {
3219 }
3220 
~ShaderImageLoadStoreTests(void)3221 ShaderImageLoadStoreTests::~ShaderImageLoadStoreTests (void)
3222 {
3223 }
3224 
init(void)3225 void ShaderImageLoadStoreTests::init (void)
3226 {
3227 	// Per-image-type tests.
3228 
3229 	{
3230 		static const TextureType imageTypes[] =
3231 		{
3232 			TEXTURETYPE_2D,
3233 			TEXTURETYPE_CUBE,
3234 			TEXTURETYPE_3D,
3235 			TEXTURETYPE_2D_ARRAY,
3236 			TEXTURETYPE_BUFFER
3237 		};
3238 
3239 		static const TextureFormat formats[] =
3240 		{
3241 			TextureFormat(TextureFormat::RGBA,	TextureFormat::FLOAT),
3242 			TextureFormat(TextureFormat::RGBA,	TextureFormat::HALF_FLOAT),
3243 			TextureFormat(TextureFormat::R,		TextureFormat::FLOAT),
3244 
3245 			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT32),
3246 			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT16),
3247 			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT8),
3248 			TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT32),
3249 
3250 			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT32),
3251 			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT16),
3252 			TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT8),
3253 			TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT32),
3254 
3255 			TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8),
3256 
3257 			TextureFormat(TextureFormat::RGBA,	TextureFormat::SNORM_INT8)
3258 		};
3259 
3260 		for (int imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageTypes); imageTypeNdx++)
3261 		{
3262 			const TextureType		imageType			= imageTypes[imageTypeNdx];
3263 			TestCaseGroup* const	imageTypeGroup		= new TestCaseGroup(m_context, getTextureTypeName(imageType), "");
3264 			addChild(imageTypeGroup);
3265 
3266 			TestCaseGroup* const	storeGroup			= new TestCaseGroup(m_context, "store",					"Plain imageStore() cases");
3267 			TestCaseGroup* const	loadStoreGroup		= new TestCaseGroup(m_context, "load_store",			"Cases with imageLoad() followed by imageStore()");
3268 			TestCaseGroup* const	atomicGroup			= new TestCaseGroup(m_context, "atomic",				"Atomic image operation cases");
3269 			TestCaseGroup* const	qualifierGroup		= new TestCaseGroup(m_context, "qualifiers",			"Coherent, volatile and restrict");
3270 			TestCaseGroup* const	reinterpretGroup	= new TestCaseGroup(m_context, "format_reinterpret",	"Cases with differing texture and image formats");
3271 			TestCaseGroup* const	imageSizeGroup		= new TestCaseGroup(m_context, "image_size",			"imageSize() cases");
3272 			imageTypeGroup->addChild(storeGroup);
3273 			imageTypeGroup->addChild(loadStoreGroup);
3274 			imageTypeGroup->addChild(atomicGroup);
3275 			imageTypeGroup->addChild(qualifierGroup);
3276 			imageTypeGroup->addChild(reinterpretGroup);
3277 			imageTypeGroup->addChild(imageSizeGroup);
3278 
3279 			for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
3280 			{
3281 				const TextureFormat&	format		= formats[formatNdx];
3282 				const string			formatName	= getShaderImageFormatQualifier(formats[formatNdx]);
3283 
3284 				if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(format))
3285 					continue;
3286 
3287 				// Store cases.
3288 
3289 				storeGroup->addChild(new ImageStoreCase(m_context, formatName.c_str(), "", format, imageType));
3290 				if (textureLayerType(imageType) != imageType)
3291 					storeGroup->addChild(new ImageStoreCase(m_context, (formatName + "_single_layer").c_str(), "", format, imageType, ImageStoreCase::CASEFLAG_SINGLE_LAYER_BIND));
3292 
3293 				// Load & store.
3294 
3295 				loadStoreGroup->addChild(new ImageLoadAndStoreCase(m_context, formatName.c_str(), "", format, imageType));
3296 				if (textureLayerType(imageType) != imageType)
3297 					loadStoreGroup->addChild(new ImageLoadAndStoreCase(m_context, (formatName + "_single_layer").c_str(), "", format, imageType, ImageLoadAndStoreCase::CASEFLAG_SINGLE_LAYER_BIND));
3298 
3299 				if (format.order == TextureFormat::R)
3300 				{
3301 					// Atomic operations.
3302 
3303 					for (int operationI = 0; operationI < ATOMIC_OPERATION_LAST; operationI++)
3304 					{
3305 						for (int atomicCaseTypeI = 0; atomicCaseTypeI < ATOMIC_OPERATION_CASE_TYPE_LAST; atomicCaseTypeI++)
3306 						{
3307 							const AtomicOperation operation = (AtomicOperation)operationI;
3308 
3309 							if (format.type == TextureFormat::FLOAT && operation != ATOMIC_OPERATION_EXCHANGE)
3310 								continue;
3311 
3312 							const AtomicOperationCaseType	caseType		= (AtomicOperationCaseType)atomicCaseTypeI;
3313 							const string					caseTypeName	= caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT		? "result"
3314 																			: caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES	? "return_value"
3315 																			: DE_NULL;
3316 							const string					caseName		= string() + getAtomicOperationCaseName(operation) + "_" + formatName + "_" + caseTypeName;
3317 
3318 							if (operation == ATOMIC_OPERATION_COMP_SWAP)
3319 								atomicGroup->addChild(new AtomicCompSwapCase(m_context, caseName.c_str(), "", format, imageType, caseType));
3320 							else
3321 								atomicGroup->addChild(new BinaryAtomicOperationCase(m_context, caseName.c_str(), "", format, imageType, operation, caseType));
3322 						}
3323 					}
3324 
3325 					// Coherence.
3326 
3327 					for (int coherenceQualifierI = 0; coherenceQualifierI < CoherenceCase::QUALIFIER_LAST; coherenceQualifierI++)
3328 					{
3329 						const CoherenceCase::Qualifier	coherenceQualifier		= (CoherenceCase::Qualifier)coherenceQualifierI;
3330 						const char* const				coherenceQualifierName	= coherenceQualifier == CoherenceCase::QUALIFIER_COHERENT ? "coherent"
3331 																				: coherenceQualifier == CoherenceCase::QUALIFIER_VOLATILE ? "volatile"
3332 																				: DE_NULL;
3333 						const string					caseName				= string() + coherenceQualifierName + "_" + formatName;
3334 
3335 						qualifierGroup->addChild(new CoherenceCase(m_context, caseName.c_str(), "", format, imageType, coherenceQualifier));
3336 					}
3337 				}
3338 			}
3339 
3340 			// Restrict.
3341 			qualifierGroup->addChild(new ImageLoadAndStoreCase(m_context, "restrict", "", TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), imageType, ImageLoadAndStoreCase::CASEFLAG_RESTRICT_IMAGES));
3342 
3343 			// Format re-interpretation.
3344 
3345 			for (int texFmtNdx = 0; texFmtNdx < DE_LENGTH_OF_ARRAY(formats); texFmtNdx++)
3346 			for (int imgFmtNdx = 0; imgFmtNdx < DE_LENGTH_OF_ARRAY(formats); imgFmtNdx++)
3347 			{
3348 				const TextureFormat& texFmt = formats[texFmtNdx];
3349 				const TextureFormat& imgFmt = formats[imgFmtNdx];
3350 
3351 				if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(texFmt))
3352 					continue;
3353 
3354 				if (texFmt != imgFmt && texFmt.getPixelSize() == imgFmt.getPixelSize())
3355 					reinterpretGroup->addChild(new ImageLoadAndStoreCase(m_context,
3356 																		 (getShaderImageFormatQualifier(texFmt) + "_" + getShaderImageFormatQualifier(imgFmt)).c_str(), "",
3357 																		 texFmt, imgFmt, imageType));
3358 			}
3359 
3360 			// imageSize().
3361 
3362 			{
3363 				static const IVec3 baseImageSizes[] =
3364 				{
3365 					IVec3(32, 32, 32),
3366 					IVec3(12, 34, 56),
3367 					IVec3(1,   1,  1),
3368 					IVec3(7,   1,  1)
3369 				};
3370 
3371 				for (int imageAccessI = 0; imageAccessI < ImageSizeCase::IMAGEACCESS_LAST; imageAccessI++)
3372 				{
3373 					const ImageSizeCase::ImageAccess	imageAccess		= (ImageSizeCase::ImageAccess)imageAccessI;
3374 					const char* const					imageAccessStr	= imageAccess == ImageSizeCase::IMAGEACCESS_READ_ONLY				? "readonly"
3375 																		: imageAccess == ImageSizeCase::IMAGEACCESS_WRITE_ONLY				? "writeonly"
3376 																		: imageAccess == ImageSizeCase::IMAGEACCESS_READ_ONLY_WRITE_ONLY	? "readonly_writeonly"
3377 																		: deFatalStr("Invalid ImageAccess");
3378 
3379 					for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(baseImageSizes); imageSizeNdx++)
3380 					{
3381 						const IVec3&	baseSize	= baseImageSizes[imageSizeNdx];
3382 						const IVec3		imageSize	= imageType == TEXTURETYPE_BUFFER		? IVec3(baseSize.x(), 1, 1)
3383 													: imageType == TEXTURETYPE_2D			? IVec3(baseSize.x(), baseSize.y(), 1)
3384 													: imageType == TEXTURETYPE_CUBE			? IVec3(baseSize.x(), baseSize.x(), 1)
3385 													: imageType == TEXTURETYPE_3D			? baseSize
3386 													: imageType == TEXTURETYPE_2D_ARRAY		? baseSize
3387 													: IVec3(-1, -1, -1);
3388 
3389 						const string	sizeStr		= imageType == TEXTURETYPE_BUFFER		? toString(imageSize.x())
3390 													: imageType == TEXTURETYPE_2D			? toString(imageSize.x()) + "x" + toString(imageSize.y())
3391 													: imageType == TEXTURETYPE_CUBE			? toString(imageSize.x()) + "x" + toString(imageSize.y())
3392 													: imageType == TEXTURETYPE_3D			? toString(imageSize.x()) + "x" + toString(imageSize.y()) + "x" + toString(imageSize.z())
3393 													: imageType == TEXTURETYPE_2D_ARRAY		? toString(imageSize.x()) + "x" + toString(imageSize.y()) + "x" + toString(imageSize.z())
3394 													: deFatalStr("Invalid TextureType");
3395 
3396 						const string	caseName	= string() + imageAccessStr + "_" + sizeStr;
3397 
3398 						imageSizeGroup->addChild(new ImageSizeCase(m_context, caseName.c_str(), "", TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), imageType, imageSize, imageAccess));
3399 					}
3400 				}
3401 			}
3402 		}
3403 	}
3404 
3405 	// early_fragment_tests cases.
3406 
3407 	{
3408 		TestCaseGroup* const earlyTestsGroup = new TestCaseGroup(m_context, "early_fragment_tests", "");
3409 		addChild(earlyTestsGroup);
3410 
3411 		for (int testRenderTargetI = 0; testRenderTargetI < EarlyFragmentTestsCase::RENDERTARGET_LAST; testRenderTargetI++)
3412 		for (int useEarlyTestsI = 0; useEarlyTestsI <= 1; useEarlyTestsI++)
3413 		for (int testTypeI = 0; testTypeI < EarlyFragmentTestsCase::TESTTYPE_LAST; testTypeI++)
3414 		{
3415 			const EarlyFragmentTestsCase::RenderTargetType	targetType		= (EarlyFragmentTestsCase::RenderTargetType)testRenderTargetI;
3416 			const bool										useEarlyTests	= useEarlyTestsI != 0;
3417 			const EarlyFragmentTestsCase::TestType			testType		= (EarlyFragmentTestsCase::TestType)testTypeI;
3418 
3419 			const string									testTypeName	= testType == EarlyFragmentTestsCase::TESTTYPE_DEPTH	? "depth"
3420 																			: testType == EarlyFragmentTestsCase::TESTTYPE_STENCIL	? "stencil"
3421 																			: DE_NULL;
3422 
3423 			const string									targetName		= targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO							? (std::string("_fbo"))
3424 																			: targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT	? (std::string("_fbo_with_no_") + testTypeName)
3425 																			: std::string("");
3426 
3427 			const string									caseName		= string(useEarlyTests ? "" : "no_") + "early_fragment_tests_" + testTypeName + targetName;
3428 
3429 			const string									caseDesc		= string(useEarlyTests ? "Specify" : "Don't specify")
3430 																			+ " early_fragment_tests, use the " + testTypeName + " test"
3431 																			+ ((targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO)								? (", render to fbo")
3432 																			   : (targetType == EarlyFragmentTestsCase::RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT)	? (", render to fbo without relevant buffer")
3433 																			   : (""));
3434 
3435 			earlyTestsGroup->addChild(new EarlyFragmentTestsCase(m_context, caseName.c_str(), caseDesc.c_str(), testType, useEarlyTests, targetType));
3436 		}
3437 	}
3438 }
3439 
3440 } // Functional
3441 } // gles31
3442 } // deqp
3443