SPIR-V validation understands VK_EXT_scalar_block_layout
authorDavid Neto <dneto@google.com>
Wed, 10 Oct 2018 20:37:38 +0000 (16:37 -0400)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Fri, 9 Nov 2018 12:45:51 +0000 (07:45 -0500)
Refactor SPIR-V validator options into own struct and header

Shader build options now record scalar layout flag.

Shader build options can yield a validator options object.

Update SSBO and UBO layout tests to tell validation when they are
using scalar layout.

Update fetch_sources.py to include GitLab SPIRV-Tools supporting
validation of scalar block layout.

Remaining validation failures:
- FPRoundingMode checks are not sensitive to capabilities in
  SPV_KHR_float_controls

Components: Vulkan
Affects:
dEQP-VK.ssbo.*
dEQP-VK.ubo.*

Change-Id: I4449b58f8c33c82eea8965847059fdeb22806876

13 files changed:
external/fetch_sources.py [changed mode: 0644->0755]
external/vulkancts/framework/vulkan/CMakeLists.txt
external/vulkancts/framework/vulkan/vkPrograms.cpp
external/vulkancts/framework/vulkan/vkPrograms.hpp
external/vulkancts/framework/vulkan/vkShaderProgram.hpp
external/vulkancts/framework/vulkan/vkSpirVAsm.cpp
external/vulkancts/framework/vulkan/vkSpirVAsm.hpp
external/vulkancts/framework/vulkan/vkSpirVProgram.hpp
external/vulkancts/framework/vulkan/vkValidatorOptions.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/ssbo/vktSSBOLayoutCase.cpp
external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.cpp
external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.hpp
external/vulkancts/modules/vulkan/vktBuildPrograms.cpp

