diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index ce13f0a855..aaf97726b0 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -162,6 +162,11 @@ bool Builder::Build() { return false; } } + for (const auto& ep : mod_->entry_points()) { + if (!GenerateExecutionModes(ep.get())) { + return false; + } + } return true; } @@ -249,10 +254,8 @@ bool Builder::GenerateEntryPoint(ast::EntryPoint* ep) { 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 @@ bool Builder::GenerateEntryPoint(ast::EntryPoint* ep) { 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 394c5e5d38..f3a40d2f09 100644 --- a/src/writer/spirv/builder.h +++ b/src/writer/spirv/builder.h @@ -98,6 +98,19 @@ class Builder { 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 @@ class Builder { /// @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 71dcfb799c..788787beee 100644 --- a/src/writer/spirv/builder_entry_point_test.cc +++ b/src/writer/spirv/builder_entry_point_test.cc @@ -106,6 +106,20 @@ INSTANTIATE_TEST_SUITE_P( // 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