mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-28 22:21:03 +00:00
02470f606f
* Disallow duplicate decorations generally * Only FuncParamAttr and UserSemantic can be applied to the same target multiple times * Unchecked: completely duplicate UserSemantic and FuncParamAttr * Disallow duplicate execution modes generally * Exceptions for float controls, float controls2 and some intel execution modes * Fix invalid fuzzer transforms
2214 lines
72 KiB
C++
2214 lines
72 KiB
C++
// Copyright (c) 2018 Google LLC.
|
|
//
|
|
// 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.
|
|
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "source/spirv_target_env.h"
|
|
#include "test/unit_spirv.h"
|
|
#include "test/val/val_fixtures.h"
|
|
|
|
namespace spvtools {
|
|
namespace val {
|
|
namespace {
|
|
|
|
using ::testing::Combine;
|
|
using ::testing::HasSubstr;
|
|
using ::testing::Values;
|
|
using ::testing::ValuesIn;
|
|
|
|
using ValidateMode = spvtest::ValidateBase<bool>;
|
|
|
|
const std::string kVoidFunction = R"(%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
TEST_F(ValidateMode, GLComputeNoMode) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateMode, GLComputeNoModeVulkan) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-LocalSize-06426"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"In the Vulkan environment, GLCompute execution model entry "
|
|
"points require either the LocalSize or LocalSizeId execution mode "
|
|
"or an object decorated with WorkgroupSize must be specified."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpDecorate %int3_1 BuiltIn WorkgroupSize
|
|
%int = OpTypeInt 32 0
|
|
%int3 = OpTypeVector %int 3
|
|
%int_1 = OpConstant %int 1
|
|
%int3_1 = OpConstantComposite %int3 %int_1 %int_1 %int_1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
|
|
}
|
|
|
|
TEST_F(ValidateMode, GLComputeVulkanLocalSize) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
|
|
}
|
|
|
|
TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_VULKAN_1_1; // need SPIR-V 1.2
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("LocalSizeId mode is not allowed by the current environment."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_VULKAN_1_1; // need SPIR-V 1.2
|
|
CompileSuccessfully(spirv, env);
|
|
spvValidatorOptionsSetAllowLocalSizeId(getValidatorOptions(), true);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentOriginLowerLeftVulkan) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginLowerLeft
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-OriginLowerLeft-04653"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("In the Vulkan environment, the OriginLowerLeft "
|
|
"execution mode must not be used."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentPixelCenterIntegerVulkan) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main PixelCenterInteger
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_VULKAN_1_0;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
AnyVUID("VUID-StandaloneSpirv-PixelCenterInteger-04654"));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("In the Vulkan environment, the PixelCenterInteger "
|
|
"execution mode must not be used."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, GeometryNoOutputMode) {
|
|
const std::string spirv = R"(
|
|
OpCapability Geometry
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Geometry %main "main"
|
|
OpExecutionMode %main InputPoints
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Geometry execution model entry points must specify "
|
|
"exactly one of OutputPoints, OutputLineStrip or "
|
|
"OutputTriangleStrip execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, GeometryNoInputMode) {
|
|
const std::string spirv = R"(
|
|
OpCapability Geometry
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Geometry %main "main"
|
|
OpExecutionMode %main OutputPoints
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Geometry execution model entry points must specify exactly "
|
|
"one of InputPoints, InputLines, InputLinesAdjacency, "
|
|
"Triangles or InputTrianglesAdjacency execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentNoOrigin) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points require either an "
|
|
"OriginUpperLeft or OriginLowerLeft execution mode."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentBothOrigins) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main OriginLowerLeft
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points can only specify one of "
|
|
"OriginUpperLeft or OriginLowerLeft execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentDepthGreaterAndLess) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main DepthGreater
|
|
OpExecutionMode %main DepthLess
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points can specify at "
|
|
"most one of DepthGreater, DepthLess or DepthUnchanged "
|
|
"execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentDepthGreaterAndUnchanged) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main DepthGreater
|
|
OpExecutionMode %main DepthUnchanged
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points can specify at "
|
|
"most one of DepthGreater, DepthLess or DepthUnchanged "
|
|
"execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentDepthLessAndUnchanged) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main DepthLess
|
|
OpExecutionMode %main DepthUnchanged
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points can specify at "
|
|
"most one of DepthGreater, DepthLess or DepthUnchanged "
|
|
"execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentAllDepths) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main DepthGreater
|
|
OpExecutionMode %main DepthLess
|
|
OpExecutionMode %main DepthUnchanged
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points can specify at "
|
|
"most one of DepthGreater, DepthLess or DepthUnchanged "
|
|
"execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, TessellationControlSpacingEqualAndFractionalOdd) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationControl %main "main"
|
|
OpExecutionMode %main SpacingEqual
|
|
OpExecutionMode %main SpacingFractionalOdd
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify "
|
|
"at most one of SpacingEqual, SpacingFractionalOdd or "
|
|
"SpacingFractionalEven execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, TessellationControlSpacingEqualAndSpacingFractionalEven) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationControl %main "main"
|
|
OpExecutionMode %main SpacingEqual
|
|
OpExecutionMode %main SpacingFractionalEven
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify "
|
|
"at most one of SpacingEqual, SpacingFractionalOdd or "
|
|
"SpacingFractionalEven execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode,
|
|
TessellationControlSpacingFractionalOddAndSpacingFractionalEven) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationControl %main "main"
|
|
OpExecutionMode %main SpacingFractionalOdd
|
|
OpExecutionMode %main SpacingFractionalEven
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify "
|
|
"at most one of SpacingEqual, SpacingFractionalOdd or "
|
|
"SpacingFractionalEven execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, TessellationControlAllSpacing) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationControl %main "main"
|
|
OpExecutionMode %main SpacingEqual
|
|
OpExecutionMode %main SpacingFractionalOdd
|
|
OpExecutionMode %main SpacingFractionalEven
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify "
|
|
"at most one of SpacingEqual, SpacingFractionalOdd or "
|
|
"SpacingFractionalEven execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode,
|
|
TessellationEvaluationSpacingEqualAndSpacingFractionalOdd) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationEvaluation %main "main"
|
|
OpExecutionMode %main SpacingEqual
|
|
OpExecutionMode %main SpacingFractionalOdd
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify "
|
|
"at most one of SpacingEqual, SpacingFractionalOdd or "
|
|
"SpacingFractionalEven execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode,
|
|
TessellationEvaluationSpacingEqualAndSpacingFractionalEven) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationEvaluation %main "main"
|
|
OpExecutionMode %main SpacingEqual
|
|
OpExecutionMode %main SpacingFractionalEven
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify "
|
|
"at most one of SpacingEqual, SpacingFractionalOdd or "
|
|
"SpacingFractionalEven execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode,
|
|
TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationEvaluation %main "main"
|
|
OpExecutionMode %main SpacingFractionalOdd
|
|
OpExecutionMode %main SpacingFractionalEven
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify "
|
|
"at most one of SpacingEqual, SpacingFractionalOdd or "
|
|
"SpacingFractionalEven execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, TessellationEvaluationAllSpacing) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationEvaluation %main "main"
|
|
OpExecutionMode %main SpacingEqual
|
|
OpExecutionMode %main SpacingFractionalOdd
|
|
OpExecutionMode %main SpacingFractionalEven
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify "
|
|
"at most one of SpacingEqual, SpacingFractionalOdd or "
|
|
"SpacingFractionalEven execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, TessellationControlBothVertex) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationControl %main "main"
|
|
OpExecutionMode %main VertexOrderCw
|
|
OpExecutionMode %main VertexOrderCcw
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify at most "
|
|
"one of VertexOrderCw or VertexOrderCcw execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, TessellationEvaluationBothVertex) {
|
|
const std::string spirv = R"(
|
|
OpCapability Tessellation
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TessellationEvaluation %main "main"
|
|
OpExecutionMode %main VertexOrderCw
|
|
OpExecutionMode %main VertexOrderCcw
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Tessellation execution model entry points can specify at most "
|
|
"one of VertexOrderCw or VertexOrderCcw execution modes."));
|
|
}
|
|
|
|
using ValidateModeGeometry = spvtest::ValidateBase<std::tuple<
|
|
std::tuple<std::string, std::string, std::string, std::string, std::string>,
|
|
std::tuple<std::string, std::string, std::string>>>;
|
|
|
|
TEST_P(ValidateModeGeometry, ExecutionMode) {
|
|
std::vector<std::string> input_modes;
|
|
std::vector<std::string> output_modes;
|
|
input_modes.push_back(std::get<0>(std::get<0>(GetParam())));
|
|
input_modes.push_back(std::get<1>(std::get<0>(GetParam())));
|
|
input_modes.push_back(std::get<2>(std::get<0>(GetParam())));
|
|
input_modes.push_back(std::get<3>(std::get<0>(GetParam())));
|
|
input_modes.push_back(std::get<4>(std::get<0>(GetParam())));
|
|
output_modes.push_back(std::get<0>(std::get<1>(GetParam())));
|
|
output_modes.push_back(std::get<1>(std::get<1>(GetParam())));
|
|
output_modes.push_back(std::get<2>(std::get<1>(GetParam())));
|
|
|
|
std::ostringstream sstr;
|
|
sstr << "OpCapability Geometry\n";
|
|
sstr << "OpMemoryModel Logical GLSL450\n";
|
|
sstr << "OpEntryPoint Geometry %main \"main\"\n";
|
|
size_t num_input_modes = 0;
|
|
for (auto input : input_modes) {
|
|
if (!input.empty()) {
|
|
num_input_modes++;
|
|
sstr << "OpExecutionMode %main " << input << "\n";
|
|
}
|
|
}
|
|
size_t num_output_modes = 0;
|
|
for (auto output : output_modes) {
|
|
if (!output.empty()) {
|
|
num_output_modes++;
|
|
sstr << "OpExecutionMode %main " << output << "\n";
|
|
}
|
|
}
|
|
sstr << "%void = OpTypeVoid\n";
|
|
sstr << "%void_fn = OpTypeFunction %void\n";
|
|
sstr << "%int = OpTypeInt 32 0\n";
|
|
sstr << "%int1 = OpConstant %int 1\n";
|
|
sstr << "%main = OpFunction %void None %void_fn\n";
|
|
sstr << "%entry = OpLabel\n";
|
|
sstr << "OpReturn\n";
|
|
sstr << "OpFunctionEnd\n";
|
|
|
|
CompileSuccessfully(sstr.str());
|
|
if (num_input_modes == 1 && num_output_modes == 1) {
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
} else {
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
if (num_input_modes != 1) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Geometry execution model entry points must "
|
|
"specify exactly one of InputPoints, InputLines, "
|
|
"InputLinesAdjacency, Triangles or "
|
|
"InputTrianglesAdjacency execution modes."));
|
|
} else {
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Geometry execution model entry points must specify "
|
|
"exactly one of OutputPoints, OutputLineStrip or "
|
|
"OutputTriangleStrip execution modes."));
|
|
}
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
GeometryRequiredModes, ValidateModeGeometry,
|
|
Combine(Combine(Values("InputPoints", ""), Values("InputLines", ""),
|
|
Values("InputLinesAdjacency", ""), Values("Triangles", ""),
|
|
Values("InputTrianglesAdjacency", "")),
|
|
Combine(Values("OutputPoints", ""), Values("OutputLineStrip", ""),
|
|
Values("OutputTriangleStrip", ""))));
|
|
|
|
using ValidateModeExecution =
|
|
spvtest::ValidateBase<std::tuple<spv_result_t, std::string, std::string,
|
|
std::string, spv_target_env>>;
|
|
|
|
TEST_P(ValidateModeExecution, ExecutionMode) {
|
|
const spv_result_t expectation = std::get<0>(GetParam());
|
|
const std::string error = std::get<1>(GetParam());
|
|
const std::string model = std::get<2>(GetParam());
|
|
const std::string mode = std::get<3>(GetParam());
|
|
const spv_target_env env = std::get<4>(GetParam());
|
|
|
|
std::ostringstream sstr;
|
|
sstr << "OpCapability Shader\n";
|
|
sstr << "OpCapability Geometry\n";
|
|
sstr << "OpCapability Tessellation\n";
|
|
sstr << "OpCapability TransformFeedback\n";
|
|
if (!spvIsVulkanEnv(env)) {
|
|
sstr << "OpCapability Kernel\n";
|
|
if (env == SPV_ENV_UNIVERSAL_1_3) {
|
|
sstr << "OpCapability SubgroupDispatch\n";
|
|
} else if (env == SPV_ENV_UNIVERSAL_1_5) {
|
|
sstr << "OpCapability TileImageColorReadAccessEXT\n";
|
|
sstr << "OpCapability TileImageDepthReadAccessEXT\n";
|
|
sstr << "OpCapability TileImageStencilReadAccessEXT\n";
|
|
sstr << "OpExtension \"SPV_EXT_shader_tile_image\"\n";
|
|
}
|
|
}
|
|
sstr << "OpMemoryModel Logical GLSL450\n";
|
|
sstr << "OpEntryPoint " << model << " %main \"main\"\n";
|
|
if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 ||
|
|
mode.find("SubgroupsPerWorkgroupId") == 0) {
|
|
sstr << "OpExecutionModeId %main " << mode << "\n";
|
|
} else {
|
|
sstr << "OpExecutionMode %main " << mode << "\n";
|
|
}
|
|
if (model == "Geometry") {
|
|
if (!(mode.find("InputPoints") == 0 || mode.find("InputLines") == 0 ||
|
|
mode.find("InputLinesAdjacency") == 0 ||
|
|
mode.find("Triangles") == 0 ||
|
|
mode.find("InputTrianglesAdjacency") == 0)) {
|
|
// Exactly one of the above modes is required for Geometry shaders.
|
|
sstr << "OpExecutionMode %main InputPoints\n";
|
|
}
|
|
if (!(mode.find("OutputPoints") == 0 || mode.find("OutputLineStrip") == 0 ||
|
|
mode.find("OutputTriangleStrip") == 0)) {
|
|
// Exactly one of the above modes is required for Geometry shaders.
|
|
sstr << "OpExecutionMode %main OutputPoints\n";
|
|
}
|
|
} else if (model == "Fragment") {
|
|
if (!(mode.find("OriginUpperLeft") == 0 ||
|
|
mode.find("OriginLowerLeft") == 0)) {
|
|
// Exactly one of the above modes is required for Fragment shaders.
|
|
sstr << "OpExecutionMode %main OriginUpperLeft\n";
|
|
}
|
|
}
|
|
sstr << "%void = OpTypeVoid\n";
|
|
sstr << "%void_fn = OpTypeFunction %void\n";
|
|
sstr << "%int = OpTypeInt 32 0\n";
|
|
sstr << "%int1 = OpConstant %int 1\n";
|
|
sstr << "%main = OpFunction %void None %void_fn\n";
|
|
sstr << "%entry = OpLabel\n";
|
|
sstr << "OpReturn\n";
|
|
sstr << "OpFunctionEnd\n";
|
|
|
|
CompileSuccessfully(sstr.str(), env);
|
|
EXPECT_THAT(expectation, ValidateInstructions(env));
|
|
if (expectation != SPV_SUCCESS) {
|
|
EXPECT_THAT(getDiagnosticString(), HasSubstr(error));
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeGeometryOnlyGoodSpv10, ValidateModeExecution,
|
|
Combine(Values(SPV_SUCCESS), Values(""), Values("Geometry"),
|
|
Values("Invocations 3", "InputPoints", "InputLines",
|
|
"InputLinesAdjacency", "InputTrianglesAdjacency",
|
|
"OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
|
|
Values(SPV_ENV_UNIVERSAL_1_0)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeGeometryOnlyBadSpv10, ValidateModeExecution,
|
|
Combine(Values(SPV_ERROR_INVALID_DATA),
|
|
Values("Execution mode can only be used with the Geometry "
|
|
"execution model."),
|
|
Values("Fragment", "TessellationEvaluation", "TessellationControl",
|
|
"GLCompute", "Vertex", "Kernel"),
|
|
Values("Invocations 3", "InputPoints", "InputLines",
|
|
"InputLinesAdjacency", "InputTrianglesAdjacency",
|
|
"OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
|
|
Values(SPV_ENV_UNIVERSAL_1_0)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeTessellationOnlyGoodSpv10, ValidateModeExecution,
|
|
Combine(Values(SPV_SUCCESS), Values(""),
|
|
Values("TessellationControl", "TessellationEvaluation"),
|
|
Values("SpacingEqual", "SpacingFractionalEven",
|
|
"SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
|
|
"PointMode", "Quads", "Isolines"),
|
|
Values(SPV_ENV_UNIVERSAL_1_0)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeTessellationOnlyBadSpv10, ValidateModeExecution,
|
|
Combine(Values(SPV_ERROR_INVALID_DATA),
|
|
Values("Execution mode can only be used with a tessellation "
|
|
"execution model."),
|
|
Values("Fragment", "Geometry", "GLCompute", "Vertex", "Kernel"),
|
|
Values("SpacingEqual", "SpacingFractionalEven",
|
|
"SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
|
|
"PointMode", "Quads", "Isolines"),
|
|
Values(SPV_ENV_UNIVERSAL_1_0)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ValidateModeGeometryAndTessellationGoodSpv10,
|
|
ValidateModeExecution,
|
|
Combine(Values(SPV_SUCCESS), Values(""),
|
|
Values("TessellationControl",
|
|
"TessellationEvaluation", "Geometry"),
|
|
Values("Triangles", "OutputVertices 3"),
|
|
Values(SPV_ENV_UNIVERSAL_1_0)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeGeometryAndTessellationBadSpv10, ValidateModeExecution,
|
|
Combine(Values(SPV_ERROR_INVALID_DATA),
|
|
Values("Execution mode can only be used with a Geometry or "
|
|
"tessellation execution model."),
|
|
Values("Fragment", "GLCompute", "Vertex", "Kernel"),
|
|
Values("Triangles", "OutputVertices 3"),
|
|
Values(SPV_ENV_UNIVERSAL_1_0)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeFragmentOnlyGoodSpv10, ValidateModeExecution,
|
|
Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"),
|
|
Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
|
|
"EarlyFragmentTests", "DepthReplacing", "DepthLess",
|
|
"DepthUnchanged"),
|
|
Values(SPV_ENV_UNIVERSAL_1_0)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeFragmentOnlyBadSpv10, ValidateModeExecution,
|
|
Combine(Values(SPV_ERROR_INVALID_DATA),
|
|
Values("Execution mode can only be used with the Fragment "
|
|
"execution model."),
|
|
Values("Geometry", "TessellationControl", "TessellationEvaluation",
|
|
"GLCompute", "Vertex", "Kernel"),
|
|
Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
|
|
"EarlyFragmentTests", "DepthReplacing", "DepthGreater",
|
|
"DepthLess", "DepthUnchanged"),
|
|
Values(SPV_ENV_UNIVERSAL_1_0)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ValidateModeFragmentOnlyGoodSpv15,
|
|
ValidateModeExecution,
|
|
Combine(Values(SPV_SUCCESS), Values(""),
|
|
Values("Fragment"),
|
|
Values("NonCoherentColorAttachmentReadEXT",
|
|
"NonCoherentDepthAttachmentReadEXT",
|
|
"NonCoherentStencilAttachmentReadEXT"),
|
|
Values(SPV_ENV_UNIVERSAL_1_5)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeFragmentOnlyBadSpv15, ValidateModeExecution,
|
|
Combine(Values(SPV_ERROR_INVALID_DATA),
|
|
Values("Execution mode can only be used with the Fragment "
|
|
"execution model."),
|
|
Values("Geometry", "TessellationControl", "TessellationEvaluation",
|
|
"GLCompute", "Vertex", "Kernel"),
|
|
Values("NonCoherentColorAttachmentReadEXT",
|
|
"NonCoherentDepthAttachmentReadEXT",
|
|
"NonCoherentStencilAttachmentReadEXT"),
|
|
Values(SPV_ENV_UNIVERSAL_1_5)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution,
|
|
Combine(Values(SPV_SUCCESS), Values(""),
|
|
Values("Kernel"),
|
|
Values("LocalSizeHint 1 1 1", "VecTypeHint 4",
|
|
"ContractionOff",
|
|
"LocalSizeHintId %int1 %int1 %int1"),
|
|
Values(SPV_ENV_UNIVERSAL_1_3)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeKernelOnlyBadSpv13, ValidateModeExecution,
|
|
Combine(
|
|
Values(SPV_ERROR_INVALID_DATA),
|
|
Values(
|
|
"Execution mode can only be used with the Kernel execution model."),
|
|
Values("Geometry", "TessellationControl", "TessellationEvaluation",
|
|
"GLCompute", "Vertex", "Fragment"),
|
|
Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff",
|
|
"LocalSizeHintId %int1 %int1 %int1"),
|
|
Values(SPV_ENV_UNIVERSAL_1_3)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeGLComputeAndKernelGoodSpv13, ValidateModeExecution,
|
|
Combine(Values(SPV_SUCCESS), Values(""), Values("Kernel", "GLCompute"),
|
|
Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
|
|
Values(SPV_ENV_UNIVERSAL_1_3)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeGLComputeAndKernelBadSpv13, ValidateModeExecution,
|
|
Combine(Values(SPV_ERROR_INVALID_DATA),
|
|
Values("Execution mode can only be used with a Kernel or GLCompute "
|
|
"execution model."),
|
|
Values("Geometry", "TessellationControl", "TessellationEvaluation",
|
|
"Fragment", "Vertex"),
|
|
Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
|
|
Values(SPV_ENV_UNIVERSAL_1_3)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidateModeAllGoodSpv13, ValidateModeExecution,
|
|
Combine(Values(SPV_SUCCESS), Values(""),
|
|
Values("Kernel", "GLCompute", "Geometry", "TessellationControl",
|
|
"TessellationEvaluation", "Fragment", "Vertex"),
|
|
Values("Xfb", "Initializer", "Finalizer", "SubgroupSize 1",
|
|
"SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"),
|
|
Values(SPV_ENV_UNIVERSAL_1_3)));
|
|
|
|
TEST_F(ValidateModeExecution, MeshNVLocalSize) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability MeshShadingNV
|
|
OpExtension "SPV_NV_mesh_shader"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint MeshNV %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, TaskNVLocalSize) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability MeshShadingNV
|
|
OpExtension "SPV_NV_mesh_shader"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TaskNV %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, MeshNVOutputPoints) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability MeshShadingNV
|
|
OpExtension "SPV_NV_mesh_shader"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint MeshNV %main "main"
|
|
OpExecutionMode %main OutputPoints
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, MeshNVOutputVertices) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability MeshShadingNV
|
|
OpExtension "SPV_NV_mesh_shader"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint MeshNV %main "main"
|
|
OpExecutionMode %main OutputVertices 42
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, MeshNVLocalSizeId) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability MeshShadingNV
|
|
OpExtension "SPV_NV_mesh_shader"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint MeshNV %main "main"
|
|
OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, TaskNVLocalSizeId) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability MeshShadingNV
|
|
OpExtension "SPV_NV_mesh_shader"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint TaskNV %main "main"
|
|
OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeSubgroupsPerWorkgroupIdBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability SubgroupDispatch
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpExecutionMode %main SubgroupsPerWorkgroupId %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("OpExecutionMode is only valid when the Mode operand "
|
|
"is an execution mode that takes no Extra Operands"));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability SubgroupDispatch
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdNonConstantBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability SubgroupDispatch
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_ptr = OpTypePointer Private %int
|
|
%int_1 = OpVariable %int_ptr Private
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
|
|
"constant instructions."));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeLocalSizeHintIdBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Kernel
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Kernel %main "main"
|
|
OpExecutionMode %main LocalSizeHintId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("OpExecutionMode is only valid when the Mode operand "
|
|
"is an execution mode that takes no Extra Operands"));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Kernel
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Kernel %main "main"
|
|
OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdNonConstantBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Kernel
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_ptr = OpTypePointer Private %int
|
|
%int_1 = OpVariable %int_ptr Private
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
|
|
"constant instructions."));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeLocalSizeIdBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Kernel
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Kernel %main "main"
|
|
OpExecutionMode %main LocalSizeId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("OpExecutionMode is only valid when the Mode operand "
|
|
"is an execution mode that takes no Extra Operands"));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Kernel
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Kernel %main "main"
|
|
OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
|
|
}
|
|
|
|
TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdNonConstantBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Kernel
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
|
|
%int = OpTypeInt 32 0
|
|
%int_ptr = OpTypePointer Private %int
|
|
%int_1 = OpVariable %int_ptr Private
|
|
)" + kVoidFunction;
|
|
|
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
|
|
CompileSuccessfully(spirv, env);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
|
|
"constant instructions."));
|
|
}
|
|
|
|
using AllowMultipleExecutionModes = spvtest::ValidateBase<std::string>;
|
|
|
|
TEST_P(AllowMultipleExecutionModes, DifferentOperand) {
|
|
const std::string mode = GetParam();
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability DenormPreserve
|
|
OpCapability DenormFlushToZero
|
|
OpCapability SignedZeroInfNanPreserve
|
|
OpCapability RoundingModeRTE
|
|
OpCapability RoundingModeRTZ
|
|
OpExtension "SPV_KHR_float_controls"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionMode %main )" + mode +
|
|
R"( 16
|
|
OpExecutionMode %main )" + mode +
|
|
R"( 32
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_P(AllowMultipleExecutionModes, SameOperand) {
|
|
const std::string mode = GetParam();
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability DenormPreserve
|
|
OpCapability DenormFlushToZero
|
|
OpCapability SignedZeroInfNanPreserve
|
|
OpCapability RoundingModeRTE
|
|
OpCapability RoundingModeRTZ
|
|
OpExtension "SPV_KHR_float_controls"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionMode %main )" + mode +
|
|
R"( 32
|
|
OpExecutionMode %main )" + mode +
|
|
R"( 32
|
|
%void = OpTypeVoid
|
|
%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("execution mode must not be specified multiple times "
|
|
"for the same entry point and operands"));
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(MultipleFloatControlsExecModes,
|
|
AllowMultipleExecutionModes,
|
|
Values("DenormPreserve", "DenormFlushToZero",
|
|
"SignedZeroInfNanPreserve", "RoundingModeRTE",
|
|
"RoundingModeRTZ"));
|
|
|
|
using MultipleExecModes = spvtest::ValidateBase<std::string>;
|
|
|
|
TEST_P(MultipleExecModes, DuplicateMode) {
|
|
const std::string mode = GetParam();
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main )" + mode +
|
|
R"(
|
|
OpExecutionMode %main )" + mode +
|
|
R"(
|
|
%void = OpTypeVoid
|
|
%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("execution mode must not be specified multiple times "
|
|
"per entry point"));
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(MultipleFragmentExecMode, MultipleExecModes,
|
|
Values("DepthReplacing", "DepthGreater", "DepthLess",
|
|
"DepthUnchanged"));
|
|
|
|
TEST_F(ValidateMode, FloatControls2FPFastMathDefaultSameOperand) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %none
|
|
OpExecutionModeId %main FPFastMathDefault %float %none
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%none = OpConstant %int 0
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("execution mode must not be specified multiple times "
|
|
"for the same entry point and operands"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FloatControls2FPFastMathDefaultDifferentOperand) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Float16
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %none
|
|
OpExecutionModeId %main FPFastMathDefault %half %none
|
|
%void = OpTypeVoid
|
|
%float = OpTypeFloat 32
|
|
%int = OpTypeInt 32 0
|
|
%none = OpConstant %int 0
|
|
%half = OpTypeFloat 16
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderInterlockVertexBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FragmentShaderPixelInterlockEXT
|
|
OpExtension "SPV_EXT_fragment_shader_interlock"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpExecutionMode %main PixelInterlockOrderedEXT
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Execution mode can only be used with the Fragment execution model"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderInterlockTooManyModesBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FragmentShaderPixelInterlockEXT
|
|
OpCapability FragmentShaderSampleInterlockEXT
|
|
OpExtension "SPV_EXT_fragment_shader_interlock"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main PixelInterlockOrderedEXT
|
|
OpExecutionMode %main SampleInterlockOrderedEXT
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points can specify at most "
|
|
"one fragment shader interlock execution mode"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderInterlockNoModeBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FragmentShaderPixelInterlockEXT
|
|
OpExtension "SPV_EXT_fragment_shader_interlock"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%func = OpFunction %void None %void_fn
|
|
%entryf = OpLabel
|
|
OpBeginInvocationInterlockEXT
|
|
OpEndInvocationInterlockEXT
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%1 = OpFunctionCall %void %func
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT require a "
|
|
"fragment shader interlock execution mode"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderInterlockGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FragmentShaderPixelInterlockEXT
|
|
OpExtension "SPV_EXT_fragment_shader_interlock"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main PixelInterlockOrderedEXT
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%func = OpFunction %void None %void_fn
|
|
%entryf = OpLabel
|
|
OpBeginInvocationInterlockEXT
|
|
OpEndInvocationInterlockEXT
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%1 = OpFunctionCall %void %func
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
|
|
TEST_F(ValidateMode, FragmentShaderStencilRefFrontTooManyModesBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability StencilExportEXT
|
|
OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
|
|
OpExtension "SPV_EXT_shader_stencil_export"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main EarlyAndLateFragmentTestsAMD
|
|
OpExecutionMode %main StencilRefLessFrontAMD
|
|
OpExecutionMode %main StencilRefGreaterFrontAMD
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points can specify at most "
|
|
"one of StencilRefUnchangedFrontAMD, "
|
|
"StencilRefLessFrontAMD or StencilRefGreaterFrontAMD "
|
|
"execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderStencilRefBackTooManyModesBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability StencilExportEXT
|
|
OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
|
|
OpExtension "SPV_EXT_shader_stencil_export"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main EarlyAndLateFragmentTestsAMD
|
|
OpExecutionMode %main StencilRefLessBackAMD
|
|
OpExecutionMode %main StencilRefGreaterBackAMD
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Fragment execution model entry points can specify at most "
|
|
"one of StencilRefUnchangedBackAMD, "
|
|
"StencilRefLessBackAMD or StencilRefGreaterBackAMD "
|
|
"execution modes."));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderStencilRefFrontGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability StencilExportEXT
|
|
OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
|
|
OpExtension "SPV_EXT_shader_stencil_export"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main EarlyAndLateFragmentTestsAMD
|
|
OpExecutionMode %main StencilRefLessFrontAMD
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderStencilRefBackGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability StencilExportEXT
|
|
OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
|
|
OpExtension "SPV_EXT_shader_stencil_export"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpExecutionMode %main EarlyAndLateFragmentTestsAMD
|
|
OpExecutionMode %main StencilRefLessBackAMD
|
|
)" + kVoidFunction;
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderDemoteVertexBad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability DemoteToHelperInvocationEXT
|
|
OpExtension "SPV_EXT_demote_to_helper_invocation"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
%bool = OpTypeBool
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpDemoteToHelperInvocationEXT
|
|
%1 = OpIsHelperInvocationEXT %bool
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"OpDemoteToHelperInvocationEXT requires Fragment execution model"));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("OpIsHelperInvocationEXT requires Fragment execution model"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderDemoteGood) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability DemoteToHelperInvocationEXT
|
|
OpExtension "SPV_EXT_demote_to_helper_invocation"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%bool = OpTypeBool
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpDemoteToHelperInvocationEXT
|
|
%1 = OpIsHelperInvocationEXT %bool
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderDemoteBadType) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability DemoteToHelperInvocationEXT
|
|
OpExtension "SPV_EXT_demote_to_helper_invocation"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%u32 = OpTypeInt 32 0
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpDemoteToHelperInvocationEXT
|
|
%1 = OpIsHelperInvocationEXT %u32
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Expected bool scalar type as Result Type"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, LocalSizeIdVulkan1p3DoesNotRequireOption) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_1 = OpConstant %int 1
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
|
|
}
|
|
|
|
TEST_F(ValidateMode, MaximalReconvergenceRequiresExtension) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionMode %main MaximallyReconvergesKHR
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("(6023) requires one of these extensions: "
|
|
"SPV_KHR_maximal_reconvergence "));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultNotExecutionModeId) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionMode %main FPFastMathDefault %int_0 %int_0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("OpExecutionMode is only valid when the Mode operand "
|
|
"is an execution mode that takes no Extra Operands, or "
|
|
"takes Extra Operands that are not id operands"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultNotAType) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %int_0 %int_0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"The Target Type operand must be a floating-point scalar type"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultNotAFloatType) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %int %int_0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"The Target Type operand must be a floating-point scalar type"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultNotAFloatScalarType) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float2 %int_0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%float2 = OpTypeVector %float 2
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"The Target Type operand must be a floating-point scalar type"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultSpecConstant) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %int_0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpSpecConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("The Fast Math Default operand must be a "
|
|
"non-specialization constant"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultInvalidMask) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 524288
|
|
%float = OpTypeFloat 32
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("The Fast Math Default operand is an invalid bitmask value"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultContainsFast) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 16
|
|
%float = OpTypeFloat 32
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("The Fast Math Default operand must not include Fast"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowReassoc) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 327680
|
|
%float = OpTypeFloat 32
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("The Fast Math Default operand must include AllowContract and "
|
|
"AllowReassoc when AllowTransform is specified"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowContract) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 393216
|
|
%float = OpTypeFloat 32
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("The Fast Math Default operand must include AllowContract and "
|
|
"AllowReassoc when AllowTransform is specified"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingContractAndReassoc) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 262144
|
|
%float = OpTypeFloat 32
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("The Fast Math Default operand must include AllowContract and "
|
|
"AllowReassoc when AllowTransform is specified"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultSignedZeroInfNanPreserve) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpCapability SignedZeroInfNanPreserve
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpExtension "SPV_KHR_float_controls"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
OpExecutionMode %main SignedZeroInfNanPreserve 32
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("FPFastMathDefault and SignedZeroInfNanPreserve execution "
|
|
"modes cannot be applied to the same entry point"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultConractionOff) {
|
|
const std::string spirv = R"(
|
|
OpCapability Kernel
|
|
OpCapability Addresses
|
|
OpCapability FloatControls2
|
|
OpCapability SignedZeroInfNanPreserve
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpExtension "SPV_KHR_float_controls"
|
|
OpMemoryModel Physical64 OpenCL
|
|
OpEntryPoint Kernel %main "main"
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
OpExecutionMode %main ContractionOff
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("FPFastMathDefault and ContractionOff execution modes "
|
|
"cannot be applied to the same entry point"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultNoContractionNotInCallTree) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %add NoContraction
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%zero = OpConstant %float 0
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%func = OpFunction %void None %void_fn
|
|
%func_entry = OpLabel
|
|
%add = OpFAdd %float %zero %zero
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %add NoContraction
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%zero = OpConstant %float 0
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall %void %func
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%func = OpFunction %void None %void_fn
|
|
%func_entry = OpLabel
|
|
%add = OpFAdd %float %zero %zero
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("NoContraction cannot be used by an entry point with "
|
|
"the FPFastMathDefault execution mode"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree2) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Kernel
|
|
OpCapability Addresses
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Physical64 OpenCL
|
|
OpEntryPoint Kernel %main "main"
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
OpDecorate %const NoContraction
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%zero = OpConstant %float 0
|
|
%const = OpSpecConstantOp %float FAdd %zero %zero
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall %void %func
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%func = OpFunction %void None %void_fn
|
|
%func_entry = OpLabel
|
|
%add = OpFAdd %float %const %zero
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("NoContraction cannot be used by an entry point with "
|
|
"the FPFastMathDefault execution mode"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultFastMathFastNotInCallTree) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %add FPFastMathMode Fast
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%zero = OpConstant %float 0
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%func = OpFunction %void None %void_fn
|
|
%func_entry = OpLabel
|
|
%add = OpFAdd %float %zero %zero
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %add FPFastMathMode Fast
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%zero = OpConstant %float 0
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall %void %func
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%func = OpFunction %void None %void_fn
|
|
%func_entry = OpLabel
|
|
%add = OpFAdd %float %zero %zero
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("FPFastMathMode Fast cannot be used by an entry point "
|
|
"with the FPFastMathDefault execution mode"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree2) {
|
|
const std::string spirv = R"(
|
|
OpCapability Kernel
|
|
OpCapability Addresses
|
|
OpCapability FloatControls2
|
|
OpExtension "SPV_KHR_float_controls2"
|
|
OpMemoryModel Physical64 OpenCL
|
|
OpEntryPoint Kernel %main "main"
|
|
OpExecutionModeId %main FPFastMathDefault %float %constant
|
|
OpDecorate %const FPFastMathMode Fast
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%constant = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%zero = OpConstant %float 0
|
|
%const = OpSpecConstantOp %float FAdd %zero %zero
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall %void %func
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%func = OpFunction %void None %void_fn
|
|
%func_entry = OpLabel
|
|
%add = OpFAdd %float %const %zero
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("FPFastMathMode Fast cannot be used by an entry point "
|
|
"with the FPFastMathDefault execution mode"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderRequireFullQuadsKHR) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability GroupNonUniform
|
|
OpCapability GroupNonUniformVote
|
|
OpCapability GroupNonUniformBallot
|
|
OpCapability QuadControlKHR
|
|
OpExtension "SPV_KHR_quad_control"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpExecutionMode %4 RequireFullQuadsKHR
|
|
OpDecorate %17 Location 0
|
|
OpDecorate %31 BuiltIn HelperInvocation
|
|
OpDecorate %40 Location 0
|
|
OpDecorate %44 DescriptorSet 0
|
|
OpDecorate %44 Binding 0
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 0
|
|
%7 = OpTypeVector %6 4
|
|
%8 = OpTypePointer Function %7
|
|
%10 = OpTypeBool
|
|
%11 = OpConstantTrue %10
|
|
%12 = OpConstant %6 7
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeVector %14 4
|
|
%16 = OpTypePointer Output %15
|
|
%17 = OpVariable %16 Output
|
|
%18 = OpConstant %14 1
|
|
%19 = OpConstant %14 0
|
|
%20 = OpConstantComposite %15 %18 %19 %19 %18
|
|
%23 = OpConstant %6 4
|
|
%27 = OpConstant %6 1
|
|
%28 = OpTypePointer Output %14
|
|
%30 = OpTypePointer Input %10
|
|
%31 = OpVariable %30 Input
|
|
%36 = OpConstant %6 2
|
|
%38 = OpTypeVector %14 2
|
|
%39 = OpTypePointer Input %38
|
|
%40 = OpVariable %39 Input
|
|
%41 = OpTypeImage %14 2D 0 0 0 1 Unknown
|
|
%42 = OpTypeSampledImage %41
|
|
%43 = OpTypePointer UniformConstant %42
|
|
%44 = OpVariable %43 UniformConstant
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%9 = OpVariable %8 Function
|
|
%13 = OpGroupNonUniformBallot %7 %12 %11
|
|
OpStore %9 %13
|
|
OpStore %17 %20
|
|
%21 = OpLoad %7 %9
|
|
%22 = OpGroupNonUniformBallotBitCount %6 %12 Reduce %21
|
|
%24 = OpIEqual %10 %22 %23
|
|
OpSelectionMerge %26 None
|
|
OpBranchConditional %24 %25 %26
|
|
%25 = OpLabel
|
|
%29 = OpAccessChain %28 %17 %27
|
|
OpStore %29 %18
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%32 = OpLoad %10 %31
|
|
%33 = OpGroupNonUniformAny %10 %12 %32
|
|
OpSelectionMerge %35 None
|
|
OpBranchConditional %33 %34 %35
|
|
%34 = OpLabel
|
|
%37 = OpAccessChain %28 %17 %36
|
|
OpStore %37 %18
|
|
OpBranch %35
|
|
%35 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Execution mode can only be used with the Fragment execution model"));
|
|
}
|
|
|
|
TEST_F(ValidateMode, FragmentShaderQuadDerivativesKHR) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability GroupNonUniform
|
|
OpCapability GroupNonUniformVote
|
|
OpCapability QuadControlKHR
|
|
OpExtension "SPV_KHR_quad_control"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpExecutionMode %4 QuadDerivativesKHR
|
|
OpDecorate %12 BuiltIn FragCoord
|
|
OpDecorate %41 Location 0
|
|
OpDecorate %45 DescriptorSet 0
|
|
OpDecorate %45 Binding 0
|
|
OpDecorate %49 Location 0
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeBool
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpTypeFloat 32
|
|
%10 = OpTypeVector %9 4
|
|
%11 = OpTypePointer Input %10
|
|
%12 = OpVariable %11 Input
|
|
%13 = OpTypeInt 32 0
|
|
%14 = OpConstant %13 1
|
|
%15 = OpTypePointer Input %9
|
|
%18 = OpConstant %9 8.5
|
|
%21 = OpConstant %9 0.100000001
|
|
%25 = OpConstant %13 0
|
|
%28 = OpConstant %9 3.5
|
|
%30 = OpConstant %9 6
|
|
%36 = OpConstant %13 7
|
|
%40 = OpTypePointer Output %10
|
|
%41 = OpVariable %40 Output
|
|
%42 = OpTypeImage %9 2D 0 0 0 1 Unknown
|
|
%43 = OpTypeSampledImage %42
|
|
%44 = OpTypePointer UniformConstant %43
|
|
%45 = OpVariable %44 UniformConstant
|
|
%47 = OpTypeVector %9 2
|
|
%48 = OpTypePointer Input %47
|
|
%49 = OpVariable %48 Input
|
|
%53 = OpConstant %9 0.899999976
|
|
%54 = OpConstant %9 0.200000003
|
|
%55 = OpConstant %9 1
|
|
%56 = OpConstantComposite %10 %53 %54 %54 %55
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%16 = OpAccessChain %15 %12 %14
|
|
%17 = OpLoad %9 %16
|
|
%19 = OpFSub %9 %17 %18
|
|
%20 = OpExtInst %9 %1 FAbs %19
|
|
%22 = OpFOrdLessThan %6 %20 %21
|
|
OpSelectionMerge %24 None
|
|
OpBranchConditional %22 %23 %24
|
|
%23 = OpLabel
|
|
%26 = OpAccessChain %15 %12 %25
|
|
%27 = OpLoad %9 %26
|
|
%29 = OpFSub %9 %27 %28
|
|
%31 = OpFMod %9 %29 %30
|
|
%33 = OpFOrdLessThan %6 %31 %21
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%34 = OpPhi %6 %22 %5 %33 %23
|
|
OpStore %8 %34
|
|
%35 = OpLoad %6 %8
|
|
%37 = OpGroupNonUniformAny %6 %36 %35
|
|
OpSelectionMerge %39 None
|
|
OpBranchConditional %37 %38 %52
|
|
%38 = OpLabel
|
|
%46 = OpLoad %43 %45
|
|
%50 = OpLoad %47 %49
|
|
%51 = OpImageSampleImplicitLod %10 %46 %50
|
|
OpStore %41 %51
|
|
OpBranch %39
|
|
%52 = OpLabel
|
|
OpStore %41 %56
|
|
OpBranch %39
|
|
%39 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_THAT(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr(
|
|
"Execution mode can only be used with the Fragment execution model"));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace val
|
|
} // namespace spvtools
|