| // Copyright (c) 2015-2016 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. |
| |
| // Validation tests for Logical Layout |
| |
| #include <sstream> |
| #include <string> |
| #include <tuple> |
| #include <utility> |
| #include <vector> |
| |
| #include "gmock/gmock.h" |
| #include "source/assembly_grammar.h" |
| #include "source/spirv_target_env.h" |
| #include "spirv-tools/libspirv.h" |
| #include "test/test_fixture.h" |
| #include "test/unit_spirv.h" |
| #include "test/val/val_fixtures.h" |
| |
| namespace spvtools { |
| namespace val { |
| namespace { |
| |
| using spvtest::ScopedContext; |
| using testing::Combine; |
| using testing::Eq; |
| using testing::HasSubstr; |
| using testing::Values; |
| using testing::ValuesIn; |
| |
| // Parameter for validation test fixtures. The first std::string is a |
| // capability name that will begin the assembly under test, the second the |
| // remainder assembly, and the std::vector at the end determines whether the |
| // test expects success or failure. See below for details and convenience |
| // methods to access each one. |
| // |
| // The assembly to test is composed from a variable top line and a fixed |
| // remainder. The top line will be an OpCapability instruction, while the |
| // remainder will be some assembly text that succeeds or fails to assemble |
| // depending on which capability was chosen. For instance, the following will |
| // succeed: |
| // |
| // OpCapability Pipes ; implies Kernel |
| // OpLifetimeStop %1 0 ; requires Kernel |
| // |
| // and the following will fail: |
| // |
| // OpCapability Kernel |
| // %1 = OpTypeNamedBarrier ; requires NamedBarrier |
| // |
| // So how does the test parameter capture which capabilities should cause |
| // success and which shouldn't? The answer is in the last element: it's a |
| // std::vector of capabilities that make the remainder assembly succeed. So if |
| // the first-line capability exists in that std::vector, success is expected; |
| // otherwise, failure is expected in the tests. |
| // |
| // We will use testing::Combine() to vary the first line: when we combine |
| // AllCapabilities() with a single remainder assembly, we generate enough test |
| // cases to try the assembly with every possible capability that could be |
| // declared. However, Combine() only produces tuples -- it cannot produce, say, |
| // a struct. Therefore, this type must be a tuple. |
| using CapTestParameter = |
| std::tuple<std::string, std::pair<std::string, std::vector<std::string>>>; |
| |
| const std::string& Capability(const CapTestParameter& p) { |
| return std::get<0>(p); |
| } |
| const std::string& Remainder(const CapTestParameter& p) { |
| return std::get<1>(p).first; |
| } |
| const std::vector<std::string>& MustSucceed(const CapTestParameter& p) { |
| return std::get<1>(p).second; |
| } |
| |
| // Creates assembly to test from p. |
| std::string MakeAssembly(const CapTestParameter& p) { |
| std::ostringstream ss; |
| const std::string& capability = Capability(p); |
| if (!capability.empty()) { |
| ss << "OpCapability " << capability << "\n"; |
| } |
| ss << Remainder(p); |
| return ss.str(); |
| } |
| |
| // Expected validation result for p. |
| spv_result_t ExpectedResult(const CapTestParameter& p) { |
| const auto& caps = MustSucceed(p); |
| auto found = find(begin(caps), end(caps), Capability(p)); |
| return (found == end(caps)) ? SPV_ERROR_INVALID_CAPABILITY : SPV_SUCCESS; |
| } |
| |
| // Assembles using v1.0, unless the parameter's capability requires v1.1. |
| using ValidateCapability = spvtest::ValidateBase<CapTestParameter>; |
| |
| // Always assembles using v1.1. |
| using ValidateCapabilityV11 = spvtest::ValidateBase<CapTestParameter>; |
| |
| // Always assembles using Vulkan 1.0. |
| // TODO(dneto): Refactor all these tests to scale better across environments. |
| using ValidateCapabilityVulkan10 = spvtest::ValidateBase<CapTestParameter>; |
| // Always assembles using OpenGL 4.0. |
| using ValidateCapabilityOpenGL40 = spvtest::ValidateBase<CapTestParameter>; |
| // Always assembles using Vulkan 1.1. |
| using ValidateCapabilityVulkan11 = spvtest::ValidateBase<CapTestParameter>; |
| // Always assembles using Vulkan 1.2. |
| using ValidateCapabilityVulkan12 = spvtest::ValidateBase<CapTestParameter>; |
| |
| TEST_F(ValidateCapability, Default) { |
| const char str[] = R"( |
| OpCapability Kernel |
| OpCapability Linkage |
| OpCapability Matrix |
| OpMemoryModel Logical OpenCL |
| %f32 = OpTypeFloat 32 |
| %vec3 = OpTypeVector %f32 3 |
| %mat33 = OpTypeMatrix %vec3 3 |
| )"; |
| |
| CompileSuccessfully(str); |
| ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); |
| } |
| |
| // clang-format off |
| const std::vector<std::string>& AllCapabilities() { |
| static const auto r = new std::vector<std::string>{ |
| "", |
| "Matrix", |
| "Shader", |
| "Geometry", |
| "Tessellation", |
| "Addresses", |
| "Linkage", |
| "Kernel", |
| "Vector16", |
| "Float16Buffer", |
| "Float16", |
| "Float64", |
| "Int64", |
| "Int64Atomics", |
| "ImageBasic", |
| "ImageReadWrite", |
| "ImageMipmap", |
| "Pipes", |
| "Groups", |
| "DeviceEnqueue", |
| "LiteralSampler", |
| "AtomicStorage", |
| "Int16", |
| "TessellationPointSize", |
| "GeometryPointSize", |
| "ImageGatherExtended", |
| "StorageImageMultisample", |
| "UniformBufferArrayDynamicIndexing", |
| "SampledImageArrayDynamicIndexing", |
| "StorageBufferArrayDynamicIndexing", |
| "StorageImageArrayDynamicIndexing", |
| "ClipDistance", |
| "CullDistance", |
| "ImageCubeArray", |
| "SampleRateShading", |
| "ImageRect", |
| "SampledRect", |
| "GenericPointer", |
| "Int8", |
| "InputAttachment", |
| "SparseResidency", |
| "MinLod", |
| "Sampled1D", |
| "Image1D", |
| "SampledCubeArray", |
| "SampledBuffer", |
| "ImageBuffer", |
| "ImageMSArray", |
| "StorageImageExtendedFormats", |
| "ImageQuery", |
| "DerivativeControl", |
| "InterpolationFunction", |
| "TransformFeedback", |
| "GeometryStreams", |
| "StorageImageReadWithoutFormat", |
| "StorageImageWriteWithoutFormat", |
| "MultiViewport", |
| "SubgroupDispatch", |
| "NamedBarrier", |
| "PipeStorage", |
| "GroupNonUniform", |
| "GroupNonUniformVote", |
| "GroupNonUniformArithmetic", |
| "GroupNonUniformBallot", |
| "GroupNonUniformShuffle", |
| "GroupNonUniformShuffleRelative", |
| "GroupNonUniformClustered", |
| "GroupNonUniformQuad", |
| "DrawParameters", |
| "StorageBuffer16BitAccess", |
| "StorageUniformBufferBlock16", |
| "UniformAndStorageBuffer16BitAccess", |
| "StorageUniform16", |
| "StoragePushConstant16", |
| "StorageInputOutput16", |
| "DeviceGroup", |
| "MultiView", |
| "VariablePointersStorageBuffer", |
| "VariablePointers"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& AllSpirV15Capabilities() { |
| static const auto r = new std::vector<std::string>{ |
| "", |
| "Matrix", |
| "Shader", |
| "Geometry", |
| "Tessellation", |
| "Addresses", |
| "Linkage", |
| "Kernel", |
| "Vector16", |
| "Float16Buffer", |
| "Float16", |
| "Float64", |
| "Int64", |
| "Int64Atomics", |
| "ImageBasic", |
| "ImageReadWrite", |
| "ImageMipmap", |
| "Pipes", |
| "Groups", |
| "DeviceEnqueue", |
| "LiteralSampler", |
| "AtomicStorage", |
| "Int16", |
| "TessellationPointSize", |
| "GeometryPointSize", |
| "ImageGatherExtended", |
| "StorageImageMultisample", |
| "UniformBufferArrayDynamicIndexing", |
| "SampledImageArrayDynamicIndexing", |
| "StorageBufferArrayDynamicIndexing", |
| "StorageImageArrayDynamicIndexing", |
| "ClipDistance", |
| "CullDistance", |
| "ImageCubeArray", |
| "SampleRateShading", |
| "ImageRect", |
| "SampledRect", |
| "GenericPointer", |
| "Int8", |
| "InputAttachment", |
| "SparseResidency", |
| "MinLod", |
| "Sampled1D", |
| "Image1D", |
| "SampledCubeArray", |
| "SampledBuffer", |
| "ImageBuffer", |
| "ImageMSArray", |
| "StorageImageExtendedFormats", |
| "ImageQuery", |
| "DerivativeControl", |
| "InterpolationFunction", |
| "TransformFeedback", |
| "GeometryStreams", |
| "StorageImageReadWithoutFormat", |
| "StorageImageWriteWithoutFormat", |
| "MultiViewport", |
| "SubgroupDispatch", |
| "NamedBarrier", |
| "PipeStorage", |
| "GroupNonUniform", |
| "GroupNonUniformVote", |
| "GroupNonUniformArithmetic", |
| "GroupNonUniformBallot", |
| "GroupNonUniformShuffle", |
| "GroupNonUniformShuffleRelative", |
| "GroupNonUniformClustered", |
| "GroupNonUniformQuad", |
| "DrawParameters", |
| "StorageBuffer16BitAccess", |
| "StorageUniformBufferBlock16", |
| "UniformAndStorageBuffer16BitAccess", |
| "StorageUniform16", |
| "StoragePushConstant16", |
| "StorageInputOutput16", |
| "DeviceGroup", |
| "MultiView", |
| "VariablePointersStorageBuffer", |
| "VariablePointers", |
| "DenormPreserve", |
| "DenormFlushToZero", |
| "SignedZeroInfNanPreserve", |
| "RoundingModeRTE", |
| "RoundingModeRTZ", |
| // Omitted due to extra validation requirements on memory model. |
| //"VulkanMemoryModel", |
| //"VulkanMemoryModelDeviceScope", |
| "StorageBuffer8BitAccess", |
| "UniformAndStorageBuffer8BitAccess", |
| "StoragePushConstant8", |
| "ShaderViewportIndex", |
| "ShaderLayer", |
| "PhysicalStorageBufferAddresses", |
| "RuntimeDescriptorArray", |
| "UniformTexelBufferArrayDynamicIndexing", |
| "StorageTexelBufferArrayDynamicIndexing", |
| "UniformBufferArrayNonUniformIndexing", |
| "SampledImageArrayNonUniformIndexing", |
| "StorageBufferArrayNonUniformIndexing", |
| "StorageImageArrayNonUniformIndexing", |
| "InputAttachmentArrayNonUniformIndexing", |
| "UniformTexelBufferArrayNonUniformIndexing", |
| "StorageTexelBufferArrayNonUniformIndexing"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& AllSpirV10Capabilities() { |
| static const auto r = new std::vector<std::string>{ |
| "", |
| "Matrix", |
| "Shader", |
| "Geometry", |
| "Tessellation", |
| "Addresses", |
| "Linkage", |
| "Kernel", |
| "Vector16", |
| "Float16Buffer", |
| "Float16", |
| "Float64", |
| "Int64", |
| "Int64Atomics", |
| "ImageBasic", |
| "ImageReadWrite", |
| "ImageMipmap", |
| "Pipes", |
| "Groups", |
| "DeviceEnqueue", |
| "LiteralSampler", |
| "AtomicStorage", |
| "Int16", |
| "TessellationPointSize", |
| "GeometryPointSize", |
| "ImageGatherExtended", |
| "StorageImageMultisample", |
| "UniformBufferArrayDynamicIndexing", |
| "SampledImageArrayDynamicIndexing", |
| "StorageBufferArrayDynamicIndexing", |
| "StorageImageArrayDynamicIndexing", |
| "ClipDistance", |
| "CullDistance", |
| "ImageCubeArray", |
| "SampleRateShading", |
| "ImageRect", |
| "SampledRect", |
| "GenericPointer", |
| "Int8", |
| "InputAttachment", |
| "SparseResidency", |
| "MinLod", |
| "Sampled1D", |
| "Image1D", |
| "SampledCubeArray", |
| "SampledBuffer", |
| "ImageBuffer", |
| "ImageMSArray", |
| "StorageImageExtendedFormats", |
| "ImageQuery", |
| "DerivativeControl", |
| "InterpolationFunction", |
| "TransformFeedback", |
| "GeometryStreams", |
| "StorageImageReadWithoutFormat", |
| "StorageImageWriteWithoutFormat", |
| "MultiViewport"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& AllVulkan10Capabilities() { |
| static const auto r = new std::vector<std::string>{ |
| "", |
| "Matrix", |
| "Shader", |
| "InputAttachment", |
| "Sampled1D", |
| "Image1D", |
| "SampledBuffer", |
| "ImageBuffer", |
| "ImageQuery", |
| "DerivativeControl", |
| "Geometry", |
| "Tessellation", |
| "Float16", |
| "Float64", |
| "Int64", |
| "Int64Atomics", |
| "Int16", |
| "TessellationPointSize", |
| "GeometryPointSize", |
| "ImageGatherExtended", |
| "StorageImageMultisample", |
| "UniformBufferArrayDynamicIndexing", |
| "SampledImageArrayDynamicIndexing", |
| "StorageBufferArrayDynamicIndexing", |
| "StorageImageArrayDynamicIndexing", |
| "ClipDistance", |
| "CullDistance", |
| "ImageCubeArray", |
| "SampleRateShading", |
| "Int8", |
| "SparseResidency", |
| "MinLod", |
| "SampledCubeArray", |
| "ImageMSArray", |
| "StorageImageExtendedFormats", |
| "InterpolationFunction", |
| "StorageImageReadWithoutFormat", |
| "StorageImageWriteWithoutFormat", |
| "MultiViewport", |
| "TransformFeedback", |
| "GeometryStreams"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& AllVulkan11Capabilities() { |
| static const auto r = new std::vector<std::string>{ |
| "", |
| "Matrix", |
| "Shader", |
| "InputAttachment", |
| "Sampled1D", |
| "Image1D", |
| "SampledBuffer", |
| "ImageBuffer", |
| "ImageQuery", |
| "DerivativeControl", |
| "Geometry", |
| "Tessellation", |
| "Float16", |
| "Float64", |
| "Int64", |
| "Int64Atomics", |
| "Int16", |
| "TessellationPointSize", |
| "GeometryPointSize", |
| "ImageGatherExtended", |
| "StorageImageMultisample", |
| "UniformBufferArrayDynamicIndexing", |
| "SampledImageArrayDynamicIndexing", |
| "StorageBufferArrayDynamicIndexing", |
| "StorageImageArrayDynamicIndexing", |
| "ClipDistance", |
| "CullDistance", |
| "ImageCubeArray", |
| "SampleRateShading", |
| "Int8", |
| "SparseResidency", |
| "MinLod", |
| "SampledCubeArray", |
| "ImageMSArray", |
| "StorageImageExtendedFormats", |
| "InterpolationFunction", |
| "StorageImageReadWithoutFormat", |
| "StorageImageWriteWithoutFormat", |
| "MultiViewport", |
| "GroupNonUniform", |
| "GroupNonUniformVote", |
| "GroupNonUniformArithmetic", |
| "GroupNonUniformBallot", |
| "GroupNonUniformShuffle", |
| "GroupNonUniformShuffleRelative", |
| "GroupNonUniformClustered", |
| "GroupNonUniformQuad", |
| "DrawParameters", |
| "StorageBuffer16BitAccess", |
| "StorageUniformBufferBlock16", |
| "UniformAndStorageBuffer16BitAccess", |
| "StorageUniform16", |
| "StoragePushConstant16", |
| "StorageInputOutput16", |
| "DeviceGroup", |
| "MultiView", |
| "VariablePointersStorageBuffer", |
| "VariablePointers", |
| "TransformFeedback", |
| "GeometryStreams"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& AllVulkan12Capabilities() { |
| static const auto r = new std::vector<std::string>{ |
| "", |
| "Matrix", |
| "Shader", |
| "InputAttachment", |
| "Sampled1D", |
| "Image1D", |
| "SampledBuffer", |
| "ImageBuffer", |
| "ImageQuery", |
| "DerivativeControl", |
| "Geometry", |
| "Tessellation", |
| "Float16", |
| "Float64", |
| "Int64", |
| "Int64Atomics", |
| "Int16", |
| "TessellationPointSize", |
| "GeometryPointSize", |
| "ImageGatherExtended", |
| "StorageImageMultisample", |
| "UniformBufferArrayDynamicIndexing", |
| "SampledImageArrayDynamicIndexing", |
| "StorageBufferArrayDynamicIndexing", |
| "StorageImageArrayDynamicIndexing", |
| "ClipDistance", |
| "CullDistance", |
| "ImageCubeArray", |
| "SampleRateShading", |
| "Int8", |
| "SparseResidency", |
| "MinLod", |
| "SampledCubeArray", |
| "ImageMSArray", |
| "StorageImageExtendedFormats", |
| "InterpolationFunction", |
| "StorageImageReadWithoutFormat", |
| "StorageImageWriteWithoutFormat", |
| "MultiViewport", |
| "GroupNonUniform", |
| "GroupNonUniformVote", |
| "GroupNonUniformArithmetic", |
| "GroupNonUniformBallot", |
| "GroupNonUniformShuffle", |
| "GroupNonUniformShuffleRelative", |
| "GroupNonUniformClustered", |
| "GroupNonUniformQuad", |
| "DrawParameters", |
| "StorageBuffer16BitAccess", |
| "StorageUniformBufferBlock16", |
| "UniformAndStorageBuffer16BitAccess", |
| "StorageUniform16", |
| "StoragePushConstant16", |
| "StorageInputOutput16", |
| "DeviceGroup", |
| "MultiView", |
| "VariablePointersStorageBuffer", |
| "VariablePointers", |
| "TransformFeedback", |
| "GeometryStreams", |
| "DenormPreserve", |
| "DenormFlushToZero", |
| "SignedZeroInfNanPreserve", |
| "RoundingModeRTE", |
| "RoundingModeRTZ", |
| "VulkanMemoryModel", |
| "VulkanMemoryModelDeviceScope", |
| "StorageBuffer8BitAccess", |
| "UniformAndStorageBuffer8BitAccess", |
| "StoragePushConstant8", |
| "ShaderViewportIndex", |
| "ShaderLayer", |
| "PhysicalStorageBufferAddresses", |
| "RuntimeDescriptorArray", |
| "UniformTexelBufferArrayDynamicIndexing", |
| "StorageTexelBufferArrayDynamicIndexing", |
| "UniformBufferArrayNonUniformIndexing", |
| "SampledImageArrayNonUniformIndexing", |
| "StorageBufferArrayNonUniformIndexing", |
| "StorageImageArrayNonUniformIndexing", |
| "InputAttachmentArrayNonUniformIndexing", |
| "UniformTexelBufferArrayNonUniformIndexing", |
| "StorageTexelBufferArrayNonUniformIndexing"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& MatrixDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Matrix", |
| "Shader", |
| "Geometry", |
| "Tessellation", |
| "AtomicStorage", |
| "TessellationPointSize", |
| "GeometryPointSize", |
| "ImageGatherExtended", |
| "StorageImageMultisample", |
| "UniformBufferArrayDynamicIndexing", |
| "SampledImageArrayDynamicIndexing", |
| "StorageBufferArrayDynamicIndexing", |
| "StorageImageArrayDynamicIndexing", |
| "ClipDistance", |
| "CullDistance", |
| "ImageCubeArray", |
| "SampleRateShading", |
| "ImageRect", |
| "SampledRect", |
| "InputAttachment", |
| "SparseResidency", |
| "MinLod", |
| "SampledCubeArray", |
| "ImageMSArray", |
| "StorageImageExtendedFormats", |
| "ImageQuery", |
| "DerivativeControl", |
| "InterpolationFunction", |
| "TransformFeedback", |
| "GeometryStreams", |
| "StorageImageReadWithoutFormat", |
| "StorageImageWriteWithoutFormat", |
| "MultiViewport", |
| "DrawParameters", |
| "MultiView", |
| "VariablePointersStorageBuffer", |
| "VariablePointers"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& ShaderDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Shader", |
| "Geometry", |
| "Tessellation", |
| "AtomicStorage", |
| "TessellationPointSize", |
| "GeometryPointSize", |
| "ImageGatherExtended", |
| "StorageImageMultisample", |
| "UniformBufferArrayDynamicIndexing", |
| "SampledImageArrayDynamicIndexing", |
| "StorageBufferArrayDynamicIndexing", |
| "StorageImageArrayDynamicIndexing", |
| "ClipDistance", |
| "CullDistance", |
| "ImageCubeArray", |
| "SampleRateShading", |
| "ImageRect", |
| "SampledRect", |
| "InputAttachment", |
| "SparseResidency", |
| "MinLod", |
| "SampledCubeArray", |
| "ImageMSArray", |
| "StorageImageExtendedFormats", |
| "ImageQuery", |
| "DerivativeControl", |
| "InterpolationFunction", |
| "TransformFeedback", |
| "GeometryStreams", |
| "StorageImageReadWithoutFormat", |
| "StorageImageWriteWithoutFormat", |
| "MultiViewport", |
| "DrawParameters", |
| "MultiView", |
| "VariablePointersStorageBuffer", |
| "VariablePointers"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& TessellationDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Tessellation", |
| "TessellationPointSize"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& GeometryDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Geometry", |
| "GeometryPointSize", |
| "GeometryStreams", |
| "MultiViewport"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& GeometryTessellationDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Tessellation", |
| "TessellationPointSize", |
| "Geometry", |
| "GeometryPointSize", |
| "GeometryStreams", |
| "MultiViewport"}; |
| return *r; |
| } |
| |
| // Returns the names of capabilities that directly depend on Kernel, |
| // plus itself. |
| const std::vector<std::string>& KernelDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Kernel", |
| "Vector16", |
| "Float16Buffer", |
| "ImageBasic", |
| "ImageReadWrite", |
| "ImageMipmap", |
| "Pipes", |
| "DeviceEnqueue", |
| "LiteralSampler", |
| "SubgroupDispatch", |
| "NamedBarrier", |
| "PipeStorage"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& KernelAndGroupNonUniformDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Kernel", |
| "Vector16", |
| "Float16Buffer", |
| "ImageBasic", |
| "ImageReadWrite", |
| "ImageMipmap", |
| "Pipes", |
| "DeviceEnqueue", |
| "LiteralSampler", |
| "SubgroupDispatch", |
| "NamedBarrier", |
| "PipeStorage", |
| "GroupNonUniform", |
| "GroupNonUniformVote", |
| "GroupNonUniformArithmetic", |
| "GroupNonUniformBallot", |
| "GroupNonUniformShuffle", |
| "GroupNonUniformShuffleRelative", |
| "GroupNonUniformClustered", |
| "GroupNonUniformQuad"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& AddressesDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Addresses", |
| "GenericPointer"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& Sampled1DDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "Sampled1D", |
| "Image1D"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& SampledRectDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "SampledRect", |
| "ImageRect"}; |
| return *r; |
| } |
| |
| const std::vector<std::string>& SampledBufferDependencies() { |
| static const auto r = new std::vector<std::string>{ |
| "SampledBuffer", |
| "ImageBuffer"}; |
| return *r; |
| } |
| |
| const char kOpenCLMemoryModel[] = \ |
| " OpCapability Kernel" |
| " OpMemoryModel Logical OpenCL "; |
| |
| const char kGLSL450MemoryModel[] = \ |
| " OpCapability Shader" |
| " OpMemoryModel Logical GLSL450 "; |
| |
| const char kVoidFVoid[] = \ |
| " %void = OpTypeVoid" |
| " %void_f = OpTypeFunction %void" |
| " %func = OpFunction %void None %void_f" |
| " %label = OpLabel" |
| " OpReturn" |
| " OpFunctionEnd "; |
| |
| const char kVoidFVoid2[] = \ |
| " %void_f = OpTypeFunction %voidt" |
| " %func = OpFunction %voidt None %void_f" |
| " %label = OpLabel" |
| " OpReturn" |
| " OpFunctionEnd "; |
| |
| INSTANTIATE_TEST_SUITE_P(ExecutionModel, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint TessellationControl %func \"shader\"" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint TessellationEvaluation %func \"shader\"" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint Geometry %func \"shader\"" + |
| " OpExecutionMode %func InputPoints" + |
| " OpExecutionMode %func OutputPoints" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint Fragment %func \"shader\"" + |
| " OpExecutionMode %func OriginUpperLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint GLCompute %func \"shader\"" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Kernel %func \"shader\"" + |
| std::string(kVoidFVoid), KernelDependencies()) |
| ))); |
| |
| INSTANTIATE_TEST_SUITE_P(AddressingAndMemoryModel, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(" OpCapability Shader" |
| " OpMemoryModel Logical Simple" |
| " OpEntryPoint Vertex %func \"shader\"" + |
| std::string(kVoidFVoid), AllCapabilities()), |
| std::make_pair(" OpCapability Shader" |
| " OpMemoryModel Logical GLSL450" |
| " OpEntryPoint Vertex %func \"shader\"" + |
| std::string(kVoidFVoid), AllCapabilities()), |
| std::make_pair(" OpCapability Kernel" |
| " OpMemoryModel Logical OpenCL" |
| " OpEntryPoint Kernel %func \"compute\"" + |
| std::string(kVoidFVoid), AllCapabilities()), |
| std::make_pair(" OpCapability Shader" |
| " OpMemoryModel Physical32 Simple" |
| " OpEntryPoint Vertex %func \"shader\"" + |
| std::string(kVoidFVoid), AddressesDependencies()), |
| std::make_pair(" OpCapability Shader" |
| " OpMemoryModel Physical32 GLSL450" |
| " OpEntryPoint Vertex %func \"shader\"" + |
| std::string(kVoidFVoid), AddressesDependencies()), |
| std::make_pair(" OpCapability Kernel" |
| " OpMemoryModel Physical32 OpenCL" |
| " OpEntryPoint Kernel %func \"compute\"" + |
| std::string(kVoidFVoid), AddressesDependencies()), |
| std::make_pair(" OpCapability Shader" |
| " OpMemoryModel Physical64 Simple" |
| " OpEntryPoint Vertex %func \"shader\"" + |
| std::string(kVoidFVoid), AddressesDependencies()), |
| std::make_pair(" OpCapability Shader" |
| " OpMemoryModel Physical64 GLSL450" |
| " OpEntryPoint Vertex %func \"shader\"" + |
| std::string(kVoidFVoid), AddressesDependencies()), |
| std::make_pair(" OpCapability Kernel" |
| " OpMemoryModel Physical64 OpenCL" |
| " OpEntryPoint Kernel %func \"compute\"" + |
| std::string(kVoidFVoid), AddressesDependencies()) |
| ))); |
| |
| INSTANTIATE_TEST_SUITE_P(ExecutionMode, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func Invocations 42" + |
| " OpExecutionMode %func InputPoints" + |
| " OpExecutionMode %func OutputPoints" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func SpacingEqual" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func SpacingFractionalEven" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func SpacingFractionalOdd" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func VertexOrderCw" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func VertexOrderCcw" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Fragment %func \"shader\" " |
| "OpExecutionMode %func PixelCenterInteger" + |
| " OpExecutionMode %func OriginUpperLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Fragment %func \"shader\" " |
| "OpExecutionMode %func OriginUpperLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Fragment %func \"shader\" " |
| "OpExecutionMode %func OriginLowerLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Fragment %func \"shader\" " |
| "OpExecutionMode %func EarlyFragmentTests" + |
| " OpExecutionMode %func OriginUpperLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func PointMode" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" " |
| "OpExecutionMode %func Xfb" + |
| std::string(kVoidFVoid), std::vector<std::string>{"TransformFeedback"}), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Fragment %func \"shader\" " |
| "OpExecutionMode %func DepthReplacing" + |
| " OpExecutionMode %func OriginUpperLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Fragment %func \"shader\" " |
| "OpExecutionMode %func DepthGreater" + |
| " OpExecutionMode %func OriginUpperLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Fragment %func \"shader\" " |
| "OpExecutionMode %func DepthLess" + |
| " OpExecutionMode %func OriginUpperLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Fragment %func \"shader\" " |
| "OpExecutionMode %func DepthUnchanged" + |
| " OpExecutionMode %func OriginUpperLeft" + |
| std::string(kVoidFVoid), ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"shader\" " |
| "OpExecutionMode %func LocalSize 42 42 42" + |
| std::string(kVoidFVoid), AllCapabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Kernel %func \"shader\" " |
| "OpExecutionMode %func LocalSizeHint 42 42 42" + |
| std::string(kVoidFVoid), KernelDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func InputPoints" + |
| " OpExecutionMode %func OutputPoints" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func InputLines" + |
| " OpExecutionMode %func OutputLineStrip" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func InputLinesAdjacency" + |
| " OpExecutionMode %func OutputLineStrip" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func Triangles" + |
| " OpExecutionMode %func OutputTriangleStrip" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func Triangles" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func InputTrianglesAdjacency" + |
| " OpExecutionMode %func OutputTriangleStrip" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func Quads" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func Isolines" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func OutputVertices 42" + |
| " OpExecutionMode %func OutputPoints" + |
| " OpExecutionMode %func InputPoints" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint TessellationControl %func \"shader\" " |
| "OpExecutionMode %func OutputVertices 42" + |
| std::string(kVoidFVoid), TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func OutputPoints" + |
| " OpExecutionMode %func InputPoints" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func OutputLineStrip" + |
| " OpExecutionMode %func InputLines" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Geometry %func \"shader\" " |
| "OpExecutionMode %func OutputTriangleStrip" + |
| " OpExecutionMode %func Triangles" + |
| std::string(kVoidFVoid), GeometryDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Kernel %func \"shader\" " |
| "OpExecutionMode %func VecTypeHint 2" + |
| std::string(kVoidFVoid), KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Kernel %func \"shader\" " |
| "OpExecutionMode %func ContractionOff" + |
| std::string(kVoidFVoid), KernelDependencies())))); |
| |
| // clang-format on |
| |
| INSTANTIATE_TEST_SUITE_P( |
| ExecutionModeV11, ValidateCapabilityV11, |
| Combine(ValuesIn(AllCapabilities()), |
| Values(std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"shader\" " |
| "OpExecutionMode %func SubgroupSize 1" + |
| std::string(kVoidFVoid), |
| std::vector<std::string>{"SubgroupDispatch"}), |
| std::make_pair( |
| std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"shader\" " |
| "OpExecutionMode %func SubgroupsPerWorkgroup 65535" + |
| std::string(kVoidFVoid), |
| std::vector<std::string>{"SubgroupDispatch"})))); |
| // clang-format off |
| |
| INSTANTIATE_TEST_SUITE_P(StorageClass, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer UniformConstant %intt\n" |
| " %var = OpVariable %ptrt UniformConstant\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint Kernel %func \"compute\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer Input %intt" |
| " %var = OpVariable %ptrt Input\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer Uniform %intt\n" |
| " %var = OpVariable %ptrt Uniform\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer Output %intt\n" |
| " %var = OpVariable %ptrt Output\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer Workgroup %intt\n" |
| " %var = OpVariable %ptrt Workgroup\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer CrossWorkgroup %intt\n" |
| " %var = OpVariable %ptrt CrossWorkgroup\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint Kernel %func \"compute\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer Private %intt\n" |
| " %var = OpVariable %ptrt Private\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| " OpEntryPoint Kernel %func \"compute\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer PushConstant %intt\n" |
| " %var = OpVariable %ptrt PushConstant\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer AtomicCounter %intt\n" |
| " %var = OpVariable %ptrt AtomicCounter\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"AtomicStorage"}), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" + |
| " %intt = OpTypeInt 32 0\n" |
| " %ptrt = OpTypePointer Image %intt\n" |
| " %var = OpVariable %ptrt Image\n" + std::string(kVoidFVoid), |
| AllCapabilities()) |
| ))); |
| |
| INSTANTIATE_TEST_SUITE_P(Dim, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(" OpCapability ImageBasic" + |
| std::string(kOpenCLMemoryModel) + |
| std::string(" OpEntryPoint Kernel %func \"compute\"") + |
| " %voidt = OpTypeVoid" |
| " %imgt = OpTypeImage %voidt 1D 0 0 0 0 Unknown" + std::string(kVoidFVoid2), |
| Sampled1DDependencies()), |
| std::make_pair(" OpCapability ImageBasic" + |
| std::string(kOpenCLMemoryModel) + |
| std::string(" OpEntryPoint Kernel %func \"compute\"") + |
| " %voidt = OpTypeVoid" |
| " %imgt = OpTypeImage %voidt 2D 0 0 0 0 Unknown" + std::string(kVoidFVoid2), |
| AllCapabilities()), |
| std::make_pair(" OpCapability ImageBasic" + |
| std::string(kOpenCLMemoryModel) + |
| std::string(" OpEntryPoint Kernel %func \"compute\"") + |
| " %voidt = OpTypeVoid" |
| " %imgt = OpTypeImage %voidt 3D 0 0 0 0 Unknown" + std::string(kVoidFVoid2), |
| AllCapabilities()), |
| std::make_pair(" OpCapability ImageBasic" + |
| std::string(kOpenCLMemoryModel) + |
| std::string(" OpEntryPoint Kernel %func \"compute\"") + |
| " %voidt = OpTypeVoid" |
| " %imgt = OpTypeImage %voidt Cube 0 0 0 0 Unknown" + std::string(kVoidFVoid2), |
| ShaderDependencies()), |
| std::make_pair(" OpCapability ImageBasic" + |
| std::string(kOpenCLMemoryModel) + |
| std::string(" OpEntryPoint Kernel %func \"compute\"") + |
| " %voidt = OpTypeVoid" |
| " %imgt = OpTypeImage %voidt Rect 0 0 0 0 Unknown" + std::string(kVoidFVoid2), |
| SampledRectDependencies()), |
| std::make_pair(" OpCapability ImageBasic" + |
| std::string(kOpenCLMemoryModel) + |
| std::string(" OpEntryPoint Kernel %func \"compute\"") + |
| " %voidt = OpTypeVoid" |
| " %imgt = OpTypeImage %voidt Buffer 0 0 0 0 Unknown" + std::string(kVoidFVoid2), |
| SampledBufferDependencies()), |
| std::make_pair(" OpCapability ImageBasic" + |
| std::string(kOpenCLMemoryModel) + |
| std::string(" OpEntryPoint Kernel %func \"compute\"") + |
| " %voidt = OpTypeVoid" |
| " %imgt = OpTypeImage %voidt SubpassData 0 0 0 2 Unknown" + std::string(kVoidFVoid2), |
| std::vector<std::string>{"InputAttachment"}) |
| ))); |
| |
| // NOTE: All Sampler Address Modes require kernel capabilities but the |
| // OpConstantSampler requires LiteralSampler which depends on Kernel |
| INSTANTIATE_TEST_SUITE_P(SamplerAddressingMode, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" |
| " %samplert = OpTypeSampler" |
| " %sampler = OpConstantSampler %samplert None 1 Nearest" + |
| std::string(kVoidFVoid), |
| std::vector<std::string>{"LiteralSampler"}), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" |
| " %samplert = OpTypeSampler" |
| " %sampler = OpConstantSampler %samplert ClampToEdge 1 Nearest" + |
| std::string(kVoidFVoid), |
| std::vector<std::string>{"LiteralSampler"}), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" |
| " %samplert = OpTypeSampler" |
| " %sampler = OpConstantSampler %samplert Clamp 1 Nearest" + |
| std::string(kVoidFVoid), |
| std::vector<std::string>{"LiteralSampler"}), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" |
| " %samplert = OpTypeSampler" |
| " %sampler = OpConstantSampler %samplert Repeat 1 Nearest" + |
| std::string(kVoidFVoid), |
| std::vector<std::string>{"LiteralSampler"}), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| " OpEntryPoint Vertex %func \"shader\"" |
| " %samplert = OpTypeSampler" |
| " %sampler = OpConstantSampler %samplert RepeatMirrored 1 Nearest" + |
| std::string(kVoidFVoid), |
| std::vector<std::string>{"LiteralSampler"}) |
| ))); |
| |
| // TODO(umar): Sampler Filter Mode |
| // TODO(umar): Image Format |
| // TODO(umar): Image Channel Order |
| // TODO(umar): Image Channel Data Type |
| // TODO(umar): Image Operands |
| // TODO(umar): FP Fast Math Mode |
| // TODO(umar): FP Rounding Mode |
| // TODO(umar): Linkage Type |
| // TODO(umar): Access Qualifier |
| // TODO(umar): Function Parameter Attribute |
| |
| INSTANTIATE_TEST_SUITE_P(Decoration, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt RelaxedPrecision\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| // Block applies to struct type. |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %block Block\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%block = OpTypeStruct %intt\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| // BufferBlock applies to struct type. |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %block BufferBlock\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%block = OpTypeStruct %intt\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt RowMajor\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| MatrixDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt ColMajor\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| MatrixDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt ArrayStride 1\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt MatrixStride 1\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| MatrixDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt GLSLShared\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt GLSLPacked\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpDecorate %intt CPacked\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt NoPerspective\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Flat\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Patch\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Centroid\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Sample\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"SampleRateShading"}), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Invariant\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Restrict\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Aliased\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Volatile\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpDecorate %intt Constant\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Coherent\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| // NonWritable must target something valid, such as a storage image. |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %var NonWritable " |
| "%float = OpTypeFloat 32 " |
| "%imstor = OpTypeImage %float 2D 0 0 0 2 Unknown " |
| "%ptr = OpTypePointer UniformConstant %imstor " |
| "%var = OpVariable %ptr UniformConstant " |
| + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt NonReadable\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| // Uniform must target a non-void value. |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %int0 Uniform\n" |
| "%intt = OpTypeInt 32 0\n" + |
| "%int0 = OpConstantNull %intt" |
| + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpDecorate %intt SaturatedConversion\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Stream 0\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"GeometryStreams"}), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpMemberDecorate %struct 0 Location 0\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%struct = OpTypeStruct %intt\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %var Component 0\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%ptr = OpTypePointer Input %intt\n" |
| "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Index 0\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Binding 0\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt DescriptorSet 0\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt Offset 0\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt XfbBuffer 0\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"TransformFeedback"}), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt XfbStride 0\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"TransformFeedback"}), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpDecorate %intt FuncParamAttr Zext\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpDecorate %intt FPFastMathMode Fast\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt LinkageAttributes \"other\" Import\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"Linkage"}), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt NoContraction\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %intt InputAttachmentIndex 0\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"InputAttachment"}), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpDecorate %intt Alignment 4\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()) |
| ))); |
| |
| // clang-format on |
| INSTANTIATE_TEST_SUITE_P( |
| DecorationSpecId, ValidateCapability, |
| Combine( |
| ValuesIn(AllSpirV10Capabilities()), |
| Values(std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %1 SpecId 1\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%1 = OpSpecConstant %intt 0\n" + |
| std::string(kVoidFVoid), |
| ShaderDependencies())))); |
| |
| INSTANTIATE_TEST_SUITE_P( |
| DecorationV11, ValidateCapabilityV11, |
| Combine(ValuesIn(AllCapabilities()), |
| Values(std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %p MaxByteOffset 0 " |
| "%i32 = OpTypeInt 32 0 " |
| "%pi32 = OpTypePointer Workgroup %i32 " |
| "%p = OpVariable %pi32 Workgroup " + |
| std::string(kVoidFVoid), |
| AddressesDependencies()), |
| // Trying to test OpDecorate here, but if this fails due to |
| // incorrect OpMemoryModel validation, that must also be |
| // fixed. |
| std::make_pair( |
| std::string("OpMemoryModel Logical OpenCL " |
| "OpEntryPoint Kernel %func \"compute\" \n" |
| "OpDecorate %1 SpecId 1 " |
| "%intt = OpTypeInt 32 0 " |
| "%1 = OpSpecConstant %intt 0") + |
| std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair( |
| std::string("OpMemoryModel Logical Simple " |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpDecorate %1 SpecId 1 " |
| "%intt = OpTypeInt 32 0 " |
| "%1 = OpSpecConstant %intt 0") + |
| std::string(kVoidFVoid), |
| ShaderDependencies())))); |
| // clang-format off |
| |
| INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn Position\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| // Just mentioning PointSize, ClipDistance, or CullDistance as a BuiltIn does |
| // not trigger the requirement for the associated capability. |
| // See https://github.com/KhronosGroup/SPIRV-Tools/issues/365 |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn PointSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn ClipDistance\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn CullDistance\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn VertexId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn InstanceId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn PrimitiveId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| GeometryTessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn InvocationId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| GeometryTessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn Layer\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| GeometryDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn ViewportIndex\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"MultiViewport"}), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn TessLevelOuter\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn TessLevelInner\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn TessCoord\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn PatchVertices\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| TessellationDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn FragCoord\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn PointCoord\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn FrontFacing\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn SampleId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"SampleRateShading"}), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn SamplePosition\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| std::vector<std::string>{"SampleRateShading"}), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn SampleMask\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn FragDepth\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn HelperInvocation\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn VertexIndex\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn InstanceIndex\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn NumWorkgroups\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn WorkgroupSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn WorkgroupId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn LocalInvocationId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn GlobalInvocationId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn LocalInvocationIndex\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllCapabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn WorkDim\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn GlobalSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn EnqueuedWorkgroupSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn GlobalOffset\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn GlobalLinearId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn SubgroupSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelAndGroupNonUniformDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn SubgroupMaxSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn NumSubgroups\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelAndGroupNonUniformDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn NumEnqueuedSubgroups\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn SubgroupId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelAndGroupNonUniformDependencies()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn SubgroupLocalInvocationId\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| KernelAndGroupNonUniformDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn VertexIndex\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()), |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "OpDecorate %int0 BuiltIn InstanceIndex\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| ShaderDependencies()) |
| ))); |
| |
| // Ensure that mere mention of PointSize, ClipDistance, or CullDistance as |
| // BuiltIns does not trigger the requirement for the associated |
| // capability. |
| // See https://github.com/KhronosGroup/SPIRV-Tools/issues/365 |
| INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapabilityVulkan10, |
| Combine( |
| // All capabilities to try. |
| ValuesIn(AllSpirV10Capabilities()), |
| Values( |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpMemberDecorate %block 0 BuiltIn PointSize\n" |
| "%f32 = OpTypeFloat 32\n" |
| "%block = OpTypeStruct %f32\n" |
| "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), |
| // Capabilities which should succeed. |
| AllVulkan10Capabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpMemberDecorate %block 0 BuiltIn ClipDistance\n" |
| "%f32 = OpTypeFloat 32\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%intt_4 = OpConstant %intt 4\n" |
| "%f32arr4 = OpTypeArray %f32 %intt_4\n" |
| "%block = OpTypeStruct %f32arr4\n" + std::string(kVoidFVoid), |
| AllVulkan10Capabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" |
| "OpMemberDecorate %block 0 BuiltIn CullDistance\n" |
| "%f32 = OpTypeFloat 32\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%intt_4 = OpConstant %intt 4\n" |
| "%f32arr4 = OpTypeArray %f32 %intt_4\n" |
| "%block = OpTypeStruct %f32arr4\n" + std::string(kVoidFVoid), |
| AllVulkan10Capabilities()) |
| ))); |
| |
| INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapabilityOpenGL40, |
| Combine( |
| // OpenGL 4.0 is based on SPIR-V 1.0 |
| ValuesIn(AllSpirV10Capabilities()), |
| Values( |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn PointSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllSpirV10Capabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn ClipDistance\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllSpirV10Capabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn CullDistance\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllSpirV10Capabilities()) |
| ))); |
| |
| INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan11, |
| Combine( |
| // All capabilities to try. |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn PointSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllVulkan11Capabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn CullDistance\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllVulkan11Capabilities()) |
| ))); |
| |
| INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan12, |
| Combine( |
| // All capabilities to try. |
| ValuesIn(AllSpirV15Capabilities()), |
| Values( |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn PointSize\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllVulkan12Capabilities()), |
| std::make_pair(std::string(kGLSL450MemoryModel) + |
| "OpEntryPoint Vertex %func \"shader\" \n" + |
| "OpDecorate %int0 BuiltIn CullDistance\n" |
| "%intt = OpTypeInt 32 0\n" |
| "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), |
| AllVulkan12Capabilities()) |
| ))); |
| |
| // TODO(umar): Selection Control |
| // TODO(umar): Loop Control |
| // TODO(umar): Function Control |
| // TODO(umar): Memory Semantics |
| // TODO(umar): Memory Access |
| // TODO(umar): Scope |
| // TODO(umar): Group Operation |
| // TODO(umar): Kernel Enqueue Flags |
| // TODO(umar): Kernel Profiling Flags |
| |
| INSTANTIATE_TEST_SUITE_P(MatrixOp, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values( |
| std::make_pair(std::string(kOpenCLMemoryModel) + |
| "OpEntryPoint Kernel %func \"compute\" \n" + |
| "%f32 = OpTypeFloat 32\n" |
| "%vec3 = OpTypeVector %f32 3\n" |
| "%mat33 = OpTypeMatrix %vec3 3\n" + std::string(kVoidFVoid), |
| MatrixDependencies())))); |
| // clang-format on |
| |
| #if 0 |
| // TODO(atgoo@github.com) The following test is not valid as it generates |
| // invalid combinations of images, instructions and image operands. |
| // |
| // Creates assembly containing an OpImageFetch instruction using operands for |
| // the image-operands part. The assembly defines constants %fzero and %izero |
| // that can be used for operands where IDs are required. The assembly is valid, |
| // apart from not declaring any capabilities required by the operands. |
| string ImageOperandsTemplate(const std::string& operands) { |
| ostringstream ss; |
| // clang-format off |
| ss << R"( |
| OpCapability Kernel |
| OpCapability Linkage |
| OpMemoryModel Logical OpenCL |
| |
| %i32 = OpTypeInt 32 0 |
| %f32 = OpTypeFloat 32 |
| %v4i32 = OpTypeVector %i32 4 |
| %timg = OpTypeImage %i32 2D 0 0 0 0 Unknown |
| %pimg = OpTypePointer UniformConstant %timg |
| %tfun = OpTypeFunction %i32 |
| |
| %vimg = OpVariable %pimg UniformConstant |
| %izero = OpConstant %i32 0 |
| %fzero = OpConstant %f32 0. |
| |
| %main = OpFunction %i32 None %tfun |
| %lbl = OpLabel |
| %img = OpLoad %timg %vimg |
| %r1 = OpImageFetch %v4i32 %img %izero )" << operands << R"( |
| OpReturnValue %izero |
| OpFunctionEnd |
| )"; |
| // clang-format on |
| return ss.str(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| TwoImageOperandsMask, ValidateCapability, |
| Combine( |
| ValuesIn(AllCapabilities()), |
| Values(std::make_pair(ImageOperandsTemplate("Bias|Lod %fzero %fzero"), |
| ShaderDependencies()), |
| std::make_pair(ImageOperandsTemplate("Lod|Offset %fzero %izero"), |
| std::vector<std::string>{"ImageGatherExtended"}), |
| std::make_pair(ImageOperandsTemplate("Sample|MinLod %izero %fzero"), |
| std::vector<std::string>{"MinLod"}), |
| std::make_pair(ImageOperandsTemplate("Lod|Sample %fzero %izero"), |
| AllCapabilities()))), ); |
| #endif |
| |
| // TODO(umar): Instruction capability checks |
| |
| spv_result_t spvCoreOperandTableNameLookup(spv_target_env env, |
| const spv_operand_table table, |
| const spv_operand_type_t type, |
| const char* name, |
| const size_t nameLength) { |
| if (!table) return SPV_ERROR_INVALID_TABLE; |
| if (!name) return SPV_ERROR_INVALID_POINTER; |
| |
| for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) { |
| const auto& group = table->types[typeIndex]; |
| if (type != group.type) continue; |
| for (uint64_t index = 0; index < group.count; ++index) { |
| const auto& entry = group.entries[index]; |
| // Check for min version only. |
| if (spvVersionForTargetEnv(env) >= entry.minVersion && |
| nameLength == strlen(entry.name) && |
| !strncmp(entry.name, name, nameLength)) { |
| return SPV_SUCCESS; |
| } |
| } |
| } |
| |
| return SPV_ERROR_INVALID_LOOKUP; |
| } |
| |
| // True if capability exists in core spec of env. |
| bool Exists(const std::string& capability, spv_target_env env) { |
| ScopedContext sc(env); |
| return SPV_SUCCESS == |
| spvCoreOperandTableNameLookup(env, sc.context->operand_table, |
| SPV_OPERAND_TYPE_CAPABILITY, |
| capability.c_str(), capability.size()); |
| } |
| |
| TEST_P(ValidateCapability, Capability) { |
| const std::string capability = Capability(GetParam()); |
| spv_target_env env = SPV_ENV_UNIVERSAL_1_0; |
| if (!capability.empty()) { |
| if (Exists(capability, SPV_ENV_UNIVERSAL_1_0)) |
| env = SPV_ENV_UNIVERSAL_1_0; |
| else if (Exists(capability, SPV_ENV_UNIVERSAL_1_1)) |
| env = SPV_ENV_UNIVERSAL_1_1; |
| else if (Exists(capability, SPV_ENV_UNIVERSAL_1_2)) |
| env = SPV_ENV_UNIVERSAL_1_2; |
| else |
| env = SPV_ENV_UNIVERSAL_1_3; |
| } |
| const std::string test_code = MakeAssembly(GetParam()); |
| CompileSuccessfully(test_code, env); |
| ASSERT_EQ(ExpectedResult(GetParam()), ValidateInstructions(env)) |
| << "target env: " << spvTargetEnvDescription(env) << "\ntest code:\n" |
| << test_code; |
| } |
| |
| TEST_P(ValidateCapabilityV11, Capability) { |
| const std::string capability = Capability(GetParam()); |
| if (Exists(capability, SPV_ENV_UNIVERSAL_1_1)) { |
| const std::string test_code = MakeAssembly(GetParam()); |
| CompileSuccessfully(test_code, SPV_ENV_UNIVERSAL_1_1); |
| ASSERT_EQ(ExpectedResult(GetParam()), |
| ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)) |
| << test_code; |
| } |
| } |
| |
| TEST_P(ValidateCapabilityVulkan10, Capability) { |
| const std::string capability = Capability(GetParam()); |
| if (Exists(capability, SPV_ENV_VULKAN_1_0)) { |
| const std::string test_code = MakeAssembly(GetParam()); |
| CompileSuccessfully(test_code, SPV_ENV_VULKAN_1_0); |
| ASSERT_EQ(ExpectedResult(GetParam()), |
| ValidateInstructions(SPV_ENV_VULKAN_1_0)) |
| << test_code; |
| } |
| } |
| |
| TEST_P(ValidateCapabilityVulkan11, Capability) { |
| const std::string capability = Capability(GetParam()); |
| if (Exists(capability, SPV_ENV_VULKAN_1_1)) { |
| const std::string test_code = MakeAssembly(GetParam()); |
| CompileSuccessfully(test_code, SPV_ENV_VULKAN_1_1); |
| ASSERT_EQ(ExpectedResult(GetParam()), |
| ValidateInstructions(SPV_ENV_VULKAN_1_1)) |
| << test_code; |
| } |
| } |
| |
| TEST_P(ValidateCapabilityVulkan12, Capability) { |
| const std::string capability = Capability(GetParam()); |
| if (Exists(capability, SPV_ENV_VULKAN_1_2)) { |
| const std::string test_code = MakeAssembly(GetParam()); |
| CompileSuccessfully(test_code, SPV_ENV_VULKAN_1_2); |
| ASSERT_EQ(ExpectedResult(GetParam()), |
| ValidateInstructions(SPV_ENV_VULKAN_1_2)) |
| << test_code; |
| } |
| } |
| |
| TEST_P(ValidateCapabilityOpenGL40, Capability) { |
| const std::string capability = Capability(GetParam()); |
| if (Exists(capability, SPV_ENV_OPENGL_4_0)) { |
| const std::string test_code = MakeAssembly(GetParam()); |
| CompileSuccessfully(test_code, SPV_ENV_OPENGL_4_0); |
| ASSERT_EQ(ExpectedResult(GetParam()), |
| ValidateInstructions(SPV_ENV_OPENGL_4_0)) |
| << test_code; |
| } |
| } |
| |
| TEST_F(ValidateCapability, SemanticsIdIsAnIdNotALiteral) { |
| // From https://github.com/KhronosGroup/SPIRV-Tools/issues/248 |
| // The validator was interpreting the memory semantics ID number |
| // as the value to be checked rather than an ID that references |
| // another value to be checked. |
| // In this case a raw ID of 64 was mistaken to mean a literal |
| // semantic value of UniformMemory, which would require the Shader |
| // capability. |
| const char str[] = R"( |
| OpCapability Kernel |
| OpCapability Linkage |
| OpMemoryModel Logical OpenCL |
| |
| ; %i32 has ID 1 |
| %i32 = OpTypeInt 32 0 |
| %tf = OpTypeFunction %i32 |
| %pi32 = OpTypePointer CrossWorkgroup %i32 |
| %var = OpVariable %pi32 CrossWorkgroup |
| %c = OpConstant %i32 100 |
| %scope = OpConstant %i32 1 ; Device scope |
| |
| ; Fake an instruction with 64 as the result id. |
| ; !64 = OpConstantNull %i32 |
| !0x3002e !1 !64 |
| |
| %f = OpFunction %i32 None %tf |
| %l = OpLabel |
| %result = OpAtomicIAdd %i32 %var %scope !64 %c |
| OpReturnValue %result |
| OpFunctionEnd |
| )"; |
| |
| CompileSuccessfully(str); |
| |
| // Since we are forcing usage of <id> 64, the "id bound" in the binary header |
| // must be overwritten so that <id> 64 is considered within bound. |
| // ID Bound is at index 3 of the binary. Set it to 65. |
| OverwriteAssembledBinary(3, 65); |
| |
| ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); |
| } |
| |
| TEST_F(ValidateCapability, IntSignednessKernelGood) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Linkage |
| OpMemoryModel Logical OpenCL |
| %i32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); |
| } |
| |
| TEST_F(ValidateCapability, IntSignednessKernelBad) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Linkage |
| OpMemoryModel Logical OpenCL |
| %i32 = OpTypeInt 32 1 |
| )"; |
| CompileSuccessfully(spirv); |
| EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("The Signedness in OpTypeInt must always be 0 when " |
| "Kernel capability is used.")); |
| } |
| |
| TEST_F(ValidateCapability, IntSignednessShaderGood) { |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability Linkage |
| OpMemoryModel Logical GLSL450 |
| %u32 = OpTypeInt 32 0 |
| %i32 = OpTypeInt 32 1 |
| )"; |
| CompileSuccessfully(spirv); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); |
| } |
| |
| TEST_F(ValidateCapability, NonVulkan10Capability) { |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability Linkage |
| OpMemoryModel Logical GLSL450 |
| %u32 = OpTypeInt 32 0 |
| %i32 = OpTypeInt 32 1 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_VULKAN_1_0)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Capability Linkage is not allowed by Vulkan 1.0")); |
| } |
| |
| TEST_F(ValidateCapability, Vulkan10EnabledByExtension) { |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability DrawParameters |
| OpExtension "SPV_KHR_shader_draw_parameters" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Vertex %func "shader" |
| OpMemberDecorate %block 0 BuiltIn PointSize |
| %f32 = OpTypeFloat 32 |
| %block = OpTypeStruct %f32 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); |
| } |
| |
| TEST_F(ValidateCapability, Vulkan10NotEnabledByExtension) { |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability DrawParameters |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Vertex %func "shader" |
| OpDecorate %intt BuiltIn PointSize |
| %intt = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_VULKAN_1_0)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr("Capability DrawParameters is not allowed by Vulkan 1.0")); |
| } |
| |
| TEST_F(ValidateCapability, NonOpenCL12FullCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Pipes |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_1_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_1_2)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr("Capability Pipes is not allowed by OpenCL 1.2 Full Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL12FullEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability ImageBasic |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_1_2); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL12FullNotEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_1_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_1_2)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr( |
| "Capability Sampled1D is not allowed by OpenCL 1.2 Full Profile")); |
| } |
| |
| TEST_F(ValidateCapability, NonOpenCL12EmbeddedCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Int64 |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_1_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_1_2)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr( |
| "Capability Int64 is not allowed by OpenCL 1.2 Embedded Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL12EmbeddedEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability ImageBasic |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_1_2); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_1_2)); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL12EmbeddedNotEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_1_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_1_2)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Capability Sampled1D is not allowed by OpenCL 1.2 " |
| "Embedded Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL12EmbeddedNoLongerEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Pipes |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_1_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_1_2)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Capability Pipes is not allowed by OpenCL 1.2 " |
| "Embedded Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL20FullCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Groups |
| OpCapability Pipes |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_0); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_0)); |
| } |
| |
| TEST_F(ValidateCapability, NonOpenCL20FullCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Matrix |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_0); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_2_0)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr( |
| "Capability Matrix is not allowed by OpenCL 2.0/2.1 Full Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL20FullEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability ImageBasic |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_0); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_0)); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL20FullNotEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_0); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_2_0)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Capability Sampled1D is not allowed by OpenCL 2.0/2.1 " |
| "Full Profile")); |
| } |
| |
| TEST_F(ValidateCapability, NonOpenCL20EmbeddedCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Int64 |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_0); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_0)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Capability Int64 is not allowed by OpenCL 2.0/2.1 " |
| "Embedded Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL20EmbeddedEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability ImageBasic |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_0); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_0)); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL20EmbeddedNotEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_0); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_0)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Capability Sampled1D is not allowed by OpenCL 2.0/2.1 " |
| "Embedded Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL22FullCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability PipeStorage |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_2); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_2)); |
| } |
| |
| TEST_F(ValidateCapability, NonOpenCL22FullCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Matrix |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_2_2)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr("Capability Matrix is not allowed by OpenCL 2.2 Full Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL22FullEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability ImageBasic |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_2); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_2)); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL22FullNotEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_2_2)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr( |
| "Capability Sampled1D is not allowed by OpenCL 2.2 Full Profile")); |
| } |
| |
| TEST_F(ValidateCapability, NonOpenCL22EmbeddedCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Int64 |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )"; |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_2)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr( |
| "Capability Int64 is not allowed by OpenCL 2.2 Embedded Profile")); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL22EmbeddedEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability ImageBasic |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_2); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_2)); |
| } |
| |
| TEST_F(ValidateCapability, OpenCL22EmbeddedNotEnabledByCapability) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability Linkage |
| OpCapability Sampled1D |
| OpMemoryModel Physical64 OpenCL |
| %u32 = OpTypeInt 32 0 |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_2); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_2)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Capability Sampled1D is not allowed by OpenCL 2.2 " |
| "Embedded Profile")); |
| } |
| |
| // Three tests to check enablement of an enum (a decoration) which is not |
| // in core, and is directly enabled by a capability, but not directly enabled |
| // by an extension. See https://github.com/KhronosGroup/SPIRV-Tools/issues/1596 |
| |
| TEST_F(ValidateCapability, DecorationFromExtensionMissingEnabledByCapability) { |
| // Decoration ViewportRelativeNV is enabled by ShaderViewportMaskNV, which in |
| // turn is enabled by SPV_NV_viewport_array2. |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpMemoryModel Logical Simple |
| OpDecorate %void ViewportRelativeNV |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Operand 2 of Decorate requires one of these " |
| "capabilities: ShaderViewportMaskNV")); |
| } |
| |
| TEST_F(ValidateCapability, CapabilityEnabledByMissingExtension) { |
| // Capability ShaderViewportMaskNV is enabled by SPV_NV_viewport_array2. |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability ShaderViewportMaskNV |
| OpMemoryModel Logical Simple |
| )" + std::string(kVoidFVoid); |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); |
| EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, |
| ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("operand ShaderViewportMaskNV(5255) requires one of " |
| "these extensions: SPV_NV_viewport_array2")); |
| } |
| |
| TEST_F(ValidateCapability, |
| DecorationEnabledByCapabilityEnabledByPresentExtension) { |
| // Decoration ViewportRelativeNV is enabled by ShaderViewportMaskNV, which in |
| // turn is enabled by SPV_NV_viewport_array2. |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability Linkage |
| OpCapability ShaderViewportMaskNV |
| OpExtension "SPV_NV_viewport_array2" |
| OpMemoryModel Logical Simple |
| OpDecorate %void ViewportRelativeNV |
| %void = OpTypeVoid |
| )"; |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)) |
| << getDiagnosticString(); |
| } |
| |
| // Three tests to check enablement of an instruction which is not in core, and |
| // is directly enabled by a capability, but not directly enabled by an |
| // extension. See https://github.com/KhronosGroup/SPIRV-Tools/issues/1624 |
| // Instruction OpSubgroupShuffleINTEL is enabled by SubgroupShuffleINTEL, which |
| // in turn is enabled by SPV_INTEL_subgroups. |
| |
| TEST_F(ValidateCapability, InstructionFromExtensionMissingEnabledByCapability) { |
| // Decoration ViewportRelativeNV is enabled by ShaderViewportMaskNV, which in |
| // turn is enabled by SPV_NV_viewport_array2. |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| ; OpCapability SubgroupShuffleINTEL |
| OpExtension "SPV_INTEL_subgroups" |
| OpMemoryModel Physical32 OpenCL |
| OpEntryPoint Kernel %main "main" |
| %void = OpTypeVoid |
| %uint = OpTypeInt 32 0 |
| %voidfn = OpTypeFunction %void |
| %zero = OpConstant %uint 0 |
| %main = OpFunction %void None %voidfn |
| %entry = OpLabel |
| %foo = OpSubgroupShuffleINTEL %uint %zero %zero |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); |
| EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, |
| ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("Opcode SubgroupShuffleINTEL requires one of these " |
| "capabilities: SubgroupShuffleINTEL")); |
| } |
| |
| TEST_F(ValidateCapability, |
| InstructionEnablingCapabilityEnabledByMissingExtension) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability SubgroupShuffleINTEL |
| ; OpExtension "SPV_INTEL_subgroups" |
| OpMemoryModel Physical32 OpenCL |
| OpEntryPoint Kernel %main "main" |
| %void = OpTypeVoid |
| %uint = OpTypeInt 32 0 |
| %voidfn = OpTypeFunction %void |
| %zero = OpConstant %uint 0 |
| %main = OpFunction %void None %voidfn |
| %entry = OpLabel |
| %foo = OpSubgroupShuffleINTEL %uint %zero %zero |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); |
| EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, |
| ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("operand SubgroupShuffleINTEL(5568) requires one of " |
| "these extensions: SPV_INTEL_subgroups")); |
| } |
| |
| TEST_F(ValidateCapability, |
| InstructionEnabledByCapabilityEnabledByPresentExtension) { |
| const std::string spirv = R"( |
| OpCapability Kernel |
| OpCapability Addresses |
| OpCapability SubgroupShuffleINTEL |
| OpExtension "SPV_INTEL_subgroups" |
| OpMemoryModel Physical32 OpenCL |
| OpEntryPoint Kernel %main "main" |
| %void = OpTypeVoid |
| %uint = OpTypeInt 32 0 |
| %voidfn = OpTypeFunction %void |
| %zero = OpConstant %uint 0 |
| %main = OpFunction %void None %voidfn |
| %entry = OpLabel |
| %foo = OpSubgroupShuffleINTEL %uint %zero %zero |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)) |
| << getDiagnosticString(); |
| } |
| |
| TEST_F(ValidateCapability, VulkanMemoryModelWithVulkanKHR) { |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability VulkanMemoryModelKHR |
| OpCapability Linkage |
| OpExtension "SPV_KHR_vulkan_memory_model" |
| OpMemoryModel Logical VulkanKHR |
| )"; |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)) |
| << getDiagnosticString(); |
| } |
| |
| TEST_F(ValidateCapability, VulkanMemoryModelWithGLSL450) { |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability VulkanMemoryModelKHR |
| OpCapability Linkage |
| OpExtension "SPV_KHR_vulkan_memory_model" |
| OpMemoryModel Logical GLSL450 |
| )"; |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); |
| EXPECT_EQ(SPV_ERROR_INVALID_DATA, |
| ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("VulkanMemoryModelKHR capability must only be " |
| "specified if the VulkanKHR memory model is used")); |
| } |
| |
| // In the grammar, SubgroupEqMask and SubgroupMaskKHR have different enabling |
| // lists of extensions. |
| TEST_F(ValidateCapability, SubgroupEqMaskEnabledByExtension) { |
| const std::string spirv = R"( |
| OpCapability Shader |
| OpCapability SubgroupBallotKHR |
| OpExtension "SPV_KHR_shader_ballot" |
| OpMemoryModel Logical Simple |
| OpEntryPoint GLCompute %main "main" |
| OpDecorate %var BuiltIn SubgroupEqMask |
| %void = OpTypeVoid |
| %uint = OpTypeInt 32 0 |
| %ptr_uint = OpTypePointer Private %uint |
| %var = OpVariable %ptr_uint Private |
| %fn = OpTypeFunction %void |
| %main = OpFunction %void None %fn |
| %entry = OpLabel |
| %val = OpLoad %uint %var |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)) |
| << getDiagnosticString(); |
| } |
| |
| // Test that extensions incorporated into SPIR-V 1.5 no longer require |
| // the associated OpExtension instruction. Test one capability per extension. |
| |
| struct CapabilityExtensionVersionCase { |
| std::string capability; |
| std::string capability_new_name; |
| std::string extension; |
| spv_target_env last_version_requiring_extension; |
| spv_target_env first_version_in_core; |
| }; |
| |
| using ValidateCapabilityExtensionVersionTest = |
| spvtest::ValidateBase<CapabilityExtensionVersionCase>; |
| |
| // Returns a minimal shader module with the given capability instruction. |
| std::string MinimalShaderModuleWithCapability(std::string cap) { |
| std::string mem_model = |
| (cap.find("VulkanMemory") == 0) ? "VulkanKHR" : "GLSL450"; |
| std::string extra_cap = (cap.find("VulkanMemoryModelDeviceScope") == 0) |
| ? "\nOpCapability VulkanMemoryModelKHR\n" |
| : ""; |
| return std::string("OpCapability ") + cap + extra_cap + R"( |
| OpCapability Shader |
| OpMemoryModel Logical )" + mem_model + R"( |
| OpEntryPoint Vertex %main "main" |
| %void = OpTypeVoid |
| %void_fn = OpTypeFunction %void |
| %main = OpFunction %void None %void_fn |
| %entry = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| } |
| |
| TEST_P(ValidateCapabilityExtensionVersionTest, FailsInOlderSpirvVersion) { |
| const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability); |
| CompileSuccessfully(spirv, GetParam().last_version_requiring_extension); |
| EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, |
| ValidateInstructions(GetParam().last_version_requiring_extension)); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr(std::string("1st operand of Capability: operand ") + |
| GetParam().capability_new_name)) |
| << spirv << "\n"; |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr(std::string("requires one of these extensions: ") + |
| GetParam().extension)); |
| } |
| |
| TEST_P(ValidateCapabilityExtensionVersionTest, |
| SucceedsInNewerSpirvVersionWithOldName) { |
| const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability); |
| CompileSuccessfully(spirv, GetParam().first_version_in_core); |
| EXPECT_EQ(SPV_SUCCESS, |
| ValidateInstructions(GetParam().first_version_in_core)); |
| EXPECT_THAT(getDiagnosticString(), Eq("")) << spirv << "\n"; |
| } |
| |
| TEST_P(ValidateCapabilityExtensionVersionTest, |
| SucceedsInNewerSpirvVersionWithNewName) { |
| const auto spirv = |
| MinimalShaderModuleWithCapability(GetParam().capability_new_name); |
| CompileSuccessfully(spirv, GetParam().first_version_in_core); |
| EXPECT_EQ(SPV_SUCCESS, |
| ValidateInstructions(GetParam().first_version_in_core)); |
| EXPECT_THAT(getDiagnosticString(), Eq("")) << spirv << "\n"; |
| } |
| |
| std::vector<CapabilityExtensionVersionCase> CapVersionCases1_5() { |
| #define IN15NOSUFFIX(C, E) \ |
| { C, C, E, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5 } |
| #define IN15(C, C_WITHOUT_SUFFIX, E) \ |
| { C, C_WITHOUT_SUFFIX, E, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5 } |
| return std::vector<CapabilityExtensionVersionCase>{ |
| // SPV_KHR_8bit_storage |
| IN15NOSUFFIX("StorageBuffer8BitAccess", "SPV_KHR_8bit_storage"), |
| IN15NOSUFFIX("UniformAndStorageBuffer8BitAccess", "SPV_KHR_8bit_storage"), |
| IN15NOSUFFIX("StoragePushConstant8", "SPV_KHR_8bit_storage"), |
| // SPV_EXT_descriptor_indexing |
| IN15("ShaderNonUniformEXT", "ShaderNonUniform", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("RuntimeDescriptorArrayEXT", "RuntimeDescriptorArray", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("InputAttachmentArrayDynamicIndexingEXT", |
| "InputAttachmentArrayDynamicIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("UniformTexelBufferArrayDynamicIndexingEXT", |
| "UniformTexelBufferArrayDynamicIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("StorageTexelBufferArrayDynamicIndexingEXT", |
| "StorageTexelBufferArrayDynamicIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("UniformBufferArrayNonUniformIndexingEXT", |
| "UniformBufferArrayNonUniformIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("SampledImageArrayNonUniformIndexingEXT", |
| "SampledImageArrayNonUniformIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("StorageBufferArrayNonUniformIndexingEXT", |
| "StorageBufferArrayNonUniformIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("StorageImageArrayNonUniformIndexingEXT", |
| "StorageImageArrayNonUniformIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("InputAttachmentArrayNonUniformIndexingEXT", |
| "InputAttachmentArrayNonUniformIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("UniformTexelBufferArrayNonUniformIndexingEXT", |
| "UniformTexelBufferArrayNonUniformIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| IN15("StorageTexelBufferArrayNonUniformIndexingEXT", |
| "StorageTexelBufferArrayNonUniformIndexing", |
| "SPV_EXT_descriptor_indexing"), |
| // SPV_EXT_physical_storage_buffer |
| IN15("PhysicalStorageBufferAddressesEXT", |
| "PhysicalStorageBufferAddresses", "SPV_EXT_physical_storage_buffer"), |
| // SPV_KHR_vulkan_memory_model |
| IN15("VulkanMemoryModelKHR", "VulkanMemoryModel", |
| "SPV_KHR_vulkan_memory_model"), |
| IN15("VulkanMemoryModelDeviceScopeKHR", "VulkanMemoryModelDeviceScope", |
| "SPV_KHR_vulkan_memory_model"), |
| }; |
| #undef IN15 |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(NewInSpirv1_5, ValidateCapabilityExtensionVersionTest, |
| ValuesIn(CapVersionCases1_5())); |
| |
| TEST_P(ValidateCapability, |
| CapShaderViewportIndexLayerFailsInOlderSpirvVersion) { |
| const auto spirv = |
| MinimalShaderModuleWithCapability("ShaderViewportIndexLayerEXT"); |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); |
| EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, |
| ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr( |
| "1st operand of Capability: operand ShaderViewportIndexLayerEXT")); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("requires one of these extensions: " |
| "SPV_EXT_shader_viewport_index_layer")); |
| } |
| |
| TEST_P(ValidateCapability, CapShaderViewportIndexLayerFailsInNewSpirvVersion) { |
| const auto spirv = |
| MinimalShaderModuleWithCapability("ShaderViewportIndexLayerEXT"); |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); |
| EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, |
| ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); |
| EXPECT_THAT( |
| getDiagnosticString(), |
| HasSubstr( |
| "1st operand of Capability: operand ShaderViewportIndexLayerEXT")); |
| EXPECT_THAT(getDiagnosticString(), |
| HasSubstr("requires one of these extensions: " |
| "SPV_EXT_shader_viewport_index_layer")); |
| } |
| |
| TEST_F(ValidateCapability, CapShaderViewportIndexSucceedsInNewSpirvVersion) { |
| const auto spirv = MinimalShaderModuleWithCapability("ShaderViewportIndex"); |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); |
| EXPECT_THAT(getDiagnosticString(), Eq("")); |
| } |
| |
| TEST_F(ValidateCapability, CapShaderLayerSucceedsInNewSpirvVersion) { |
| const auto spirv = MinimalShaderModuleWithCapability("ShaderLayer"); |
| CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); |
| EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); |
| EXPECT_THAT(getDiagnosticString(), Eq("")); |
| } |
| |
| } // namespace |
| } // namespace val |
| } // namespace spvtools |