diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 5fc8859616af86b18d2d94de8f222076586dc17e..d1d9beccbb4c63b73e0f9726e1aa2e682556cac4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -260,6 +260,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
         SyncDepthModifiers();
         break;
 
+    // Depth buffering
+    case PICA_REG_INDEX(depthmap_enable):
+        shader_dirty = true;
+        break;
+
     // Blending
     case PICA_REG_INDEX(output_merger.alphablend_enable):
         SyncBlendEnabled();
@@ -910,10 +915,10 @@ void RasterizerOpenGL::SyncCullMode() {
 }
 
 void RasterizerOpenGL::SyncDepthModifiers() {
-    float depth_scale = -Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_range).ToFloat32();
-    float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32() / 2.0f;
+    float depth_scale = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_range).ToFloat32();
+    float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32();
 
-    // TODO: Implement scale modifier
+    uniform_block_data.data.depth_scale = depth_scale;
     uniform_block_data.data.depth_offset = depth_offset;
     uniform_block_data.dirty = true;
 }
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 4f9a032fb2eed8f67d46feeb1edc6f626b42be5a..6fdb7f61b7cd0c574af2a391d0c329d98f1bf31c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -56,6 +56,8 @@ union PicaShaderConfig {
 
         const auto& regs = Pica::g_state.regs;
 
+        state.depthmap_enable = regs.depthmap_enable;
+
         state.alpha_test_func = regs.output_merger.alpha_test.enable ?
             regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always;
 
@@ -171,6 +173,8 @@ union PicaShaderConfig {
         std::array<TevStageConfigRaw, 6> tev_stages;
         u8 combiner_buffer_input;
 
+        Pica::Regs::DepthBuffering depthmap_enable;
+
         struct {
             struct {
                 unsigned num;
@@ -315,6 +319,7 @@ private:
         GLvec4 const_color[6];
         GLvec4 tev_combiner_buffer_color;
         GLint alphatest_ref;
+        GLfloat depth_scale;
         GLfloat depth_offset;
         alignas(16) GLvec3 lighting_global_ambient;
         LightSrc light_src[8];
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 0890adb12b9aaf5e6b155d53261b3d5b2e27c431..0c3153e8f8164eea8ce981554645692b45bd0113 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -540,6 +540,7 @@ layout (std140) uniform shader_data {
     vec4 const_color[NUM_TEV_STAGES];
     vec4 tev_combiner_buffer_color;
     int alphatest_ref;
+    float depth_scale;
     float depth_offset;
     vec3 lighting_global_ambient;
     LightSrc light_src[NUM_LIGHTS];
@@ -581,7 +582,15 @@ vec4 secondary_fragment_color = vec4(0.0);
     }
 
     out += "color = last_tex_env_out;\n";
-    out += "gl_FragDepth = gl_FragCoord.z + depth_offset;\n}";
+
+    out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";
+    out += "float depth = z_over_w * depth_scale + depth_offset;\n";
+    if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
+        out += "depth /= gl_FragCoord.w;\n";
+    }
+    out += "gl_FragDepth = depth;\n";
+
+    out += "}";
 
     return out;
 }