[glsl] Add builtin depth mode support

Bug: 457993779
Change-Id: I601384ad01ae90c482eeffe47e413f252fa1d343
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/273915
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: Stephen White <senorblanco@chromium.org>
Commit-Queue: Fr <beaufort.francois@gmail.com>
diff --git a/src/tint/lang/glsl/writer/printer/printer.cc b/src/tint/lang/glsl/writer/printer/printer.cc
index 0ce4042..bbf6a38 100644
--- a/src/tint/lang/glsl/writer/printer/printer.cc
+++ b/src/tint/lang/glsl/writer/printer/printer.cc
@@ -103,6 +103,7 @@
 constexpr const char* kEXTTextureShadowLod = "GL_EXT_texture_shadow_lod";
 constexpr const char* kEXTGeometryShader = "GL_EXT_geometry_shader";
 constexpr const char* kEXTFragmentShaderBarycentric = "GL_EXT_fragment_shader_barycentric";
+constexpr const char* kEXTConservativeDepth = "GL_EXT_conservative_depth";
 
 enum class LayoutFormat : uint8_t {
     kStd140,
@@ -1148,6 +1149,19 @@
                 EmitExtension(kOESSampleVariables);
             }
 
+            if (attrs.builtin == tint::core::BuiltinValue::kFragDepth) {
+                if (attrs.depth_mode == core::BuiltinDepthMode::kGreater ||
+                    attrs.depth_mode == core::BuiltinDepthMode::kLess) {
+                    if (options_.version.IsES()) {
+                        EmitExtension(kEXTConservativeDepth);
+                    }
+                    std::string depth_layout_qualifier =
+                        (attrs.depth_mode == core::BuiltinDepthMode::kGreater) ? "depth_greater"
+                                                                               : "depth_less";
+                    Line() << "layout(" << depth_layout_qualifier << ") out float gl_FragDepth;";
+                }
+            }
+
             // Do not emit builtin (gl_) variables, but register the GLSL builtin names so that they
             // are correct at the point of use.
             names_.Add(var->Result(), GLSLBuiltinToString(*attrs.builtin, addrspace));
diff --git a/test/tint/extensions/fragment_depth/basic.wgsl.expected.glsl b/test/tint/extensions/fragment_depth/basic.wgsl.expected.glsl
index ef77cdb..5628ac7 100644
--- a/test/tint/extensions/fragment_depth/basic.wgsl.expected.glsl
+++ b/test/tint/extensions/fragment_depth/basic.wgsl.expected.glsl
@@ -23,6 +23,7 @@
 // less
 //
 #version 310 es
+#extension GL_EXT_conservative_depth: require
 precision highp float;
 precision highp int;
 
@@ -33,6 +34,7 @@
 };
 
 layout(location = 0) uniform tint_immediate_struct tint_immediates;
+layout(depth_less) out float gl_FragDepth;
 float less_inner() {
   return 1.0f;
 }
@@ -44,6 +46,7 @@
 // greater
 //
 #version 310 es
+#extension GL_EXT_conservative_depth: require
 precision highp float;
 precision highp int;
 
@@ -54,6 +57,7 @@
 };
 
 layout(location = 0) uniform tint_immediate_struct tint_immediates;
+layout(depth_greater) out float gl_FragDepth;
 float greater_inner() {
   return 1.0f;
 }
