diff --git a/rpcs3/Emu/RSX/Program/ProgramStateCache.cpp b/rpcs3/Emu/RSX/Program/ProgramStateCache.cpp index 7f1ea5ae27..9d70212c2a 100644 --- a/rpcs3/Emu/RSX/Program/ProgramStateCache.cpp +++ b/rpcs3/Emu/RSX/Program/ProgramStateCache.cpp @@ -533,16 +533,16 @@ AVX512_ICL_FUNC bool vertex_program_compare_512(const RSXVertexProgram &binary1, bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const { - if (binary1.output_mask != binary2.output_mask) + if (!compare_properties(binary1, binary2)) + { return false; - if (binary1.ctrl != binary2.ctrl) - return false; - if (binary1.texture_state != binary2.texture_state) - return false; - if (binary1.data.size() != binary2.data.size()) - return false; - if (binary1.jump_table != binary2.jump_table) + } + + if (binary1.data.size() != binary2.data.size() || + binary1.jump_table != binary2.jump_table) + { return false; + } #ifdef ARCH_X64 if (utils::has_avx512_icl()) @@ -572,6 +572,13 @@ bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const R return true; } +bool vertex_program_compare::compare_properties(const RSXVertexProgram& binary1, const RSXVertexProgram& binary2) +{ + return binary1.output_mask == binary2.output_mask && + binary1.ctrl == binary2.ctrl && + binary1.texture_state == binary2.texture_state; +} + bool fragment_program_utils::is_any_src_constant(v128 sourceOperand) { const u64 masked = sourceOperand._u64[1] & 0x30000000300; @@ -741,12 +748,7 @@ usz fragment_program_storage_hash::operator()(const RSXFragmentProgram& program) bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) const { - if (binary1.ucode_length != binary2.ucode_length || - binary1.ctrl != binary2.ctrl || - binary1.texture_state != binary2.texture_state || - binary1.texcoord_control_mask != binary2.texcoord_control_mask || - binary1.two_sided_lighting != binary2.two_sided_lighting || - binary1.mrt_buffers_count != binary2.mrt_buffers_count) + if (!compare_properties(binary1, binary2)) { return false; } @@ -771,19 +773,14 @@ bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, con return true; } -bool fragment_program_compare::config_only(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) +bool fragment_program_compare::compare_properties(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) { - if (binary1.ucode_length != binary2.ucode_length || - binary1.ctrl != binary2.ctrl || - binary1.texture_state != binary2.texture_state || - binary1.texcoord_control_mask != binary2.texcoord_control_mask || - binary1.two_sided_lighting != binary2.two_sided_lighting || - binary1.mrt_buffers_count != binary2.mrt_buffers_count) - { - return false; - } - - return true; + return binary1.ucode_length == binary2.ucode_length && + binary1.ctrl == binary2.ctrl && + binary1.texture_state == binary2.texture_state && + binary1.texcoord_control_mask == binary2.texcoord_control_mask && + binary1.two_sided_lighting == binary2.two_sided_lighting && + binary1.mrt_buffers_count == binary2.mrt_buffers_count; } namespace rsx @@ -857,12 +854,68 @@ namespace rsx { if (flags & rsx::vertex_program_dirty) { - cached_vertex_program = nullptr; + m_cached_vertex_program = nullptr; } if (flags & rsx::fragment_program_dirty) { - cached_fragment_program = nullptr; + m_cached_fragment_program = nullptr; } } + + void program_cache_hint_t::invalidate_vertex_program(const RSXVertexProgram& p) + { + if (!m_cached_vertex_program) + { + return; + } + + if (!vertex_program_compare::compare_properties(m_cached_vp_properties, p)) + { + m_cached_vertex_program = nullptr; + } + } + + void program_cache_hint_t::invalidate_fragment_program(const RSXFragmentProgram& p) + { + if (!m_cached_fragment_program) + { + return; + } + + if (!fragment_program_compare::compare_properties(m_cached_fp_properties, p)) + { + m_cached_fragment_program = nullptr; + } + } + + void program_cache_hint_t::cache_vertex_program(program_cache_hint_t* cache, const RSXVertexProgram& ref, void* vertex_program) + { + if (!cache) + { + return; + } + + cache->m_cached_vertex_program = vertex_program; + cache->m_cached_vp_properties.output_mask = ref.output_mask; + cache->m_cached_vp_properties.ctrl = ref.ctrl; + cache->m_cached_vp_properties.texture_state = ref.texture_state; + } + + void program_cache_hint_t::cache_fragment_program(program_cache_hint_t* cache, const RSXFragmentProgram& ref, void* fragment_program) + { + if (!cache) + { + return; + } + + cache->m_cached_fragment_program = fragment_program; + cache->m_cached_fp_properties.ucode_length = ref.ucode_length; + cache->m_cached_fp_properties.ctrl = ref.ctrl; + cache->m_cached_fp_properties.texture_state = ref.texture_state; + cache->m_cached_fp_properties.texcoord_control_mask = ref.texcoord_control_mask; + cache->m_cached_fp_properties.two_sided_lighting = ref.two_sided_lighting; + cache->m_cached_fp_properties.mrt_buffers_count = ref.mrt_buffers_count; + } + } diff --git a/rpcs3/Emu/RSX/Program/ProgramStateCache.h b/rpcs3/Emu/RSX/Program/ProgramStateCache.h index ff1082dc36..6007ac7f2d 100644 --- a/rpcs3/Emu/RSX/Program/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Program/ProgramStateCache.h @@ -43,6 +43,8 @@ namespace program_hash_util struct vertex_program_compare { + static bool compare_properties(const RSXVertexProgram& binary1, const RSXVertexProgram& binary2); + bool operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const; }; @@ -80,8 +82,9 @@ namespace program_hash_util struct fragment_program_compare { + static bool compare_properties(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2); + bool operator()(const RSXFragmentProgram &binary1, const RSXFragmentProgram &binary2) const; - static bool config_only(const RSXFragmentProgram &binary1, const RSXFragmentProgram &binary2); }; } @@ -92,40 +95,46 @@ namespace rsx template T* get_fragment_program() const { - return utils::bless(cached_fragment_program); + return utils::bless(m_cached_fragment_program); } template T* get_vertex_program() const { - return utils::bless(cached_vertex_program); + return utils::bless(m_cached_vertex_program); } bool has_vertex_program() const { - return cached_vertex_program != nullptr; + return m_cached_vertex_program != nullptr; } bool has_fragment_program() const { - return cached_fragment_program != nullptr; + return m_cached_fragment_program != nullptr; } + // Invalidate caches if the renderer state shows they are out of date void invalidate(u32 flags); - static inline void cache_vertex_program(program_cache_hint_t* cache, void* vertex_program) - { - if (cache) cache->cached_vertex_program = vertex_program; - } + // Invalidate vertex program if the cached program is not compatible with the incoming + void invalidate_vertex_program(const RSXVertexProgram& p); - static inline void cache_fragment_program(program_cache_hint_t* cache, void* fragment_program) - { - if (cache) cache->cached_fragment_program = fragment_program; - } + // Invalidate fragment program if the cached program is not compatible with the incoming + void invalidate_fragment_program(const RSXFragmentProgram& p); + + // Helper - optionally cache the vertex program if possible + static void cache_vertex_program(program_cache_hint_t* cache, const RSXVertexProgram& ref, void* vertex_program); + + // Helper - optionally cache the fragment program if possible + static void cache_fragment_program(program_cache_hint_t* cache, const RSXFragmentProgram& ref, void* fragment_program); protected: - void* cached_fragment_program = nullptr; - void* cached_vertex_program = nullptr; + void* m_cached_fragment_program = nullptr; + void* m_cached_vertex_program = nullptr; + + RSXFragmentProgram m_cached_fp_properties; + RSXVertexProgram m_cached_vp_properties; }; void write_fragment_constants_to_buffer(const std::span& buffer, const RSXFragmentProgram& rsx_prog, const std::vector& offsets_cache, bool sanitize = true); @@ -228,7 +237,7 @@ protected: const auto& I = m_vertex_shader_cache.find(rsx_vp); if (I != m_vertex_shader_cache.end()) { - rsx::program_cache_hint_t::cache_vertex_program(cache_hint, &(I->second)); + rsx::program_cache_hint_t::cache_vertex_program(cache_hint, rsx_vp, &(I->second)); return std::forward_as_tuple(I->second, true); } @@ -245,7 +254,7 @@ protected: backend_traits::recompile_vertex_program(rsx_vp, *new_shader, m_next_id++); } - rsx::program_cache_hint_t::cache_vertex_program(cache_hint, new_shader); + rsx::program_cache_hint_t::cache_vertex_program(cache_hint, rsx_vp, new_shader); return std::forward_as_tuple(*new_shader, false); } @@ -267,7 +276,7 @@ protected: const auto& I = m_fragment_shader_cache.find(rsx_fp); if (I != m_fragment_shader_cache.end()) { - rsx::program_cache_hint_t::cache_fragment_program(cache_hint, &(I->second)); + rsx::program_cache_hint_t::cache_fragment_program(cache_hint, rsx_fp, &(I->second)); return std::forward_as_tuple(I->second, true); } @@ -284,7 +293,7 @@ protected: backend_traits::recompile_fragment_program(rsx_fp, *new_shader, m_next_id++); } - rsx::program_cache_hint_t::cache_fragment_program(cache_hint, new_shader); + rsx::program_cache_hint_t::cache_fragment_program(cache_hint, rsx_fp, new_shader); return std::forward_as_tuple(*new_shader, false); } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f33c778e62..f733a20847 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -2034,6 +2034,8 @@ namespace rsx } current_vertex_program.texture_state.import(current_vp_texture_state, current_vp_metadata.referenced_textures_mask); + + m_program_cache_hint.invalidate_vertex_program(current_vertex_program); } void thread::get_current_fragment_program(const std::array, rsx::limits::fragment_textures_count>& sampler_descriptors) @@ -2275,6 +2277,8 @@ namespace rsx rsx_log.trace("FS exports depth component but depth test is disabled (INVALID_OPERATION)"); } } + + m_program_cache_hint.invalidate_fragment_program(current_fragment_program); } bool thread::invalidate_fragment_program(u32 dst_dma, u32 dst_offset, u32 size)