[glsl] Clamp frag depth using push constant values

Use the push constant layout generated by `PreparePushConstants` to
find the min and max values used for frag depth clamping.

Bug: 42251044
Change-Id: I2f3930e7bf39e1fa01c884465e3b2c23aa8343db
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/209835
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/glsl/writer/raise/BUILD.bazel b/src/tint/lang/glsl/writer/raise/BUILD.bazel
index 19351da..8122943 100644
--- a/src/tint/lang/glsl/writer/raise/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/raise/BUILD.bazel
@@ -113,6 +113,7 @@
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/ir",
+    "//src/tint/lang/core/ir/transform",
     "//src/tint/lang/core/ir/transform:test",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
diff --git a/src/tint/lang/glsl/writer/raise/BUILD.cmake b/src/tint/lang/glsl/writer/raise/BUILD.cmake
index b1b1a71..0893974 100644
--- a/src/tint/lang/glsl/writer/raise/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/raise/BUILD.cmake
@@ -121,6 +121,7 @@
   tint_lang_core_constant
   tint_lang_core_intrinsic
   tint_lang_core_ir
+  tint_lang_core_ir_transform
   tint_lang_core_ir_transform_test
   tint_lang_core_type
   tint_lang_wgsl
diff --git a/src/tint/lang/glsl/writer/raise/BUILD.gn b/src/tint/lang/glsl/writer/raise/BUILD.gn
index 51b4f74..3886a8a 100644
--- a/src/tint/lang/glsl/writer/raise/BUILD.gn
+++ b/src/tint/lang/glsl/writer/raise/BUILD.gn
@@ -117,6 +117,7 @@
         "${tint_src_dir}/lang/core/constant",
         "${tint_src_dir}/lang/core/intrinsic",
         "${tint_src_dir}/lang/core/ir",
+        "${tint_src_dir}/lang/core/ir/transform",
         "${tint_src_dir}/lang/core/ir/transform:unittests",
         "${tint_src_dir}/lang/core/type",
         "${tint_src_dir}/lang/wgsl",
diff --git a/src/tint/lang/glsl/writer/raise/raise.cc b/src/tint/lang/glsl/writer/raise/raise.cc
index 91d2037..b2e66e8 100644
--- a/src/tint/lang/glsl/writer/raise/raise.cc
+++ b/src/tint/lang/glsl/writer/raise/raise.cc
@@ -188,7 +188,8 @@
 
     RUN_TRANSFORM(core::ir::transform::AddEmptyEntryPoint, module);
 
-    RUN_TRANSFORM(raise::ShaderIO, module, raise::ShaderIOConfig{options.depth_range_offsets});
+    RUN_TRANSFORM(raise::ShaderIO, module,
+                  raise::ShaderIOConfig{push_constant_layout.Get(), options.depth_range_offsets});
 
     RUN_TRANSFORM(core::ir::transform::Std140, module);
 
diff --git a/src/tint/lang/glsl/writer/raise/shader_io.cc b/src/tint/lang/glsl/writer/raise/shader_io.cc
index 4e67e94..2e6054c 100644
--- a/src/tint/lang/glsl/writer/raise/shader_io.cc
+++ b/src/tint/lang/glsl/writer/raise/shader_io.cc
@@ -243,12 +243,16 @@
     /// @returns the clamped value
     core::ir::Value* ClampFragDepth([[maybe_unused]] core::ir::Builder& builder,
                                     core::ir::Value* frag_depth) {
-        // TODO(dsinclair): Add a clamp frag depth implementation. The `depth_offsets.{min,max}` are
-        // offsets into a push_constant structure, not the actual values as was done here.
-        //
-        // This needs to create a the `push_constant` structure (or append to the existing one if it
-        // was already created) and add these members.
-        return frag_depth;
+        if (!config.depth_range_offsets) {
+            return frag_depth;
+        }
+
+        auto* push_constants = config.push_constant_layout.var;
+        auto min_idx = u32(config.push_constant_layout.IndexOf(config.depth_range_offsets->min));
+        auto max_idx = u32(config.push_constant_layout.IndexOf(config.depth_range_offsets->max));
+        auto* min = builder.Load(builder.Access<ptr<push_constant, f32>>(push_constants, min_idx));
+        auto* max = builder.Load(builder.Access<ptr<push_constant, f32>>(push_constants, max_idx));
+        return builder.Call<f32>(core::BuiltinFn::kClamp, frag_depth, min, max)->Result(0);
     }
 
     /// @copydoc ShaderIO::BackendState::NeedsVertexPointSize
