Tint: Support `clip_distances` on MSL
This patch implements the translation of `clip_distances` on MSL.
1. The struct member `clip_distances` will be translated into a
C-style array.
2. The struct member `clip_distances` will be assigned once per
array index.
Bug: chromium:358408571
Change-Id: I5ecd77b4827815fba830fd0bed39ecd17babb9ed
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/203156
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index 91d4237..39aa061 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -291,6 +291,7 @@
wgsl::Extension::kChromiumExperimentalSubgroups,
wgsl::Extension::kChromiumInternalGraphite,
wgsl::Extension::kChromiumInternalRelaxedUniformLayout,
+ wgsl::Extension::kClipDistances,
wgsl::Extension::kF16,
wgsl::Extension::kDualSourceBlending,
wgsl::Extension::kSubgroups,
@@ -2994,23 +2995,40 @@
add_byte_offset_comment(out, msl_offset);
}
+ auto* ty = mem->Type();
+
+ // Emit attributes
+ auto& attributes = mem->Attributes();
+ std::string builtin_value_name;
+ if (auto builtin = attributes.builtin) {
+ builtin_value_name = BuiltinToAttribute(builtin.value());
+ if (builtin_value_name.empty()) {
+ diagnostics_.AddError(Source{}) << "unknown builtin";
+ return false;
+ }
+
+ // Emit `[[clip_distance]]` as a C-style f32 array
+ if (builtin == core::BuiltinValue::kClipDistances) {
+ const auto* arrayType = mem->Type()->As<core::type::Array>();
+ if (TINT_UNLIKELY(arrayType == nullptr ||
+ !arrayType->ConstantCount().has_value())) {
+ TINT_ICE() << "The type of `clip_distances` is not a sized array";
+ } else {
+ out << "float " << mem_name << " [[" << builtin_value_name << "]] ["
+ << *arrayType->ConstantCount() << "];";
+ }
+ continue;
+ }
+ }
+
if (!EmitType(out, mem->Type())) {
return false;
}
- auto* ty = mem->Type();
-
out << " " << mem_name;
- // Emit attributes
- auto& attributes = mem->Attributes();
- if (auto builtin = attributes.builtin) {
- auto name = BuiltinToAttribute(builtin.value());
- if (name.empty()) {
- diagnostics_.AddError(Source{}) << "unknown builtin";
- return false;
- }
- out << " [[" << name << "]]";
+ if (!builtin_value_name.empty()) {
+ out << " [[" << builtin_value_name << "]]";
}
if (auto location = attributes.location) {
diff --git a/src/tint/lang/msl/writer/common/printer_support.cc b/src/tint/lang/msl/writer/common/printer_support.cc
index d3dbba0..ce92042 100644
--- a/src/tint/lang/msl/writer/common/printer_support.cc
+++ b/src/tint/lang/msl/writer/common/printer_support.cc
@@ -77,6 +77,8 @@
return "thread_index_in_simdgroup";
case core::BuiltinValue::kSubgroupSize:
return "threads_per_simdgroup";
+ case core::BuiltinValue::kClipDistances:
+ return "clip_distance";
default:
break;
}
diff --git a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
index c7847e8..eec3c26 100644
--- a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
@@ -165,6 +165,8 @@
Hashmap<const BuiltinAttribute*, core::BuiltinValue, 16> builtin_attrs;
/// A map of builtin values to HLSL wave intrinsic functions.
Hashmap<core::BuiltinValue, Symbol, 2> wave_intrinsics;
+ /// The array length of the struct member with builtin attribute `clip_distances`.
+ uint32_t clip_distances_size = 0;
/// Constructor
/// @param context the clone context
@@ -407,6 +409,17 @@
core::InterpolationSampling::kUndefined));
}
+ if (cfg.shader_style == ShaderStyle::kMsl &&
+ func_ast->PipelineStage() == PipelineStage::kVertex &&
+ builtin_attr == core::BuiltinValue::kClipDistances) {
+ const auto* arrayType = type->As<core::type::Array>();
+ if (TINT_UNLIKELY(arrayType == nullptr || !arrayType->ConstantCount().has_value())) {
+ TINT_ICE() << "The type of `clip_distances` is not a sized array";
+ } else {
+ clip_distances_size = *arrayType->ConstantCount();
+ }
+ }
+
// In GLSL, if it's a builtin, override the name with the
// corresponding gl_ builtin name
if (cfg.shader_style == ShaderStyle::kGlsl) {
@@ -682,13 +695,26 @@
}
member_names.insert(name.Name());
+ auto* builtin_attribute = GetAttribute<BuiltinAttribute>(outval.attributes);
+ if (cfg.shader_style == ShaderStyle::kMsl && builtin_attribute != nullptr &&
+ builtin_attribute->builtin == core::BuiltinValue::kClipDistances) {
+ Symbol clip_distances_inner_array = b.Symbols().New("tmp_inner_clip_distances");
+ assignments.Push(b.Decl(b.Let(clip_distances_inner_array, outval.value)));
+ for (uint32_t i = 0; i < clip_distances_size; ++i) {
+ assignments.Push(
+ b.Assign(b.IndexAccessor(b.MemberAccessor(wrapper_result, name), u32(i)),
+ b.IndexAccessor(clip_distances_inner_array, u32(i))));
+ }
+ } else {
+ assignments.Push(b.Assign(b.MemberAccessor(wrapper_result, name), outval.value));
+ }
+
wrapper_struct_output_members.Push({
/* member */ b.Member(name, outval.type, std::move(outval.attributes)),
/* location */ outval.location,
/* blend_src */ outval.blend_src,
/* color */ std::nullopt,
});
- assignments.Push(b.Assign(b.MemberAccessor(wrapper_result, name), outval.value));
}
// Sort the struct members to satisfy HLSL interfacing matching rules.
diff --git a/test/tint/extensions/clip_distances/clip_distances_size_1.wgsl.expected.msl b/test/tint/extensions/clip_distances/clip_distances_size_1.wgsl.expected.msl
index 557ef30..fd5ca23 100644
--- a/test/tint/extensions/clip_distances/clip_distances_size_1.wgsl.expected.msl
+++ b/test/tint/extensions/clip_distances/clip_distances_size_1.wgsl.expected.msl
@@ -1,21 +1,40 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
-enable clip_distances;
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
struct VertexOutputs {
- @builtin(position)
- position : vec4<f32>,
- @builtin(clip_distances)
- clipDistance : array<f32, 1>,
+ float4 position;
+ tint_array<float, 1> clipDistance;
+};
+
+struct tint_symbol_1 {
+ float4 position [[position]];
+ float clipDistance [[clip_distance]] [1];
+};
+
+VertexOutputs tint_symbol_inner() {
+ VertexOutputs const tint_symbol_2 = VertexOutputs{.position=float4(1.0f, 2.0f, 3.0f, 4.0f), .clipDistance=tint_array<float, 1>{}};
+ return tint_symbol_2;
}
-@vertex
-fn tint_symbol() -> VertexOutputs {
- return VertexOutputs(vec4<f32>(1.0, 2.0, 3.0, 4.0), array<f32, 1>(0.0));
+vertex tint_symbol_1 tint_symbol() {
+ VertexOutputs const inner_result = tint_symbol_inner();
+ tint_symbol_1 wrapper_result = {};
+ wrapper_result.position = inner_result.position;
+ tint_array<float, 1> const tmp_inner_clip_distances = inner_result.clipDistance;
+ wrapper_result.clipDistance[0u] = tmp_inner_clip_distances[0u];
+ return wrapper_result;
}
-Failed to generate: <dawn>/test/tint/extensions/clip_distances/clip_distances_size_1.wgsl:1:8 error: MSL backend does not support extension 'clip_distances'
-enable clip_distances;
- ^^^^^^^^^^^^^^
-
diff --git a/test/tint/extensions/clip_distances/clip_distances_size_4.wgsl.expected.msl b/test/tint/extensions/clip_distances/clip_distances_size_4.wgsl.expected.msl
index 668fc1f..8f88332 100644
--- a/test/tint/extensions/clip_distances/clip_distances_size_4.wgsl.expected.msl
+++ b/test/tint/extensions/clip_distances/clip_distances_size_4.wgsl.expected.msl
@@ -1,21 +1,43 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
-enable clip_distances;
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
struct VertexOutputs {
- @builtin(position)
- position : vec4<f32>,
- @builtin(clip_distances)
- clipDistance : array<f32, 4>,
+ float4 position;
+ tint_array<float, 4> clipDistance;
+};
+
+struct tint_symbol_1 {
+ float4 position [[position]];
+ float clipDistance [[clip_distance]] [4];
+};
+
+VertexOutputs tint_symbol_inner() {
+ VertexOutputs const tint_symbol_2 = VertexOutputs{.position=float4(1.0f, 2.0f, 3.0f, 4.0f), .clipDistance=tint_array<float, 4>{}};
+ return tint_symbol_2;
}
-@vertex
-fn tint_symbol() -> VertexOutputs {
- return VertexOutputs(vec4<f32>(1.0, 2.0, 3.0, 4.0), array<f32, 4>(0.0, 0.0, 0.0, 0.0));
+vertex tint_symbol_1 tint_symbol() {
+ VertexOutputs const inner_result = tint_symbol_inner();
+ tint_symbol_1 wrapper_result = {};
+ wrapper_result.position = inner_result.position;
+ tint_array<float, 4> const tmp_inner_clip_distances = inner_result.clipDistance;
+ wrapper_result.clipDistance[0u] = tmp_inner_clip_distances[0u];
+ wrapper_result.clipDistance[1u] = tmp_inner_clip_distances[1u];
+ wrapper_result.clipDistance[2u] = tmp_inner_clip_distances[2u];
+ wrapper_result.clipDistance[3u] = tmp_inner_clip_distances[3u];
+ return wrapper_result;
}
-Failed to generate: <dawn>/test/tint/extensions/clip_distances/clip_distances_size_4.wgsl:1:8 error: MSL backend does not support extension 'clip_distances'
-enable clip_distances;
- ^^^^^^^^^^^^^^
-
diff --git a/test/tint/extensions/clip_distances/clip_distances_size_8.wgsl.expected.msl b/test/tint/extensions/clip_distances/clip_distances_size_8.wgsl.expected.msl
index 2592985..952455e 100644
--- a/test/tint/extensions/clip_distances/clip_distances_size_8.wgsl.expected.msl
+++ b/test/tint/extensions/clip_distances/clip_distances_size_8.wgsl.expected.msl
@@ -1,21 +1,47 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
-enable clip_distances;
+template<typename T, size_t N>
+struct tint_array {
+ const constant T& operator[](size_t i) const constant { return elements[i]; }
+ device T& operator[](size_t i) device { return elements[i]; }
+ const device T& operator[](size_t i) const device { return elements[i]; }
+ thread T& operator[](size_t i) thread { return elements[i]; }
+ const thread T& operator[](size_t i) const thread { return elements[i]; }
+ threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+ const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+ T elements[N];
+};
struct VertexOutputs {
- @builtin(position)
- position : vec4<f32>,
- @builtin(clip_distances)
- clipDistance : array<f32, 8>,
+ float4 position;
+ tint_array<float, 8> clipDistance;
+};
+
+struct tint_symbol_1 {
+ float4 position [[position]];
+ float clipDistance [[clip_distance]] [8];
+};
+
+VertexOutputs tint_symbol_inner() {
+ VertexOutputs const tint_symbol_2 = VertexOutputs{.position=float4(1.0f, 2.0f, 3.0f, 4.0f), .clipDistance=tint_array<float, 8>{}};
+ return tint_symbol_2;
}
-@vertex
-fn tint_symbol() -> VertexOutputs {
- return VertexOutputs(vec4<f32>(1.0, 2.0, 3.0, 4.0), array<f32, 8>(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+vertex tint_symbol_1 tint_symbol() {
+ VertexOutputs const inner_result = tint_symbol_inner();
+ tint_symbol_1 wrapper_result = {};
+ wrapper_result.position = inner_result.position;
+ tint_array<float, 8> const tmp_inner_clip_distances = inner_result.clipDistance;
+ wrapper_result.clipDistance[0u] = tmp_inner_clip_distances[0u];
+ wrapper_result.clipDistance[1u] = tmp_inner_clip_distances[1u];
+ wrapper_result.clipDistance[2u] = tmp_inner_clip_distances[2u];
+ wrapper_result.clipDistance[3u] = tmp_inner_clip_distances[3u];
+ wrapper_result.clipDistance[4u] = tmp_inner_clip_distances[4u];
+ wrapper_result.clipDistance[5u] = tmp_inner_clip_distances[5u];
+ wrapper_result.clipDistance[6u] = tmp_inner_clip_distances[6u];
+ wrapper_result.clipDistance[7u] = tmp_inner_clip_distances[7u];
+ return wrapper_result;
}
-Failed to generate: <dawn>/test/tint/extensions/clip_distances/clip_distances_size_8.wgsl:1:8 error: MSL backend does not support extension 'clip_distances'
-enable clip_distances;
- ^^^^^^^^^^^^^^
-