mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-10-11 22:49:55 +00:00
rsx: Emulate float depth range on hosts without extended depth range support
This commit is contained in:
@@ -1502,6 +1502,24 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
bool is_float_depth_format(rsx::surface_depth_format2 format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_depth_format2::z16_float:
|
||||
case rsx::surface_depth_format2::z24s8_float:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
f32 encode_emulated_depth(f32 depth)
|
||||
{
|
||||
// Halving the IEEE bit pattern of a non-negative float is monotonic and maps every finite value below 1
|
||||
return std::bit_cast<f32>((std::bit_cast<u32>(std::max(depth, 0.f)) & 0x7fffffffu) >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of texel lines decoded in one pitch-length number of bytes
|
||||
*/
|
||||
|
||||
@@ -367,6 +367,10 @@ namespace rsx
|
||||
f32 get_depth_clear_value(rsx::surface_depth_format2 format, u32 raw);
|
||||
f32 clamp_depth_bounds_value(rsx::surface_depth_format2 format, f32 value);
|
||||
bool is_depth_stencil_format(rsx::surface_depth_format2 format);
|
||||
bool is_float_depth_format(rsx::surface_depth_format2 format);
|
||||
|
||||
// Storage encoding of float depth when the host cannot hold depth values above 1. Must match encode_emulated_depth in GLSL.
|
||||
f32 encode_emulated_depth(f32 depth);
|
||||
|
||||
/**
|
||||
* Format feature support. There is not simple format to determine what is supported here, results are from hw tests
|
||||
|
||||
@@ -696,6 +696,15 @@ namespace rsx
|
||||
rop_control.set_blend_target_mask(blend_enable_mask);
|
||||
}
|
||||
|
||||
if (fragment_program.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE)
|
||||
{
|
||||
// Hardware clipping is disabled for these draws, see the fragment epilogue
|
||||
if (REGS(m_ctx)->depth_clamp_enabled() || !REGS(m_ctx)->depth_clip_enabled())
|
||||
{
|
||||
rop_control.enable_depth_clamp();
|
||||
}
|
||||
}
|
||||
|
||||
// Generate wpos coefficients
|
||||
// wpos equation is now as follows (ignoring pixel center offset):
|
||||
// wpos.y = (frag_coord / resolution_scale) * ((window_origin!=top)?-1.: 1.) + ((window_origin!=top)? window_height : 0)
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace gl
|
||||
{"tc6", 12},
|
||||
{"tc7", 13},
|
||||
{"tc8", 14},
|
||||
{"tc9", 15}
|
||||
{"tc9", 15},
|
||||
{"depth_range", 16} // clip range for depth range emulation
|
||||
}};
|
||||
|
||||
int get_varying_register_location(std::string_view varying_register_name)
|
||||
|
||||
@@ -233,6 +233,12 @@ namespace gl
|
||||
work_kernel = fmt::replace_all(work_kernel, "bswap_u32(value)", "value", 1);
|
||||
}
|
||||
|
||||
if (gl::emulate_extended_depth_range())
|
||||
{
|
||||
// Float depth surfaces hold the emulated encoding (half the bit pattern)
|
||||
work_kernel = fmt::replace_all(work_kernel, "f32_to_d24f(depth)", "f32_to_d24f(depth << 1)");
|
||||
}
|
||||
|
||||
cs_shuffle_base::build("");
|
||||
}
|
||||
|
||||
@@ -290,6 +296,11 @@ namespace gl
|
||||
work_kernel = fmt::replace_all(work_kernel, "value = bswap_u32(value)", "// value = bswap_u32(value)", 1);
|
||||
}
|
||||
|
||||
if (gl::emulate_extended_depth_range())
|
||||
{
|
||||
work_kernel = fmt::replace_all(work_kernel, "d24f_to_f32(depth)", "(d24f_to_f32(depth) >> 1)");
|
||||
}
|
||||
|
||||
cs_shuffle_base::build("");
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +144,12 @@ namespace gl
|
||||
" tmp = bswap_u32(tmp);\n";
|
||||
}
|
||||
|
||||
if (gl::emulate_extended_depth_range())
|
||||
{
|
||||
// Float depth surfaces hold the emulated encoding (half the bit pattern)
|
||||
work_kernel += " tmp.xy <<= 1;\n";
|
||||
}
|
||||
|
||||
// Convert
|
||||
work_kernel += " tmp.z = pack_e4m12_pack16(tmp.xy);\n";
|
||||
|
||||
@@ -175,6 +181,11 @@ namespace gl
|
||||
// Convert
|
||||
work_kernel += " tmp.yz = unpack_e4m12_pack16(tmp.x);\n";
|
||||
|
||||
if (gl::emulate_extended_depth_range())
|
||||
{
|
||||
work_kernel += " tmp.yz >>= 1;\n";
|
||||
}
|
||||
|
||||
if constexpr (_SwapDst)
|
||||
{
|
||||
work_kernel += " tmp.yz = bswap_u32(tmp.yz);\n";
|
||||
|
||||
@@ -84,7 +84,16 @@ void GLGSRender::update_draw_state()
|
||||
{
|
||||
// Z-buffer is active.
|
||||
gl_state.depth_mask(rsx::method_registers.depth_write_enabled());
|
||||
gl_state.enable(rsx::method_registers.depth_clamp_enabled() || !rsx::method_registers.depth_clip_enabled(), GL_DEPTH_CLAMP);
|
||||
const bool emulate_depth_range = requires_depth_range_emulation();
|
||||
if (!emulate_depth_range) [[ likely ]]
|
||||
{
|
||||
gl_state.enable(rsx::method_registers.depth_clamp_enabled() || !rsx::method_registers.depth_clip_enabled(), GL_DEPTH_CLAMP);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Depth clip and clamp are emulated in the fragment shader
|
||||
gl_state.enable(GL_DEPTH_CLAMP);
|
||||
}
|
||||
|
||||
if (gl_state.enable(rsx::method_registers.depth_test_enabled(), GL_DEPTH_TEST))
|
||||
{
|
||||
@@ -95,9 +104,16 @@ void GLGSRender::update_draw_state()
|
||||
(gl_state.enable(REGS(m_ctx)->depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
|
||||
{
|
||||
const auto depth_format = REGS(m_ctx)->surface_depth_fmt();
|
||||
gl_state.depth_bounds(
|
||||
rsx::clamp_depth_bounds_value(depth_format, REGS(m_ctx)->depth_bounds_min()),
|
||||
rsx::clamp_depth_bounds_value(depth_format, REGS(m_ctx)->depth_bounds_max()));
|
||||
f32 bounds_min = rsx::clamp_depth_bounds_value(depth_format, REGS(m_ctx)->depth_bounds_min());
|
||||
f32 bounds_max = rsx::clamp_depth_bounds_value(depth_format, REGS(m_ctx)->depth_bounds_max());
|
||||
|
||||
if (emulate_depth_range) [[ unlikely ]]
|
||||
{
|
||||
bounds_min = rsx::encode_emulated_depth(bounds_min);
|
||||
bounds_max = rsx::encode_emulated_depth(bounds_max);
|
||||
}
|
||||
|
||||
gl_state.depth_bounds(bounds_min, bounds_max);
|
||||
}
|
||||
|
||||
if (gl::get_driver_caps().NV_depth_buffer_float_supported)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "Emu/system_config.h"
|
||||
#include "GLCommonDecompiler.h"
|
||||
#include "GLHelpers.h"
|
||||
#include "../Program/GLSLCommon.h"
|
||||
|
||||
std::string GLFragmentDecompilerThread::getFloatTypeName(usz elementCount)
|
||||
@@ -86,6 +87,11 @@ void GLFragmentDecompilerThread::insertInputs(std::stringstream & OS)
|
||||
},
|
||||
gl::get_varying_register_location
|
||||
);
|
||||
|
||||
if (m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE)
|
||||
{
|
||||
OS << "layout(location=" << gl::get_varying_register_location("depth_range") << ") in flat vec2 depth_range;\n";
|
||||
}
|
||||
}
|
||||
|
||||
void GLFragmentDecompilerThread::insertOutputs(std::stringstream & OS)
|
||||
@@ -227,7 +233,7 @@ void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
|
||||
m_shader_props.require_srgb_to_linear = properties.has_upg;
|
||||
m_shader_props.require_linear_to_srgb = properties.has_pkg;
|
||||
m_shader_props.require_fog_read = properties.in_register_mask & in_fogc;
|
||||
m_shader_props.emulate_shadow_compare = device_props.emulate_depth_compare;
|
||||
m_shader_props.emulate_shadow_compare = device_props.emulate_depth_compare || device_props.emulated_depth_storage;
|
||||
|
||||
m_shader_props.low_precision_tests = ::gl::get_driver_caps().vendor_NVIDIA && !(m_prog.ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION);
|
||||
m_shader_props.disable_early_discard = !::gl::get_driver_caps().vendor_NVIDIA;
|
||||
@@ -249,6 +255,9 @@ void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
|
||||
m_shader_props.require_color_format_convert = !!(m_prog.ctrl & RSX_SHADER_CONTROL_TEXTURE_FORMAT_CONVERT);
|
||||
m_shader_props.emulate_depth_compare = !!(m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_COMPARE);
|
||||
m_shader_props.ROP_output_multisampled = !!(m_prog.ctrl & RSX_SHADER_CONTROL_ROP_MULTISAMPLED);
|
||||
m_shader_props.ROP_emulate_depth_range = !!(m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE);
|
||||
m_shader_props.ROP_depth_export = !!(m_prog.ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) && m_shader_props.ROP_emulate_depth_range;
|
||||
m_shader_props.emulated_depth_storage = device_props.emulated_depth_storage;
|
||||
|
||||
glsl::insert_glsl_legacy_function(OS, m_shader_props);
|
||||
}
|
||||
@@ -372,6 +381,8 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
|
||||
}
|
||||
}
|
||||
|
||||
glsl::insert_fragment_epilogue(OS, m_shader_props);
|
||||
|
||||
OS << "}\n";
|
||||
}
|
||||
|
||||
@@ -400,6 +411,7 @@ void GLFragmentProgram::Decompile(const RSXFragmentProgram& prog)
|
||||
decompiler.device_props.has_low_precision_rounding = driver_caps.vendor_NVIDIA;
|
||||
}
|
||||
|
||||
decompiler.device_props.emulated_depth_storage = gl::emulate_extended_depth_range();
|
||||
decompiler.Task();
|
||||
|
||||
constant_offsets = std::move(decompiler.properties.constant_offsets);
|
||||
|
||||
@@ -52,6 +52,7 @@ GLGSRender::GLGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
||||
backend_config.supports_hw_instanced_rendering = true;
|
||||
// OpenGL 3.2+ defaults to GL_LAST_VERTEX_CONVENTION.
|
||||
backend_config.supports_last_provoking_vertex = true;
|
||||
backend_config.supports_extended_depth_range = gl::get_driver_caps().NV_depth_buffer_float_supported;
|
||||
|
||||
if (g_cfg.video.antialiasing_level != msaa_level::none)
|
||||
{
|
||||
@@ -673,7 +674,12 @@ void GLGSRender::clear_surface(u32 arg)
|
||||
{
|
||||
const u32 clear_depth_bits = REGS(m_ctx)->z_clear_value(is_depth_stencil_format(surface_depth_format));
|
||||
clear_cmd.clear_depth.value = rsx::get_depth_clear_value(surface_depth_format, clear_depth_bits);
|
||||
clear_cmd.aspect_mask |= gl::image_aspect::depth;
|
||||
clear_cmd.aspect_mask |= gl::image_aspect::depth;
|
||||
|
||||
if (gl::emulate_extended_depth_range() && rsx::is_float_depth_format(surface_depth_format)) [[ unlikely ]]
|
||||
{
|
||||
clear_cmd.clear_depth.value = rsx::encode_emulated_depth(clear_cmd.clear_depth.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_depth_stencil_format(surface_depth_format))
|
||||
@@ -861,12 +867,16 @@ bool GLGSRender::load_program()
|
||||
}
|
||||
|
||||
void* pipeline_properties = nullptr;
|
||||
// The shader interpreter does not emulate the depth range; compile those programs synchronously instead
|
||||
const bool allow_async = shadermode != shader_mode::recompiler &&
|
||||
!(current_fragment_program.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE);
|
||||
|
||||
std::tie(m_program, m_vertex_prog, m_fragment_prog) = m_prog_buffer.get_graphics_pipeline(
|
||||
&m_program_cache_hint,
|
||||
current_vertex_program,
|
||||
current_fragment_program,
|
||||
pipeline_properties,
|
||||
shadermode != shader_mode::recompiler, true);
|
||||
allow_async, true);
|
||||
|
||||
if (m_prog_buffer.check_cache_missed())
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "GLHelpers.h"
|
||||
#include "GLCompute.h"
|
||||
#include "util/logs.hpp"
|
||||
@@ -186,4 +187,9 @@ namespace gl
|
||||
fmt::throw_exception("unknown primitive type");
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_extended_depth_range()
|
||||
{
|
||||
return !get_driver_caps().NV_depth_buffer_float_supported && g_cfg.video.emulate_extended_depth_range;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,5 +35,6 @@ namespace gl
|
||||
{
|
||||
void enable_debugging();
|
||||
bool is_primitive_native(rsx::primitive_type in);
|
||||
bool emulate_extended_depth_range();
|
||||
GLenum draw_mode(rsx::primitive_type in);
|
||||
}
|
||||
|
||||
@@ -560,7 +560,8 @@ namespace gl
|
||||
{ "%loc", std::to_string(GL_COMPUTE_BUFFER_SLOT(0)) },
|
||||
{ "%push_block", fmt::format("binding=%d, std140", GL_COMPUTE_BUFFER_SLOT(1)) },
|
||||
{ "%stencil_export_supported", stencil_export_supported ? "1" : "0" },
|
||||
{ "%legacy_format_support", legacy_format_support ? "1" : "0" }
|
||||
{ "%legacy_format_support", legacy_format_support ? "1" : "0" },
|
||||
{ "%emulated_depth_storage", gl::emulate_extended_depth_range() ? "1" : "0" }
|
||||
};
|
||||
|
||||
fs_src = fmt::replace_all(fs_src, repl_list);
|
||||
@@ -594,6 +595,11 @@ namespace gl
|
||||
program_handle.uniforms["src_pitch"] = row_length;
|
||||
program_handle.uniforms["swap_bytes"] = layout.swap_bytes;
|
||||
program_handle.uniforms["format"] = static_cast<GLenum>(dst->image()->get_internal_format());
|
||||
|
||||
if (gl::emulate_extended_depth_range())
|
||||
{
|
||||
program_handle.uniforms["depth_float"] = (dst->image()->format_class() & RSX_FORMAT_CLASS_DEPTH_FLOAT_MASK) ? 1u : 0u;
|
||||
}
|
||||
src->bind_range(gl::buffer::target::ssbo, GL_COMPUTE_BUFFER_SLOT(0), src_offset, row_length * bpp * dst_region.height);
|
||||
|
||||
cmd->stencil_mask(0xFF);
|
||||
|
||||
@@ -164,6 +164,11 @@ void GLVertexDecompilerThread::insertOutputs(std::stringstream& OS, const std::v
|
||||
<< (flat_color ? "flat " : "") << "vec4 " << i.name << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE)
|
||||
{
|
||||
OS << "layout(location=" << gl::get_varying_register_location("depth_range") << ") out flat vec2 depth_range;\n";
|
||||
}
|
||||
}
|
||||
|
||||
void GLVertexDecompilerThread::insertMainStart(std::stringstream& OS)
|
||||
@@ -179,6 +184,7 @@ void GLVertexDecompilerThread::insertMainStart(std::stringstream& OS)
|
||||
properties2.require_explicit_invariance = dev_caps.vendor_MESA || (dev_caps.vendor_NVIDIA && g_cfg.video.shader_precision != gpu_preset_level::low);
|
||||
properties2.require_instanced_render = !!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS);
|
||||
properties2.require_clip_plane_functions = true;
|
||||
properties2.emulate_depth_range = !!(m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE);
|
||||
|
||||
insert_glsl_legacy_function(OS, properties2);
|
||||
glsl::insert_vertex_input_fetch(OS, glsl::glsl_rules_opengl4, dev_caps.vendor_INTEL == false);
|
||||
@@ -286,7 +292,17 @@ void GLVertexDecompilerThread::insertMainEnd(std::stringstream& OS)
|
||||
}
|
||||
|
||||
OS << " gl_Position = gl_Position * scale_offset_mat;\n";
|
||||
OS << " gl_Position = apply_zclip_xform(gl_Position, z_near, z_far);\n";
|
||||
|
||||
if (!(m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE)) [[ likely ]]
|
||||
{
|
||||
OS << " gl_Position = apply_zclip_xform(gl_Position, z_near, z_far);\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
OS <<
|
||||
" depth_range = vec2(min(z_near, z_far), max(z_near, z_far));\n"
|
||||
" gl_Position = apply_depth_range_xform(gl_Position, depth_range);\n";
|
||||
}
|
||||
|
||||
// Since our clip_space is symmetrical [-1, 1] we map it to linear space using the eqn:
|
||||
// ln = (clip * 2) - 1 to fully utilize the 0-1 range of the depth buffer
|
||||
|
||||
@@ -272,6 +272,22 @@ namespace rsx
|
||||
RSX(ctx)->m_graphics_state.clear(rtt_config_contested);
|
||||
}
|
||||
|
||||
void set_zmin_max_control(context* ctx, u32 /*reg*/, u32 arg)
|
||||
{
|
||||
if (arg == REGS(ctx)->latch)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::pipeline_config_dirty;
|
||||
|
||||
// Depth clip and clamp are read by the fragment epilogue when the depth range is emulated
|
||||
if (!RSX(ctx)->get_backend_config().supports_extended_depth_range && g_cfg.video.emulate_extended_depth_range)
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_state_dirty;
|
||||
}
|
||||
}
|
||||
|
||||
void set_surface_format(context* ctx, u32 reg, u32 arg)
|
||||
{
|
||||
// The high bits of this register are just log2(dimension), ignore them
|
||||
|
||||
@@ -69,6 +69,8 @@ namespace rsx
|
||||
|
||||
void set_surface_dirty_bit(context* ctx, u32 reg, u32 arg);
|
||||
|
||||
void set_zmin_max_control(context* ctx, u32 reg, u32 arg);
|
||||
|
||||
void set_surface_format(context* ctx, u32 reg, u32 arg);
|
||||
|
||||
void set_surface_options_dirty_bit(context* ctx, u32 reg, u32 arg);
|
||||
|
||||
@@ -195,6 +195,7 @@ public:
|
||||
bool has_native_half_support = false;
|
||||
bool emulate_depth_compare = false;
|
||||
bool has_low_precision_rounding = false;
|
||||
bool emulated_depth_storage = false;
|
||||
}
|
||||
device_props;
|
||||
|
||||
|
||||
@@ -170,6 +170,13 @@ namespace glsl
|
||||
;
|
||||
}
|
||||
|
||||
void insert_fragment_epilogue(std::ostream& OS, const shader_properties& /*props*/)
|
||||
{
|
||||
OS <<
|
||||
#include "GLSLSnippets/RSXProg/RSXFragmentEpilogue.glsl"
|
||||
;
|
||||
}
|
||||
|
||||
void insert_glsl_legacy_function(std::ostream& OS, const shader_properties& props)
|
||||
{
|
||||
std::vector<std::string_view> enabled_options;
|
||||
@@ -208,6 +215,7 @@ namespace glsl
|
||||
{ "MSAA_SAMPLE_CTRL_LENGTH ", rsx::ROP_control_bits::MSAA_SAMPLE_CTRL_NUM_BITS },
|
||||
{ "FRAG_DEPTH_24_BIT ", rsx::ROP_control_bits::FRAG_DEPTH_24_BIT },
|
||||
{ "FRAG_DEPTH_FLOAT_BIT ", rsx::ROP_control_bits::FRAG_DEPTH_FLOAT_BIT },
|
||||
{ "DEPTH_CLAMP_ENABLE_BIT ", rsx::ROP_control_bits::DEPTH_CLAMP_ENABLE_BIT },
|
||||
{ "MRT_CHANNEL_REMAP_OFFSET ", rsx::ROP_control_bits::MRT_CHANNEL_REMAP_OFFSET },
|
||||
{ "MRT_CHANNEL_REMAP_LENGTH ", rsx::ROP_control_bits::MRT_CHANNEL_REMAP_NUM_BITS },
|
||||
{ "MRT_BLEND_TARGETS_OFFSET ", rsx::ROP_control_bits::MRT_BLEND_TARGETS_OFFSET },
|
||||
@@ -274,6 +282,16 @@ namespace glsl
|
||||
{
|
||||
enabled_options.push_back("_ENABLE_ROP_OUTPUT_MULTISAMPLED");
|
||||
}
|
||||
|
||||
if (props.ROP_emulate_depth_range)
|
||||
{
|
||||
enabled_options.push_back("_EMULATE_DEPTH_RANGE");
|
||||
}
|
||||
|
||||
if (props.ROP_depth_export)
|
||||
{
|
||||
enabled_options.push_back("_ENABLE_DEPTH_EXPORT");
|
||||
}
|
||||
}
|
||||
|
||||
// Import common header
|
||||
@@ -308,6 +326,11 @@ namespace glsl
|
||||
enabled_options.push_back("_ENABLE_INSTANCED_CONSTANTS");
|
||||
}
|
||||
|
||||
if (props.emulate_depth_range)
|
||||
{
|
||||
enabled_options.push_back("_EMULATE_DEPTH_RANGE");
|
||||
}
|
||||
|
||||
// Import vertex header
|
||||
program_common::define_glsl_switches(OS, enabled_options);
|
||||
|
||||
@@ -373,6 +396,12 @@ namespace glsl
|
||||
enabled_options.push_back("_ENABLE_FOG_READ");
|
||||
}
|
||||
|
||||
// Programs with the emulation bit always need the encoding, even if they were cached while the option was off
|
||||
if (props.emulated_depth_storage || props.ROP_emulate_depth_range)
|
||||
{
|
||||
enabled_options.push_back("_EMULATED_DEPTH_STORAGE");
|
||||
}
|
||||
|
||||
// Import fragment header
|
||||
program_common::define_glsl_switches(OS, enabled_options);
|
||||
enabled_options.clear();
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace rsx
|
||||
MSAA_WRITE_ENABLE_BIT = 9,
|
||||
FRAG_DEPTH_24_BIT = 10,
|
||||
FRAG_DEPTH_FLOAT_BIT = 11,
|
||||
DEPTH_CLAMP_ENABLE_BIT = 24,
|
||||
|
||||
// Data
|
||||
ALPHA_FUNC_OFFSET = 12,
|
||||
@@ -51,6 +52,7 @@ namespace rsx
|
||||
|
||||
void enable_framebuffer_INT() { value |= (1u << ROP_control_bits::INT_FRAMEBUFFER_BIT); }
|
||||
void enable_MSAA_writes() { value |= (1u << ROP_control_bits::MSAA_WRITE_ENABLE_BIT); }
|
||||
void enable_depth_clamp() { value |= (1u << ROP_control_bits::DEPTH_CLAMP_ENABLE_BIT); }
|
||||
|
||||
void set_alpha_test_func(uint func) { value |= (func << ROP_control_bits::ALPHA_FUNC_OFFSET); }
|
||||
void set_msaa_control(uint ctrl) { value |= (ctrl << ROP_control_bits::MSAA_SAMPLE_CTRL_OFFSET); }
|
||||
@@ -82,6 +84,7 @@ namespace glsl
|
||||
void insert_vertex_input_fetch(std::stringstream& OS, glsl_rules rules, bool glsl4_compliant=true);
|
||||
void insert_rop_init(std::ostream& OS, u32 mrt_buffers_count);
|
||||
void insert_rop(std::ostream& OS, const shader_properties& props);
|
||||
void insert_fragment_epilogue(std::ostream& OS, const shader_properties& props);
|
||||
void insert_glsl_legacy_function(std::ostream& OS, const shader_properties& props);
|
||||
std::string getFunctionImpl(FUNCTION f);
|
||||
void insert_subheader_block(std::ostream& OS);
|
||||
|
||||
@@ -4,6 +4,7 @@ R"(
|
||||
|
||||
#define ENABLE_DEPTH_STENCIL_LOAD %stencil_export_supported
|
||||
#define LEGACY_FORMAT_SUPPORT %legacy_format_support
|
||||
#define EMULATED_DEPTH_STORAGE %emulated_depth_storage
|
||||
|
||||
#define FMT_GL_DEPTH_COMPONENT16 0x81A5
|
||||
#define FMT_GL_DEPTH_COMPONENT32F 0x8CAC
|
||||
@@ -45,11 +46,13 @@ layout(%push_block) uniform UnpackConfiguration
|
||||
uint swap_bytes;
|
||||
uint src_pitch;
|
||||
uint format;
|
||||
uint depth_float;
|
||||
};
|
||||
#else
|
||||
uniform uint swap_bytes;
|
||||
uniform uint src_pitch;
|
||||
uniform uint format;
|
||||
uniform uint depth_float;
|
||||
#endif
|
||||
|
||||
uint getTexelOffset()
|
||||
@@ -130,6 +133,11 @@ float readE4M12(const in uint address)
|
||||
}
|
||||
|
||||
#define readFixed16(address) readUint16(uint(address)) / 65535.f
|
||||
|
||||
#if EMULATED_DEPTH_STORAGE
|
||||
// Float depth surfaces hold half the IEEE bit pattern, see encode_emulated_depth
|
||||
#define encodeDepth(value) uintBitsToFloat((floatBitsToUint(max(value, 0.)) & 0x7fffffffu) >> 1)
|
||||
#endif
|
||||
#define readFixed16x2(address) vec2(readFixed16(address * 2 + 0), readFixed16(address * 2 + 1))
|
||||
#define readFixed16x4(address) vec4(readFixed16(address * 4 + 0), readFixed16(address * 4 + 1), readFixed16(address * 4 + 2), readFixed16(address * 4 + 3))
|
||||
|
||||
@@ -153,7 +161,11 @@ void main()
|
||||
gl_FragDepth = readFixed16(texel_address);
|
||||
break;
|
||||
case FMT_GL_DEPTH_COMPONENT32F:
|
||||
#if EMULATED_DEPTH_STORAGE
|
||||
gl_FragDepth = encodeDepth(readE4M12(texel_address));
|
||||
#else
|
||||
gl_FragDepth = readE4M12(texel_address);
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if ENABLE_DEPTH_STENCIL_LOAD
|
||||
@@ -162,6 +174,13 @@ void main()
|
||||
case FMT_GL_DEPTH24_STENCIL8:
|
||||
case FMT_GL_DEPTH32F_STENCIL8:
|
||||
utmp2 = readUint24_8(texel_address);
|
||||
#if EMULATED_DEPTH_STORAGE
|
||||
if (depth_float != 0)
|
||||
{
|
||||
gl_FragDepth = encodeDepth(uintBitsToFloat(utmp2.x << 7));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
gl_FragDepth = float(utmp2.x) / 0xffffff;
|
||||
gl_FragStencilRefARB = int(utmp2.y);
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
R"(
|
||||
#ifdef _EMULATE_DEPTH_RANGE
|
||||
// The vertex stage mapped the clip range onto the [0, 1] viewport and hardware clipping is disabled.
|
||||
// Clip or clamp against the real range here, then store the window Z encoded.
|
||||
if (!_test_bit(rop_control, DEPTH_CLAMP_ENABLE_BIT) && (gl_FragCoord.z < 0. || gl_FragCoord.z > 1.))
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
#ifdef _ENABLE_DEPTH_EXPORT
|
||||
// Hardware tests show exported depth is not clamped to 1 on float depth surfaces
|
||||
float emulated_depth = encode_emulated_depth(r1.z);
|
||||
#else
|
||||
float emulated_depth = encode_emulated_depth(depth_range.x + _saturate(gl_FragCoord.z) * (depth_range.y - depth_range.x));
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_DEPTH_COMPARE
|
||||
// dstDepth is the stored value, already encoded. One step of the 24-bit float format is 64 steps of the encoding.
|
||||
if (abs(int(floatBitsToUint(emulated_depth)) - int(floatBitsToUint(dstDepth))) < 64)
|
||||
{
|
||||
emulated_depth = dstDepth;
|
||||
}
|
||||
#endif
|
||||
|
||||
gl_FragDepth = emulated_depth;
|
||||
#endif
|
||||
)"
|
||||
@@ -1,5 +1,19 @@
|
||||
R"(
|
||||
|
||||
#ifdef _EMULATED_DEPTH_STORAGE
|
||||
// Halving the IEEE bit pattern of a non-negative float is monotonic and maps every finite value below 1.
|
||||
// The host depth test keeps working on the encoded values.
|
||||
float encode_emulated_depth(const in float depth)
|
||||
{
|
||||
return uintBitsToFloat((floatBitsToUint(max(depth, 0.)) & 0x7fffffffu) >> 1);
|
||||
}
|
||||
|
||||
float decode_emulated_depth(const in float stored)
|
||||
{
|
||||
return uintBitsToFloat(floatBitsToUint(stored) << 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _32_BIT_OUTPUT
|
||||
// Everything is fp32 on ouput channels
|
||||
#define _mrt_color_t(expr) expr
|
||||
|
||||
@@ -17,7 +17,11 @@ vec4 decode_depth24(const in float depth_value, const in bool depth_float)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _EMULATED_DEPTH_STORAGE
|
||||
value = _get_bits(floatBitsToUint(decode_emulated_depth(depth_value)), 7, 24);
|
||||
#else
|
||||
value = _get_bits(floatBitsToUint(depth_value), 7, 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint b = _get_bits(value, 0, 8);
|
||||
|
||||
@@ -55,6 +55,25 @@ R"(
|
||||
#define TEX_NAME(index) tex##index
|
||||
#define TEX_NAME_STENCIL(index) tex##index##_stencil
|
||||
|
||||
#ifdef _EMULATED_DEPTH_STORAGE
|
||||
// Float depth surfaces hold the emulated encoding; recover the depth value when they are sampled directly
|
||||
vec4 _decode_depth_texel(const in vec4 texel, const in uint flags, const in uint remap)
|
||||
{
|
||||
if (!_test_bit(flags, DEPTH_FLOAT))
|
||||
{
|
||||
return texel;
|
||||
}
|
||||
|
||||
// Only channels sourced from the texture (remap select == 2) hold encoded depth
|
||||
const uvec4 remap_select = (uvec4(remap) >> uvec4(10, 12, 14, 8)) & 3u;
|
||||
const vec4 decoded = uintBitsToFloat(floatBitsToUint(texel) << 1u);
|
||||
return _select(texel, decoded, equal(remap_select, uvec4(2u)));
|
||||
}
|
||||
#define _DEPTH_DECODE(index, texel) _decode_depth_texel(texel, TEX_PARAM(index).flags, TEX_PARAM(index).remap)
|
||||
#else
|
||||
#define _DEPTH_DECODE(index, texel) texel
|
||||
#endif
|
||||
|
||||
#define COORD_SCALE1(index, coord1) _texcoord_xform(coord1, TEX_PARAM(index))
|
||||
#define COORD_SCALE2(index, coord2) _texcoord_xform(coord2, TEX_PARAM(index))
|
||||
#define COORD_SCALE3(index, coord3) _texcoord_xform(coord3, TEX_PARAM(index))
|
||||
@@ -63,19 +82,19 @@ R"(
|
||||
#define COORD_PROJ3(index, coord4) COORD_SCALE3(index, coord4.xyz / coord4.w)
|
||||
|
||||
#ifdef _ENABLE_TEX1D
|
||||
#define TEX1D(index, coord1) _process_texel(texture(TEX_NAME(index), COORD_SCALE1(index, coord1)), TEX_FLAGS(index))
|
||||
#define TEX1D_BIAS(index, coord1, bias) _process_texel(texture(TEX_NAME(index), COORD_SCALE1(index, coord1), bias), TEX_FLAGS(index))
|
||||
#define TEX1D_LOD(index, coord1, lod) _process_texel(textureLod(TEX_NAME(index), COORD_SCALE1(index, coord1), lod), TEX_FLAGS(index))
|
||||
#define TEX1D_GRAD(index, coord1, dpdx, dpdy) _process_texel(textureGrad(TEX_NAME(index), COORD_SCALE1(index, coord1), dpdx, dpdy), TEX_FLAGS(index))
|
||||
#define TEX1D_PROJ(index, coord4) _process_texel(texture(TEX_NAME(index), COORD_PROJ1(index, coord4.xw)), TEX_FLAGS(index))
|
||||
#define TEX1D(index, coord1) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_SCALE1(index, coord1))), TEX_FLAGS(index))
|
||||
#define TEX1D_BIAS(index, coord1, bias) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_SCALE1(index, coord1), bias)), TEX_FLAGS(index))
|
||||
#define TEX1D_LOD(index, coord1, lod) _process_texel(_DEPTH_DECODE(index, textureLod(TEX_NAME(index), COORD_SCALE1(index, coord1), lod)), TEX_FLAGS(index))
|
||||
#define TEX1D_GRAD(index, coord1, dpdx, dpdy) _process_texel(_DEPTH_DECODE(index, textureGrad(TEX_NAME(index), COORD_SCALE1(index, coord1), dpdx, dpdy)), TEX_FLAGS(index))
|
||||
#define TEX1D_PROJ(index, coord4) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_PROJ1(index, coord4.xw))), TEX_FLAGS(index))
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_TEX2D
|
||||
#define TEX2D(index, coord2) _process_texel(texture(TEX_NAME(index), COORD_SCALE2(index, coord2)), TEX_FLAGS(index))
|
||||
#define TEX2D_BIAS(index, coord2, bias) _process_texel(texture(TEX_NAME(index), COORD_SCALE2(index, coord2), bias), TEX_FLAGS(index))
|
||||
#define TEX2D_LOD(index, coord2, lod) _process_texel(textureLod(TEX_NAME(index), COORD_SCALE2(index, coord2), lod), TEX_FLAGS(index))
|
||||
#define TEX2D_GRAD(index, coord2, dpdx, dpdy) _process_texel(textureGrad(TEX_NAME(index), COORD_SCALE2(index, coord2), dpdx, dpdy), TEX_FLAGS(index))
|
||||
#define TEX2D_PROJ(index, coord4) _process_texel(texture(TEX_NAME(index), COORD_PROJ2(index, coord4.xyw)), TEX_FLAGS(index))
|
||||
#define TEX2D(index, coord2) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_SCALE2(index, coord2))), TEX_FLAGS(index))
|
||||
#define TEX2D_BIAS(index, coord2, bias) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_SCALE2(index, coord2), bias)), TEX_FLAGS(index))
|
||||
#define TEX2D_LOD(index, coord2, lod) _process_texel(_DEPTH_DECODE(index, textureLod(TEX_NAME(index), COORD_SCALE2(index, coord2), lod)), TEX_FLAGS(index))
|
||||
#define TEX2D_GRAD(index, coord2, dpdx, dpdy) _process_texel(_DEPTH_DECODE(index, textureGrad(TEX_NAME(index), COORD_SCALE2(index, coord2), dpdx, dpdy)), TEX_FLAGS(index))
|
||||
#define TEX2D_PROJ(index, coord4) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_PROJ2(index, coord4.xyw))), TEX_FLAGS(index))
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_SHADOW
|
||||
@@ -96,11 +115,11 @@ R"(
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_TEX3D
|
||||
#define TEX3D(index, coord3) _process_texel(texture(TEX_NAME(index), COORD_SCALE3(index, coord3)), TEX_FLAGS(index))
|
||||
#define TEX3D_BIAS(index, coord3, bias) _process_texel(texture(TEX_NAME(index), COORD_SCALE3(index, coord3), bias), TEX_FLAGS(index))
|
||||
#define TEX3D_LOD(index, coord3, lod) _process_texel(textureLod(TEX_NAME(index), COORD_SCALE3(index, coord3), lod), TEX_FLAGS(index))
|
||||
#define TEX3D_GRAD(index, coord3, dpdx, dpdy) _process_texel(textureGrad(TEX_NAME(index), COORD_SCALE3(index, coord3), dpdx, dpdy), TEX_FLAGS(index))
|
||||
#define TEX3D_PROJ(index, coord4) _process_texel(texture(TEX_NAME(index), COORD_PROJ3(index, coord4).xyz), TEX_FLAGS(index))
|
||||
#define TEX3D(index, coord3) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_SCALE3(index, coord3))), TEX_FLAGS(index))
|
||||
#define TEX3D_BIAS(index, coord3, bias) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_SCALE3(index, coord3), bias)), TEX_FLAGS(index))
|
||||
#define TEX3D_LOD(index, coord3, lod) _process_texel(_DEPTH_DECODE(index, textureLod(TEX_NAME(index), COORD_SCALE3(index, coord3), lod)), TEX_FLAGS(index))
|
||||
#define TEX3D_GRAD(index, coord3, dpdx, dpdy) _process_texel(_DEPTH_DECODE(index, textureGrad(TEX_NAME(index), COORD_SCALE3(index, coord3), dpdx, dpdy)), TEX_FLAGS(index))
|
||||
#define TEX3D_PROJ(index, coord4) _process_texel(_DEPTH_DECODE(index, texture(TEX_NAME(index), COORD_PROJ3(index, coord4).xyz)), TEX_FLAGS(index))
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_TEX1D
|
||||
@@ -160,7 +179,12 @@ vec3 _texcoord_xform_shadow(const in vec3 coord3, const in sampler_info params)
|
||||
if (_test_bit(params.flags, DEPTH_FLOAT))
|
||||
{
|
||||
// Depth-float buffer, extended range supported
|
||||
#ifdef _EMULATED_DEPTH_STORAGE
|
||||
// The stored values are encoded; the encoding is monotonic so the hardware compare still holds
|
||||
result.z = encode_emulated_depth(coord3.z);
|
||||
#else
|
||||
result.z = coord3.z;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -180,7 +204,11 @@ vec4 _texcoord_xform_shadow(const in vec4 coord4, const in sampler_info params)
|
||||
if (_test_bit(params.flags, DEPTH_FLOAT))
|
||||
{
|
||||
// Depth-float buffer, extended range supported
|
||||
#ifdef _EMULATED_DEPTH_STORAGE
|
||||
result.w = encode_emulated_depth(coord4.w);
|
||||
#else
|
||||
result.w = coord4.w;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -55,6 +55,20 @@ vec4 apply_zclip_xform(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _EMULATE_DEPTH_RANGE
|
||||
// The host viewport only holds [0, 1] while float depth targets store window Z far above 1.
|
||||
// Map the clip range linearly onto the viewport instead; the fragment stage recovers the window Z.
|
||||
vec4 apply_depth_range_xform(const in vec4 pos, const in vec2 range)
|
||||
{
|
||||
if (range.y <= range.x)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
return vec4(pos.xy, (pos.z - range.x * pos.w) / (range.y - range.x), pos.w);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_ENABLE_INSTANCED_CONSTANTS)
|
||||
// Workaround for GL vs VK builtin variable naming
|
||||
#ifdef VULKAN
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace glsl
|
||||
bool require_clip_plane_functions : 1;
|
||||
bool emulate_zclip_transform : 1;
|
||||
bool emulate_depth_clip_only : 1;
|
||||
bool emulate_depth_range : 1;
|
||||
|
||||
// Only relevant for fragment programs
|
||||
bool fp32_outputs : 1;
|
||||
@@ -41,6 +42,7 @@ namespace glsl
|
||||
bool low_precision_tests : 1;
|
||||
bool disable_early_discard : 1;
|
||||
bool supports_native_fp16 : 1;
|
||||
bool emulated_depth_storage : 1; // Float depth surfaces hold encode_emulated_depth(z)
|
||||
|
||||
// ROP control flags
|
||||
bool ROP_output_multisampled : 1;
|
||||
@@ -52,6 +54,8 @@ namespace glsl
|
||||
bool ROP_discard : 1;
|
||||
bool ROP_channel_remap : 1;
|
||||
bool ROP_programmable_blend : 1;
|
||||
bool ROP_emulate_depth_range : 1;
|
||||
bool ROP_depth_export : 1;
|
||||
|
||||
// Texturing spec
|
||||
bool require_texture_ops : 1; // Global switch to enable/disable all texture code
|
||||
|
||||
@@ -127,7 +127,8 @@ namespace rsx
|
||||
constexpr u32 fs_export_config_mask =
|
||||
RSX_SHADER_CONTROL_EMULATE_DEPTH_COMPARE |
|
||||
RSX_SHADER_CONTROL_ROP_MULTISAMPLED |
|
||||
RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING;
|
||||
RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING |
|
||||
RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE;
|
||||
|
||||
rsx_iomap_table::rsx_iomap_table() noexcept
|
||||
: ea(fill_array(-1))
|
||||
@@ -2137,6 +2138,11 @@ namespace rsx
|
||||
expected_ctrl |= RSX_SHADER_CONTROL_ROP_MULTISAMPLED;
|
||||
}
|
||||
|
||||
if (requires_depth_range_emulation()) [[ unlikely ]]
|
||||
{
|
||||
expected_ctrl |= RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE;
|
||||
}
|
||||
|
||||
// Depth compare
|
||||
if (!g_cfg.video.emulate_depth_compare) [[ likely ]]
|
||||
{
|
||||
@@ -2166,6 +2172,16 @@ namespace rsx
|
||||
return expected_ctrl;
|
||||
}
|
||||
|
||||
bool thread::requires_depth_range_emulation() const
|
||||
{
|
||||
if (backend_config.supports_extended_depth_range || !g_cfg.video.emulate_extended_depth_range) [[ likely ]]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_framebuffer_layout.zeta_address && rsx::is_float_depth_format(REGS(m_ctx)->surface_depth_fmt());
|
||||
}
|
||||
|
||||
void thread::prefetch_fragment_program()
|
||||
{
|
||||
if (!m_graphics_state.test(rsx::pipeline_state::fragment_program_ucode_dirty))
|
||||
@@ -2291,6 +2307,13 @@ namespace rsx
|
||||
m_program_cache_hint.invalidate_vertex_program(current_vertex_program);
|
||||
}
|
||||
|
||||
if (const bool emulate_depth_range = requires_depth_range_emulation();
|
||||
emulate_depth_range != !!(current_vertex_program.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE))
|
||||
{
|
||||
current_vertex_program.ctrl ^= RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE;
|
||||
m_program_cache_hint.invalidate_vertex_program(current_vertex_program);
|
||||
}
|
||||
|
||||
if (!m_graphics_state.test(rsx::pipeline_state::vertex_program_dirty))
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace rsx
|
||||
bool supports_host_gpu_labels; // Advanced host synchronization
|
||||
bool supports_normalized_barycentrics; // Basically all GPUs except NVIDIA have properly normalized barycentrics
|
||||
bool supports_last_provoking_vertex; // Flat shading using RSX's last-vertex convention
|
||||
bool supports_extended_depth_range; // Depth values above 1 can be stored and tested. Float depth targets are emulated otherwise.
|
||||
bool supports_programmable_blending; // Can handle programmable blending requests
|
||||
};
|
||||
|
||||
@@ -265,6 +266,7 @@ namespace rsx
|
||||
protected:
|
||||
void get_framebuffer_layout(rsx::framebuffer_creation_context context, framebuffer_layout &layout);
|
||||
bool get_scissor(areau& region, bool clip_viewport);
|
||||
bool requires_depth_range_emulation() const;
|
||||
|
||||
// Notify framebuffer layout has been committed.
|
||||
// FIXME: This should not be here
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace vk
|
||||
{ "fog_c", 14 },
|
||||
{ "fogc", 14 },
|
||||
{ "usr", 15 }, // custom injected stuff
|
||||
{ "depth_range", 17 }, // clip range for depth range emulation; 16 is used by the shader interpreter
|
||||
} };
|
||||
|
||||
int get_varying_register_location(std::string_view varying_register_name)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "VKProgramPipeline.h"
|
||||
#include "vkutils/descriptors.h"
|
||||
#include "vkutils/buffer_object.h"
|
||||
#include "VKHelpers.h"
|
||||
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/RSX/Utils/algorithm.hpp"
|
||||
@@ -182,8 +183,10 @@ namespace vk
|
||||
}
|
||||
else
|
||||
{
|
||||
work_kernel +=
|
||||
" depth = f32_to_d24f(data[index + z_offset]);\n";
|
||||
// With depth range emulation, float depth surfaces hold the emulated encoding (half the bit pattern)
|
||||
work_kernel += !vk::emulate_extended_depth_range()
|
||||
? " depth = f32_to_d24f(data[index + z_offset]);\n"
|
||||
: " depth = f32_to_d24f(data[index + z_offset] << 1);\n";
|
||||
}
|
||||
|
||||
work_kernel +=
|
||||
@@ -231,8 +234,9 @@ namespace vk
|
||||
}
|
||||
else
|
||||
{
|
||||
work_kernel +=
|
||||
" data[index + z_offset] = d24f_to_f32(value >> 8);\n";
|
||||
work_kernel += !vk::emulate_extended_depth_range()
|
||||
? " data[index + z_offset] = d24f_to_f32(value >> 8);\n"
|
||||
: " data[index + z_offset] = d24f_to_f32(value >> 8) >> 1;\n";
|
||||
}
|
||||
|
||||
work_kernel +=
|
||||
@@ -283,6 +287,12 @@ namespace vk
|
||||
" tmp = bswap_u32(tmp);\n";
|
||||
}
|
||||
|
||||
if (vk::emulate_extended_depth_range())
|
||||
{
|
||||
// Float depth surfaces hold the emulated encoding (half the bit pattern)
|
||||
work_kernel += " tmp.xy <<= 1;\n";
|
||||
}
|
||||
|
||||
// Convert
|
||||
work_kernel += " tmp.z = pack_e4m12_pack16(tmp.xy);\n";
|
||||
|
||||
@@ -314,6 +324,11 @@ namespace vk
|
||||
// Convert
|
||||
work_kernel += " tmp.yz = unpack_e4m12_pack16(tmp.x);\n";
|
||||
|
||||
if (vk::emulate_extended_depth_range())
|
||||
{
|
||||
work_kernel += " tmp.yz >>= 1;\n";
|
||||
}
|
||||
|
||||
if constexpr (_SwapDst)
|
||||
{
|
||||
work_kernel += " tmp.yz = bswap_u32(tmp.yz);\n";
|
||||
|
||||
@@ -253,8 +253,14 @@ void VKGSRender::update_draw_state()
|
||||
bounds_max = std::max(1.f, rsx::method_registers.clip_max());
|
||||
}
|
||||
|
||||
if (!m_device->get_unrestricted_depth_range_support())
|
||||
if (!backend_config.supports_extended_depth_range)
|
||||
{
|
||||
if (rsx::method_registers.depth_bounds_test_enabled() && requires_depth_range_emulation()) [[ unlikely ]]
|
||||
{
|
||||
bounds_min = rsx::encode_emulated_depth(bounds_min);
|
||||
bounds_max = rsx::encode_emulated_depth(bounds_max);
|
||||
}
|
||||
|
||||
bounds_min = std::clamp(bounds_min, 0.f, 1.f);
|
||||
bounds_max = std::clamp(bounds_max, 0.f, 1.f);
|
||||
}
|
||||
|
||||
@@ -298,6 +298,12 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
||||
"layout(location=" << vk::get_varying_register_location("usr") << ") in flat uvec4 draw_params_payload;\n\n";
|
||||
}
|
||||
|
||||
if (m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE)
|
||||
{
|
||||
OS <<
|
||||
"layout(location=" << vk::get_varying_register_location("depth_range") << ") in flat vec2 depth_range;\n\n";
|
||||
}
|
||||
|
||||
OS <<
|
||||
"#define _fs_constants_offset draw_params_payload.x\n"
|
||||
"#define _fs_context_offset draw_params_payload.y\n"
|
||||
@@ -396,7 +402,7 @@ void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
|
||||
m_shader_props.require_srgb_to_linear = properties.has_upg;
|
||||
m_shader_props.require_linear_to_srgb = properties.has_pkg;
|
||||
m_shader_props.require_fog_read = properties.in_register_mask & in_fogc;
|
||||
m_shader_props.emulate_shadow_compare = device_props.emulate_depth_compare;
|
||||
m_shader_props.emulate_shadow_compare = device_props.emulate_depth_compare || device_props.emulated_depth_storage;
|
||||
|
||||
m_shader_props.low_precision_tests = device_props.has_low_precision_rounding && !(m_prog.ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION);
|
||||
m_shader_props.disable_early_discard = !vk::is_NVIDIA(vk::get_driver_vendor());
|
||||
@@ -419,6 +425,9 @@ void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
|
||||
m_shader_props.require_color_format_convert = !!(m_prog.ctrl & RSX_SHADER_CONTROL_TEXTURE_FORMAT_CONVERT);
|
||||
m_shader_props.emulate_depth_compare = !!(m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_COMPARE);
|
||||
m_shader_props.ROP_output_multisampled = !!(m_prog.ctrl & RSX_SHADER_CONTROL_ROP_MULTISAMPLED);
|
||||
m_shader_props.ROP_emulate_depth_range = !!(m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE);
|
||||
m_shader_props.ROP_depth_export = !!(m_prog.ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) && m_shader_props.ROP_emulate_depth_range;
|
||||
m_shader_props.emulated_depth_storage = device_props.emulated_depth_storage;
|
||||
|
||||
// Declare global constants
|
||||
if (m_shader_props.require_fog_read)
|
||||
@@ -547,7 +556,8 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
|
||||
RSX_SHADER_CONTROL_ALPHA_TEST |
|
||||
RSX_SHADER_CONTROL_EMULATE_DEPTH_COMPARE |
|
||||
RSX_SHADER_CONTROL_ROP_OUTPUT_REMAP |
|
||||
RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING;
|
||||
RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING |
|
||||
RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE;
|
||||
|
||||
if (m_prog.ctrl & ROP_control_access_options)
|
||||
{
|
||||
@@ -593,6 +603,8 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
|
||||
}
|
||||
}
|
||||
|
||||
glsl::insert_fragment_epilogue(OS, m_shader_props);
|
||||
|
||||
OS << "}\n";
|
||||
}
|
||||
|
||||
@@ -622,6 +634,7 @@ void VKFragmentProgram::Decompile(const RSXFragmentProgram& prog)
|
||||
}
|
||||
|
||||
decompiler.device_props.emulate_depth_compare = !pdev->get_formats_support().d24_unorm_s8;
|
||||
decompiler.device_props.emulated_depth_storage = vk::emulate_extended_depth_range();
|
||||
decompiler.device_props.has_low_precision_rounding = vk::is_NVIDIA(vk::get_driver_vendor());
|
||||
decompiler.Task();
|
||||
|
||||
|
||||
@@ -251,7 +251,8 @@ namespace vk
|
||||
u8 num_draw_buffers,
|
||||
u8 num_rasterization_samples,
|
||||
bool depth_bounds_support,
|
||||
bool force_disable_blending)
|
||||
bool force_disable_blending,
|
||||
bool force_depth_clamp)
|
||||
{
|
||||
vk::pipeline_props properties{};
|
||||
|
||||
@@ -262,7 +263,15 @@ namespace vk
|
||||
// Rasterizer state
|
||||
properties.state.set_attachment_count(num_draw_buffers);
|
||||
properties.state.set_front_face(vk::get_front_face(REGS(ctx)->front_face_mode()));
|
||||
properties.state.enable_depth_clamp(REGS(ctx)->depth_clamp_enabled() || !REGS(ctx)->depth_clip_enabled());
|
||||
if (!force_depth_clamp) [[ likely ]]
|
||||
{
|
||||
properties.state.enable_depth_clamp(REGS(ctx)->depth_clamp_enabled() || !REGS(ctx)->depth_clip_enabled());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Depth clip and clamp are emulated in the fragment shader
|
||||
properties.state.enable_depth_clamp(true);
|
||||
}
|
||||
properties.state.enable_depth_bias(true);
|
||||
properties.state.enable_depth_bounds_test(depth_bounds_support);
|
||||
|
||||
@@ -645,6 +654,7 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
||||
backend_config.supports_hw_instanced_rendering = true;
|
||||
backend_config.supports_programmable_blending = true;
|
||||
|
||||
backend_config.supports_extended_depth_range = m_device->get_unrestricted_depth_range_support();
|
||||
backend_config.supports_last_provoking_vertex = m_device->get_provoking_vertex_last_support();
|
||||
if (!backend_config.supports_last_provoking_vertex)
|
||||
{
|
||||
@@ -1335,7 +1345,13 @@ void VKGSRender::clear_surface(u32 mask)
|
||||
if (mask & RSX_GCM_CLEAR_DEPTH_BIT)
|
||||
{
|
||||
const u32 clear_depth_bits = REGS(m_ctx)->z_clear_value(is_depth_stencil_format(surface_depth_format));
|
||||
depth_stencil_clear_values.depthStencil.depth = rsx::get_depth_clear_value(surface_depth_format, clear_depth_bits);
|
||||
f32 depth_clear = rsx::get_depth_clear_value(surface_depth_format, clear_depth_bits);
|
||||
if (vk::emulate_extended_depth_range() && rsx::is_float_depth_format(surface_depth_format)) [[ unlikely ]]
|
||||
{
|
||||
depth_clear = rsx::encode_emulated_depth(depth_clear);
|
||||
}
|
||||
|
||||
depth_stencil_clear_values.depthStencil.depth = depth_clear;
|
||||
depth_stencil_clear_values.depthStencil.stencil = stencil_clear;
|
||||
|
||||
depth_stencil_mask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
@@ -1856,7 +1872,8 @@ bool VKGSRender::load_program()
|
||||
static_cast<u8>(m_draw_buffers.size()),
|
||||
u8((m_current_renderpass_key >> 16) & 0xF),
|
||||
m_device->get_depth_bounds_support(),
|
||||
!!(current_fragment_program.ctrl & RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING)
|
||||
!!(current_fragment_program.ctrl & RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING),
|
||||
!!(current_fragment_program.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE)
|
||||
);
|
||||
|
||||
properties.renderpass_key = m_current_renderpass_key;
|
||||
@@ -1901,12 +1918,16 @@ bool VKGSRender::load_program()
|
||||
}
|
||||
|
||||
// Load current program from cache
|
||||
// The shader interpreter does not emulate the depth range; compile those programs synchronously instead
|
||||
const bool allow_async = shadermode != shader_mode::recompiler &&
|
||||
!(fragment_program.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE);
|
||||
|
||||
std::tie(m_program, m_vertex_prog, m_fragment_prog) = m_prog_buffer->get_graphics_pipeline(
|
||||
&m_program_cache_hint,
|
||||
vertex_program,
|
||||
fragment_program,
|
||||
m_pipeline_properties,
|
||||
shadermode != shader_mode::recompiler, true);
|
||||
allow_async, true);
|
||||
|
||||
vk::leave_uninterruptible();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "VKHelpers.h"
|
||||
#include "VKGSRender.h"
|
||||
#include "VKCompute.h"
|
||||
@@ -245,6 +246,11 @@ namespace vk
|
||||
return g_drv_emulate_cond_render;
|
||||
}
|
||||
|
||||
bool emulate_extended_depth_range()
|
||||
{
|
||||
return !g_render_device->get_unrestricted_depth_range_support() && g_cfg.video.emulate_extended_depth_range;
|
||||
}
|
||||
|
||||
bool use_strict_query_scopes()
|
||||
{
|
||||
return g_drv_strict_query_scopes;
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace vk
|
||||
bool sanitize_fp_values();
|
||||
bool fence_reset_disabled();
|
||||
bool emulate_conditional_rendering();
|
||||
bool emulate_extended_depth_range();
|
||||
bool use_strict_query_scopes();
|
||||
bool force_reuse_query_pools();
|
||||
VkFlags get_heap_compatible_buffer_types();
|
||||
|
||||
@@ -321,6 +321,11 @@ void VKVertexDecompilerThread::insertOutputs(std::stringstream& OS, const std::v
|
||||
{
|
||||
OS << "layout(location=" << vk::get_varying_register_location("usr") << ") out flat uvec4 draw_params_payload;\n";
|
||||
}
|
||||
|
||||
if (m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE)
|
||||
{
|
||||
OS << "layout(location=" << vk::get_varying_register_location("depth_range") << ") out flat vec2 depth_range;\n";
|
||||
}
|
||||
}
|
||||
|
||||
void VKVertexDecompilerThread::insertFSExport(std::stringstream& OS)
|
||||
@@ -346,6 +351,7 @@ void VKVertexDecompilerThread::insertMainStart(std::stringstream& OS)
|
||||
properties2.low_precision_tests = vk::is_NVIDIA(vk::get_driver_vendor());
|
||||
properties2.require_explicit_invariance = (vk::is_NVIDIA(vk::get_driver_vendor()) && g_cfg.video.shader_precision != gpu_preset_level::low);
|
||||
properties2.require_instanced_render = !!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS);
|
||||
properties2.emulate_depth_range = !!(m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE);
|
||||
|
||||
glsl::insert_glsl_legacy_function(OS, properties2);
|
||||
glsl::insert_vertex_input_fetch(OS, glsl::glsl_rules_vulkan);
|
||||
@@ -477,7 +483,18 @@ void VKVertexDecompilerThread::insertMainEnd(std::stringstream& OS)
|
||||
}
|
||||
|
||||
OS << " gl_Position = gl_Position * scale_offset_mat;\n";
|
||||
OS << " gl_Position = apply_zclip_xform(gl_Position, z_near, z_far);\n";
|
||||
|
||||
if (!(m_prog.ctrl & RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE)) [[ likely ]]
|
||||
{
|
||||
OS << " gl_Position = apply_zclip_xform(gl_Position, z_near, z_far);\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
OS <<
|
||||
" depth_range = vec2(min(z_near, z_far), max(z_near, z_far));\n"
|
||||
" gl_Position = apply_depth_range_xform(gl_Position, depth_range);\n";
|
||||
}
|
||||
|
||||
OS << "}\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -476,6 +476,7 @@ namespace gcm
|
||||
RSX_SHADER_CONTROL_ROP_MULTISAMPLED = 0x10000000, // ROP outputs are multisampled
|
||||
RSX_SHADER_CONTROL_ROP_OUTPUT_REMAP = 0x20000000, // ROP outputs need channel swizzles.
|
||||
RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING = 0x40000000, // Enable programmable blending.
|
||||
RSX_SHADER_CONTROL_EMULATE_DEPTH_RANGE = 0x80000000, // Float depth target without host support for depth values above 1
|
||||
|
||||
// Meta
|
||||
RSX_SHADER_CONTROL_META_USES_DISCARD = (RSX_SHADER_CONTROL_USES_KIL | RSX_SHADER_CONTROL_TEXTURE_ALPHA_KILL | RSX_SHADER_CONTROL_ALPHA_TEST | RSX_SHADER_CONTROL_POLYGON_STIPPLE | RSX_SHADER_CONTROL_ALPHA_TO_COVERAGE),
|
||||
|
||||
@@ -775,7 +775,6 @@ namespace rsx
|
||||
state_signals[NV4097_SET_DEPTH_BOUNDS_MIN] = rsx::depth_bounds_state_dirty;
|
||||
state_signals[NV4097_SET_DEPTH_BOUNDS_MAX] = rsx::depth_bounds_state_dirty;
|
||||
state_signals[NV4097_SET_CULL_FACE_ENABLE] = rsx::pipeline_config_dirty;
|
||||
state_signals[NV4097_SET_ZMIN_MAX_CONTROL] = rsx::pipeline_config_dirty;
|
||||
state_signals[NV4097_SET_LOGIC_OP_ENABLE] = rsx::pipeline_config_dirty;
|
||||
state_signals[NV4097_SET_LOGIC_OP] = rsx::pipeline_config_dirty;
|
||||
state_signals[NV4097_SET_BLEND_ENABLE] = rsx::pipeline_config_dirty | rsx::blend_config_dirty;
|
||||
@@ -1621,6 +1620,7 @@ namespace rsx
|
||||
|
||||
// NV4097
|
||||
bind(NV4097_SET_CULL_FACE, nv4097::set_face_property);
|
||||
bind(NV4097_SET_ZMIN_MAX_CONTROL, nv4097::set_zmin_max_control);
|
||||
bind(NV4097_SET_FRONT_FACE, nv4097::set_face_property);
|
||||
bind(NV4097_TEXTURE_READ_SEMAPHORE_RELEASE, nv4097::texture_read_semaphore_release);
|
||||
bind(NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE, nv4097::back_end_write_semaphore_release);
|
||||
|
||||
@@ -149,6 +149,7 @@ struct cfg_root : cfg::node
|
||||
cfg::_bool disable_vertex_cache{ this, "Disable Vertex Cache", false };
|
||||
cfg::_bool disable_FIFO_reordering{ this, "Disable FIFO Reordering", false };
|
||||
cfg::_bool emulate_depth_compare{ this, "Emulate Special Depth Comparison", false };
|
||||
cfg::_bool emulate_extended_depth_range{ this, "Emulate Extended Depth Range", false };
|
||||
cfg::_bool frame_skip_enabled{ this, "Enable Frame Skip", false, true };
|
||||
cfg::_bool force_cpu_blit_processing{ this, "Force CPU Blit", false, true }; // Debugging option
|
||||
cfg::_bool disable_on_disk_shader_cache{ this, "Disable On-Disk Shader Cache", false };
|
||||
|
||||
@@ -1131,6 +1131,7 @@
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\OverlayRenderVS.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\RSXMemoryTiling.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\RSXProg\RSXDefines2.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\RSXProg\RSXFragmentEpilogue.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\RSXProg\RSXFragmentPrologue.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\RSXProg\RSXFragmentTextureDepthConversion.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\RSXProg\RSXFragmentTextureMSAAOps.glsl" />
|
||||
|
||||
@@ -3063,6 +3063,9 @@
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\OverlayRenderFS.glsl">
|
||||
<Filter>Emu\GPU\RSX\Program\Snippets</Filter>
|
||||
</None>
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\RSXProg\RSXFragmentEpilogue.glsl">
|
||||
<Filter>Emu\GPU\RSX\Program\Snippets\RSXProg</Filter>
|
||||
</None>
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\RSXProg\RSXFragmentPrologue.glsl">
|
||||
<Filter>Emu\GPU\RSX\Program\Snippets\RSXProg</Filter>
|
||||
</None>
|
||||
|
||||
Reference in New Issue
Block a user