1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Shader Image Load & Store Tests.
22 *//*--------------------------------------------------------------------*/
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"
47 #include "glwFunctions.hpp"
48 #include "glwDefs.hpp"
49 #include "glwEnums.hpp"
56 using glu::RenderContext;
67 using tcu::TextureFormat;
68 using tcu::ConstPixelBufferAccess;
69 using tcu::PixelBufferAccess;
80 using namespace gls::TextureTestUtil;
81 using namespace glu::TextureTestUtil;
88 //! Default image sizes used in most test cases.
89 static inline IVec3 defaultImageSize (TextureType type)
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);
104 template <typename T, int Size>
105 static string arrayStr (const T (&arr)[Size])
107 string result = "{ ";
108 for (int i = 0; i < Size; i++)
109 result += (i > 0 ? ", " : "") + toString(arr[i]);
114 template <typename T, int N>
115 static int arrayIndexOf (const T (&arr)[N], const T& e)
117 return (int)(std::find(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr), e) - DE_ARRAY_BEGIN(arr));
120 static const char* getTextureTypeName (TextureType type)
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";
135 static inline bool isFormatTypeUnsignedInteger (TextureFormat::ChannelType type)
137 return type == TextureFormat::UNSIGNED_INT8 ||
138 type == TextureFormat::UNSIGNED_INT16 ||
139 type == TextureFormat::UNSIGNED_INT32;
142 static inline bool isFormatTypeSignedInteger (TextureFormat::ChannelType type)
144 return type == TextureFormat::SIGNED_INT8 ||
145 type == TextureFormat::SIGNED_INT16 ||
146 type == TextureFormat::SIGNED_INT32;
149 static inline bool isFormatTypeInteger (TextureFormat::ChannelType type)
151 return isFormatTypeUnsignedInteger(type) || isFormatTypeSignedInteger(type);
154 static inline bool isFormatTypeUnorm (TextureFormat::ChannelType type)
156 return type == TextureFormat::UNORM_INT8 ||
157 type == TextureFormat::UNORM_INT16 ||
158 type == TextureFormat::UNORM_INT32;
161 static inline bool isFormatTypeSnorm (TextureFormat::ChannelType type)
163 return type == TextureFormat::SNORM_INT8 ||
164 type == TextureFormat::SNORM_INT16 ||
165 type == TextureFormat::SNORM_INT32;
168 static inline bool isFormatSupportedForTextureBuffer (const TextureFormat& format)
170 switch (format.order)
172 case TextureFormat::RGB:
173 return format.type == TextureFormat::FLOAT ||
174 format.type == TextureFormat::SIGNED_INT32 ||
175 format.type == TextureFormat::UNSIGNED_INT32;
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;
196 static inline string getShaderImageFormatQualifier (const TextureFormat& format)
198 const char* orderPart;
199 const char* typePart;
201 switch (format.order)
203 case TextureFormat::R: orderPart = "r"; break;
204 case TextureFormat::RGBA: orderPart = "rgba"; break;
212 case TextureFormat::FLOAT: typePart = "32f"; break;
213 case TextureFormat::HALF_FLOAT: typePart = "16f"; break;
215 case TextureFormat::UNSIGNED_INT32: typePart = "32ui"; break;
216 case TextureFormat::UNSIGNED_INT16: typePart = "16ui"; break;
217 case TextureFormat::UNSIGNED_INT8: typePart = "8ui"; break;
219 case TextureFormat::SIGNED_INT32: typePart = "32i"; break;
220 case TextureFormat::SIGNED_INT16: typePart = "16i"; break;
221 case TextureFormat::SIGNED_INT8: typePart = "8i"; break;
223 case TextureFormat::UNORM_INT16: typePart = "16"; break;
224 case TextureFormat::UNORM_INT8: typePart = "8"; break;
226 case TextureFormat::SNORM_INT16: typePart = "16_snorm"; break;
227 case TextureFormat::SNORM_INT8: typePart = "8_snorm"; break;
234 return string() + orderPart + typePart;
237 static inline string getShaderSamplerOrImageType (TextureFormat::ChannelType formatType, TextureType textureType, bool isSampler)
239 const char* const formatPart = isFormatTypeUnsignedInteger(formatType) ? "u"
240 : isFormatTypeSignedInteger(formatType) ? "i"
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"
250 return string() + formatPart + (isSampler ? "sampler" : "image") + imageTypePart;
253 static inline string getShaderImageType (TextureFormat::ChannelType formatType, TextureType imageType)
255 return getShaderSamplerOrImageType(formatType, imageType, false);
258 static inline string getShaderSamplerType (TextureFormat::ChannelType formatType, TextureType imageType)
260 return getShaderSamplerOrImageType(formatType, imageType, true);
263 static inline deUint32 getGLTextureTarget (TextureType texType)
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;
278 static deUint32 cubeFaceToGLFace (tcu::CubeFace face)
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;
294 static inline tcu::Texture1D* newOneLevelTexture1D (const tcu::TextureFormat& format, int w)
296 tcu::Texture1D* const res = new tcu::Texture1D(format, w);
301 static inline tcu::Texture2D* newOneLevelTexture2D (const tcu::TextureFormat& format, int w, int h)
303 tcu::Texture2D* const res = new tcu::Texture2D(format, w, h);
308 static inline tcu::TextureCube* newOneLevelTextureCube (const tcu::TextureFormat& format, int size)
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);
316 static inline tcu::Texture3D* newOneLevelTexture3D (const tcu::TextureFormat& format, int w, int h, int d)
318 tcu::Texture3D* const res = new tcu::Texture3D(format, w, h, d);
323 static inline tcu::Texture2DArray* newOneLevelTexture2DArray (const tcu::TextureFormat& format, int w, int h, int d)
325 tcu::Texture2DArray* const res = new tcu::Texture2DArray(format, w, h, d);
330 static inline TextureType textureLayerType (TextureType entireTextureType)
332 switch (entireTextureType)
334 // Single-layer types.
335 // \note Fallthrough.
336 case TEXTURETYPE_BUFFER:
338 return entireTextureType;
340 // Multi-layer types with 2d layers.
342 case TEXTURETYPE_CUBE:
343 case TEXTURETYPE_2D_ARRAY:
344 return TEXTURETYPE_2D;
348 return TEXTURETYPE_LAST;
352 static const char* const s_texBufExtString = "GL_EXT_texture_buffer";
354 static inline void checkTextureTypeExtensions (const glu::ContextInfo& contextInfo, TextureType type, const RenderContext& renderContext)
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");
360 static inline string textureTypeExtensionShaderRequires (TextureType type, const RenderContext& renderContext)
362 if (!glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)) && (type == TEXTURETYPE_BUFFER))
363 return "#extension " + string(s_texBufExtString) + " : require\n";
368 static const char* const s_imageAtomicExtString = "GL_OES_shader_image_atomic";
370 static inline string imageAtomicExtensionShaderRequires (const RenderContext& renderContext)
372 if (!glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)))
373 return "#extension " + string(s_imageAtomicExtString) + " : require\n";
383 ATOMIC_OPERATION_ADD = 0,
384 ATOMIC_OPERATION_MIN,
385 ATOMIC_OPERATION_MAX,
386 ATOMIC_OPERATION_AND,
388 ATOMIC_OPERATION_XOR,
389 ATOMIC_OPERATION_EXCHANGE,
390 ATOMIC_OPERATION_COMP_SWAP,
392 ATOMIC_OPERATION_LAST
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)
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;
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)
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;
424 //! \note For floats, only the exchange operation is supported.
425 float computeBinaryAtomicOperationResult (AtomicOperation op, float /*a*/, float b)
429 case ATOMIC_OPERATION_EXCHANGE: return b;
436 static const char* getAtomicOperationCaseName (AtomicOperation op)
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";
454 static const char* getAtomicOperationShaderFuncName (AtomicOperation op)
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";
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)
476 static const tcu::CubeFace faces[6] =
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
486 DE_ASSERT(de::inBounds(z, 0, DE_LENGTH_OF_ARRAY(faces)));
493 BufferMemMap (const glw::Functions& gl, deUint32 target, int offset, int size, deUint32 access)
498 m_ptr = gl.mapBufferRange(target, offset, size, access);
499 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
505 m_gl.unmapBuffer(m_target);
508 void* getPtr (void) const { return m_ptr; }
509 void* operator* (void) const { return m_ptr; }
512 BufferMemMap (const BufferMemMap& other);
513 BufferMemMap& operator= (const BufferMemMap& other);
515 const glw::Functions& m_gl;
516 const deUint32 m_target;
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
525 UniformAccessLogger (const glw::Functions& gl, TestLog& log, deUint32 programGL)
528 , m_programGL (programGL)
532 void assign1i (const string& name, int x);
533 void assign3f (const string& name, float x, float y, float z);
536 int getLocation (const string& name);
538 const glw::Functions& m_gl;
540 const deUint32 m_programGL;
542 std::map<string, int> m_uniformLocations;
545 int UniformAccessLogger::getLocation (const string& name)
547 if (m_uniformLocations.find(name) == m_uniformLocations.end())
549 const int loc = m_gl.getUniformLocation(m_programGL, name.c_str());
550 TCU_CHECK(loc != -1);
551 m_uniformLocations[name] = loc;
553 return m_uniformLocations[name];
556 void UniformAccessLogger::assign1i (const string& name, int x)
558 const int loc = getLocation(name);
559 m_log << TestLog::Message << "// Assigning to uniform " << name << ": " << x << TestLog::EndMessage;
560 m_gl.uniform1i(loc, x);
563 void UniformAccessLogger::assign3f (const string& name, float x, float y, float z)
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);
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.
574 LayeredImage (TextureType type, const TextureFormat& format, int w, int h, int d);
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; }
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.
582 template <typename ColorT>
583 void setPixel (int x, int y, int z, const ColorT& color) const;
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(); }
589 PixelBufferAccess getAccess (void) { return getAccessInternal(); }
590 PixelBufferAccess getSliceAccess (int slice) { return getSliceAccessInternal(slice); }
591 PixelBufferAccess getCubeFaceAccess (tcu::CubeFace face) { return getCubeFaceAccessInternal(face); }
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); }
598 LayeredImage (const LayeredImage&);
599 LayeredImage& operator= (const LayeredImage&);
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;
606 const TextureType m_type;
608 const TextureFormat m_format;
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;
618 LayeredImage::LayeredImage (TextureType type, const TextureFormat& format, int w, int h, int d)
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>())
628 DE_ASSERT(m_size.z() == 1 ||
629 m_type == TEXTURETYPE_3D ||
630 m_type == TEXTURETYPE_2D_ARRAY);
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);
638 DE_ASSERT(w == h || type != TEXTURETYPE_CUBE);
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);
647 template <typename ColorT>
648 void LayeredImage::setPixel (int x, int y, int z, const ColorT& color) const
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();
657 access.setPixel(color, x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
660 Vec4 LayeredImage::getPixel (int x, int y, int z) const
662 const ConstPixelBufferAccess access = m_type == TEXTURETYPE_CUBE ? getCubeFaceAccess(glslImageFuncZToCubeFace(z)) : getAccess();
663 return access.getPixel(x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
666 IVec4 LayeredImage::getPixelInt (int x, int y, int z) const
668 const ConstPixelBufferAccess access = m_type == TEXTURETYPE_CUBE ? getCubeFaceAccess(glslImageFuncZToCubeFace(z)) : getAccess();
669 return access.getPixelInt(x, y, m_type == TEXTURETYPE_CUBE ? 0 : z);
672 PixelBufferAccess LayeredImage::getAccessInternal (void) const
674 DE_ASSERT(m_type == TEXTURETYPE_BUFFER || m_type == TEXTURETYPE_2D || m_type == TEXTURETYPE_3D || m_type == TEXTURETYPE_2D_ARRAY);
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();
683 PixelBufferAccess LayeredImage::getSliceAccessInternal (int slice) const
685 const PixelBufferAccess srcAccess = getAccessInternal();
686 return tcu::getSubregion(srcAccess, 0, 0, slice, srcAccess.getWidth(), srcAccess.getHeight(), 1);
689 PixelBufferAccess LayeredImage::getCubeFaceAccessInternal (tcu::CubeFace face) const
691 DE_ASSERT(m_type == TEXTURETYPE_CUBE);
692 return m_texCube->getLevelFace(0, face);
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)
698 const deUint32 textureTarget = getGLTextureTarget(imageType);
702 case TEXTURETYPE_BUFFER:
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);
714 // \note Fall-throughs.
717 case TEXTURETYPE_CUBE:
718 glLog.glTexStorage2D(textureTarget, 1, internalFormat, imageSize.x(), imageSize.y());
719 DE_ASSERT(imageSize.z() == 1);
723 case TEXTURETYPE_2D_ARRAY:
724 glLog.glTexStorage3D(textureTarget, 1, internalFormat, imageSize.x(), imageSize.y(), imageSize.z());
732 static void uploadTexture (glu::CallLogWrapper& glLog, const LayeredImage& src, deUint32 textureBufGL)
734 const deUint32 internalFormat = glu::getInternalFormat(src.getFormat());
735 const glu::TransferFormat transferFormat = glu::getTransferFormat(src.getFormat());
736 const IVec3& imageSize = src.getSize();
738 setTextureStorage(glLog, src.getImageType(), internalFormat, imageSize, textureBufGL);
741 const int pixelSize = src.getFormat().getPixelSize();
744 if (deIsPowerOfTwo32(pixelSize))
749 glLog.glPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlignment);
752 if (src.getImageType() == TEXTURETYPE_BUFFER)
754 glLog.glBindBuffer(GL_TEXTURE_BUFFER, textureBufGL);
755 glLog.glBufferData(GL_TEXTURE_BUFFER, src.getFormat().getPixelSize() * imageSize.x(), src.getAccess().getDataPtr(), GL_STATIC_DRAW);
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)
761 for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++)
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());
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());
775 static void readPixelsRGBAInteger32 (const PixelBufferAccess& dst, int originX, int originY, glu::CallLogWrapper& glLog)
777 DE_ASSERT(dst.getDepth() == 1);
779 if (isFormatTypeUnsignedInteger(dst.getFormat().type))
781 vector<UVec4> data(dst.getWidth()*dst.getHeight());
783 glLog.glReadPixels(originX, originY, dst.getWidth(), dst.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]);
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);
789 else if (isFormatTypeSignedInteger(dst.getFormat().type))
791 vector<IVec4> data(dst.getWidth()*dst.getHeight());
793 glLog.glReadPixels(originX, originY, dst.getWidth(), dst.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]);
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);
803 //! Base for a functor for verifying and logging a 2d texture layer (2d image, cube face, 3d slice, 2d layer).
804 class ImageLayerVerifier
807 virtual bool operator() (TestLog&, const ConstPixelBufferAccess&, int sliceOrFaceNdx) const = 0;
808 virtual ~ImageLayerVerifier (void) {}
811 static void setTexParameteri (glu::CallLogWrapper& glLog, deUint32 target)
813 if (target != GL_TEXTURE_BUFFER)
815 glLog.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
816 glLog.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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,
825 TextureType textureType,
826 const TextureFormat& textureFormat,
827 const IVec3& textureSize,
828 const ImageLayerVerifier& verifyLayer)
830 DE_ASSERT(isFormatTypeInteger(textureFormat.type));
831 DE_ASSERT(textureType != TEXTURETYPE_BUFFER);
833 TestLog& log = glLog.getLog();
835 const tcu::ScopedLogSection section(log, "Verification", "Result verification (bind texture layer-by-layer to FBO, read with glReadPixels())");
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());
842 glLog.glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
843 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Bind FBO");
845 glLog.glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
846 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glMemoryBarrier");
848 glLog.glActiveTexture(GL_TEXTURE0);
849 glLog.glBindTexture(textureTargetGL, textureGL);
850 setTexParameteri(glLog, textureTargetGL);
852 for (int sliceOrFaceNdx = 0; sliceOrFaceNdx < numSlicesOrFaces; sliceOrFaceNdx++)
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);
863 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "Bind texture to framebuffer color attachment 0");
865 TCU_CHECK(glLog.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
867 readPixelsRGBAInteger32(resultSlice.getAccess(), 0, 0, glLog);
868 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glReadPixels");
870 if (!verifyLayer(log, resultSlice, sliceOrFaceNdx))
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,
882 TextureType textureType,
883 const TextureFormat& textureFormat,
884 const IVec3& textureSize,
885 const ImageLayerVerifier& verifyLayer)
887 DE_ASSERT(!isFormatTypeInteger(textureFormat.type));
888 DE_ASSERT(textureType != TEXTURETYPE_BUFFER);
890 TestLog& log = glLog.getLog();
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()));
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"
900 " vec4 color[" + toString(textureSize.x()*textureSize.y()) + "];\n"
903 "precision highp " + getShaderSamplerType(textureFormat.type, textureType) + ";\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"
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"
925 glLog.glUseProgram(program.getProgram());
931 log << TestLog::Message << "// Failure: failed to compile program" << TestLog::EndMessage;
932 TCU_FAIL("Program compilation failed");
936 const deUint32 textureTargetGL = getGLTextureTarget(textureType);
937 const glu::Buffer outputBuffer (renderCtx);
938 UniformAccessLogger uniforms (renderCtx.getFunctions(), log, program.getProgram());
942 glLog.glActiveTexture(GL_TEXTURE0);
943 glLog.glBindTexture(textureTargetGL, textureGL);
944 setTexParameteri(glLog, textureTargetGL);
946 uniforms.assign1i("u_texture", 0);
948 // Setup output buffer.
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);
953 log << TestLog::Message << "// Got buffer data size = " << blockSize << TestLog::EndMessage;
954 TCU_CHECK(blockSize > 0);
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");
962 // Dispatch one layer at a time, read back and verify.
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);
972 TCU_CHECK(valueInfo.arraySize == (deUint32)(textureSize.x()*textureSize.y()));
974 glLog.glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
976 for (int sliceOrFaceNdx = 0; sliceOrFaceNdx < numSlicesOrFaces; sliceOrFaceNdx++)
978 if (textureType == TEXTURETYPE_CUBE)
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]);
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);
998 glLog.glDispatchCompute(textureSize.x(), textureSize.y(), 1);
1001 log << TestLog::Message << "// Note: mapping buffer and reading color values written" << TestLog::EndMessage;
1003 const BufferMemMap bufMap(renderCtx.getFunctions(), GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT);
1005 for (int y = 0; y < textureSize.y(); y++)
1006 for (int x = 0; x < textureSize.x(); x++)
1008 const int ndx = y*textureSize.x() + x;
1009 const float* const clrData = (const float*)((const deUint8*)bufMap.getPtr() + valueInfo.offset + valueInfo.arrayStride*ndx);
1011 switch (textureFormat.order)
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;
1021 if (!verifyLayer(log, resultSliceAccess, sliceOrFaceNdx))
1030 //! Read buffer texture by reading the corresponding buffer with a mapping.
1031 static bool readBufferTextureWithMappingAndVerify (const RenderContext& renderCtx,
1032 glu::CallLogWrapper& glLog,
1034 const TextureFormat& textureFormat,
1036 const ImageLayerVerifier& verifyLayer)
1038 tcu::TextureLevel result (textureFormat, imageSize, 1);
1039 const PixelBufferAccess resultAccess = result.getAccess();
1040 const int dataSize = imageSize * textureFormat.getPixelSize();
1042 const tcu::ScopedLogSection section(glLog.getLog(), "Verification", "Result verification (read texture's buffer with a mapping)");
1043 glLog.glBindBuffer(GL_TEXTURE_BUFFER, bufferGL);
1046 const BufferMemMap bufMap(renderCtx.getFunctions(), GL_TEXTURE_BUFFER, 0, dataSize, GL_MAP_READ_BIT);
1047 deMemcpy(resultAccess.getDataPtr(), bufMap.getPtr(), dataSize);
1050 return verifyLayer(glLog.getLog(), resultAccess, 0);
1053 //! Calls the appropriate texture verification function depending on texture format or type.
1054 static bool readTextureAndVerify (const RenderContext& renderCtx,
1055 glu::CallLogWrapper& glLog,
1058 TextureType textureType,
1059 const TextureFormat& textureFormat,
1060 const IVec3& imageSize,
1061 const ImageLayerVerifier& verifyLayer)
1063 if (textureType == TEXTURETYPE_BUFFER)
1064 return readBufferTextureWithMappingAndVerify(renderCtx, glLog, bufferGL, textureFormat, imageSize.x(), verifyLayer);
1066 return isFormatTypeInteger(textureFormat.type) ? readIntegerTextureViaFBOAndVerify (renderCtx, glLog, textureGL, textureType, textureFormat, imageSize, verifyLayer)
1067 : readFloatOrNormTextureWithLookupsAndVerify (renderCtx, glLog, textureGL, textureType, textureFormat, imageSize, verifyLayer);
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
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))
1082 bool operator() (TestLog& log, const tcu::ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
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());
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));
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);
1097 return tcu::floatThresholdCompare(log, comparisonName.c_str(), comparisonDesc.c_str(), referenceSlice, resultSlice, Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
1101 const LayeredImage& m_reference;
1102 const IVec2 m_relevantRegion;
1105 //! Case that just stores some computation results into an image.
1106 class ImageStoreCase : public TestCase
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.
1114 ImageStoreCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType textureType, deUint32 caseFlags = 0)
1115 : TestCase (context, name, description)
1117 , m_textureType (textureType)
1118 , m_singleLayerBind ((caseFlags & CASEFLAG_SINGLE_LAYER_BIND) != 0)
1122 void init (void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_textureType, m_context.getRenderContext()); }
1123 IterateResult iterate (void);
1126 const TextureFormat m_format;
1127 const TextureType m_textureType;
1128 const bool m_singleLayerBind;
1131 ImageStoreCase::IterateResult ImageStoreCase::iterate (void)
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)
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);
1148 glLog.enableLogging(true);
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;
1156 glLog.glActiveTexture(GL_TEXTURE0);
1157 glLog.glBindTexture(textureTargetGL, *texture);
1158 setTexParameteri(glLog, textureTargetGL);
1159 setTextureStorage(glLog, m_textureType, internalFormatGL, imageSize, *textureBuf);
1161 // Perform image stores in compute shader.
1164 // Generate compute shader.
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()));
1179 const glu::ShaderProgram program(renderCtx,
1180 glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
1181 + textureTypeExtensionShaderRequires(shaderImageType, renderCtx) +
1183 "precision highp " + shaderImageTypeStr + ";\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" : "") +
1189 "void main (void)\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"
1203 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
1207 if (!program.isOk())
1209 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
1213 // Setup and dispatch.
1215 glLog.glUseProgram(program.getProgram());
1217 if (m_singleLayerBind)
1219 for (int layerNdx = 0; layerNdx < numSlicesOrFaces; layerNdx++)
1222 glLog.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1224 uniforms.assign1i("u_layerNdx", layerNdx);
1226 glLog.glBindImageTexture(0, *texture, 0, GL_FALSE, layerNdx, GL_WRITE_ONLY, internalFormatGL);
1227 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1229 glLog.glDispatchCompute(imageSize.x(), imageSize.y(), 1);
1230 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
1235 glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
1236 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1238 glLog.glDispatchCompute(imageSize.x(), imageSize.y(), numSlicesOrFaces);
1239 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
1243 // Create reference, read texture and compare to reference.
1245 const int isIntegerFormat = isFormatTypeInteger(m_format.type);
1246 LayeredImage reference (m_textureType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
1248 DE_ASSERT(!isIntegerFormat || (storeColorScale == 1.0f && storeColorBias == 0.0f));
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++)
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);
1256 if (isIntegerFormat)
1257 reference.setPixel(x, y, z, color);
1259 reference.setPixel(x, y, z, color.asFloat()*storeColorScale + storeColorBias);
1262 const bool compareOk = readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_textureType, m_format, imageSize, ImageLayerComparer(reference));
1264 m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, compareOk ? "Pass" : "Image comparison failed");
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
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".
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)
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)
1297 DE_ASSERT(textureFormat.getPixelSize() == imageFormat.getPixelSize());
1300 void init (void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_textureType, m_context.getRenderContext()); }
1301 IterateResult iterate (void);
1304 template <TextureFormat::ChannelType ImageFormatType, typename TcuFloatType, typename TcuFloatStorageType>
1305 static void replaceBadFloatReinterpretValues (LayeredImage& image, const TextureFormat& imageFormat);
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;
1314 template <TextureFormat::ChannelType ImageFormatType, typename TcuFloatType, typename TcuFloatTypeStorageType>
1315 void ImageLoadAndStoreCase::replaceBadFloatReinterpretValues (LayeredImage& image, const TextureFormat& imageFormat)
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
1322 const IVec3 imageSize = image.getSize();
1323 const int numSlicesOrFaces = image.getImageType() == TEXTURETYPE_CUBE ? 6 : imageSize.z();
1325 DE_ASSERT(pixelSize % imageNumChannels == 0);
1327 for (int z = 0; z < numSlicesOrFaces; z++)
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();
1333 for (int y = 0; y < imageSize.y(); y++)
1334 for (int x = 0; x < imageSize.x(); x++)
1336 void *const pixelData = (deUint8*)data + y*rowPitch + x*pixelSize;
1338 for (int c = 0; c < imageNumChannels; c++)
1340 void *const channelData = (deUint8*)pixelData + c*pixelSize/imageNumChannels;
1341 const TcuFloatType f (*(TcuFloatTypeStorageType*)channelData);
1343 if (f.isDenorm() || f.isInf() || f.isNaN())
1344 *(TcuFloatTypeStorageType*)channelData = TcuFloatType(0.0f).bits();
1350 ImageLoadAndStoreCase::IterateResult ImageLoadAndStoreCase::iterate (void)
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)
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());
1372 glLog.enableLogging(true);
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;
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.
1382 DE_ASSERT(!isIntegerTextureFormat || (storeColorScale == 1.0f && storeColorBias == 0.0f));
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++)
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);
1390 if (isIntegerTextureFormat)
1391 reference.setPixel(x, y, z, color);
1393 reference.setPixel(x, y, z, color.asFloat()*storeColorScale + storeColorBias);
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);
1402 // Upload initial pattern to texture 0.
1404 glLog.glActiveTexture(GL_TEXTURE0);
1405 glLog.glBindTexture(textureTargetGL, *texture0);
1406 setTexParameteri(glLog, textureTargetGL);
1408 log << TestLog::Message << "// Filling texture " << *texture0 << " with xor pattern" << TestLog::EndMessage;
1410 uploadTexture(glLog, reference, *texture0Buf);
1412 // Set storage for texture 1.
1414 glLog.glActiveTexture(GL_TEXTURE1);
1415 glLog.glBindTexture(textureTargetGL, *texture1);
1416 setTexParameteri(glLog, textureTargetGL);
1417 setTextureStorage(glLog, m_textureType, textureInternalFormatGL, imageSize, *texture1Buf);
1419 // Perform image loads and stores in compute shader and finalize reference computation.
1422 // Generate compute shader.
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()));
1430 const glu::ShaderProgram program(renderCtx,
1431 glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
1432 + textureTypeExtensionShaderRequires(shaderImageType, renderCtx) +
1434 "precision highp " + shaderImageTypeStr + ";\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"
1440 "void main (void)\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"
1454 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
1458 if (!program.isOk())
1460 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
1464 // Setup and dispatch.
1466 glLog.glUseProgram(program.getProgram());
1468 if (m_singleLayerBind)
1470 for (int layerNdx = 0; layerNdx < numSlicesOrFaces; layerNdx++)
1473 glLog.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1475 glLog.glBindImageTexture(0, *texture0, 0, GL_FALSE, layerNdx, GL_READ_ONLY, imageInternalFormatGL);
1476 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1478 glLog.glBindImageTexture(1, *texture1, 0, GL_FALSE, layerNdx, GL_WRITE_ONLY, imageInternalFormatGL);
1479 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1481 glLog.glDispatchCompute(imageSize.x(), imageSize.y(), 1);
1482 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
1487 glLog.glBindImageTexture(0, *texture0, 0, GL_TRUE, 0, GL_READ_ONLY, imageInternalFormatGL);
1488 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1490 glLog.glBindImageTexture(1, *texture1, 0, GL_TRUE, 0, GL_WRITE_ONLY, imageInternalFormatGL);
1491 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1493 glLog.glDispatchCompute(imageSize.x(), imageSize.y(), numSlicesOrFaces);
1494 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
1497 // Finalize reference.
1499 if (m_textureFormat != m_imageFormat)
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).
1504 const int pixelSize = m_imageFormat.getPixelSize();
1505 tcu::TextureLevel scratch (m_imageFormat, 1, 1);
1506 const PixelBufferAccess scratchAccess = scratch.getAccess();
1508 for (int z = 0; z < numSlicesOrFaces; z++)
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();
1514 for (int y = 0; y < imageSize.y(); y++)
1515 for (int x = 0; x < imageSize.x(); x++)
1517 void *const pixelData = (deUint8*)data + y*rowPitch + x*pixelSize;
1519 deMemcpy(scratchAccess.getDataPtr(), pixelData, pixelSize);
1521 if (isFormatTypeInteger(m_imageFormat.type))
1522 scratchAccess.setPixel(scratchAccess.getPixelUint(0, 0), 0, 0);
1524 scratchAccess.setPixel(scratchAccess.getPixel(0, 0), 0, 0);
1526 deMemcpy(pixelData, scratchAccess.getDataPtr(), pixelSize);
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++)
1535 if (isIntegerTextureFormat)
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);
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);
1550 // Read texture 1 and compare to reference.
1552 const bool compareOk = readTextureAndVerify(renderCtx, glLog, *texture1, *texture1Buf, m_textureType, m_textureFormat, imageSize, ImageLayerComparer(reference));
1554 m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, compareOk ? "Pass" : "Image comparison failed");
1558 enum AtomicOperationCaseType
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.
1563 ATOMIC_OPERATION_CASE_TYPE_LAST
1566 /*--------------------------------------------------------------------*//*!
1567 * \brief Binary atomic operation case.
1569 * Case that performs binary atomic operations (i.e. any but compSwap) and
1570 * verifies according to the given AtomicOperationCaseType.
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.
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.
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
1595 BinaryAtomicOperationCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, AtomicOperation operation, AtomicOperationCaseType caseType)
1596 : TestCase (context, name, description)
1598 , m_imageType (imageType)
1599 , m_operation (operation)
1600 , m_caseType (caseType)
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));
1606 DE_ASSERT(m_operation != ATOMIC_OPERATION_COMP_SWAP);
1610 IterateResult iterate (void);
1613 class EndResultVerifier;
1614 class ReturnValueVerifier;
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);
1622 static const int NUM_INVOCATIONS_PER_PIXEL = 5;
1624 const TextureFormat m_format;
1625 const TextureType m_imageType;
1626 const AtomicOperation m_operation;
1627 const AtomicOperationCaseType m_caseType;
1630 int BinaryAtomicOperationCase::getOperationInitialValue (AtomicOperation op)
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;
1648 int BinaryAtomicOperationCase::getAtomicFuncArgument (AtomicOperation op, const IVec3& invocationID, const IVec2& dispatchSizeXY)
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();
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;
1667 case ATOMIC_OPERATION_EXCHANGE:
1668 return (z*wid + x)*hei + y;
1676 string BinaryAtomicOperationCase::getAtomicFuncArgumentShaderStr (AtomicOperation op, const string& x, const string& y, const string& z, const IVec2& dispatchSizeXY)
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 +")";
1689 case ATOMIC_OPERATION_EXCHANGE:
1690 return "((" + z + "*" + toString(dispatchSizeXY.x()) + " + " + x + ")*" + toString(dispatchSizeXY.y()) + " + " + y + ")";
1698 class BinaryAtomicOperationCase::EndResultVerifier : public ImageLayerVerifier
1701 EndResultVerifier (AtomicOperation operation, TextureType imageType) : m_operation(operation), m_imageType(imageType) {}
1703 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
1705 const bool isIntegerFormat = isFormatTypeInteger(resultSlice.getFormat().type);
1706 const IVec2 dispatchSizeXY (NUM_INVOCATIONS_PER_PIXEL*resultSlice.getWidth(), resultSlice.getHeight());
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)),
1713 for (int y = 0; y < resultSlice.getHeight(); y++)
1714 for (int x = 0; x < resultSlice.getWidth(); x++)
1722 if (isIntegerFormat)
1723 result.i = resultSlice.getPixelInt(x, y).x();
1725 result.f = resultSlice.getPixel(x, y).x();
1727 // Compute the arguments that were given to the atomic function in the invocations that contribute to this pixel.
1729 IVec3 invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
1730 int atomicArgs[NUM_INVOCATIONS_PER_PIXEL];
1732 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
1734 const IVec3 gid(x + i*resultSlice.getWidth(), y, sliceOrFaceNdx);
1736 invocationGlobalIDs[i] = gid;
1737 atomicArgs[i] = getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
1740 if (isOrderIndependentAtomicOperation(m_operation))
1742 // Just accumulate the atomic args (and the initial value) according to the operation, and compare.
1744 DE_ASSERT(isIntegerFormat);
1746 int reference = getOperationInitialValue(m_operation);
1748 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
1749 reference = computeBinaryAtomicOperationResult(m_operation, reference, atomicArgs[i]);
1751 if (result.i != reference)
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;
1760 else if (m_operation == ATOMIC_OPERATION_EXCHANGE)
1762 // Check that the end result equals one of the atomic args.
1764 bool matchFound = false;
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;
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;
1786 const AtomicOperation m_operation;
1787 const TextureType m_imageType;
1790 class BinaryAtomicOperationCase::ReturnValueVerifier : public ImageLayerVerifier
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) {}
1796 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
1798 const bool isIntegerFormat (isFormatTypeInteger(resultSlice.getFormat().type));
1799 const IVec2 dispatchSizeXY (resultSlice.getWidth(), resultSlice.getHeight());
1801 DE_ASSERT(resultSlice.getWidth() == NUM_INVOCATIONS_PER_PIXEL*m_endResultImageLayerSize.x() &&
1802 resultSlice.getHeight() == m_endResultImageLayerSize.y() &&
1803 resultSlice.getDepth() == 1);
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)),
1811 for (int y = 0; y < m_endResultImageLayerSize.y(); y++)
1812 for (int x = 0; x < m_endResultImageLayerSize.x(); x++)
1816 int i[NUM_INVOCATIONS_PER_PIXEL];
1817 float f[NUM_INVOCATIONS_PER_PIXEL];
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.
1822 IntFloatArr returnValues;
1823 IntFloatArr atomicArgs;
1824 IVec3 invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
1825 IVec2 pixelCoords[NUM_INVOCATIONS_PER_PIXEL];
1827 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
1829 const IVec2 pixCoord (x + i*m_endResultImageLayerSize.x(), y);
1830 const IVec3 gid (pixCoord.x(), pixCoord.y(), sliceOrFaceNdx);
1832 invocationGlobalIDs[i] = gid;
1833 pixelCoords[i] = pixCoord;
1835 if (isIntegerFormat)
1837 returnValues.i[i] = resultSlice.getPixelInt(gid.x(), y).x();
1838 atomicArgs.i[i] = getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
1842 returnValues.f[i] = resultSlice.getPixel(gid.x(), y).x();
1843 atomicArgs.f[i] = (float)getAtomicFuncArgument(m_operation, gid, dispatchSizeXY);
1847 // Verify that the return values form a valid sequence.
1850 const bool success = isIntegerFormat ? verifyOperationAccumulationIntermediateValues(m_operation,
1851 getOperationInitialValue(m_operation),
1855 : verifyOperationAccumulationIntermediateValues(m_operation,
1856 (float)getOperationInitialValue(m_operation),
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;
1877 const AtomicOperation m_operation;
1878 const TextureType m_imageType;
1879 const IVec2 m_endResultImageLayerSize;
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])
1886 bool argsUsed[NUM_INVOCATIONS_PER_PIXEL] = { false };
1888 return verifyRecursive(operation, 0, init, argsUsed, args, returnValues);
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; }
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])
1898 if (index < NUM_INVOCATIONS_PER_PIXEL)
1900 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
1902 if (!argsUsed[i] && compare(returnValues[i], valueSoFar))
1905 if (verifyRecursive(operation, index+1, computeBinaryAtomicOperationResult(operation, valueSoFar, args[i]), argsUsed, args, returnValues))
1907 argsUsed[i] = false;
1918 void BinaryAtomicOperationCase::init (void)
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");
1923 checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext());
1926 BinaryAtomicOperationCase::IterateResult BinaryAtomicOperationCase::iterate (void)
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.
1943 glLog.enableLogging(true);
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;
1951 if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
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;
1958 // Fill endResultTexture with initial pattern.
1961 const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
1964 const IVec4 initial(getOperationInitialValue(m_operation));
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);
1972 // Upload initial pattern to endResultTexture and bind to image.
1974 glLog.glActiveTexture(GL_TEXTURE0);
1975 glLog.glBindTexture(textureTargetGL, *endResultTexture);
1976 setTexParameteri(glLog, textureTargetGL);
1978 log << TestLog::Message << "// Filling end-result texture with initial pattern (initial value " << getOperationInitialValue(m_operation) << ")" << TestLog::EndMessage;
1980 uploadTexture(glLog, imageData, *endResultTextureBuf);
1983 glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
1984 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
1986 if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
1988 // Set storage for returnValueTexture and bind to image.
1990 glLog.glActiveTexture(GL_TEXTURE1);
1991 glLog.glBindTexture(textureTargetGL, *returnValueTexture);
1992 setTexParameteri(glLog, textureTargetGL);
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);
1999 glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
2000 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2003 // Perform image stores in compute shader and finalize reference computation.
2006 // Generate compute shader.
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"
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()));
2024 const glu::ShaderProgram program(renderCtx,
2025 glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2026 + imageAtomicExtensionShaderRequires(renderCtx)
2027 + textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2029 "precision highp " + shaderImageTypeStr + ";\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"
2037 "void main (void)\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"
2049 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2053 if (!program.isOk())
2055 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2059 // Setup and dispatch.
2061 glLog.glUseProgram(program.getProgram());
2063 glLog.glDispatchCompute(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y(), numSlicesOrFaces);
2064 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2067 // Read texture and check.
2070 const deUint32 textureToCheckGL = m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? *endResultTexture
2071 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? *returnValueTexture
2073 const deUint32 textureToCheckBufGL = m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? *endResultTextureBuf
2074 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? *returnValueTextureBuf
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);
2082 if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, textureToCheckSize, *verifier))
2083 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2085 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
2091 /*--------------------------------------------------------------------*//*!
2092 * \brief Atomic compSwap operation case.
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
2102 AtomicCompSwapCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, AtomicOperationCaseType caseType)
2103 : TestCase (context, name, description)
2105 , m_imageType (imageType)
2106 , m_caseType (caseType)
2108 DE_ASSERT(m_format == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32) ||
2109 m_format == TextureFormat(TextureFormat::R, TextureFormat::SIGNED_INT32));
2113 IterateResult iterate (void);
2116 class EndResultVerifier;
2117 class ReturnValueVerifier;
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);
2124 static const int NUM_INVOCATIONS_PER_PIXEL = 5;
2126 const TextureFormat m_format;
2127 const TextureType m_imageType;
2128 const AtomicOperationCaseType m_caseType;
2131 int AtomicCompSwapCase::getCompareArg (const IVec3& invocationID, int imageWidth)
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;
2139 return wrapX*wrapX + y*y + z*z + curPixelInvocationNdx*42;
2142 int AtomicCompSwapCase::getAssignArg (const IVec3& invocationID, int imageWidth)
2144 return getCompareArg(IVec3(invocationID.x() + imageWidth, invocationID.y(), invocationID.z()), imageWidth);
2147 string AtomicCompSwapCase::getCompareArgShaderStr (const string& x, const string& y, const string& z, int imageWidth)
2149 const string wrapX = "(" + x + "%" + toString(imageWidth) + ")";
2150 const string curPixelInvocationNdx = "(" + x + "/" + toString(imageWidth) + ")";
2152 return "(" +wrapX+"*"+wrapX+ " + " +y+"*"+y+ " + " +z+"*"+z+ " + " + curPixelInvocationNdx + "*42)";
2155 string AtomicCompSwapCase::getAssignArgShaderStr (const string& x, const string& y, const string& z, int imageWidth)
2157 const string wrapX = "(" + x + "%" + toString(imageWidth) + ")";
2158 const string curPixelInvocationNdx = "(" + x + "/" + toString(imageWidth) + " + 1)";
2160 return "(" +wrapX+"*"+wrapX+ " + " +y+"*"+y+ " + " +z+"*"+z+ " + " + curPixelInvocationNdx + "*42)";
2163 void AtomicCompSwapCase::init (void)
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");
2168 checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext());
2171 class AtomicCompSwapCase::EndResultVerifier : public ImageLayerVerifier
2174 EndResultVerifier (TextureType imageType, int imageWidth) : m_imageType(imageType), m_imageWidth(imageWidth) {}
2176 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
2178 DE_ASSERT(isFormatTypeInteger(resultSlice.getFormat().type));
2179 DE_ASSERT(resultSlice.getWidth() == m_imageWidth);
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)),
2186 for (int y = 0; y < resultSlice.getHeight(); y++)
2187 for (int x = 0; x < resultSlice.getWidth(); x++)
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.
2192 const int result = resultSlice.getPixelInt(x, y).x();
2193 IVec3 invocationGlobalIDs[NUM_INVOCATIONS_PER_PIXEL];
2194 int assignArgs[NUM_INVOCATIONS_PER_PIXEL];
2196 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
2198 const IVec3 gid(x + i*resultSlice.getWidth(), y, sliceOrFaceNdx);
2200 invocationGlobalIDs[i] = gid;
2201 assignArgs[i] = getAssignArg(gid, m_imageWidth);
2205 bool matchFound = false;
2206 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL && !matchFound; i++)
2207 matchFound = result == assignArgs[i];
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;
2225 const TextureType m_imageType;
2226 const int m_imageWidth;
2229 class AtomicCompSwapCase::ReturnValueVerifier : public ImageLayerVerifier
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) {}
2235 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int sliceOrFaceNdx) const
2237 DE_ASSERT(isFormatTypeInteger(resultSlice.getFormat().type));
2238 DE_ASSERT(resultSlice.getWidth() == NUM_INVOCATIONS_PER_PIXEL*m_endResultImageWidth);
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)),
2246 for (int y = 0; y < resultSlice.getHeight(); y++)
2247 for (int x = 0; x < m_endResultImageWidth; x++)
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.
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];
2256 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
2258 const IVec2 pixCoord (x + i*m_endResultImageWidth, y);
2259 const IVec3 gid (pixCoord.x(), pixCoord.y(), sliceOrFaceNdx);
2261 pixelCoords[i] = pixCoord;
2262 invocationGlobalIDs[i] = gid;
2263 returnValues[i] = resultSlice.getPixelInt(gid.x(), y).x();
2264 compareArgs[i] = getCompareArg(gid, m_endResultImageWidth);
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
2278 int failingNdx = -1;
2281 int currentAtomicValueNdx = 0;
2282 for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
2284 if (returnValues[i] == compareArgs[currentAtomicValueNdx])
2286 if (i > 0 && returnValues[i] == compareArgs[currentAtomicValueNdx+1])
2288 currentAtomicValueNdx++;
2296 if (failingNdx >= 0)
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;
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;
2323 const TextureType m_imageType;
2324 const int m_endResultImageWidth;
2327 AtomicCompSwapCase::IterateResult AtomicCompSwapCase::iterate (void)
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.
2344 DE_ASSERT(isUintFormat || isIntFormat);
2346 glLog.enableLogging(true);
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;
2354 if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
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;
2361 // Fill endResultTexture with initial pattern.
2364 const LayeredImage imageData(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
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())));
2373 // Upload initial pattern to endResultTexture and bind to image.
2375 glLog.glActiveTexture(GL_TEXTURE0);
2376 glLog.glBindTexture(textureTargetGL, *endResultTexture);
2377 setTexParameteri(glLog, textureTargetGL);
2379 log << TestLog::Message << "// Filling end-result texture with initial pattern" << TestLog::EndMessage;
2381 uploadTexture(glLog, imageData, *endResultTextureBuf);
2384 glLog.glBindImageTexture(0, *endResultTexture, 0, GL_TRUE, 0, GL_READ_WRITE, internalFormatGL);
2385 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2387 if (m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES)
2389 // Set storage for returnValueTexture and bind to image.
2391 glLog.glActiveTexture(GL_TEXTURE1);
2392 glLog.glBindTexture(textureTargetGL, *returnValueTexture);
2393 setTexParameteri(glLog, textureTargetGL);
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);
2400 glLog.glBindImageTexture(1, *returnValueTexture, 0, GL_TRUE, 0, GL_WRITE_ONLY, internalFormatGL);
2401 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2404 // Perform atomics in compute shader.
2407 // Generate compute shader.
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()));
2421 const glu::ShaderProgram program(renderCtx,
2422 glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2423 + imageAtomicExtensionShaderRequires(renderCtx)
2424 + textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2426 "precision highp " + shaderImageTypeStr + ";\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"
2434 "void main (void)\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" :
2448 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2452 if (!program.isOk())
2454 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2458 // Setup and dispatch.
2460 glLog.glUseProgram(program.getProgram());
2462 glLog.glDispatchCompute(NUM_INVOCATIONS_PER_PIXEL*imageSize.x(), imageSize.y(), numSlicesOrFaces);
2463 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2466 // Create reference, read texture and compare.
2469 const deUint32 textureToCheckGL = m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? *endResultTexture
2470 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? *returnValueTexture
2473 const deUint32 textureToCheckBufGL = m_caseType == ATOMIC_OPERATION_CASE_TYPE_END_RESULT ? *endResultTextureBuf
2474 : m_caseType == ATOMIC_OPERATION_CASE_TYPE_RETURN_VALUES ? *returnValueTextureBuf
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));
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);
2487 if (readTextureAndVerify(renderCtx, glLog, textureToCheckGL, textureToCheckBufGL, m_imageType, m_format, relevantRegion, *verifier))
2488 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2490 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
2496 //! Case testing the "coherent" or "volatile" qualifier, along with memoryBarrier() and barrier().
2497 class CoherenceCase : public TestCase
2502 QUALIFIER_COHERENT = 0,
2508 CoherenceCase (Context& context, const char* name, const char* description, const TextureFormat& format, TextureType imageType, Qualifier qualifier)
2509 : TestCase (context, name, description)
2511 , m_imageType (imageType)
2512 , m_qualifier (qualifier)
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));
2517 DE_ASSERT(qualifier == QUALIFIER_COHERENT || qualifier == QUALIFIER_VOLATILE);
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));
2524 void init (void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext()); }
2525 IterateResult iterate (void);
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;
2535 const TextureFormat m_format;
2536 const TextureType m_imageType;
2537 const Qualifier m_qualifier;
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 )";
2547 CoherenceCase::IterateResult CoherenceCase::iterate (void)
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"
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;
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);
2575 glLog.enableLogging(true);
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;
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");
2590 // Perform computations in compute shader.
2593 // Generate compute shader.
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()));
2608 const glu::ShaderProgram program(renderCtx,
2609 glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2610 + textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2612 "precision highp " + shaderImageTypeStr + ";\n"
2614 "layout (local_size_x = " + localSizeX
2615 + ", local_size_y = " + localSizeY
2616 + ", local_size_z = " + localSizeZ
2618 "layout (" + shaderImageFormatStr + ", binding=0) " + qualifierName + " uniform " + shaderImageTypeStr + " u_image;\n"
2619 "void main (void)\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"
2626 " memoryBarrier();\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"
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"
2646 " memoryBarrier();\n"
2649 " imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(sum));\n"
2652 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2656 if (!program.isOk())
2658 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2662 // Setup and dispatch.
2664 glLog.glUseProgram(program.getProgram());
2666 glLog.glDispatchCompute(numGroups.x(), numGroups.y(), numGroups.z());
2667 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2670 // Create reference, read texture and compare.
2673 LayeredImage reference(m_imageType, m_format, imageSize.x(), imageSize.y(), imageSize.z());
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));
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++)
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();
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();
2695 reference.setPixel(x, y, z, IVec4(sum));
2699 if (readTextureAndVerify(renderCtx, glLog, *texture, *textureBuf, m_imageType, m_format, imageSize, ImageLayerComparer(reference)))
2700 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2702 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2708 class R32UIImageSingleValueVerifier : public ImageLayerVerifier
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) {}
2714 bool operator() (TestLog& log, const ConstPixelBufferAccess& resultSlice, int) const
2716 DE_ASSERT(resultSlice.getWidth() == 1 && resultSlice.getHeight() == 1 && resultSlice.getDepth() == 1);
2717 DE_ASSERT(resultSlice.getFormat() == TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT32));
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;
2721 const deUint32 resultValue = resultSlice.getPixelUint(0, 0).x();
2722 if (!de::inRange(resultValue, m_min, m_max))
2724 log << TestLog::Message << "// Failure: got value " << resultValue << TestLog::EndMessage;
2729 log << TestLog::Message << "// Success: got value " << resultValue << TestLog::EndMessage;
2735 const deUint32 m_min;
2736 const deUint32 m_max;
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
2746 IMAGEACCESS_READ_ONLY = 0,
2747 IMAGEACCESS_WRITE_ONLY,
2748 IMAGEACCESS_READ_ONLY_WRITE_ONLY,
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)
2756 , m_imageType (imageType)
2757 , m_imageSize (size)
2758 , m_imageAccess (imageAccess)
2762 void init (void) { checkTextureTypeExtensions(m_context.getContextInfo(), m_imageType, m_context.getRenderContext()); }
2763 IterateResult iterate (void);
2766 const TextureFormat m_format;
2767 const TextureType m_imageType;
2768 const IVec3 m_imageSize;
2769 const ImageAccess m_imageAccess;
2772 ImageSizeCase::IterateResult ImageSizeCase::iterate (void)
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);
2783 glLog.enableLogging(true);
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;
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");
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");
2806 // Read texture size in compute shader.
2809 // Generate compute shader.
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"
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()));
2819 const glu::ShaderProgram program(renderCtx,
2820 glu::ProgramSources() << glu::ComputeSource(glslVersionDeclaration + "\n"
2821 + textureTypeExtensionShaderRequires(m_imageType, renderCtx) +
2823 "precision highp " + shaderImageTypeStr + ";\n"
2824 "precision highp uimage2D;\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"
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"
2840 " imageStore(u_result, ivec2(0, 0), uvec4(result));\n"
2843 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
2847 if (!program.isOk())
2849 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
2853 // Setup and dispatch.
2855 glLog.glUseProgram(program.getProgram());
2857 glLog.glDispatchCompute(1, 1, 1);
2858 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glDispatchCompute");
2861 // Read texture and compare to reference.
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())
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");
2873 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value");
2879 //! Case testing the control over early/late fragment tests.
2880 class EarlyFragmentTestsCase : public TestCase
2891 enum RenderTargetType
2893 RENDERTARGET_DEFAULT = 0,
2895 RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT,
2901 EarlyFragmentTestsCase (Context& context, const char* name, const char* description, TestType type, bool useEarlyTests, RenderTargetType renderTarget)
2902 : TestCase (context, name, description)
2904 , m_useEarlyTests (useEarlyTests)
2905 , m_renderTarget (renderTarget)
2911 if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) == 0)
2912 throw tcu::NotSupportedError("GL_MAX_FRAGMENT_IMAGE_UNIFORMS is zero");
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");
2917 if (m_type == TESTTYPE_DEPTH &&
2918 m_renderTarget == RENDERTARGET_DEFAULT &&
2919 m_context.getRenderTarget().getDepthBits() == 0)
2921 throw tcu::NotSupportedError("Test requires depth buffer");
2924 if (m_type == TESTTYPE_STENCIL &&
2925 m_renderTarget == RENDERTARGET_DEFAULT &&
2926 m_context.getRenderTarget().getStencilBits() == 0)
2928 throw tcu::NotSupportedError("Test requires stencil buffer");
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");
2936 IterateResult iterate (void);
2939 static const int RENDER_SIZE;
2941 const TestType m_type;
2942 const bool m_useEarlyTests;
2943 const RenderTargetType m_renderTarget;
2946 const int EarlyFragmentTestsCase::RENDER_SIZE = 32;
2948 EarlyFragmentTestsCase::IterateResult EarlyFragmentTestsCase::iterate (void)
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;
2964 glLog.enableLogging(true);
2968 log << TestLog::Message << "// Created a texture (name " << *texture << ")" << TestLog::EndMessage;
2970 glLog.glActiveTexture(GL_TEXTURE0);
2971 glLog.glBindTexture(GL_TEXTURE_2D, *texture);
2972 setTexParameteri(glLog, GL_TEXTURE_2D);
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 */);
2978 glLog.glBindImageTexture(0, *texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32UI);
2979 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "glBindImageTexture");
2981 // Set up framebuffer
2982 if (m_renderTarget == RENDERTARGET_FBO ||
2983 m_renderTarget == RENDERTARGET_FBO_WITHOUT_TEST_ATTACHMENT)
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));
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");
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");
2997 if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_DEPTH)
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");
3003 glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, **testAttachment);
3004 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo depth attachment");
3006 else if (m_renderTarget == RENDERTARGET_FBO && m_type == TESTTYPE_STENCIL)
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");
3012 glLog.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, **testAttachment);
3013 GLU_EXPECT_NO_ERROR(renderCtx.getFunctions().getError(), "set fbo stencil attachment");
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);
3021 // Set up appropriate conditions for the test.
3023 glLog.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
3024 glLog.glClear(GL_COLOR_BUFFER_BIT);
3026 if (m_type == TESTTYPE_DEPTH)
3028 glLog.glClearDepthf(0.5f);
3029 glLog.glClear(GL_DEPTH_BUFFER_BIT);
3030 glLog.glEnable(GL_DEPTH_TEST);
3032 else if (m_type == TESTTYPE_STENCIL)
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);
3048 // Perform image stores in fragment shader.
3051 const std::string glslVersionDeclaration = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(renderCtx.getType()));
3053 // Generate fragment shader.
3055 const glu::ShaderProgram program(renderCtx,
3056 glu::ProgramSources() << glu::VertexSource( glslVersionDeclaration + "\n"
3058 "highp in vec3 a_position;\n"
3060 "void main (void)\n"
3062 " gl_Position = vec4(a_position, 1.0);\n"
3065 << glu::FragmentSource( glslVersionDeclaration + "\n"
3066 + imageAtomicExtensionShaderRequires(renderCtx) +
3068 + string(m_useEarlyTests ? "layout (early_fragment_tests) in;\n\n" : "") +
3069 "layout (location = 0) out highp vec4 o_color;\n"
3071 "precision highp uimage2D;\n"
3073 "layout (r32ui, binding=0) coherent uniform uimage2D u_image;\n"
3075 "void main (void)\n"
3077 " imageAtomicAdd(u_image, ivec2(0, 0), uint(1));\n"
3078 " o_color = vec4(1.0);\n"
3081 UniformAccessLogger uniforms(renderCtx.getFunctions(), log, program.getProgram());
3085 if (!program.isOk())
3087 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program compilation failed");
3091 // Setup and draw full-viewport quad.
3093 glLog.glUseProgram(program.getProgram());
3096 static const float vertexPositions[4*3] =
3104 static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 };
3106 const glu::VertexArrayBinding attrBindings[] =
3108 glu::va::Float("a_position", 3, 4, 0, &vertexPositions[0])
3111 glLog.glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
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");
3119 // Log rendered result for convenience.
3121 tcu::Surface rendered(viewportWidth, viewportHeight);
3122 glu::readPixels(renderCtx, viewportX, viewportY, rendered.getAccess());
3123 log << TestLog::Image("Rendered", "Rendered image", rendered);
3126 // Read counter value and check.
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;
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");
3138 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong value");
3146 ShaderImageLoadStoreTests::ShaderImageLoadStoreTests (Context& context)
3147 : TestCaseGroup(context, "image_load_store", "Shader Image Load & Store Tests")
3151 ShaderImageLoadStoreTests::~ShaderImageLoadStoreTests (void)
3155 void ShaderImageLoadStoreTests::init (void)
3157 // Per-image-type tests.
3160 static const TextureType imageTypes[] =
3165 TEXTURETYPE_2D_ARRAY,
3169 static const TextureFormat formats[] =
3171 TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT),
3172 TextureFormat(TextureFormat::RGBA, TextureFormat::HALF_FLOAT),
3173 TextureFormat(TextureFormat::R, TextureFormat::FLOAT),
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),
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),
3185 TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8),
3187 TextureFormat(TextureFormat::RGBA, TextureFormat::SNORM_INT8)
3190 for (int imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageTypes); imageTypeNdx++)
3192 const TextureType imageType = imageTypes[imageTypeNdx];
3193 TestCaseGroup* const imageTypeGroup = new TestCaseGroup(m_context, getTextureTypeName(imageType), "");
3194 addChild(imageTypeGroup);
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);
3209 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
3211 const TextureFormat& format = formats[formatNdx];
3212 const string formatName = getShaderImageFormatQualifier(formats[formatNdx]);
3214 if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(format))
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));
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));
3229 if (format.order == TextureFormat::R)
3231 // Atomic operations.
3233 for (int operationI = 0; operationI < ATOMIC_OPERATION_LAST; operationI++)
3235 for (int atomicCaseTypeI = 0; atomicCaseTypeI < ATOMIC_OPERATION_CASE_TYPE_LAST; atomicCaseTypeI++)
3237 const AtomicOperation operation = (AtomicOperation)operationI;
3239 if (format.type == TextureFormat::FLOAT && operation != ATOMIC_OPERATION_EXCHANGE)
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"
3246 const string caseName = string() + getAtomicOperationCaseName(operation) + "_" + formatName + "_" + caseTypeName;
3248 if (operation == ATOMIC_OPERATION_COMP_SWAP)
3249 atomicGroup->addChild(new AtomicCompSwapCase(m_context, caseName.c_str(), "", format, imageType, caseType));
3251 atomicGroup->addChild(new BinaryAtomicOperationCase(m_context, caseName.c_str(), "", format, imageType, operation, caseType));
3257 for (int coherenceQualifierI = 0; coherenceQualifierI < CoherenceCase::QUALIFIER_LAST; coherenceQualifierI++)
3259 const CoherenceCase::Qualifier coherenceQualifier = (CoherenceCase::Qualifier)coherenceQualifierI;
3260 const char* const coherenceQualifierName = coherenceQualifier == CoherenceCase::QUALIFIER_COHERENT ? "coherent"
3261 : coherenceQualifier == CoherenceCase::QUALIFIER_VOLATILE ? "volatile"
3263 const string caseName = string() + coherenceQualifierName + "_" + formatName;
3265 qualifierGroup->addChild(new CoherenceCase(m_context, caseName.c_str(), "", format, imageType, coherenceQualifier));
3271 qualifierGroup->addChild(new ImageLoadAndStoreCase(m_context, "restrict", "", TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), imageType, ImageLoadAndStoreCase::CASEFLAG_RESTRICT_IMAGES));
3273 // Format re-interpretation.
3275 for (int texFmtNdx = 0; texFmtNdx < DE_LENGTH_OF_ARRAY(formats); texFmtNdx++)
3276 for (int imgFmtNdx = 0; imgFmtNdx < DE_LENGTH_OF_ARRAY(formats); imgFmtNdx++)
3278 const TextureFormat& texFmt = formats[texFmtNdx];
3279 const TextureFormat& imgFmt = formats[imgFmtNdx];
3281 if (imageType == TEXTURETYPE_BUFFER && !isFormatSupportedForTextureBuffer(texFmt))
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));
3293 static const IVec3 baseImageSizes[] =
3301 for (int imageAccessI = 0; imageAccessI < ImageSizeCase::IMAGEACCESS_LAST; imageAccessI++)
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"
3309 for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(baseImageSizes); imageSizeNdx++)
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);
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())
3326 const string caseName = string() + imageAccessStr + "_" + sizeStr;
3328 imageSizeGroup->addChild(new ImageSizeCase(m_context, caseName.c_str(), "", TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), imageType, imageSize, imageAccess));
3335 // early_fragment_tests cases.
3338 TestCaseGroup* const earlyTestsGroup = new TestCaseGroup(m_context, "early_fragment_tests", "");
3339 addChild(earlyTestsGroup);
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++)
3345 const EarlyFragmentTestsCase::RenderTargetType targetType = (EarlyFragmentTestsCase::RenderTargetType)testRenderTargetI;
3346 const bool useEarlyTests = useEarlyTestsI != 0;
3347 const EarlyFragmentTestsCase::TestType testType = (EarlyFragmentTestsCase::TestType)testTypeI;
3349 const string testTypeName = testType == EarlyFragmentTestsCase::TESTTYPE_DEPTH ? "depth"
3350 : testType == EarlyFragmentTestsCase::TESTTYPE_STENCIL ? "stencil"
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)
3357 const string caseName = string(useEarlyTests ? "" : "no_") + "early_fragment_tests_" + testTypeName + targetName;
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")
3365 earlyTestsGroup->addChild(new EarlyFragmentTestsCase(m_context, caseName.c_str(), caseDesc.c_str(), testType, useEarlyTests, targetType));