old mode 100644 (file)
new mode 100755 (executable)
index ed238a2..66ba8d7 100644 (file)
@@ -51,6 +51,7 @@ set(VKUTILNOSHADER_SRCS
        vkImageWithMemory.hpp
        vkShaderProgram.cpp
        vkShaderProgram.hpp
+       vkValidatorOptions.hpp
        vkYCbCrImageWithMemory.cpp
        vkYCbCrImageWithMemory.hpp
        vkObjUtil.cpp
index 6dd594a..8795d8b 100644 (file)
@@ -337,11 +337,11 @@ ProgramBinary* createProgramBinaryFromSpirV (const vector<deUint32>& binary)
 
 #if defined(DEQP_HAVE_SPIRV_TOOLS)
 
-void validateCompiledBinary(const vector<deUint32>& binary, glu::ShaderProgramInfo* buildInfo, deUint32 vulkanVersion, const SpirvVersion spirvVersion, const bool relaxedLayout)
+void validateCompiledBinary(const vector<deUint32>& binary, glu::ShaderProgramInfo* buildInfo, const SpirvValidatorOptions& options)
 {
        std::ostringstream validationLog;
 
-       if (!validateSpirV(binary.size(), &binary[0], &validationLog, vulkanVersion, spirvVersion, relaxedLayout))
+       if (!validateSpirV(binary.size(), &binary[0], &validationLog, options))
        {
                buildInfo->program.linkOk        = false;
                buildInfo->program.infoLog      += "\n" + validationLog.str();
@@ -602,8 +602,7 @@ ProgramBinary* buildProgram (const GlslSource& program, glu::ShaderProgramInfo*
 
                if (validateBinary)
                {
-                       const bool relaxedLayout = program.buildOptions.flags & ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS;
-                       validateCompiledBinary(binary, buildInfo, program.buildOptions.vulkanVersion, spirvVersion, relaxedLayout);
+                       validateCompiledBinary(binary, buildInfo, program.buildOptions.getSpirvValidatorOptions());
                }
 
                if (optimizationRecipe != 0)
@@ -685,8 +684,7 @@ ProgramBinary* buildProgram (const HlslSource& program, glu::ShaderProgramInfo*
 
                if (validateBinary)
                {
-                       const bool relaxedLayout = program.buildOptions.flags & ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS;
-                       validateCompiledBinary(binary, buildInfo, program.buildOptions.vulkanVersion, spirvVersion, relaxedLayout);
+                       validateCompiledBinary(binary, buildInfo, program.buildOptions.getSpirvValidatorOptions());
                }
 
                if (optimizationRecipe != 0)
@@ -744,9 +742,8 @@ ProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo*
                if (validateBinary)
                {
                        std::ostringstream      validationLog;
-                       const bool                      relaxedLayout   = false;
 
-                       if (!validateSpirV(binary.size(), &binary[0], &validationLog, program.buildOptions.vulkanVersion, spirvVersion, relaxedLayout))
+                       if (!validateSpirV(binary.size(), &binary[0], &validationLog, program.buildOptions.getSpirvValidatorOptions()))
                        {
                                buildInfo->compileOk = false;
                                buildInfo->infoLog += "\n" + validationLog.str();
@@ -799,7 +796,7 @@ void disassembleProgram (const ProgramBinary& program, std::ostream* dst)
                TCU_THROW(NotSupportedError, "Unsupported program format");
 }
 
-bool validateProgram (const ProgramBinary& program, std::ostream* dst, deUint32 vulkanVersion, bool relaxedLayout)
+bool validateProgram (const ProgramBinary& program, std::ostream* dst, const SpirvValidatorOptions& options)
 {
        if (program.getFormat() == PROGRAM_FORMAT_SPIRV)
        {
@@ -810,8 +807,7 @@ bool validateProgram (const ProgramBinary& program, std::ostream* dst, deUint32
                }
 
                if (isNativeSpirVBinaryEndianness())
-                       return validateSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst,
-                                                                vulkanVersion, extractSpirvVersion(program), relaxedLayout);
+                       return validateSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst, options);
                else
                        TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
        }
index 4087f9f..cca650d 100644 (file)
@@ -211,7 +211,7 @@ ProgramBinary*                      buildProgram            (const GlslSource& program, glu::ShaderProgramInf
 ProgramBinary*                 buildProgram            (const HlslSource& program, glu::ShaderProgramInfo* buildInfo, const tcu::CommandLine& commandLine);
 ProgramBinary*                 assembleProgram         (const vk::SpirVAsmSource& program, SpirVProgramInfo* buildInfo, const tcu::CommandLine& commandLine);
 void                                   disassembleProgram      (const ProgramBinary& program, std::ostream* dst);
-bool                                   validateProgram         (const ProgramBinary& program, std::ostream* dst, deUint32 vulkanVersion, bool relaxedLayout);
+bool                                   validateProgram         (const ProgramBinary& program, std::ostream* dst, const SpirvValidatorOptions&);
 
 Move<VkShaderModule>   createShaderModule      (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags);
 
index c567edf..73b96a1 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "vkDefs.hpp"
 #include "gluShaderProgram.hpp"
+#include "vkValidatorOptions.hpp"
 
 #include <string>
 
@@ -41,7 +42,8 @@ struct ShaderBuildOptions
        enum Flags
        {
                FLAG_USE_STORAGE_BUFFER_STORAGE_CLASS   = (1u<<0),
-               FLAG_ALLOW_RELAXED_OFFSETS                              = (1u<<1)       // allow block offsets to follow VK_KHR_relaxed_block_layout
+               FLAG_ALLOW_RELAXED_OFFSETS                              = (1u<<1),      // allow block offsets to follow VK_KHR_relaxed_block_layout
+               FLAG_ALLOW_SCALAR_OFFSETS                               = (1u<<2)       // allow block offsets to follow VK_EXT_scalar_block_layout
        };
 
        deUint32                vulkanVersion;
@@ -59,6 +61,22 @@ struct ShaderBuildOptions
                , targetVersion (SPIRV_VERSION_1_0)
                , flags                 (0u)
        {}
+
+       SpirvValidatorOptions getSpirvValidatorOptions() const
+       {
+               SpirvValidatorOptions::BlockLayoutRules rules = SpirvValidatorOptions::kDefaultBlockLayout;
+
+               if (flags & FLAG_ALLOW_SCALAR_OFFSETS)
+               {
+                       rules = SpirvValidatorOptions::kScalarBlockLayout;
+               }
+               else if (flags & FLAG_ALLOW_RELAXED_OFFSETS)
+               {
+                       rules = SpirvValidatorOptions::kRelaxedBlockLayout;
+               }
+
+               return SpirvValidatorOptions(vulkanVersion, rules);
+       }
 };
 
 enum ShaderLanguage
index 3ab6307..c20a5e0 100644 (file)
@@ -144,17 +144,31 @@ void disassembleSpirV (size_t binarySizeInWords, const deUint32* binary, std::os
        }
 }
 
-bool validateSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog, deUint32 vulkanVersion, SpirvVersion, bool relaxedLayout)
+bool validateSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog, const SpirvValidatorOptions &val_options)
 {
-       const spv_context       context         = spvContextCreate(mapVulkanVersionToSpirvToolsEnv(vulkanVersion));
+       const spv_context       context         = spvContextCreate(mapVulkanVersionToSpirvToolsEnv(val_options.vulkanVersion));
        spv_diagnostic          diagnostic      = DE_NULL;
 
        try
        {
                spv_const_binary_t              cbinary = { binary, binarySizeInWords };
 
-               spv_validator_options   options = spvValidatorOptionsCreate();
-               spvValidatorOptionsSetRelaxBlockLayout(options, relaxedLayout);
+               spv_validator_options options = spvValidatorOptionsCreate();
+
+               switch (val_options.blockLayout)
+               {
+                       case SpirvValidatorOptions::kDefaultBlockLayout:
+                               break;
+                       case SpirvValidatorOptions::kNoneBlockLayout:
+                               spvValidatorOptionsSetSkipBlockLayout(options, true);
+                               break;
+                       case SpirvValidatorOptions::kRelaxedBlockLayout:
+                               spvValidatorOptionsSetRelaxBlockLayout(options, true);
+                               break;
+                       case SpirvValidatorOptions::kScalarBlockLayout:
+                               spvValidatorOptionsSetScalarBlockLayout(options, true);
+                               break;
+               }
 
                const spv_result_t              valid   = spvValidateWithOptions(context, options, &cbinary, &diagnostic);
                const bool                              passed  = (valid == SPV_SUCCESS);
index 1afcf21..4ec795b 100644 (file)
@@ -38,7 +38,7 @@ bool  assembleSpirV           (const SpirVAsmSource* program, std::vector<deUint32>* dst,
 void   disassembleSpirV        (size_t binarySizeInWords, const deUint32* binary, std::ostream* dst, SpirvVersion spirvVersion);
 
 //! Validate SPIR-V binary, returning true if validation succeeds. Will fail with NotSupportedError if compiler is not available.
-bool   validateSpirV           (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog, deUint32 vulkanVersion, SpirvVersion spirvVersion, bool relaxedLayout);
+bool   validateSpirV           (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog, const SpirvValidatorOptions&);
 
 } // vk
 
index d0baba3..6f9d449 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "vkDefs.hpp"
 #include "deStringUtil.hpp"
+#include "vkValidatorOptions.hpp"
 
 #include <string>
 
@@ -50,6 +51,11 @@ struct SpirVAsmBuildOptions
                : vulkanVersion (VK_MAKE_VERSION(1, 0, 0))
                , targetVersion (SPIRV_VERSION_1_0)
        {}
+
+       SpirvValidatorOptions getSpirvValidatorOptions() const
+       {
+               return SpirvValidatorOptions(vulkanVersion);
+       }
 };
 
 struct SpirVAsmSource
diff --git a/external/vulkancts/framework/vulkan/vkValidatorOptions.hpp b/external/vulkancts/framework/vulkan/vkValidatorOptions.hpp
new file mode 100644 (file)
index 0000000..31ca8a0
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _VKVALIDATOROPTIONS_HPP
+#define _VKVALIDATOROPTIONS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2018 Google LLC
+ *
+ * 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 SPIR-V validator options
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+
+namespace vk
+{
+
+struct SpirvValidatorOptions
+{
+       enum BlockLayoutRules
+       {
+               // The default for the target Vulkan environment.
+               kDefaultBlockLayout,
+               // Don't check block layout
+               kNoneBlockLayout,
+               // VK_KHR_relaxed_block_layout
+               kRelaxedBlockLayout,
+               // VK_EXT_scalar_block_layout
+               kScalarBlockLayout
+       };
+
+       SpirvValidatorOptions(deUint32 the_vulkan_version = VK_MAKE_VERSION(1, 0, 0), BlockLayoutRules the_layout = kDefaultBlockLayout)
+       : vulkanVersion(the_vulkan_version), blockLayout(the_layout) {}
+
+       // The target Vulkan version.  This determines the SPIR-V environment rules to
+       // be checked. The bit pattern is as produced by VK_MAKE_VERSION.
+       deUint32 vulkanVersion;
+
+       // The block layout rules to enforce.
+       BlockLayoutRules blockLayout;
+};
+
+}  // namespace vk
+
+#endif // _VKVALIDATOROPTIONS_HPP
index 17a8228..d543b87 100644 (file)
@@ -2415,7 +2415,13 @@ void SSBOLayoutCase::initPrograms (vk::SourceCollections& programCollection) con
 {
        DE_ASSERT(!m_computeShaderSrc.empty());
 
-       if (usesRelaxedLayout(m_interface))
+       // Valid scalar layouts are a superset of valid relaxed layouts.  So check scalar layout first.
+       if (usesScalarLayout(m_interface))
+       {
+               programCollection.glslSources.add("compute") << glu::ComputeSource(m_computeShaderSrc)
+                       << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS);
+       }
+       else if (usesRelaxedLayout(m_interface))
        {
                programCollection.glslSources.add("compute") << glu::ComputeSource(m_computeShaderSrc)
                        << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, vk::ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS);
index ff5159e..174a1a2 100644 (file)
@@ -246,6 +246,16 @@ UniformBlock& ShaderInterface::allocBlock (const std::string& name)
        return *m_uniformBlocks.back();
 }
 
+bool ShaderInterface::usesBlockLayout (UniformFlags layoutFlag) const
+{
+       for (int i = 0, num_blocks = getNumUniformBlocks() ; i < num_blocks ; i++)
+       {
+               if (m_uniformBlocks[i]->getFlags() & layoutFlag)
+                       return true;
+       }
+       return false;
+}
+
 namespace // Utilities
 {
 
@@ -2093,8 +2103,19 @@ void UniformBlockCase::initPrograms (vk::SourceCollections& programCollection) c
        DE_ASSERT(!m_vertShaderSource.empty());
        DE_ASSERT(!m_fragShaderSource.empty());
 
-       programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
-       programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
+       vk::ShaderBuildOptions::Flags flags = vk::ShaderBuildOptions::Flags(0);
+       // TODO(dneto): If these tests ever use LAYOUT_RELAXED, then add support
+       // here as well.
+       if (usesBlockLayout(UniformFlags(LAYOUT_SCALAR | LAYOUT_STD430)))
+       {
+               flags = vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS;
+       }
+
+       programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource)
+       << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags);
+
+       programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource)
+       << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags);
 }
 
 TestInstance* UniformBlockCase::createInstance (Context& context) const
