Add ClampFragDepth transform to GLSL writer.
Also, make the ClampFragDepth transform play well with
existing push constants in the AST. This required implementing a ClampFragDepth::Config containing byte offsets for the min_depth and max_depth push constants, so they can be specified by Dawn.
These are std::optional, and leaving them null indicates not to
run the transform. Run the transform if any shaders being compiled
into a pipeline by Dawn write to frag_depth. In practice, this means to
force-run the transform in the vertex shader if the fragment shader is
writing to frag_depth. This keeps the PushConstants struct identical
at link time.
Bug: dawn:2185
Change-Id: Ieb9e282f94b8c74374f11b90324dacf2325183f0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/172640
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
diff --git a/src/dawn/native/opengl/CommandBufferGL.cpp b/src/dawn/native/opengl/CommandBufferGL.cpp
index 5797278b..51b0b53 100644
--- a/src/dawn/native/opengl/CommandBufferGL.cpp
+++ b/src/dawn/native/opengl/CommandBufferGL.cpp
@@ -1025,7 +1025,10 @@
persistentPipelineState.SetDefaultState(gl);
gl.BlendColor(0, 0, 0, 0);
gl.Viewport(0, 0, renderPass->width, renderPass->height);
- gl.DepthRangef(0.0, 1.0);
+ float minDepth = 0.0f;
+ float maxDepth = 1.0f;
+ gl.DepthRangef(minDepth, maxDepth);
+
gl.Scissor(0, 0, renderPass->width, renderPass->height);
// Clear framebuffer attachments as needed
@@ -1230,6 +1233,10 @@
vertexStateBufferBindingTracker.OnSetPipeline(lastPipeline);
bindGroupTracker.OnSetPipeline(lastPipeline);
+ if (lastPipeline->UsesFragDepth()) {
+ gl.Uniform1f(PipelineLayout::PushConstantLocation::MinDepth, minDepth);
+ gl.Uniform1f(PipelineLayout::PushConstantLocation::MaxDepth, maxDepth);
+ }
break;
}
@@ -1310,7 +1317,13 @@
gl.Viewport(static_cast<int>(cmd->x), static_cast<int>(cmd->y),
static_cast<int>(cmd->width), static_cast<int>(cmd->height));
}
- gl.DepthRangef(cmd->minDepth, cmd->maxDepth);
+ minDepth = cmd->minDepth;
+ maxDepth = cmd->maxDepth;
+ gl.DepthRangef(minDepth, maxDepth);
+ if (lastPipeline && lastPipeline->UsesFragDepth()) {
+ gl.Uniform1f(PipelineLayout::PushConstantLocation::MinDepth, minDepth);
+ gl.Uniform1f(PipelineLayout::PushConstantLocation::MaxDepth, maxDepth);
+ }
break;
}
diff --git a/src/dawn/native/opengl/ComputePipelineGL.cpp b/src/dawn/native/opengl/ComputePipelineGL.cpp
index 6dfa69a8..3344cd5 100644
--- a/src/dawn/native/opengl/ComputePipelineGL.cpp
+++ b/src/dawn/native/opengl/ComputePipelineGL.cpp
@@ -47,7 +47,7 @@
MaybeError ComputePipeline::InitializeImpl() {
DAWN_TRY(InitializeBase(ToBackend(GetDevice())->GetGL(), ToBackend(GetLayout()), GetAllStages(),
- /* usesInstanceIndex */ false));
+ /* usesInstanceIndex */ false, /* usesFragDepth */ false));
return {};
}
diff --git a/src/dawn/native/opengl/PipelineGL.cpp b/src/dawn/native/opengl/PipelineGL.cpp
index 08c4ebe..5c665a2 100644
--- a/src/dawn/native/opengl/PipelineGL.cpp
+++ b/src/dawn/native/opengl/PipelineGL.cpp
@@ -53,7 +53,8 @@
MaybeError PipelineGL::InitializeBase(const OpenGLFunctions& gl,
const PipelineLayout* layout,
const PerStage<ProgrammableStage>& stages,
- bool usesInstanceIndex) {
+ bool usesInstanceIndex,
+ bool usesFragDepth) {
mProgram = gl.CreateProgram();
// Compute the set of active stages.
@@ -72,8 +73,8 @@
const ShaderModule* module = ToBackend(stages[stage].module.Get());
GLuint shader;
DAWN_TRY_ASSIGN(shader, module->CompileShader(gl, stages[stage], stage, usesInstanceIndex,
- &combinedSamplers[stage], layout,
- &needsPlaceholderSampler,
+ usesFragDepth, &combinedSamplers[stage],
+ layout, &needsPlaceholderSampler,
&mNeedsTextureBuiltinUniformBuffer,
&mBindingPointEmulatedBuiltins));
gl.AttachShader(mProgram, shader);
diff --git a/src/dawn/native/opengl/PipelineGL.h b/src/dawn/native/opengl/PipelineGL.h
index 60fc43f..2370f55 100644
--- a/src/dawn/native/opengl/PipelineGL.h
+++ b/src/dawn/native/opengl/PipelineGL.h
@@ -74,7 +74,8 @@
MaybeError InitializeBase(const OpenGLFunctions& gl,
const PipelineLayout* layout,
const PerStage<ProgrammableStage>& stages,
- bool usesInstanceIndex);
+ bool usesInstanceIndex,
+ bool usesFragDepth);
void DeleteProgram(const OpenGLFunctions& gl);
private:
diff --git a/src/dawn/native/opengl/PipelineLayoutGL.h b/src/dawn/native/opengl/PipelineLayoutGL.h
index e2ab802..bc0fe3a 100644
--- a/src/dawn/native/opengl/PipelineLayoutGL.h
+++ b/src/dawn/native/opengl/PipelineLayoutGL.h
@@ -57,6 +57,8 @@
enum PushConstantLocation {
FirstInstance = 0,
+ MinDepth = 1,
+ MaxDepth = 2,
};
private:
diff --git a/src/dawn/native/opengl/RenderPipelineGL.cpp b/src/dawn/native/opengl/RenderPipelineGL.cpp
index 5819a32..9923bb9 100644
--- a/src/dawn/native/opengl/RenderPipelineGL.cpp
+++ b/src/dawn/native/opengl/RenderPipelineGL.cpp
@@ -257,7 +257,7 @@
MaybeError RenderPipeline::InitializeImpl() {
DAWN_TRY(InitializeBase(ToBackend(GetDevice())->GetGL(), ToBackend(GetLayout()), GetAllStages(),
- UsesInstanceIndex()));
+ UsesInstanceIndex(), UsesFragDepth()));
CreateVAOForVertexState();
return {};
}
diff --git a/src/dawn/native/opengl/ShaderModuleGL.cpp b/src/dawn/native/opengl/ShaderModuleGL.cpp
index b4659b5..aa5768b 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -168,6 +168,7 @@
const ProgrammableStage& programmableStage,
SingleShaderStage stage,
bool usesInstanceIndex,
+ bool usesFragDepth,
CombinedSamplerInfo* combinedSamplers,
const PipelineLayout* layout,
bool* needsPlaceholderSampler,
@@ -294,6 +295,12 @@
4 * PipelineLayout::PushConstantLocation::FirstInstance;
}
+ if (usesFragDepth) {
+ req.tintOptions.min_depth_offset = 4 * PipelineLayout::PushConstantLocation::MinDepth;
+
+ req.tintOptions.max_depth_offset = 4 * PipelineLayout::PushConstantLocation::MaxDepth;
+ }
+
req.disableSymbolRenaming = GetDevice()->IsToggleEnabled(Toggle::DisableSymbolRenaming);
req.interstageVariables = {};
diff --git a/src/dawn/native/opengl/ShaderModuleGL.h b/src/dawn/native/opengl/ShaderModuleGL.h
index 1a3b3a1..71251e4 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.h
+++ b/src/dawn/native/opengl/ShaderModuleGL.h
@@ -90,6 +90,7 @@
const ProgrammableStage& programmableStage,
SingleShaderStage stage,
bool usesInstanceIndex,
+ bool usesFragDepth,
CombinedSamplerInfo* combinedSamplers,
const PipelineLayout* layout,
bool* needsPlaceholderSampler,
diff --git a/src/dawn/tests/end2end/FragDepthTests.cpp b/src/dawn/tests/end2end/FragDepthTests.cpp
index b98bbba..9af0533 100644
--- a/src/dawn/tests/end2end/FragDepthTests.cpp
+++ b/src/dawn/tests/end2end/FragDepthTests.cpp
@@ -38,9 +38,6 @@
// Test that when writing to FragDepth the result is clamped to the viewport.
TEST_P(FragDepthTests, FragDepthIsClampedToViewport) {
- // TODO(dawn:1125): Add the shader transform to clamp the frag depth to the GL backend.
- DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
-
wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
@vertex fn vs() -> @builtin(position) vec4f {
return vec4f(0.0, 0.0, 0.5, 1.0);
@@ -91,12 +88,12 @@
// Test for the push constant logic for ClampFragDepth in Vulkan to check that changing the
// pipeline layout doesn't invalidate the push constants that were set.
TEST_P(FragDepthTests, ChangingPipelineLayoutDoesntInvalidateViewport) {
- // TODO(dawn:1125): Add the shader transform to clamp the frag depth to the GL backend.
- DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
-
// TODO(dawn:1805): Load ByteAddressBuffer in Pixel Shader doesn't work with NVIDIA on D3D11
DAWN_SUPPRESS_TEST_IF(IsD3D11() && IsNvidia());
+ // TODO(dawn:2393): ANGLE/D3D11 fails in HLSL shader compilation (UAV vs PS register bug)
+ DAWN_SUPPRESS_TEST_IF(IsANGLED3D11());
+
wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
@vertex fn vs() -> @builtin(position) vec4f {
return vec4f(0.0, 0.0, 0.5, 1.0);
diff --git a/src/dawn/tests/end2end/ShaderTests.cpp b/src/dawn/tests/end2end/ShaderTests.cpp
index f10a4ea..bc16efa 100644
--- a/src/dawn/tests/end2end/ShaderTests.cpp
+++ b/src/dawn/tests/end2end/ShaderTests.cpp
@@ -2160,6 +2160,32 @@
device.CreateRenderPipeline(&desc);
}
+// Test that accessing instance_index in the vert shader and assigning to frag_depth in the frag
+// shader works.
+TEST_P(ShaderTests, FragDepthAndInstanceIndex) {
+ wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
+ @group(0) @binding(0) var<uniform> a : f32;
+
+ @fragment fn fragment() -> @builtin(frag_depth) f32 {
+ return a;
+ }
+
+ @vertex fn vertex(@builtin(instance_index) instance : u32) -> @builtin(position) vec4f {
+ return vec4f(f32(instance));
+ }
+ )");
+
+ utils::ComboRenderPipelineDescriptor desc;
+ desc.vertex.module = module;
+ desc.cFragment.module = module;
+ desc.cFragment.targetCount = 0;
+ wgpu::DepthStencilState* dsState = desc.EnableDepthStencil();
+ dsState->depthWriteEnabled = true;
+ dsState->depthCompare = wgpu::CompareFunction::Always;
+
+ device.CreateRenderPipeline(&desc);
+}
+
// Having different block contents at the same binding point used in different stages is allowed.
TEST_P(ShaderTests, UniformAcrossStagesSameBindingPointCollide) {
wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 4d18bb9..1601a76 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -1080,11 +1080,18 @@
gen_options.texture_builtins_from_uniform = std::move(textureBuiltinsFromUniform);
auto entry_point = inspector.GetEntryPoint(entry_point_name);
+ uint32_t offset = entry_point.push_constant_size;
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;
+ gen_options.first_instance_offset = offset;
+ offset += 4;
+ }
+ if (entry_point.frag_depth_used) {
+ gen_options.min_depth_offset = offset + 0;
+ gen_options.max_depth_offset = offset + 4;
+ offset += 8;
}
auto result = tint::glsl::writer::Generate(prg, gen_options, entry_point_name);
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index 326c1a2..764b779 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -61,6 +61,7 @@
#include "src/tint/lang/wgsl/ast/transform/binding_remapper.h"
#include "src/tint/lang/wgsl/ast/transform/builtin_polyfill.h"
#include "src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.h"
+#include "src/tint/lang/wgsl/ast/transform/clamp_frag_depth.h"
#include "src/tint/lang/wgsl/ast/transform/demote_to_helper.h"
#include "src/tint/lang/wgsl/ast/transform/direct_variable_access.h"
#include "src/tint/lang/wgsl/ast/transform/disable_uniformity_analysis.h"
@@ -206,6 +207,10 @@
manager.Add<ast::transform::OffsetFirstIndex>();
+ // ClampFragDepth must come before CanonicalizeEntryPointIO, or the assignments to FragDepth are
+ // lost
+ manager.Add<ast::transform::ClampFragDepth>();
+
// CanonicalizeEntryPointIO must come after Robustness
manager.Add<ast::transform::CanonicalizeEntryPointIO>();
@@ -249,6 +254,8 @@
data.Add<ast::transform::OffsetFirstIndex::Config>(std::nullopt, options.first_instance_offset);
+ data.Add<ast::transform::ClampFragDepth::Config>(options.min_depth_offset,
+ options.max_depth_offset);
SanitizedResult result;
ast::transform::DataMap outputs;
result.program = manager.Run(in, data, outputs);
diff --git a/src/tint/lang/glsl/writer/common/options.h b/src/tint/lang/glsl/writer/common/options.h
index 7545366..62cd80c 100644
--- a/src/tint/lang/glsl/writer/common/options.h
+++ b/src/tint/lang/glsl/writer/common/options.h
@@ -82,6 +82,12 @@
/// Offset of the firstInstance push constant.
std::optional<int32_t> first_instance_offset;
+ /// Offset of the minDepth push constant.
+ std::optional<uint32_t> min_depth_offset;
+
+ /// Offset of the maxDepth push constant.
+ std::optional<uint32_t> max_depth_offset;
+
/// Options used to map WGSL textureNumLevels/textureNumSamples builtins to internal uniform
/// buffer values. If not specified, emits corresponding GLSL builtins
/// textureQueryLevels/textureSamples directly.
@@ -98,6 +104,8 @@
binding_remapper_options,
external_texture_options,
first_instance_offset,
+ min_depth_offset,
+ max_depth_offset,
texture_builtins_from_uniform);
};
diff --git a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
index 4272172..c782db5 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
@@ -66,6 +66,7 @@
if (options.clamp_frag_depth) {
manager.Add<ast::transform::ClampFragDepth>();
+ data.Add<ast::transform::ClampFragDepth::Config>(0, 4);
}
manager.Add<ast::transform::DisableUniformityAnalysis>();
diff --git a/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.cc b/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.cc
index 59e6dd6..2b5e6a2 100644
--- a/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.cc
+++ b/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.cc
@@ -35,6 +35,7 @@
#include "src/tint/lang/wgsl/ast/function.h"
#include "src/tint/lang/wgsl/ast/module.h"
#include "src/tint/lang/wgsl/ast/struct.h"
+#include "src/tint/lang/wgsl/ast/transform/push_constant_helper.h"
#include "src/tint/lang/wgsl/program/clone_context.h"
#include "src/tint/lang/wgsl/program/program_builder.h"
#include "src/tint/lang/wgsl/resolver/resolve.h"
@@ -45,6 +46,7 @@
#include "src/tint/utils/macros/scoped_assignment.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ClampFragDepth);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ClampFragDepth::Config);
namespace tint::ast::transform {
@@ -63,49 +65,37 @@
/// Runs the transform
/// @returns the new program or SkipTransform if the transform is not required
- Transform::ApplyResult Run() {
- // Abort on any use of push constants in the module.
- for (auto* global : src.AST().GlobalVariables()) {
- if (auto* var = global->As<ast::Var>()) {
- auto* v = src.Sem().Get(var);
- if (TINT_UNLIKELY(v->AddressSpace() == core::AddressSpace::kPushConstant)) {
- TINT_ICE()
- << "ClampFragDepth doesn't know how to handle module that already use push "
- "constants";
- return resolver::Resolve(b);
- }
- }
- }
-
- if (!ShouldRun()) {
+ Transform::ApplyResult Run(const DataMap& inputs) {
+ const Config* cfg = inputs.Get<Config>();
+ if (!cfg || !cfg->min_depth_offset.has_value() || !cfg->max_depth_offset.has_value()) {
return SkipTransform;
}
+ PushConstantHelper push_constant_helper(ctx);
+
// At least one entry-point needs clamping. Add the following to the module:
//
// enable chromium_experimental_push_constant;
//
- // struct FragDepthClampArgs {
- // min : f32,
- // max : f32,
+ // struct PushConstants {
+ // min_depth : f32,
+ // max_depth : f32,
// }
- // var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
+ // var<push_constant> push_constants : PushConstants;
//
// fn clamp_frag_depth(v : f32) -> f32 {
- // return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
+ // return clamp(v, push_constants.min, push_constants.max_depth);
// }
- b.Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
- b.Structure(b.Symbols().New("FragDepthClampArgs"),
- Vector{b.Member("min", b.ty.f32()), b.Member("max", b.ty.f32())});
+ push_constant_helper.InsertMember("min_depth", b.ty.f32(), *cfg->min_depth_offset);
+ push_constant_helper.InsertMember("max_depth", b.ty.f32(), *cfg->max_depth_offset);
- auto args_sym = b.Symbols().New("frag_depth_clamp_args");
- b.GlobalVar(args_sym, b.ty("FragDepthClampArgs"), core::AddressSpace::kPushConstant);
+ Symbol buffer_name = push_constant_helper.Run();
auto base_fn_sym = b.Symbols().New("clamp_frag_depth");
b.Func(base_fn_sym, Vector{b.Param("v", b.ty.f32())}, b.ty.f32(),
- Vector{b.Return(b.Call("clamp", "v", b.MemberAccessor(args_sym, "min"),
- b.MemberAccessor(args_sym, "max")))});
+ Vector{b.Return(b.Call("clamp", "v", b.MemberAccessor(buffer_name, "min_depth"),
+ b.MemberAccessor(buffer_name, "max_depth")))});
// If true, the currently cloned function returns frag depth directly as a scalar
bool returns_frag_depth_as_value = false;
@@ -185,17 +175,6 @@
}
private:
- /// @returns true if the transform should run
- bool ShouldRun() {
- for (auto* fn : src.AST().Functions()) {
- if (fn->PipelineStage() == ast::PipelineStage::kFragment &&
- (ReturnsFragDepthAsValue(fn) || ReturnsFragDepthInStruct(fn))) {
- return true;
- }
- }
-
- return false;
- }
/// @param attrs the attributes to examine
/// @returns true if @p attrs contains a `@builtin(frag_depth)` attribute
bool ContainsFragDepth(VectorRef<const ast::Attribute*> attrs) {
@@ -237,9 +216,15 @@
ClampFragDepth::~ClampFragDepth() = default;
ast::transform::Transform::ApplyResult ClampFragDepth::Apply(const Program& src,
- const ast::transform::DataMap&,
+ const ast::transform::DataMap& inputs,
ast::transform::DataMap&) const {
- return State{src}.Run();
+ return State{src}.Run(inputs);
}
+ClampFragDepth::Config::Config(std::optional<uint32_t> min_depth_off,
+ std::optional<uint32_t> max_depth_off)
+ : min_depth_offset(min_depth_off), max_depth_offset(max_depth_off) {}
+
+ClampFragDepth::Config::~Config() = default;
+
} // namespace tint::ast::transform
diff --git a/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.h b/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.h
index 5bcd3ea..599b91c 100644
--- a/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.h
+++ b/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.h
@@ -69,6 +69,23 @@
/// Destructor
~ClampFragDepth() override;
+ /// Transform configuration options
+ struct Config final : public Castable<Config, ast::transform::Data> {
+ /// Constructor
+ /// @param min_depth_off Offset of the minDepth push constant
+ /// @param max_depth_off Offset of the maxDepth push constant
+ Config(std::optional<uint32_t> min_depth_off, std::optional<uint32_t> max_depth_off);
+
+ /// Destructor
+ ~Config() override;
+
+ /// Offset of the min_depth push constant
+ std::optional<uint32_t> min_depth_offset;
+
+ /// Offset of the min_depth push constant
+ std::optional<uint32_t> max_depth_offset;
+ };
+
/// @copydoc ast::transform::Transform::Apply
ApplyResult Apply(const Program& program,
const ast::transform::DataMap& inputs,
diff --git a/src/tint/lang/wgsl/ast/transform/clamp_frag_depth_test.cc b/src/tint/lang/wgsl/ast/transform/clamp_frag_depth_test.cc
index cc09c6f..97f1f31 100644
--- a/src/tint/lang/wgsl/ast/transform/clamp_frag_depth_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/clamp_frag_depth_test.cc
@@ -40,48 +40,102 @@
EXPECT_FALSE(ShouldRun<ClampFragDepth>(src));
}
-TEST_F(ClampFragDepthTest, ShouldRunNoFragmentShader) {
+TEST_F(ClampFragDepthTest, ShouldRunNoConfig) {
auto* src = R"(
- fn f() -> f32 {
+ @fragment fn main() -> @builtin(frag_depth) f32 {
return 0.0;
}
-
- @compute @workgroup_size(1) fn cs() {
- }
-
- @vertex fn vs() -> @builtin(position) vec4<f32> {
- return vec4<f32>();
- }
)";
EXPECT_FALSE(ShouldRun<ClampFragDepth>(src));
}
-TEST_F(ClampFragDepthTest, ShouldRunFragmentShaderNoReturnType) {
+TEST_F(ClampFragDepthTest, ShouldRunNoMin) {
auto* src = R"(
- @fragment fn main() {
- }
- )";
-
- EXPECT_FALSE(ShouldRun<ClampFragDepth>(src));
-}
-
-TEST_F(ClampFragDepthTest, ShouldRunFragmentShaderNoFragDepth) {
- auto* src = R"(
- @fragment fn main() -> @location(0) f32 {
+ @fragment fn main() -> @builtin(frag_depth) f32 {
return 0.0;
}
+ )";
- struct S {
- @location(0) a : f32,
- @builtin(sample_mask) b : u32,
- }
- @fragment fn main2() -> S {
- return S();
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(std::nullopt, 4);
+
+ EXPECT_FALSE(ShouldRun<ClampFragDepth>(src, config));
+}
+
+TEST_F(ClampFragDepthTest, ShouldRunNoMinNoMax) {
+ auto* src = R"(
+ @fragment fn main() -> @builtin(frag_depth) f32 {
+ return 0.0;
}
)";
- EXPECT_FALSE(ShouldRun<ClampFragDepth>(src));
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, std::nullopt);
+
+ EXPECT_FALSE(ShouldRun<ClampFragDepth>(src, config));
+}
+
+TEST_F(ClampFragDepthTest, ShouldRun) {
+ auto* src = R"(
+ @fragment fn main() -> @builtin(frag_depth) f32 {
+ return 0.0;
+ }
+ )";
+
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+
+ EXPECT_TRUE(ShouldRun<ClampFragDepth>(src, config));
+}
+
+TEST_F(ClampFragDepthTest, ExistingPushConstant) {
+ auto* src = R"(
+ enable chromium_experimental_push_constant;
+
+ struct PushConstants {
+ a : f32,
+ }
+
+ var<push_constant> push_constants : PushConstants;
+ @fragment fn main() -> @builtin(frag_depth) f32 {
+ return push_constants.a;
+ }
+
+ )";
+
+ auto* expect = R"(
+enable chromium_experimental_push_constant;
+
+struct PushConstants_1 {
+ a : f32,
+ /* @offset(4) */
+ min_depth : f32,
+ /* @offset(8) */
+ max_depth : f32,
+}
+
+fn clamp_frag_depth(v : f32) -> f32 {
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
+}
+
+struct PushConstants {
+ a : f32,
+}
+
+var<push_constant> push_constants : PushConstants_1;
+
+@fragment
+fn main() -> @builtin(frag_depth) f32 {
+ return clamp_frag_depth(push_constants.a);
+}
+)";
+
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(4, 8);
+
+ auto got = Run<ClampFragDepth>(src, config);
+ EXPECT_EQ(expect, str(got));
}
TEST_F(ClampFragDepthTest, ShouldRunFragDepthAsDirectReturn) {
@@ -91,7 +145,10 @@
}
)";
- EXPECT_TRUE(ShouldRun<ClampFragDepth>(src));
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+
+ EXPECT_TRUE(ShouldRun<ClampFragDepth>(src, config));
}
TEST_F(ClampFragDepthTest, ShouldRunFragDepthInStruct) {
@@ -106,7 +163,10 @@
}
)";
- EXPECT_TRUE(ShouldRun<ClampFragDepth>(src));
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+
+ EXPECT_TRUE(ShouldRun<ClampFragDepth>(src, config));
}
TEST_F(ClampFragDepthTest, SingleReturnOfFragDepth) {
@@ -119,15 +179,17 @@
auto* expect = R"(
enable chromium_experimental_push_constant;
-struct FragDepthClampArgs {
- min : f32,
- max : f32,
+struct PushConstants {
+ /* @offset(0) */
+ min_depth : f32,
+ /* @offset(4) */
+ max_depth : f32,
}
-var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
+var<push_constant> push_constants : PushConstants;
fn clamp_frag_depth(v : f32) -> f32 {
- return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
}
@fragment
@@ -136,7 +198,9 @@
}
)";
- auto got = Run<ClampFragDepth>(src);
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+ auto got = Run<ClampFragDepth>(src, config);
EXPECT_EQ(expect, str(got));
}
@@ -153,15 +217,17 @@
auto* expect = R"(
enable chromium_experimental_push_constant;
-struct FragDepthClampArgs {
- min : f32,
- max : f32,
+struct PushConstants {
+ /* @offset(0) */
+ min_depth : f32,
+ /* @offset(4) */
+ max_depth : f32,
}
-var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
+var<push_constant> push_constants : PushConstants;
fn clamp_frag_depth(v : f32) -> f32 {
- return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
}
@fragment
@@ -173,7 +239,9 @@
}
)";
- auto got = Run<ClampFragDepth>(src);
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+ auto got = Run<ClampFragDepth>(src, config);
EXPECT_EQ(expect, str(got));
}
@@ -190,15 +258,17 @@
auto* expect = R"(
enable chromium_experimental_push_constant;
-struct FragDepthClampArgs {
- min : f32,
- max : f32,
+struct PushConstants {
+ /* @offset(0) */
+ min_depth : f32,
+ /* @offset(4) */
+ max_depth : f32,
}
-var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
+var<push_constant> push_constants : PushConstants;
fn clamp_frag_depth(v : f32) -> f32 {
- return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
}
@fragment
@@ -212,7 +282,9 @@
}
)";
- auto got = Run<ClampFragDepth>(src);
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+ auto got = Run<ClampFragDepth>(src, config);
EXPECT_EQ(expect, str(got));
}
@@ -230,15 +302,17 @@
auto* expect = R"(
enable chromium_experimental_push_constant;
-struct FragDepthClampArgs {
- min : f32,
- max : f32,
+struct PushConstants {
+ /* @offset(0) */
+ min_depth : f32,
+ /* @offset(4) */
+ max_depth : f32,
}
-var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
+var<push_constant> push_constants : PushConstants;
fn clamp_frag_depth(v : f32) -> f32 {
- return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
}
struct S {
@@ -256,7 +330,9 @@
}
)";
- auto got = Run<ClampFragDepth>(src);
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+ auto got = Run<ClampFragDepth>(src, config);
EXPECT_EQ(expect, str(got));
}
@@ -285,15 +361,17 @@
auto* expect = R"(
enable chromium_experimental_push_constant;
-struct FragDepthClampArgs {
- min : f32,
- max : f32,
+struct PushConstants {
+ /* @offset(0) */
+ min_depth : f32,
+ /* @offset(4) */
+ max_depth : f32,
}
-var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
+var<push_constant> push_constants : PushConstants;
fn clamp_frag_depth(v : f32) -> f32 {
- return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
}
struct S {
@@ -330,7 +408,9 @@
}
)";
- auto got = Run<ClampFragDepth>(src);
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+ auto got = Run<ClampFragDepth>(src, config);
EXPECT_EQ(expect, str(got));
}
@@ -352,15 +432,17 @@
auto* expect = R"(
enable chromium_experimental_push_constant;
-struct FragDepthClampArgs {
- min : f32,
- max : f32,
+struct PushConstants {
+ /* @offset(0) */
+ min_depth : f32,
+ /* @offset(4) */
+ max_depth : f32,
}
-var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
+var<push_constant> push_constants : PushConstants;
fn clamp_frag_depth(v : f32) -> f32 {
- return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
}
struct S {
@@ -386,7 +468,9 @@
}
)";
- auto got = Run<ClampFragDepth>(src);
+ DataMap config;
+ config.Add<ClampFragDepth::Config>(0, 4);
+ auto got = Run<ClampFragDepth>(src, config);
EXPECT_EQ(expect, str(got));
}
diff --git a/test/tint/types/functions/shader_io/fragment_output_builtins.wgsl.expected.glsl b/test/tint/types/functions/shader_io/fragment_output_builtins.wgsl.expected.glsl
index 3e264e1..e7ac574 100644
--- a/test/tint/types/functions/shader_io/fragment_output_builtins.wgsl.expected.glsl
+++ b/test/tint/types/functions/shader_io/fragment_output_builtins.wgsl.expected.glsl
@@ -2,8 +2,18 @@
precision highp float;
precision highp int;
+struct PushConstants {
+ float min_depth;
+ float max_depth;
+};
+
+layout(location=0) uniform PushConstants push_constants;
+float clamp_frag_depth(float v) {
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
+}
+
float main1() {
- return 1.0f;
+ return clamp_frag_depth(1.0f);
}
void main() {
diff --git a/test/tint/types/functions/shader_io/fragment_output_builtins_struct.wgsl.expected.glsl b/test/tint/types/functions/shader_io/fragment_output_builtins_struct.wgsl.expected.glsl
index 6f5c106..1385388 100644
--- a/test/tint/types/functions/shader_io/fragment_output_builtins_struct.wgsl.expected.glsl
+++ b/test/tint/types/functions/shader_io/fragment_output_builtins_struct.wgsl.expected.glsl
@@ -3,16 +3,31 @@
precision highp float;
precision highp int;
+struct PushConstants {
+ float min_depth;
+ float max_depth;
+};
+
+layout(location=0) uniform PushConstants push_constants;
+float clamp_frag_depth(float v) {
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
+}
+
struct FragmentOutputs {
float frag_depth;
uint sample_mask;
};
-FragmentOutputs tint_symbol() {
- FragmentOutputs tint_symbol_1 = FragmentOutputs(1.0f, 1u);
+FragmentOutputs clamp_frag_depth_FragmentOutputs(FragmentOutputs s) {
+ FragmentOutputs tint_symbol_1 = FragmentOutputs(clamp_frag_depth(s.frag_depth), s.sample_mask);
return tint_symbol_1;
}
+FragmentOutputs tint_symbol() {
+ FragmentOutputs tint_symbol_2 = FragmentOutputs(1.0f, 1u);
+ return clamp_frag_depth_FragmentOutputs(tint_symbol_2);
+}
+
void main() {
FragmentOutputs inner_result = tint_symbol();
gl_FragDepth = inner_result.frag_depth;
diff --git a/test/tint/types/functions/shader_io/fragment_output_mixed.wgsl.expected.glsl b/test/tint/types/functions/shader_io/fragment_output_mixed.wgsl.expected.glsl
index c43b3ea..905ec2f 100644
--- a/test/tint/types/functions/shader_io/fragment_output_mixed.wgsl.expected.glsl
+++ b/test/tint/types/functions/shader_io/fragment_output_mixed.wgsl.expected.glsl
@@ -7,6 +7,16 @@
layout(location = 1) out uint loc1_1;
layout(location = 2) out float loc2_1;
layout(location = 3) out vec4 loc3_1;
+struct PushConstants {
+ float min_depth;
+ float max_depth;
+};
+
+layout(location=0) uniform PushConstants push_constants;
+float clamp_frag_depth(float v) {
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
+}
+
struct FragmentOutputs {
int loc0;
float frag_depth;
@@ -16,11 +26,16 @@
vec4 loc3;
};
-FragmentOutputs tint_symbol() {
- FragmentOutputs tint_symbol_1 = FragmentOutputs(1, 2.0f, 1u, 1.0f, 2u, vec4(1.0f, 2.0f, 3.0f, 4.0f));
+FragmentOutputs clamp_frag_depth_FragmentOutputs(FragmentOutputs s) {
+ FragmentOutputs tint_symbol_1 = FragmentOutputs(s.loc0, clamp_frag_depth(s.frag_depth), s.loc1, s.loc2, s.sample_mask, s.loc3);
return tint_symbol_1;
}
+FragmentOutputs tint_symbol() {
+ FragmentOutputs tint_symbol_2 = FragmentOutputs(1, 2.0f, 1u, 1.0f, 2u, vec4(1.0f, 2.0f, 3.0f, 4.0f));
+ return clamp_frag_depth_FragmentOutputs(tint_symbol_2);
+}
+
void main() {
FragmentOutputs inner_result = tint_symbol();
loc0_1 = inner_result.loc0;
diff --git a/test/tint/types/functions/shader_io/fragment_output_mixed_f16.wgsl.expected.glsl b/test/tint/types/functions/shader_io/fragment_output_mixed_f16.wgsl.expected.glsl
index a10d9c0..5fdfa4d 100644
--- a/test/tint/types/functions/shader_io/fragment_output_mixed_f16.wgsl.expected.glsl
+++ b/test/tint/types/functions/shader_io/fragment_output_mixed_f16.wgsl.expected.glsl
@@ -10,6 +10,16 @@
layout(location = 3) out vec4 loc3_1;
layout(location = 4) out float16_t loc4_1;
layout(location = 5) out f16vec3 loc5_1;
+struct PushConstants {
+ float min_depth;
+ float max_depth;
+};
+
+layout(location=0) uniform PushConstants push_constants;
+float clamp_frag_depth(float v) {
+ return clamp(v, push_constants.min_depth, push_constants.max_depth);
+}
+
struct FragmentOutputs {
int loc0;
float frag_depth;
@@ -21,11 +31,16 @@
f16vec3 loc5;
};
-FragmentOutputs tint_symbol() {
- FragmentOutputs tint_symbol_1 = FragmentOutputs(1, 2.0f, 1u, 1.0f, 2u, vec4(1.0f, 2.0f, 3.0f, 4.0f), 2.25hf, f16vec3(3.0hf, 5.0hf, 8.0hf));
+FragmentOutputs clamp_frag_depth_FragmentOutputs(FragmentOutputs s) {
+ FragmentOutputs tint_symbol_1 = FragmentOutputs(s.loc0, clamp_frag_depth(s.frag_depth), s.loc1, s.loc2, s.sample_mask, s.loc3, s.loc4, s.loc5);
return tint_symbol_1;
}
+FragmentOutputs tint_symbol() {
+ FragmentOutputs tint_symbol_2 = FragmentOutputs(1, 2.0f, 1u, 1.0f, 2u, vec4(1.0f, 2.0f, 3.0f, 4.0f), 2.25hf, f16vec3(3.0hf, 5.0hf, 8.0hf));
+ return clamp_frag_depth_FragmentOutputs(tint_symbol_2);
+}
+
void main() {
FragmentOutputs inner_result = tint_symbol();
loc0_1 = inner_result.loc0;