diff --git a/test/tint/extensions/fragment_depth/glsl-desktop.wgsl b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl
new file mode 100644
index 0000000..6331a35
--- /dev/null
+++ b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl
@@ -0,0 +1,12 @@
+// flags: --glsl-desktop
+
+requires fragment_depth;
+
+@fragment
+fn any() -> @builtin(frag_depth, any) f32 { return 1.0; }
+
+@fragment
+fn less() -> @builtin(frag_depth, less) f32 { return 1.0; }
+
+@fragment
+fn greater() -> @builtin(frag_depth, greater) f32 { return 1.0; }
diff --git a/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.dxc.hlsl b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d59d002
--- /dev/null
+++ b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.dxc.hlsl
@@ -0,0 +1,51 @@
+//
+// any
+//
+struct any_outputs {
+  float tint_symbol : SV_Depth;
+};
+
+
+float any_inner() {
+  return 1.0f;
+}
+
+any_outputs any() {
+  any_outputs v = {any_inner()};
+  return v;
+}
+
+//
+// less
+//
+struct less_outputs {
+  float tint_symbol : SV_DepthLessEqual;
+};
+
+
+float less_inner() {
+  return 1.0f;
+}
+
+less_outputs less() {
+  less_outputs v = {less_inner()};
+  return v;
+}
+
+//
+// greater
+//
+struct greater_outputs {
+  float tint_symbol : SV_DepthGreaterEqual;
+};
+
+
+float greater_inner() {
+  return 1.0f;
+}
+
+greater_outputs greater() {
+  greater_outputs v = {greater_inner()};
+  return v;
+}
+
diff --git a/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.fxc.hlsl b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d59d002
--- /dev/null
+++ b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.fxc.hlsl
@@ -0,0 +1,51 @@
+//
+// any
+//
+struct any_outputs {
+  float tint_symbol : SV_Depth;
+};
+
+
+float any_inner() {
+  return 1.0f;
+}
+
+any_outputs any() {
+  any_outputs v = {any_inner()};
+  return v;
+}
+
+//
+// less
+//
+struct less_outputs {
+  float tint_symbol : SV_DepthLessEqual;
+};
+
+
+float less_inner() {
+  return 1.0f;
+}
+
+less_outputs less() {
+  less_outputs v = {less_inner()};
+  return v;
+}
+
+//
+// greater
+//
+struct greater_outputs {
+  float tint_symbol : SV_DepthGreaterEqual;
+};
+
+
+float greater_inner() {
+  return 1.0f;
+}
+
+greater_outputs greater() {
+  greater_outputs v = {greater_inner()};
+  return v;
+}
+
diff --git a/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.glsl b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.glsl
new file mode 100644
index 0000000..bc35f91
--- /dev/null
+++ b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.glsl
@@ -0,0 +1,65 @@
+//
+// any
+//
+#version 460
+precision highp float;
+precision highp int;
+
+
+struct tint_immediate_struct {
+  float tint_frag_depth_min;
+  float tint_frag_depth_max;
+};
+
+layout(location = 0) uniform tint_immediate_struct tint_immediates;
+float any_inner() {
+  return 1.0f;
+}
+void main() {
+  float v = any_inner();
+  gl_FragDepth = clamp(v, tint_immediates.tint_frag_depth_min, tint_immediates.tint_frag_depth_max);
+}
+//
+// less
+//
+#version 460
+precision highp float;
+precision highp int;
+
+
+struct tint_immediate_struct {
+  float tint_frag_depth_min;
+  float tint_frag_depth_max;
+};
+
+layout(location = 0) uniform tint_immediate_struct tint_immediates;
+layout(depth_less) out float gl_FragDepth;
+float less_inner() {
+  return 1.0f;
+}
+void main() {
+  float v = less_inner();
+  gl_FragDepth = clamp(v, tint_immediates.tint_frag_depth_min, tint_immediates.tint_frag_depth_max);
+}
+//
+// greater
+//
+#version 460
+precision highp float;
+precision highp int;
+
+
+struct tint_immediate_struct {
+  float tint_frag_depth_min;
+  float tint_frag_depth_max;
+};
+
+layout(location = 0) uniform tint_immediate_struct tint_immediates;
+layout(depth_greater) out float gl_FragDepth;
+float greater_inner() {
+  return 1.0f;
+}
+void main() {
+  float v = greater_inner();
+  gl_FragDepth = clamp(v, tint_immediates.tint_frag_depth_min, tint_immediates.tint_frag_depth_max);
+}
diff --git a/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.msl b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.msl
new file mode 100644
index 0000000..29d75c1
--- /dev/null
+++ b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.msl
@@ -0,0 +1,57 @@
+//
+// any
+//
+#include <metal_stdlib>
+using namespace metal;
+
+struct any_outputs {
+  float tint_symbol [[depth(any)]];
+};
+
+float any_inner() {
+  return 1.0f;
+}
+
+fragment any_outputs any() {
+  any_outputs tint_wrapper_result = {};
+  tint_wrapper_result.tint_symbol = any_inner();
+  return tint_wrapper_result;
+}
+//
+// less
+//
+#include <metal_stdlib>
+using namespace metal;
+
+struct less_outputs {
+  float tint_symbol [[depth(less)]];
+};
+
+float less_inner() {
+  return 1.0f;
+}
+
+fragment less_outputs less() {
+  less_outputs tint_wrapper_result = {};
+  tint_wrapper_result.tint_symbol = less_inner();
+  return tint_wrapper_result;
+}
+//
+// greater
+//
+#include <metal_stdlib>
+using namespace metal;
+
+struct greater_outputs {
+  float tint_symbol [[depth(greater)]];
+};
+
+float greater_inner() {
+  return 1.0f;
+}
+
+fragment greater_outputs greater() {
+  greater_outputs tint_wrapper_result = {};
+  tint_wrapper_result.tint_symbol = greater_inner();
+  return tint_wrapper_result;
+}
diff --git a/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.spvasm b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.spvasm
new file mode 100644
index 0000000..324b3e5
--- /dev/null
+++ b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.spvasm
@@ -0,0 +1,164 @@
+;
+; any
+;
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 1
+; Bound: 26
+; Schema: 0
+               OpCapability Shader
+         %25 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %any "any" %any_frag_depth_Output
+               OpExecutionMode %any OriginUpperLeft
+               OpExecutionMode %any DepthReplacing
+               OpMemberName %tint_immediate_data_struct 0 "tint_frag_depth_min"
+               OpMemberName %tint_immediate_data_struct 1 "tint_frag_depth_max"
+               OpName %tint_immediate_data_struct "tint_immediate_data_struct"
+               OpName %tint_immediate_data "tint_immediate_data"
+               OpName %any_frag_depth_Output "any_frag_depth_Output"
+               OpName %any_inner "any_inner"
+               OpName %any "any"
+               OpMemberDecorate %tint_immediate_data_struct 0 Offset 0
+               OpMemberDecorate %tint_immediate_data_struct 1 Offset 4
+               OpDecorate %tint_immediate_data_struct Block
+               OpDecorate %any_frag_depth_Output BuiltIn FragDepth
+      %float = OpTypeFloat 32
+%tint_immediate_data_struct = OpTypeStruct %float %float
+%_ptr_PushConstant_tint_immediate_data_struct = OpTypePointer PushConstant %tint_immediate_data_struct
+%tint_immediate_data = OpVariable %_ptr_PushConstant_tint_immediate_data_struct PushConstant
+%_ptr_Output_float = OpTypePointer Output %float
+%any_frag_depth_Output = OpVariable %_ptr_Output_float Output
+          %8 = OpTypeFunction %float
+    %float_1 = OpConstant %float 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+%_ptr_PushConstant_float = OpTypePointer PushConstant %float
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+     %uint_1 = OpConstant %uint 1
+  %any_inner = OpFunction %float None %8
+          %9 = OpLabel
+               OpReturnValue %float_1
+               OpFunctionEnd
+        %any = OpFunction %void None %13
+         %14 = OpLabel
+         %15 = OpFunctionCall %float %any_inner
+         %16 = OpAccessChain %_ptr_PushConstant_float %tint_immediate_data %uint_0
+         %20 = OpLoad %float %16 None
+         %21 = OpAccessChain %_ptr_PushConstant_float %tint_immediate_data %uint_1
+         %23 = OpLoad %float %21 None
+         %24 = OpExtInst %float %25 NClamp %15 %20 %23
+               OpStore %any_frag_depth_Output %24 None
+               OpReturn
+               OpFunctionEnd
+;
+; less
+;
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 1
+; Bound: 26
+; Schema: 0
+               OpCapability Shader
+         %25 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %less "less" %less_frag_depth_Output
+               OpExecutionMode %less OriginUpperLeft
+               OpExecutionMode %less DepthReplacing
+               OpExecutionMode %less DepthLess
+               OpMemberName %tint_immediate_data_struct 0 "tint_frag_depth_min"
+               OpMemberName %tint_immediate_data_struct 1 "tint_frag_depth_max"
+               OpName %tint_immediate_data_struct "tint_immediate_data_struct"
+               OpName %tint_immediate_data "tint_immediate_data"
+               OpName %less_frag_depth_Output "less_frag_depth_Output"
+               OpName %less_inner "less_inner"
+               OpName %less "less"
+               OpMemberDecorate %tint_immediate_data_struct 0 Offset 0
+               OpMemberDecorate %tint_immediate_data_struct 1 Offset 4
+               OpDecorate %tint_immediate_data_struct Block
+               OpDecorate %less_frag_depth_Output BuiltIn FragDepth
+      %float = OpTypeFloat 32
+%tint_immediate_data_struct = OpTypeStruct %float %float
+%_ptr_PushConstant_tint_immediate_data_struct = OpTypePointer PushConstant %tint_immediate_data_struct
+%tint_immediate_data = OpVariable %_ptr_PushConstant_tint_immediate_data_struct PushConstant
+%_ptr_Output_float = OpTypePointer Output %float
+%less_frag_depth_Output = OpVariable %_ptr_Output_float Output
+          %8 = OpTypeFunction %float
+    %float_1 = OpConstant %float 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+%_ptr_PushConstant_float = OpTypePointer PushConstant %float
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+     %uint_1 = OpConstant %uint 1
+ %less_inner = OpFunction %float None %8
+          %9 = OpLabel
+               OpReturnValue %float_1
+               OpFunctionEnd
+       %less = OpFunction %void None %13
+         %14 = OpLabel
+         %15 = OpFunctionCall %float %less_inner
+         %16 = OpAccessChain %_ptr_PushConstant_float %tint_immediate_data %uint_0
+         %20 = OpLoad %float %16 None
+         %21 = OpAccessChain %_ptr_PushConstant_float %tint_immediate_data %uint_1
+         %23 = OpLoad %float %21 None
+         %24 = OpExtInst %float %25 NClamp %15 %20 %23
+               OpStore %less_frag_depth_Output %24 None
+               OpReturn
+               OpFunctionEnd
+;
+; greater
+;
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 1
+; Bound: 26
+; Schema: 0
+               OpCapability Shader
+         %25 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %greater "greater" %greater_frag_depth_Output
+               OpExecutionMode %greater OriginUpperLeft
+               OpExecutionMode %greater DepthReplacing
+               OpExecutionMode %greater DepthGreater
+               OpMemberName %tint_immediate_data_struct 0 "tint_frag_depth_min"
+               OpMemberName %tint_immediate_data_struct 1 "tint_frag_depth_max"
+               OpName %tint_immediate_data_struct "tint_immediate_data_struct"
+               OpName %tint_immediate_data "tint_immediate_data"
+               OpName %greater_frag_depth_Output "greater_frag_depth_Output"
+               OpName %greater_inner "greater_inner"
+               OpName %greater "greater"
+               OpMemberDecorate %tint_immediate_data_struct 0 Offset 0
+               OpMemberDecorate %tint_immediate_data_struct 1 Offset 4
+               OpDecorate %tint_immediate_data_struct Block
+               OpDecorate %greater_frag_depth_Output BuiltIn FragDepth
+      %float = OpTypeFloat 32
+%tint_immediate_data_struct = OpTypeStruct %float %float
+%_ptr_PushConstant_tint_immediate_data_struct = OpTypePointer PushConstant %tint_immediate_data_struct
+%tint_immediate_data = OpVariable %_ptr_PushConstant_tint_immediate_data_struct PushConstant
+%_ptr_Output_float = OpTypePointer Output %float
+%greater_frag_depth_Output = OpVariable %_ptr_Output_float Output
+          %8 = OpTypeFunction %float
+    %float_1 = OpConstant %float 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+%_ptr_PushConstant_float = OpTypePointer PushConstant %float
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+     %uint_1 = OpConstant %uint 1
+%greater_inner = OpFunction %float None %8
+          %9 = OpLabel
+               OpReturnValue %float_1
+               OpFunctionEnd
+    %greater = OpFunction %void None %13
+         %14 = OpLabel
+         %15 = OpFunctionCall %float %greater_inner
+         %16 = OpAccessChain %_ptr_PushConstant_float %tint_immediate_data %uint_0
+         %20 = OpLoad %float %16 None
+         %21 = OpAccessChain %_ptr_PushConstant_float %tint_immediate_data %uint_1
+         %23 = OpLoad %float %21 None
+         %24 = OpExtInst %float %25 NClamp %15 %20 %23
+               OpStore %greater_frag_depth_Output %24 None
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.wgsl b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.wgsl
new file mode 100644
index 0000000..bdf78c8
--- /dev/null
+++ b/test/tint/extensions/fragment_depth/glsl-desktop.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+requires fragment_depth;
+
+@fragment
+fn any() -> @builtin(frag_depth) f32 {
+  return 1.0;
+}
+
+@fragment
+fn less() -> @builtin(frag_depth) f32 {
+  return 1.0;
+}
+
+@fragment
+fn greater() -> @builtin(frag_depth) f32 {
+  return 1.0;
+}
diff --git a/test/tint/extensions/fragment_depth/struct.wgsl.expected.glsl b/test/tint/extensions/fragment_depth/struct.wgsl.expected.glsl
index e3c3c4b..7b28e2e 100644
--- a/test/tint/extensions/fragment_depth/struct.wgsl.expected.glsl
+++ b/test/tint/extensions/fragment_depth/struct.wgsl.expected.glsl
@@ -27,6 +27,7 @@
 // less
 //
 #version 310 es
+#extension GL_EXT_conservative_depth: require
 precision highp float;
 precision highp int;
 
@@ -41,6 +42,7 @@
 };
 
 layout(location = 0) uniform tint_immediate_struct tint_immediates;
+layout(depth_less) out float gl_FragDepth;
 FragDepthLessOutput less_inner() {
   return FragDepthLessOutput(1.0f);
 }
@@ -52,6 +54,7 @@
 // greater
 //
 #version 310 es
+#extension GL_EXT_conservative_depth: require
 precision highp float;
 precision highp int;
 
@@ -66,6 +69,7 @@
 };
 
 layout(location = 0) uniform tint_immediate_struct tint_immediates;
+layout(depth_greater) out float gl_FragDepth;
 FragDepthGreaterOutput greater_inner() {
   return FragDepthGreaterOutput(1.0f);
 }