blob: ba0e95976c929e5d7581dbb1532590ce1b2a571c [file] [log] [blame]
// Copyright (c) 2017 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 decorations
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "source/val/decoration.h"
#include "test/unit_spirv.h"
#include "test/val/val_code_generator.h"
#include "test/val/val_fixtures.h"
namespace spvtools {
namespace val {
namespace {
using ::testing::Combine;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::Values;
struct TestResult {
TestResult(spv_result_t in_validation_result = SPV_SUCCESS,
const std::string& in_error_str = "")
: validation_result(in_validation_result), error_str(in_error_str) {}
spv_result_t validation_result;
const std::string error_str;
};
using ValidateDecorations = spvtest::ValidateBase<bool>;
using ValidateDecorationString = spvtest::ValidateBase<std::string>;
using ValidateVulkanCombineDecorationResult =
spvtest::ValidateBase<std::tuple<const char*, const char*, TestResult>>;
TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %1 Location 4
OpDecorate %1 Centroid
%2 = OpTypeFloat 32
%3 = OpTypePointer Output %2
%1 = OpVariable %3 Output
; Since %1 is used first in Decoration, it gets id 1.
)";
const uint32_t id = 1;
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
// Must have 2 decorations.
EXPECT_THAT(
vstate_->id_decorations(id),
Eq(std::set<Decoration>{Decoration(spv::Decoration::Location, {4}),
Decoration(spv::Decoration::Centroid)}));
}
TEST_F(ValidateDecorations, ValidateOpMemberDecorateRegistration) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %_arr_double_uint_6 ArrayStride 4
OpMemberDecorate %_struct_115 2 NonReadable
OpMemberDecorate %_struct_115 2 Offset 2
OpDecorate %_struct_115 BufferBlock
%float = OpTypeFloat 32
%uint = OpTypeInt 32 0
%uint_6 = OpConstant %uint 6
%_arr_double_uint_6 = OpTypeArray %float %uint_6
%_struct_115 = OpTypeStruct %float %float %_arr_double_uint_6
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
// The array must have 1 decoration.
const uint32_t arr_id = 1;
EXPECT_THAT(
vstate_->id_decorations(arr_id),
Eq(std::set<Decoration>{Decoration(spv::Decoration::ArrayStride, {4})}));
// The struct must have 3 decorations.
const uint32_t struct_id = 2;
EXPECT_THAT(
vstate_->id_decorations(struct_id),
Eq(std::set<Decoration>{Decoration(spv::Decoration::NonReadable, {}, 2),
Decoration(spv::Decoration::Offset, {2}, 2),
Decoration(spv::Decoration::BufferBlock)}));
}
TEST_F(ValidateDecorations, ValidateOpMemberDecorateOutOfBound) {
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "Main"
OpExecutionMode %1 OriginUpperLeft
OpMemberDecorate %_struct_2 1 RelaxedPrecision
%void = OpTypeVoid
%4 = OpTypeFunction %void
%float = OpTypeFloat 32
%_struct_2 = OpTypeStruct %float
%1 = OpFunction %void None %4
%6 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Index 1 provided in OpMemberDecorate for struct <id> "
"'2[%_struct_2]' is out of bounds. The structure has 1 "
"members. Largest valid index is 0."));
}
TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %1 DescriptorSet 0
OpDecorate %1 RelaxedPrecision
OpDecorate %1 Restrict
%1 = OpDecorationGroup
OpGroupDecorate %1 %2 %3
OpGroupDecorate %1 %4
%float = OpTypeFloat 32
%_runtimearr_float = OpTypeRuntimeArray %float
%_struct_9 = OpTypeStruct %_runtimearr_float
%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
%2 = OpVariable %_ptr_Uniform__struct_9 Uniform
%_struct_10 = OpTypeStruct %_runtimearr_float
%_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
%3 = OpVariable %_ptr_Uniform__struct_10 Uniform
%_struct_11 = OpTypeStruct %_runtimearr_float
%_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11
%4 = OpVariable %_ptr_Uniform__struct_11 Uniform
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
// Decoration group has 3 decorations.
auto expected_decorations =
std::set<Decoration>{Decoration(spv::Decoration::DescriptorSet, {0}),
Decoration(spv::Decoration::RelaxedPrecision),
Decoration(spv::Decoration::Restrict)};
// Decoration group is applied to id 1, 2, 3, and 4. Note that id 1 (which is
// the decoration group id) also has all the decorations.
EXPECT_THAT(vstate_->id_decorations(1), Eq(expected_decorations));
EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations));
EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations));
EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
}
TEST_F(ValidateDecorations, ValidateGroupMemberDecorateRegistration) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %1 Offset 3
%1 = OpDecorationGroup
OpGroupMemberDecorate %1 %_struct_1 3 %_struct_2 3 %_struct_3 3
%float = OpTypeFloat 32
%_runtimearr = OpTypeRuntimeArray %float
%_struct_1 = OpTypeStruct %float %float %float %_runtimearr
%_struct_2 = OpTypeStruct %float %float %float %_runtimearr
%_struct_3 = OpTypeStruct %float %float %float %_runtimearr
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
// Decoration group has 1 decoration.
auto expected_decorations =
std::set<Decoration>{Decoration(spv::Decoration::Offset, {3}, 3)};
// Decoration group is applied to id 2, 3, and 4.
EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations));
EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations));
EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
}
TEST_F(ValidateDecorations, LinkageImportUsedForInitializedVariableBad) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %target LinkageAttributes "link_ptr" Import
%float = OpTypeFloat 32
%_ptr_float = OpTypePointer Uniform %float
%zero = OpConstantNull %float
%target = OpVariable %_ptr_float Uniform %zero
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("A module-scope OpVariable with initialization value "
"cannot be marked with the Import Linkage Type."));
}
TEST_F(ValidateDecorations, LinkageExportUsedForInitializedVariableGood) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %target LinkageAttributes "link_ptr" Export
%float = OpTypeFloat 32
%_ptr_float = OpTypePointer Uniform %float
%zero = OpConstantNull %float
%target = OpVariable %_ptr_float Uniform %zero
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, StructAllMembersHaveBuiltInDecorationsGood) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %_struct_1 Block
OpMemberDecorate %_struct_1 0 BuiltIn Position
OpMemberDecorate %_struct_1 1 BuiltIn Position
OpMemberDecorate %_struct_1 2 BuiltIn Position
OpMemberDecorate %_struct_1 3 BuiltIn Position
%float = OpTypeFloat 32
%_runtimearr = OpTypeRuntimeArray %float
%_struct_1 = OpTypeStruct %float %float %float %_runtimearr
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, MixedBuiltInDecorationsBad) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %_struct_1 Block
OpMemberDecorate %_struct_1 0 BuiltIn Position
OpMemberDecorate %_struct_1 1 BuiltIn Position
%float = OpTypeFloat 32
%_runtimearr = OpTypeRuntimeArray %float
%_struct_1 = OpTypeStruct %float %float %float %_runtimearr
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("When BuiltIn decoration is applied to a structure-type "
"member, all members of that structure type must also be "
"decorated with BuiltIn (No allowed mixing of built-in "
"variables and non-built-in variables within a single "
"structure). Structure id 1 does not meet this requirement."));
}
TEST_F(ValidateDecorations, StructContainsBuiltInStructBad) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %_struct_1 Block
OpMemberDecorate %_struct_1 0 BuiltIn Position
OpMemberDecorate %_struct_1 1 BuiltIn Position
OpMemberDecorate %_struct_1 2 BuiltIn Position
OpMemberDecorate %_struct_1 3 BuiltIn Position
%float = OpTypeFloat 32
%_runtimearr = OpTypeRuntimeArray %float
%_struct_1 = OpTypeStruct %float %float %float %_runtimearr
%_struct_2 = OpTypeStruct %_struct_1
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Structure <id> '1[%_struct_1]' contains members with "
"BuiltIn decoration. Therefore this structure may not "
"be contained as a member of another structure type. "
"Structure <id> '4[%_struct_4]' contains structure <id> "
"'1[%_struct_1]'."));
}
TEST_F(ValidateDecorations, StructContainsNonBuiltInStructGood) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
%float = OpTypeFloat 32
%_struct_1 = OpTypeStruct %float
%_struct_2 = OpTypeStruct %_struct_1
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, MultipleBuiltInObjectsConsumedByOpEntryPointBad) {
std::string spirv = R"(
OpCapability Shader
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %in_1 %in_2
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
OpDecorate %struct_1 Block
OpDecorate %struct_2 Block
OpMemberDecorate %struct_1 0 BuiltIn InvocationId
OpMemberDecorate %struct_2 0 BuiltIn Position
%int = OpTypeInt 32 1
%void = OpTypeVoid
%func = OpTypeFunction %void
%float = OpTypeFloat 32
%struct_1 = OpTypeStruct %int
%struct_2 = OpTypeStruct %float
%ptr_builtin_1 = OpTypePointer Input %struct_1
%ptr_builtin_2 = OpTypePointer Input %struct_2
%in_1 = OpVariable %ptr_builtin_1 Input
%in_2 = OpVariable %ptr_builtin_2 Input
%main = OpFunction %void None %func
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("There must be at most one object per Storage Class "
"that can contain a structure type containing members "
"decorated with BuiltIn, consumed per entry-point."));
}
TEST_F(ValidateDecorations,
OneBuiltInObjectPerStorageClassConsumedByOpEntryPointGood) {
std::string spirv = R"(
OpCapability Shader
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %in_1 %out_1
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
OpDecorate %struct_1 Block
OpDecorate %struct_2 Block
OpMemberDecorate %struct_1 0 BuiltIn InvocationId
OpMemberDecorate %struct_2 0 BuiltIn Position
%int = OpTypeInt 32 1
%void = OpTypeVoid
%func = OpTypeFunction %void
%float = OpTypeFloat 32
%struct_1 = OpTypeStruct %int
%struct_2 = OpTypeStruct %float
%ptr_builtin_1 = OpTypePointer Input %struct_1
%ptr_builtin_2 = OpTypePointer Output %struct_2
%in_1 = OpVariable %ptr_builtin_1 Input
%out_1 = OpVariable %ptr_builtin_2 Output
%main = OpFunction %void None %func
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, NoBuiltInObjectsConsumedByOpEntryPointGood) {
std::string spirv = R"(
OpCapability Shader
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %in_1 %out_1
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
%int = OpTypeInt 32 1
%void = OpTypeVoid
%func = OpTypeFunction %void
%float = OpTypeFloat 32
%struct_1 = OpTypeStruct %int
%struct_2 = OpTypeStruct %float
%ptr_builtin_1 = OpTypePointer Input %struct_1
%ptr_builtin_2 = OpTypePointer Output %struct_2
%in_1 = OpVariable %ptr_builtin_1 Input
%out_1 = OpVariable %ptr_builtin_2 Output
%main = OpFunction %void None %func
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, EntryPointFunctionHasLinkageAttributeBad) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpDecorate %main LinkageAttributes "import_main" Import
%1 = OpTypeVoid
%2 = OpTypeFunction %1
%main = OpFunction %1 None %2
%4 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("The LinkageAttributes Decoration (Linkage name: import_main) "
"cannot be applied to function id 1 because it is targeted by "
"an OpEntryPoint instruction."));
}
TEST_F(ValidateDecorations, FunctionDeclarationWithoutImportLinkageBad) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
%void = OpTypeVoid
%func = OpTypeFunction %void
%main = OpFunction %void None %func
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Function declaration (id 3) must have a LinkageAttributes "
"decoration with the Import Linkage type."));
}
TEST_F(ValidateDecorations, FunctionDeclarationWithImportLinkageGood) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %main LinkageAttributes "link_fn" Import
%void = OpTypeVoid
%func = OpTypeFunction %void
%main = OpFunction %void None %func
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, FunctionDeclarationWithExportLinkageBad) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %main LinkageAttributes "link_fn" Export
%void = OpTypeVoid
%func = OpTypeFunction %void
%main = OpFunction %void None %func
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Function declaration (id 1) must have a LinkageAttributes "
"decoration with the Import Linkage type."));
}
TEST_F(ValidateDecorations, FunctionDefinitionWithImportLinkageBad) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %main LinkageAttributes "link_fn" Import
%void = OpTypeVoid
%func = OpTypeFunction %void
%main = OpFunction %void None %func
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Function definition (id 1) may not be decorated with "
"Import Linkage type."));
}
TEST_F(ValidateDecorations, FunctionDefinitionWithoutImportLinkageGood) {
std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
%void = OpTypeVoid
%func = OpTypeFunction %void
%main = OpFunction %void None %func
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, BuiltinVariablesGoodVulkan) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpDecorate %gl_FragCoord BuiltIn FragCoord
OpDecorate %_entryPointOutput Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%float_0 = OpConstant %float 0
%14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%_ptr_Input_v4float = OpTypePointer Input %v4float
%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
OpStore %_entryPointOutput %14
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
}
TEST_F(ValidateDecorations, BuiltinVariablesWithLocationDecorationVulkan) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpDecorate %gl_FragCoord BuiltIn FragCoord
OpDecorate %gl_FragCoord Location 0
OpDecorate %_entryPointOutput Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%float_0 = OpConstant %float 0
%14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%_ptr_Input_v4float = OpTypePointer Input %v4float
%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
OpStore %_entryPointOutput %14
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-Location-04915"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
"Component decorations"));
}
TEST_F(ValidateDecorations, BuiltinVariablesWithComponentDecorationVulkan) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpDecorate %gl_FragCoord BuiltIn FragCoord
OpDecorate %gl_FragCoord Component 0
OpDecorate %_entryPointOutput Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%float_0 = OpConstant %float 0
%14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%_ptr_Input_v4float = OpTypePointer Input %v4float
%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
OpStore %_entryPointOutput %14
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-Location-04915"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
"Component decorations"));
}
TEST_F(ValidateDecorations, LocationDecorationOnNumericTypeBad) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord
OpExecutionMode %main OriginUpperLeft
OpDecorate %fragCoord Location 0
OpDecorate %v4float Location 1
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%non_interface = OpVariable %ptr_v4float Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Location decoration on target <id> '3[%v4float]' must "
"be a variable"));
}
TEST_F(ValidateDecorations, LocationDecorationOnStructBad) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord
OpExecutionMode %main OriginUpperLeft
OpDecorate %fragCoord Location 0
OpDecorate %struct Location 1
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%struct = OpTypeStruct %float
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%non_interface = OpVariable %ptr_v4float Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Location decoration on target <id> '3[%_struct_3]' "
"must be a variable"));
}
TEST_F(ValidateDecorations,
LocationDecorationUnusedNonInterfaceVariableVulkan_Ignored) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpDecorate %fragCoord Location 0
OpDecorate %non_interface Location 1
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%non_interface = OpVariable %ptr_v4float Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
EXPECT_EQ(getDiagnosticString(), "");
}
TEST_F(ValidateDecorations,
LocationDecorationNonInterfaceStructVulkan_Ignored) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord
OpExecutionMode %main OriginUpperLeft
OpDecorate %fragCoord Location 0
OpMemberDecorate %block 0 Location 2
OpMemberDecorate %block 0 Component 1
OpDecorate %block Block
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%vec3 = OpTypeVector %float 3
%outvar_ptr = OpTypePointer Output %vec3
%fragCoord = OpVariable %outvar_ptr Output
%block = OpTypeStruct %vec3
%invar_ptr = OpTypePointer Input %block
%non_interface = OpVariable %invar_ptr Input
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
EXPECT_EQ(getDiagnosticString(), "");
}
TEST_F(ValidateDecorations, LocationDecorationNonInterfaceStructVulkanGood) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord %interface
OpExecutionMode %main OriginUpperLeft
OpDecorate %fragCoord Location 0
OpMemberDecorate %block 0 Location 2
OpMemberDecorate %block 0 Component 1
OpDecorate %block Block
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%vec3 = OpTypeVector %float 3
%outvar_ptr = OpTypePointer Output %vec3
%fragCoord = OpVariable %outvar_ptr Output
%block = OpTypeStruct %vec3
%invar_ptr = OpTypePointer Input %block
%interface = OpVariable %invar_ptr Input ;; this variable is unused. Ignore it
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
}
TEST_F(ValidateDecorations, LocationDecorationVariableNonStructVulkanBad) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord %nonblock_var
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpDecorate %fragCoord Location 0
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%nonblock_var = OpVariable %ptr_v4float Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-Location-04916"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Variable must be decorated with a location"));
}
TEST_F(ValidateDecorations, LocationDecorationVariableStructNoBlockVulkanBad) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord %block_var
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpDecorate %fragCoord Location 0
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%block = OpTypeStruct %v4float
%block_ptr = OpTypePointer Output %block
%block_var = OpVariable %block_ptr Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-Location-04917"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Variable must be decorated with a location"));
}
TEST_F(ValidateDecorations, LocationDecorationVariableNoBlockVulkanGood) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord %block_var
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpDecorate %fragCoord Location 0
OpDecorate %block_var Location 1
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%block = OpTypeStruct %v4float
%block_ptr = OpTypePointer Output %block
%block_var = OpVariable %block_ptr Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, LocationDecorationVariableExtraMemeberVulkan) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord %block_var
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpDecorate %fragCoord Location 0
OpDecorate %block Block
OpDecorate %block_var Location 1
OpMemberDecorate %block 0 Location 1
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%block = OpTypeStruct %v4float
%block_ptr = OpTypePointer Output %block
%block_var = OpVariable %block_ptr Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-Location-04918"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Members cannot be assigned a location"));
}
TEST_F(ValidateDecorations, LocationDecorationVariableMissingMemeberVulkan) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord %block_var
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpDecorate %fragCoord Location 0
OpDecorate %block Block
OpMemberDecorate %block 0 Location 1
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%block = OpTypeStruct %v4float %v4float
%block_ptr = OpTypePointer Output %block
%block_var = OpVariable %block_ptr Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateAndRetrieveValidationState(env));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-Location-04919"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Member index 1 is missing a location assignment"));
}
TEST_F(ValidateDecorations, LocationDecorationVariableOnlyMemeberVulkanGood) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord %block_var
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpDecorate %fragCoord Location 0
OpDecorate %block Block
OpMemberDecorate %block 0 Location 1
OpMemberDecorate %block 1 Location 4
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%block = OpTypeStruct %v4float %v4float
%block_ptr = OpTypePointer Output %block
%block_var = OpVariable %block_ptr Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
// #version 440
// #extension GL_EXT_nonuniform_qualifier : enable
// layout(binding = 1) uniform sampler2D s2d[];
// layout(location = 0) in nonuniformEXT int i;
// void main()
// {
// vec4 v = texture(s2d[i], vec2(0.3));
// }
TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) {
const spv_target_env env = SPV_ENV_VULKAN_1_0;
std::string spirv = R"(
OpCapability Shader
OpCapability ShaderNonUniformEXT
OpCapability RuntimeDescriptorArrayEXT
OpCapability SampledImageArrayNonUniformIndexingEXT
OpExtension "SPV_EXT_descriptor_indexing"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %i
OpSource GLSL 440
OpSourceExtension "GL_EXT_nonuniform_qualifier"
OpName %main "main"
OpName %v "v"
OpName %s2d "s2d"
OpName %i "i"
OpDecorate %s2d DescriptorSet 0
OpDecorate %s2d Binding 1
OpDecorate %i Location 0
OpDecorate %i NonUniformEXT
OpDecorate %18 NonUniformEXT
OpDecorate %21 NonUniformEXT
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
%11 = OpTypeSampledImage %10
%_runtimearr_11 = OpTypeRuntimeArray %11
%_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_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
%float_0 = OpConstant %float 0
%main = OpFunction %void None %3
%5 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%18 = OpLoad %int %i
%20 = OpAccessChain %_ptr_Uniform_11 %s2d %18
%21 = OpLoad %11 %20
%26 = OpImageSampleExplicitLod %v4float %21 %24 Lod %float_0
OpStore %v %26
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, env);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
TEST_F(ValidateDecorations, BlockDecoratingArrayBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%int = OpTypeInt 32 1
%int_3 = OpConstant %int 3
%Output = OpTypeArray %float %int_3
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
}
TEST_F(ValidateDecorations, BlockDecoratingIntBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%Output = OpTypeInt 32 1
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
}
TEST_F(ValidateDecorations, BlockMissingOffsetBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%Output = OpTypeStruct %float
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("must be explicitly laid out with Offset decorations"));
}
TEST_F(ValidateDecorations, BufferBlockMissingOffsetBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output BufferBlock
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%Output = OpTypeStruct %float
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("must be explicitly laid out with Offset decorations"));
}
TEST_F(ValidateDecorations, BlockNestedStructMissingOffsetBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%v3float = OpTypeVector %float 3
%int = OpTypeInt 32 1
%S = OpTypeStruct %v3float %int
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("must be explicitly laid out with Offset decorations"));
}
TEST_F(ValidateDecorations, BufferBlockNestedStructMissingOffsetBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output BufferBlock
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%v3float = OpTypeVector %float 3
%int = OpTypeInt 32 1
%S = OpTypeStruct %v3float %int
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("must be explicitly laid out with Offset decorations"));
}
TEST_F(ValidateDecorations, BlockGLSLSharedBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output Block
OpDecorate %Output GLSLShared
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%Output = OpTypeStruct %float
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"'GLSLShared' is not valid for the Vulkan execution environment"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("[VUID-StandaloneSpirv-GLSLShared-04669]"));
}
TEST_F(ValidateDecorations, BufferBlockGLSLSharedBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output BufferBlock
OpDecorate %Output GLSLShared
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%Output = OpTypeStruct %float
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"'GLSLShared' is not valid for the Vulkan execution environment"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("[VUID-StandaloneSpirv-GLSLShared-04669]"));
}
TEST_F(ValidateDecorations, BlockNestedStructGLSLSharedBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpDecorate %S GLSLShared
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int = OpTypeInt 32 1
%S = OpTypeStruct %int
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"'GLSLShared' is not valid for the Vulkan execution environment"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("[VUID-StandaloneSpirv-GLSLShared-04669]"));
}
TEST_F(ValidateDecorations, BufferBlockNestedStructGLSLSharedBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpDecorate %S GLSLShared
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output BufferBlock
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int = OpTypeInt 32 1
%S = OpTypeStruct %int
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"'GLSLShared' is not valid for the Vulkan execution environment"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("[VUID-StandaloneSpirv-GLSLShared-04669]"));
}
TEST_F(ValidateDecorations, BlockGLSLPackedBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output Block
OpDecorate %Output GLSLPacked
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%Output = OpTypeStruct %float
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"'GLSLPacked' is not valid for the Vulkan execution environment"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("[VUID-StandaloneSpirv-GLSLShared-04669]"));
}
TEST_F(ValidateDecorations, BufferBlockGLSLPackedBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output BufferBlock
OpDecorate %Output GLSLPacked
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%Output = OpTypeStruct %float
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"'GLSLPacked' is not valid for the Vulkan execution environment"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("[VUID-StandaloneSpirv-GLSLShared-04669]"));
}
TEST_F(ValidateDecorations, BlockNestedStructGLSLPackedBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpDecorate %S GLSLPacked
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int = OpTypeInt 32 1
%S = OpTypeStruct %int
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"'GLSLPacked' is not valid for the Vulkan execution environment"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("[VUID-StandaloneSpirv-GLSLShared-04669]"));
}
TEST_F(ValidateDecorations, BufferBlockNestedStructGLSLPackedBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpDecorate %S GLSLPacked
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output BufferBlock
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int = OpTypeInt 32 1
%S = OpTypeStruct %int
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"'GLSLPacked' is not valid for the Vulkan execution environment"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("[VUID-StandaloneSpirv-GLSLShared-04669]"));
}
TEST_F(ValidateDecorations, BlockMissingArrayStrideBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output Block
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%int = OpTypeInt 32 1
%int_3 = OpConstant %int 3
%array = OpTypeArray %float %int_3
%Output = OpTypeStruct %array
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with ArrayStride decorations"));
}
TEST_F(ValidateDecorations, BufferBlockMissingArrayStrideBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output BufferBlock
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%int = OpTypeInt 32 1
%int_3 = OpConstant %int 3
%array = OpTypeArray %float %int_3
%Output = OpTypeStruct %array
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with ArrayStride decorations"));
}
TEST_F(ValidateDecorations, BlockNestedStructMissingArrayStrideBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int = OpTypeInt 32 1
%int_3 = OpConstant %int 3
%array = OpTypeArray %float %int_3
%S = OpTypeStruct %array
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with ArrayStride decorations"));
}
TEST_F(ValidateDecorations, BufferBlockNestedStructMissingArrayStrideBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output BufferBlock
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int = OpTypeInt 32 1
%int_3 = OpConstant %int 3
%array = OpTypeArray %float %int_3
%S = OpTypeStruct %array
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with ArrayStride decorations"));
}
TEST_F(ValidateDecorations, BlockMissingMatrixStrideBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output Block
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%matrix = OpTypeMatrix %v3float 4
%Output = OpTypeStruct %matrix
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with MatrixStride decorations"));
}
TEST_F(ValidateDecorations, BufferBlockMissingMatrixStrideBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output BufferBlock
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%matrix = OpTypeMatrix %v3float 4
%Output = OpTypeStruct %matrix
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with MatrixStride decorations"));
}
TEST_F(ValidateDecorations, BlockMissingMatrixStrideArrayBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output Block
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%matrix = OpTypeMatrix %v3float 4
%int = OpTypeInt 32 1
%int_3 = OpConstant %int 3
%array = OpTypeArray %matrix %int_3
%Output = OpTypeStruct %matrix
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with MatrixStride decorations"));
}
TEST_F(ValidateDecorations, BufferBlockMissingMatrixStrideArrayBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpDecorate %Output BufferBlock
OpMemberDecorate %Output 0 Offset 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%matrix = OpTypeMatrix %v3float 4
%int = OpTypeInt 32 1
%int_3 = OpConstant %int 3
%array = OpTypeArray %matrix %int_3
%Output = OpTypeStruct %matrix
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with MatrixStride decorations"));
}
TEST_F(ValidateDecorations, BlockNestedStructMissingMatrixStrideBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%v4float = OpTypeVector %float 4
%matrix = OpTypeMatrix %v3float 4
%S = OpTypeStruct %matrix
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with MatrixStride decorations"));
}
TEST_F(ValidateDecorations, BufferBlockNestedStructMissingMatrixStrideBad) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 16
OpMemberDecorate %Output 2 Offset 32
OpDecorate %Output BufferBlock
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%v4float = OpTypeVector %float 4
%matrix = OpTypeMatrix %v3float 4
%S = OpTypeStruct %matrix
%Output = OpTypeStruct %float %v4float %S
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("must be explicitly laid out with MatrixStride decorations"));
}
TEST_F(ValidateDecorations, BlockStandardUniformBufferLayout) {
std::string spirv = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 430
OpMemberDecorate %F 0 Offset 0
OpMemberDecorate %F 1 Offset 8
OpDecorate %_arr_float_uint_2 ArrayStride 16
OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
OpMemberDecorate %O 0 Offset 0
OpMemberDecorate %O 1 Offset 16
OpMemberDecorate %O 2 Offset 32
OpMemberDecorate %O 3 Offset 64
OpMemberDecorate %O 4 ColMajor
OpMemberDecorate %O 4 Offset 80
OpMemberDecorate %O 4 MatrixStride 16
OpDecorate %_arr_O_uint_2 ArrayStride 176
OpMemberDecorate %Output 0 Offset 0
OpMemberDecorate %Output 1 Offset 8
OpMemberDecorate %Output 2 Offset 16
OpMemberDecorate %Output 3 Offset 32
OpMemberDecorate %Output 4 Offset 48
OpMemberDecorate %Output 5 Offset 64
OpMemberDecorate %Output 6 ColMajor
OpMemberDecorate %Output 6 Offset 96
OpMemberDecorate %Output 6 MatrixStride 16
OpMemberDecorate %Output 7 Offset 128
OpDecorate %Output Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%v3float = OpTypeVector %float 3
%int = OpTypeInt 32 1
%uint = OpTypeInt 32 0
%v2uint = OpTypeVector %uint 2
%F = OpTypeStruct %int %v2uint
%uint_2 = OpConstant %uint 2
%_arr_float_uint_2 = OpTypeArray %float %uint_2
%mat2v3float = OpTypeMatrix %v3float 2
%v3uint = OpTypeVector %uint 3
%mat3v3float = OpTypeMatrix %v3float 3
%_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
%O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
%_arr_O_uint_2 = OpTypeArray %O %uint_2
%Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
%_ptr_Uniform_Output = OpTypePointer Uniform %Output
%dataOutput = OpVariable %_ptr_Uniform_Output Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
}
TEST_F(ValidateDecorations, BlockLayoutPermitsTightVec3ScalarPackingGood) {
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 12
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%S = OpTypeStruct %v3float %float
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0))
<< getDiagnosticString();
}
TEST_F(ValidateDecorations, BlockCantAppearWithinABlockBad) {
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 16
OpMemberDecorate %S2 0 Offset 0
OpMemberDecorate %S2 1 Offset 12
OpDecorate %S Block
OpDecorate %S2 Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%S2 = OpTypeStruct %float %float
%S = OpTypeStruct %float %S2
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("rules: A Block or BufferBlock cannot be nested within "
"another Block or BufferBlock."));
}
TEST_F(ValidateDecorations, BufferblockCantAppearWithinABufferblockBad) {
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 16
OpMemberDecorate %S2 0 Offset 0
OpMemberDecorate %S2 1 Offset 16
OpMemberDecorate %S3 0 Offset 0
OpMemberDecorate %S3 1 Offset 12
OpDecorate %S BufferBlock
OpDecorate %S3 BufferBlock
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%S3 = OpTypeStruct %float %float
%S2 = OpTypeStruct %float %S3
%S = OpTypeStruct %float %S2
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("rules: A Block or BufferBlock cannot be nested within "
"another Block or BufferBlock."));
}
TEST_F(ValidateDecorations, BufferblockCantAppearWithinABlockBad) {
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 16
OpMemberDecorate %S2 0 Offset 0
OpMemberDecorate %S2 1 Offset 16
OpMemberDecorate %S3 0 Offset 0
OpMemberDecorate %S3 1 Offset 12
OpDecorate %S Block
OpDecorate %S3 BufferBlock
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%S3 = OpTypeStruct %float %float
%S2 = OpTypeStruct %float %S3
%S = OpTypeStruct %float %S2
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("rules: A Block or BufferBlock cannot be nested within "
"another Block or BufferBlock."));
}
TEST_F(ValidateDecorations, BlockCantAppearWithinABufferblockBad) {
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 16
OpMemberDecorate %S2 0 Offset 0
OpMemberDecorate %S2 1 Offset 16
OpMemberDecorate %S3 0 Offset 0
OpMemberDecorate %S3 1 Offset 16
OpMemberDecorate %S4 0 Offset 0
OpMemberDecorate %S4 1 Offset 12
OpDecorate %S BufferBlock
OpDecorate %S4 Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%S4 = OpTypeStruct %float %float
%S3 = OpTypeStruct %float %S4
%S2 = OpTypeStruct %float %S3
%S = OpTypeStruct %float %S2
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("rules: A Block or BufferBlock cannot be nested within "
"another Block or BufferBlock."));
}
TEST_F(ValidateDecorations, BlockLayoutForbidsTightScalarVec3PackingBad) {
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%S = OpTypeStruct %float %v3float
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Structure id 2 decorated as Block for variable in Uniform "
"storage class must follow standard uniform buffer layout "
"rules: member 1 at offset 4 is not aligned to 16"));
}
TEST_F(ValidateDecorations,
BlockLayoutPermitsTightScalarVec3PackingWithRelaxedLayoutGood) {
// Same as previous test, but with explicit option to relax block layout.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%S = OpTypeStruct %float %v3float
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations,
BlockLayoutPermitsTightScalarVec3PackingBadOffsetWithRelaxedLayoutBad) {
// Same as previous test, but with the vector not aligned to its scalar
// element. Use offset 5 instead of a multiple of 4.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 5
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%S = OpTypeStruct %float %v3float
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"Structure id 2 decorated as Block for variable in Uniform storage "
"class must follow relaxed uniform buffer layout rules: member 1 at "
"offset 5 is not aligned to scalar element size 4"));
}
TEST_F(ValidateDecorations,
BlockLayoutPermitsTightScalarVec3PackingWithVulkan1_1Good) {
// Same as previous test, but with Vulkan 1.1. Vulkan 1.1 included
// VK_KHR_relaxed_block_layout in core.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%S = OpTypeStruct %float %v3float
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations,
BlockLayoutPermitsTightScalarVec3PackingWithScalarLayoutGood) {
// Same as previous test, but with scalar block layout.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%S = OpTypeStruct %float %v3float
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations,
BlockLayoutPermitsScalarAlignedArrayWithScalarLayoutGood) {
// The array at offset 4 is ok with scalar block layout.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
OpDecorate %arr_float ArrayStride 4
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%float = OpTypeFloat 32
%arr_float = OpTypeArray %float %uint_3
%S = OpTypeStruct %float %arr_float
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations,
BlockLayoutPermitsScalarAlignedArrayOfVec3WithScalarLayoutGood) {
// The array at offset 4 is ok with scalar block layout, even though
// its elements are vec3.
// This is the same as the previous case, but the array elements are vec3
// instead of float.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
OpDecorate %arr_vec3 ArrayStride 12
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%float = OpTypeFloat 32
%vec3 = OpTypeVector %float 3
%arr_vec3 = OpTypeArray %vec3 %uint_3
%S = OpTypeStruct %float %arr_vec3
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations,
BlockLayoutPermitsScalarAlignedStructWithScalarLayoutGood) {
// Scalar block layout permits the struct at offset 4, even though
// it contains a vector with base alignment 8 and scalar alignment 4.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpMemberDecorate %st 0 Offset 0
OpMemberDecorate %st 1 Offset 8
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%vec2 = OpTypeVector %float 2
%st = OpTypeStruct %vec2 %float
%S = OpTypeStruct %float %st
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(
ValidateDecorations,
BlockLayoutPermitsFieldsInBaseAlignmentPaddingAtEndOfStructWithScalarLayoutGood) {
// Scalar block layout permits fields in what would normally be the padding at
// the end of a struct.
std::string spirv = R"(
OpCapability Shader
OpCapability Float64
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %st 0 Offset 0
OpMemberDecorate %st 1 Offset 8
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 12
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%double = OpTypeFloat 64
%st = OpTypeStruct %double %float
%S = OpTypeStruct %st %float
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(
ValidateDecorations,
BlockLayoutPermitsStraddlingVectorWithScalarLayoutOverrideRelaxBlockLayoutGood) {
// Same as previous, but set relaxed block layout first. Scalar layout always
// wins.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%vec4 = OpTypeVector %float 4
%S = OpTypeStruct %float %vec4
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(
ValidateDecorations,
BlockLayoutPermitsStraddlingVectorWithRelaxedLayoutOverridenByScalarBlockLayoutGood) {
// Same as previous, but set scalar block layout first. Scalar layout always
// wins.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %S Block
OpDecorate %B DescriptorSet 0
OpDecorate %B Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%vec4 = OpTypeVector %float 4
%S = OpTypeStruct %float %vec4
%_ptr_Uniform_S = OpTypePointer Uniform %S
%B = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(), Eq(""));
}
TEST_F(ValidateDecorations, BufferBlock16bitStandardStorageBufferLayout) {
std::string spirv = R"(
OpCapability Shader
OpCapability StorageUniform16
OpExtension "SPV_KHR_16bit_storage"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpDecorate %f32arr ArrayStride 4
OpDecorate %f16arr ArrayStride 2
OpMemberDecorate %SSBO32 0 Offset 0
OpMemberDecorate %SSBO16 0 Offset 0
OpDecorate %SSBO32 BufferBlock
OpDecorate %SSBO16 BufferBlock
%void = OpTypeVoid
%voidf = OpTypeFunction %void
%u32 = OpTypeInt 32 0
%i32 = OpTypeInt 32 1
%f32 = OpTypeFloat 32
%uvec3 = OpTypeVector %u32 3
%c_i32_32 = OpConstant %i32 32
%c_i32_128 = OpConstant %i32 128
%f32arr = OpTypeArray %f32 %c_i32_128
%f16 = OpTypeFloat 16
%f16arr = OpTypeArray %f16 %c_i32_128
%SSBO32 = OpTypeStruct %f32arr
%SSBO16 = OpTypeStruct %f16arr
%_ptr_Uniform_SSBO32 = OpTypePointer Uniform %SSBO32
%varSSBO32 = OpVariable %_ptr_Uniform_SSBO32 Uniform
%_ptr_Uniform_SSBO16 = OpTypePointer Uniform %SSBO16
%varSSBO16 = OpVariable %_ptr_Uniform_SSBO16 Uniform
%main = OpFunction %void None %voidf
%label = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
}
TEST_F(ValidateDecorations, BlockArrayExtendedAlignmentGood) {
// For uniform buffer, Array base alignment is 16, and ArrayStride
// must be a multiple of 16.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpDecorate %_arr_float_uint_2 ArrayStride 16
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 16
OpDecorate %S Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%_arr_float_uint_2 = OpTypeArray %float %uint_2
%S = OpTypeStruct %v2float %_arr_float_uint_2
%_ptr_PushConstant_S = OpTypePointer PushConstant %S
%u = OpVariable %_ptr_PushConstant_S PushConstant
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
<< getDiagnosticString();
}
TEST_F(ValidateDecorations, BlockArrayBaseAlignmentBad) {
// For uniform buffer, Array base alignment is 16.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpDecorate %_arr_float_uint_2 ArrayStride 16
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 8
OpDecorate %S Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%_arr_float_uint_2 = OpTypeArray %float %uint_2
%S = OpTypeStruct %v2float %_arr_float_uint_2
%_ptr_Uniform_S = OpTypePointer Uniform %S
%u = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"Structure id 3 decorated as Block for variable in Uniform "
"storage class must follow standard uniform buffer layout rules: "
"member 1 at offset 8 is not aligned to 16"));
}
TEST_F(ValidateDecorations, BlockArrayBaseAlignmentWithRelaxedLayoutStillBad) {
// For uniform buffer, Array base alignment is 16, and ArrayStride
// must be a multiple of 16. This case uses relaxed block layout. Relaxed
// layout only relaxes rules for vector alignment, not array alignment.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpDecorate %_arr_float_uint_2 ArrayStride 16
OpDecorate %u DescriptorSet 0
OpDecorate %u Binding 0
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 8
OpDecorate %S Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%_arr_float_uint_2 = OpTypeArray %float %uint_2
%S = OpTypeStruct %v2float %_arr_float_uint_2
%_ptr_Uniform_S = OpTypePointer Uniform %S
%u = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"Structure id 4 decorated as Block for variable in Uniform "
"storage class must follow standard uniform buffer layout rules: "
"member 1 at offset 8 is not aligned to 16"));
}
TEST_F(ValidateDecorations, BlockArrayBaseAlignmentWithVulkan1_1StillBad) {
// Same as previous test, but with Vulkan 1.1, which includes
// VK_KHR_relaxed_block_layout in core.
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpDecorate %_arr_float_uint_2 ArrayStride 16
OpDecorate %u DescriptorSet 0
OpDecorate %u Binding 0
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 8
OpDecorate %S Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%_arr_float_uint_2 = OpTypeArray %float %uint_2
%S = OpTypeStruct %v2float %_arr_float_uint_2
%_ptr_Uniform_S = OpTypePointer Uniform %S
%u = OpVariable %_ptr_Uniform_S Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"Structure id 4 decorated as Block for variable in Uniform "
"storage class must follow relaxed uniform buffer layout rules: "
"member 1 at offset 8 is not aligned to 16"));
}
TEST_F(ValidateDecorations,
BlockArrayBaseAlignmentWithBlockStandardLayoutGood) {
// Same as previous test, but with VK_KHR_uniform_buffer_standard_layout
std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 450
OpDecorate %_arr_float_uint_2 ArrayStride 16
OpDecorate %u DescriptorSet 0
OpDecorate %u Binding 0
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 8
OpDecorate %S Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2