Test additional atomic image SPIR-V operations
authorRicardo Garcia <rgarcia@igalia.com>
Mon, 20 Jan 2020 09:02:04 +0000 (10:02 +0100)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Mon, 24 Feb 2020 09:21:22 +0000 (04:21 -0500)
This commit adds tests to check OpAtomicIIncrement, OpAtomicIDecrement
and OpAtomicISub with images.

New tests:
dEQP-VK.image.atomic_operations.sub.*
dEQP-VK.image.atomic_operations.inc.*
dEQP-VK.image.atomic_operations.dec.*

Components: Framework, Vulkan
VK-GL-CTS issue: 2186

Change-Id: Ib2c5d5075555ad0be025b0498960b646852fdcd4

AndroidGen.mk
android/cts/master/vk-master.txt
external/vulkancts/modules/vulkan/image/CMakeLists.txt
external/vulkancts/modules/vulkan/image/vktImageAtomicOperationTests.cpp
external/vulkancts/modules/vulkan/image/vktImageAtomicSpirvShaders.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/image/vktImageAtomicSpirvShaders.hpp [new file with mode: 0644]
external/vulkancts/mustpass/master/vk-default-no-waivers.txt
external/vulkancts/mustpass/master/vk-default.txt
framework/common/tcuStringTemplate.cpp

index 94b62d9..816e5d6 100644 (file)
@@ -159,6 +159,7 @@ LOCAL_SRC_FILES := \
        external/vulkancts/modules/vulkan/geometry/vktGeometryVaryingGeometryShaderTests.cpp \
        external/vulkancts/modules/vulkan/image/vktImageAstcDecodeModeTests.cpp \
        external/vulkancts/modules/vulkan/image/vktImageAtomicOperationTests.cpp \
+       external/vulkancts/modules/vulkan/image/vktImageAtomicSpirvShaders.cpp \
        external/vulkancts/modules/vulkan/image/vktImageCompressionTranscodingSupport.cpp \
        external/vulkancts/modules/vulkan/image/vktImageLoadStoreTests.cpp \
        external/vulkancts/modules/vulkan/image/vktImageLoadStoreUtil.cpp \
index df49b59..93b763b 100644 (file)
@@ -428819,6 +428819,90 @@ dEQP-VK.image.atomic_operations.add.cube_array.r32ui_end_result
 dEQP-VK.image.atomic_operations.add.cube_array.r32ui_intermediate_values
 dEQP-VK.image.atomic_operations.add.cube_array.r32i_end_result
 dEQP-VK.image.atomic_operations.add.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.cube_array.r32i_intermediate_values
 dEQP-VK.image.atomic_operations.min.1d.r32ui_end_result
 dEQP-VK.image.atomic_operations.min.1d.r32ui_intermediate_values
 dEQP-VK.image.atomic_operations.min.1d.r32i_end_result
