GLSL: run OFI if any stage uses firstInstance.
Run the OffsetFirstIndex transform if either the vertex or fragment
stage uses instance_index.
This requires cooperation from Dawn, since Tint is unaware of the
other shader stages being compiled.
Bug: dawn:2185
Change-Id: Id6f019da2b9acb4bde0cca888920dc6e969109b0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/173741
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Stephen White <senorblanco@chromium.org>
diff --git a/src/dawn/native/opengl/ComputePipelineGL.cpp b/src/dawn/native/opengl/ComputePipelineGL.cpp
index eecab24..6dfa69a8 100644
--- a/src/dawn/native/opengl/ComputePipelineGL.cpp
+++ b/src/dawn/native/opengl/ComputePipelineGL.cpp
@@ -46,8 +46,8 @@
}
MaybeError ComputePipeline::InitializeImpl() {
- DAWN_TRY(
- InitializeBase(ToBackend(GetDevice())->GetGL(), ToBackend(GetLayout()), GetAllStages()));
+ DAWN_TRY(InitializeBase(ToBackend(GetDevice())->GetGL(), ToBackend(GetLayout()), GetAllStages(),
+ /* usesInstanceIndex */ false));
return {};
}
diff --git a/src/dawn/native/opengl/PipelineGL.cpp b/src/dawn/native/opengl/PipelineGL.cpp
index 6c5d12b..08c4ebe 100644
--- a/src/dawn/native/opengl/PipelineGL.cpp
+++ b/src/dawn/native/opengl/PipelineGL.cpp
@@ -52,7 +52,8 @@
MaybeError PipelineGL::InitializeBase(const OpenGLFunctions& gl,
const PipelineLayout* layout,
- const PerStage<ProgrammableStage>& stages) {
+ const PerStage<ProgrammableStage>& stages,
+ bool usesInstanceIndex) {
mProgram = gl.CreateProgram();
// Compute the set of active stages.
@@ -70,10 +71,11 @@
for (SingleShaderStage stage : IterateStages(activeStages)) {
const ShaderModule* module = ToBackend(stages[stage].module.Get());
GLuint shader;
- DAWN_TRY_ASSIGN(shader, module->CompileShader(
- gl, stages[stage], stage, &combinedSamplers[stage], layout,
- &needsPlaceholderSampler, &mNeedsTextureBuiltinUniformBuffer,
- &mBindingPointEmulatedBuiltins));
+ DAWN_TRY_ASSIGN(shader, module->CompileShader(gl, stages[stage], stage, usesInstanceIndex,
+ &combinedSamplers[stage], layout,
+ &needsPlaceholderSampler,
+ &mNeedsTextureBuiltinUniformBuffer,
+ &mBindingPointEmulatedBuiltins));
gl.AttachShader(mProgram, shader);
glShaders.push_back(shader);
}
diff --git a/src/dawn/native/opengl/PipelineGL.h b/src/dawn/native/opengl/PipelineGL.h
index b2a6591..60fc43f 100644
--- a/src/dawn/native/opengl/PipelineGL.h
+++ b/src/dawn/native/opengl/PipelineGL.h
@@ -73,7 +73,8 @@
void ApplyNow(const OpenGLFunctions& gl);
MaybeError InitializeBase(const OpenGLFunctions& gl,
const PipelineLayout* layout,
- const PerStage<ProgrammableStage>& stages);
+ const PerStage<ProgrammableStage>& stages,
+ bool usesInstanceIndex);
void DeleteProgram(const OpenGLFunctions& gl);
private:
diff --git a/src/dawn/native/opengl/RenderPipelineGL.cpp b/src/dawn/native/opengl/RenderPipelineGL.cpp
index aea3743..5819a32 100644
--- a/src/dawn/native/opengl/RenderPipelineGL.cpp
+++ b/src/dawn/native/opengl/RenderPipelineGL.cpp
@@ -256,8 +256,8 @@
mGlPrimitiveTopology(GLPrimitiveTopology(GetPrimitiveTopology())) {}
MaybeError RenderPipeline::InitializeImpl() {
- DAWN_TRY(
- InitializeBase(ToBackend(GetDevice())->GetGL(), ToBackend(GetLayout()), GetAllStages()));
+ DAWN_TRY(InitializeBase(ToBackend(GetDevice())->GetGL(), ToBackend(GetLayout()), GetAllStages(),
+ UsesInstanceIndex()));
CreateVAOForVertexState();
return {};
}
diff --git a/src/dawn/native/opengl/ShaderModuleGL.cpp b/src/dawn/native/opengl/ShaderModuleGL.cpp
index 77ad5ed..b4659b5 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -167,6 +167,7 @@
const OpenGLFunctions& gl,
const ProgrammableStage& programmableStage,
SingleShaderStage stage,
+ bool usesInstanceIndex,
CombinedSamplerInfo* combinedSamplers,
const PipelineLayout* layout,
bool* needsPlaceholderSampler,
@@ -287,6 +288,12 @@
version.GetMajor(), version.GetMinor());
req.tintOptions.disable_robustness = false;
+
+ if (usesInstanceIndex) {
+ req.tintOptions.first_instance_offset =
+ 4 * PipelineLayout::PushConstantLocation::FirstInstance;
+ }
+
req.disableSymbolRenaming = GetDevice()->IsToggleEnabled(Toggle::DisableSymbolRenaming);
req.interstageVariables = {};
@@ -418,9 +425,6 @@
/* fullSubgroups */ {}));
}
- r.tintOptions.first_instance_offset =
- 4 * PipelineLayout::PushConstantLocation::FirstInstance;
-
auto result = tint::glsl::writer::Generate(program, r.tintOptions, remappedEntryPoint);
DAWN_INVALID_IF(result != tint::Success, "An error occurred while generating GLSL:\n%s",
result.Failure().reason.Str());
diff --git a/src/dawn/native/opengl/ShaderModuleGL.h b/src/dawn/native/opengl/ShaderModuleGL.h
index a452b2fc..1a3b3a1 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.h
+++ b/src/dawn/native/opengl/ShaderModuleGL.h
@@ -89,6 +89,7 @@
ResultOrError<GLuint> CompileShader(const OpenGLFunctions& gl,
const ProgrammableStage& programmableStage,
SingleShaderStage stage,
+ bool usesInstanceIndex,
CombinedSamplerInfo* combinedSamplers,
const PipelineLayout* layout,
bool* needsPlaceholderSampler,
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 81a9e5b..85d8d3e 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -1067,9 +1067,13 @@
gen_options.texture_builtins_from_uniform = std::move(textureBuiltinsFromUniform);
- // Place the first_instance push constant member after user-defined push constants (if any).
- gen_options.first_instance_offset =
- inspector.GetEntryPoint(entry_point_name).push_constant_size;
+ auto entry_point = inspector.GetEntryPoint(entry_point_name);
+
+ if (entry_point.instance_index_used) {
+ // Place the first_instance push constant member after user-defined push constants (if
+ // any).
+ gen_options.first_instance_offset = entry_point.push_constant_size;
+ }
auto result = tint::glsl::writer::Generate(prg, gen_options, entry_point_name);
if (result != tint::Success) {
diff --git a/src/tint/lang/wgsl/ast/transform/offset_first_index.cc b/src/tint/lang/wgsl/ast/transform/offset_first_index.cc
index 04bdd9a..143b43f 100644
--- a/src/tint/lang/wgsl/ast/transform/offset_first_index.cc
+++ b/src/tint/lang/wgsl/ast/transform/offset_first_index.cc
@@ -53,15 +53,6 @@
constexpr char kFirstVertexName[] = "first_vertex";
constexpr char kFirstInstanceName[] = "first_instance";
-bool ShouldRun(const Program& program) {
- for (auto* fn : program.AST().Functions()) {
- if (fn->PipelineStage() == PipelineStage::kVertex) {
- return true;
- }
- }
- return false;
-}
-
} // namespace
OffsetFirstIndex::OffsetFirstIndex() = default;
@@ -70,14 +61,13 @@
Transform::ApplyResult OffsetFirstIndex::Apply(const Program& src,
const DataMap& inputs,
DataMap&) const {
- if (!ShouldRun(src)) {
- return SkipTransform;
- }
-
const Config* cfg = inputs.Get<Config>();
if (!cfg) {
return SkipTransform;
}
+ if (!cfg->first_vertex_offset.has_value() && !cfg->first_instance_offset.has_value()) {
+ return SkipTransform;
+ }
ProgramBuilder b;
program::CloneContext ctx{&b, &src, /* auto_clone_symbols */ true};
@@ -86,9 +76,6 @@
std::unordered_map<const sem::Variable*, const char*> builtin_vars;
std::unordered_map<const core::type::StructMember*, const char*> builtin_members;
- bool has_vertex_index = false;
- bool has_instance_index = false;
-
// Traverse the AST scanning for builtin accesses via variables (includes
// parameters) or structure member accesses.
for (auto* node : ctx.src->ASTNodes().Objects()) {
@@ -100,13 +87,11 @@
cfg->first_vertex_offset.has_value()) {
auto* sem_var = ctx.src->Sem().Get(var);
builtin_vars.emplace(sem_var, kFirstVertexName);
- has_vertex_index = true;
}
if (builtin == core::BuiltinValue::kInstanceIndex && cfg &&
cfg->first_instance_offset.has_value()) {
auto* sem_var = ctx.src->Sem().Get(var);
builtin_vars.emplace(sem_var, kFirstInstanceName);
- has_instance_index = true;
}
}
}
@@ -119,23 +104,17 @@
cfg->first_vertex_offset.has_value()) {
auto* sem_mem = ctx.src->Sem().Get(member);
builtin_members.emplace(sem_mem, kFirstVertexName);
- has_vertex_index = true;
}
if (builtin == core::BuiltinValue::kInstanceIndex && cfg &&
cfg->first_instance_offset.has_value()) {
auto* sem_mem = ctx.src->Sem().Get(member);
builtin_members.emplace(sem_mem, kFirstInstanceName);
- has_instance_index = true;
}
}
}
}
}
- if (!has_vertex_index && !has_instance_index) {
- return SkipTransform;
- }
-
Vector<const ast::StructMember*, 8> members;
const ast::Variable* push_constants_var = nullptr;
@@ -159,11 +138,11 @@
}
// Add push constant members and calculate byte offsets
- if (has_vertex_index) {
+ if (cfg->first_vertex_offset.has_value()) {
members.Push(b.Member(kFirstVertexName, b.ty.u32(),
Vector{b.MemberOffset(AInt(*cfg->first_vertex_offset))}));
}
- if (has_instance_index) {
+ if (cfg->first_instance_offset.has_value()) {
members.Push(b.Member(kFirstInstanceName, b.ty.u32(),
Vector{b.MemberOffset(AInt(*cfg->first_instance_offset))}));
}
diff --git a/src/tint/lang/wgsl/ast/transform/offset_first_index_test.cc b/src/tint/lang/wgsl/ast/transform/offset_first_index_test.cc
index 7d026ed..09dd505 100644
--- a/src/tint/lang/wgsl/ast/transform/offset_first_index_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/offset_first_index_test.cc
@@ -41,12 +41,49 @@
TEST_F(OffsetFirstIndexTest, ShouldRunEmptyModule) {
auto* src = R"()";
- DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
- EXPECT_FALSE(ShouldRun<OffsetFirstIndex>(src, config));
+ EXPECT_FALSE(ShouldRun<OffsetFirstIndex>(src));
}
-TEST_F(OffsetFirstIndexTest, ShouldRunFragmentStage) {
+TEST_F(OffsetFirstIndexTest, ShouldRunNoVertexIndexNoInstanceIndex) {
+ auto* src = R"(
+@fragment
+fn entry() {
+ return;
+}
+)";
+
+ DataMap config;
+ config.Add<OffsetFirstIndex::Config>(std::nullopt, std::nullopt);
+ EXPECT_FALSE(ShouldRun<OffsetFirstIndex>(src, std::move(config)));
+}
+
+TEST_F(OffsetFirstIndexTest, ShouldRunNoVertexIndex) {
+ auto* src = R"(
+@fragment
+fn entry() {
+ return;
+}
+)";
+
+ DataMap config;
+ config.Add<OffsetFirstIndex::Config>(std::nullopt, 0);
+ EXPECT_TRUE(ShouldRun<OffsetFirstIndex>(src, std::move(config)));
+}
+
+TEST_F(OffsetFirstIndexTest, ShouldRunNoInstanceIndex) {
+ auto* src = R"(
+@fragment
+fn entry() {
+ return;
+}
+)";
+
+ DataMap config;
+ config.Add<OffsetFirstIndex::Config>(0, std::nullopt);
+ EXPECT_TRUE(ShouldRun<OffsetFirstIndex>(src, std::move(config)));
+}
+
+TEST_F(OffsetFirstIndexTest, ShouldRun) {
auto* src = R"(
@fragment
fn entry() {
@@ -56,20 +93,7 @@
DataMap config;
config.Add<OffsetFirstIndex::Config>(0, 4);
- EXPECT_FALSE(ShouldRun<OffsetFirstIndex>(src, config));
-}
-
-TEST_F(OffsetFirstIndexTest, ShouldRunVertexStage) {
- auto* src = R"(
-@vertex
-fn entry() -> @builtin(position) vec4<f32> {
- return vec4<f32>();
-}
-)";
-
- DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
- EXPECT_FALSE(ShouldRun<OffsetFirstIndex>(src, config));
+ EXPECT_TRUE(ShouldRun<OffsetFirstIndex>(src, std::move(config)));
}
TEST_F(OffsetFirstIndexTest, ShouldRunVertexStageWithVertexIndex) {
@@ -82,7 +106,7 @@
DataMap config;
config.Add<OffsetFirstIndex::Config>(0, 4);
- EXPECT_TRUE(ShouldRun<OffsetFirstIndex>(src, config));
+ EXPECT_TRUE(ShouldRun<OffsetFirstIndex>(src, std::move(config)));
}
TEST_F(OffsetFirstIndexTest, ShouldRunVertexStageWithInstanceIndex) {
@@ -95,16 +119,14 @@
DataMap config;
config.Add<OffsetFirstIndex::Config>(0, 4);
- EXPECT_TRUE(ShouldRun<OffsetFirstIndex>(src, config));
+ EXPECT_TRUE(ShouldRun<OffsetFirstIndex>(src, std::move(config)));
}
TEST_F(OffsetFirstIndexTest, EmptyModule) {
auto* src = "";
auto* expect = "";
- DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
- auto got = Run<OffsetFirstIndex>(src, std::move(config));
+ auto got = Run<OffsetFirstIndex>(src);
EXPECT_EQ(expect, str(got));
}
@@ -118,9 +140,7 @@
)";
auto* expect = src;
- DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
- auto got = Run<OffsetFirstIndex>(src, std::move(config));
+ auto got = Run<OffsetFirstIndex>(src);
EXPECT_EQ(expect, str(got));
}
@@ -160,7 +180,7 @@
)";
DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
+ config.Add<OffsetFirstIndex::Config>(0, std::nullopt);
auto got = Run<OffsetFirstIndex>(src, std::move(config));
EXPECT_EQ(expect, str(got));
@@ -201,7 +221,7 @@
)";
DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
+ config.Add<OffsetFirstIndex::Config>(0, std::nullopt);
auto got = Run<OffsetFirstIndex>(src, std::move(config));
EXPECT_EQ(expect, str(got));
@@ -244,7 +264,7 @@
)";
DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
+ config.Add<OffsetFirstIndex::Config>(std::nullopt, 4);
auto got = Run<OffsetFirstIndex>(src, std::move(config));
EXPECT_EQ(expect, str(got));
@@ -287,7 +307,7 @@
)";
DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
+ config.Add<OffsetFirstIndex::Config>(std::nullopt, 4);
auto got = Run<OffsetFirstIndex>(src, std::move(config));
EXPECT_EQ(expect, str(got));
@@ -577,7 +597,7 @@
)";
DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
+ config.Add<OffsetFirstIndex::Config>(0, std::nullopt);
auto got = Run<OffsetFirstIndex>(src, std::move(config));
EXPECT_EQ(expect, str(got));
@@ -614,7 +634,7 @@
)";
DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
+ config.Add<OffsetFirstIndex::Config>(0, std::nullopt);
auto got = Run<OffsetFirstIndex>(src, std::move(config));
EXPECT_EQ(expect, str(got));
@@ -663,7 +683,7 @@
)";
DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
+ config.Add<OffsetFirstIndex::Config>(0, std::nullopt);
auto got = Run<OffsetFirstIndex>(src, std::move(config));
EXPECT_EQ(expect, str(got));
@@ -712,7 +732,7 @@
)";
DataMap config;
- config.Add<OffsetFirstIndex::Config>(0, 4);
+ config.Add<OffsetFirstIndex::Config>(0, std::nullopt);
auto got = Run<OffsetFirstIndex>(src, std::move(config));
EXPECT_EQ(expect, str(got));