Add SpirvValidationCapabilitiesTest test case implementation
authorAdam Czupryna <adam.czupryna@mobica.com>
Fri, 24 Nov 2017 13:59:39 +0000 (14:59 +0100)
committerAlexander Galazin <alexander.galazin@arm.com>
Tue, 23 Jan 2018 02:40:52 +0000 (03:40 +0100)
Add CTS_ARB_gl_spirv test implementation that contains:
SpirvValidationCapabilitiesTest

Affects:

KHR-GL45.gl_spirv.spirv_validation_capabilities_test

Components: OpenGL

VK-GL-CTS issue: 554

Change-Id: I0ba93f0ea0dd5c8c9c1348033448fe5ada82b99b

16 files changed:
external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.1.x/gl45-master.txt
external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.1.x/gl46-master.txt
external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_gpu_shader_int64.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture2.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture_clamp_frag.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture_clamp_vert.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/GL_EXT_shader_image_load_formatted.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/binary_p0s0.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s0.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s1.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s2.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s3.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s4.nspv [new file with mode: 0644]
external/openglcts/data/spirv/spirv_validation_capabilities/binary_p2s0.nspv [new file with mode: 0644]
external/openglcts/modules/gl/gl4cGlSpirvTests.cpp
external/openglcts/modules/gl/gl4cGlSpirvTests.hpp

index f8e520e..1bf1fd9 100644 (file)
@@ -7745,3 +7745,4 @@ KHR-GL45.gl_spirv.spirv_glsl_to_spirv_enable_test
 KHR-GL45.gl_spirv.spirv_glsl_to_spirv_builtin_functions_test
 KHR-GL45.gl_spirv.spirv_glsl_to_spirv_specialization_constants_test
 KHR-GL45.gl_spirv.spirv_validation_builtin_variable_decorations_test
+KHR-GL45.gl_spirv.spirv_validation_capabilities_test
index 2987f1e..5bad2fc 100644 (file)
@@ -7745,3 +7745,4 @@ KHR-GL46.gl_spirv.spirv_glsl_to_spirv_enable_test
 KHR-GL46.gl_spirv.spirv_glsl_to_spirv_builtin_functions_test
 KHR-GL46.gl_spirv.spirv_glsl_to_spirv_specialization_constants_test
 KHR-GL46.gl_spirv.spirv_validation_builtin_variable_decorations_test
+KHR-GL46.gl_spirv.spirv_validation_capabilities_test
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_gpu_shader_int64.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_gpu_shader_int64.nspv
new file mode 100644 (file)
index 0000000..a0d2223
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_gpu_shader_int64.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture2.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture2.nspv
new file mode 100644 (file)
index 0000000..b5a11f2
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture2.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture_clamp_frag.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture_clamp_frag.nspv
new file mode 100644 (file)
index 0000000..a72fdf7
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture_clamp_frag.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture_clamp_vert.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture_clamp_vert.nspv
new file mode 100644 (file)
index 0000000..407a635
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_ARB_sparse_texture_clamp_vert.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/GL_EXT_shader_image_load_formatted.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_EXT_shader_image_load_formatted.nspv
new file mode 100644 (file)
index 0000000..a3f6539
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/GL_EXT_shader_image_load_formatted.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p0s0.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p0s0.nspv
new file mode 100644 (file)
index 0000000..69c9faa
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p0s0.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s0.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s0.nspv
new file mode 100644 (file)
index 0000000..b4c9c0a
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s0.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s1.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s1.nspv
new file mode 100644 (file)
index 0000000..b7d6765
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s1.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s2.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s2.nspv
new file mode 100644 (file)
index 0000000..8bd0d00
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s2.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s3.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s3.nspv
new file mode 100644 (file)
index 0000000..e4f1d5a
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s3.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s4.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s4.nspv
new file mode 100644 (file)
index 0000000..c89b853
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p1s4.nspv differ
diff --git a/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p2s0.nspv b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p2s0.nspv
new file mode 100644 (file)
index 0000000..501ca49
Binary files /dev/null and b/external/openglcts/data/spirv/spirv_validation_capabilities/binary_p2s0.nspv differ
index 78e6149..7e9e9bb 100644 (file)
@@ -260,36 +260,48 @@ bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType t
 
 #if defined DEQP_HAVE_SPIRV_TOOLS
 
