From 6380e67af97752c588cb5ed209c7dffbfb21a5f3 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 18 Aug 2020 19:51:11 +0300 Subject: [PATCH] rsx: Fix depth clipping - Fix special case where n=f making (f-n) = 0 - Dynamically update depth range by setting dirty bits - Fix depth bounds when n=f and bounds test is disabled --- rpcs3/Emu/RSX/Common/GLSLCommon.h | 39 ++++++++++++++++++++++++------- rpcs3/Emu/RSX/GL/GLDraw.cpp | 6 ++--- rpcs3/Emu/RSX/RSXThread.h | 10 ++++---- rpcs3/Emu/RSX/VK/VKDraw.cpp | 5 ++-- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 13 +++++++++++ rpcs3/Emu/RSX/rsx_methods.cpp | 20 ++++------------ 6 files changed, 60 insertions(+), 33 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/GLSLCommon.h b/rpcs3/Emu/RSX/Common/GLSLCommon.h index d61459cd6a..15985dc629 100644 --- a/rpcs3/Emu/RSX/Common/GLSLCommon.h +++ b/rpcs3/Emu/RSX/Common/GLSLCommon.h @@ -576,19 +576,34 @@ namespace glsl if (props.domain == glsl::program_domain::glsl_vertex_program && props.emulate_zclip_transform) { OS << - "vec4 apply_zclip_xform(const in vec4 pos, const in float near_plane, const in float far_plane)\n" + "double rcp_precise(double x)\n" "{\n" - " float d = pos.z / pos.w;\n"; + " double scaled = x * 0.0009765625;\n" + " double inv = 1.0 / scaled;\n" + " return inv * 0.0009765625;\n" + "}\n" + "\n" + "vec4 apply_zclip_xform(const in vec4 pos, const in float near_plane, const in float far_plane)\n" + "{\n"; if (!props.emulate_depth_clip_only) { OS << + " float d = float(pos.z * rcp_precise(pos.w));\n" " if (d < 0.f && d >= near_plane)\n" - " d = 0.f;\n" //force clamp negative values + " {\n" + " // Clamp\n" + " d = 0.f;\n" + " }\n" " else if (d > 1.f && d <= far_plane)\n" + " {\n" + " // Compress Z and store towards highest end of the range\n" " d = min(1., 0.99 + (0.01 * (pos.z - near_plane) / (far_plane - near_plane)));\n" + " }\n" " else\n" - " return pos; //d = (0.99 * d);\n" //range compression for normal values is disabled until a solution to ops comparing z is found + " {\n" + " return pos;\n" + " }\n" "\n" " return vec4(pos.x, pos.y, d * pos.w, pos.w);\n"; } @@ -597,10 +612,18 @@ namespace glsl // Technically the depth value here is the 'final' depth that should be stored in the Z buffer. // Forward mapping eqn is d' = d * (f - n) + n, where d' is the stored Z value (this) and d is the normalized API value. OS << - " double inv_range = double(1.0) / double(far_plane - near_plane);\n" - " double new_d = (double(d) - double(near_plane)) * inv_range;\n" - "\n" - " return vec4(pos.x, pos.y, float(new_d * pos.w), pos.w);\n"; + " if (far_plane != 0.0)\n" + " {\n" + " double z_range = (far_plane > near_plane)? (far_plane - near_plane) : far_plane;\n" + " double inv_range = rcp_precise(z_range);\n" + " float d = float(pos.z * rcp_precise(pos.w));\n" + " float new_d = (d - near_plane) * float(inv_range);\n" + " return vec4(pos.x, pos.y, (new_d * pos.w), pos.w);\n" + " }\n" + " else\n" + " {\n" + " return pos;\n" // Only values where Z=0 can ever pass this clip + " }\n"; } OS << diff --git a/rpcs3/Emu/RSX/GL/GLDraw.cpp b/rpcs3/Emu/RSX/GL/GLDraw.cpp index 46da003033..94f15433da 100644 --- a/rpcs3/Emu/RSX/GL/GLDraw.cpp +++ b/rpcs3/Emu/RSX/GL/GLDraw.cpp @@ -257,15 +257,15 @@ void GLGSRender::update_draw_state() //NV4097_SET_TWO_SIDE_LIGHT_EN //NV4097_SET_FLAT_SHADE_OP //NV4097_SET_EDGE_FLAG - - - //NV4097_SET_COLOR_KEY_COLOR //NV4097_SET_SHADER_CONTROL //NV4097_SET_ZMIN_MAX_CONTROL //NV4097_SET_ANTI_ALIASING_CONTROL //NV4097_SET_CLIP_ID_TEST_ENABLE + // For OGL Z range is updated every draw as it is separate from viewport config + m_graphics_state &= ~(rsx::pipeline_state::zclip_config_state_dirty); + m_frame_stats.setup_time += m_profiler.duration(); } diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 82f9e63ef0..999f8f086c 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -78,14 +78,16 @@ namespace rsx fragment_texture_state_dirty = 0x80, // Fragment texture parameters changed vertex_texture_state_dirty = 0x100, // Fragment texture parameters changed scissor_config_state_dirty = 0x200, // Scissor region changed + zclip_config_state_dirty = 0x400, // Viewport Z clip changed - scissor_setup_invalid = 0x400, // Scissor configuration is broken - scissor_setup_clipped = 0x800, // Scissor region is cropped by viewport constraint + scissor_setup_invalid = 0x800, // Scissor configuration is broken + scissor_setup_clipped = 0x1000, // Scissor region is cropped by viewport constraint - polygon_stipple_pattern_dirty = 0x1000, // Rasterizer stippling pattern changed - line_stipple_pattern_dirty = 0x2000, // Line stippling pattern changed + polygon_stipple_pattern_dirty = 0x2000, // Rasterizer stippling pattern changed + line_stipple_pattern_dirty = 0x4000, // Line stippling pattern changed invalidate_pipeline_bits = fragment_program_dirty | vertex_program_dirty, + invalidate_zclip_bits = vertex_state_dirty | zclip_config_state_dirty, memory_barrier_bits = framebuffer_reads_dirty, all_dirty = ~0u }; diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 104de76b92..2ae7824970 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -117,8 +117,9 @@ void VKGSRender::update_draw_state() } else { - bounds_min = rsx::method_registers.clip_min(); - bounds_max = rsx::method_registers.clip_max(); + // Avoid special case where min=max and depth bounds (incorrectly) fails + bounds_min = std::min(0.f, rsx::method_registers.clip_min()); + bounds_max = std::max(1.f, rsx::method_registers.clip_max()); } if (!m_device->get_unrestricted_depth_range_support()) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 82306001f6..d3dcb30dbe 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -974,6 +974,8 @@ void VKGSRender::set_viewport() m_viewport.minDepth = 0.f; m_viewport.maxDepth = 1.f; } + + m_graphics_state &= ~(rsx::pipeline_state::zclip_config_state_dirty); } void VKGSRender::set_scissor(bool clip_viewport) @@ -990,6 +992,17 @@ void VKGSRender::set_scissor(bool clip_viewport) void VKGSRender::bind_viewport() { + if (m_graphics_state & rsx::pipeline_state::zclip_config_state_dirty) + { + if (m_device->get_unrestricted_depth_range_support()) + { + m_viewport.minDepth = rsx::method_registers.clip_min(); + m_viewport.maxDepth = rsx::method_registers.clip_max(); + } + + m_graphics_state &= ~(rsx::pipeline_state::zclip_config_state_dirty); + } + vkCmdSetViewport(*m_current_command_buffer, 0, 1, &m_viewport); vkCmdSetScissor(*m_current_command_buffer, 0, 1, &m_scissor); } diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index cc0d470280..007bee6f5c 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -887,18 +887,6 @@ namespace rsx } } }; - - template - struct set_viewport_dirty_bit - { - static void impl(thread* rsx, u32 _reg, u32 arg) - { - if (arg != method_registers.register_previous_value) - { - rsx->m_graphics_state |= rsx::pipeline_state::vertex_state_dirty; - } - } - }; } namespace nv308a @@ -3169,8 +3157,8 @@ namespace rsx bind(); bind>(); bind>(); - bind>(); - bind>(); + bind>(); + bind>(); bind>(); bind>(); bind>(); @@ -3184,8 +3172,8 @@ namespace rsx bind>(); bind>(); bind_array>(); - bind_range(); - bind_range(); + bind_array>(); + bind_array>(); bind(); bind(); bind();