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