index bded831..c4938cb 100644 (file)
@@ -235,6 +235,7 @@ public:
 
        int                                                     getNumUniformBlocks             (void) const    { return (int)m_uniformBlocks.size();   }
        const UniformBlock&                     getUniformBlock                 (int ndx) const { return *m_uniformBlocks[ndx];                 }
+       bool                                            usesBlockLayout                 (UniformFlags layoutFlag) const;
 
 private:
        std::vector<StructTypeSP>               m_structs;
@@ -315,6 +316,7 @@ public:
 
        virtual void                            initPrograms                            (vk::SourceCollections& programCollection) const;
        virtual TestInstance*           createInstance                          (Context& context) const;
+       bool                                            usesBlockLayout                         (UniformFlags layoutFlag) const { return m_interface.usesBlockLayout(layoutFlag); }
 
 protected:
        void                                            init                                            (void);
index 3b501a0..2138f39 100644 (file)
@@ -201,25 +201,19 @@ struct Program
        Status                                  validationStatus;
        std::string                             validationLog;
 
-       deUint32                                vulkanVersion;  // Target Vulkan environment.
-       vk::SpirvVersion                spirvVersion;
-       bool                                    relaxedLayout;  // Uses VK_KHR_relaxed_block_layout?
+       vk::SpirvValidatorOptions       validatorOptions;
 
