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
This commit is contained in:
kd-11 2020-08-18 19:51:11 +03:00 committed by kd-11
parent dc465df3bc
commit 6380e67af9
6 changed files with 60 additions and 33 deletions

View File

@ -576,19 +576,34 @@ namespace glsl
if (props.domain == glsl::program_domain::glsl_vertex_program && props.emulate_zclip_transform) if (props.domain == glsl::program_domain::glsl_vertex_program && props.emulate_zclip_transform)
{ {
OS << 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" "{\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) if (!props.emulate_depth_clip_only)
{ {
OS << OS <<
" float d = float(pos.z * rcp_precise(pos.w));\n"
" if (d < 0.f && d >= near_plane)\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" " 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" " d = min(1., 0.99 + (0.01 * (pos.z - near_plane) / (far_plane - near_plane)));\n"
" }\n"
" else\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" "\n"
" return vec4(pos.x, pos.y, d * pos.w, pos.w);\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. // 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. // 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 << OS <<
" double inv_range = double(1.0) / double(far_plane - near_plane);\n" " if (far_plane != 0.0)\n"
" double new_d = (double(d) - double(near_plane)) * inv_range;\n" " {\n"
"\n" " double z_range = (far_plane > near_plane)? (far_plane - near_plane) : far_plane;\n"
" return vec4(pos.x, pos.y, float(new_d * pos.w), pos.w);\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 << OS <<

View File

@ -257,15 +257,15 @@ void GLGSRender::update_draw_state()
//NV4097_SET_TWO_SIDE_LIGHT_EN //NV4097_SET_TWO_SIDE_LIGHT_EN
//NV4097_SET_FLAT_SHADE_OP //NV4097_SET_FLAT_SHADE_OP
//NV4097_SET_EDGE_FLAG //NV4097_SET_EDGE_FLAG
//NV4097_SET_COLOR_KEY_COLOR //NV4097_SET_COLOR_KEY_COLOR
//NV4097_SET_SHADER_CONTROL //NV4097_SET_SHADER_CONTROL
//NV4097_SET_ZMIN_MAX_CONTROL //NV4097_SET_ZMIN_MAX_CONTROL
//NV4097_SET_ANTI_ALIASING_CONTROL //NV4097_SET_ANTI_ALIASING_CONTROL
//NV4097_SET_CLIP_ID_TEST_ENABLE //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(); m_frame_stats.setup_time += m_profiler.duration();
} }

View File

@ -78,14 +78,16 @@ namespace rsx
fragment_texture_state_dirty = 0x80, // Fragment texture parameters changed fragment_texture_state_dirty = 0x80, // Fragment texture parameters changed
vertex_texture_state_dirty = 0x100, // Fragment texture parameters changed vertex_texture_state_dirty = 0x100, // Fragment texture parameters changed
scissor_config_state_dirty = 0x200, // Scissor region 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_invalid = 0x800, // Scissor configuration is broken
scissor_setup_clipped = 0x800, // Scissor region is cropped by viewport constraint scissor_setup_clipped = 0x1000, // Scissor region is cropped by viewport constraint
polygon_stipple_pattern_dirty = 0x1000, // Rasterizer stippling pattern changed polygon_stipple_pattern_dirty = 0x2000, // Rasterizer stippling pattern changed
line_stipple_pattern_dirty = 0x2000, // Line stippling pattern changed line_stipple_pattern_dirty = 0x4000, // Line stippling pattern changed
invalidate_pipeline_bits = fragment_program_dirty | vertex_program_dirty, 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, memory_barrier_bits = framebuffer_reads_dirty,
all_dirty = ~0u all_dirty = ~0u
}; };

View File

@ -117,8 +117,9 @@ void VKGSRender::update_draw_state()
} }
else else
{ {
bounds_min = rsx::method_registers.clip_min(); // Avoid special case where min=max and depth bounds (incorrectly) fails
bounds_max = rsx::method_registers.clip_max(); 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()) if (!m_device->get_unrestricted_depth_range_support())

View File

@ -974,6 +974,8 @@ void VKGSRender::set_viewport()
m_viewport.minDepth = 0.f; m_viewport.minDepth = 0.f;
m_viewport.maxDepth = 1.f; m_viewport.maxDepth = 1.f;
} }
m_graphics_state &= ~(rsx::pipeline_state::zclip_config_state_dirty);
} }
void VKGSRender::set_scissor(bool clip_viewport) void VKGSRender::set_scissor(bool clip_viewport)
@ -990,6 +992,17 @@ void VKGSRender::set_scissor(bool clip_viewport)
void VKGSRender::bind_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); vkCmdSetViewport(*m_current_command_buffer, 0, 1, &m_viewport);
vkCmdSetScissor(*m_current_command_buffer, 0, 1, &m_scissor); vkCmdSetScissor(*m_current_command_buffer, 0, 1, &m_scissor);
} }

