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