transform: Add NumWorkgroupsFromUniform transform
This transform scans entry points for struct parameters that contain the num_workgroups builtin, and replace accesses to these members with a value loaded from a uniform buffer. This will be used by the HLSL backend to implement the num_workgroups builtin. Bug: tint:752 Change-Id: Iefab3b14af8a08a6135348fded368a06d932e915 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/63961 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
1bb637195b
commit
77a25c060f
14
src/BUILD.gn
14
src/BUILD.gn
|
@ -143,10 +143,10 @@ template("libtint_source_set") {
|
||||||
"${tint_spirv_headers_dir}:spv_headers",
|
"${tint_spirv_headers_dir}:spv_headers",
|
||||||
"${tint_spirv_tools_dir}:spvtools_core_enums_unified1",
|
"${tint_spirv_tools_dir}:spvtools_core_enums_unified1",
|
||||||
"${tint_spirv_tools_dir}:spvtools_core_tables_unified1",
|
"${tint_spirv_tools_dir}:spvtools_core_tables_unified1",
|
||||||
"${tint_spirv_tools_dir}:spvtools_language_header_cldebuginfo100",
|
|
||||||
"${tint_spirv_tools_dir}:spvtools_language_header_vkdebuginfo100",
|
|
||||||
"${tint_spirv_tools_dir}:spvtools_language_header_debuginfo",
|
|
||||||
"${tint_spirv_tools_dir}:spvtools_headers",
|
"${tint_spirv_tools_dir}:spvtools_headers",
|
||||||
|
"${tint_spirv_tools_dir}:spvtools_language_header_cldebuginfo100",
|
||||||
|
"${tint_spirv_tools_dir}:spvtools_language_header_debuginfo",
|
||||||
|
"${tint_spirv_tools_dir}:spvtools_language_header_vkdebuginfo100",
|
||||||
]
|
]
|
||||||
|
|
||||||
if (defined(invoker.configs)) {
|
if (defined(invoker.configs)) {
|
||||||
|
@ -369,8 +369,8 @@ libtint_source_set("libtint_core_all_src") {
|
||||||
"reader/reader.cc",
|
"reader/reader.cc",
|
||||||
"reader/reader.h",
|
"reader/reader.h",
|
||||||
"resolver/resolver.cc",
|
"resolver/resolver.cc",
|
||||||
"resolver/resolver_constants.cc",
|
|
||||||
"resolver/resolver.h",
|
"resolver/resolver.h",
|
||||||
|
"resolver/resolver_constants.cc",
|
||||||
"scope_stack.h",
|
"scope_stack.h",
|
||||||
"sem/array.h",
|
"sem/array.h",
|
||||||
"sem/atomic_type.h",
|
"sem/atomic_type.h",
|
||||||
|
@ -448,6 +448,8 @@ libtint_source_set("libtint_core_all_src") {
|
||||||
"transform/manager.h",
|
"transform/manager.h",
|
||||||
"transform/module_scope_var_to_entry_point_param.cc",
|
"transform/module_scope_var_to_entry_point_param.cc",
|
||||||
"transform/module_scope_var_to_entry_point_param.h",
|
"transform/module_scope_var_to_entry_point_param.h",
|
||||||
|
"transform/num_workgroups_from_uniform.cc",
|
||||||
|
"transform/num_workgroups_from_uniform.h",
|
||||||
"transform/pad_array_elements.cc",
|
"transform/pad_array_elements.cc",
|
||||||
"transform/pad_array_elements.h",
|
"transform/pad_array_elements.h",
|
||||||
"transform/promote_initializers_to_const_var.cc",
|
"transform/promote_initializers_to_const_var.cc",
|
||||||
|
@ -614,9 +616,7 @@ libtint_source_set("libtint_spv_reader_src") {
|
||||||
"${tint_spirv_tools_dir}/:spvtools_opt",
|
"${tint_spirv_tools_dir}/:spvtools_opt",
|
||||||
]
|
]
|
||||||
|
|
||||||
public_configs = [
|
public_configs = [ "${tint_spirv_tools_dir}/:spvtools_internal_config" ]
|
||||||
"${tint_spirv_tools_dir}/:spvtools_internal_config"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
libtint_source_set("libtint_spv_writer_src") {
|
libtint_source_set("libtint_spv_writer_src") {
|
||||||
|
|
|
@ -318,6 +318,8 @@ set(TINT_LIB_SRCS
|
||||||
transform/manager.h
|
transform/manager.h
|
||||||
transform/module_scope_var_to_entry_point_param.cc
|
transform/module_scope_var_to_entry_point_param.cc
|
||||||
transform/module_scope_var_to_entry_point_param.h
|
transform/module_scope_var_to_entry_point_param.h
|
||||||
|
transform/num_workgroups_from_uniform.cc
|
||||||
|
transform/num_workgroups_from_uniform.h
|
||||||
transform/pad_array_elements.cc
|
transform/pad_array_elements.cc
|
||||||
transform/pad_array_elements.h
|
transform/pad_array_elements.h
|
||||||
transform/promote_initializers_to_const_var.cc
|
transform/promote_initializers_to_const_var.cc
|
||||||
|
@ -932,6 +934,7 @@ if(${TINT_BUILD_TESTS})
|
||||||
transform/inline_pointer_lets_test.cc
|
transform/inline_pointer_lets_test.cc
|
||||||
transform/loop_to_for_loop_test.cc
|
transform/loop_to_for_loop_test.cc
|
||||||
transform/module_scope_var_to_entry_point_param_test.cc
|
transform/module_scope_var_to_entry_point_param_test.cc
|
||||||
|
transform/num_workgroups_from_uniform_test.cc
|
||||||
transform/pad_array_elements_test.cc
|
transform/pad_array_elements_test.cc
|
||||||
transform/promote_initializers_to_const_var_test.cc
|
transform/promote_initializers_to_const_var_test.cc
|
||||||
transform/renamer_test.cc
|
transform/renamer_test.cc
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
// Copyright 2021 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/transform/num_workgroups_from_uniform.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "src/program_builder.h"
|
||||||
|
#include "src/sem/function.h"
|
||||||
|
#include "src/transform/canonicalize_entry_point_io.h"
|
||||||
|
#include "src/utils/hash.h"
|
||||||
|
|
||||||
|
TINT_INSTANTIATE_TYPEINFO(tint::transform::NumWorkgroupsFromUniform);
|
||||||
|
TINT_INSTANTIATE_TYPEINFO(tint::transform::NumWorkgroupsFromUniform::Config);
|
||||||
|
|
||||||
|
namespace tint {
|
||||||
|
namespace transform {
|
||||||
|
namespace {
|
||||||
|
/// Accessor describes the identifiers used in a member accessor that is being
|
||||||
|
/// used to retrieve the num_workgroups builtin from a parameter.
|
||||||
|
struct Accessor {
|
||||||
|
Symbol param;
|
||||||
|
Symbol member;
|
||||||
|
|
||||||
|
/// Equality operator
|
||||||
|
bool operator==(const Accessor& other) const {
|
||||||
|
return param == other.param && member == other.member;
|
||||||
|
}
|
||||||
|
/// Hash function
|
||||||
|
struct Hasher {
|
||||||
|
size_t operator()(const Accessor& a) const {
|
||||||
|
return utils::Hash(a.param, a.member);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NumWorkgroupsFromUniform::NumWorkgroupsFromUniform() = default;
|
||||||
|
NumWorkgroupsFromUniform::~NumWorkgroupsFromUniform() = default;
|
||||||
|
|
||||||
|
void NumWorkgroupsFromUniform::Run(CloneContext& ctx,
|
||||||
|
const DataMap& inputs,
|
||||||
|
DataMap&) {
|
||||||
|
if (!Requires<CanonicalizeEntryPointIO>(ctx)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* cfg = inputs.Get<Config>();
|
||||||
|
if (cfg == nullptr) {
|
||||||
|
ctx.dst->Diagnostics().add_error(
|
||||||
|
diag::System::Transform,
|
||||||
|
"missing transform data for " + std::string(TypeInfo().name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* kNumWorkgroupsMemberName = "num_workgroups";
|
||||||
|
|
||||||
|
// Find all entry point parameters that declare the num_workgroups builtin.
|
||||||
|
std::unordered_set<Accessor, Accessor::Hasher> to_replace;
|
||||||
|
for (auto* func : ctx.src->AST().Functions()) {
|
||||||
|
// num_workgroups is only valid for compute stages.
|
||||||
|
if (func->pipeline_stage() != ast::PipelineStage::kCompute) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto* param : ctx.src->Sem().Get(func)->Parameters()) {
|
||||||
|
// Because the CanonicalizeEntryPointIO transform has been run, builtins
|
||||||
|
// will only appear as struct members.
|
||||||
|
auto* str = param->Type()->As<sem::Struct>();
|
||||||
|
if (!str) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto* member : str->Members()) {
|
||||||
|
auto* builtin = ast::GetDecoration<ast::BuiltinDecoration>(
|
||||||
|
member->Declaration()->decorations());
|
||||||
|
if (!builtin || builtin->value() != ast::Builtin::kNumWorkgroups) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture the symbols that would be used to access this member, which
|
||||||
|
// we will replace later. We currently have no way to get from the
|
||||||
|
// parameter directly to the member accessor expressions that use it.
|
||||||
|
to_replace.insert(
|
||||||
|
{param->Declaration()->symbol(), member->Declaration()->symbol()});
|
||||||
|
|
||||||
|
// Remove the struct member.
|
||||||
|
// The CanonicalizeEntryPointIO transform will have generated this
|
||||||
|
// struct uniquely for this particular entry point, so we know that
|
||||||
|
// there will be no other uses of this struct in the module and that we
|
||||||
|
// can safely modify it here.
|
||||||
|
ctx.Remove(str->Declaration()->members(), member->Declaration());
|
||||||
|
|
||||||
|
// If this is the only member, remove the struct and parameter too.
|
||||||
|
if (str->Members().size() == 1) {
|
||||||
|
ctx.Remove(func->params(), param->Declaration());
|
||||||
|
ctx.Remove(ctx.src->AST().GlobalDeclarations(), str->Declaration());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get (or create, on first call) the uniform buffer that will receive the
|
||||||
|
// number of workgroups.
|
||||||
|
ast::Variable* num_workgroups_ubo = nullptr;
|
||||||
|
auto get_ubo = [&]() {
|
||||||
|
if (!num_workgroups_ubo) {
|
||||||
|
auto* num_workgroups_struct = ctx.dst->Structure(
|
||||||
|
ctx.dst->Sym(),
|
||||||
|
{ctx.dst->Member(kNumWorkgroupsMemberName,
|
||||||
|
ctx.dst->ty.vec3(ctx.dst->ty.u32()))},
|
||||||
|
ast::DecorationList{ctx.dst->create<ast::StructBlockDecoration>()});
|
||||||
|
num_workgroups_ubo = ctx.dst->Global(
|
||||||
|
ctx.dst->Sym(), ctx.dst->ty.Of(num_workgroups_struct),
|
||||||
|
ast::StorageClass::kUniform,
|
||||||
|
ast::DecorationList{ctx.dst->GroupAndBinding(
|
||||||
|
cfg->ubo_binding.group, cfg->ubo_binding.binding)});
|
||||||
|
}
|
||||||
|
return num_workgroups_ubo;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Now replace all the places where the builtins are accessed with the value
|
||||||
|
// loaded from the uniform buffer.
|
||||||
|
for (auto* node : ctx.src->ASTNodes().Objects()) {
|
||||||
|
auto* accessor = node->As<ast::MemberAccessorExpression>();
|
||||||
|
if (!accessor) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto* ident = accessor->structure()->As<ast::IdentifierExpression>();
|
||||||
|
if (!ident) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_replace.count({ident->symbol(), accessor->member()->symbol()})) {
|
||||||
|
ctx.Replace(accessor, ctx.dst->MemberAccessor(get_ubo()->symbol(),
|
||||||
|
kNumWorkgroupsMemberName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
NumWorkgroupsFromUniform::Config::Config(sem::BindingPoint ubo_bp)
|
||||||
|
: ubo_binding(ubo_bp) {}
|
||||||
|
NumWorkgroupsFromUniform::Config::Config(const Config&) = default;
|
||||||
|
NumWorkgroupsFromUniform::Config::~Config() = default;
|
||||||
|
|
||||||
|
} // namespace transform
|
||||||
|
} // namespace tint
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright 2021 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.
|
||||||
|
|
||||||
|
#ifndef SRC_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
|
||||||
|
#define SRC_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
|
||||||
|
|
||||||
|
#include "src/sem/binding_point.h"
|
||||||
|
#include "src/transform/transform.h"
|
||||||
|
|
||||||
|
namespace tint {
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class CloneContext;
|
||||||
|
|
||||||
|
namespace transform {
|
||||||
|
|
||||||
|
/// NumWorkgroupsFromUniform is a transform that implements the `num_workgroups`
|
||||||
|
/// builtin by loading it from a uniform buffer.
|
||||||
|
///
|
||||||
|
/// The generated uniform buffer will have the form:
|
||||||
|
/// ```
|
||||||
|
/// [[block]]
|
||||||
|
/// struct num_workgroups_struct {
|
||||||
|
/// num_workgroups : vec3<u32>;
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// [[group(0), binding(0)]]
|
||||||
|
/// var<uniform> num_workgroups_ubo : num_workgroups_struct;
|
||||||
|
/// ```
|
||||||
|
/// The binding group and number used for this uniform buffer is provided via
|
||||||
|
/// the `Config` transform input.
|
||||||
|
class NumWorkgroupsFromUniform
|
||||||
|
: public Castable<NumWorkgroupsFromUniform, Transform> {
|
||||||
|
public:
|
||||||
|
/// Constructor
|
||||||
|
NumWorkgroupsFromUniform();
|
||||||
|
/// Destructor
|
||||||
|
~NumWorkgroupsFromUniform() override;
|
||||||
|
|
||||||
|
/// Configuration options for the NumWorkgroupsFromUniform transform.
|
||||||
|
struct Config : public Castable<Data, transform::Data> {
|
||||||
|
/// Constructor
|
||||||
|
/// @param ubo_bp the binding point to use for the generated uniform buffer.
|
||||||
|
explicit Config(sem::BindingPoint ubo_bp);
|
||||||
|
|
||||||
|
/// Copy constructor
|
||||||
|
Config(const Config&);
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~Config() override;
|
||||||
|
|
||||||
|
/// The binding point to use for the generated uniform buffer.
|
||||||
|
sem::BindingPoint ubo_binding;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Runs the transform using the CloneContext built for transforming a
|
||||||
|
/// program. Run() is responsible for calling Clone() on the CloneContext.
|
||||||
|
/// @param ctx the CloneContext primed with the input program and
|
||||||
|
/// ProgramBuilder
|
||||||
|
/// @param inputs optional extra transform-specific input data
|
||||||
|
/// @param outputs optional extra transform-specific output data
|
||||||
|
void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace transform
|
||||||
|
} // namespace tint
|
||||||
|
|
||||||
|
#endif // SRC_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
|
|
@ -0,0 +1,342 @@
|
||||||
|
// Copyright 2021 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/transform/num_workgroups_from_uniform.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "src/transform/canonicalize_entry_point_io.h"
|
||||||
|
#include "src/transform/test_helper.h"
|
||||||
|
|
||||||
|
namespace tint {
|
||||||
|
namespace transform {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using NumWorkgroupsFromUniformTest = TransformTest;
|
||||||
|
|
||||||
|
TEST_F(NumWorkgroupsFromUniformTest, Error_MissingTransformData) {
|
||||||
|
auto* src = "";
|
||||||
|
|
||||||
|
auto* expect =
|
||||||
|
"error: missing transform data for "
|
||||||
|
"tint::transform::NumWorkgroupsFromUniform";
|
||||||
|
|
||||||
|
DataMap data;
|
||||||
|
data.Add<CanonicalizeEntryPointIO::Config>(
|
||||||
|
CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
|
||||||
|
auto got = Run<CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NumWorkgroupsFromUniformTest, Error_MissingCanonicalizeEntryPointIO) {
|
||||||
|
auto* src = "";
|
||||||
|
|
||||||
|
auto* expect =
|
||||||
|
"error: tint::transform::NumWorkgroupsFromUniform depends on "
|
||||||
|
"tint::transform::CanonicalizeEntryPointIO but the dependency was not "
|
||||||
|
"run";
|
||||||
|
|
||||||
|
auto got = Run<NumWorkgroupsFromUniform>(src);
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NumWorkgroupsFromUniformTest, Basic) {
|
||||||
|
auto* src = R"(
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main([[builtin(num_workgroups)]] num_wgs : vec3<u32>) {
|
||||||
|
let groups_x = num_wgs.x;
|
||||||
|
let groups_y = num_wgs.y;
|
||||||
|
let groups_z = num_wgs.z;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct tint_symbol_2 {
|
||||||
|
num_workgroups : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(30)]] var<uniform> tint_symbol_3 : tint_symbol_2;
|
||||||
|
|
||||||
|
fn main_inner(num_wgs : vec3<u32>) {
|
||||||
|
let groups_x = num_wgs.x;
|
||||||
|
let groups_y = num_wgs.y;
|
||||||
|
let groups_z = num_wgs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main() {
|
||||||
|
main_inner(tint_symbol_3.num_workgroups);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
DataMap data;
|
||||||
|
data.Add<CanonicalizeEntryPointIO::Config>(
|
||||||
|
CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
|
||||||
|
data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
|
||||||
|
auto got = Run<CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NumWorkgroupsFromUniformTest, StructOnlyMember) {
|
||||||
|
auto* src = R"(
|
||||||
|
struct Builtins {
|
||||||
|
[[builtin(num_workgroups)]] num_wgs : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main(in : Builtins) {
|
||||||
|
let groups_x = in.num_wgs.x;
|
||||||
|
let groups_y = in.num_wgs.y;
|
||||||
|
let groups_z = in.num_wgs.z;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct tint_symbol_2 {
|
||||||
|
num_workgroups : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(30)]] var<uniform> tint_symbol_3 : tint_symbol_2;
|
||||||
|
|
||||||
|
struct Builtins {
|
||||||
|
num_wgs : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main_inner(in : Builtins) {
|
||||||
|
let groups_x = in.num_wgs.x;
|
||||||
|
let groups_y = in.num_wgs.y;
|
||||||
|
let groups_z = in.num_wgs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main() {
|
||||||
|
main_inner(Builtins(tint_symbol_3.num_workgroups));
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
DataMap data;
|
||||||
|
data.Add<CanonicalizeEntryPointIO::Config>(
|
||||||
|
CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
|
||||||
|
data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
|
||||||
|
auto got = Run<CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NumWorkgroupsFromUniformTest, StructMultipleMembers) {
|
||||||
|
auto* src = R"(
|
||||||
|
struct Builtins {
|
||||||
|
[[builtin(global_invocation_id)]] gid : vec3<u32>;
|
||||||
|
[[builtin(num_workgroups)]] num_wgs : vec3<u32>;
|
||||||
|
[[builtin(workgroup_id)]] wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main(in : Builtins) {
|
||||||
|
let groups_x = in.num_wgs.x;
|
||||||
|
let groups_y = in.num_wgs.y;
|
||||||
|
let groups_z = in.num_wgs.z;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct tint_symbol_2 {
|
||||||
|
num_workgroups : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(30)]] var<uniform> tint_symbol_3 : tint_symbol_2;
|
||||||
|
|
||||||
|
struct Builtins {
|
||||||
|
gid : vec3<u32>;
|
||||||
|
num_wgs : vec3<u32>;
|
||||||
|
wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tint_symbol_1 {
|
||||||
|
[[builtin(global_invocation_id)]]
|
||||||
|
gid : vec3<u32>;
|
||||||
|
[[builtin(workgroup_id)]]
|
||||||
|
wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main_inner(in : Builtins) {
|
||||||
|
let groups_x = in.num_wgs.x;
|
||||||
|
let groups_y = in.num_wgs.y;
|
||||||
|
let groups_z = in.num_wgs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main(tint_symbol : tint_symbol_1) {
|
||||||
|
main_inner(Builtins(tint_symbol.gid, tint_symbol_3.num_workgroups, tint_symbol.wgid));
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
DataMap data;
|
||||||
|
data.Add<CanonicalizeEntryPointIO::Config>(
|
||||||
|
CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
|
||||||
|
data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
|
||||||
|
auto got = Run<CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NumWorkgroupsFromUniformTest, MultipleEntryPoints) {
|
||||||
|
auto* src = R"(
|
||||||
|
struct Builtins1 {
|
||||||
|
[[builtin(num_workgroups)]] num_wgs : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Builtins2 {
|
||||||
|
[[builtin(global_invocation_id)]] gid : vec3<u32>;
|
||||||
|
[[builtin(num_workgroups)]] num_wgs : vec3<u32>;
|
||||||
|
[[builtin(workgroup_id)]] wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main1(in : Builtins1) {
|
||||||
|
let groups_x = in.num_wgs.x;
|
||||||
|
let groups_y = in.num_wgs.y;
|
||||||
|
let groups_z = in.num_wgs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main2(in : Builtins2) {
|
||||||
|
let groups_x = in.num_wgs.x;
|
||||||
|
let groups_y = in.num_wgs.y;
|
||||||
|
let groups_z = in.num_wgs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main3([[builtin(num_workgroups)]] num_wgs : vec3<u32>) {
|
||||||
|
let groups_x = num_wgs.x;
|
||||||
|
let groups_y = num_wgs.y;
|
||||||
|
let groups_z = num_wgs.z;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct tint_symbol_6 {
|
||||||
|
num_workgroups : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(30)]] var<uniform> tint_symbol_7 : tint_symbol_6;
|
||||||
|
|
||||||
|
struct Builtins1 {
|
||||||
|
num_wgs : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Builtins2 {
|
||||||
|
gid : vec3<u32>;
|
||||||
|
num_wgs : vec3<u32>;
|
||||||
|
wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main1_inner(in : Builtins1) {
|
||||||
|
let groups_x = in.num_wgs.x;
|
||||||
|
let groups_y = in.num_wgs.y;
|
||||||
|
let groups_z = in.num_wgs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main1() {
|
||||||
|
main1_inner(Builtins1(tint_symbol_7.num_workgroups));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tint_symbol_3 {
|
||||||
|
[[builtin(global_invocation_id)]]
|
||||||
|
gid : vec3<u32>;
|
||||||
|
[[builtin(workgroup_id)]]
|
||||||
|
wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main2_inner(in : Builtins2) {
|
||||||
|
let groups_x = in.num_wgs.x;
|
||||||
|
let groups_y = in.num_wgs.y;
|
||||||
|
let groups_z = in.num_wgs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main2(tint_symbol_2 : tint_symbol_3) {
|
||||||
|
main2_inner(Builtins2(tint_symbol_2.gid, tint_symbol_7.num_workgroups, tint_symbol_2.wgid));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main3_inner(num_wgs : vec3<u32>) {
|
||||||
|
let groups_x = num_wgs.x;
|
||||||
|
let groups_y = num_wgs.y;
|
||||||
|
let groups_z = num_wgs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main3() {
|
||||||
|
main3_inner(tint_symbol_7.num_workgroups);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
DataMap data;
|
||||||
|
data.Add<CanonicalizeEntryPointIO::Config>(
|
||||||
|
CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
|
||||||
|
data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
|
||||||
|
auto got = Run<CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NumWorkgroupsFromUniformTest, NoUsages) {
|
||||||
|
auto* src = R"(
|
||||||
|
struct Builtins {
|
||||||
|
[[builtin(global_invocation_id)]] gid : vec3<u32>;
|
||||||
|
[[builtin(workgroup_id)]] wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main(in : Builtins) {
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
struct Builtins {
|
||||||
|
gid : vec3<u32>;
|
||||||
|
wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tint_symbol_1 {
|
||||||
|
[[builtin(global_invocation_id)]]
|
||||||
|
gid : vec3<u32>;
|
||||||
|
[[builtin(workgroup_id)]]
|
||||||
|
wgid : vec3<u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main_inner(in : Builtins) {
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(1)]]
|
||||||
|
fn main(tint_symbol : tint_symbol_1) {
|
||||||
|
main_inner(Builtins(tint_symbol.gid, tint_symbol.wgid));
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
DataMap data;
|
||||||
|
data.Add<CanonicalizeEntryPointIO::Config>(
|
||||||
|
CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
|
||||||
|
data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
|
||||||
|
auto got = Run<CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace transform
|
||||||
|
} // namespace tint
|
|
@ -302,6 +302,7 @@ tint_unittests_source_set("tint_unittests_core_src") {
|
||||||
"../src/transform/inline_pointer_lets_test.cc",
|
"../src/transform/inline_pointer_lets_test.cc",
|
||||||
"../src/transform/loop_to_for_loop_test.cc",
|
"../src/transform/loop_to_for_loop_test.cc",
|
||||||
"../src/transform/module_scope_var_to_entry_point_param_test.cc",
|
"../src/transform/module_scope_var_to_entry_point_param_test.cc",
|
||||||
|
"../src/transform/num_workgroups_from_uniform_test.cc",
|
||||||
"../src/transform/pad_array_elements_test.cc",
|
"../src/transform/pad_array_elements_test.cc",
|
||||||
"../src/transform/promote_initializers_to_const_var_test.cc",
|
"../src/transform/promote_initializers_to_const_var_test.cc",
|
||||||
"../src/transform/renamer_test.cc",
|
"../src/transform/renamer_test.cc",
|
||||||
|
|
Loading…
Reference in New Issue