Support ClipDistances in SPIR-V reader with Tint AST - Part I
This patch adds the support of parsing `spv::BuiltIn::ClipDistance`
into the built-in attribute `@builtin(clip_distances)` in the SPIR-V
reader with Tint AST.
Note that this CL doesn't implement parsing `ClipDistance` in
`gl_PerVertex` struct, which will be implemented in the next CL.
Bug: chromium:358408571
Test: tint_unittests
Change-Id: Ieba8e810789357ebd4ed15dcdba390ed44c663ba
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/210138
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc b/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
index 58c9ef9..de9615a 100644
--- a/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
@@ -1156,7 +1156,7 @@
builtin_position_.pointsize_member_index = member_index;
create_ast_member = false; // Not part of the WGSL structure.
break;
- case spv::BuiltIn::ClipDistance: // not supported in WGSL
+ case spv::BuiltIn::ClipDistance:
case spv::BuiltIn::CullDistance: // not supported in WGSL
create_ast_member = false; // Not part of the WGSL structure.
break;
@@ -1555,6 +1555,7 @@
}
// Emit gl_Position instead of gl_PerVertex
+ // TODO(chromium:358408571): handle gl_ClipDistance[] in gl_PerVertex
if (builtin_position_.per_vertex_var_id) {
// Make sure the variable has a name.
namer_.SuggestSanitizedName(builtin_position_.per_vertex_var_id, "gl_Position");
@@ -1737,6 +1738,9 @@
}
break;
}
+ case spv::BuiltIn::ClipDistance:
+ Enable(wgsl::Extension::kClipDistances);
+ break;
default:
break;
}
diff --git a/src/tint/lang/spirv/reader/ast_parser/ast_parser_test.cc b/src/tint/lang/spirv/reader/ast_parser/ast_parser_test.cc
index 3aaf1f9..54548ef 100644
--- a/src/tint/lang/spirv/reader/ast_parser/ast_parser_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/ast_parser_test.cc
@@ -264,7 +264,7 @@
TEST_F(SpirvASTParserTest, BlendSrc) {
auto spv = test::Assemble(R"(
-OpCapability Shader
+ OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %frag_main "frag_main" %frag_main_loc0_idx0_Output %frag_main_loc0_idx1_Output
OpExecutionMode %frag_main OriginUpperLeft
@@ -372,5 +372,205 @@
)");
}
+TEST_F(SpirvASTParserTest, ClipDistances_ArraySize_1) {
+ auto spv = test::Assemble(R"(
+ OpCapability Shader
+ OpCapability ClipDistance
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %main_position_Output %main_clip_distances_Output %main___point_size_Output
+ OpName %main_position_Output "main_position_Output"
+ OpName %main_clip_distances_Output "main_clip_distances_Output"
+ OpName %main___point_size_Output "main___point_size_Output"
+ OpName %main_inner "main_inner"
+ OpMemberName %VertexOutputs 0 "position"
+ OpMemberName %VertexOutputs 1 "clipDistance"
+ OpName %VertexOutputs "VertexOutputs"
+ OpName %main "main"
+ OpDecorate %main_position_Output BuiltIn Position
+ OpDecorate %_arr_float_uint_1 ArrayStride 4
+ OpDecorate %main_clip_distances_Output BuiltIn ClipDistance
+ OpDecorate %main___point_size_Output BuiltIn PointSize
+ OpMemberDecorate %VertexOutputs 0 Offset 0
+ OpMemberDecorate %VertexOutputs 1 Offset 16
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%main_position_Output = OpVariable %_ptr_Output_v4float Output
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 1
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%_ptr_Output__arr_float_uint_1 = OpTypePointer Output %_arr_float_uint_1
+%main_clip_distances_Output = OpVariable %_ptr_Output__arr_float_uint_1 Output
+%_ptr_Output_float = OpTypePointer Output %float
+%main___point_size_Output = OpVariable %_ptr_Output_float Output
+%VertexOutputs = OpTypeStruct %v4float %_arr_float_uint_1
+ %14 = OpTypeFunction %VertexOutputs
+ %16 = OpConstantNull %VertexOutputs
+ %void = OpTypeVoid
+ %19 = OpTypeFunction %void
+ %float_1 = OpConstant %float 1
+ %main_inner = OpFunction %VertexOutputs None %14
+ %15 = OpLabel
+ OpReturnValue %16
+ OpFunctionEnd
+ %main = OpFunction %void None %19
+ %20 = OpLabel
+ %21 = OpFunctionCall %VertexOutputs %main_inner
+ %22 = OpCompositeExtract %v4float %21 0
+ OpStore %main_position_Output %22 None
+ %23 = OpCompositeExtract %_arr_float_uint_1 %21 1
+ OpStore %main_clip_distances_Output %23 None
+ OpStore %main___point_size_Output %float_1 None
+ OpReturn
+ OpFunctionEnd
+)");
+ auto program = Parse(spv, {});
+ auto errs = program.Diagnostics().Str();
+ EXPECT_TRUE(program.IsValid()) << errs;
+ EXPECT_EQ(program.Diagnostics().Count(), 0u) << errs;
+ auto result = wgsl::writer::Generate(program, {});
+ EXPECT_EQ(result, Success);
+ EXPECT_EQ("\n" + result->wgsl, R"(
+enable clip_distances;
+
+alias Arr = array<f32, 1u>;
+
+struct VertexOutputs {
+ /* @offset(0) */
+ position : vec4f,
+ /* @offset(16) */
+ clipDistance : Arr,
+}
+
+var<private> main_position_Output : vec4f;
+
+var<private> main_clip_distances_Output : Arr;
+
+fn main_inner() -> VertexOutputs {
+ return VertexOutputs(vec4f(), array<f32, 1u>());
+}
+
+fn main_1() {
+ let x_21 = main_inner();
+ main_position_Output = x_21.position;
+ main_clip_distances_Output = x_21.clipDistance;
+ return;
+}
+
+struct main_out {
+ @builtin(position)
+ main_position_Output_1 : vec4f,
+ @builtin(clip_distances)
+ main_clip_distances_Output_1 : Arr,
+}
+
+@vertex
+fn main() -> main_out {
+ main_1();
+ return main_out(main_position_Output, main_clip_distances_Output);
+}
+)");
+}
+
+TEST_F(SpirvASTParserTest, ClipDistances_ArraySize_4) {
+ auto spv = test::Assemble(R"(
+ OpCapability Shader
+ OpCapability ClipDistance
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %main_position_Output %main_clip_distances_Output %main___point_size_Output
+ OpName %main_position_Output "main_position_Output"
+ OpName %main_clip_distances_Output "main_clip_distances_Output"
+ OpName %main___point_size_Output "main___point_size_Output"
+ OpName %main_inner "main_inner"
+ OpMemberName %VertexOutputs 0 "position"
+ OpMemberName %VertexOutputs 1 "clipDistance"
+ OpName %VertexOutputs "VertexOutputs"
+ OpName %main "main"
+ OpDecorate %main_position_Output BuiltIn Position
+ OpDecorate %_arr_float_uint_1 ArrayStride 4
+ OpDecorate %main_clip_distances_Output BuiltIn ClipDistance
+ OpDecorate %main___point_size_Output BuiltIn PointSize
+ OpMemberDecorate %VertexOutputs 0 Offset 0
+ OpMemberDecorate %VertexOutputs 1 Offset 16
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%main_position_Output = OpVariable %_ptr_Output_v4float Output
+ %uint = OpTypeInt 32 0
+ %uint_1 = OpConstant %uint 4
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%_ptr_Output__arr_float_uint_1 = OpTypePointer Output %_arr_float_uint_1
+%main_clip_distances_Output = OpVariable %_ptr_Output__arr_float_uint_1 Output
+%_ptr_Output_float = OpTypePointer Output %float
+%main___point_size_Output = OpVariable %_ptr_Output_float Output
+%VertexOutputs = OpTypeStruct %v4float %_arr_float_uint_1
+ %14 = OpTypeFunction %VertexOutputs
+ %16 = OpConstantNull %VertexOutputs
+ %void = OpTypeVoid
+ %19 = OpTypeFunction %void
+ %float_1 = OpConstant %float 1
+ %main_inner = OpFunction %VertexOutputs None %14
+ %15 = OpLabel
+ OpReturnValue %16
+ OpFunctionEnd
+ %main = OpFunction %void None %19
+ %20 = OpLabel
+ %21 = OpFunctionCall %VertexOutputs %main_inner
+ %22 = OpCompositeExtract %v4float %21 0
+ OpStore %main_position_Output %22 None
+ %23 = OpCompositeExtract %_arr_float_uint_1 %21 1
+ OpStore %main_clip_distances_Output %23 None
+ OpStore %main___point_size_Output %float_1 None
+ OpReturn
+ OpFunctionEnd
+)");
+ auto program = Parse(spv, {});
+ auto errs = program.Diagnostics().Str();
+ EXPECT_TRUE(program.IsValid()) << errs;
+ EXPECT_EQ(program.Diagnostics().Count(), 0u) << errs;
+ auto result = wgsl::writer::Generate(program, {});
+ EXPECT_EQ(result, Success);
+ EXPECT_EQ("\n" + result->wgsl, R"(
+enable clip_distances;
+
+alias Arr = array<f32, 4u>;
+
+struct VertexOutputs {
+ /* @offset(0) */
+ position : vec4f,
+ /* @offset(16) */
+ clipDistance : Arr,
+}
+
+var<private> main_position_Output : vec4f;
+
+var<private> main_clip_distances_Output : Arr;
+
+fn main_inner() -> VertexOutputs {
+ return VertexOutputs(vec4f(), array<f32, 4u>());
+}
+
+fn main_1() {
+ let x_21 = main_inner();
+ main_position_Output = x_21.position;
+ main_clip_distances_Output = x_21.clipDistance;
+ return;
+}
+
+struct main_out {
+ @builtin(position)
+ main_position_Output_1 : vec4f,
+ @builtin(clip_distances)
+ main_clip_distances_Output_1 : Arr,
+}
+
+@vertex
+fn main() -> main_out {
+ main_1();
+ return main_out(main_position_Output, main_clip_distances_Output);
+}
+)");
+}
+
} // namespace
} // namespace tint::spirv::reader::ast_parser
diff --git a/src/tint/lang/spirv/reader/ast_parser/enum_converter.cc b/src/tint/lang/spirv/reader/ast_parser/enum_converter.cc
index b8c805b..5f6083b 100644
--- a/src/tint/lang/spirv/reader/ast_parser/enum_converter.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/enum_converter.cc
@@ -105,6 +105,8 @@
return core::BuiltinValue::kSampleIndex;
case spv::BuiltIn::SampleMask:
return core::BuiltinValue::kSampleMask;
+ case spv::BuiltIn::ClipDistance:
+ return core::BuiltinValue::kClipDistances;
default:
break;
}
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.cc b/src/tint/lang/spirv/reader/ast_parser/function.cc
index 9eaea1e..6ce6314 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/function.cc
@@ -1163,6 +1163,19 @@
if (array_type->size == 0) {
return Fail() << "runtime-size array not allowed on pipeline IO";
}
+
+ const ast::BuiltinAttribute* builtin_attribute = attrs.Get<ast::BuiltinAttribute>();
+ if (builtin_attribute != nullptr &&
+ builtin_attribute->builtin == core::BuiltinValue::kClipDistances) {
+ const Type* member_type = forced_member_type;
+ const auto member_name = namer_.MakeDerivedName(var_name);
+ return_members.Push(
+ builder_.Member(member_name, member_type->Build(builder_), attrs.list));
+ const ast::Expression* load_source = builder_.Expr(var_name);
+ return_exprs.Push(load_source);
+ return success();
+ }
+
index_prefix.Push(0);
const Type* elem_ty = array_type->type;
for (int i = 0; i < static_cast<int>(array_type->size); i++) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/parse.cc b/src/tint/lang/spirv/reader/ast_parser/parse.cc
index 8081c14..df00f2e 100644
--- a/src/tint/lang/spirv/reader/ast_parser/parse.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/parse.cc
@@ -101,6 +101,7 @@
// Allow below WGSL extensions unconditionally but not enable them by default.
allowed_features.extensions.insert(wgsl::Extension::kDualSourceBlending);
+ allowed_features.extensions.insert(wgsl::Extension::kClipDistances);
// The SPIR-V parser can construct disjoint AST nodes, which is invalid for
// the Resolver. Clone the Program to clean these up.