-       explicit                                Program         (const vk::ProgramIdentifier& id_, deUint32 vulkanVersion_, const vk::SpirvVersion spirvVersion_, const bool relaxedLayout_)
+       explicit                                Program         (const vk::ProgramIdentifier& id_, const vk::SpirvValidatorOptions& valOptions_)
                                                                : id                            (id_)
                                                                , buildStatus           (STATUS_NOT_COMPLETED)
                                                                , validationStatus      (STATUS_NOT_COMPLETED)
-                                                               , vulkanVersion         (vulkanVersion_)
-                                                               , spirvVersion          (spirvVersion_)
-                                                               , relaxedLayout         (relaxedLayout_)
+                                                               , validatorOptions      (valOptions_)
                                                        {}
                                                        Program         (void)
                                                                : id                            ("", "")
                                                                , buildStatus           (STATUS_NOT_COMPLETED)
                                                                , validationStatus      (STATUS_NOT_COMPLETED)
-                                                               , vulkanVersion         (VK_MAKE_VERSION(1, 0, 0))
-                                                               , spirvVersion          (vk::SPIRV_VERSION_LAST)
-                                                               , relaxedLayout         (false)
+                                                               , validatorOptions()
                                                        {}
 };
 
@@ -274,7 +268,7 @@ public:
                        DE_ASSERT(m_commandLine != DE_NULL);
                        m_program->binary                       = ProgramBinarySp(vk::buildProgram(m_source, &buildInfo, *m_commandLine));
                        m_program->buildStatus          = Program::STATUS_PASSED;
