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)
{
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 <<

View File

@ -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();
}

View File

@ -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
};

View File

@ -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())

View File

@ -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);
}

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
@ -3169,8 +3157,8 @@ namespace rsx
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_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_MAX, 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<invalidate_zclip_bits>>();
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_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_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_range<NV4097_SET_VIEWPORT_SCALE, 1, 3, nv4097::set_viewport_dirty_bit>();
bind_range<NV4097_SET_VIEWPORT_OFFSET, 1, 3, nv4097::set_viewport_dirty_bit>();
bind_array<NV4097_SET_VIEWPORT_SCALE, 1, 3, nv4097::notify_state_changed<vertex_state_dirty>>();
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_BLEND_EQUATION, nv4097::set_blend_equation>();
bind<NV4097_SET_BLEND_FUNC_SFACTOR, nv4097::set_blend_factor>();