diff --git a/src/tint/lang/glsl/writer/raise/shader_io.h b/src/tint/lang/glsl/writer/raise/shader_io.h
index d847718..d857e05 100644
--- a/src/tint/lang/glsl/writer/raise/shader_io.h
+++ b/src/tint/lang/glsl/writer/raise/shader_io.h
@@ -30,6 +30,7 @@
 
 #include <string>
 
+#include "src/tint/lang/core/ir/transform/prepare_push_constants.h"
 #include "src/tint/lang/glsl/writer/common/options.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
@@ -43,12 +44,15 @@
 
 /// ShaderIOConfig describes the set of configuration options for the ShaderIO transform.
 struct ShaderIOConfig {
+    /// push constant layout information
+    const core::ir::transform::PushConstantLayout& push_constant_layout;
+
     /// offsets for clamping frag depth
-    std::optional<Options::RangeOffsets> depth_range_offsets;
+    std::optional<Options::RangeOffsets> depth_range_offsets{};
 };
 
 /// ShaderIO is a transform that moves each entry point function's parameters and return value to
-/// global variables to prepare them for SPIR-V codegen.
+/// global variables to prepare them for GLSL codegen.
 /// @param module the module to transform
 /// @param config the configuration
 /// @returns success or failure
diff --git a/src/tint/lang/glsl/writer/raise/shader_io_test.cc b/src/tint/lang/glsl/writer/raise/shader_io_test.cc
index 638540f..67cb91a 100644
--- a/src/tint/lang/glsl/writer/raise/shader_io_test.cc
+++ b/src/tint/lang/glsl/writer/raise/shader_io_test.cc
@@ -59,7 +59,8 @@
 
     auto* expect = src;
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -139,7 +140,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -290,7 +292,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -411,7 +414,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -467,7 +471,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -512,7 +517,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -631,7 +637,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -717,7 +724,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -867,7 +875,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -973,7 +982,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -1070,7 +1080,8 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
@@ -1230,13 +1241,14 @@
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PushConstantLayout push_constants;
+    ShaderIOConfig config{push_constants};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
 }
 
