From 5430e1d31089eab725b61b4896355f051ec79292 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 29 Sep 2016 09:54:32 +0300 Subject: [PATCH] rsx/gl/vk/dx12: Add emulated texture fetch for depth read (#2173) * rsx/gl/vk/dx12: Add emulated texture fetch for depth read gl/vk/dx12: Simplify reinterpretation equation * gl: Remove unnecessary re-swizzle * glsl: explicitly cast uint to float --- .../RSX/Common/FragmentProgramDecompiler.cpp | 5 ++++- rpcs3/Emu/RSX/Common/ProgramStateCache.cpp | 2 +- rpcs3/Emu/RSX/Common/ShaderParam.h | 1 + rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp | 11 +++++++++++ rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp | 17 +++++++++++++++++ rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp | 13 +++++++++++++ rpcs3/Emu/RSX/GL/GLGSRender.cpp | 17 +++++++++++++++++ rpcs3/Emu/RSX/RSXFragmentProgram.h | 1 + rpcs3/Emu/RSX/RSXThread.cpp | 2 ++ rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp | 12 ++++++++++++ rpcs3/Emu/RSX/VK/VKGSRender.cpp | 17 +++++++++++++++++ 11 files changed, 96 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index ca69d312e0..0e8b16e7bf 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -448,7 +448,10 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D)); return true; case rsx::texture_dimension_extended::texture_dimension_2d: - SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D)); + if (m_prog.redirected_textures & (1 << dst.tex_num)) + SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA)); + else + SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D)); return true; case rsx::texture_dimension_extended::texture_dimension_cubemap: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE)); diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp b/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp index b9704b2802..9f4130ef64 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp @@ -106,7 +106,7 @@ bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, con if (binary1.texture_dimensions != binary2.texture_dimensions || binary1.unnormalized_coords != binary2.unnormalized_coords || binary1.height != binary2.height || binary1.origin_mode != binary2.origin_mode || binary1.pixel_center_mode != binary2.pixel_center_mode || binary1.back_color_diffuse_output != binary2.back_color_diffuse_output || binary1.back_color_specular_output != binary2.back_color_specular_output || - binary1.front_back_color_enabled != binary2.front_back_color_enabled || binary1.alpha_func != binary2.alpha_func) + binary1.front_back_color_enabled != binary2.front_back_color_enabled || binary1.alpha_func != binary2.alpha_func || binary1.redirected_textures != binary2.redirected_textures) return false; const qword *instBuffer1 = (const qword*)binary1.addr; const qword *instBuffer2 = (const qword*)binary2.addr; diff --git a/rpcs3/Emu/RSX/Common/ShaderParam.h b/rpcs3/Emu/RSX/Common/ShaderParam.h index 4adf78073a..6d3fd4d79b 100644 --- a/rpcs3/Emu/RSX/Common/ShaderParam.h +++ b/rpcs3/Emu/RSX/Common/ShaderParam.h @@ -37,6 +37,7 @@ enum class FUNCTION { FUNCTION_VERTEX_TEXTURE_FETCH2D, FUNCTION_VERTEX_TEXTURE_FETCH3D, FUNCTION_VERTEX_TEXTURE_FETCHCUBE, + FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA }; enum class COMPARE { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp index 635b154d07..0e5b602981 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp @@ -80,6 +80,8 @@ std::string getFunctionImp(FUNCTION f) return "ddx($0)"; case FUNCTION::FUNCTION_DFDY: return "ddy($0)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA: + return "texture2DReconstruct($t.Sample($tsampler, $0.xy * $t_scale))"; } } @@ -202,5 +204,14 @@ void insert_d3d12_legacy_function(std::ostream& OS) OS << "{\n"; OS << " return unpackSnorm2x16(val) * 6.1E+5;\n"; OS << "}\n\n"; + + OS << "float4 texture2DReconstruct(float depth_value)\n"; + OS << "{\n"; + OS << " uint value = round(depth_value * 16777215);\n"; + OS << " uint b = (value & 0xff);\n"; + OS << " uint g = (value >> 8) & 0xff;\n"; + OS << " uint r = (value >> 16) & 0xff;\n"; + OS << " return float4(r/255., g/255., b/255., 1.);\n"; + OS << "}\n\n"; } #endif diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index fdd40afe1a..385bd2ec05 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -43,6 +43,23 @@ void D3D12GSRender::load_program() m_vertex_program = get_current_vertex_program(); m_fragment_program = get_current_fragment_program(); + for (int i = 0; i < 16; ++i) + { + auto &tex = rsx::method_registers.fragment_textures[i]; + if (tex.enabled()) + { + const u32 texaddr = rsx::get_address(tex.offset(), tex.location()); + if (m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) + { + u32 format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + if (format == CELL_GCM_TEXTURE_A8R8G8B8 || format == CELL_GCM_TEXTURE_D8R8G8B8) + { + m_fragment_program.redirected_textures |= (1 << i); + } + } + } + } + D3D12PipelineProperties prop = {}; prop.Topology = get_primitive_topology_type(rsx::method_registers.current_draw_clause.primitive); diff --git a/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp b/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp index 10a3bf8b0b..66c4781825 100644 --- a/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp @@ -80,6 +80,8 @@ std::string getFunctionImpl(FUNCTION f) return "dFdy($0)"; case FUNCTION::FUNCTION_VERTEX_TEXTURE_FETCH2D: return "textureLod($t, $0.xy, 0)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA: + return "texture2DReconstruct($t, $0.xy)"; } } @@ -137,4 +139,15 @@ void insert_glsl_legacy_function(std::ostream& OS) OS << " result.z = clamped_val.x > 0.0 ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.0;\n"; OS << " return result;\n"; OS << "}\n\n"; + + //NOTE: We lose precision if we just store depth value into 8-bit textures i.e (depth, 0, 0) + OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord)\n"; + OS << "{\n"; + OS << " float depth_value = texture(tex, coord.xy).r;\n"; + OS << " uint value = uint(depth_value * 16777215);\n"; + OS << " uint b = (value & 0xff);\n"; + OS << " uint g = (value >> 8) & 0xff;\n"; + OS << " uint r = (value >> 16) & 0xff;\n"; + OS << " return vec4(float(r)/255., float(g)/255., float(b)/255., 1.);\n"; + OS << "}\n\n"; } diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 1496605f1f..f2ac598bea 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -653,6 +653,23 @@ bool GLGSRender::load_program() RSXVertexProgram vertex_program = get_current_vertex_program(); RSXFragmentProgram fragment_program = get_current_fragment_program(); + for (int i = 0; i < 16; ++i) + { + auto &tex = rsx::method_registers.fragment_textures[i]; + if (tex.enabled()) + { + const u32 texaddr = rsx::get_address(tex.offset(), tex.location()); + if (m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) + { + u32 format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + if (format == CELL_GCM_TEXTURE_A8R8G8B8 || format == CELL_GCM_TEXTURE_D8R8G8B8) + { + fragment_program.redirected_textures |= (1 << i); + } + } + } + } + m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr); m_program->use(); diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 9b1d763c18..2583dc8daa 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -221,6 +221,7 @@ struct RSXFragmentProgram u32 offset; u32 ctrl; u16 unnormalized_coords; + u16 redirected_textures; rsx::comparison_function alpha_func; bool front_back_color_enabled : 1; bool back_color_diffuse_output : 1; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 283011c62e..56f05debc1 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -828,6 +828,8 @@ namespace rsx result.origin_mode = rsx::method_registers.shader_window_origin(); result.pixel_center_mode = rsx::method_registers.shader_window_pixel(); result.height = rsx::method_registers.shader_window_height(); + result.redirected_textures = 0; + std::array texture_dimensions; for (u32 i = 0; i < rsx::limits::fragment_textures_count; ++i) diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp index ca675132a6..7405b1e6a3 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp @@ -75,6 +75,8 @@ namespace vk return "dFdy($0)"; case FUNCTION::FUNCTION_VERTEX_TEXTURE_FETCH2D: return "textureLod($t, $0.xy, 0)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA: + return "texture2DReconstruct($t, $0.xy)"; } } @@ -132,6 +134,16 @@ namespace vk OS << " result.z = clamped_val.x > 0. ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.;\n"; OS << " return result;\n"; OS << "}\n\n"; + + OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord)\n"; + OS << "{\n"; + OS << " float depth_value = texture(tex, coord.xy).r;\n"; + OS << " uint value = uint(depth_value * 16777215);\n"; + OS << " uint b = (value & 0xff);\n"; + OS << " uint g = (value >> 8) & 0xff;\n"; + OS << " uint r = (value >> 16) & 0xff;\n"; + OS << " return vec4(float(r)/255., float(g)/255., float(b)/255., 1.);\n"; + OS << "}\n\n"; } void init_default_resources(TBuiltInResource &rsc) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 3a2795e1db..a6ec9231d3 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -975,6 +975,23 @@ bool VKGSRender::load_program() RSXVertexProgram vertex_program = get_current_vertex_program(); RSXFragmentProgram fragment_program = get_current_fragment_program(); + for (int i = 0; i < 16; ++i) + { + auto &tex = rsx::method_registers.fragment_textures[i]; + if (tex.enabled()) + { + const u32 texaddr = rsx::get_address(tex.offset(), tex.location()); + if (m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) + { + u32 format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + if (format == CELL_GCM_TEXTURE_A8R8G8B8 || format == CELL_GCM_TEXTURE_D8R8G8B8) + { + fragment_program.redirected_textures |= (1 << i); + } + } + } + } + vk::pipeline_props properties = {}; properties.ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;