+void consumer(spv_message_level_t, const char*, const spv_position_t&, const char* m)
+{
+       std::cerr << "error: " << m << std::endl;
+}
+
 void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
 {
        spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
 
-       auto print_msg_to_stderr = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
-               std::cerr << "error: " << m << std::endl;
-       };
-
-       core.SetMessageConsumer(print_msg_to_stderr);
+       core.SetMessageConsumer(consumer);
 
        if (!core.Assemble(src, &dst))
                TCU_THROW(InternalError, "Failed to assemble Spir-V source.");
-       if (!core.Validate(dst))
-               TCU_THROW(InternalError, "Failed to validate Spir-V module.");
 }
 
 void spirvDisassemble(std::string& dst, const ShaderBinaryDataType& src)
 {
        spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
 
-       auto print_msg_to_stderr = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
-               std::cerr << "error: " << m << std::endl;
-       };
-
-       core.SetMessageConsumer(print_msg_to_stderr);
+       core.SetMessageConsumer(consumer);
 
        if (!core.Disassemble(src, &dst))
                TCU_THROW(InternalError, "Failed to disassemble Spir-V module.");
 }
 
+bool spirvValidate(ShaderBinaryDataType& dst, bool throwOnError)
+{
+       spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
+
+       if (throwOnError)
+               core.SetMessageConsumer(consumer);
+
+       if (!core.Validate(dst))
+       {
+               if (throwOnError)
+                       TCU_THROW(InternalError, "Failed to validate Spir-V module.");
+               return false;
+       }
+
+       return true;
+}
+
 #else //DEQP_HAVE_SPIRV_TOOLS
 
 void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
@@ -305,7 +317,15 @@ void spirvDisassemble(std::string& dst, ShaderBinaryDataType& src)
        DE_UNREF(dst);
        DE_UNREF(src);
 
-       TCU_THROW(InternalError, "Glslang not available.");
+       TCU_THROW(InternalError, "Spirv-tools not available.");
+}
+
+bool spirvValidate(ShaderBinaryDataType& dst, bool throwOnError)
+{
+       DE_UNREF(dst);
+       DE_UNREF(throwOnError);
+
+       TCU_THROW(InternalError, "Spirv-tools not available.");
 }
 
 #endif // DEQP_HAVE_SPIRV_TOOLS
@@ -926,6 +946,7 @@ tcu::TestNode::IterateResult SpirvShaderBinaryMultipleShaderObjectsTest::iterate
        binary << SHADERTYPE_FRAGMENT << "mainf";
 
        glslangUtils::spirvAssemble(binary.binary, m_spirv);
+       glslangUtils::spirvValidate(binary.binary, true);
 #else  // DEQP_HAVE_SPIRV_TOOLS
        tcu::Archive& archive = m_testCtx.getArchive();
        ShaderBinary  binary  = commonUtils::readSpirV(
@@ -1093,6 +1114,7 @@ tcu::TestNode::IterateResult SpirvModulesStateQueriesTest::iterate()
                // Assemble Spir-V module
                vertexBinary.binary.clear();
                glslangUtils::spirvAssemble(vertexBinary.binary, input);
+               glslangUtils::spirvValidate(vertexBinary.binary, true);
        }
 #else  // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS
        tcu::Archive& archive = m_testCtx.getArchive();
