diff --git a/source/validate_capability.cpp b/source/validate_capability.cpp index 1a47ebc5e..af88d5c85 100644 --- a/source/validate_capability.cpp +++ b/source/validate_capability.cpp @@ -44,6 +44,16 @@ bool IsSupportGuaranteedVulkan_1_0(uint32_t capability) { return false; } +bool IsSupportGuaranteedVulkan_1_1(uint32_t capability) { + if (IsSupportGuaranteedVulkan_1_0(capability)) return true; + switch (capability) { + case SpvCapabilityDeviceGroup: + case SpvCapabilityMultiView: + return true; + } + return false; +} + bool IsSupportOptionalVulkan_1_0(uint32_t capability) { switch (capability) { case SpvCapabilityGeometry: @@ -77,6 +87,34 @@ bool IsSupportOptionalVulkan_1_0(uint32_t capability) { return false; } +bool IsSupportOptionalVulkan_1_1(uint32_t capability) { + if (IsSupportOptionalVulkan_1_0(capability)) return true; + + switch (capability) { + case SpvCapabilityGroupNonUniform: + case SpvCapabilityGroupNonUniformVote: + case SpvCapabilityGroupNonUniformArithmetic: + case SpvCapabilityGroupNonUniformBallot: + case SpvCapabilityGroupNonUniformShuffle: + case SpvCapabilityGroupNonUniformShuffleRelative: + case SpvCapabilityGroupNonUniformClustered: + case SpvCapabilityGroupNonUniformQuad: + case SpvCapabilityDrawParameters: + // Alias SpvCapabilityStorageBuffer16BitAccess. + case SpvCapabilityStorageUniformBufferBlock16: + // Alias SpvCapabilityUniformAndStorageBuffer16BitAccess. + case SpvCapabilityStorageUniform16: + case SpvCapabilityStoragePushConstant16: + case SpvCapabilityStorageInputOutput16: + case SpvCapabilityDeviceGroup: + case SpvCapabilityMultiView: + case SpvCapabilityVariablePointersStorageBuffer: + case SpvCapabilityVariablePointers: + return true; + } + return false; +} + bool IsSupportGuaranteedOpenCL_1_2(uint32_t capability, bool embedded_profile) { switch (capability) { case SpvCapabilityAddresses: @@ -220,6 +258,15 @@ spv_result_t CapabilityPass(ValidationState_t& _, << " is not allowed by Vulkan 1.0 specification" << " (or requires extension)"; } + } else if (env == SPV_ENV_VULKAN_1_1) { + if (!IsSupportGuaranteedVulkan_1_1(capability) && + !IsSupportOptionalVulkan_1_1(capability) && + !IsEnabledByExtension(_, capability)) { + return _.diag(SPV_ERROR_INVALID_CAPABILITY) + << "Capability " << capability_str() + << " is not allowed by Vulkan 1.1 specification" + << " (or requires extension)"; + } } else if (env == SPV_ENV_OPENCL_1_2 || env == SPV_ENV_OPENCL_EMBEDDED_1_2) { if (!IsSupportGuaranteedOpenCL_1_2(capability, opencl_embedded) && !IsSupportOptionalOpenCL_1_2(capability) && diff --git a/test/val/val_capability_test.cpp b/test/val/val_capability_test.cpp index 53d685dbe..1b90b59c9 100644 --- a/test/val/val_capability_test.cpp +++ b/test/val/val_capability_test.cpp @@ -22,6 +22,7 @@ #include #include "source/assembly_grammar.h" +#include "spirv_target_env.h" #include "test_fixture.h" #include "unit_spirv.h" #include "val_fixtures.h" @@ -109,6 +110,8 @@ using ValidateCapabilityV11 = spvtest::ValidateBase; using ValidateCapabilityVulkan10 = spvtest::ValidateBase; // Always assembles using OpenGL 4.0. using ValidateCapabilityOpenGL40 = spvtest::ValidateBase; +// Always assembles using Vulkan 1.1. +using ValidateCapabilityVulkan11 = spvtest::ValidateBase; TEST_F(ValidateCapability, Default) { const char str[] = R"( @@ -187,7 +190,26 @@ const vector& AllCapabilities() { "MultiViewport", "SubgroupDispatch", "NamedBarrier", - "PipeStorage"}; + "PipeStorage", + "GroupNonUniform", + "GroupNonUniformVote", + "GroupNonUniformArithmetic", + "GroupNonUniformBallot", + "GroupNonUniformShuffle", + "GroupNonUniformShuffleRelative", + "GroupNonUniformClustered", + "GroupNonUniformQuad", + "DrawParameters", + "StorageBuffer16BitAccess", + "StorageUniformBufferBlock16", + "UniformAndStorageBuffer16BitAccess", + "StorageUniform16", + "StoragePushConstant16", + "StorageInputOutput16", + "DeviceGroup", + "MultiView", + "VariablePointersStorageBuffer", + "VariablePointers"}; return *r; } @@ -294,6 +316,66 @@ const vector& AllVulkan10Capabilities() { return *r; } +const vector& AllVulkan11Capabilities() { + static const auto r = new vector{ + "", + "Matrix", + "Shader", + "InputAttachment", + "Sampled1D", + "Image1D", + "SampledBuffer", + "ImageBuffer", + "ImageQuery", + "DerivativeControl", + "Geometry", + "Tessellation", + "Float64", + "Int64", + "Int16", + "TessellationPointSize", + "GeometryPointSize", + "ImageGatherExtended", + "StorageImageMultisample", + "UniformBufferArrayDynamicIndexing", + "SampledImageArrayDynamicIndexing", + "StorageBufferArrayDynamicIndexing", + "StorageImageArrayDynamicIndexing", + "ClipDistance", + "CullDistance", + "ImageCubeArray", + "SampleRateShading", + "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"}; + return *r; +} + const vector& MatrixDependencies() { static const auto r = new vector{ "Matrix", @@ -328,7 +410,11 @@ const vector& MatrixDependencies() { "GeometryStreams", "StorageImageReadWithoutFormat", "StorageImageWriteWithoutFormat", - "MultiViewport"}; + "MultiViewport", + "DrawParameters", + "MultiView", + "VariablePointersStorageBuffer", + "VariablePointers"}; return *r; } @@ -365,7 +451,11 @@ const vector& ShaderDependencies() { "GeometryStreams", "StorageImageReadWithoutFormat", "StorageImageWriteWithoutFormat", - "MultiViewport"}; + "MultiViewport", + "DrawParameters", + "MultiView", + "VariablePointersStorageBuffer", + "VariablePointers"}; return *r; } @@ -415,6 +505,31 @@ const vector& KernelDependencies() { return *r; } +const vector& KernelAndGroupNonUniformDependencies() { + static const auto r = new vector{ + "Kernel", + "Vector16", + "Float16Buffer", + "ImageBasic", + "ImageReadWrite", + "ImageMipmap", + "Pipes", + "DeviceEnqueue", + "LiteralSampler", + "SubgroupDispatch", + "NamedBarrier", + "PipeStorage", + "GroupNonUniform", + "GroupNonUniformVote", + "GroupNonUniformArithmetic", + "GroupNonUniformBallot", + "GroupNonUniformShuffle", + "GroupNonUniformShuffleRelative", + "GroupNonUniformClustered", + "GroupNonUniformQuad"}; + return *r; +} + const vector& AddressesDependencies() { static const auto r = new vector{ "Addresses", @@ -1287,7 +1402,7 @@ make_pair(string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %intt BuiltIn SubgroupSize\n" "%intt = OpTypeInt 32 0\n" + string(kVoidFVoid), - KernelDependencies()), + KernelAndGroupNonUniformDependencies()), make_pair(string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %intt BuiltIn SubgroupMaxSize\n" @@ -1297,7 +1412,7 @@ make_pair(string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %intt BuiltIn NumSubgroups\n" "%intt = OpTypeInt 32 0\n" + string(kVoidFVoid), - KernelDependencies()), + KernelAndGroupNonUniformDependencies()), make_pair(string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %intt BuiltIn NumEnqueuedSubgroups\n" @@ -1307,12 +1422,12 @@ make_pair(string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %intt BuiltIn SubgroupId\n" "%intt = OpTypeInt 32 0\n" + string(kVoidFVoid), - KernelDependencies()), + KernelAndGroupNonUniformDependencies()), make_pair(string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %intt BuiltIn SubgroupLocalInvocationId\n" "%intt = OpTypeInt 32 0\n" + string(kVoidFVoid), - KernelDependencies()), + KernelAndGroupNonUniformDependencies()), make_pair(string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %intt BuiltIn VertexIndex\n" @@ -1384,6 +1499,23 @@ make_pair(string(kGLSL450MemoryModel) + AllSpirV10Capabilities()) )),); +INSTANTIATE_TEST_CASE_P(Capabilities, ValidateCapabilityVulkan11, + Combine( + // All capabilities to try. + ValuesIn(AllCapabilities()), + Values( +make_pair(string(kGLSL450MemoryModel) + + "OpEntryPoint Vertex %func \"shader\" \n" + + "OpDecorate %intt BuiltIn PointSize\n" + "%intt = OpTypeInt 32 0\n" + string(kVoidFVoid), + AllVulkan11Capabilities()), +make_pair(string(kGLSL450MemoryModel) + + "OpEntryPoint Vertex %func \"shader\" \n" + + "OpDecorate %intt BuiltIn CullDistance\n" + "%intt = OpTypeInt 32 0\n" + string(kVoidFVoid), + AllVulkan11Capabilities()) +)),); + // TODO(umar): Selection Control // TODO(umar): Loop Control // TODO(umar): Function Control @@ -1460,21 +1592,53 @@ INSTANTIATE_TEST_CASE_P( // TODO(umar): Instruction capability checks -// True if capability exists in env. +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) { - spv_operand_desc dummy; - return SPV_SUCCESS == libspirv::AssemblyGrammar(ScopedContext(env).context) - .lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, - capability.c_str(), - capability.size(), &dummy); + 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 string capability = Capability(GetParam()); - spv_target_env env = - (capability.empty() || Exists(capability, SPV_ENV_UNIVERSAL_1_0)) - ? SPV_ENV_UNIVERSAL_1_0 - : SPV_ENV_UNIVERSAL_1_1; + 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 string test_code = MakeAssembly(GetParam()); CompileSuccessfully(test_code, env); ASSERT_EQ(ExpectedResult(GetParam()), ValidateInstructions(env)) @@ -1483,27 +1647,47 @@ TEST_P(ValidateCapability, Capability) { } TEST_P(ValidateCapabilityV11, Capability) { - const 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; + const string capability = Capability(GetParam()); + if (Exists(capability, SPV_ENV_UNIVERSAL_1_1)) { + const 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 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; + const string capability = Capability(GetParam()); + if (Exists(capability, SPV_ENV_VULKAN_1_0)) { + const 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 string capability = Capability(GetParam()); + if (Exists(capability, SPV_ENV_VULKAN_1_1)) { + const 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(ValidateCapabilityOpenGL40, Capability) { - const 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; + const string capability = Capability(GetParam()); + if (Exists(capability, SPV_ENV_OPENGL_4_0)) { + const 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) {