-                       m_program->relaxedLayout        = m_source.buildOptions.flags & vk::ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS;
+                       m_program->validatorOptions     = m_source.buildOptions.getSpirvValidatorOptions();
                }
                catch (const tcu::Exception&)
                {
@@ -361,7 +355,7 @@ public:
 
                std::ostringstream                      validationLogStream;
 
-               if (vk::validateProgram(*m_program->binary, &validationLogStream, m_program->vulkanVersion, m_program->relaxedLayout))
+               if (vk::validateProgram(*m_program->binary, &validationLogStream, m_program->validatorOptions))
                        m_program->validationStatus = Program::STATUS_PASSED;
                else
                        m_program->validationStatus = Program::STATUS_FAILED;
@@ -455,8 +449,7 @@ BuildStats buildPrograms (tcu::TestContext&                 testCtx,
                                                if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion)
                                                        continue;
 
-                                               const bool relaxedLayout = progIter.getProgram().buildOptions.flags & vk::ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS;
-                                               programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.vulkanVersion, progIter.getProgram().buildOptions.targetVersion, relaxedLayout));
+                                               programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
                                                buildGlslTasks.pushBack(BuildHighLevelShaderTask<vk::GlslSource>(progIter.getProgram(), &programs.back()));
                                                buildGlslTasks.back().setCommandline(testCtx.getCommandLine());
                                                executor.submit(&buildGlslTasks.back());
@@ -470,8 +463,7 @@ BuildStats buildPrograms (tcu::TestContext&                 testCtx,
                                                if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion)
                                                        continue;
 
-                                               const bool relaxedLayout = progIter.getProgram().buildOptions.flags & vk::ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS;
-                                               programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.vulkanVersion, progIter.getProgram().buildOptions.targetVersion, relaxedLayout));
+                                               programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
                                                buildHlslTasks.pushBack(BuildHighLevelShaderTask<vk::HlslSource>(progIter.getProgram(), &programs.back()));
                                                buildHlslTasks.back().setCommandline(testCtx.getCommandLine());
                                                executor.submit(&buildHlslTasks.back());
@@ -485,7 +477,7 @@ BuildStats buildPrograms (tcu::TestContext&                 testCtx,
                                                if (progIter.getProgram().buildOptions.targetVersion > maxSpirvVersion)
                                                        continue;
 
-                                               programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.vulkanVersion, progIter.getProgram().buildOptions.targetVersion, false));
+                                               programs.pushBack(Program(vk::ProgramIdentifier(casePath, progIter.getName()), progIter.getProgram().buildOptions.getSpirvValidatorOptions()));
                                                buildSpirvAsmTasks.pushBack(BuildSpirVAsmTask(progIter.getProgram(), &programs.back()));
                                                buildSpirvAsmTasks.back().setCommandline(testCtx.getCommandLine());
                                                executor.submit(&buildSpirvAsmTasks.back());