[spirv-writer] Fragment shaders use OriginUpperLeft
Fixes a validation error
Change-Id: Ie003ac61a10f87f3d0c42ad8cb162da50c1c416b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/20740
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index ce13f0a..aaf9772 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -162,6 +162,11 @@
return false;
}
}
+ for (const auto& ep : mod_->entry_points()) {
+ if (!GenerateExecutionModes(ep.get())) {
+ return false;
+ }
+ }
return true;
}
@@ -249,10 +254,8 @@
if (name.empty()) {
name = ep->function_name();
}
-
- auto id = id_for_func_name(ep->function_name());
+ const auto id = id_for_entry_point(ep);
if (id == 0) {
- error_ = "unable to find ID for function: " + ep->function_name();
return false;
}
@@ -268,6 +271,22 @@
return true;
}
+bool Builder::GenerateExecutionModes(ast::EntryPoint* ep) {
+ const auto id = id_for_entry_point(ep);
+ if (id == 0) {
+ return false;
+ }
+
+ // WGSL fragment shader origin is upper left
+ if (ep->stage() == ast::PipelineStage::kFragment) {
+ push_preamble(
+ spv::Op::OpExecutionMode,
+ {Operand::Int(id), Operand::Int(SpvExecutionModeOriginUpperLeft)});
+ }
+
+ return true;
+}
+
uint32_t Builder::GenerateExpression(ast::Expression* expr) {
if (expr->IsArrayAccessor()) {
return GenerateAccessorExpression(expr->AsArrayAccessor());
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 394c5e5..f3a40d2 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -98,6 +98,19 @@
return func_name_to_id_[name];
}
+ /// Retrieves the id for an entry point function, or 0 if not found.
+ /// Emits an error if not found.
+ /// @param ep the entry point
+ /// @returns 0 on error
+ uint32_t id_for_entry_point(ast::EntryPoint* ep) {
+ auto id = id_for_func_name(ep->function_name());
+ if (id == 0) {
+ error_ = "unable to find ID for function: " + ep->function_name();
+ return 0;
+ }
+ return id;
+ }
+
/// Iterates over all the instructions in the correct order and calls the
/// given callback
/// @param cb the callback to execute
@@ -182,6 +195,10 @@
/// @param ep the entry point
/// @returns true if the instruction was generated, false otherwise
bool GenerateEntryPoint(ast::EntryPoint* ep);
+ /// Generates execution modes for an entry point
+ /// @param ep the entry point
+ /// @returns false on failure
+ bool GenerateExecutionModes(ast::EntryPoint* ep);
/// Generates an expression
/// @param expr the expression to generate
/// @returns the resulting ID of the exp = {};ression or 0 on error
diff --git a/src/writer/spirv/builder_entry_point_test.cc b/src/writer/spirv/builder_entry_point_test.cc
index 71dcfb7..788787b 100644
--- a/src/writer/spirv/builder_entry_point_test.cc
+++ b/src/writer/spirv/builder_entry_point_test.cc
@@ -106,6 +106,20 @@
// TODO(http://crbug.com/tint/28)
TEST_F(BuilderTest, DISABLED_EntryPoint_WithInterfaceIds) {}
+TEST_F(BuilderTest, ExecutionModel_Fragment_OriginUpperLeft) {
+ ast::EntryPoint ep(ast::PipelineStage::kFragment, "main", "frag_main");
+
+ ast::Module mod;
+ Builder b(&mod);
+ b.set_func_name_to_id("frag_main", 2);
+ ASSERT_TRUE(b.GenerateExecutionModes(&ep));
+
+ auto preamble = b.preamble();
+ ASSERT_EQ(preamble.size(), 1u);
+ EXPECT_EQ(DumpInstruction(preamble[0]), R"(OpExecutionMode %2 OriginUpperLeft
+)");
+}
+
} // namespace
} // namespace spirv
} // namespace writer