mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-08-29 06:55:56 +00:00
Bug: tint:1580 Change-Id: Ib3a5ff5c567e19eca1ba8fb3c2f7e83dee68e2a0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94686 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
313 lines
10 KiB
C++
313 lines
10 KiB
C++
// Copyright 2020 The Tint Authors.
|
|
//
|
|
// 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 "src/tint/ast/stage_attribute.h"
|
|
#include "src/tint/ast/workgroup_attribute.h"
|
|
#include "src/tint/writer/spirv/spv_dump.h"
|
|
#include "src/tint/writer/spirv/test_helper.h"
|
|
|
|
using namespace tint::number_suffixes; // NOLINT
|
|
|
|
namespace tint::writer::spirv {
|
|
namespace {
|
|
|
|
using BuilderTest = TestHelper;
|
|
|
|
TEST_F(BuilderTest, Attribute_Stage) {
|
|
auto* func = Func("main", {}, ty.void_(), {},
|
|
{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.entry_points()),
|
|
R"(OpEntryPoint Fragment %3 "main"
|
|
)");
|
|
}
|
|
|
|
struct FunctionStageData {
|
|
ast::PipelineStage stage;
|
|
SpvExecutionModel model;
|
|
};
|
|
inline std::ostream& operator<<(std::ostream& out, FunctionStageData data) {
|
|
out << data.stage;
|
|
return out;
|
|
}
|
|
using Attribute_StageTest = TestParamHelper<FunctionStageData>;
|
|
TEST_P(Attribute_StageTest, Emit) {
|
|
auto params = GetParam();
|
|
|
|
const ast::Variable* var = nullptr;
|
|
const ast::Type* ret_type = nullptr;
|
|
ast::AttributeList ret_type_attrs;
|
|
ast::StatementList body;
|
|
if (params.stage == ast::PipelineStage::kVertex) {
|
|
ret_type = ty.vec4<f32>();
|
|
ret_type_attrs.push_back(Builtin(ast::Builtin::kPosition));
|
|
body.push_back(Return(Construct(ty.vec4<f32>())));
|
|
} else {
|
|
ret_type = ty.void_();
|
|
}
|
|
|
|
auto deco_list = ast::AttributeList{Stage(params.stage)};
|
|
if (params.stage == ast::PipelineStage::kCompute) {
|
|
deco_list.push_back(WorkgroupSize(1_i));
|
|
}
|
|
|
|
auto* func = Func("main", {}, ret_type, body, deco_list, ret_type_attrs);
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
if (var) {
|
|
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
|
|
}
|
|
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
|
|
|
|
auto preamble = b.entry_points();
|
|
ASSERT_GE(preamble.size(), 1u);
|
|
EXPECT_EQ(preamble[0].opcode(), spv::Op::OpEntryPoint);
|
|
|
|
ASSERT_GE(preamble[0].operands().size(), 3u);
|
|
EXPECT_EQ(std::get<uint32_t>(preamble[0].operands()[0]), static_cast<uint32_t>(params.model));
|
|
}
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
BuilderTest,
|
|
Attribute_StageTest,
|
|
testing::Values(FunctionStageData{ast::PipelineStage::kVertex, SpvExecutionModelVertex},
|
|
FunctionStageData{ast::PipelineStage::kFragment, SpvExecutionModelFragment},
|
|
FunctionStageData{ast::PipelineStage::kCompute, SpvExecutionModelGLCompute}));
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_Fragment_OriginUpperLeft) {
|
|
auto* func = Func("main", {}, ty.void_(), {},
|
|
{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()),
|
|
R"(OpExecutionMode %3 OriginUpperLeft
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Default) {
|
|
auto* func =
|
|
Func("main", {}, ty.void_(), {}, {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()),
|
|
R"(OpExecutionMode %3 LocalSize 1 1 1
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Literals) {
|
|
auto* func = Func("main", {}, ty.void_(), {},
|
|
{
|
|
WorkgroupSize(2_i, 4_i, 6_i),
|
|
Stage(ast::PipelineStage::kCompute),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()),
|
|
R"(OpExecutionMode %3 LocalSize 2 4 6
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Let) {
|
|
GlobalLet("width", ty.i32(), Construct(ty.i32(), 2_i));
|
|
GlobalLet("height", ty.i32(), Construct(ty.i32(), 3_i));
|
|
GlobalLet("depth", ty.i32(), Construct(ty.i32(), 4_i));
|
|
auto* func = Func("main", {}, ty.void_(), {},
|
|
{
|
|
WorkgroupSize("width", "height", "depth"),
|
|
Stage(ast::PipelineStage::kCompute),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()),
|
|
R"(OpExecutionMode %3 LocalSize 2 3 4
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Const) {
|
|
GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
|
|
GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
|
|
GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
|
|
auto* func = Func("main", {}, ty.void_(), {},
|
|
{
|
|
WorkgroupSize("width", "height", "depth"),
|
|
Stage(ast::PipelineStage::kCompute),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()),
|
|
R"(OpExecutionMode %3 LocalSize 2 3 4
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_OverridableConst) {
|
|
Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
|
|
Override("height", ty.i32(), Construct(ty.i32(), 3_i), {Id(8u)});
|
|
Override("depth", ty.i32(), Construct(ty.i32(), 4_i), {Id(9u)});
|
|
auto* func = Func("main", {}, ty.void_(), {},
|
|
{
|
|
WorkgroupSize("width", "height", "depth"),
|
|
Stage(ast::PipelineStage::kCompute),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
|
|
EXPECT_EQ(DumpInstructions(b.types()),
|
|
R"(%2 = OpTypeInt 32 0
|
|
%1 = OpTypeVector %2 3
|
|
%4 = OpSpecConstant %2 2
|
|
%5 = OpSpecConstant %2 3
|
|
%6 = OpSpecConstant %2 4
|
|
%3 = OpSpecConstantComposite %1 %4 %5 %6
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.annots()),
|
|
R"(OpDecorate %4 SpecId 7
|
|
OpDecorate %5 SpecId 8
|
|
OpDecorate %6 SpecId 9
|
|
OpDecorate %3 BuiltIn WorkgroupSize
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndLet) {
|
|
Override("height", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
|
|
GlobalLet("depth", ty.i32(), Construct(ty.i32(), 3_i));
|
|
auto* func = Func("main", {}, ty.void_(), {},
|
|
{
|
|
WorkgroupSize(4_i, "height", "depth"),
|
|
Stage(ast::PipelineStage::kCompute),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
|
|
EXPECT_EQ(DumpInstructions(b.types()),
|
|
R"(%2 = OpTypeInt 32 0
|
|
%1 = OpTypeVector %2 3
|
|
%4 = OpConstant %2 4
|
|
%5 = OpSpecConstant %2 2
|
|
%6 = OpConstant %2 3
|
|
%3 = OpSpecConstantComposite %1 %4 %5 %6
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.annots()),
|
|
R"(OpDecorate %5 SpecId 7
|
|
OpDecorate %3 BuiltIn WorkgroupSize
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndConst) {
|
|
Override("height", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
|
|
GlobalConst("depth", ty.i32(), Construct(ty.i32(), 3_i));
|
|
auto* func = Func("main", {}, ty.void_(), {},
|
|
{
|
|
WorkgroupSize(4_i, "height", "depth"),
|
|
Stage(ast::PipelineStage::kCompute),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
|
|
EXPECT_EQ(DumpInstructions(b.types()),
|
|
R"(%2 = OpTypeInt 32 0
|
|
%1 = OpTypeVector %2 3
|
|
%4 = OpConstant %2 4
|
|
%5 = OpSpecConstant %2 2
|
|
%6 = OpConstant %2 3
|
|
%3 = OpSpecConstantComposite %1 %4 %5 %6
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.annots()),
|
|
R"(OpDecorate %5 SpecId 7
|
|
OpDecorate %3 BuiltIn WorkgroupSize
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_MultipleFragment) {
|
|
auto* func1 = Func("main1", {}, ty.void_(), {},
|
|
{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
auto* func2 = Func("main2", {}, ty.void_(), {},
|
|
{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
spirv::Builder& b = Build();
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(func1)) << b.error();
|
|
ASSERT_TRUE(b.GenerateFunction(func2)) << b.error();
|
|
EXPECT_EQ(DumpBuilder(b),
|
|
R"(OpEntryPoint Fragment %3 "main1"
|
|
OpEntryPoint Fragment %5 "main2"
|
|
OpExecutionMode %3 OriginUpperLeft
|
|
OpExecutionMode %5 OriginUpperLeft
|
|
OpName %3 "main1"
|
|
OpName %5 "main2"
|
|
%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%3 = OpFunction %2 None %1
|
|
%4 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%5 = OpFunction %2 None %1
|
|
%6 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)");
|
|
}
|
|
|
|
TEST_F(BuilderTest, Decoration_ExecutionMode_FragDepth) {
|
|
Func("main", {}, ty.f32(),
|
|
{
|
|
Return(Expr(1_f)),
|
|
},
|
|
{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
},
|
|
{
|
|
Builtin(ast::Builtin::kFragDepth),
|
|
});
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build());
|
|
|
|
EXPECT_EQ(DumpInstructions(b.execution_modes()),
|
|
R"(OpExecutionMode %11 OriginUpperLeft
|
|
OpExecutionMode %11 DepthReplacing
|
|
)");
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace tint::writer::spirv
|