Validate variable types for UniformConstant storage in Vulkan (#2008) (#2044)

Validate variable types for UniformConstant storage in Vulkan (#2008)

From the Vulkan 1.1 spec 14.5.2:
  Variables identified with the UniformConstant storage class are used
  only as handles to refer to opaque resources. Such variables must be
  typed as OpTypeImage, OpTypeSampler, OpTypeSampledImage, or an array
  of one of these types.

Fixes #2008
This commit is contained in:
Ryan Harrison 2018-11-14 15:00:03 -05:00 committed by GitHub
parent dc9d155d62
commit a362e60d5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 177 additions and 11 deletions

View File

@ -19,6 +19,7 @@
#include <vector>
#include "source/opcode.h"
#include "source/spirv_target_env.h"
#include "source/val/instruction.h"
#include "source/val/validation_state.h"
@ -323,6 +324,35 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
<< "Classes: Workgroup, CrossWorkgroup, Private, and Function";
}
}
// Check that UniformConstant variables are the correct type, see Vulkan spec
// section 14.5.2 for details.
if (spvIsVulkanEnv(_.context()->target_env) &&
storage_class == SpvStorageClassUniformConstant) {
auto variable_type = _.FindDef(result_type->GetOperandAs<uint32_t>(2));
auto variable_type_opcode = variable_type->opcode();
// If the variable is actually an array extract the element type.
if (variable_type_opcode == SpvOpTypeArray) {
variable_type = _.FindDef(variable_type->GetOperandAs<uint32_t>(1));
variable_type_opcode = variable_type->opcode();
}
switch (variable_type_opcode) {
case SpvOpTypeImage:
case SpvOpTypeSampler:
case SpvOpTypeSampledImage:
break;
default:
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "From Vulkan spec, section 14.5.2:\n"
<< "Variables identified with the UniformConstant storage class "
<< "are used only as handles to refer to opaque resources. Such "
<< "variables must be typed as OpTypeImage, OpTypeSampler, "
<< "OpTypeSampledImage, or an array of one of these types.";
}
}
return SPV_SUCCESS;
}

View File

