From 90c2324e47c979122a7c38f2a3e29e2accd9d6bc Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 2 Dec 2017 18:20:52 +0300 Subject: [PATCH] rsx: Program cache fixes - Reorganize storage hash vs ucode hash - Scan for actual fragment program start in case leading NOPed code precedes the actual instructions -- e.g FEAR2 Demo has over 32k of padding before actual program code that messes up hashes --- rpcs3/Emu/RSX/Common/ProgramStateCache.cpp | 43 +++++++++++++++++++++- rpcs3/Emu/RSX/Common/ProgramStateCache.h | 17 +++++++-- rpcs3/Emu/RSX/GL/GLProgramBuffer.h | 4 +- rpcs3/Emu/RSX/RSXThread.cpp | 10 ++++- rpcs3/Emu/RSX/VK/VKProgramBuffer.h | 4 +- 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp b/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp index d3eb754cff..39b2082793 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp @@ -3,7 +3,7 @@ using namespace program_hash_util; -size_t vertex_program_hash::operator()(const RSXVertexProgram &program) const +size_t vertex_program_utils::get_vertex_program_ucode_hash(const RSXVertexProgram &program) { // 64-bit Fowler/Noll/Vo FNV-1a hash code size_t hash = 0xCBF29CE484222325ULL; @@ -22,6 +22,13 @@ size_t vertex_program_hash::operator()(const RSXVertexProgram &program) const return hash; } +size_t vertex_program_storage_hash::operator()(const RSXVertexProgram &program) const +{ + size_t hash = vertex_program_utils::get_vertex_program_ucode_hash(program); + hash ^= program.output_mask; + return hash; +} + bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const { if (binary1.output_mask != binary2.output_mask) @@ -77,7 +84,24 @@ size_t fragment_program_utils::get_fragment_program_ucode_size(void *ptr) } } -size_t fragment_program_hash::operator()(const RSXFragmentProgram& program) const +u32 fragment_program_utils::get_fragment_program_start(void *ptr) +{ + const qword *instBuffer = (const qword*)ptr; + size_t instIndex = 0; + while (true) + { + const qword& inst = instBuffer[instIndex]; + u32 opcode = inst.word[0] >> 16 & 0x3F; + if (opcode) + break; + + instIndex++; + } + + return instIndex * 16; +} + +size_t fragment_program_utils::get_fragment_program_ucode_hash(const RSXFragmentProgram& program) { // 64-bit Fowler/Noll/Vo FNV-1a hash code size_t hash = 0xCBF29CE484222325ULL; @@ -104,6 +128,21 @@ size_t fragment_program_hash::operator()(const RSXFragmentProgram& program) cons return 0; } +size_t fragment_program_storage_hash::operator()(const RSXFragmentProgram& program) const +{ + size_t hash = fragment_program_utils::get_fragment_program_ucode_hash(program); + hash ^= program.ctrl; + hash ^= program.texture_dimensions; + hash ^= program.unnormalized_coords; + hash ^= program.back_color_diffuse_output; + hash ^= program.back_color_specular_output; + hash ^= program.front_back_color_enabled; + hash ^= program.shadow_textures; + hash ^= program.redirected_textures; + + return hash; +} + bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) const { if (binary1.ctrl != binary2.ctrl || binary1.texture_dimensions != binary2.texture_dimensions || binary1.unnormalized_coords != binary2.unnormalized_coords || diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.h b/rpcs3/Emu/RSX/Common/ProgramStateCache.h index 121cb15b00..ed8d33539d 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.h @@ -24,7 +24,12 @@ namespace program_hash_util u32 word[4]; }; - struct vertex_program_hash + struct vertex_program_utils + { + static size_t get_vertex_program_ucode_hash(const RSXVertexProgram &program); + }; + + struct vertex_program_storage_hash { size_t operator()(const RSXVertexProgram &program) const; }; @@ -42,9 +47,13 @@ namespace program_hash_util static bool is_constant(u32 sourceOperand); static size_t get_fragment_program_ucode_size(void *ptr); + + static u32 get_fragment_program_start(void *ptr); + + static size_t get_fragment_program_ucode_hash(const RSXFragmentProgram &program); }; - struct fragment_program_hash + struct fragment_program_storage_hash { size_t operator()(const RSXFragmentProgram &program) const; }; @@ -78,8 +87,8 @@ class program_state_cache using vertex_program_type = typename backend_traits::vertex_program_type; using fragment_program_type = typename backend_traits::fragment_program_type; - using binary_to_vertex_program = std::unordered_map ; - using binary_to_fragment_program = std::unordered_map; + using binary_to_vertex_program = std::unordered_map ; + using binary_to_fragment_program = std::unordered_map; struct pipeline_key diff --git a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h index 7ea8c85bfc..4499203a80 100644 --- a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h +++ b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h @@ -82,12 +82,12 @@ public: u64 get_hash(RSXVertexProgram &prog) { - return program_hash_util::vertex_program_hash()(prog); + return program_hash_util::vertex_program_utils::get_vertex_program_ucode_hash(prog); } u64 get_hash(RSXFragmentProgram &prog) { - return program_hash_util::fragment_program_hash()(prog); + return program_hash_util::fragment_program_utils::get_fragment_program_ucode_hash(prog); } template diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 86d78df432..2efa9ec853 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1348,8 +1348,11 @@ namespace rsx const u32 program_location = (shader_program & 0x3) - 1; const u32 program_offset = (shader_program & ~0x3); - result.offset = program_offset; result.addr = vm::base(rsx::get_address(program_offset, program_location)); + auto program_start = program_hash_util::fragment_program_utils::get_fragment_program_start(result.addr); + + result.addr = ((u8*)result.addr + program_start); + result.offset = program_offset + program_start; result.valid = true; result.ctrl = rsx::method_registers.shader_control() & (CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS | CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT); result.unnormalized_coords = 0; @@ -1454,8 +1457,11 @@ namespace rsx const u32 program_location = (shader_program & 0x3) - 1; const u32 program_offset = (shader_program & ~0x3); - result.offset = program_offset; result.addr = vm::base(rsx::get_address(program_offset, program_location)); + auto program_start = program_hash_util::fragment_program_utils::get_fragment_program_start(result.addr); + + result.addr = ((u8*)result.addr + program_start); + result.offset = program_offset + program_start; result.valid = true; result.ctrl = rsx::method_registers.shader_control() & (CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS | CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT); result.unnormalized_coords = 0; diff --git a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h index 224c10a141..c037a80c37 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h +++ b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h @@ -185,12 +185,12 @@ public: u64 get_hash(RSXVertexProgram &prog) { - return program_hash_util::vertex_program_hash()(prog); + return program_hash_util::vertex_program_utils::get_vertex_program_ucode_hash(prog); } u64 get_hash(RSXFragmentProgram &prog) { - return program_hash_util::fragment_program_hash()(prog); + return program_hash_util::fragment_program_utils::get_fragment_program_ucode_hash(prog); } template