-TEST_F(GlslWriter_ShaderIOTest, DISABLED_ClampFragDepth) {
+TEST_F(GlslWriter_ShaderIOTest, ClampFragDepth) {
     auto* str_ty = ty.Struct(mod.symbols.New("Outputs"),
                              {
                                  {
@@ -1293,38 +1305,54 @@
   depth:f32 @offset(4)
 }
 
+tint_push_constant_struct = struct @align(4), @block {
+  depth_min:f32 @offset(4)
+  depth_max:f32 @offset(8)
+}
+
 $B1: {  # root
+  %tint_push_constants:ptr<push_constant, tint_push_constant_struct, read> = var
   %foo_loc0_Output:ptr<__out, f32, write> = var @location(0)
   %gl_FragDepth:ptr<__out, f32, write> = var @builtin(frag_depth)
 }
 
 %foo_inner = func():Outputs {
   $B2: {
-    %4:Outputs = construct 0.5f, 2.0f
-    ret %4
+    %5:Outputs = construct 0.5f, 2.0f
+    ret %5
   }
 }
 %foo = @fragment func():void {
   $B3: {
-    %6:Outputs = call %foo_inner
-    %7:f32 = access %6, 0u
-    store %foo_loc0_Output, %7
-    %8:f32 = access %6, 1u
-    %9:f32 = clamp %8, 2.0f, 3.0f
-    store %gl_FragDepth, %9
+    %7:Outputs = call %foo_inner
+    %8:f32 = access %7, 0u
+    store %foo_loc0_Output, %8
+    %9:f32 = access %7, 1u
+    %10:ptr<push_constant, f32, read> = access %tint_push_constants, 0u
+    %11:f32 = load %10
+    %12:ptr<push_constant, f32, read> = access %tint_push_constants, 1u
+    %13:f32 = load %12
+    %14:f32 = clamp %9, %11, %13
+    store %gl_FragDepth, %14
     ret
   }
 }
 )";
 
-    ShaderIOConfig config;
-    config.depth_range_offsets = {2, 3};
+    core::ir::transform::PreparePushConstantsConfig push_constants_config;
+    push_constants_config.AddInternalConstant(4, mod.symbols.New("depth_min"), ty.f32());
+    push_constants_config.AddInternalConstant(8, mod.symbols.New("depth_max"), ty.f32());
+    auto push_constants = PreparePushConstants(mod, push_constants_config);
+    EXPECT_EQ(push_constants, Success);
+
+    ShaderIOConfig config{push_constants.Get()};
+    config.depth_range_offsets = {4, 8};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
 }
 
-TEST_F(GlslWriter_ShaderIOTest, DISABLED_ClampFragDepth_MultipleFragmentShaders) {
+TEST_F(GlslWriter_ShaderIOTest, ClampFragDepth_MultipleFragmentShaders) {
     auto* str_ty = ty.Struct(mod.symbols.New("Outputs"),
                              {
                                  {
@@ -1397,7 +1425,13 @@
   depth:f32 @offset(4)
 }
 
+tint_push_constant_struct = struct @align(4), @block {
+  depth_min:f32 @offset(4)
+  depth_max:f32 @offset(8)
+}
+
 $B1: {  # root
+  %tint_push_constants:ptr<push_constant, tint_push_constant_struct, read> = var
   %ep1_loc0_Output:ptr<__out, f32, write> = var @location(0)
   %gl_FragDepth:ptr<__out, f32, write> = var @builtin(frag_depth)
   %ep2_loc0_Output:ptr<__out, f32, write> = var @location(0)
@@ -1408,58 +1442,77 @@
 
 %ep1_inner = func():Outputs {
   $B2: {
-    %8:Outputs = construct 0.5f, 2.0f
-    ret %8
+    %9:Outputs = construct 0.5f, 2.0f
+    ret %9
   }
 }
 %ep2_inner = func():Outputs {
   $B3: {
-    %10:Outputs = construct 0.5f, 2.0f
-    ret %10
+    %11:Outputs = construct 0.5f, 2.0f
+    ret %11
   }
 }
 %ep3_inner = func():Outputs {
   $B4: {
-    %12:Outputs = construct 0.5f, 2.0f
-    ret %12
+    %13:Outputs = construct 0.5f, 2.0f
+    ret %13
   }
 }
 %ep1 = @fragment func():void {
   $B5: {
-    %14:Outputs = call %ep1_inner
-    %15:f32 = access %14, 0u
-    store %ep1_loc0_Output, %15
-    %16:f32 = access %14, 1u
-    %17:f32 = clamp %16, 0.0f, 0.0f
-    store %gl_FragDepth, %17
+    %15:Outputs = call %ep1_inner
+    %16:f32 = access %15, 0u
+    store %ep1_loc0_Output, %16
+    %17:f32 = access %15, 1u
+    %18:ptr<push_constant, f32, read> = access %tint_push_constants, 0u
+    %19:f32 = load %18
+    %20:ptr<push_constant, f32, read> = access %tint_push_constants, 1u
+    %21:f32 = load %20
+    %22:f32 = clamp %17, %19, %21
+    store %gl_FragDepth, %22
     ret
   }
 }
 %ep2 = @fragment func():void {
   $B6: {
-    %19:Outputs = call %ep2_inner
-    %20:f32 = access %19, 0u
-    store %ep2_loc0_Output, %20
-    %21:f32 = access %19, 1u
-    %22:f32 = clamp %21, 0.0f, 0.0f
-    store %gl_FragDepth_1, %22
+    %24:Outputs = call %ep2_inner
+    %25:f32 = access %24, 0u
+    store %ep2_loc0_Output, %25
+    %26:f32 = access %24, 1u
+    %27:ptr<push_constant, f32, read> = access %tint_push_constants, 0u
+    %28:f32 = load %27
+    %29:ptr<push_constant, f32, read> = access %tint_push_constants, 1u
+    %30:f32 = load %29
+    %31:f32 = clamp %26, %28, %30
+    store %gl_FragDepth_1, %31
     ret
   }
 }
 %ep3 = @fragment func():void {
   $B7: {
-    %24:Outputs = call %ep3_inner
-    %25:f32 = access %24, 0u
-    store %ep3_loc0_Output, %25
-    %26:f32 = access %24, 1u
-    %27:f32 = clamp %26, 0.0f, 0.0f
-    store %gl_FragDepth_2, %27
+    %33:Outputs = call %ep3_inner
+    %34:f32 = access %33, 0u
+    store %ep3_loc0_Output, %34
+    %35:f32 = access %33, 1u
+    %36:ptr<push_constant, f32, read> = access %tint_push_constants, 0u
+    %37:f32 = load %36
+    %38:ptr<push_constant, f32, read> = access %tint_push_constants, 1u
+    %39:f32 = load %38
+    %40:f32 = clamp %35, %37, %39
+    store %gl_FragDepth_2, %40
     ret
   }
 }
 )";
 
-    ShaderIOConfig config;
+    core::ir::transform::PreparePushConstantsConfig push_constants_config;
+    push_constants_config.AddInternalConstant(4, mod.symbols.New("depth_min"), ty.f32());
+    push_constants_config.AddInternalConstant(8, mod.symbols.New("depth_max"), ty.f32());
+    auto push_constants = PreparePushConstants(mod, push_constants_config);
+    EXPECT_EQ(push_constants, Success);
+
+    ShaderIOConfig config{push_constants.Get()};
+    config.depth_range_offsets = {4, 8};
     Run(ShaderIO, config);
 
     EXPECT_EQ(expect, str());
diff --git a/test/tint/types/functions/shader_io/fragment_output_builtins.wgsl.expected.ir.glsl b/test/tint/types/functions/shader_io/fragment_output_builtins.wgsl.expected.ir.glsl
index 789ea76..0fab68e 100644
--- a/test/tint/types/functions/shader_io/fragment_output_builtins.wgsl.expected.ir.glsl
+++ b/test/tint/types/functions/shader_io/fragment_output_builtins.wgsl.expected.ir.glsl
@@ -13,7 +13,8 @@
   return 1.0f;
 }
 void main() {
-  gl_FragDepth = main1_inner();
+  float v = main1_inner();
+  gl_FragDepth = clamp(v, tint_push_constants.tint_frag_depth_min, tint_push_constants.tint_frag_depth_max);
 }
 #version 310 es
 #extension GL_OES_sample_variables: require
diff --git a/test/tint/types/functions/shader_io/fragment_output_builtins_struct.wgsl.expected.ir.glsl b/test/tint/types/functions/shader_io/fragment_output_builtins_struct.wgsl.expected.ir.glsl
index 3d6f909..9d3e79b 100644
--- a/test/tint/types/functions/shader_io/fragment_output_builtins_struct.wgsl.expected.ir.glsl
+++ b/test/tint/types/functions/shader_io/fragment_output_builtins_struct.wgsl.expected.ir.glsl
@@ -20,6 +20,6 @@
 }
 void main() {
   FragmentOutputs v = tint_symbol_inner();
-  gl_FragDepth = v.frag_depth;
+  gl_FragDepth = clamp(v.frag_depth, tint_push_constants.tint_frag_depth_min, tint_push_constants.tint_frag_depth_max);
   gl_SampleMask[0u] = int(v.sample_mask);
 }
diff --git a/test/tint/types/functions/shader_io/fragment_output_mixed.wgsl.expected.ir.glsl b/test/tint/types/functions/shader_io/fragment_output_mixed.wgsl.expected.ir.glsl
index 42f7bc4..a56141e 100644
--- a/test/tint/types/functions/shader_io/fragment_output_mixed.wgsl.expected.ir.glsl
+++ b/test/tint/types/functions/shader_io/fragment_output_mixed.wgsl.expected.ir.glsl
@@ -29,7 +29,7 @@
 void main() {
   FragmentOutputs v = tint_symbol_inner();
   tint_symbol_loc0_Output = v.loc0;
-  gl_FragDepth = v.frag_depth;
+  gl_FragDepth = clamp(v.frag_depth, tint_push_constants.tint_frag_depth_min, tint_push_constants.tint_frag_depth_max);
   tint_symbol_loc1_Output = v.loc1;
   tint_symbol_loc2_Output = v.loc2;
   gl_SampleMask[0u] = int(v.sample_mask);
diff --git a/test/tint/types/functions/shader_io/fragment_output_mixed_f16.wgsl.expected.ir.glsl b/test/tint/types/functions/shader_io/fragment_output_mixed_f16.wgsl.expected.ir.glsl
index 8a9b3d8..f78dbb0 100644
--- a/test/tint/types/functions/shader_io/fragment_output_mixed_f16.wgsl.expected.ir.glsl
+++ b/test/tint/types/functions/shader_io/fragment_output_mixed_f16.wgsl.expected.ir.glsl
@@ -34,7 +34,7 @@
 void main() {
   FragmentOutputs v = tint_symbol_inner();
   tint_symbol_loc0_Output = v.loc0;
-  gl_FragDepth = v.frag_depth;
+  gl_FragDepth = clamp(v.frag_depth, tint_push_constants.tint_frag_depth_min, tint_push_constants.tint_frag_depth_max);
   tint_symbol_loc1_Output = v.loc1;
   tint_symbol_loc2_Output = v.loc2;
   gl_SampleMask[0u] = int(v.sample_mask);