mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-20 12:00:05 +00:00
c94501352d
A std::set is used instead of std::vector, where the elements are ordered by member index first. Decorations for fields are now looked up by going over the range of decorations for the member only, instead of the whole set. In an ANGLE test that generates a struct with 4096 members, validation goes down from ~140ms to ~90ms. On debug builds, the difference is more pronounced, going down from ~2.5s to ~600ms.
8369 lines
293 KiB
C++
8369 lines
293 KiB
C++
// 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/test_fixture.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 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 ArrayStride 4
|
|
OpDecorate %1 RelaxedPrecision
|
|
%2 = OpTypeFloat 32
|
|
%1 = OpTypeRuntimeArray %2
|
|
; 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(SpvDecorationArrayStride, {4}),
|
|
Decoration(SpvDecorationRelaxedPrecision)}));
|
|
}
|
|
|
|
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(SpvDecorationArrayStride, {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(SpvDecorationNonReadable, {}, 2),
|
|
Decoration(SpvDecorationOffset, {2}, 2),
|
|
Decoration(SpvDecorationBufferBlock)}));
|
|
}
|
|
|
|
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(SpvDecorationDescriptorSet, {0}),
|
|
Decoration(SpvDecorationRelaxedPrecision),
|
|
Decoration(SpvDecorationRestrict)};
|
|
|
|
// 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(SpvDecorationOffset, {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());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must not use GLSLShared decoration"));
|
|
}
|
|
|
|
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());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must not use GLSLShared decoration"));
|
|
}
|
|
|
|
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());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must not use GLSLShared decoration"));
|
|
}
|
|
|
|
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());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must not use GLSLShared decoration"));
|
|
}
|
|
|
|
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());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must not use GLSLPacked decoration"));
|
|
}
|
|
|
|
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());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must not use GLSLPacked decoration"));
|
|
}
|
|
|
|
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());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must not use GLSLPacked decoration"));
|
|
}
|
|
|
|
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());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must not use GLSLPacked decoration"));
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
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())
|
|
<< 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());
|
|
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());
|
|
}
|
|
|
|
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());
|
|
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
|
|
%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);
|
|
spvValidatorOptionsSetUniformBufferStandardLayout(getValidatorOptions(),
|
|
true);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanBufferBlockOnStorageBufferBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct BufferBlock
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr StorageBuffer
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-PushConstant-06675"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("In Vulkan, BufferBlock is disallowed on variables in "
|
|
"the StorageBuffer storage class"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PushConstantArrayBaseAlignmentGood) {
|
|
// Tests https://github.com/KhronosGroup/SPIRV-Tools/issues/1664
|
|
// From GLSL vertex shader:
|
|
// #version 450
|
|
// layout(push_constant) uniform S { vec2 v; float arr[2]; } u;
|
|
// void main() { }
|
|
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource GLSL 450
|
|
OpDecorate %_arr_float_uint_2 ArrayStride 4
|
|
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_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, PushConstantArrayBadAlignmentBad) {
|
|
// Like the previous test, but with offset 7 instead of 8.
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource GLSL 450
|
|
OpDecorate %_arr_float_uint_2 ArrayStride 4
|
|
OpMemberDecorate %S 0 Offset 0
|
|
OpMemberDecorate %S 1 Offset 7
|
|
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_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 3 decorated as Block for variable in PushConstant "
|
|
"storage class must follow standard storage buffer layout rules: "
|
|
"member 1 at offset 7 is not aligned to 4"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
PushConstantLayoutPermitsTightVec3ScalarPackingGood) {
|
|
// 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
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v3float = OpTypeVector %float 3
|
|
%S = OpTypeStruct %v3float %float
|
|
%_ptr_PushConstant_S = OpTypePointer PushConstant %S
|
|
%B = 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,
|
|
PushConstantLayoutForbidsTightScalarVec3PackingBad) {
|
|
// 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
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v3float = OpTypeVector %float 3
|
|
%S = OpTypeStruct %float %v3float
|
|
%_ptr_Uniform_S = OpTypePointer PushConstant %S
|
|
%B = OpVariable %_ptr_Uniform_S PushConstant
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 2 decorated as Block for variable in PushConstant "
|
|
"storage class must follow standard storage buffer layout "
|
|
"rules: member 1 at offset 4 is not aligned to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PushConstantMissingBlockGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer PushConstant %struct
|
|
%pc = OpVariable %ptr PushConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanPushConstantMissingBlockBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer PushConstant %struct
|
|
%pc = OpVariable %ptr PushConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-PushConstant-06675"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("PushConstant id '2' is missing Block decoration.\n"
|
|
"From Vulkan spec:\n"
|
|
"Such variables must be identified with a Block "
|
|
"decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, MultiplePushConstantsSingleEntryPointGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer PushConstant %struct
|
|
%ptr_float = OpTypePointer PushConstant %float
|
|
%pc1 = OpVariable %ptr PushConstant
|
|
%pc2 = OpVariable %ptr PushConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%2 = OpAccessChain %ptr_float %pc1 %int_0
|
|
%3 = OpLoad %float %2
|
|
%4 = OpAccessChain %ptr_float %pc2 %int_0
|
|
%5 = OpLoad %float %4
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
VulkanMultiplePushConstantsDifferentEntryPointGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "func1"
|
|
OpEntryPoint Fragment %2 "func2"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer PushConstant %struct
|
|
%ptr_float = OpTypePointer PushConstant %float
|
|
%pc1 = OpVariable %ptr PushConstant
|
|
%pc2 = OpVariable %ptr PushConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label1 = OpLabel
|
|
%3 = OpAccessChain %ptr_float %pc1 %int_0
|
|
%4 = OpLoad %float %3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
%2 = OpFunction %void None %voidfn
|
|
%label2 = OpLabel
|
|
%5 = OpAccessChain %ptr_float %pc2 %int_0
|
|
%6 = OpLoad %float %5
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
VulkanMultiplePushConstantsUnusedSingleEntryPointGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer PushConstant %struct
|
|
%ptr_float = OpTypePointer PushConstant %float
|
|
%pc1 = OpVariable %ptr PushConstant
|
|
%pc2 = OpVariable %ptr PushConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanMultiplePushConstantsSingleEntryPointBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer PushConstant %struct
|
|
%ptr_float = OpTypePointer PushConstant %float
|
|
%pc1 = OpVariable %ptr PushConstant
|
|
%pc2 = OpVariable %ptr PushConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%2 = OpAccessChain %ptr_float %pc1 %int_0
|
|
%3 = OpLoad %float %2
|
|
%4 = OpAccessChain %ptr_float %pc2 %int_0
|
|
%5 = OpLoad %float %4
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-06674"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Entry point id '1' uses more than one PushConstant interface.\n"
|
|
"From Vulkan spec:\n"
|
|
"There must be no more than one push constant block "
|
|
"statically used per shader entry point."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "func1"
|
|
OpEntryPoint Fragment %2 "func2"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer PushConstant %struct
|
|
%ptr_float = OpTypePointer PushConstant %float
|
|
%pc1 = OpVariable %ptr PushConstant
|
|
%pc2 = OpVariable %ptr PushConstant
|
|
|
|
%sub1 = OpFunction %void None %voidfn
|
|
%label_sub1 = OpLabel
|
|
%3 = OpAccessChain %ptr_float %pc1 %int_0
|
|
%4 = OpLoad %float %3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
%sub2 = OpFunction %void None %voidfn
|
|
%label_sub2 = OpLabel
|
|
%5 = OpAccessChain %ptr_float %pc2 %int_0
|
|
%6 = OpLoad %float %5
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label1 = OpLabel
|
|
%call1 = OpFunctionCall %void %sub1
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
%2 = OpFunction %void None %voidfn
|
|
%label2 = OpLabel
|
|
%call2 = OpFunctionCall %void %sub2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer PushConstant %struct
|
|
%ptr_float = OpTypePointer PushConstant %float
|
|
%pc1 = OpVariable %ptr PushConstant
|
|
%pc2 = OpVariable %ptr PushConstant
|
|
|
|
%sub1 = OpFunction %void None %voidfn
|
|
%label_sub1 = OpLabel
|
|
%3 = OpAccessChain %ptr_float %pc1 %int_0
|
|
%4 = OpLoad %float %3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
%sub2 = OpFunction %void None %voidfn
|
|
%label_sub2 = OpLabel
|
|
%5 = OpAccessChain %ptr_float %pc2 %int_0
|
|
%6 = OpLoad %float %5
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label1 = OpLabel
|
|
%call1 = OpFunctionCall %void %sub1
|
|
%call2 = OpFunctionCall %void %sub2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-06674"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Entry point id '1' uses more than one PushConstant interface.\n"
|
|
"From Vulkan spec:\n"
|
|
"There must be no more than one push constant block "
|
|
"statically used per shader entry point."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformMissingDescriptorSetBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %var Binding 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer Uniform %struct
|
|
%ptr_float = OpTypePointer Uniform %float
|
|
%var = OpVariable %ptr Uniform
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%2 = OpAccessChain %ptr_float %var %int_0
|
|
%3 = OpLoad %float %2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-UniformConstant-06677"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Uniform id '3' is missing DescriptorSet decoration.\n"
|
|
"From Vulkan spec:\n"
|
|
"These variables must have DescriptorSet and Binding "
|
|
"decorations specified"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformMissingBindingBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %var DescriptorSet 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer Uniform %struct
|
|
%ptr_float = OpTypePointer Uniform %float
|
|
%var = OpVariable %ptr Uniform
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%2 = OpAccessChain %ptr_float %var %int_0
|
|
%3 = OpLoad %float %2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-UniformConstant-06677"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Uniform id '3' is missing Binding decoration.\n"
|
|
"From Vulkan spec:\n"
|
|
"These variables must have DescriptorSet and Binding "
|
|
"decorations specified"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformConstantMissingDescriptorSetBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %var Binding 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%sampler = OpTypeSampler
|
|
%ptr = OpTypePointer UniformConstant %sampler
|
|
%var = OpVariable %ptr UniformConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%2 = OpLoad %sampler %var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-UniformConstant-06677"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("UniformConstant id '2' is missing DescriptorSet decoration.\n"
|
|
"From Vulkan spec:\n"
|
|
"These variables must have DescriptorSet and Binding "
|
|
"decorations specified"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformConstantMissingBindingBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %var DescriptorSet 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%sampler = OpTypeSampler
|
|
%ptr = OpTypePointer UniformConstant %sampler
|
|
%var = OpVariable %ptr UniformConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%2 = OpLoad %sampler %var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-UniformConstant-06677"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("UniformConstant id '2' is missing Binding decoration.\n"
|
|
"From Vulkan spec:\n"
|
|
"These variables must have DescriptorSet and Binding "
|
|
"decorations specified"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanStorageBufferMissingDescriptorSetBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpDecorate %var Binding 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr StorageBuffer
|
|
%ptr_float = OpTypePointer StorageBuffer %float
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%2 = OpAccessChain %ptr_float %var %int_0
|
|
%3 = OpLoad %float %2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-UniformConstant-06677"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n"
|
|
"From Vulkan spec:\n"
|
|
"These variables must have DescriptorSet and Binding "
|
|
"decorations specified"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanStorageBufferMissingBindingBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpDecorate %var DescriptorSet 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr StorageBuffer
|
|
%ptr_float = OpTypePointer StorageBuffer %float
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%2 = OpAccessChain %ptr_float %var %int_0
|
|
%3 = OpLoad %float %2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-UniformConstant-06677"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("StorageBuffer id '3' is missing Binding decoration.\n"
|
|
"From Vulkan spec:\n"
|
|
"These variables must have DescriptorSet and Binding "
|
|
"decorations specified"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
VulkanStorageBufferMissingDescriptorSetSubFunctionBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpDecorate %var Binding 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr StorageBuffer
|
|
%ptr_float = OpTypePointer StorageBuffer %float
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
%call = OpFunctionCall %void %2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%2 = OpFunction %void None %voidfn
|
|
%label2 = OpLabel
|
|
%3 = OpAccessChain %ptr_float %var %int_0
|
|
%4 = OpLoad %float %3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-UniformConstant-06677"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n"
|
|
"From Vulkan spec:\n"
|
|
"These variables must have DescriptorSet and Binding "
|
|
"decorations specified"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
VulkanStorageBufferMissingDescriptorAndBindingUnusedGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr StorageBuffer
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformMissingDescriptorSetGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %var Binding 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer Uniform %struct
|
|
%var = OpVariable %ptr Uniform
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformMissingBindingGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %var DescriptorSet 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer Uniform %struct
|
|
%var = OpVariable %ptr Uniform
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformConstantMissingDescriptorSetGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %var Binding 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%sampler = OpTypeSampler
|
|
%ptr = OpTypePointer UniformConstant %sampler
|
|
%var = OpVariable %ptr UniformConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformConstantMissingBindingGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %var DescriptorSet 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%sampler = OpTypeSampler
|
|
%ptr = OpTypePointer UniformConstant %sampler
|
|
%var = OpVariable %ptr UniformConstant
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, StorageBufferMissingDescriptorSetGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct BufferBlock
|
|
OpDecorate %var Binding 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr StorageBuffer
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, StorageBufferMissingBindingGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct BufferBlock
|
|
OpDecorate %var DescriptorSet 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
%ptr = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr StorageBuffer
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBaseAlignmentGood) {
|
|
// Spot check buffer rules when using StorageBuffer storage class with Block
|
|
// decoration.
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource GLSL 450
|
|
OpDecorate %_arr_float_uint_2 ArrayStride 4
|
|
OpMemberDecorate %S 0 Offset 0
|
|
OpMemberDecorate %S 1 Offset 8
|
|
OpDecorate %S Block
|
|
OpDecorate %u DescriptorSet 0
|
|
OpDecorate %u Binding 0
|
|
%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 StorageBuffer %S
|
|
%u = OpVariable %_ptr_Uniform_S StorageBuffer
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBadAlignmentBad) {
|
|
// Like the previous test, but with offset 7.
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource GLSL 450
|
|
OpDecorate %_arr_float_uint_2 ArrayStride 4
|
|
OpMemberDecorate %S 0 Offset 0
|
|
OpMemberDecorate %S 1 Offset 7
|
|
OpDecorate %S Block
|
|
OpDecorate %u DescriptorSet 0
|
|
OpDecorate %u Binding 0
|
|
%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 StorageBuffer %S
|
|
%u = OpVariable %_ptr_Uniform_S StorageBuffer
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 3 decorated as Block for variable in StorageBuffer "
|
|
"storage class must follow standard storage buffer layout rules: "
|
|
"member 1 at offset 7 is not aligned to 4"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BufferBlockStandardStorageBufferLayout) {
|
|
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 4
|
|
OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
|
|
OpMemberDecorate %O 0 Offset 0
|
|
OpMemberDecorate %O 1 Offset 16
|
|
OpMemberDecorate %O 2 Offset 24
|
|
OpMemberDecorate %O 3 Offset 32
|
|
OpMemberDecorate %O 4 ColMajor
|
|
OpMemberDecorate %O 4 Offset 48
|
|
OpMemberDecorate %O 4 MatrixStride 16
|
|
OpDecorate %_arr_O_uint_2 ArrayStride 144
|
|
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 52
|
|
OpMemberDecorate %Output 6 ColMajor
|
|
OpMemberDecorate %Output 6 Offset 64
|
|
OpMemberDecorate %Output 6 MatrixStride 16
|
|
OpMemberDecorate %Output 7 Offset 96
|
|
OpDecorate %Output BufferBlock
|
|
%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());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
StorageBufferLayoutPermitsTightVec3ScalarPackingGood) {
|
|
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
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_StorageBuffer_S = OpTypePointer StorageBuffer %S
|
|
%B = OpVariable %_ptr_StorageBuffer_S StorageBuffer
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
StorageBufferLayoutForbidsTightScalarVec3PackingBad) {
|
|
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
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_StorageBuffer_S = OpTypePointer StorageBuffer %S
|
|
%B = OpVariable %_ptr_StorageBuffer_S StorageBuffer
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 2 decorated as Block for variable in StorageBuffer "
|
|
"storage class must follow standard storage buffer layout "
|
|
"rules: member 1 at offset 4 is not aligned to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
BlockStandardUniformBufferLayoutIncorrectOffset0Bad) {
|
|
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 24
|
|
OpMemberDecorate %O 3 Offset 33
|
|
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_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Structure id 6 decorated as Block for variable in Uniform "
|
|
"storage class must follow standard uniform buffer layout "
|
|
"rules: member 2 at offset 152 is not aligned to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
BlockStandardUniformBufferLayoutIncorrectOffset1Bad) {
|
|
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 71
|
|
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_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Structure id 8 decorated as Block for variable in Uniform "
|
|
"storage class must follow standard uniform buffer layout "
|
|
"rules: member 5 at offset 71 is not aligned to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BlockUniformBufferLayoutIncorrectArrayStrideBad) {
|
|
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 49
|
|
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_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 6 decorated as Block for variable in Uniform storage "
|
|
"class must follow standard uniform buffer layout rules: member 4 "
|
|
"contains "
|
|
"an array with stride 49 not satisfying alignment to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
BufferBlockStandardStorageBufferLayoutImproperStraddleBad) {
|
|
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 %Output 0 Offset 0
|
|
OpMemberDecorate %Output 1 Offset 8
|
|
OpDecorate %Output BufferBlock
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v3float = OpTypeVector %float 3
|
|
%Output = OpTypeStruct %float %v3float
|
|
%_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("Structure id 3 decorated as BufferBlock for variable in "
|
|
"Uniform storage class must follow standard storage buffer "
|
|
"layout rules: member 1 at offset 8 is not aligned to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
BlockUniformBufferLayoutOffsetInsideArrayPaddingBad) {
|
|
// In this case the 2nd member fits entirely within the padding.
|
|
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 %_arr_float_uint_2 ArrayStride 16
|
|
OpMemberDecorate %Output 0 Offset 0
|
|
OpMemberDecorate %Output 1 Offset 20
|
|
OpDecorate %Output Block
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%uint = OpTypeInt 32 0
|
|
%v2uint = OpTypeVector %uint 2
|
|
%uint_2 = OpConstant %uint 2
|
|
%_arr_float_uint_2 = OpTypeArray %float %uint_2
|
|
%Output = OpTypeStruct %_arr_float_uint_2 %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(
|
|
"Structure id 4 decorated as Block for variable in Uniform storage "
|
|
"class must follow standard uniform buffer layout rules: member 1 at "
|
|
"offset 20 overlaps previous member ending at offset 31"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
BlockUniformBufferLayoutOffsetInsideStructPaddingBad) {
|
|
// In this case the 2nd member fits entirely within the padding.
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %1 "main"
|
|
OpMemberDecorate %_struct_6 0 Offset 0
|
|
OpMemberDecorate %_struct_2 0 Offset 0
|
|
OpMemberDecorate %_struct_2 1 Offset 4
|
|
OpDecorate %_struct_2 Block
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%_struct_6 = OpTypeStruct %float
|
|
%_struct_2 = OpTypeStruct %_struct_6 %float
|
|
%_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
|
|
%8 = OpVariable %_ptr_Uniform__struct_2 Uniform
|
|
%1 = OpFunction %void None %4
|
|
%9 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
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 4 overlaps previous member ending at offset 15"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodUniversal1_0) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpMemberDecorate %Outer 0 Offset 4
|
|
OpMemberDecorate %Outer 1 Offset 0
|
|
OpDecorate %Outer Block
|
|
OpDecorate %O DescriptorSet 0
|
|
OpDecorate %O Binding 0
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%uint = OpTypeInt 32 0
|
|
%Outer = OpTypeStruct %uint %uint
|
|
%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
|
|
%O = OpVariable %_ptr_Uniform_Outer Uniform
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_0));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodOpenGL4_5) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpMemberDecorate %Outer 0 Offset 4
|
|
OpMemberDecorate %Outer 1 Offset 0
|
|
OpDecorate %Outer Block
|
|
OpDecorate %O DescriptorSet 0
|
|
OpDecorate %O Binding 0
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%uint = OpTypeInt 32 0
|
|
%Outer = OpTypeStruct %uint %uint
|
|
%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
|
|
%O = OpVariable %_ptr_Uniform_Outer Uniform
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_OPENGL_4_5));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodVulkan1_1) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpMemberDecorate %Outer 0 Offset 4
|
|
OpMemberDecorate %Outer 1 Offset 0
|
|
OpDecorate %Outer Block
|
|
OpDecorate %O DescriptorSet 0
|
|
OpDecorate %O Binding 0
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%uint = OpTypeInt 32 0
|
|
%Outer = OpTypeStruct %uint %uint
|
|
%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
|
|
%O = OpVariable %_ptr_Uniform_Outer Uniform
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
|
|
<< getDiagnosticString();
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BlockLayoutOffsetOverlapBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpMemberDecorate %Outer 0 Offset 0
|
|
OpMemberDecorate %Outer 1 Offset 16
|
|
OpMemberDecorate %Inner 0 Offset 0
|
|
OpMemberDecorate %Inner 1 Offset 16
|
|
OpDecorate %Outer Block
|
|
OpDecorate %O DescriptorSet 0
|
|
OpDecorate %O Binding 0
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%uint = OpTypeInt 32 0
|
|
%Inner = OpTypeStruct %uint %uint
|
|
%Outer = OpTypeStruct %Inner %uint
|
|
%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
|
|
%O = OpVariable %_ptr_Uniform_Outer Uniform
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
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 16 overlaps previous member ending at offset 31"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BufferBlockEmptyStruct) {
|
|
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 %Output 0 Offset 0
|
|
OpDecorate %Output BufferBlock
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%S = OpTypeStruct
|
|
%Output = OpTypeStruct %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_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, RowMajorMatrixTightPackingGood) {
|
|
// Row major matrix rule:
|
|
// A row-major matrix of C columns has a base alignment equal to
|
|
// the base alignment of a vector of C matrix components.
|
|
// Note: The "matrix component" is the scalar element type.
|
|
|
|
// The matrix has 3 columns and 2 rows (C=3, R=2).
|
|
// So the base alignment of b is the same as a vector of 3 floats, which is 16
|
|
// bytes. The matrix consists of two of these, and therefore occupies 2 x 16
|
|
// bytes, or 32 bytes.
|
|
//
|
|
// So the offsets can be:
|
|
// a -> 0
|
|
// b -> 16
|
|
// c -> 48
|
|
// d -> 60 ; d fits at bytes 12-15 after offset of c. Tight (vec3;float)
|
|
// packing
|
|
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "main"
|
|
OpSource GLSL 450
|
|
OpMemberDecorate %_struct_2 0 Offset 0
|
|
OpMemberDecorate %_struct_2 1 RowMajor
|
|
OpMemberDecorate %_struct_2 1 Offset 16
|
|
OpMemberDecorate %_struct_2 1 MatrixStride 16
|
|
OpMemberDecorate %_struct_2 2 Offset 48
|
|
OpMemberDecorate %_struct_2 3 Offset 60
|
|
OpDecorate %_struct_2 Block
|
|
OpDecorate %3 DescriptorSet 0
|
|
OpDecorate %3 Binding 0
|
|
%void = OpTypeVoid
|
|
%5 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%v2float = OpTypeVector %float 2
|
|
%mat3v2float = OpTypeMatrix %v2float 3
|
|
%v3float = OpTypeVector %float 3
|
|
%_struct_2 = OpTypeStruct %v4float %mat3v2float %v3float %float
|
|
%_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
|
|
%3 = OpVariable %_ptr_Uniform__struct_2 Uniform
|
|
%1 = OpFunction %void None %5
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ArrayArrayRowMajorMatrixTightPackingGood) {
|
|
// Like the previous case, but we have an array of arrays of matrices.
|
|
// The RowMajor decoration goes on the struct member (surprisingly).
|
|
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "main"
|
|
OpSource GLSL 450
|
|
OpMemberDecorate %_struct_2 0 Offset 0
|
|
OpMemberDecorate %_struct_2 1 RowMajor
|
|
OpMemberDecorate %_struct_2 1 Offset 16
|
|
OpMemberDecorate %_struct_2 1 MatrixStride 16
|
|
OpMemberDecorate %_struct_2 2 Offset 80
|
|
OpMemberDecorate %_struct_2 3 Offset 92
|
|
OpDecorate %arr_mat ArrayStride 32
|
|
OpDecorate %arr_arr_mat ArrayStride 32
|
|
OpDecorate %_struct_2 Block
|
|
OpDecorate %3 DescriptorSet 0
|
|
OpDecorate %3 Binding 0
|
|
%void = OpTypeVoid
|
|
%5 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%v2float = OpTypeVector %float 2
|
|
%mat3v2float = OpTypeMatrix %v2float 3
|
|
%uint = OpTypeInt 32 0
|
|
%uint_1 = OpConstant %uint 1
|
|
%uint_2 = OpConstant %uint 2
|
|
%arr_mat = OpTypeArray %mat3v2float %uint_1
|
|
%arr_arr_mat = OpTypeArray %arr_mat %uint_2
|
|
%v3float = OpTypeVector %float 3
|
|
%_struct_2 = OpTypeStruct %v4float %arr_arr_mat %v3float %float
|
|
%_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
|
|
%3 = OpVariable %_ptr_Uniform__struct_2 Uniform
|
|
%1 = OpFunction %void None %5
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ArrayArrayRowMajorMatrixNextMemberOverlapsBad) {
|
|
// Like the previous case, but the offset of member 2 overlaps the matrix.
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "main"
|
|
OpSource GLSL 450
|
|
OpMemberDecorate %_struct_2 0 Offset 0
|
|
OpMemberDecorate %_struct_2 1 RowMajor
|
|
OpMemberDecorate %_struct_2 1 Offset 16
|
|
OpMemberDecorate %_struct_2 1 MatrixStride 16
|
|
OpMemberDecorate %_struct_2 2 Offset 64
|
|
OpMemberDecorate %_struct_2 3 Offset 92
|
|
OpDecorate %arr_mat ArrayStride 32
|
|
OpDecorate %arr_arr_mat ArrayStride 32
|
|
OpDecorate %_struct_2 Block
|
|
OpDecorate %3 DescriptorSet 0
|
|
OpDecorate %3 Binding 0
|
|
%void = OpTypeVoid
|
|
%5 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%v2float = OpTypeVector %float 2
|
|
%mat3v2float = OpTypeMatrix %v2float 3
|
|
%uint = OpTypeInt 32 0
|
|
%uint_1 = OpConstant %uint 1
|
|
%uint_2 = OpConstant %uint 2
|
|
%arr_mat = OpTypeArray %mat3v2float %uint_1
|
|
%arr_arr_mat = OpTypeArray %arr_mat %uint_2
|
|
%v3float = OpTypeVector %float 3
|
|
%_struct_2 = OpTypeStruct %v4float %arr_arr_mat %v3float %float
|
|
%_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
|
|
%3 = OpVariable %_ptr_Uniform__struct_2 Uniform
|
|
%1 = OpFunction %void None %5
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 2 decorated as Block for variable in Uniform storage "
|
|
"class must follow standard uniform buffer layout rules: member 2 at "
|
|
"offset 64 overlaps previous member ending at offset 79"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackGood) {
|
|
// Original GLSL
|
|
|
|
// #version 450
|
|
// layout (set=0,binding=0) buffer S {
|
|
// uvec3 arr[2][2]; // first 3 elements are 16 bytes, last is 12
|
|
// uint i; // Can have offset 60 = 3x16 + 12
|
|
// } B;
|
|
// void main() {}
|
|
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "main"
|
|
OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
|
|
OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
|
|
OpMemberDecorate %_struct_4 0 Offset 0
|
|
OpMemberDecorate %_struct_4 1 Offset 60
|
|
OpDecorate %_struct_4 BufferBlock
|
|
OpDecorate %5 DescriptorSet 0
|
|
OpDecorate %5 Binding 0
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%uint = OpTypeInt 32 0
|
|
%v3uint = OpTypeVector %uint 3
|
|
%uint_2 = OpConstant %uint 2
|
|
%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
|
|
%_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
|
|
%_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
|
|
%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
|
|
%5 = OpVariable %_ptr_Uniform__struct_4 Uniform
|
|
%1 = OpFunction %void None %7
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackBad) {
|
|
// Like previous but, the offset of the second member is too small.
|
|
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "main"
|
|
OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
|
|
OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
|
|
OpMemberDecorate %_struct_4 0 Offset 0
|
|
OpMemberDecorate %_struct_4 1 Offset 56
|
|
OpDecorate %_struct_4 BufferBlock
|
|
OpDecorate %5 DescriptorSet 0
|
|
OpDecorate %5 Binding 0
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%uint = OpTypeInt 32 0
|
|
%v3uint = OpTypeVector %uint 3
|
|
%uint_2 = OpConstant %uint 2
|
|
%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
|
|
%_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
|
|
%_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
|
|
%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
|
|
%5 = OpVariable %_ptr_Uniform__struct_4 Uniform
|
|
%1 = OpFunction %void None %7
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Structure id 4 decorated as BufferBlock for variable "
|
|
"in Uniform storage class must follow standard storage "
|
|
"buffer layout rules: member 1 at offset 56 overlaps "
|
|
"previous member ending at offset 59"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackGood) {
|
|
// Like the corresponding buffer block case, but the array padding must
|
|
// count for the last element as well, and so the offset of the second
|
|
// member must be at least 64.
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "main"
|
|
OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
|
|
OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
|
|
OpMemberDecorate %_struct_4 0 Offset 0
|
|
OpMemberDecorate %_struct_4 1 Offset 64
|
|
OpDecorate %_struct_4 Block
|
|
OpDecorate %5 DescriptorSet 0
|
|
OpDecorate %5 Binding 0
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%uint = OpTypeInt 32 0
|
|
%v3uint = OpTypeVector %uint 3
|
|
%uint_2 = OpConstant %uint 2
|
|
%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
|
|
%_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
|
|
%_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
|
|
%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
|
|
%5 = OpVariable %_ptr_Uniform__struct_4 Uniform
|
|
%1 = OpFunction %void None %7
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackBad) {
|
|
// Like previous but, the offset of the second member is too small.
|
|
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %1 "main"
|
|
OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
|
|
OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
|
|
OpMemberDecorate %_struct_4 0 Offset 0
|
|
OpMemberDecorate %_struct_4 1 Offset 60
|
|
OpDecorate %_struct_4 Block
|
|
OpDecorate %5 DescriptorSet 0
|
|
OpDecorate %5 Binding 0
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%uint = OpTypeInt 32 0
|
|
%v3uint = OpTypeVector %uint 3
|
|
%uint_2 = OpConstant %uint 2
|
|
%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
|
|
%_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
|
|
%_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
|
|
%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
|
|
%5 = OpVariable %_ptr_Uniform__struct_4 Uniform
|
|
%1 = OpFunction %void None %7
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
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 60 overlaps previous member ending at offset 63"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, LayoutNotCheckedWhenSkipBlockLayout) {
|
|
// Checks that block layout is not verified in skipping block layout mode.
|
|
// Even for obviously wrong layout.
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource GLSL 450
|
|
OpMemberDecorate %S 0 Offset 3 ; wrong alignment
|
|
OpMemberDecorate %S 1 Offset 3 ; same offset as before!
|
|
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);
|
|
spvValidatorOptionsSetSkipBlockLayout(getValidatorOptions(), true);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, EntryPointVariableWrongStorageClass) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "func" %var
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%ptr_int_Workgroup = OpTypePointer Workgroup %int
|
|
%var = OpVariable %ptr_int_Workgroup Workgroup
|
|
%func_ty = OpTypeFunction %void
|
|
%1 = OpFunction %void None %func_ty
|
|
%2 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("OpEntryPoint interfaces must be OpVariables with "
|
|
"Storage Class of Input(1) or Output(3). Found Storage "
|
|
"Class 4 for Entry Point id 1."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanMemoryModelNonCoherent) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VulkanMemoryModelKHR
|
|
OpCapability Linkage
|
|
OpExtension "SPV_KHR_vulkan_memory_model"
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical VulkanKHR
|
|
OpDecorate %1 Coherent
|
|
%2 = OpTypeInt 32 0
|
|
%3 = OpTypePointer StorageBuffer %2
|
|
%1 = OpVariable %3 StorageBuffer
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Coherent decoration targeting 1[%1] is "
|
|
"banned when using the Vulkan memory model."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanMemoryModelNoCoherentMember) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VulkanMemoryModelKHR
|
|
OpCapability Linkage
|
|
OpExtension "SPV_KHR_vulkan_memory_model"
|
|
OpMemoryModel Logical VulkanKHR
|
|
OpMemberDecorate %1 0 Coherent
|
|
%2 = OpTypeInt 32 0
|
|
%1 = OpTypeStruct %2 %2
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Coherent decoration targeting 1[%_struct_1] (member index 0) "
|
|
"is banned when using the Vulkan memory model."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatile) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VulkanMemoryModelKHR
|
|
OpCapability Linkage
|
|
OpExtension "SPV_KHR_vulkan_memory_model"
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical VulkanKHR
|
|
OpDecorate %1 Volatile
|
|
%2 = OpTypeInt 32 0
|
|
%3 = OpTypePointer StorageBuffer %2
|
|
%1 = OpVariable %3 StorageBuffer
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Volatile decoration targeting 1[%1] is banned when "
|
|
"using the Vulkan memory model."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatileMember) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VulkanMemoryModelKHR
|
|
OpCapability Linkage
|
|
OpExtension "SPV_KHR_vulkan_memory_model"
|
|
OpMemoryModel Logical VulkanKHR
|
|
OpMemberDecorate %1 1 Volatile
|
|
%2 = OpTypeInt 32 0
|
|
%1 = OpTypeStruct %2 %2
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Volatile decoration targeting 1[%_struct_1] (member "
|
|
"index 1) is banned when using the Vulkan memory "
|
|
"model."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FPRoundingModeGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
%half = OpTypeFloat 16
|
|
%float = OpTypeFloat 32
|
|
%float_1_25 = OpConstant %float 1.25
|
|
%half_ptr = OpTypePointer StorageBuffer %half
|
|
%half_ptr_var = OpVariable %half_ptr StorageBuffer
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%_ = OpFConvert %half %float_1_25
|
|
OpStore %half_ptr_var %_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FPRoundingModeVectorGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
%half = OpTypeFloat 16
|
|
%float = OpTypeFloat 32
|
|
%v2half = OpTypeVector %half 2
|
|
%v2float = OpTypeVector %float 2
|
|
%float_1_25 = OpConstant %float 1.25
|
|
%floats = OpConstantComposite %v2float %float_1_25 %float_1_25
|
|
%halfs_ptr = OpTypePointer StorageBuffer %v2half
|
|
%halfs_ptr_var = OpVariable %halfs_ptr StorageBuffer
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%_ = OpFConvert %v2half %floats
|
|
OpStore %halfs_ptr_var %_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FPRoundingModeNotOpFConvert) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
%short = OpTypeInt 16 1
|
|
%int = OpTypeInt 32 1
|
|
%int_17 = OpConstant %int 17
|
|
%short_ptr = OpTypePointer StorageBuffer %short
|
|
%short_ptr_var = OpVariable %short_ptr StorageBuffer
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%_ = OpSConvert %short %int_17
|
|
OpStore %short_ptr_var %_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("FPRoundingMode decoration can be applied only to a "
|
|
"width-only conversion instruction for floating-point "
|
|
"object."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FPRoundingModeNoOpStoreGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
%half = OpTypeFloat 16
|
|
%float = OpTypeFloat 32
|
|
%float_1_25 = OpConstant %float 1.25
|
|
%half_ptr = OpTypePointer StorageBuffer %half
|
|
%half_ptr_var = OpVariable %half_ptr StorageBuffer
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%_ = OpFConvert %half %float_1_25
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FPRoundingModeFConvert64to16Good) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpCapability Float64
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
%half = OpTypeFloat 16
|
|
%double = OpTypeFloat 64
|
|
%double_1_25 = OpConstant %double 1.25
|
|
%half_ptr = OpTypePointer StorageBuffer %half
|
|
%half_ptr_var = OpVariable %half_ptr StorageBuffer
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%_ = OpFConvert %half %double_1_25
|
|
OpStore %half_ptr_var %_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FPRoundingModeNotStoreInFloat16) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpCapability Float64
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
%float = OpTypeFloat 32
|
|
%double = OpTypeFloat 64
|
|
%double_1_25 = OpConstant %double 1.25
|
|
%float_ptr = OpTypePointer StorageBuffer %float
|
|
%float_ptr_var = OpVariable %float_ptr StorageBuffer
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%_ = OpFConvert %float %double_1_25
|
|
OpStore %float_ptr_var %_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("FPRoundingMode decoration can be applied only to the "
|
|
"Object operand of an OpStore storing through a "
|
|
"pointer to a 16-bit floating-point scalar or vector object."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
%half = OpTypeFloat 16
|
|
%float = OpTypeFloat 32
|
|
%float_1_25 = OpConstant %float 1.25
|
|
%half_ptr = OpTypePointer StorageBuffer %half
|
|
%half_ptr_var_0 = OpVariable %half_ptr StorageBuffer
|
|
%half_ptr_var_1 = OpVariable %half_ptr StorageBuffer
|
|
%half_ptr_var_2 = OpVariable %half_ptr StorageBuffer
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%_ = OpFConvert %half %float_1_25
|
|
OpStore %half_ptr_var_0 %_
|
|
OpStore %half_ptr_var_1 %_
|
|
OpStore %half_ptr_var_2 %_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FPRoundingModeMultipleUsesBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
%half = OpTypeFloat 16
|
|
%float = OpTypeFloat 32
|
|
%float_1_25 = OpConstant %float 1.25
|
|
%half_ptr = OpTypePointer StorageBuffer %half
|
|
%half_ptr_var_0 = OpVariable %half_ptr StorageBuffer
|
|
%half_ptr_var_1 = OpVariable %half_ptr StorageBuffer
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%_ = OpFConvert %half %float_1_25
|
|
OpStore %half_ptr_var_0 %_
|
|
%result = OpFAdd %half %_ %_
|
|
OpStore %half_ptr_var_1 %_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("FPRoundingMode decoration can be applied only to the "
|
|
"Object operand of an OpStore."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanFPRoundingModeGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability StorageBuffer16BitAccess
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpMemberDecorate %ssbo 0 Offset 0
|
|
OpDecorate %ssbo Block
|
|
OpDecorate %_ DescriptorSet 0
|
|
OpDecorate %_ Binding 0
|
|
OpDecorate %17 FPRoundingMode RTE
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%float_1 = OpConstant %float 1
|
|
%half = OpTypeFloat 16
|
|
%ssbo = OpTypeStruct %half
|
|
%_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo
|
|
%_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%b = OpVariable %_ptr_Function_float Function
|
|
OpStore %b %float_1
|
|
%16 = OpLoad %float %b
|
|
%17 = OpFConvert %half %16
|
|
%19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0
|
|
OpStore %19 %17
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanFPRoundingModeBadMode) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability StorageBuffer16BitAccess
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpMemberDecorate %ssbo 0 Offset 0
|
|
OpDecorate %ssbo Block
|
|
OpDecorate %_ DescriptorSet 0
|
|
OpDecorate %_ Binding 0
|
|
OpDecorate %17 FPRoundingMode RTP
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%float_1 = OpConstant %float 1
|
|
%half = OpTypeFloat 16
|
|
%ssbo = OpTypeStruct %half
|
|
%_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo
|
|
%_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%b = OpVariable %_ptr_Function_float Function
|
|
OpStore %b %float_1
|
|
%16 = OpLoad %float %b
|
|
%17 = OpFConvert %half %16
|
|
%19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0
|
|
OpStore %19 %17
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-FPRoundingMode-04675"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("In Vulkan, the FPRoundingMode mode must only by RTE or RTZ."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
%1 = OpDecorationGroup
|
|
OpGroupDecorate %1 %1
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("OpGroupDecorate may not target OpDecorationGroup <id> "
|
|
"'1[%1]'"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup2) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
%1 = OpDecorationGroup
|
|
OpGroupDecorate %1 %2 %1
|
|
%2 = OpTypeVoid
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("OpGroupDecorate may not target OpDecorationGroup <id> "
|
|
"'1[%1]'"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, RecurseThroughRuntimeArray) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %outer Block
|
|
OpMemberDecorate %inner 0 Offset 0
|
|
OpMemberDecorate %inner 1 Offset 1
|
|
OpDecorate %runtime ArrayStride 16
|
|
OpMemberDecorate %outer 0 Offset 0
|
|
%int = OpTypeInt 32 0
|
|
%inner = OpTypeStruct %int %int
|
|
%runtime = OpTypeRuntimeArray %inner
|
|
%outer = OpTypeStruct %runtime
|
|
%outer_ptr = OpTypePointer Uniform %outer
|
|
%var = OpVariable %outer_ptr Uniform
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
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 1 is not aligned to 4"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, EmptyStructAtNonZeroOffsetGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 1 Offset 16
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%empty = OpTypeStruct
|
|
%struct = OpTypeStruct %float %empty
|
|
%ptr_struct_ubo = OpTypePointer Uniform %struct
|
|
%var = OpVariable %ptr_struct_ubo Uniform
|
|
%voidfn = OpTypeFunction %void
|
|
%main = OpFunction %void None %voidfn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
// Uniform and UniformId decorations
|
|
|
|
TEST_F(ValidateDecorations, UniformDecorationGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical Simple
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %int0 Uniform
|
|
OpDecorate %var Uniform
|
|
OpDecorate %val Uniform
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 1
|
|
%int0 = OpConstantNull %int
|
|
%intptr = OpTypePointer Private %int
|
|
%var = OpVariable %intptr Private
|
|
%fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %fn
|
|
%entry = OpLabel
|
|
%val = OpLoad %int %var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
// Returns SPIR-V assembly for a shader that uses a given decoration
|
|
// instruction.
|
|
std::string ShaderWithUniformLikeDecoration(const std::string& inst) {
|
|
return std::string(R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical Simple
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpName %subgroupscope "subgroupscope"
|
|
OpName %call "call"
|
|
OpName %myfunc "myfunc"
|
|
OpName %int0 "int0"
|
|
OpName %float0 "float0"
|
|
OpName %fn "fn"
|
|
)") + inst +
|
|
R"(
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 1
|
|
%int0 = OpConstantNull %int
|
|
%int_99 = OpConstant %int 99
|
|
%subgroupscope = OpConstant %int 3
|
|
%float0 = OpConstantNull %float
|
|
%fn = OpTypeFunction %void
|
|
%myfunc = OpFunction %void None %fn
|
|
%myfuncentry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%main = OpFunction %void None %fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall %void %myfunc
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV13Bad) {
|
|
const std::string spirv = ShaderWithUniformLikeDecoration(
|
|
"OpDecorateId %int0 UniformId %subgroupscope");
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("requires SPIR-V version 1.4 or later\n"
|
|
" OpDecorateId %int0 UniformId %subgroupscope"))
|
|
<< spirv;
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV13BadTargetV14) {
|
|
const std::string spirv = ShaderWithUniformLikeDecoration(
|
|
"OpDecorateId %int0 UniformId %subgroupscope");
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("requires SPIR-V version 1.4 or later"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV14Good) {
|
|
const std::string spirv = ShaderWithUniformLikeDecoration(
|
|
"OpDecorateId %int0 UniformId %subgroupscope");
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformDecorationTargetsTypeBad) {
|
|
const std::string spirv =
|
|
ShaderWithUniformLikeDecoration("OpDecorate %fn Uniform");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Uniform decoration applied to a non-object"));
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("%fn = OpTypeFunction %void"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformIdDecorationTargetsTypeBad) {
|
|
const std::string spirv = ShaderWithUniformLikeDecoration(
|
|
"OpDecorateId %fn UniformId %subgroupscope");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("UniformId decoration applied to a non-object"));
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("%fn = OpTypeFunction %void"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformDecorationTargetsVoidValueBad) {
|
|
const std::string spirv =
|
|
ShaderWithUniformLikeDecoration("OpDecorate %call Uniform");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Uniform decoration applied to a value with void type\n"
|
|
" %call = OpFunctionCall %void %myfunc"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformIdDecorationTargetsVoidValueBad) {
|
|
const std::string spirv = ShaderWithUniformLikeDecoration(
|
|
"OpDecorateId %call UniformId %subgroupscope");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4))
|
|
<< spirv;
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("UniformId decoration applied to a value with void type\n"
|
|
" %call = OpFunctionCall %void %myfunc"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
UniformDecorationWithScopeIdV14IdIsFloatValueIsBad) {
|
|
const std::string spirv =
|
|
ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %float0");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("ConstantNull: expected scope to be a 32-bit int"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations,
|
|
UniformDecorationWithScopeIdV14IdIsInvalidIntValueBad) {
|
|
const std::string spirv =
|
|
ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %int_99");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Invalid scope value:\n %int_99 = OpConstant %int 99\n"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformDecorationWithScopeIdV14VulkanEnv) {
|
|
const std::string spirv =
|
|
ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %int0");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1_SPIRV_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-None-04636"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr(": in Vulkan environment Execution Scope is limited to "
|
|
"Workgroup and Subgroup"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformDecorationWithWrongInstructionBad) {
|
|
const std::string spirv =
|
|
ShaderWithUniformLikeDecoration("OpDecorateId %int0 Uniform");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Decorations that don't take ID parameters may not be "
|
|
"used with OpDecorateId\n"
|
|
" OpDecorateId %int0 Uniform"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, UniformIdDecorationWithWrongInstructionBad) {
|
|
const std::string spirv = ShaderWithUniformLikeDecoration(
|
|
"OpDecorate %int0 UniformId %subgroupscope");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Decorations taking ID parameters may not be used with OpDecorateId\n"
|
|
" OpDecorate %int0 UniformId %subgroupscope"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, MultipleOffsetDecorationsOnSameID) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("ID '2', member '0' decorated with Offset multiple "
|
|
"times is not allowed."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, MultipleArrayStrideDecorationsOnSameID) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %array ArrayStride 4
|
|
OpDecorate %array ArrayStride 4
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%uint = OpTypeInt 32 0
|
|
%uint_4 = OpConstant %uint 4
|
|
%array = OpTypeArray %float %uint_4
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("ID '2' decorated with ArrayStride multiple "
|
|
"times is not allowed."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, MultipleMatrixStrideDecorationsOnSameID) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 0 ColMajor
|
|
OpMemberDecorate %struct 0 MatrixStride 16
|
|
OpMemberDecorate %struct 0 MatrixStride 16
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%fvec4 = OpTypeVector %float 4
|
|
%fmat4 = OpTypeMatrix %fvec4 4
|
|
%struct = OpTypeStruct %fmat4
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("ID '2', member '0' decorated with MatrixStride "
|
|
"multiple times is not allowed."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, MultipleRowMajorDecorationsOnSameID) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 0 MatrixStride 16
|
|
OpMemberDecorate %struct 0 RowMajor
|
|
OpMemberDecorate %struct 0 RowMajor
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%fvec4 = OpTypeVector %float 4
|
|
%fmat4 = OpTypeMatrix %fvec4 4
|
|
%struct = OpTypeStruct %fmat4
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("ID '2', member '0' decorated with RowMajor multiple "
|
|
"times is not allowed."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, MultipleColMajorDecorationsOnSameID) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 0 MatrixStride 16
|
|
OpMemberDecorate %struct 0 ColMajor
|
|
OpMemberDecorate %struct 0 ColMajor
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%fvec4 = OpTypeVector %float 4
|
|
%fmat4 = OpTypeMatrix %fvec4 4
|
|
%struct = OpTypeStruct %fmat4
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("ID '2', member '0' decorated with ColMajor multiple "
|
|
"times is not allowed."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, RowMajorAndColMajorDecorationsOnSameID) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 0 MatrixStride 16
|
|
OpMemberDecorate %struct 0 ColMajor
|
|
OpMemberDecorate %struct 0 RowMajor
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%fvec4 = OpTypeVector %float 4
|
|
%fmat4 = OpTypeMatrix %fvec4 4
|
|
%struct = OpTypeStruct %fmat4
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("ID '2', member '0' decorated with both RowMajor and "
|
|
"ColMajor is not allowed."));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
|
|
OpDecorate %struct Block
|
|
OpDecorate %struct BufferBlock
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 0 MatrixStride 16
|
|
OpMemberDecorate %struct 0 RowMajor
|
|
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%fvec4 = OpTypeVector %float 4
|
|
%fmat4 = OpTypeMatrix %fvec4 4
|
|
%struct = OpTypeStruct %fmat4
|
|
|
|
%1 = OpFunction %void None %voidfn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"ID '2' decorated with both BufferBlock and Block is not allowed."));
|
|
}
|
|
|
|
std::string MakeIntegerShader(
|
|
const std::string& decoration, const std::string& inst,
|
|
const std::string& extension =
|
|
"OpExtension \"SPV_KHR_no_integer_wrap_decoration\"") {
|
|
return R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
)" + extension +
|
|
R"(
|
|
%glsl = OpExtInstImport "GLSL.std.450"
|
|
%opencl = OpExtInstImport "OpenCL.std"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpName %entry "entry"
|
|
)" + decoration +
|
|
R"(
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%zero = OpConstantNull %int
|
|
%float = OpTypeFloat 32
|
|
%float0 = OpConstantNull %float
|
|
%main = OpFunction %void None %voidfn
|
|
%entry = OpLabel
|
|
)" + inst +
|
|
R"(
|
|
OpReturn
|
|
OpFunctionEnd)";
|
|
}
|
|
|
|
// NoSignedWrap
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapOnTypeBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %void NoSignedWrap", "");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("NoSignedWrap decoration may not be applied to TypeVoid"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapOnLabelBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %entry NoSignedWrap", "");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("NoSignedWrap decoration may not be applied to Label"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpIAdd %int %zero %zero", "");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("requires one of these extensions: "
|
|
"SPV_KHR_no_integer_wrap_decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionV13Bad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpIAdd %int %zero %zero", "");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("requires one of these extensions: "
|
|
"SPV_KHR_no_integer_wrap_decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapOkInSPV14Good) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpIAdd %int %zero %zero", "");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapIAddGood) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpIAdd %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapISubGood) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpISub %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapIMulGood) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpIMul %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapShiftLeftLogicalGood) {
|
|
std::string spirv =
|
|
MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpShiftLeftLogical %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapSNegateGood) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpSNegate %int %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapSRemBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpSRem %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("NoSignedWrap decoration may not be applied to SRem"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapFAddBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpFAdd %float %float0 %float0");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("NoSignedWrap decoration may not be applied to FAdd"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapExtInstOpenCLGood) {
|
|
std::string spirv =
|
|
MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
|
"%val = OpExtInst %int %opencl s_abs %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoSignedWrapExtInstGLSLGood) {
|
|
std::string spirv = MakeIntegerShader(
|
|
"OpDecorate %val NoSignedWrap", "%val = OpExtInst %int %glsl SAbs %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
// TODO(dneto): For NoSignedWrap and NoUnsignedWrap, permit
|
|
// "OpExtInst for instruction numbers specified in the extended
|
|
// instruction-set specifications as accepting this decoration."
|
|
|
|
// NoUnignedWrap
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapOnTypeBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %void NoUnsignedWrap", "");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("NoUnsignedWrap decoration may not be applied to TypeVoid"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapOnLabelBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %entry NoUnsignedWrap", "");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("NoUnsignedWrap decoration may not be applied to Label"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpIAdd %int %zero %zero", "");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("requires one of these extensions: "
|
|
"SPV_KHR_no_integer_wrap_decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionV13Bad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpIAdd %int %zero %zero", "");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("requires one of these extensions: "
|
|
"SPV_KHR_no_integer_wrap_decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapOkInSPV14Good) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpIAdd %int %zero %zero", "");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapIAddGood) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpIAdd %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapISubGood) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpISub %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapIMulGood) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpIMul %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapShiftLeftLogicalGood) {
|
|
std::string spirv =
|
|
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpShiftLeftLogical %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapSNegateGood) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpSNegate %int %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapSRemBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpSRem %int %zero %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("NoUnsignedWrap decoration may not be applied to SRem"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapFAddBad) {
|
|
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpFAdd %float %float0 %float0");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("NoUnsignedWrap decoration may not be applied to FAdd"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapExtInstOpenCLGood) {
|
|
std::string spirv =
|
|
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpExtInst %int %opencl s_abs %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NoUnsignedWrapExtInstGLSLGood) {
|
|
std::string spirv =
|
|
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
|
"%val = OpExtInst %int %glsl SAbs %zero");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, AliasedandRestrictBad) {
|
|
const std::string body = 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 %Output 0 Offset 0
|
|
OpDecorate %Output BufferBlock
|
|
OpDecorate %dataOutput Restrict
|
|
OpDecorate %dataOutput Aliased
|
|
%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(body.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("decorated with both Aliased and Restrict is not allowed"));
|
|
}
|
|
|
|
// TODO(dneto): For NoUnsignedWrap and NoUnsignedWrap, permit
|
|
// "OpExtInst for instruction numbers specified in the extended
|
|
// instruction-set specifications as accepting this decoration."
|
|
|
|
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) {
|
|
const std::string body = R"(
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
OpCapability Int64
|
|
OpCapability Shader
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpDecorate %val1 RestrictPointer
|
|
%uint64 = OpTypeInt 64 0
|
|
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
|
|
%pptr_f = OpTypePointer Function %ptr
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%main = OpFunction %void None %voidfn
|
|
%entry = OpLabel
|
|
%val1 = OpVariable %pptr_f Function
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(body.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerMissing) {
|
|
const std::string body = R"(
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
OpCapability Int64
|
|
OpCapability Shader
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%uint64 = OpTypeInt 64 0
|
|
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
|
|
%pptr_f = OpTypePointer Function %ptr
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%main = OpFunction %void None %voidfn
|
|
%entry = OpLabel
|
|
%val1 = OpVariable %pptr_f Function
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(body.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("expected AliasedPointer or RestrictPointer for "
|
|
"PhysicalStorageBuffer pointer"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerBoth) {
|
|
const std::string body = R"(
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
OpCapability Int64
|
|
OpCapability Shader
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpDecorate %val1 RestrictPointer
|
|
OpDecorate %val1 AliasedPointer
|
|
%uint64 = OpTypeInt 64 0
|
|
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
|
|
%pptr_f = OpTypePointer Function %ptr
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%main = OpFunction %void None %voidfn
|
|
%entry = OpLabel
|
|
%val1 = OpVariable %pptr_f Function
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(body.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("can't specify both AliasedPointer and RestrictPointer "
|
|
"for PhysicalStorageBuffer pointer"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamSuccess) {
|
|
const std::string body = R"(
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
OpCapability Int64
|
|
OpCapability Shader
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpDecorate %fparam Restrict
|
|
%uint64 = OpTypeInt 64 0
|
|
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%fnptr = OpTypeFunction %void %ptr
|
|
%main = OpFunction %void None %voidfn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%fn = OpFunction %void None %fnptr
|
|
%fparam = OpFunctionParameter %ptr
|
|
%lab = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(body.c_str());
|
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamMissing) {
|
|
const std::string body = R"(
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
OpCapability Int64
|
|
OpCapability Shader
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%uint64 = OpTypeInt 64 0
|
|
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%fnptr = OpTypeFunction %void %ptr
|
|
%main = OpFunction %void None %voidfn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%fn = OpFunction %void None %fnptr
|
|
%fparam = OpFunctionParameter %ptr
|
|
%lab = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(body.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("expected Aliased or Restrict for "
|
|
"PhysicalStorageBuffer pointer"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) {
|
|
const std::string body = R"(
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
OpCapability Int64
|
|
OpCapability Shader
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpDecorate %fparam Restrict
|
|
OpDecorate %fparam Aliased
|
|
%uint64 = OpTypeInt 64 0
|
|
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
|
|
%void = OpTypeVoid
|
|
%voidfn = OpTypeFunction %void
|
|
%fnptr = OpTypeFunction %void %ptr
|
|
%main = OpFunction %void None %voidfn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%fn = OpFunction %void None %fnptr
|
|
%fparam = OpFunctionParameter %ptr
|
|
%lab = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(body.c_str());
|
|
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("can't specify both Aliased and Restrict for "
|
|
"PhysicalStorageBuffer pointer"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PSBFPRoundingModeSuccess) {
|
|
std::string spirv = R"(
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability StorageBuffer16BitAccess
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_KHR_variable_pointers"
|
|
OpExtension "SPV_KHR_16bit_storage"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %_ FPRoundingMode RTE
|
|
OpDecorate %half_ptr_var AliasedPointer
|
|
%half = OpTypeFloat 16
|
|
%float = OpTypeFloat 32
|
|
%float_1_25 = OpConstant %float 1.25
|
|
%half_ptr = OpTypePointer PhysicalStorageBuffer %half
|
|
%half_pptr_f = OpTypePointer Function %half_ptr
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%main = OpFunction %void None %func
|
|
%main_entry = OpLabel
|
|
%half_ptr_var = OpVariable %half_pptr_f Function
|
|
%val1 = OpLoad %half_ptr %half_ptr_var
|
|
%_ = OpFConvert %half %float_1_25
|
|
OpStore %val1 %_ Aligned 2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, InvalidStraddle) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpMemberDecorate %inner_struct 0 Offset 0
|
|
OpMemberDecorate %inner_struct 1 Offset 4
|
|
OpDecorate %outer_struct Block
|
|
OpMemberDecorate %outer_struct 0 Offset 0
|
|
OpMemberDecorate %outer_struct 1 Offset 8
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%float2 = OpTypeVector %float 2
|
|
%inner_struct = OpTypeStruct %float %float2
|
|
%outer_struct = OpTypeStruct %float2 %inner_struct
|
|
%ptr_ssbo_outer = OpTypePointer StorageBuffer %outer_struct
|
|
%var = OpVariable %ptr_ssbo_outer StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Structure id 2 decorated as Block for variable in "
|
|
"StorageBuffer storage class must follow relaxed "
|
|
"storage buffer layout rules: member 1 is an "
|
|
"improperly straddling vector at offset 12"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, DescriptorArray) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 1 Offset 1
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%int_2 = OpConstant %int 2
|
|
%float2 = OpTypeVector %float 2
|
|
%struct = OpTypeStruct %float %float2
|
|
%struct_array = OpTypeArray %struct %int_2
|
|
%ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array
|
|
%var = OpVariable %ptr_ssbo_array StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Structure id 2 decorated as Block for variable in "
|
|
"StorageBuffer storage class must follow standard "
|
|
"storage buffer layout rules: member 1 at offset 1 is "
|
|
"not aligned to 8"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, DescriptorRuntimeArray) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability RuntimeDescriptorArrayEXT
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpExtension "SPV_EXT_descriptor_indexing"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpMemberDecorate %struct 1 Offset 1
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%float2 = OpTypeVector %float 2
|
|
%struct = OpTypeStruct %float %float2
|
|
%struct_array = OpTypeRuntimeArray %struct
|
|
%ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array
|
|
%var = OpVariable %ptr_ssbo_array StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Structure id 2 decorated as Block for variable in "
|
|
"StorageBuffer storage class must follow standard "
|
|
"storage buffer layout rules: member 1 at offset 1 is "
|
|
"not aligned to 8"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, MultiDimensionalArray) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %array_4 ArrayStride 4
|
|
OpDecorate %array_3 ArrayStride 48
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_3 = OpConstant %int 3
|
|
%int_4 = OpConstant %int 4
|
|
%array_4 = OpTypeArray %int %int_4
|
|
%array_3 = OpTypeArray %array_4 %int_3
|
|
%struct = OpTypeStruct %array_3
|
|
%ptr_struct = OpTypePointer Uniform %struct
|
|
%var = OpVariable %ptr_struct Uniform
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(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 0 contains an array with "
|
|
"stride 4 not satisfying alignment to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ImproperStraddleInArray) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %array ArrayStride 24
|
|
OpMemberDecorate %inner 0 Offset 0
|
|
OpMemberDecorate %inner 1 Offset 4
|
|
OpMemberDecorate %inner 2 Offset 12
|
|
OpMemberDecorate %inner 3 Offset 16
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_2 = OpConstant %int 2
|
|
%int2 = OpTypeVector %int 2
|
|
%inner = OpTypeStruct %int %int2 %int %int
|
|
%array = OpTypeArray %inner %int_2
|
|
%struct = OpTypeStruct %array
|
|
%ptr_struct = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr_struct StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Structure id 4 decorated as Block for variable in "
|
|
"StorageBuffer storage class must follow relaxed "
|
|
"storage buffer layout rules: member 1 is an "
|
|
"improperly straddling vector at offset 28"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, LargeArray) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %array ArrayStride 24
|
|
OpMemberDecorate %inner 0 Offset 0
|
|
OpMemberDecorate %inner 1 Offset 8
|
|
OpMemberDecorate %inner 2 Offset 16
|
|
OpMemberDecorate %inner 3 Offset 20
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_2000000 = OpConstant %int 2000000
|
|
%int2 = OpTypeVector %int 2
|
|
%inner = OpTypeStruct %int %int2 %int %int
|
|
%array = OpTypeArray %inner %int_2000000
|
|
%struct = OpTypeStruct %array
|
|
%ptr_struct = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr_struct StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
|
}
|
|
|
|
// NonWritable
|
|
|
|
// Returns a SPIR-V shader module with variables in various storage classes,
|
|
// parameterizable by which ID should be decorated as NonWritable.
|
|
std::string ShaderWithNonWritableTarget(const std::string& target,
|
|
bool member_decorate = false) {
|
|
const std::string decoration_inst =
|
|
std::string(member_decorate ? "OpMemberDecorate " : "OpDecorate ") +
|
|
target + (member_decorate ? " 0" : "");
|
|
|
|
return std::string(R"(
|
|
OpCapability Shader
|
|
OpCapability RuntimeDescriptorArrayEXT
|
|
OpExtension "SPV_EXT_descriptor_indexing"
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpName %label "label"
|
|
OpName %param_f "param_f"
|
|
OpName %param_p "param_p"
|
|
OpName %_ptr_imstor "_ptr_imstor"
|
|
OpName %_ptr_imsam "_ptr_imsam"
|
|
OpName %var_wg "var_wg"
|
|
OpName %var_imsam "var_imsam"
|
|
OpName %var_priv "var_priv"
|
|
OpName %var_func "var_func"
|
|
OpName %simple_struct "simple_struct"
|
|
|
|
OpDecorate %struct_b Block
|
|
OpDecorate %struct_b_rtarr Block
|
|
OpMemberDecorate %struct_b 0 Offset 0
|
|
OpMemberDecorate %struct_b_rtarr 0 Offset 0
|
|
OpDecorate %rtarr ArrayStride 4
|
|
)") + decoration_inst +
|
|
|
|
R"( NonWritable
|
|
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%float_0 = OpConstant %float 0
|
|
%int = OpTypeInt 32 0
|
|
%int_2 = OpConstant %int 2
|
|
%struct_b = OpTypeStruct %float
|
|
%rtarr = OpTypeRuntimeArray %float
|
|
%struct_b_rtarr = OpTypeStruct %rtarr
|
|
%simple_struct = OpTypeStruct %float
|
|
; storage image
|
|
%imstor = OpTypeImage %float 2D 0 0 0 2 R32f
|
|
; sampled image
|
|
%imsam = OpTypeImage %float 2D 0 0 0 1 R32f
|
|
%array_imstor = OpTypeArray %imstor %int_2
|
|
%rta_imstor = OpTypeRuntimeArray %imstor
|
|
|
|
%_ptr_Uniform_stb = OpTypePointer Uniform %struct_b
|
|
%_ptr_StorageBuffer_stb = OpTypePointer StorageBuffer %struct_b
|
|
%_ptr_StorageBuffer_stb_rtarr = OpTypePointer StorageBuffer %struct_b_rtarr
|
|
%_ptr_Workgroup = OpTypePointer Workgroup %float
|
|
%_ptr_Private = OpTypePointer Private %float
|
|
%_ptr_Function = OpTypePointer Function %float
|
|
%_ptr_imstor = OpTypePointer UniformConstant %imstor
|
|
%_ptr_imsam = OpTypePointer UniformConstant %imsam
|
|
%_ptr_array_imstor = OpTypePointer UniformConstant %array_imstor
|
|
%_ptr_rta_imstor = OpTypePointer UniformConstant %rta_imstor
|
|
|
|
%extra_fn = OpTypeFunction %void %float %_ptr_Private %_ptr_imstor
|
|
|
|
%var_ubo = OpVariable %_ptr_Uniform_stb Uniform
|
|
%var_ssbo_sb = OpVariable %_ptr_StorageBuffer_stb StorageBuffer
|
|
%var_ssbo_sb_rtarr = OpVariable %_ptr_StorageBuffer_stb_rtarr StorageBuffer
|
|
%var_wg = OpVariable %_ptr_Workgroup Workgroup
|
|
%var_priv = OpVariable %_ptr_Private Private
|
|
%var_imstor = OpVariable %_ptr_imstor UniformConstant
|
|
%var_imsam = OpVariable %_ptr_imsam UniformConstant
|
|
%var_array_imstor = OpVariable %_ptr_array_imstor UniformConstant
|
|
%var_rta_imstor = OpVariable %_ptr_rta_imstor UniformConstant
|
|
|
|
%helper = OpFunction %void None %extra_fn
|
|
%param_f = OpFunctionParameter %float
|
|
%param_p = OpFunctionParameter %_ptr_Private
|
|
%param_pimstor = OpFunctionParameter %_ptr_imstor
|
|
%helper_label = OpLabel
|
|
%helper_func_var = OpVariable %_ptr_Function Function
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
%main = OpFunction %void None %void_fn
|
|
%label = OpLabel
|
|
%var_func = OpVariable %_ptr_Function Function
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableLabelTargetBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%label");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must be a memory object declaration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableTypeTargetBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%void");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must be a memory object declaration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableValueTargetBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%float_0");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("must be a memory object declaration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableValueParamBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%param_f");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a pointer type"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritablePointerParamButWrongTypeBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%param_p");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %param_p = OpFunctionParameter %_ptr_Private_float"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritablePointerParamStorageImageGood) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%param_pimstor");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarStorageImageGood) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_imstor");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarSampledImageBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_imsam");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %var_imsam"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarUboGood) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_ubo");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarSsboInUniformGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpDecorate %struct_bb BufferBlock
|
|
OpMemberDecorate %struct_bb 0 Offset 0
|
|
OpDecorate %var_ssbo_u NonWritable
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%struct_bb = OpTypeStruct %float
|
|
%_ptr_Uniform_stbb = OpTypePointer Uniform %struct_bb
|
|
%var_ssbo_u = OpVariable %_ptr_Uniform_stbb Uniform
|
|
%main = OpFunction %void None %void_fn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarSsboInStorageBufferGood) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_ssbo_sb");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableMemberOfSsboInStorageBufferGood) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%struct_b_rtarr", true);
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableMemberOfStructGood) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%simple_struct", true);
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarWorkgroupBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_wg");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %var_wg"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarWorkgroupV14Bad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_wg");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, storage "
|
|
"buffer, or variable in Private or Function storage "
|
|
"class\n %var_wg"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarPrivateBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_priv");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %var_priv"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarPrivateV13Bad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_priv");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %var_priv"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarPrivateV14Good) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_priv");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarPrivateV13TargetV14Bad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_priv");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %var_priv"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarFunctionBad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_func");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %var_func"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableArrayGood) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_array_imstor");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableRuntimeArrayGood) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_rta_imstor");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_P(ValidateVulkanCombineDecorationResult, Decorate) {
|
|
const char* const decoration = std::get<0>(GetParam());
|
|
const char* const vuid = std::get<1>(GetParam());
|
|
const TestResult& test_result = std::get<2>(GetParam());
|
|
|
|
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
|
|
generator.before_types_ = "OpDecorate %u32 ";
|
|
generator.before_types_ += decoration;
|
|
generator.before_types_ += "\n";
|
|
|
|
EntryPoint entry_point;
|
|
entry_point.name = "main";
|
|
entry_point.execution_model = "Vertex";
|
|
generator.entry_points_.push_back(std::move(entry_point));
|
|
|
|
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
|
|
ASSERT_EQ(test_result.validation_result,
|
|
ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
if (!test_result.error_str.empty()) {
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
|
|
}
|
|
if (vuid) {
|
|
EXPECT_THAT(getDiagnosticString(), AnyVUID(vuid));
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
DecorationAllowListFailure, ValidateVulkanCombineDecorationResult,
|
|
Combine(Values("GLSLShared", "GLSLPacked"),
|
|
Values("VUID-StandaloneSpirv-GLSLShared-04669"),
|
|
Values(TestResult(
|
|
SPV_ERROR_INVALID_ID,
|
|
"is not valid for the Vulkan execution environment."))));
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarFunctionV13Bad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_func");
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %var_func"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarFunctionV14Good) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_func");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, NonWritableVarFunctionV13TargetV14Bad) {
|
|
std::string spirv = ShaderWithNonWritableTarget("%var_func");
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of NonWritable decoration is invalid: must "
|
|
"point to a storage image, uniform block, or storage "
|
|
"buffer\n %var_func"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BufferBlockV13ValV14Good) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %1 BufferBlock
|
|
%1 = OpTypeStruct
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BufferBlockV14Bad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %1 BufferBlock
|
|
%1 = OpTypeStruct
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("2nd operand of Decorate: operand BufferBlock(3) "
|
|
"requires SPIR-V version 1.3 or earlier"));
|
|
}
|
|
|
|
// Component
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationBadTarget) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpDecorate %t Component 0
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%t = OpTypeVector %float 2
|
|
%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 memory object declaration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationBadStorageClass) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpDecorate %v Component 0
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%t = OpTypeVector %float 2
|
|
%ptr_private = OpTypePointer Private %t
|
|
%v = OpVariable %ptr_private Private
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Target of Component decoration is invalid: must "
|
|
"point to a Storage Class of Input(1) or Output(3)"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationBadTypeVulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Matrix
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpDecorate %v Component 0
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%vtype = OpTypeVector %float 4
|
|
%t = OpTypeMatrix %vtype 4
|
|
%ptr_input = OpTypePointer Input %t
|
|
%v = OpVariable %ptr_input Input
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Component decoration specified for type"));
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a scalar or vector"));
|
|
}
|
|
|
|
std::string ShaderWithComponentDecoration(const std::string& type,
|
|
const std::string& decoration) {
|
|
return R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %entryPointOutput
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpDecorate %entryPointOutput Location 0
|
|
OpDecorate %entryPointOutput )" +
|
|
decoration + R"(
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v3float = OpTypeVector %float 3
|
|
%v4float = OpTypeVector %float 4
|
|
%uint = OpTypeInt 32 0
|
|
%uint_2 = OpConstant %uint 2
|
|
%arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
|
|
%float_0 = OpConstant %float 0
|
|
%_ptr_Output_type = OpTypePointer Output %)" + type + R"(
|
|
%entryPointOutput = OpVariable %_ptr_Output_type Output
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("uint", "Component 0");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("uint", "Component 1");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("uint", "Component 2");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("uint", "Component 3");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("uint", "Component 4");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Sequence of components starting with 4 "
|
|
"and ending with 4 gets larger than 3"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("v3float", "Component 1");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("v4float", "Component 0");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("v4float", "Component 1");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Sequence of components starting with 1 "
|
|
"and ending with 4 gets larger than 3"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = ShaderWithComponentDecoration("v4float", "Component 3");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Sequence of components starting with 3 "
|
|
"and ending with 6 gets larger than 3"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationArrayGoodVulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv =
|
|
ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 1");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationArrayBadVulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv =
|
|
ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 2");
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Sequence of components starting with 2 "
|
|
"and ending with 4 gets larger than 3"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationBlockGood) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main" %9 %12
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpDecorate %9 Location 0
|
|
OpMemberDecorate %block 0 Location 2
|
|
OpMemberDecorate %block 0 Component 1
|
|
OpDecorate %block Block
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%float = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %float 3
|
|
%8 = OpTypePointer Output %vec3
|
|
%9 = OpVariable %8 Output
|
|
%block = OpTypeStruct %vec3
|
|
%11 = OpTypePointer Input %block
|
|
%12 = OpVariable %11 Input
|
|
%int = OpTypeInt 32 1
|
|
%14 = OpConstant %int 0
|
|
%15 = OpTypePointer Input %vec3
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%16 = OpAccessChain %15 %12 %14
|
|
%17 = OpLoad %vec3 %16
|
|
OpStore %9 %17
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationBlockBadVulkan) {
|
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main" %9 %12
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpDecorate %9 Location 0
|
|
OpMemberDecorate %block 0 Location 2
|
|
OpMemberDecorate %block 0 Component 2
|
|
OpDecorate %block Block
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%float = OpTypeFloat 32
|
|
%vec3 = OpTypeVector %float 3
|
|
%8 = OpTypePointer Output %vec3
|
|
%9 = OpVariable %8 Output
|
|
%block = OpTypeStruct %vec3
|
|
%11 = OpTypePointer Input %block
|
|
%12 = OpVariable %11 Input
|
|
%int = OpTypeInt 32 1
|
|
%14 = OpConstant %int 0
|
|
%15 = OpTypePointer Input %vec3
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%16 = OpAccessChain %15 %12 %14
|
|
%17 = OpLoad %vec3 %16
|
|
OpStore %9 %17
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Sequence of components starting with 2 "
|
|
"and ending with 4 gets larger than 3"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, ComponentDecorationFunctionParameter) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
|
|
OpDecorate %param_f Component 0
|
|
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%float_0 = OpConstant %float 0
|
|
%int = OpTypeInt 32 0
|
|
%int_2 = OpConstant %int 2
|
|
%struct_b = OpTypeStruct %float
|
|
|
|
%extra_fn = OpTypeFunction %void %float
|
|
|
|
%helper = OpFunction %void None %extra_fn
|
|
%param_f = OpFunctionParameter %float
|
|
%helper_label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
%main = OpFunction %void None %void_fn
|
|
%label = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a pointer type"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanStorageBufferBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %uint
|
|
%ptr_ssbo = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr_ssbo StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanStorageBufferMissingBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %uint
|
|
%ptr_ssbo = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr_ssbo StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-PushConstant-06675"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("From Vulkan spec:\nSuch variables "
|
|
"must be identified with a Block decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanStorageBufferArrayMissingBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%uint_4 = OpConstant %uint 4
|
|
%struct = OpTypeStruct %uint
|
|
%array = OpTypeArray %struct %uint_4
|
|
%ptr_ssbo = OpTypePointer StorageBuffer %array
|
|
%var = OpVariable %ptr_ssbo StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-PushConstant-06675"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("From Vulkan spec:\nSuch variables "
|
|
"must be identified with a Block decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanStorageBufferRuntimeArrayMissingBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability RuntimeDescriptorArrayEXT
|
|
OpExtension "SPV_EXT_descriptor_indexing"
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %uint
|
|
%array = OpTypeRuntimeArray %struct
|
|
%ptr_ssbo = OpTypePointer StorageBuffer %array
|
|
%var = OpVariable %ptr_ssbo StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-PushConstant-06675"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("From Vulkan spec:\nSuch variables "
|
|
"must be identified with a Block decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %uint
|
|
%ptr_ubo = OpTypePointer Uniform %struct
|
|
%var = OpVariable %ptr_ubo Uniform
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformBufferBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct BufferBlock
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %uint
|
|
%ptr_ubo = OpTypePointer Uniform %struct
|
|
%var = OpVariable %ptr_ubo Uniform
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformMissingBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %uint
|
|
%ptr_ubo = OpTypePointer Uniform %struct
|
|
%var = OpVariable %ptr_ubo Uniform
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-Uniform-06676"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("From Vulkan spec:\nSuch variables must be "
|
|
"identified with a Block or BufferBlock decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformArrayMissingBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%uint_4 = OpConstant %uint 4
|
|
%struct = OpTypeStruct %uint
|
|
%array = OpTypeArray %struct %uint_4
|
|
%ptr_ubo = OpTypePointer Uniform %array
|
|
%var = OpVariable %ptr_ubo Uniform
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-Uniform-06676"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("From Vulkan spec:\nSuch variables must be "
|
|
"identified with a Block or BufferBlock decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanUniformRuntimeArrayMissingBlock) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability RuntimeDescriptorArrayEXT
|
|
OpExtension "SPV_EXT_descriptor_indexing"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%uint = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %uint
|
|
%array = OpTypeRuntimeArray %struct
|
|
%ptr_ubo = OpTypePointer Uniform %array
|
|
%var = OpVariable %ptr_ubo Uniform
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-Uniform-06676"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("From Vulkan spec:\nSuch variables must be "
|
|
"identified with a Block or BufferBlock decoration"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanArrayStrideZero) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %array ArrayStride 0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_4 = OpConstant %int 4
|
|
%array = OpTypeArray %int %int_4
|
|
%struct = OpTypeStruct %array
|
|
%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr_ssbo_struct StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("contains an array with stride 0"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, VulkanArrayStrideTooSmall) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
OpDecorate %inner ArrayStride 4
|
|
OpDecorate %outer ArrayStride 4
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_4 = OpConstant %int 4
|
|
%inner = OpTypeArray %int %int_4
|
|
%outer = OpTypeArray %inner %int_4
|
|
%struct = OpTypeStruct %outer
|
|
%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr_ssbo_struct StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"contains an array with stride 4, but with an element size of 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, FunctionsWithOpGroupDecorate) {
|
|
std::string spirv = R"(
|
|
OpCapability Addresses
|
|
OpCapability Linkage
|
|
OpCapability Kernel
|
|
OpCapability Int8
|
|
%1 = OpExtInstImport "OpenCL.std"
|
|
OpMemoryModel Physical32 OpenCL
|
|
OpName %foo "foo"
|
|
OpName %entry "entry"
|
|
OpName %bar "bar"
|
|
OpName %entry_0 "entry"
|
|
OpName %k "k"
|
|
OpName %entry_1 "entry"
|
|
OpName %b "b"
|
|
OpDecorate %28 FuncParamAttr Zext
|
|
%28 = OpDecorationGroup
|
|
OpDecorate %k LinkageAttributes "k" Export
|
|
OpDecorate %foo LinkageAttributes "foo" Export
|
|
OpDecorate %bar LinkageAttributes "bar" Export
|
|
OpDecorate %b Alignment 1
|
|
OpGroupDecorate %28 %foo %bar
|
|
%uchar = OpTypeInt 8 0
|
|
%bool = OpTypeBool
|
|
%3 = OpTypeFunction %bool
|
|
%void = OpTypeVoid
|
|
%10 = OpTypeFunction %void
|
|
%_ptr_Function_uchar = OpTypePointer Function %uchar
|
|
%true = OpConstantTrue %bool
|
|
%foo = OpFunction %bool DontInline %3
|
|
%entry = OpLabel
|
|
OpReturnValue %true
|
|
OpFunctionEnd
|
|
%bar = OpFunction %bool DontInline %3
|
|
%entry_0 = OpLabel
|
|
OpReturnValue %true
|
|
OpFunctionEnd
|
|
%k = OpFunction %void DontInline %10
|
|
%entry_1 = OpLabel
|
|
%b = OpVariable %_ptr_Function_uchar Function
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, LocationVariableGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %in_var Location 0
|
|
%float = OpTypeFloat 32
|
|
%ptr_input_float = OpTypePointer Input %float
|
|
%in_var = OpVariable %ptr_input_float Input
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, LocationStructMemberGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
OpMemberDecorate %struct 0 Location 0
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, LocationStructBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %struct Location 0
|
|
%float = OpTypeFloat 32
|
|
%struct = OpTypeStruct %float
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, LocationFloatBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %float Location 0
|
|
%float = OpTypeFloat 32
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupSingleBlockVariable) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
OpMemberDecorate %first 0 Offset 0
|
|
OpDecorate %first Block
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%first = OpTypeStruct %int
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int_0 = OpConstant %int 0
|
|
%int_2 = OpConstant %int 2
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
|
|
OpStore %13 %int_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupBlockVariableRequiresV14) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
OpMemberDecorate %first 0 Offset 0
|
|
OpDecorate %first Block
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%first = OpTypeStruct %int
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int_0 = OpConstant %int 0
|
|
%int_2 = OpConstant %int 2
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
|
|
OpStore %13 %int_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("requires SPIR-V version 1.4 or later"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupSingleNonBlockVariable) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %a
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%a = OpVariable %_ptr_Workgroup_int Workgroup
|
|
%int_2 = OpConstant %int 2
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpStore %a %int_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupMultiBlockVariable) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_ %__0
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
OpMemberDecorate %first 0 Offset 0
|
|
OpDecorate %first Block
|
|
OpMemberDecorate %second 0 Offset 0
|
|
OpDecorate %second Block
|
|
OpDecorate %_ Aliased
|
|
OpDecorate %__0 Aliased
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%first = OpTypeStruct %int
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int_0 = OpConstant %int 0
|
|
%int_2 = OpConstant %int 2
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%second = OpTypeStruct %int
|
|
%_ptr_Workgroup_second = OpTypePointer Workgroup %second
|
|
%__0 = OpVariable %_ptr_Workgroup_second Workgroup
|
|
%int_3 = OpConstant %int 3
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
|
|
OpStore %13 %int_2
|
|
%18 = OpAccessChain %_ptr_Workgroup_int %__0 %int_0
|
|
OpStore %18 %int_3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupBlockVariableWith8BitType) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Int8
|
|
OpCapability WorkgroupMemoryExplicitLayout8BitAccessKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 2 1 1
|
|
OpMemberDecorate %first 0 Offset 0
|
|
OpDecorate %first Block
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%char = OpTypeInt 8 1
|
|
%first = OpTypeStruct %char
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%char_2 = OpConstant %char 2
|
|
%_ptr_Workgroup_char = OpTypePointer Workgroup %char
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%14 = OpAccessChain %_ptr_Workgroup_char %_ %int_0
|
|
OpStore %14 %char_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupMultiNonBlockVariable) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %a %b
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%a = OpVariable %_ptr_Workgroup_int Workgroup
|
|
%int_2 = OpConstant %int 2
|
|
%b = OpVariable %_ptr_Workgroup_int Workgroup
|
|
%int_3 = OpConstant %int 3
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpStore %a %int_2
|
|
OpStore %b %int_3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupBlockVariableWith16BitType) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Float16
|
|
OpCapability Int16
|
|
OpCapability WorkgroupMemoryExplicitLayout16BitAccessKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 2 1 1
|
|
OpMemberDecorate %first 0 Offset 0
|
|
OpMemberDecorate %first 1 Offset 2
|
|
OpDecorate %first Block
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%short = OpTypeInt 16 1
|
|
%half = OpTypeFloat 16
|
|
%first = OpTypeStruct %short %half
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%short_3 = OpConstant %short 3
|
|
%_ptr_Workgroup_short = OpTypePointer Workgroup %short
|
|
%int_1 = OpConstant %int 1
|
|
%half_0x1_898p_3 = OpConstant %half 0x1.898p+3
|
|
%_ptr_Workgroup_half = OpTypePointer Workgroup %half
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%15 = OpAccessChain %_ptr_Workgroup_short %_ %int_0
|
|
OpStore %15 %short_3
|
|
%19 = OpAccessChain %_ptr_Workgroup_half %_ %int_1
|
|
OpStore %19 %half_0x1_898p_3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_SUCCESS,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupBlockVariableScalarLayout) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main" %B
|
|
OpSource GLSL 450
|
|
OpMemberDecorate %S 0 Offset 0
|
|
OpMemberDecorate %S 1 Offset 4
|
|
OpMemberDecorate %S 2 Offset 16
|
|
OpMemberDecorate %S 3 Offset 28
|
|
OpDecorate %S Block
|
|
OpDecorate %B Aliased
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v3float = OpTypeVector %float 3
|
|
%S = OpTypeStruct %float %v3float %v3float %v3float
|
|
%_ptr_Workgroup_S = OpTypePointer Workgroup %S
|
|
%B = OpVariable %_ptr_Workgroup_S Workgroup
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
spvValidatorOptionsSetWorkgroupScalarBlockLayout(getValidatorOptions(), true);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4))
|
|
<< getDiagnosticString();
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupMixBlockAndNonBlockBad) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_ %b
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
OpMemberDecorate %first 0 Offset 0
|
|
OpDecorate %first Block
|
|
OpDecorate %_ Aliased
|
|
OpDecorate %b Aliased
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%first = OpTypeStruct %int
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int_0 = OpConstant %int 0
|
|
%int_2 = OpConstant %int 2
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%b = OpVariable %_ptr_Workgroup_int Workgroup
|
|
%int_3 = OpConstant %int 3
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
|
|
OpStore %13 %int_2
|
|
OpStore %b %int_3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("either all or none of the Workgroup Storage Class variables "
|
|
"in the entry point interface must point to struct types "
|
|
"decorated with Block"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupMultiBlockVariableMissingAliased) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_ %__0
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
OpMemberDecorate %first 0 Offset 0
|
|
OpDecorate %first Block
|
|
OpMemberDecorate %second 0 Offset 0
|
|
OpDecorate %second Block
|
|
OpDecorate %_ Aliased
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%first = OpTypeStruct %int
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int_0 = OpConstant %int 0
|
|
%int_2 = OpConstant %int 2
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%second = OpTypeStruct %int
|
|
%_ptr_Workgroup_second = OpTypePointer Workgroup %second
|
|
%__0 = OpVariable %_ptr_Workgroup_second Workgroup
|
|
%int_3 = OpConstant %int 3
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
|
|
OpStore %13 %int_2
|
|
%18 = OpAccessChain %_ptr_Workgroup_int %__0 %int_0
|
|
OpStore %18 %int_3
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("more than one Workgroup Storage Class variable in the "
|
|
"entry point interface point to a type decorated with Block, "
|
|
"all of them must be decorated with Aliased"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableNotAStruct) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
OpDecorate %first Block
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%int_3 = OpConstant %int 3
|
|
%first = OpTypeArray %int %int_3
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int_0 = OpConstant %int 0
|
|
%int_2 = OpConstant %int 2
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
|
|
OpStore %13 %int_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableMissingLayout) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
OpDecorate %first Block
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%first = OpTypeStruct %int
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int_0 = OpConstant %int 0
|
|
%int_2 = OpConstant %int 2
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
|
|
OpStore %13 %int_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Block must be explicitly laid out with Offset decorations"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableBadLayout) {
|
|
std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability WorkgroupMemoryExplicitLayoutKHR
|
|
OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main" %_
|
|
OpExecutionMode %main LocalSize 8 1 1
|
|
OpMemberDecorate %first 0 Offset 1
|
|
OpDecorate %first Block
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%first = OpTypeStruct %int
|
|
%_ptr_Workgroup_first = OpTypePointer Workgroup %first
|
|
%_ = OpVariable %_ptr_Workgroup_first Workgroup
|
|
%int_0 = OpConstant %int 0
|
|
%int_2 = OpConstant %int 2
|
|
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
|
|
OpStore %13 %int_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
|
ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Block for variable in Workgroup storage class must follow "
|
|
"standard storage buffer layout rules: "
|
|
"member 0 at offset 1 is not aligned to 4"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BadMatrixStrideUniform) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %block Block
|
|
OpMemberDecorate %block 0 Offset 0
|
|
OpMemberDecorate %block 0 MatrixStride 3
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%float4 = OpTypeVector %float 4
|
|
%matrix4x4 = OpTypeMatrix %float4 4
|
|
%block = OpTypeStruct %matrix4x4
|
|
%block_ptr = OpTypePointer Uniform %block
|
|
%var = OpVariable %block_ptr Uniform
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 2 decorated as Block for variable in Uniform storage "
|
|
"class must follow standard uniform buffer layout rules: member 0 is "
|
|
"a matrix with stride 3 not satisfying alignment to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BadMatrixStrideStorageBuffer) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %block Block
|
|
OpMemberDecorate %block 0 Offset 0
|
|
OpMemberDecorate %block 0 MatrixStride 3
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%float4 = OpTypeVector %float 4
|
|
%matrix4x4 = OpTypeMatrix %float4 4
|
|
%block = OpTypeStruct %matrix4x4
|
|
%block_ptr = OpTypePointer StorageBuffer %block
|
|
%var = OpVariable %block_ptr StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 2 decorated as Block for variable in StorageBuffer "
|
|
"storage class must follow standard storage buffer layout rules: "
|
|
"member 0 is a matrix with stride 3 not satisfying alignment to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BadMatrixStridePushConstant) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %block Block
|
|
OpMemberDecorate %block 0 Offset 0
|
|
OpMemberDecorate %block 0 MatrixStride 3
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%float4 = OpTypeVector %float 4
|
|
%matrix4x4 = OpTypeMatrix %float4 4
|
|
%block = OpTypeStruct %matrix4x4
|
|
%block_ptr = OpTypePointer PushConstant %block
|
|
%var = OpVariable %block_ptr PushConstant
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 2 decorated as Block for variable in PushConstant "
|
|
"storage class must follow standard storage buffer layout rules: "
|
|
"member 0 is a matrix with stride 3 not satisfying alignment to 16"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, BadMatrixStrideStorageBufferScalarLayout) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %block Block
|
|
OpMemberDecorate %block 0 Offset 0
|
|
OpMemberDecorate %block 0 MatrixStride 3
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%float4 = OpTypeVector %float 4
|
|
%matrix4x4 = OpTypeMatrix %float4 4
|
|
%block = OpTypeStruct %matrix4x4
|
|
%block_ptr = OpTypePointer StorageBuffer %block
|
|
%var = OpVariable %block_ptr StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
options_->scalar_block_layout = true;
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Structure id 2 decorated as Block for variable in StorageBuffer "
|
|
"storage class must follow scalar storage buffer layout rules: "
|
|
"member 0 is a matrix with stride 3 not satisfying alignment to 4"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, MissingOffsetStructNestedInArray) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %array ArrayStride 4
|
|
OpDecorate %outer Block
|
|
OpMemberDecorate %outer 0 Offset 0
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_4 = OpConstant %int 4
|
|
%inner = OpTypeStruct %int
|
|
%array = OpTypeArray %inner %int_4
|
|
%outer = OpTypeStruct %array
|
|
%ptr_ssbo_outer = OpTypePointer StorageBuffer %outer
|
|
%var = OpVariable %ptr_ssbo_outer StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Structure id 3 decorated as Block must be explicitly "
|
|
"laid out with Offset decorations"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, AllOnesOffset) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %var DescriptorSet 0
|
|
OpDecorate %var Binding 0
|
|
OpDecorate %outer Block
|
|
OpMemberDecorate %outer 0 Offset 0
|
|
OpMemberDecorate %struct 0 Offset 4294967295
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %int
|
|
%outer = OpTypeStruct %struct
|
|
%ptr = OpTypePointer Uniform %outer
|
|
%var = OpVariable %ptr Uniform
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("decorated as Block must be explicitly laid out with "
|
|
"Offset decorations"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PerVertexVulkanGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FragmentBarycentricKHR
|
|
OpExtension "SPV_KHR_fragment_shader_barycentric"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %vertexIDs
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpDecorate %vertexIDs Location 0
|
|
OpDecorate %vertexIDs PerVertexKHR
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%uint = OpTypeInt 32 0
|
|
%ptrFloat = OpTypePointer Input %float
|
|
%uint_3 = OpConstant %uint 3
|
|
%floatArray = OpTypeArray %float %uint_3
|
|
%ptrFloatArray = OpTypePointer Input %floatArray
|
|
%vertexIDs = OpVariable %ptrFloatArray Input
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%main = OpFunction %void None %func
|
|
%label = OpLabel
|
|
%access = OpAccessChain %ptrFloat %vertexIDs %int_0
|
|
%load = OpLoad %float %access
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PerVertexVulkanOutput) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FragmentBarycentricKHR
|
|
OpExtension "SPV_KHR_fragment_shader_barycentric"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %vertexIDs
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpDecorate %vertexIDs Location 0
|
|
OpDecorate %vertexIDs PerVertexKHR
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%uint = OpTypeInt 32 0
|
|
%ptrFloat = OpTypePointer Output %float
|
|
%uint_3 = OpConstant %uint 3
|
|
%floatArray = OpTypeArray %float %uint_3
|
|
%ptrFloatArray = OpTypePointer Output %floatArray
|
|
%vertexIDs = OpVariable %ptrFloatArray Output
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%main = OpFunction %void None %func
|
|
%label = OpLabel
|
|
%access = OpAccessChain %ptrFloat %vertexIDs %int_0
|
|
%load = OpLoad %float %access
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-PerVertexKHR-06777"));
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("storage class must be Input"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PerVertexVulkanNonFragment) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FragmentBarycentricKHR
|
|
OpExtension "SPV_KHR_fragment_shader_barycentric"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main" %vertexIDs
|
|
OpDecorate %vertexIDs Location 0
|
|
OpDecorate %vertexIDs PerVertexKHR
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%uint = OpTypeInt 32 0
|
|
%ptrFloat = OpTypePointer Input %float
|
|
%uint_3 = OpConstant %uint 3
|
|
%floatArray = OpTypeArray %float %uint_3
|
|
%ptrFloatArray = OpTypePointer Input %floatArray
|
|
%vertexIDs = OpVariable %ptrFloatArray Input
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%main = OpFunction %void None %func
|
|
%label = OpLabel
|
|
%access = OpAccessChain %ptrFloat %vertexIDs %int_0
|
|
%load = OpLoad %float %access
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-PerVertexKHR-06777"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"PerVertexKHR can only be applied to Fragment Execution Models"));
|
|
}
|
|
|
|
TEST_F(ValidateDecorations, PerVertexVulkanNonArray) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FragmentBarycentricKHR
|
|
OpExtension "SPV_KHR_fragment_shader_barycentric"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %vertexIDs
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpDecorate %vertexIDs Location 0
|
|
OpDecorate %vertexIDs PerVertexKHR
|
|
%void = OpTypeVoid
|
|
%func = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%ptrFloat = OpTypePointer Input %float
|
|
%vertexIDs = OpVariable %ptrFloat Input
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%main = OpFunction %void None %func
|
|
%label = OpLabel
|
|
%load = OpLoad %float %vertexIDs
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-Input-06778"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("PerVertexKHR must be declared as arrays"));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace val
|
|
} // namespace spvtools
|