index 19ba98c..b8d3c45 100644 (file)
@@ -9,6 +9,8 @@ set(DEQP_VK_IMAGE_SRCS
        vktImageAstcDecodeModeTests.hpp
        vktImageAtomicOperationTests.cpp
        vktImageAtomicOperationTests.hpp
+       vktImageAtomicSpirvShaders.cpp
+       vktImageAtomicSpirvShaders.hpp
        vktImageLoadStoreTests.cpp
        vktImageLoadStoreTests.hpp
        vktImageMutableTests.cpp
index 66d9265..a6e624b 100644 (file)
@@ -22,6 +22,7 @@
  *//*--------------------------------------------------------------------*/
 
 #include "vktImageAtomicOperationTests.hpp"
+#include "vktImageAtomicSpirvShaders.hpp"
 
 #include "deUniquePtr.hpp"
 #include "deStringUtil.hpp"
@@ -41,6 +42,7 @@
 #include "tcuTextureUtil.hpp"
 #include "tcuTexture.hpp"
 #include "tcuVectorType.hpp"
+#include "tcuStringTemplate.hpp"
 
 namespace vkt
 {
@@ -79,6 +81,9 @@ enum
 enum AtomicOperation
 {
        ATOMIC_OPERATION_ADD = 0,
+       ATOMIC_OPERATION_SUB,
+       ATOMIC_OPERATION_INC,
+       ATOMIC_OPERATION_DEC,
        ATOMIC_OPERATION_MIN,
        ATOMIC_OPERATION_MAX,
        ATOMIC_OPERATION_AND,
@@ -146,6 +151,9 @@ static string getAtomicOperationCaseName (const AtomicOperation op)
        switch (op)
        {
                case ATOMIC_OPERATION_ADD:                              return string("add");
+               case ATOMIC_OPERATION_SUB:                              return string("sub");
+               case ATOMIC_OPERATION_INC:                              return string("inc");
+               case ATOMIC_OPERATION_DEC:                              return string("dec");
                case ATOMIC_OPERATION_MIN:                              return string("min");
                case ATOMIC_OPERATION_MAX:                              return string("max");
                case ATOMIC_OPERATION_AND:                              return string("and");
@@ -183,6 +191,9 @@ static deInt32 getOperationInitialValue (const AtomicOperation op)
        {
                // \note 18 is just an arbitrary small nonzero value.
                case ATOMIC_OPERATION_ADD:                              return 18;
+               case ATOMIC_OPERATION_INC:                              return 18;
+               case ATOMIC_OPERATION_SUB:                              return (1 << 24) - 1;
+               case ATOMIC_OPERATION_DEC:                              return (1 << 24) - 1;
                case ATOMIC_OPERATION_MIN:                              return (1 << 15) - 1;
                case ATOMIC_OPERATION_MAX:                              return 18;
                case ATOMIC_OPERATION_AND:                              return (1 << 15) - 1;
@@ -209,10 +220,14 @@ static T getAtomicFuncArgument (const AtomicOperation     op,
        {
                // \note Fall-throughs.
                case ATOMIC_OPERATION_ADD:
+               case ATOMIC_OPERATION_SUB:
                case ATOMIC_OPERATION_AND:
                case ATOMIC_OPERATION_OR:
                case ATOMIC_OPERATION_XOR:
                        return x*x + y*y + z*z;
+               case ATOMIC_OPERATION_INC:
+               case ATOMIC_OPERATION_DEC:
+                       return 1;
                case ATOMIC_OPERATION_MIN:
                case ATOMIC_OPERATION_MAX:
                        // multiply half of the data by -1
@@ -230,6 +245,9 @@ static T getAtomicFuncArgument (const AtomicOperation       op,
 static bool isOrderIndependentAtomicOperation (const AtomicOperation op)
 {
        return  op == ATOMIC_OPERATION_ADD ||
+                       op == ATOMIC_OPERATION_SUB ||
+                       op == ATOMIC_OPERATION_INC ||
+                       op == ATOMIC_OPERATION_DEC ||
                        op == ATOMIC_OPERATION_MIN ||
                        op == ATOMIC_OPERATION_MAX ||
                        op == ATOMIC_OPERATION_AND ||
@@ -237,13 +255,54 @@ static bool isOrderIndependentAtomicOperation (const AtomicOperation op)
                        op == ATOMIC_OPERATION_XOR;
 }
 
+//! Checks if the operation needs an SPIR-V shader.
+static bool isSpirvAtomicOperation (const AtomicOperation op)
+{
+       return  op == ATOMIC_OPERATION_SUB ||
+                       op == ATOMIC_OPERATION_INC ||
+                       op == ATOMIC_OPERATION_DEC;
+}
+
+//! Returns the SPIR-V assembler name of the given operation.
+static std::string getSpirvAtomicOpName (const AtomicOperation op)
+{
+       switch (op)
+       {
+       case ATOMIC_OPERATION_SUB:      return "OpAtomicISub";
+       case ATOMIC_OPERATION_INC:      return "OpAtomicIIncrement";
+       case ATOMIC_OPERATION_DEC:      return "OpAtomicIDecrement";
+       default:                                        break;
+       }
+
+       DE_ASSERT(false);
+       return "";
+}
+
+//! Returns true if the given SPIR-V operation does not need the last argument, compared to OpAtomicIAdd.
+static bool isSpirvAtomicNoLastArgOp (const AtomicOperation op)
+{
+       switch (op)
+       {
+       case ATOMIC_OPERATION_SUB:      return false;
+       case ATOMIC_OPERATION_INC:      // fallthrough
+       case ATOMIC_OPERATION_DEC:      return true;
+       default:                                        break;
+       }
+
+       DE_ASSERT(false);
+       return false;
+}
+
 //! Computes the result of an atomic operation where "a" is the data operated on and "b" is the parameter to the atomic function.
 template <typename T>
 static T computeBinaryAtomicOperationResult (const AtomicOperation op, const T a, const T b)
 {
        switch (op)
        {
+               case ATOMIC_OPERATION_INC:                              // fallthrough.
                case ATOMIC_OPERATION_ADD:                              return a + b;
+               case ATOMIC_OPERATION_DEC:                              // fallthrough.
+               case ATOMIC_OPERATION_SUB:                              return a - b;
                case ATOMIC_OPERATION_MIN:                              return de::min(a, b);
                case ATOMIC_OPERATION_MAX:                              return de::max(a, b);
                case ATOMIC_OPERATION_AND:                              return a & b;
@@ -306,36 +365,51 @@ void BinaryAtomicEndResultCase::checkSupport (Context& context) const
 
 void BinaryAtomicEndResultCase::initPrograms (SourceCollections& sourceCollections) const
 {
-       const string    versionDecl                             = glu::getGLSLVersionDeclaration(m_glslVersion);
-
-       const bool              uintFormat                              = isUintFormat(mapTextureFormat(m_format));
-       const bool              intFormat                               = isIntFormat(mapTextureFormat(m_format));
-       const UVec3             gridSize                                = getShaderGridSize(m_imageType, m_imageSize);
-       const string    atomicCoord                             = getCoordStr(m_imageType, "gx % " + toString(gridSize.x()), "gy", "gz");
-
-       const string    atomicArgExpr                   = (uintFormat ? "uint" : intFormat ? "int" : "float")
-                                                                                       + getAtomicFuncArgumentShaderStr(m_operation, "gx", "gy", "gz", IVec3(NUM_INVOCATIONS_PER_PIXEL*gridSize.x(), gridSize.y(), gridSize.z()));
-
-       const string    compareExchangeStr              = (m_operation == ATOMIC_OPERATION_COMPARE_EXCHANGE) ? ", 18" + string(uintFormat ? "u" : "") : "";
-       const string    atomicInvocation                = getAtomicOperationShaderFuncName(m_operation) + "(u_resultImage, " + atomicCoord + compareExchangeStr + ", " + atomicArgExpr + ")";
-       const string    shaderImageFormatStr    = getShaderImageFormatQualifier(m_format);
-       const string    shaderImageTypeStr              = getShaderImageType(m_format, m_imageType);
-
-       string source = versionDecl + "\n"
-                                       "precision highp " + shaderImageTypeStr + ";\n"
-                                       "\n"
-                                       "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
-                                       "layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_resultImage;\n"
-                                       "\n"
-                                       "void main (void)\n"
-                                       "{\n"
-                                       "       int gx = int(gl_GlobalInvocationID.x);\n"
-                                       "       int gy = int(gl_GlobalInvocationID.y);\n"
-                                       "       int gz = int(gl_GlobalInvocationID.z);\n"
-                                       "       " + atomicInvocation + ";\n"
-                                       "}\n";
-
-       sourceCollections.glslSources.add(m_name) << glu::ComputeSource(source.c_str());
+       if (isSpirvAtomicOperation(m_operation))
+       {
+               const CaseVariant                                       caseVariant{m_imageType, m_format.order, m_format.type, CaseVariant::CHECK_TYPE_END_RESULTS};
+               const tcu::StringTemplate                       shaderTemplate{getSpirvAtomicOpShader(caseVariant)};
+               std::map<std::string, std::string>      specializations;
+
+               specializations["OPNAME"] = getSpirvAtomicOpName(m_operation);
+               if (isSpirvAtomicNoLastArgOp(m_operation))
+                       specializations["LASTARG"] = "";
+
+               sourceCollections.spirvAsmSources.add(m_name) << shaderTemplate.specialize(specializations);
+       }
+       else
+       {
+               const string    versionDecl                             = glu::getGLSLVersionDeclaration(m_glslVersion);
+
+               const bool              uintFormat                              = isUintFormat(mapTextureFormat(m_format));
+               const bool              intFormat                               = isIntFormat(mapTextureFormat(m_format));
+               const UVec3             gridSize                                = getShaderGridSize(m_imageType, m_imageSize);
+               const string    atomicCoord                             = getCoordStr(m_imageType, "gx % " + toString(gridSize.x()), "gy", "gz");
+
+               const string    atomicArgExpr                   = (uintFormat ? "uint" : intFormat ? "int" : "float")
+                                                                                               + getAtomicFuncArgumentShaderStr(m_operation, "gx", "gy", "gz", IVec3(NUM_INVOCATIONS_PER_PIXEL*gridSize.x(), gridSize.y(), gridSize.z()));
+
+               const string    compareExchangeStr              = (m_operation == ATOMIC_OPERATION_COMPARE_EXCHANGE) ? ", 18" + string(uintFormat ? "u" : "") : "";
+               const string    atomicInvocation                = getAtomicOperationShaderFuncName(m_operation) + "(u_resultImage, " + atomicCoord + compareExchangeStr + ", " + atomicArgExpr + ")";
+               const string    shaderImageFormatStr    = getShaderImageFormatQualifier(m_format);
+               const string    shaderImageTypeStr              = getShaderImageType(m_format, m_imageType);
+
+               string source = versionDecl + "\n"
+                                               "precision highp " + shaderImageTypeStr + ";\n"
+                                               "\n"
+                                               "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
+                                               "layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_resultImage;\n"
+                                               "\n"
+                                               "void main (void)\n"
+                                               "{\n"
+                                               "       int gx = int(gl_GlobalInvocationID.x);\n"
+                                               "       int gy = int(gl_GlobalInvocationID.y);\n"
+                                               "       int gz = int(gl_GlobalInvocationID.z);\n"
+                                               "       " + atomicInvocation + ";\n"
+                                               "}\n";
+
+               sourceCollections.glslSources.add(m_name) << glu::ComputeSource(source.c_str());
+       }
 }
 
 class BinaryAtomicIntermValuesCase : public vkt::TestCase
@@ -387,38 +461,53 @@ void BinaryAtomicIntermValuesCase::checkSupport (Context& context) const
 
 void BinaryAtomicIntermValuesCase::initPrograms (SourceCollections& sourceCollections) const
 {
-       const string    versionDecl                             = glu::getGLSLVersionDeclaration(m_glslVersion);
-
-       const bool              uintFormat                              = isUintFormat(mapTextureFormat(m_format));
-       const bool              intFormat                               = isIntFormat(mapTextureFormat(m_format));
-       const string    colorVecTypeName                = string(uintFormat ? "u" : intFormat ? "i" : "") + "vec4";
-       const UVec3             gridSize                                = getShaderGridSize(m_imageType, m_imageSize);
-       const string    atomicCoord                             = getCoordStr(m_imageType, "gx % " + toString(gridSize.x()), "gy", "gz");
-       const string    invocationCoord                 = getCoordStr(m_imageType, "gx", "gy", "gz");
-       const string    atomicArgExpr                   = (uintFormat ? "uint" : intFormat ? "int" : "float")
-                                                                                       + getAtomicFuncArgumentShaderStr(m_operation, "gx", "gy", "gz", IVec3(NUM_INVOCATIONS_PER_PIXEL*gridSize.x(), gridSize.y(), gridSize.z()));
-
-       const string    compareExchangeStr              = (m_operation == ATOMIC_OPERATION_COMPARE_EXCHANGE) ? ", 18" + string(uintFormat ? "u" : "")  : "";
-       const string    atomicInvocation                = getAtomicOperationShaderFuncName(m_operation) + "(u_resultImage, " + atomicCoord + compareExchangeStr + ", " + atomicArgExpr + ")";
-       const string    shaderImageFormatStr    = getShaderImageFormatQualifier(m_format);
-       const string    shaderImageTypeStr              = getShaderImageType(m_format, m_imageType);
-
-       string source = versionDecl + "\n"
-                                       "precision highp " + shaderImageTypeStr + ";\n"
-                                       "\n"
-                                       "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
-                                       "layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_resultImage;\n"
-                                       "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_intermValuesImage;\n"
-                                       "\n"
-                                       "void main (void)\n"
-                                       "{\n"
-                                       "       int gx = int(gl_GlobalInvocationID.x);\n"
-                                       "       int gy = int(gl_GlobalInvocationID.y);\n"
-                                       "       int gz = int(gl_GlobalInvocationID.z);\n"
-                                       "       imageStore(u_intermValuesImage, " + invocationCoord + ", " + colorVecTypeName + "(" + atomicInvocation + "));\n"
-                                       "}\n";
-
-       sourceCollections.glslSources.add(m_name) << glu::ComputeSource(source.c_str());
+       if (isSpirvAtomicOperation(m_operation))
+       {
+               const CaseVariant                                       caseVariant{m_imageType, m_format.order, m_format.type, CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS};
+               const tcu::StringTemplate                       shaderTemplate{getSpirvAtomicOpShader(caseVariant)};
+               std::map<std::string, std::string>      specializations;
+
+               specializations["OPNAME"] = getSpirvAtomicOpName(m_operation);
+               if (isSpirvAtomicNoLastArgOp(m_operation))
+                       specializations["LASTARG"] = "";
+
+               sourceCollections.spirvAsmSources.add(m_name) << shaderTemplate.specialize(specializations);
+       }
+       else
+       {
+               const string    versionDecl                             = glu::getGLSLVersionDeclaration(m_glslVersion);
+
+               const bool              uintFormat                              = isUintFormat(mapTextureFormat(m_format));
+               const bool              intFormat                               = isIntFormat(mapTextureFormat(m_format));
+               const string    colorVecTypeName                = string(uintFormat ? "u" : intFormat ? "i" : "") + "vec4";
+               const UVec3             gridSize                                = getShaderGridSize(m_imageType, m_imageSize);
+               const string    atomicCoord                             = getCoordStr(m_imageType, "gx % " + toString(gridSize.x()), "gy", "gz");
+               const string    invocationCoord                 = getCoordStr(m_imageType, "gx", "gy", "gz");
+               const string    atomicArgExpr                   = (uintFormat ? "uint" : intFormat ? "int" : "float")
+                                                                                               + getAtomicFuncArgumentShaderStr(m_operation, "gx", "gy", "gz", IVec3(NUM_INVOCATIONS_PER_PIXEL*gridSize.x(), gridSize.y(), gridSize.z()));
+
+               const string    compareExchangeStr              = (m_operation == ATOMIC_OPERATION_COMPARE_EXCHANGE) ? ", 18" + string(uintFormat ? "u" : "")  : "";
+               const string    atomicInvocation                = getAtomicOperationShaderFuncName(m_operation) + "(u_resultImage, " + atomicCoord + compareExchangeStr + ", " + atomicArgExpr + ")";
+               const string    shaderImageFormatStr    = getShaderImageFormatQualifier(m_format);
+               const string    shaderImageTypeStr              = getShaderImageType(m_format, m_imageType);
+
+               string source = versionDecl + "\n"
+                                               "precision highp " + shaderImageTypeStr + ";\n"
+                                               "\n"
+                                               "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
+                                               "layout (" + shaderImageFormatStr + ", binding=0) coherent uniform " + shaderImageTypeStr + " u_resultImage;\n"
+                                               "layout (" + shaderImageFormatStr + ", binding=1) writeonly uniform " + shaderImageTypeStr + " u_intermValuesImage;\n"
+                                               "\n"
+                                               "void main (void)\n"
+                                               "{\n"
+                                               "       int gx = int(gl_GlobalInvocationID.x);\n"
+                                               "       int gy = int(gl_GlobalInvocationID.y);\n"
+                                               "       int gz = int(gl_GlobalInvocationID.z);\n"
+                                               "       imageStore(u_intermValuesImage, " + invocationCoord + ", " + colorVecTypeName + "(" + atomicInvocation + "));\n"
+                                               "}\n";
+
+               sourceCollections.glslSources.add(m_name) << glu::ComputeSource(source.c_str());
+       }
 }
 
 class BinaryAtomicInstanceBase : public vkt::TestInstance
diff --git a/external/vulkancts/modules/vulkan/image/vktImageAtomicSpirvShaders.cpp b/external/vulkancts/modules/vulkan/image/vktImageAtomicSpirvShaders.cpp
new file mode 100644 (file)
index 0000000..59da84e
--- /dev/null
@@ -0,0 +1,2903 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2020 Valve Corporation.
+ * Copyright (c) 2020 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Helper SPIR-V shaders for some image atomic operations.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktImageAtomicSpirvShaders.hpp"
+
+#include <array>
+#include <map>
+
+namespace vkt
+{
+namespace image
+{
+
+namespace
+{
+
+const std::string kShader_1d_r32ui_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage1D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage1D u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, gx % 64, uint(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 50
+; Schema: 0
+OpCapability Shader
+OpCapability Image1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %49 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 1D 0 0 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%46 = OpTypePointer Image %9
+%49 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %8
+%35 = OpLoad %6 %8
+%36 = OpIMul %6 %34 %35
+%37 = OpLoad %6 %18
+%38 = OpLoad %6 %18
+%39 = OpIMul %6 %37 %38
+%40 = OpIAdd %6 %36 %39
+%41 = OpLoad %6 %23
+%42 = OpLoad %6 %23
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpBitcast %9 %44
+%47 = OpImageTexelPointer %46 %30 %33 %13
+%48 = ${OPNAME} %9 %47 %19 %13 ${LASTARG:default=%45}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_1d_r32ui_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage1D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage1D u_resultImage;
+; layout (r32ui, binding=1) writeonly uniform uimage1D u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, gx, uvec4(imageAtomicAdd(u_resultImage, gx % 64, uint(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 55
+; Schema: 0
+OpCapability Shader
+OpCapability Image1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %33 DescriptorSet 0
+OpDecorate %33 Binding 0
+OpDecorate %33 Coherent
+OpDecorate %54 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 1D 0 0 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%33 = OpVariable %29 UniformConstant
+%35 = OpConstant %6 64
+%49 = OpTypePointer Image %9
+%52 = OpTypeVector %9 4
+%54 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%34 = OpLoad %6 %8
+%36 = OpSMod %6 %34 %35
+%37 = OpLoad %6 %8
+%38 = OpLoad %6 %8
+%39 = OpIMul %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpLoad %6 %18
+%42 = OpIMul %6 %40 %41
+%43 = OpIAdd %6 %39 %42
+%44 = OpLoad %6 %23
+%45 = OpLoad %6 %23
+%46 = OpIMul %6 %44 %45
+%47 = OpIAdd %6 %43 %46
+%48 = OpBitcast %9 %47
+%50 = OpImageTexelPointer %49 %33 %36 %13
+%51 = ${OPNAME} %9 %50 %19 %13 ${LASTARG:default=%48}
+%53 = OpCompositeConstruct %52 %51 %51 %51 %51
+OpImageWrite %31 %32 %53
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_1d_r32i_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage1D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage1D u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, gx % 64, int(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 49
+; Schema: 0
+OpCapability Shader
+OpCapability Image1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %48 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 1D 0 0 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%45 = OpTypePointer Image %6
+%48 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %8
+%35 = OpLoad %6 %8
+%36 = OpIMul %6 %34 %35
+%37 = OpLoad %6 %18
+%38 = OpLoad %6 %18
+%39 = OpIMul %6 %37 %38
+%40 = OpIAdd %6 %36 %39
+%41 = OpLoad %6 %23
+%42 = OpLoad %6 %23
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%46 = OpImageTexelPointer %45 %30 %33 %13
+%47 = ${OPNAME} %6 %46 %19 %13 ${LASTARG:default=%44}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_1d_r32i_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage1D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage1D u_resultImage;
+; layout (r32i, binding=1) writeonly uniform iimage1D u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, gx, ivec4(imageAtomicAdd(u_resultImage, gx % 64, int(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 54
+; Schema: 0
+OpCapability Shader
+OpCapability Image1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %33 DescriptorSet 0
+OpDecorate %33 Binding 0
+OpDecorate %33 Coherent
+OpDecorate %53 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 1D 0 0 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%33 = OpVariable %29 UniformConstant
+%35 = OpConstant %6 64
+%48 = OpTypePointer Image %6
+%51 = OpTypeVector %6 4
+%53 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%34 = OpLoad %6 %8
+%36 = OpSMod %6 %34 %35
+%37 = OpLoad %6 %8
+%38 = OpLoad %6 %8
+%39 = OpIMul %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpLoad %6 %18
+%42 = OpIMul %6 %40 %41
+%43 = OpIAdd %6 %39 %42
+%44 = OpLoad %6 %23
+%45 = OpLoad %6 %23
+%46 = OpIMul %6 %44 %45
+%47 = OpIAdd %6 %43 %46
+%49 = OpImageTexelPointer %48 %33 %36 %13
+%50 = ${OPNAME} %6 %49 %19 %13 ${LASTARG:default=%47}
+%52 = OpCompositeConstruct %51 %50 %50 %50 %50
+OpImageWrite %31 %32 %52
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_1d_array_r32ui_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage1DArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage1DArray u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec2(gx % 64,gy), uint(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 53
+; Schema: 0
+OpCapability Shader
+OpCapability Image1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %52 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 1D 0 1 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%35 = OpTypeVector %6 2
+%49 = OpTypePointer Image %9
+%52 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%36 = OpCompositeConstruct %35 %33 %34
+%37 = OpLoad %6 %8
+%38 = OpLoad %6 %8
+%39 = OpIMul %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpLoad %6 %18
+%42 = OpIMul %6 %40 %41
+%43 = OpIAdd %6 %39 %42
+%44 = OpLoad %6 %23
+%45 = OpLoad %6 %23
+%46 = OpIMul %6 %44 %45
+%47 = OpIAdd %6 %43 %46
+%48 = OpBitcast %9 %47
+%50 = OpImageTexelPointer %49 %30 %36 %13
+%51 = ${OPNAME} %9 %50 %19 %13 ${LASTARG:default=%48}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_1d_array_r32ui_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage1DArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage1DArray u_resultImage;
+; layout (r32ui, binding=1) writeonly uniform uimage1DArray u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec2(gx,gy), uvec4(imageAtomicAdd(u_resultImage, ivec2(gx % 64,gy), uint(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 60
+; Schema: 0
+OpCapability Shader
+OpCapability Image1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %36 DescriptorSet 0
+OpDecorate %36 Binding 0
+OpDecorate %36 Coherent
+OpDecorate %59 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 1D 0 1 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%34 = OpTypeVector %6 2
+%36 = OpVariable %29 UniformConstant
+%38 = OpConstant %6 64
+%54 = OpTypePointer Image %9
+%57 = OpTypeVector %9 4
+%59 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%35 = OpCompositeConstruct %34 %32 %33
+%37 = OpLoad %6 %8
+%39 = OpSMod %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpCompositeConstruct %34 %39 %40
+%42 = OpLoad %6 %8
+%43 = OpLoad %6 %8
+%44 = OpIMul %6 %42 %43
+%45 = OpLoad %6 %18
+%46 = OpLoad %6 %18
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%49 = OpLoad %6 %23
+%50 = OpLoad %6 %23
+%51 = OpIMul %6 %49 %50
+%52 = OpIAdd %6 %48 %51
+%53 = OpBitcast %9 %52
+%55 = OpImageTexelPointer %54 %36 %41 %13
+%56 = ${OPNAME} %9 %55 %19 %13 ${LASTARG:default=%53}
+%58 = OpCompositeConstruct %57 %56 %56 %56 %56
+OpImageWrite %31 %35 %58
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_1d_array_r32i_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage1DArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage1DArray u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec2(gx % 64,gy), int(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 52
+; Schema: 0
+OpCapability Shader
+OpCapability Image1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %51 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 1D 0 1 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%35 = OpTypeVector %6 2
+%48 = OpTypePointer Image %6
+%51 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%36 = OpCompositeConstruct %35 %33 %34
+%37 = OpLoad %6 %8
+%38 = OpLoad %6 %8
+%39 = OpIMul %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpLoad %6 %18
+%42 = OpIMul %6 %40 %41
+%43 = OpIAdd %6 %39 %42
+%44 = OpLoad %6 %23
+%45 = OpLoad %6 %23
+%46 = OpIMul %6 %44 %45
+%47 = OpIAdd %6 %43 %46
+%49 = OpImageTexelPointer %48 %30 %36 %13
+%50 = ${OPNAME} %6 %49 %19 %13 ${LASTARG:default=%47}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_1d_array_r32i_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage1DArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage1DArray u_resultImage;
+; layout (r32i, binding=1) writeonly uniform iimage1DArray u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec2(gx,gy), ivec4(imageAtomicAdd(u_resultImage, ivec2(gx % 64,gy), int(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 59
+; Schema: 0
+OpCapability Shader
+OpCapability Image1D
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %36 DescriptorSet 0
+OpDecorate %36 Binding 0
+OpDecorate %36 Coherent
+OpDecorate %58 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 1D 0 1 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%34 = OpTypeVector %6 2
+%36 = OpVariable %29 UniformConstant
+%38 = OpConstant %6 64
+%53 = OpTypePointer Image %6
+%56 = OpTypeVector %6 4
+%58 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%35 = OpCompositeConstruct %34 %32 %33
+%37 = OpLoad %6 %8
+%39 = OpSMod %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpCompositeConstruct %34 %39 %40
+%42 = OpLoad %6 %8
+%43 = OpLoad %6 %8
+%44 = OpIMul %6 %42 %43
+%45 = OpLoad %6 %18
+%46 = OpLoad %6 %18
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%49 = OpLoad %6 %23
+%50 = OpLoad %6 %23
+%51 = OpIMul %6 %49 %50
+%52 = OpIAdd %6 %48 %51
+%54 = OpImageTexelPointer %53 %36 %41 %13
+%55 = ${OPNAME} %6 %54 %19 %13 ${LASTARG:default=%52}
+%57 = OpCompositeConstruct %56 %55 %55 %55 %55
+OpImageWrite %31 %35 %57
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_2d_r32ui_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage2D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage2D u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec2(gx % 64,gy), uint(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 53
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %52 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 2D 0 0 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%35 = OpTypeVector %6 2
+%49 = OpTypePointer Image %9
+%52 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%36 = OpCompositeConstruct %35 %33 %34
+%37 = OpLoad %6 %8
+%38 = OpLoad %6 %8
+%39 = OpIMul %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpLoad %6 %18
+%42 = OpIMul %6 %40 %41
+%43 = OpIAdd %6 %39 %42
+%44 = OpLoad %6 %23
+%45 = OpLoad %6 %23
+%46 = OpIMul %6 %44 %45
+%47 = OpIAdd %6 %43 %46
+%48 = OpBitcast %9 %47
+%50 = OpImageTexelPointer %49 %30 %36 %13
+%51 = ${OPNAME} %9 %50 %19 %13 ${LASTARG:default=%48}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_2d_r32ui_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage2D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage2D u_resultImage;
+; layout (r32ui, binding=1) writeonly uniform uimage2D u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec2(gx,gy), uvec4(imageAtomicAdd(u_resultImage, ivec2(gx % 64,gy), uint(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 60
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %36 DescriptorSet 0
+OpDecorate %36 Binding 0
+OpDecorate %36 Coherent
+OpDecorate %59 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 2D 0 0 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%34 = OpTypeVector %6 2
+%36 = OpVariable %29 UniformConstant
+%38 = OpConstant %6 64
+%54 = OpTypePointer Image %9
+%57 = OpTypeVector %9 4
+%59 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%35 = OpCompositeConstruct %34 %32 %33
+%37 = OpLoad %6 %8
+%39 = OpSMod %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpCompositeConstruct %34 %39 %40
+%42 = OpLoad %6 %8
+%43 = OpLoad %6 %8
+%44 = OpIMul %6 %42 %43
+%45 = OpLoad %6 %18
+%46 = OpLoad %6 %18
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%49 = OpLoad %6 %23
+%50 = OpLoad %6 %23
+%51 = OpIMul %6 %49 %50
+%52 = OpIAdd %6 %48 %51
+%53 = OpBitcast %9 %52
+%55 = OpImageTexelPointer %54 %36 %41 %13
+%56 = ${OPNAME} %9 %55 %19 %13 ${LASTARG:default=%53}
+%58 = OpCompositeConstruct %57 %56 %56 %56 %56
+OpImageWrite %31 %35 %58
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_2d_r32i_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage2D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage2D u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec2(gx % 64,gy), int(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 52
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %51 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 2D 0 0 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%35 = OpTypeVector %6 2
+%48 = OpTypePointer Image %6
+%51 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%36 = OpCompositeConstruct %35 %33 %34
+%37 = OpLoad %6 %8
+%38 = OpLoad %6 %8
+%39 = OpIMul %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpLoad %6 %18
+%42 = OpIMul %6 %40 %41
+%43 = OpIAdd %6 %39 %42
+%44 = OpLoad %6 %23
+%45 = OpLoad %6 %23
+%46 = OpIMul %6 %44 %45
+%47 = OpIAdd %6 %43 %46
+%49 = OpImageTexelPointer %48 %30 %36 %13
+%50 = ${OPNAME} %6 %49 %19 %13 ${LASTARG:default=%47}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_2d_r32i_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage2D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage2D u_resultImage;
+; layout (r32i, binding=1) writeonly uniform iimage2D u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec2(gx,gy), ivec4(imageAtomicAdd(u_resultImage, ivec2(gx % 64,gy), int(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 59
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %36 DescriptorSet 0
+OpDecorate %36 Binding 0
+OpDecorate %36 Coherent
+OpDecorate %58 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 2D 0 0 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%34 = OpTypeVector %6 2
+%36 = OpVariable %29 UniformConstant
+%38 = OpConstant %6 64
+%53 = OpTypePointer Image %6
+%56 = OpTypeVector %6 4
+%58 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%35 = OpCompositeConstruct %34 %32 %33
+%37 = OpLoad %6 %8
+%39 = OpSMod %6 %37 %38
+%40 = OpLoad %6 %18
+%41 = OpCompositeConstruct %34 %39 %40
+%42 = OpLoad %6 %8
+%43 = OpLoad %6 %8
+%44 = OpIMul %6 %42 %43
+%45 = OpLoad %6 %18
+%46 = OpLoad %6 %18
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%49 = OpLoad %6 %23
+%50 = OpLoad %6 %23
+%51 = OpIMul %6 %49 %50
+%52 = OpIAdd %6 %48 %51
+%54 = OpImageTexelPointer %53 %36 %41 %13
+%55 = ${OPNAME} %6 %54 %19 %13 ${LASTARG:default=%52}
+%57 = OpCompositeConstruct %56 %55 %55 %55 %55
+OpImageWrite %31 %35 %57
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_2d_array_r32ui_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage2DArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage2DArray u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), uint(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 54
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %53 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 2D 0 1 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%36 = OpTypeVector %6 3
+%50 = OpTypePointer Image %9
+%53 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%35 = OpLoad %6 %23
+%37 = OpCompositeConstruct %36 %33 %34 %35
+%38 = OpLoad %6 %8
+%39 = OpLoad %6 %8
+%40 = OpIMul %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %18
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpLoad %6 %23
+%46 = OpLoad %6 %23
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%49 = OpBitcast %9 %48
+%51 = OpImageTexelPointer %50 %30 %37 %13
+%52 = ${OPNAME} %9 %51 %19 %13 ${LASTARG:default=%49}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_2d_array_r32ui_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage2DArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage2DArray u_resultImage;
+; layout (r32ui, binding=1) writeonly uniform uimage2DArray u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec3(gx,gy,gz), uvec4(imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), uint(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 62
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %37 DescriptorSet 0
+OpDecorate %37 Binding 0
+OpDecorate %37 Coherent
+OpDecorate %61 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 2D 0 1 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%35 = OpTypeVector %6 3
+%37 = OpVariable %29 UniformConstant
+%39 = OpConstant %6 64
+%56 = OpTypePointer Image %9
+%59 = OpTypeVector %9 4
+%61 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%34 = OpLoad %6 %23
+%36 = OpCompositeConstruct %35 %32 %33 %34
+%38 = OpLoad %6 %8
+%40 = OpSMod %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %23
+%43 = OpCompositeConstruct %35 %40 %41 %42
+%44 = OpLoad %6 %8
+%45 = OpLoad %6 %8
+%46 = OpIMul %6 %44 %45
+%47 = OpLoad %6 %18
+%48 = OpLoad %6 %18
+%49 = OpIMul %6 %47 %48
+%50 = OpIAdd %6 %46 %49
+%51 = OpLoad %6 %23
+%52 = OpLoad %6 %23
+%53 = OpIMul %6 %51 %52
+%54 = OpIAdd %6 %50 %53
+%55 = OpBitcast %9 %54
+%57 = OpImageTexelPointer %56 %37 %43 %13
+%58 = ${OPNAME} %9 %57 %19 %13 ${LASTARG:default=%55}
+%60 = OpCompositeConstruct %59 %58 %58 %58 %58
+OpImageWrite %31 %36 %60
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_2d_array_r32i_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage2DArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage2DArray u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), int(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 53
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %52 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 2D 0 1 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%36 = OpTypeVector %6 3
+%49 = OpTypePointer Image %6
+%52 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%35 = OpLoad %6 %23
+%37 = OpCompositeConstruct %36 %33 %34 %35
+%38 = OpLoad %6 %8
+%39 = OpLoad %6 %8
+%40 = OpIMul %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %18
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpLoad %6 %23
+%46 = OpLoad %6 %23
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%50 = OpImageTexelPointer %49 %30 %37 %13
+%51 = ${OPNAME} %6 %50 %19 %13 ${LASTARG:default=%48}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_2d_array_r32i_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage2DArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage2DArray u_resultImage;
+; layout (r32i, binding=1) writeonly uniform iimage2DArray u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec3(gx,gy,gz), ivec4(imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), int(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 61
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %37 DescriptorSet 0
+OpDecorate %37 Binding 0
+OpDecorate %37 Coherent
+OpDecorate %60 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 2D 0 1 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%35 = OpTypeVector %6 3
+%37 = OpVariable %29 UniformConstant
+%39 = OpConstant %6 64
+%55 = OpTypePointer Image %6
+%58 = OpTypeVector %6 4
+%60 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%34 = OpLoad %6 %23
+%36 = OpCompositeConstruct %35 %32 %33 %34
+%38 = OpLoad %6 %8
+%40 = OpSMod %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %23
+%43 = OpCompositeConstruct %35 %40 %41 %42
+%44 = OpLoad %6 %8
+%45 = OpLoad %6 %8
+%46 = OpIMul %6 %44 %45
+%47 = OpLoad %6 %18
+%48 = OpLoad %6 %18
+%49 = OpIMul %6 %47 %48
+%50 = OpIAdd %6 %46 %49
+%51 = OpLoad %6 %23
+%52 = OpLoad %6 %23
+%53 = OpIMul %6 %51 %52
+%54 = OpIAdd %6 %50 %53
+%56 = OpImageTexelPointer %55 %37 %43 %13
+%57 = ${OPNAME} %6 %56 %19 %13 ${LASTARG:default=%54}
+%59 = OpCompositeConstruct %58 %57 %57 %57 %57
+OpImageWrite %31 %36 %59
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_3d_r32ui_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage3D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage3D u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), uint(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 54
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %53 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 3D 0 0 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%36 = OpTypeVector %6 3
+%50 = OpTypePointer Image %9
+%53 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%35 = OpLoad %6 %23
+%37 = OpCompositeConstruct %36 %33 %34 %35
+%38 = OpLoad %6 %8
+%39 = OpLoad %6 %8
+%40 = OpIMul %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %18
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpLoad %6 %23
+%46 = OpLoad %6 %23
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%49 = OpBitcast %9 %48
+%51 = OpImageTexelPointer %50 %30 %37 %13
+%52 = ${OPNAME} %9 %51 %19 %13 ${LASTARG:default=%49}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_3d_r32ui_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimage3D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimage3D u_resultImage;
+; layout (r32ui, binding=1) writeonly uniform uimage3D u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec3(gx,gy,gz), uvec4(imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), uint(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 62
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %37 DescriptorSet 0
+OpDecorate %37 Binding 0
+OpDecorate %37 Coherent
+OpDecorate %61 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 3D 0 0 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%35 = OpTypeVector %6 3
+%37 = OpVariable %29 UniformConstant
+%39 = OpConstant %6 64
+%56 = OpTypePointer Image %9
+%59 = OpTypeVector %9 4
+%61 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%34 = OpLoad %6 %23
+%36 = OpCompositeConstruct %35 %32 %33 %34
+%38 = OpLoad %6 %8
+%40 = OpSMod %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %23
+%43 = OpCompositeConstruct %35 %40 %41 %42
+%44 = OpLoad %6 %8
+%45 = OpLoad %6 %8
+%46 = OpIMul %6 %44 %45
+%47 = OpLoad %6 %18
+%48 = OpLoad %6 %18
+%49 = OpIMul %6 %47 %48
+%50 = OpIAdd %6 %46 %49
+%51 = OpLoad %6 %23
+%52 = OpLoad %6 %23
+%53 = OpIMul %6 %51 %52
+%54 = OpIAdd %6 %50 %53
+%55 = OpBitcast %9 %54
+%57 = OpImageTexelPointer %56 %37 %43 %13
+%58 = ${OPNAME} %9 %57 %19 %13 ${LASTARG:default=%55}
+%60 = OpCompositeConstruct %59 %58 %58 %58 %58
+OpImageWrite %31 %36 %60
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_3d_r32i_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage3D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage3D u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), int(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 53
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %52 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 3D 0 0 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%36 = OpTypeVector %6 3
+%49 = OpTypePointer Image %6
+%52 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%35 = OpLoad %6 %23
+%37 = OpCompositeConstruct %36 %33 %34 %35
+%38 = OpLoad %6 %8
+%39 = OpLoad %6 %8
+%40 = OpIMul %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %18
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpLoad %6 %23
+%46 = OpLoad %6 %23
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%50 = OpImageTexelPointer %49 %30 %37 %13
+%51 = ${OPNAME} %6 %50 %19 %13 ${LASTARG:default=%48}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_3d_r32i_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimage3D;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimage3D u_resultImage;
+; layout (r32i, binding=1) writeonly uniform iimage3D u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec3(gx,gy,gz), ivec4(imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), int(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 61
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %37 DescriptorSet 0
+OpDecorate %37 Binding 0
+OpDecorate %37 Coherent
+OpDecorate %60 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 3D 0 0 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%35 = OpTypeVector %6 3
+%37 = OpVariable %29 UniformConstant
+%39 = OpConstant %6 64
+%55 = OpTypePointer Image %6
+%58 = OpTypeVector %6 4
+%60 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%34 = OpLoad %6 %23
+%36 = OpCompositeConstruct %35 %32 %33 %34
+%38 = OpLoad %6 %8
+%40 = OpSMod %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %23
+%43 = OpCompositeConstruct %35 %40 %41 %42
+%44 = OpLoad %6 %8
+%45 = OpLoad %6 %8
+%46 = OpIMul %6 %44 %45
+%47 = OpLoad %6 %18
+%48 = OpLoad %6 %18
+%49 = OpIMul %6 %47 %48
+%50 = OpIAdd %6 %46 %49
+%51 = OpLoad %6 %23
+%52 = OpLoad %6 %23
+%53 = OpIMul %6 %51 %52
+%54 = OpIAdd %6 %50 %53
+%56 = OpImageTexelPointer %55 %37 %43 %13
+%57 = ${OPNAME} %6 %56 %19 %13 ${LASTARG:default=%54}
+%59 = OpCompositeConstruct %58 %57 %57 %57 %57
+OpImageWrite %31 %36 %59
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_cube_r32ui_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimageCube;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimageCube u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), uint(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 54
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %53 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 Cube 0 0 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%36 = OpTypeVector %6 3
+%50 = OpTypePointer Image %9
+%53 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%35 = OpLoad %6 %23
+%37 = OpCompositeConstruct %36 %33 %34 %35
+%38 = OpLoad %6 %8
+%39 = OpLoad %6 %8
+%40 = OpIMul %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %18
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpLoad %6 %23
+%46 = OpLoad %6 %23
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%49 = OpBitcast %9 %48
+%51 = OpImageTexelPointer %50 %30 %37 %13
+%52 = ${OPNAME} %9 %51 %19 %13 ${LASTARG:default=%49}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_cube_r32ui_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimageCube;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimageCube u_resultImage;
+; layout (r32ui, binding=1) writeonly uniform uimageCube u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec3(gx,gy,gz), uvec4(imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), uint(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 62
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %37 DescriptorSet 0
+OpDecorate %37 Binding 0
+OpDecorate %37 Coherent
+OpDecorate %61 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 Cube 0 0 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%35 = OpTypeVector %6 3
+%37 = OpVariable %29 UniformConstant
+%39 = OpConstant %6 64
+%56 = OpTypePointer Image %9
+%59 = OpTypeVector %9 4
+%61 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%34 = OpLoad %6 %23
+%36 = OpCompositeConstruct %35 %32 %33 %34
+%38 = OpLoad %6 %8
+%40 = OpSMod %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %23
+%43 = OpCompositeConstruct %35 %40 %41 %42
+%44 = OpLoad %6 %8
+%45 = OpLoad %6 %8
+%46 = OpIMul %6 %44 %45
+%47 = OpLoad %6 %18
+%48 = OpLoad %6 %18
+%49 = OpIMul %6 %47 %48
+%50 = OpIAdd %6 %46 %49
+%51 = OpLoad %6 %23
+%52 = OpLoad %6 %23
+%53 = OpIMul %6 %51 %52
+%54 = OpIAdd %6 %50 %53
+%55 = OpBitcast %9 %54
+%57 = OpImageTexelPointer %56 %37 %43 %13
+%58 = ${OPNAME} %9 %57 %19 %13 ${LASTARG:default=%55}
+%60 = OpCompositeConstruct %59 %58 %58 %58 %58
+OpImageWrite %31 %36 %60
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_cube_r32i_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimageCube;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimageCube u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), int(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 53
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %52 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 Cube 0 0 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%36 = OpTypeVector %6 3
+%49 = OpTypePointer Image %6
+%52 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%35 = OpLoad %6 %23
+%37 = OpCompositeConstruct %36 %33 %34 %35
+%38 = OpLoad %6 %8
+%39 = OpLoad %6 %8
+%40 = OpIMul %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %18
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpLoad %6 %23
+%46 = OpLoad %6 %23
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%50 = OpImageTexelPointer %49 %30 %37 %13
+%51 = ${OPNAME} %6 %50 %19 %13 ${LASTARG:default=%48}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_cube_r32i_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimageCube;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimageCube u_resultImage;
+; layout (r32i, binding=1) writeonly uniform iimageCube u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec3(gx,gy,gz), ivec4(imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), int(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 61
+; Schema: 0
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %37 DescriptorSet 0
+OpDecorate %37 Binding 0
+OpDecorate %37 Coherent
+OpDecorate %60 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 Cube 0 0 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%35 = OpTypeVector %6 3
+%37 = OpVariable %29 UniformConstant
+%39 = OpConstant %6 64
+%55 = OpTypePointer Image %6
+%58 = OpTypeVector %6 4
+%60 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%34 = OpLoad %6 %23
+%36 = OpCompositeConstruct %35 %32 %33 %34
+%38 = OpLoad %6 %8
+%40 = OpSMod %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %23
+%43 = OpCompositeConstruct %35 %40 %41 %42
+%44 = OpLoad %6 %8
+%45 = OpLoad %6 %8
+%46 = OpIMul %6 %44 %45
+%47 = OpLoad %6 %18
+%48 = OpLoad %6 %18
+%49 = OpIMul %6 %47 %48
+%50 = OpIAdd %6 %46 %49
+%51 = OpLoad %6 %23
+%52 = OpLoad %6 %23
+%53 = OpIMul %6 %51 %52
+%54 = OpIAdd %6 %50 %53
+%56 = OpImageTexelPointer %55 %37 %43 %13
+%57 = ${OPNAME} %6 %56 %19 %13 ${LASTARG:default=%54}
+%59 = OpCompositeConstruct %58 %57 %57 %57 %57
+OpImageWrite %31 %36 %59
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_cube_array_r32ui_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimageCubeArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimageCubeArray u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), uint(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 54
+; Schema: 0
+OpCapability Shader
+OpCapability ImageCubeArray
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %53 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 Cube 0 1 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%36 = OpTypeVector %6 3
+%50 = OpTypePointer Image %9
+%53 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%35 = OpLoad %6 %23
+%37 = OpCompositeConstruct %36 %33 %34 %35
+%38 = OpLoad %6 %8
+%39 = OpLoad %6 %8
+%40 = OpIMul %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %18
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpLoad %6 %23
+%46 = OpLoad %6 %23
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%49 = OpBitcast %9 %48
+%51 = OpImageTexelPointer %50 %30 %37 %13
+%52 = ${OPNAME} %9 %51 %19 %13 ${LASTARG:default=%49}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_cube_array_r32ui_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp uimageCubeArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32ui, binding=0) coherent uniform uimageCubeArray u_resultImage;
+; layout (r32ui, binding=1) writeonly uniform uimageCubeArray u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec3(gx,gy,gz), uvec4(imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), uint(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 62
+; Schema: 0
+OpCapability Shader
+OpCapability ImageCubeArray
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %37 DescriptorSet 0
+OpDecorate %37 Binding 0
+OpDecorate %37 Coherent
+OpDecorate %61 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %9 Cube 0 1 0 2 R32ui
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%35 = OpTypeVector %6 3
+%37 = OpVariable %29 UniformConstant
+%39 = OpConstant %6 64
+%56 = OpTypePointer Image %9
+%59 = OpTypeVector %9 4
+%61 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%34 = OpLoad %6 %23
+%36 = OpCompositeConstruct %35 %32 %33 %34
+%38 = OpLoad %6 %8
+%40 = OpSMod %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %23
+%43 = OpCompositeConstruct %35 %40 %41 %42
+%44 = OpLoad %6 %8
+%45 = OpLoad %6 %8
+%46 = OpIMul %6 %44 %45
+%47 = OpLoad %6 %18
+%48 = OpLoad %6 %18
+%49 = OpIMul %6 %47 %48
+%50 = OpIAdd %6 %46 %49
+%51 = OpLoad %6 %23
+%52 = OpLoad %6 %23
+%53 = OpIMul %6 %51 %52
+%54 = OpIAdd %6 %50 %53
+%55 = OpBitcast %9 %54
+%57 = OpImageTexelPointer %56 %37 %43 %13
+%58 = ${OPNAME} %9 %57 %19 %13 ${LASTARG:default=%55}
+%60 = OpCompositeConstruct %59 %58 %58 %58 %58
+OpImageWrite %31 %36 %60
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_cube_array_r32i_end_result = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimageCubeArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimageCubeArray u_resultImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), int(gx*gx + gy*gy + gz*gz));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 53
+; Schema: 0
+OpCapability Shader
+OpCapability ImageCubeArray
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 0
+OpDecorate %30 Coherent
+OpDecorate %52 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 Cube 0 1 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%32 = OpConstant %6 64
+%36 = OpTypeVector %6 3
+%49 = OpTypePointer Image %6
+%52 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %6 %8
+%33 = OpSMod %6 %31 %32
+%34 = OpLoad %6 %18
+%35 = OpLoad %6 %23
+%37 = OpCompositeConstruct %36 %33 %34 %35
+%38 = OpLoad %6 %8
+%39 = OpLoad %6 %8
+%40 = OpIMul %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %18
+%43 = OpIMul %6 %41 %42
+%44 = OpIAdd %6 %40 %43
+%45 = OpLoad %6 %23
+%46 = OpLoad %6 %23
+%47 = OpIMul %6 %45 %46
+%48 = OpIAdd %6 %44 %47
+%50 = OpImageTexelPointer %49 %30 %37 %13
+%51 = ${OPNAME} %6 %50 %19 %13 ${LASTARG:default=%48}
+OpReturn
+OpFunctionEnd
+)";
+
+const std::string kShader_cube_array_r32i_intermediate_values = R"(
+; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been
+; replaced with a template parameter and the last argument for it has been made optional.
+;
+; #version 440
+; precision highp iimageCubeArray;
+;
+; layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+; layout (r32i, binding=0) coherent uniform iimageCubeArray u_resultImage;
+; layout (r32i, binding=1) writeonly uniform iimageCubeArray u_intermValuesImage;
+;
+; void main (void)
+; {
+;     int gx = int(gl_GlobalInvocationID.x);
+;     int gy = int(gl_GlobalInvocationID.y);
+;     int gz = int(gl_GlobalInvocationID.z);
+;     imageStore(u_intermValuesImage, ivec3(gx,gy,gz), ivec4(imageAtomicAdd(u_resultImage, ivec3(gx % 64,gy,gz), int(gx*gx + gy*gy + gz*gz))));
+; }
+;
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 61
+; Schema: 0
+OpCapability Shader
+OpCapability ImageCubeArray
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %4 "main" %12
+OpExecutionMode %4 LocalSize 1 1 1
+OpDecorate %12 BuiltIn GlobalInvocationId
+OpDecorate %30 DescriptorSet 0
+OpDecorate %30 Binding 1
+OpDecorate %30 NonReadable
+OpDecorate %37 DescriptorSet 0
+OpDecorate %37 Binding 0
+OpDecorate %37 Coherent
+OpDecorate %60 BuiltIn WorkgroupSize
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%7 = OpTypePointer Function %6
+%9 = OpTypeInt 32 0
+%10 = OpTypeVector %9 3
+%11 = OpTypePointer Input %10
+%12 = OpVariable %11 Input
+%13 = OpConstant %9 0
+%14 = OpTypePointer Input %9
+%19 = OpConstant %9 1
+%24 = OpConstant %9 2
+%28 = OpTypeImage %6 Cube 0 1 0 2 R32i
+%29 = OpTypePointer UniformConstant %28
+%30 = OpVariable %29 UniformConstant
+%35 = OpTypeVector %6 3
+%37 = OpVariable %29 UniformConstant
+%39 = OpConstant %6 64
+%55 = OpTypePointer Image %6
+%58 = OpTypeVector %6 4
+%60 = OpConstantComposite %10 %19 %19 %19
+%4 = OpFunction %2 None %3
+%5 = OpLabel
+%8 = OpVariable %7 Function
+%18 = OpVariable %7 Function
+%23 = OpVariable %7 Function
+%15 = OpAccessChain %14 %12 %13
+%16 = OpLoad %9 %15
+%17 = OpBitcast %6 %16
+OpStore %8 %17
+%20 = OpAccessChain %14 %12 %19
+%21 = OpLoad %9 %20
+%22 = OpBitcast %6 %21
+OpStore %18 %22
+%25 = OpAccessChain %14 %12 %24
+%26 = OpLoad %9 %25
+%27 = OpBitcast %6 %26
+OpStore %23 %27
+%31 = OpLoad %28 %30
+%32 = OpLoad %6 %8
+%33 = OpLoad %6 %18
+%34 = OpLoad %6 %23
+%36 = OpCompositeConstruct %35 %32 %33 %34
+%38 = OpLoad %6 %8
+%40 = OpSMod %6 %38 %39
+%41 = OpLoad %6 %18
+%42 = OpLoad %6 %23
+%43 = OpCompositeConstruct %35 %40 %41 %42
+%44 = OpLoad %6 %8
+%45 = OpLoad %6 %8
+%46 = OpIMul %6 %44 %45
+%47 = OpLoad %6 %18
+%48 = OpLoad %6 %18
+%49 = OpIMul %6 %47 %48
+%50 = OpIAdd %6 %46 %49
+%51 = OpLoad %6 %23
+%52 = OpLoad %6 %23
+%53 = OpIMul %6 %51 %52
+%54 = OpIAdd %6 %50 %53
+%56 = OpImageTexelPointer %55 %37 %43 %13
+%57 = ${OPNAME} %6 %56 %19 %13 ${LASTARG:default=%54}
+%59 = OpCompositeConstruct %58 %57 %57 %57 %57
+OpImageWrite %31 %36 %59
+OpReturn
+OpFunctionEnd
+)";
+
+} // anonymous namespace
+
+bool CaseVariant::operator< (const CaseVariant& other) const
+{
+       // Simple lexicographical comparison using the struct members.
+       const std::array<int, 4> thisMembers =
+       {{
+               static_cast<int>(imageType),
+               static_cast<int>(textureFormat.order),
+               static_cast<int>(textureFormat.type),
+               static_cast<int>(checkType),
+       }};
+
+       const std::array<int, 4> otherMembers =
+       {{
+               static_cast<int>(other.imageType),
+               static_cast<int>(other.textureFormat.order),
+               static_cast<int>(other.textureFormat.type),
+               static_cast<int>(other.checkType),
+       }};
+
+       return thisMembers < otherMembers;
+}
+
+CaseVariant::CaseVariant (ImageType imgtype, tcu::TextureFormat::ChannelOrder order, tcu::TextureFormat::ChannelType chtype, CheckType cktype)
+       : imageType{imgtype}, textureFormat{order, chtype}, checkType{cktype}
+{}
+
+std::string getSpirvAtomicOpShader (const CaseVariant& caseVariant)
+{
+       using ShadersMapT       = std::map<CaseVariant, const std::string*>;
+       using ValueType         = ShadersMapT::value_type;
+
+       static const ShadersMapT kShadersMap =
+       {
+               ValueType{CaseVariant{IMAGE_TYPE_1D,                    tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_1d_r32ui_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_1D,                    tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_1d_r32ui_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_1D,                    tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_1d_r32i_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_1D,                    tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_1d_r32i_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_1D_ARRAY,              tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_1d_array_r32ui_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_1D_ARRAY,              tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_1d_array_r32ui_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_1D_ARRAY,              tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_1d_array_r32i_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_1D_ARRAY,              tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_1d_array_r32i_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_2D,                    tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_2d_r32ui_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_2D,                    tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_2d_r32ui_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_2D,                    tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_2d_r32i_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_2D,                    tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_2d_r32i_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_2D_ARRAY,              tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_2d_array_r32ui_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_2D_ARRAY,              tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_2d_array_r32ui_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_2D_ARRAY,              tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_2d_array_r32i_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_2D_ARRAY,              tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_2d_array_r32i_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_3D,                    tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_3d_r32ui_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_3D,                    tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_3d_r32ui_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_3D,                    tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_3d_r32i_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_3D,                    tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_3d_r32i_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_CUBE,                  tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_cube_r32ui_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_CUBE,                  tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_cube_r32ui_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_CUBE,                  tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_cube_r32i_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_CUBE,                  tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_cube_r32i_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_CUBE_ARRAY,    tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_cube_array_r32ui_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_CUBE_ARRAY,    tcu::TextureFormat::R,  tcu::TextureFormat::UNSIGNED_INT32,     CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_cube_array_r32ui_intermediate_values},
+               ValueType{CaseVariant{IMAGE_TYPE_CUBE_ARRAY,    tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_END_RESULTS},                   &kShader_cube_array_r32i_end_result},
+               ValueType{CaseVariant{IMAGE_TYPE_CUBE_ARRAY,    tcu::TextureFormat::R,  tcu::TextureFormat::SIGNED_INT32,       CaseVariant::CHECK_TYPE_INTERMEDIATE_RESULTS},  &kShader_cube_array_r32i_intermediate_values},
+       };
+
+       const auto iter = kShadersMap.find(caseVariant);
+       DE_ASSERT(iter != kShadersMap.end());
+       return *(iter->second);
+}
+
+} // namespace image
+} // namespace vkt
+
+// Note: the SPIR-V shaders above were created using the atomic addition shaders as a base, replacing OpAtomicIAdd with a string
+// template and making the last operation argument optional. Because the atomic addition shaders are generated, the final version of
+// each shader was obtained from TestResults.qpa after running the whole atomic addition group, using the Python script documented
+// below.
+#if 0
+import html
+import re
+import sys
+
+STATE_OUT = 0
+STATE_GLSL = 1
+STATE_SPIRV = 2
+
+state = STATE_OUT
+test_name = None
+glsl_lines = []
+spirv_lines = []
+header_printed = False
+
+for line in sys.stdin:
+       if line.startswith("#beginTestCaseResult"):
+               test_name = line.strip().split()[1]
+               test_name = "_".join(test_name.split(".")[-2:])
+
+       if "<ShaderSource>" in line:
+               line = re.sub(r".*<ShaderSource>", "", line)
+               state = STATE_GLSL
+
+       if "</ShaderSource>" in line:
+               state = STATE_OUT
+
+       if "<SpirVAssemblySource>" in line:
+               line = re.sub(r".*<SpirVAssemblySource>", "", line)
+               state = STATE_SPIRV
+
+       if "</SpirVAssemblySource>" in line:
+               state = STATE_OUT
+               if not header_printed:
+                       print("#include <string>")
+                       print()
+                       header_printed = True
+               print("const std::string kShader_%s = R\"(" % (test_name,))
+               print("; The SPIR-V shader below is based on the following GLSL shader, but OpAtomicIAdd has been")
+               print("; replaced with a template parameter and the last argument for it has been made optional.")
+               print(";")
+               for glsl_line in glsl_lines:
+                       glsl_line = html.unescape(glsl_line)
+                       print("; %s" % (glsl_line,), end="")
+               print(";")
+               for spirv_line in spirv_lines:
+                       spirv_line = html.unescape(spirv_line)
+                       if "OpAtomicIAdd" in spirv_line:
+                               words = spirv_line.strip().split()
+                               for i in range(len(words)):
+                                       if words[i] == "OpAtomicIAdd":
+                                               words[i] = r"${OPNAME}"
+                               words[-1] = r"${LASTARG:default=%s}" % (words[-1], )
+                               spirv_line = " ".join(words) + "\n"
+                       print("%s" % (spirv_line, ), end="")
+               print(")\";")
+               print()
+
+               test_name = None
+               glsl_lines = []
+               spirv_lines = []
+
+       if state == STATE_GLSL:
+               glsl_lines.append(line)
+       elif state == STATE_SPIRV:
+               spirv_lines.append(line)
+#endif
diff --git a/external/vulkancts/modules/vulkan/image/vktImageAtomicSpirvShaders.hpp b/external/vulkancts/modules/vulkan/image/vktImageAtomicSpirvShaders.hpp
new file mode 100644 (file)
index 0000000..e4e284c
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _VKTIMAGEATOMICSPIRVSHADERS_HPP
+#define _VKTIMAGEATOMICSPIRVSHADERS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2020 Valve Corporation.
+ * Copyright (c) 2020 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Helper SPIR-V shaders for some image atomic operations.
+ *//*--------------------------------------------------------------------*/
+#include "vktImageTestsUtil.hpp"
+
+#include <string>
+
+namespace vkt
+{
+namespace image
+{
+
+// Test case variant, used when deciding which SPIR-V shader to get.
+struct CaseVariant
+{
+       enum CheckType
+       {
+               CHECK_TYPE_INTERMEDIATE_RESULTS = 0,
+               CHECK_TYPE_END_RESULTS,
+       };
+
+       ImageType                       imageType;
+       tcu::TextureFormat      textureFormat;
+       CheckType                       checkType;
+
+       // Allows this struct to be used as key in maps.
+       bool operator< (const CaseVariant& other) const;
+
+       // Constructor.
+       CaseVariant (ImageType imgtype, tcu::TextureFormat::ChannelOrder order, tcu::TextureFormat::ChannelType chtype, CheckType cktype);
+};
+
+// Gets the shader template for the appropriate case variant.
+std::string getSpirvAtomicOpShader (const CaseVariant& caseVariant);
+
+} // namespace image
+} // namespace vkt
+
+#endif // _VKTIMAGEATOMICSPIRVSHADERS_HPP
index b9ac5d0..bbada76 100644 (file)
@@ -428718,6 +428718,90 @@ dEQP-VK.image.atomic_operations.add.cube_array.r32ui_end_result
 dEQP-VK.image.atomic_operations.add.cube_array.r32ui_intermediate_values
 dEQP-VK.image.atomic_operations.add.cube_array.r32i_end_result
 dEQP-VK.image.atomic_operations.add.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.cube_array.r32i_intermediate_values
 dEQP-VK.image.atomic_operations.min.1d.r32ui_end_result
 dEQP-VK.image.atomic_operations.min.1d.r32ui_intermediate_values
 dEQP-VK.image.atomic_operations.min.1d.r32i_end_result
index 2edc568..d4c9e20 100644 (file)
@@ -428679,6 +428679,90 @@ dEQP-VK.image.atomic_operations.add.cube_array.r32ui_end_result
 dEQP-VK.image.atomic_operations.add.cube_array.r32ui_intermediate_values
 dEQP-VK.image.atomic_operations.add.cube_array.r32i_end_result
 dEQP-VK.image.atomic_operations.add.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.sub.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.sub.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.sub.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.inc.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.inc.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.inc.cube_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.1d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.1d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.1d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.1d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.1d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.2d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.2d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.2d_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.2d_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.2d_array.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.3d.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.3d.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.3d.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.3d.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.cube.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.cube.r32i_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube_array.r32ui_end_result
+dEQP-VK.image.atomic_operations.dec.cube_array.r32ui_intermediate_values
+dEQP-VK.image.atomic_operations.dec.cube_array.r32i_end_result
+dEQP-VK.image.atomic_operations.dec.cube_array.r32i_intermediate_values
 dEQP-VK.image.atomic_operations.min.1d.r32ui_end_result
 dEQP-VK.image.atomic_operations.min.1d.r32ui_intermediate_values
 dEQP-VK.image.atomic_operations.min.1d.r32i_end_result
index d9ddedc..702f949 100644 (file)
@@ -24,6 +24,8 @@
 #include "tcuStringTemplate.hpp"
 #include "tcuDefs.hpp"
 
+#include "deStringUtil.hpp"
+
 #include <sstream>
 
 using std::string;
@@ -51,6 +53,10 @@ void StringTemplate::setString (const std::string& str)
        m_template = str;
 }
 
+const string kSingleLineFlag = "single-line";
+const string kOptFlag = "opt";
+const string kDefaultFlag = "default=";
+
 string StringTemplate::specialize (const map<string, string>& params) const
 {
        ostringstream res;
@@ -73,20 +79,27 @@ string StringTemplate::specialize (const map<string, string>& params) const
                        string  paramStr                = m_template.substr(paramNdx+2, paramEndNdx-2-paramNdx);
                        bool    paramSingleLine = false;
                        bool    paramOptional   = false;
+                       bool    paramDefault    = false;
                        string  paramName;
+                       string  defaultValue;
                        size_t colonNdx = paramStr.find(":");
                        if (colonNdx != string::npos)
                        {
                                paramName = paramStr.substr(0, colonNdx);
                                string flagsStr = paramStr.substr(colonNdx+1);
-                               if (flagsStr == "single-line")
+                               if (flagsStr == kSingleLineFlag)
                                {
                                        paramSingleLine = true;
                                }
-                               else if (flagsStr == "opt")
+                               else if (flagsStr == kOptFlag)
                                {
                                        paramOptional = true;
                                }
+                               else if (de::beginsWith(flagsStr, kDefaultFlag))
+                               {
+                                       paramDefault = true;
+                                       defaultValue = flagsStr.substr(kDefaultFlag.size());
+                               }
                                else
                                {
                                        TCU_THROW(InternalError, (string("Unrecognized flag") + paramStr).c_str());
@@ -109,6 +122,8 @@ string StringTemplate::specialize (const map<string, string>& params) const
                                else
                                        res << val;
                        }
+                       else if (paramDefault)
+                               res << defaultValue;
                        else if (!paramOptional)
                                TCU_THROW(InternalError, (string("Value for parameter '") + paramName + "' not found in map").c_str());