@ -55,6 +55,7 @@ add_spvtools_unittest(TARGET val_ijklmnop
val_layout_test.cpp
val_literals_test.cpp
val_logicals_test.cpp
val_memory_test.cpp
val_modes_test.cpp
val_non_uniform_test.cpp
val_primitives_test.cpp

View File

@ -1203,7 +1203,7 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
SampleMaskWrongStorageClass,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("SampleMask"), Values("Fragment"), Values("UniformConstant"),
Combine(Values("SampleMask"), Values("Fragment"), Values("Uniform"),
Values("%u32arr2"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,

View File

@ -621,12 +621,12 @@ TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) {
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
%11 = OpTypeSampledImage %10
%_runtimearr_11 = OpTypeRuntimeArray %11
%_ptr_UniformConstant__runtimearr_11 = OpTypePointer UniformConstant %_runtimearr_11
%s2d = OpVariable %_ptr_UniformConstant__runtimearr_11 UniformConstant
%_ptr_Uniform__runtimearr_11 = OpTypePointer Uniform %_runtimearr_11
%s2d = OpVariable %_ptr_Uniform__runtimearr_11 Uniform
%int = OpTypeInt 32 1
%_ptr_Input_int = OpTypePointer Input %int
%i = OpVariable %_ptr_Input_int Input
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
%_ptr_Uniform_11 = OpTypePointer Uniform %11
%v2float = OpTypeVector %float 2
%float_0_300000012 = OpConstant %float 0.300000012
%24 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012
@ -635,7 +635,7 @@ TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) {
%5 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%18 = OpLoad %int %i
%20 = OpAccessChain %_ptr_UniformConstant_11 %s2d %18
%20 = OpAccessChain %_ptr_Uniform_11 %s2d %18
%21 = OpLoad %11 %20
%26 = OpImageSampleExplicitLod %v4float %21 %24 Lod %float_0
OpStore %v %26
@ -689,12 +689,12 @@ TEST_F(ValidateDecorations, RuntimeArrayOfArraysOfDescriptorSetsIsDisallowed) {
%uint_2 = OpConstant %uint 2
%_arr_11_uint_2 = OpTypeArray %11 %uint_2
%_runtimearr__arr_11_uint_2 = OpTypeRuntimeArray %_arr_11_uint_2
%_ptr_UniformConstant__runtimearr__arr_11_uint_2 = OpTypePointer UniformConstant %_runtimearr__arr_11_uint_2
%s2d = OpVariable %_ptr_UniformConstant__runtimearr__arr_11_uint_2 UniformConstant
%_ptr_Uniform__runtimearr__arr_11_uint_2 = OpTypePointer Uniform %_runtimearr__arr_11_uint_2
%s2d = OpVariable %_ptr_Uniform__runtimearr__arr_11_uint_2 Uniform
%int = OpTypeInt 32 1
%_ptr_Input_int = OpTypePointer Input %int
%i = OpVariable %_ptr_Input_int Input
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
%_ptr_Uniform_11 = OpTypePointer Uniform %11
%v2float = OpTypeVector %float 2
%float_0_300000012 = OpConstant %float 0.300000012
%28 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012
@ -704,7 +704,7 @@ TEST_F(ValidateDecorations, RuntimeArrayOfArraysOfDescriptorSetsIsDisallowed) {
%v = OpVariable %_ptr_Function_v4float Function
%21 = OpLoad %int %i
%22 = OpLoad %int %i
%24 = OpAccessChain %_ptr_UniformConstant_11 %s2d %21 %22
%24 = OpAccessChain %_ptr_Uniform_11 %s2d %21 %22
%25 = OpLoad %11 %24
%30 = OpImageSampleExplicitLod %v4float %25 %28 Lod %float_0
OpStore %v %30
@ -744,8 +744,8 @@ TEST_F(ValidateDecorations, ArrayOfArraysOfDescriptorSetsIsDisallowed) {
%uint_2 = OpConstant %uint 2
%_arr_8_uint_2 = OpTypeArray %8 %uint_2
%_arr__arr_8_uint_2_uint_2 = OpTypeArray %_arr_8_uint_2 %uint_2
%_ptr_UniformConstant__arr__arr_8_uint_2_uint_2 = OpTypePointer UniformConstant %_arr__arr_8_uint_2_uint_2
%variableName = OpVariable %_ptr_UniformConstant__arr__arr_8_uint_2_uint_2 UniformConstant
%_ptr_Uniform__arr__arr_8_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_8_uint_2_uint_2
%variableName = OpVariable %_ptr_Uniform__arr__arr_8_uint_2_uint_2 Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn

View File

@ -0,0 +1,135 @@
// Copyright (c) 2018 Google 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 memory/storage
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "test/unit_spirv.h"
#include "test/val/val_fixtures.h"
namespace spvtools {
namespace val {
namespace {
using ::testing::Eq;
using ::testing::HasSubstr;
using ValidateMemory = spvtest::ValidateBase<bool>;
TEST_F(ValidateMemory, VulkanUniformConstantOnNonOpaqueResourceBad) {
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%float = OpTypeFloat 32
%float_ptr = OpTypePointer UniformConstant %float
%2 = OpVariable %float_ptr UniformConstant
%void = OpTypeVoid
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("From Vulkan spec, section 14.5.2:\n"
"Variables identified with the UniformConstant storage class "
"are used only as handles to refer to opaque resources. Such "
"variables must be typed as OpTypeImage, OpTypeSampler, "
"OpTypeSampledImage, or an array of one of these types."));
}
TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceGood) {
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%sampler = OpTypeSampler
%sampler_ptr = OpTypePointer UniformConstant %sampler
%2 = OpVariable %sampler_ptr UniformConstant
%void = OpTypeVoid
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
}
TEST_F(ValidateMemory, VulkanUniformConstantOnNonOpaqueResourceArrayBad) {
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%float = OpTypeFloat 32
%uint = OpTypeInt 32 0
%array_size = OpConstant %uint 5
%array = OpTypeArray %float %array_size
%array_ptr = OpTypePointer UniformConstant %array
%2 = OpVariable %array_ptr UniformConstant
%void = OpTypeVoid
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("From Vulkan spec, section 14.5.2:\n"
"Variables identified with the UniformConstant storage class "
"are used only as handles to refer to opaque resources. Such "
"variables must be typed as OpTypeImage, OpTypeSampler, "
"OpTypeSampledImage, or an array of one of these types."));
}
TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceArrayGood) {
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%sampler = OpTypeSampler
%uint = OpTypeInt 32 0
%array_size = OpConstant %uint 5
%array = OpTypeArray %sampler %array_size
%array_ptr = OpTypePointer UniformConstant %array
%2 = OpVariable %array_ptr UniformConstant
%void = OpTypeVoid
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
}
} // namespace
} // namespace val
} // namespace spvtools