View File

@ -887,18 +887,6 @@ namespace rsx
} }
} }
}; };
template<u32 index>
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 namespace nv308a
@ -3169,8 +3157,8 @@ namespace rsx
bind<NV4097_SET_VERTEX_DATA_BASE_INDEX, nv4097::set_index_base_offset>(); bind<NV4097_SET_VERTEX_DATA_BASE_INDEX, nv4097::set_index_base_offset>();
bind<NV4097_SET_USER_CLIP_PLANE_CONTROL, nv4097::notify_state_changed<vertex_state_dirty>>(); bind<NV4097_SET_USER_CLIP_PLANE_CONTROL, nv4097::notify_state_changed<vertex_state_dirty>>();
bind<NV4097_SET_TRANSFORM_BRANCH_BITS, nv4097::notify_state_changed<vertex_state_dirty>>(); bind<NV4097_SET_TRANSFORM_BRANCH_BITS, nv4097::notify_state_changed<vertex_state_dirty>>();
bind<NV4097_SET_CLIP_MIN, nv4097::notify_state_changed<vertex_state_dirty>>(); bind<NV4097_SET_CLIP_MIN, nv4097::notify_state_changed<invalidate_zclip_bits>>();
bind<NV4097_SET_CLIP_MAX, nv4097::notify_state_changed<vertex_state_dirty>>(); bind<NV4097_SET_CLIP_MAX, nv4097::notify_state_changed<invalidate_zclip_bits>>();
bind<NV4097_SET_POINT_SIZE, nv4097::notify_state_changed<vertex_state_dirty>>(); bind<NV4097_SET_POINT_SIZE, nv4097::notify_state_changed<vertex_state_dirty>>();
bind<NV4097_SET_ALPHA_FUNC, nv4097::notify_state_changed<fragment_state_dirty>>(); bind<NV4097_SET_ALPHA_FUNC, nv4097::notify_state_changed<fragment_state_dirty>>();
bind<NV4097_SET_ALPHA_REF, nv4097::notify_state_changed<fragment_state_dirty>>(); bind<NV4097_SET_ALPHA_REF, nv4097::notify_state_changed<fragment_state_dirty>>();
@ -3184,8 +3172,8 @@ namespace rsx
bind<NV4097_SET_VIEWPORT_HORIZONTAL, nv4097::notify_state_changed<scissor_config_state_dirty>>(); bind<NV4097_SET_VIEWPORT_HORIZONTAL, nv4097::notify_state_changed<scissor_config_state_dirty>>();
bind<NV4097_SET_VIEWPORT_VERTICAL, nv4097::notify_state_changed<scissor_config_state_dirty>>(); bind<NV4097_SET_VIEWPORT_VERTICAL, nv4097::notify_state_changed<scissor_config_state_dirty>>();
bind_array<NV4097_SET_FOG_PARAMS, 1, 2, nv4097::notify_state_changed<fragment_state_dirty>>(); bind_array<NV4097_SET_FOG_PARAMS, 1, 2, nv4097::notify_state_changed<fragment_state_dirty>>();
bind_range<NV4097_SET_VIEWPORT_SCALE, 1, 3, nv4097::set_viewport_dirty_bit>(); bind_array<NV4097_SET_VIEWPORT_SCALE, 1, 3, nv4097::notify_state_changed<vertex_state_dirty>>();
bind_range<NV4097_SET_VIEWPORT_OFFSET, 1, 3, nv4097::set_viewport_dirty_bit>(); bind_array<NV4097_SET_VIEWPORT_OFFSET, 1, 3, nv4097::notify_state_changed<vertex_state_dirty>>();
bind<NV4097_SET_INDEX_ARRAY_DMA, nv4097::check_index_array_dma>(); bind<NV4097_SET_INDEX_ARRAY_DMA, nv4097::check_index_array_dma>();
bind<NV4097_SET_BLEND_EQUATION, nv4097::set_blend_equation>(); bind<NV4097_SET_BLEND_EQUATION, nv4097::set_blend_equation>();
bind<NV4097_SET_BLEND_FUNC_SFACTOR, nv4097::set_blend_factor>(); bind<NV4097_SET_BLEND_FUNC_SFACTOR, nv4097::set_blend_factor>();