@@ -3451,6 +3473,503 @@ bool SpirvValidationBuiltInVariableDecorationsTest::validMultiSamplingFunc(Valid
 
 /** Constructor.
  *
+ *  @param context     Rendering context
+ *  @param name        Test name
+ *  @param description Test description
+ */
+SpirvValidationCapabilitiesTest::SpirvValidationCapabilitiesTest(deqp::Context& context)
+       : TestCase(context, "spirv_validation_capabilities_test", "Test verifies if Spir-V capabilities works as expected.")
+{
+       /* Left blank intentionally */
+}
+
+/** Stub init method */
+void SpirvValidationCapabilitiesTest::init()
+{
+       ShaderStage computeStage;
+       computeStage.source = ComputeSource("#version 450\n"
+                                                                               "\n"
+                                                                               "layout (local_size_x = 1, local_size_y = 2, local_size_z = 1) in;\n"
+                                                                               "\n"
+                                                                               "layout (location = 0, rgba8) uniform image2DMS img0;\n"
+                                                                               "layout (location = 1, rgba8) uniform image2DMSArray img1;\n"
+                                                                               "layout (location = 2, rgba8) uniform image2DRect img2;\n"
+                                                                               "layout (location = 3, rgba8) uniform imageCube img3;\n"
+                                                                               "layout (location = 4, rgba8) uniform imageCubeArray img4;\n"
+                                                                               "layout (location = 5, rgba8) uniform imageBuffer img5;\n"
+                                                                               "layout (location = 6, rgba8) uniform image2D img6;\n"
+                                                                               "layout (location = 7, rgba8) uniform image1D img7;\n"
+                                                                               "layout (location = 8) uniform writeonly image1D img8;\n"
+                                                                               "layout (location = 9, rg32f) uniform image1D img9;\n"
+                                                                               "layout (location = 10) uniform sampler2DRect img10;\n"
+                                                                               "layout (location = 11) uniform samplerCubeArray img11;\n"
+                                                                               "layout (location = 12) uniform samplerBuffer img12;\n"
+                                                                               "layout (location = 13) uniform sampler1D img13;\n"
+                                                                               "layout (location = 14) uniform sampler2D img14;\n"
+                                                                               "\n"
+                                                                               "layout (binding = 0) uniform atomic_uint atCounter;\n"
+                                                                               "\n"
+                                                                               "void main()\n"
+                                                                               "{\n"
+                                                                               "    ivec2 size = imageSize(img6);\n"
+                                                                               "    ivec3 point = ivec3(gl_GlobalInvocationID);\n"
+                                                                               "    imageStore(img0, point.xy, 0, vec4(0));\n"
+                                                                               "    imageStore(img1, point, 0, vec4(0));\n"
+                                                                               "    imageStore(img2, point.xy, vec4(0));\n"
+                                                                               "    imageStore(img3, point, vec4(0));\n"
+                                                                               "    imageStore(img4, point, vec4(0));\n"
+                                                                               "    imageStore(img5, point.x, vec4(0));\n"
+                                                                               "    imageStore(img6, point.xy, vec4(0));\n"
+                                                                               "    imageStore(img7, point.x, vec4(0));\n"
+                                                                               "    imageStore(img8, point.x, vec4(0));\n"
+                                                                               "\n"
+                                                                               "    vec3 coord = vec3(0);\n"
+                                                                               "    ivec2 offset = ivec2(gl_GlobalInvocationID.xy);\n"
+                                                                               "    vec4 color;\n"
+                                                                               "    color = textureGather(img10, coord.xy);\n"
+                                                                               "    color = textureGather(img11, vec4(0));\n"
+                                                                               "    color = texelFetch(img12, point.x);\n"
+                                                                               "    color = textureGatherOffset(img14, coord.xy, offset);\n"
+                                                                               "    memoryBarrier();\n"
+                                                                               "}\n");
+
+       computeStage.caps.push_back("Shader");
+       computeStage.caps.push_back("SampledRect Shader");
+       computeStage.caps.push_back("SampledCubeArray Shader");
+       computeStage.caps.push_back("SampledBuffer Shader");
+       computeStage.caps.push_back("Sampled1D");
+       computeStage.caps.push_back("ImageRect SampledRect Shader");
+       computeStage.caps.push_back("Image1D Sampled1D");
+       computeStage.caps.push_back("ImageCubeArray SampledCubeArray Shader");
+       computeStage.caps.push_back("ImageBuffer SampledBuffer");
+       computeStage.caps.push_back("ImageMSArray Shader");
+       computeStage.caps.push_back("ImageQuery Shader");
+       computeStage.caps.push_back("ImageGatherExtended Shader");
+       computeStage.caps.push_back("StorageImageExtendedFormats Shader");
+       computeStage.caps.push_back("StorageImageWriteWithoutFormat Shader");
+       computeStage.caps.push_back("AtomicStorage Shader");
+
+       ShaderStage vertexStage;
+       vertexStage.source = VertexSource("#version 450\n"
+                                                                         "\n"
+                                                                         "layout (location = 0) in vec3 position;\n"
+                                                                         "layout (location = 1) in mat4 projMatrix;\n"
+                                                                         "\n"
+                                                                         "layout (location = 2, xfb_buffer = 0) out float xfbVal;\n"
+                                                                         "layout (location = 3) out vec2 texCoord;\n"
+                                                                         "\n"
+                                                                         "void main()\n"
+                                                                         "{\n"
+                                                                         "    double dval = double(position.x);\n"
+                                                                         "    gl_Position = vec4(position, 1.0) * projMatrix;\n"
+                                                                         "    gl_ClipDistance[0] = 0.0;\n"
+                                                                         "    gl_CullDistance[0] = 0.0;\n"
+                                                                         "\n"
+                                                                         "    xfbVal = 1.0;\n"
+                                                                         "    texCoord = vec2(0, 0);\n"
+                                                                         "}\n");
+
+       vertexStage.caps.push_back("Matrix");
+       vertexStage.caps.push_back("Shader Matrix");
+       vertexStage.caps.push_back("Float64");
+       vertexStage.caps.push_back("ClipDistance Shader");
+       vertexStage.caps.push_back("CullDistance Shader");
+       vertexStage.caps.push_back("TransformFeedback Shader");
+
+       ShaderStage tessCtrlStage;
+       tessCtrlStage.source =
+               TessellationControlSource("#version 450\n"
+                                                                 "\n"
+                                                                 "layout (vertices = 3) out;\n"
+                                                                 "\n"
+                                                                 "void main()\n"
+                                                                 "{\n"
+                                                                 "    if (gl_InvocationID == 0) {\n"
+                                                                 "        gl_TessLevelOuter[0] = 1.0;\n"
+                                                                 "        gl_TessLevelOuter[1] = 1.0;\n"
+                                                                 "        gl_TessLevelOuter[2] = 1.0;\n"
+                                                                 "        gl_TessLevelInner[0] = 1.0;\n"
+                                                                 "    }\n"
+                                                                 "\n"
+                                                                 "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+                                                                 "    gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n"
+                                                                 "}\n");
+
+       tessCtrlStage.caps.push_back("Tessellation Shader");
+       tessCtrlStage.caps.push_back("TessellationPointSize Tessellation");
+
+       ShaderStage tessEvalStage;
+       tessEvalStage.source = TessellationEvaluationSource("#version 450\n"
+                                                                                                               "\n"
+                                                                                                               "layout (triangles) in;\n"
+                                                                                                               "\n"
+                                                                                                               "void main()\n"
+                                                                                                               "{\n"
+                                                                                                               "    gl_Position = gl_TessCoord.x * gl_in[0].gl_Position +\n"
+                                                                                                               "                  gl_TessCoord.y * gl_in[1].gl_Position +\n"
+                                                                                                               "                  gl_TessCoord.z * gl_in[2].gl_Position;\n"
+                                                                                                               "}\n");
+
+       ShaderStage geometryStage;
+       geometryStage.source = GeometrySource("#version 450\n"
+                                                                                 "\n"
+                                                                                 "layout (triangles) in;\n"
+                                                                                 "layout (triangle_strip, max_vertices = 3) out;\n"
+                                                                                 "\n"
+                                                                                 "void main()\n"
+                                                                                 "{\n"
+                                                                                 "    gl_ViewportIndex = 0;\n"
+                                                                                 "    for (int i = 0; i < 3; ++i) {\n"
+                                                                                 "        gl_Position = gl_in[i].gl_Position;\n"
+                                                                                 "        gl_PointSize = gl_in[i].gl_PointSize;\n"
+                                                                                 "        EmitStreamVertex(0);\n"
+                                                                                 "    }\n"
+                                                                                 "    EndStreamPrimitive(0);\n"
+                                                                                 "}\n");
+
+       geometryStage.caps.push_back("Geometry Shader");
+       geometryStage.caps.push_back("GeometryPointSize Geometry");
+       geometryStage.caps.push_back("GeometryStreams Geometry");
+       geometryStage.caps.push_back("MultiViewport Geometry");
+
+       ShaderStage fragmentStage;
+       fragmentStage.source = FragmentSource("#version 450\n"
+                                                                                 "\n"
+                                                                                 "layout (location = 3) in vec2 texCoord;\n"
+                                                                                 "\n"
+                                                                                 "layout (location = 0) out vec4 fColor;\n"
+                                                                                 "\n"
+                                                                                 "layout (location = 1) uniform sampler2D tex;\n"
+                                                                                 "\n"
+                                                                                 "void main()\n"
+                                                                                 "{\n"
+                                                                                 "    vec2 p = vec2(gl_SampleID);\n"
+                                                                                 "    vec2 dx = dFdxFine(p);\n"
+                                                                                 "\n"
+                                                                                 "    interpolateAtCentroid(texCoord);"
+                                                                                 "\n"
+                                                                                 "    fColor = vec4(1.0);\n"
+                                                                                 "}\n");
+
+       fragmentStage.caps.push_back("Shader");
+       fragmentStage.caps.push_back("DerivativeControl Shader");
+       fragmentStage.caps.push_back("SampleRateShading");
+       fragmentStage.caps.push_back("InterpolationFunction");
+
+       ShaderStage dynamicIndexingStage;
+       dynamicIndexingStage.source = ComputeSource("#version 450\n"
+                                                                                               "\n"
+                                                                                               "layout (location = 0) uniform sampler2D uniSamp[10];\n"
+                                                                                               "layout (location = 10, rgba8) uniform image2D uniImg[10];\n"
+                                                                                               "layout (binding = 5) uniform UniData\n"
+                                                                                               "{\n"
+                                                                                               "   int a[10];\n"
+                                                                                               "} uniBuff[10];\n"
+                                                                                               "layout (binding = 5) buffer StorageData\n"
+                                                                                               "{\n"
+                                                                                               "   int a[10];\n"
+                                                                                               "} storageBuff[10];\n"
+                                                                                               "\n"
+                                                                                               "void main()\n"
+                                                                                               "{\n"
+                                                                                               "    vec2 coord = vec2(0.0);\n"
+                                                                                               "    ivec2 point = ivec2(0);\n"
+                                                                                               "\n"
+                                                                                               "    int ret = 0;\n"
+                                                                                               "    for (int i = 0; i < 10; ++i)"
+                                                                                               "    {\n"
+                                                                                               "        ret = ret + uniBuff[i].a[i] + storageBuff[i].a[i];\n"
+                                                                                               "        textureGather(uniSamp[i], coord);\n"
+                                                                                               "        imageLoad(uniImg[i], point);\n"
+                                                                                               "    }\n"
+                                                                                               "    memoryBarrier();\n"
+                                                                                               "}\n");
+
+       dynamicIndexingStage.caps.push_back("UniformBufferArrayDynamicIndexing");
+       dynamicIndexingStage.caps.push_back("SampledImageArrayDynamicIndexing");
+       dynamicIndexingStage.caps.push_back("StorageBufferArrayDynamicIndexing");
+       dynamicIndexingStage.caps.push_back("StorageImageArrayDynamicIndexing");
+
+       Pipeline computePipeline;
+       computePipeline.push_back(computeStage);
+
+       Pipeline standardPipeline;
+       standardPipeline.push_back(vertexStage);
+       standardPipeline.push_back(tessCtrlStage);
+       standardPipeline.push_back(tessEvalStage);
+       standardPipeline.push_back(geometryStage);
+       standardPipeline.push_back(fragmentStage);
+
+       Pipeline dynamicIndexingPipeline;
+       dynamicIndexingPipeline.push_back(dynamicIndexingStage);
+
+       m_pipelines.push_back(computePipeline);
+       m_pipelines.push_back(standardPipeline);
+       m_pipelines.push_back(dynamicIndexingPipeline);
+
+       if (m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_int64"))
+       {
+               ShaderStage computeStageExt("GL_ARB_gpu_shader_int64");
+               computeStageExt.source = ComputeSource("#version 450\n"
+                                                                                          "\n"
+                                                                                          "#extension GL_ARB_gpu_shader_int64 : require\n"
+                                                                                          "\n"
+                                                                                          "void main()\n"
+                                                                                          "{\n"
+                                                                                          "    int64_t ival = int64_t(gl_GlobalInvocationID.x);\n"
+                                                                                          "}\n");
+               computeStageExt.caps.push_back("Int64");
+
+               Pipeline extPipeline;
+               extPipeline.push_back(computeStageExt);
+
+               m_pipelines.push_back(extPipeline);
+       }
+
+       if (m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_texture2"))
+       {
+               ShaderStage computeStageExt("GL_ARB_sparse_texture2");
+               computeStageExt.source = ComputeSource("#version 450\n"
+                                                                                          "\n"
+                                                                                          "#extension GL_ARB_sparse_texture2 : require\n"
+                                                                                          "\n"
+                                                                                          "layout (location = 0) uniform sampler2D tex;\n"
+                                                                                          "\n"
+                                                                                          "void main()\n"
+                                                                                          "{\n"
+                                                                                          "    vec2 p = vec2(0.0);\n"
+                                                                                          "\n"
+                                                                                          "    vec4 spCol;\n"
+                                                                                          "    sparseTextureARB(tex, p, spCol);\n"
+                                                                                          "}\n");
+
+               computeStageExt.caps.push_back("SparseResidency");
+
+               Pipeline extPipeline;
+               extPipeline.push_back(computeStageExt);
+
+               m_pipelines.push_back(extPipeline);
+
+               if (m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_texture_clamp"))
+               {
+                       ShaderStage vertexStageExt("GL_ARB_sparse_texture_clamp_vert");
+                       vertexStageExt.source = VertexSource("#version 450\n"
+                                                                                                "\n"
+                                                                                                "layout (location = 0) in vec4 pos;\n"
+                                                                                                "\n"
+                                                                                                "void main()\n"
+                                                                                                "{\n"
+                                                                                                "    gl_Position = pos;\n"
+                                                                                                "}\n");
+
+                       ShaderStage fragmentStageExt("GL_ARB_sparse_texture_clamp_frag");
+                       fragmentStageExt.source = FragmentSource("#version 450\n"
+                                                                                                        "\n"
+                                                                                                        "#extension GL_ARB_sparse_texture2 : require\n"
+                                                                                                        "#extension GL_ARB_sparse_texture_clamp : require\n"
+                                                                                                        "\n"
+                                                                                                        "uniform sampler2D tex;\n"
+                                                                                                        "\n"
+                                                                                                        "layout (location = 0) out vec4 spCol;\n"
+                                                                                                        "\n"
+                                                                                                        "void main()\n"
+                                                                                                        "{\n"
+                                                                                                        "    vec2 p = vec2(0.0);\n"
+                                                                                                        "\n"
+                                                                                                        "    sparseTextureClampARB(tex, p, 0.5, spCol);\n"
+                                                                                                        "}\n");
+
+                       fragmentStageExt.caps.push_back("MinLod");
+
+                       Pipeline extPipeline;
+                       extPipeline.push_back(vertexStageExt);
+                       extPipeline.push_back(fragmentStageExt);
+
+                       m_pipelines.push_back(extPipeline);
+               }
+       }
+
+       if (m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_image_load_formatted"))
+       {
+               ShaderStage computeStageExt("GL_EXT_shader_image_load_formatted");
+               computeStageExt.source = ComputeSource("#version 450\n"
+                                                                                          "\n"
+                                                                                          "#extension GL_EXT_shader_image_load_formatted : require\n"
+                                                                                          "\n"
+                                                                                          "layout (location = 0) uniform image2D img;\n"
+                                                                                          "\n"
+                                                                                          "void main()\n"
+                                                                                          "{\n"
+                                                                                          "    ivec3 point = ivec3(gl_GlobalInvocationID);\n"
+                                                                                          "    vec4 color = imageLoad(img, point.xy);\n"
+                                                                                          "}\n");
+
+               computeStageExt.caps.push_back("StorageImageReadWithoutFormat");
+
+               Pipeline extPipeline;
+               extPipeline.push_back(computeStageExt);
+
+               m_pipelines.push_back(extPipeline);
+       }
+}
+
+/** Stub de-init method */
+void SpirvValidationCapabilitiesTest::deinit()
+{
+}
+
+/** Executes test iteration.
+ *
+ *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
+ */
+tcu::TestNode::IterateResult SpirvValidationCapabilitiesTest::iterate()
+{
+       const Functions& gl = m_context.getRenderContext().getFunctions();
+
+       bool result = true;
+
+       for (int p = 0; p < m_pipelines.size(); ++p)
+       {
+               ProgramBinaries programBinaries;
+
+               Pipeline& pipeline = m_pipelines[p];
+               for (int s = 0; s < pipeline.size(); ++s)
+               {
+                       ShaderStage& stage = pipeline[s];
+#if defined                             DEQP_HAVE_GLSLANG
+                       stage.binary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), stage.source);
+                       std::stringstream ssw;
+                       if (stage.name.empty())
+                               ssw << "gl_cts/data/spirv/spirv_validation_capabilities/binary_p" << p << "s" << s << ".nspv";
+                       else
+                               ssw << "gl_cts/data/spirv/spirv_validation_capabilities/" << stage.name << ".nspv";
+                       commonUtils::writeSpirV(ssw.str().c_str(), stage.binary);
+#else  // DEQP_HAVE_GLSLANG
+                       tcu::Archive&    archive = m_testCtx.getArchive();
+                       std::stringstream ss;
+                       if (stage.name.empty())
+                               ss << "spirv/spirv_validation_capabilities/binary_p" << p << "s" << s << ".nspv";
+                       else
+                               ss << "spirv/spirv_validation_capabilities/" << stage.name << ".nspv";
+                       stage.binary = commonUtils::readSpirV(archive.getResource(ss.str().c_str()));
+#endif // DEQP_HAVE_GLSLANG
+                       programBinaries << stage.binary;
+               }
+
+               ShaderProgram program(gl, programBinaries);
+               if (!program.isOk())
+               {
+                       std::stringstream ssLog;
+
+                       ssLog << "Program build failed [" << p << "].\n";
+                       if (program.hasShader(SHADERTYPE_COMPUTE))
+                               ssLog << "Compute: " << program.getShaderInfo(SHADERTYPE_COMPUTE).infoLog << "\n";
+                       if (program.hasShader(SHADERTYPE_VERTEX))
+                               ssLog << "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n";
+                       if (program.hasShader(SHADERTYPE_TESSELLATION_CONTROL))
+                               ssLog << "TessellationCtrl: " << program.getShaderInfo(SHADERTYPE_TESSELLATION_CONTROL).infoLog << "\n";
+                       if (program.hasShader(SHADERTYPE_TESSELLATION_EVALUATION))
+                               ssLog << "TessellationEval: " << program.getShaderInfo(SHADERTYPE_TESSELLATION_EVALUATION).infoLog
+                                         << "\n";
+                       if (program.hasShader(SHADERTYPE_GEOMETRY))
+                               ssLog << "Geometry: " << program.getShaderInfo(SHADERTYPE_GEOMETRY).infoLog << "\n";
+                       if (program.hasShader(SHADERTYPE_FRAGMENT))
+                               ssLog << "Fragment: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n";
+                       ssLog << "Program: " << program.getProgramInfo().infoLog;
+
+                       m_testCtx.getLog() << tcu::TestLog::Message << ssLog.str() << tcu::TestLog::EndMessage;
+
+                       m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+                       return STOP;
+               }
+
+#if defined DEQP_HAVE_SPIRV_TOOLS
+               for (int s = 0; s < pipeline.size(); ++s)
+               {
+                       ShaderStage  stage  = pipeline[s];
+                       ShaderBinary binary = stage.binary;
+
+                       std::string spirVSource;
+                       glslangUtils::spirvDisassemble(spirVSource, binary.binary);
+
+                       for (int c = 0; c < stage.caps.size(); ++c)
+                       {
+                               std::string spirVSourceCut;
+                               int                     foundCount = spirVCapabilityCutOff(spirVSource, spirVSourceCut, stage.caps, c);
+
+                               if (foundCount == 0)
+                               {
+                                       m_testCtx.getLog()
+                                               << tcu::TestLog::Message << "OpCapability (" << stage.caps[c] << ") [" << p << "/" << s
+                                               << "].\n"
+                                               << "Neither capability nor capabilities that depends on this capability has been found."
+                                               << tcu::TestLog::EndMessage;
+                               }
+                               else
+                               {
+                                       // Assemble and validate cut off SpirV source
+                                       glslangUtils::spirvAssemble(binary.binary, spirVSourceCut);
+                                       if (glslangUtils::spirvValidate(binary.binary, false))
+                                       {
+                                               m_testCtx.getLog() << tcu::TestLog::Message << "OpCapability (" << stage.caps[c] << ") [" << p
+                                                                                  << "/" << s << "].\n"
+                                                                                  << "Validation passed without corresponding OpCapability declared."
+                                                                                  << tcu::TestLog::EndMessage;
+                                       }
+                               }
+                       }
+               }
+#endif // DEQP_HAVE_SPIRV_TOOLS
+       }
+
+       m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+       return STOP;
+}
+
+int SpirvValidationCapabilitiesTest::spirVCapabilityCutOff(std::string spirVSrcInput, std::string& spirVSrcOutput,
+                                                                                                                  CapabilitiesVec& capabilities, int& currentCapability)
+{
+       std::vector<std::string> current = de::splitString(capabilities[currentCapability], ' ');
+
+       CapabilitiesVec toDisable;
+       toDisable.push_back(current[0]);
+
+       // Search for capabilities that depends on current one as it should be removed either
+       for (int cr = 0; cr < capabilities.size(); ++cr)
+       {
+               std::vector<std::string> split = de::splitString(capabilities[cr], ' ');
+
+               if (split[0] == current[0])
+                       continue;
+
+               for (int s = 1; s < split.size(); ++s)
+               {
+                       if (split[s] == current[0])
+                               toDisable.push_back(split[0]);
+               }
+       }
+
+       // Disable current capability and capabilities that depends on it
+       int foundCount = 0;
+       spirVSrcOutput = spirVSrcInput;
+       for (int d = 0; d < toDisable.size(); ++d)
+       {
+               std::string searchString = std::string("OpCapability ") + toDisable[d];
+
+               size_t pos = spirVSrcOutput.find(searchString);
+
+               if (pos != std::string::npos)
+               {
+                       foundCount++;
+                       spirVSrcOutput.erase(pos, searchString.length());
+               }
+       }
+
+       return foundCount;
+}
+
+/** Constructor.
+ *
  *  @param context Rendering context.
  */
 GlSpirvTests::GlSpirvTests(deqp::Context& context)
@@ -3469,6 +3988,7 @@ void GlSpirvTests::init()
        addChild(new SpirvGlslToSpirVBuiltInFunctionsTest(m_context));
        addChild(new SpirvGlslToSpirVSpecializationConstantsTest(m_context));
        addChild(new SpirvValidationBuiltInVariableDecorationsTest(m_context));
+       addChild(new SpirvValidationCapabilitiesTest(m_context));
 }
 
 } /* gl4cts namespace */
index 25034b0..0671801 100644 (file)
@@ -44,6 +44,8 @@ namespace gl4cts
 
 typedef std::map<std::string, std::vector<std::string> > SpirVMapping;
 
+typedef std::vector<std::string> CapabilitiesVec;
+
 /**  Verifies if using SPIR-V modules for each shader stage works as expected. */
 class SpirvModulesPositiveTest : public deqp::TestCase
 {
@@ -210,8 +212,7 @@ public:
 
        tcu::TestNode::IterateResult iterate();
 
-private:
-       /* Private structs */
+private: /* Private structs */
        struct ValidationOutputStruct
        {
                GLubyte x, y, z;
@@ -269,6 +270,48 @@ private:
        std::string m_fragment;
 };
 
+/**  Verifies if Spir-V capabilities works as expected. */
+class SpirvValidationCapabilitiesTest : public deqp::TestCase
+{
+public:
+       /* Public methods */
+       SpirvValidationCapabilitiesTest(deqp::Context& context);
+
+       void init();
+       void deinit();
+
+       tcu::TestNode::IterateResult iterate();
+
+       int spirVCapabilityCutOff(std::string spirVSrcInput, std::string& spirVSrcOutput, CapabilitiesVec& capabilities,
+                                                         int& currentCapability);
+
+private:
+       typedef std::map<glu::ShaderType, CapabilitiesVec> CapabilitiesMap;
+
+       struct ShaderStage
+       {
+               std::string             name;
+               ShaderSource    source;
+               ShaderBinary    binary;
+               CapabilitiesVec caps;
+
+               ShaderStage()
+               {
+               }
+
+               ShaderStage(std::string _name) : name(_name)
+               {
+               }
+       };
+
+       typedef std::vector<ShaderStage> Pipeline;
+
+       /* Private methods */
+
+       /* Private members */
+       std::vector<Pipeline> m_pipelines;
+};
+
 /** Test group which encapsulates all sparse buffer conformance tests */
 class GlSpirvTests : public deqp::TestCaseGroup
 {