diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 6dbd7f919c..0a8b78bf51 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -781,7 +781,10 @@ bool GLGSRender::load_program() if (shadermode != shader_mode::interpreter_only) [[likely]] { void* pipeline_properties = nullptr; - std::tie(m_program, m_vertex_prog, m_fragment_prog) = m_prog_buffer.get_graphics_pipeline(current_vertex_program, current_fragment_program, pipeline_properties, + std::tie(m_program, m_vertex_prog, m_fragment_prog) = m_prog_buffer.get_graphics_pipeline( + current_vertex_program, vertex_program_invalidation_count, + current_fragment_program, fragment_program_invalidation_count, + pipeline_properties, shadermode != shader_mode::recompiler, true); if (m_prog_buffer.check_cache_missed()) diff --git a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h index 2d6f19f271..9a1d249f59 100644 --- a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h +++ b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h @@ -135,13 +135,13 @@ struct GLProgramBuffer : public program_state_cache template void add_pipeline_entry(const RSXVertexProgram& vp, const RSXFragmentProgram& fp, void* &props, Args&& ...args) { - get_graphics_pipeline(vp, fp, props, false, false, std::forward(args)...); + get_graphics_pipeline(vp, umax, fp, umax, props, false, false, std::forward(args)...); } void preload_programs(const RSXVertexProgram& vp, const RSXFragmentProgram& fp) { - search_vertex_program(vp); - search_fragment_program(fp); + search_vertex_program(vp, umax); + search_fragment_program(fp, umax); } bool check_cache_missed() const diff --git a/rpcs3/Emu/RSX/Program/ProgramStateCache.h b/rpcs3/Emu/RSX/Program/ProgramStateCache.h index c4bacedf30..ae0e8f6258 100644 --- a/rpcs3/Emu/RSX/Program/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Program/ProgramStateCache.h @@ -167,24 +167,30 @@ protected: pipeline_storage_type __null_pipeline_handle; /// bool here to inform that the program was preexisting. - std::tuple search_vertex_program(const RSXVertexProgram& rsx_vp, bool force_load = true) + std::tuple search_vertex_program(const RSXVertexProgram& rsx_vp, usz rsx_vp_invalidation_count) { bool recompile = false; vertex_program_type* new_shader; { thread_local const std::pair* prev_vp = nullptr; - thread_local usz prev_count = umax; - static atomic_t invl_count = 0; + thread_local usz prev_map_count = umax, prev_rsx_count = umax; + static atomic_t map_invl_count = 0; reader_lock lock(m_vertex_mutex); - if (prev_count == invl_count) + if (prev_map_count == map_invl_count) { // prev_vp must be non-null here if (prev_vp->first.data.size() == rsx_vp.data.size() && prev_vp->first.output_mask == rsx_vp.output_mask) { + if (rsx_vp_invalidation_count != umax && prev_rsx_count == rsx_vp_invalidation_count) + { + return std::forward_as_tuple(prev_vp->second, true); + } + if (program_hash_util::vertex_program_compare()(prev_vp->first, rsx_vp)) { + prev_rsx_count = rsx_vp_invalidation_count; return std::forward_as_tuple(prev_vp->second, true); } } @@ -194,24 +200,20 @@ protected: if (I != m_vertex_shader_cache.end()) { prev_vp = &*I; - prev_count = invl_count; + prev_map_count = map_invl_count; + prev_rsx_count = rsx_vp_invalidation_count; return std::forward_as_tuple(I->second, true); } - if (!force_load) - { - prev_count = umax; - return std::forward_as_tuple(__null_vertex_program, false); - } - rsx_log.trace("VP not found in buffer!"); lock.upgrade(); auto [it, inserted] = m_vertex_shader_cache.try_emplace(rsx_vp); new_shader = &(it->second); recompile = inserted; - prev_count = umax; - invl_count++; + prev_map_count = umax; + prev_rsx_count = umax; + map_invl_count++; } if (recompile) @@ -223,24 +225,28 @@ protected: } /// bool here to inform that the program was preexisting. - std::tuple search_fragment_program(const RSXFragmentProgram& rsx_fp, bool force_load = true) + std::tuple search_fragment_program(const RSXFragmentProgram& rsx_fp, usz /*rsx_fp_invalidation_count*/) { bool recompile = false; typename binary_to_fragment_program::iterator it; fragment_program_type* new_shader; - { thread_local const std::pair* prev_fp = nullptr; - thread_local usz prev_count = umax; - static atomic_t invl_count = 0; + thread_local usz prev_map_count = umax, prev_rsx_count = umax; + static atomic_t map_invl_count = 0; reader_lock lock(m_fragment_mutex); - if (prev_count == invl_count) + if (prev_map_count == map_invl_count) { // prev_vp must be non-null here if (prev_fp->first.ucode_length == rsx_fp.ucode_length && prev_fp->first.texcoord_control_mask == rsx_fp.texcoord_control_mask) { + // if (rsx_fp_invalidation_count != umax && prev_rsx_count == rsx_fp_invalidation_count) + // { + // return std::forward_as_tuple(prev_fp->second, true); + // } + if (program_hash_util::fragment_program_compare()(prev_fp->first, rsx_fp)) { return std::forward_as_tuple(prev_fp->second, true); @@ -252,23 +258,19 @@ protected: if (I != m_fragment_shader_cache.end()) { prev_fp = &*I; - prev_count = invl_count; + //prev_rsx_count = rsx_fp_invalidation_count; + prev_map_count = map_invl_count; return std::forward_as_tuple(I->second, true); } - if (!force_load) - { - prev_count = umax; - return std::forward_as_tuple(__null_fragment_program, false); - } - rsx_log.trace("FP not found in buffer!"); lock.upgrade(); std::tie(it, recompile) = m_fragment_shader_cache.try_emplace(rsx_fp); new_shader = &(it->second); - prev_count = umax; - invl_count++; + prev_map_count = umax; + prev_rsx_count = umax; + map_invl_count++; } if (recompile) @@ -332,15 +334,17 @@ public: template pipeline_data_type get_graphics_pipeline( const RSXVertexProgram& vertexShader, + usz vertexShaderInvalidationCount, const RSXFragmentProgram& fragmentShader, + usz fragmentShaderInvalidationCount, pipeline_properties& pipelineProperties, bool compile_async, bool allow_notification, Args&& ...args ) { - const auto& vp_search = search_vertex_program(vertexShader); - const auto& fp_search = search_fragment_program(fragmentShader); + const auto& vp_search = search_vertex_program(vertexShader, vertexShaderInvalidationCount); + const auto& fp_search = search_fragment_program(fragmentShader, fragmentShaderInvalidationCount); const bool already_existing_fragment_program = std::get<1>(fp_search); const bool already_existing_vertex_program = std::get<1>(vp_search); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 420aa6eb8e..91efee217b 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1953,6 +1953,7 @@ namespace rsx } m_graphics_state.clear(rsx::pipeline_state::vertex_program_ucode_dirty); + vertex_program_invalidation_count++; // Reload transform constants unconditionally for now m_graphics_state |= rsx::pipeline_state::transform_constants_dirty; @@ -2010,6 +2011,7 @@ namespace rsx return; } + vertex_program_invalidation_count++; ensure(!m_graphics_state.test(rsx::pipeline_state::vertex_program_ucode_dirty)); current_vertex_program.output_mask = rsx::method_registers.vertex_attrib_output_mask(); diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 8b5f2af10d..19b40d3087 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -242,6 +242,8 @@ namespace rsx rsx::atomic_bitmask_t m_eng_interrupt_mask; rsx::bitmask_t m_graphics_state; + u64 fragment_program_invalidation_count = umax; + u64 vertex_program_invalidation_count = umax; u64 ROP_sync_timestamp = 0; program_hash_util::fragment_program_utils::fragment_program_metadata current_fp_metadata = {}; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index d37f6d62d0..2513b070eb 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1960,7 +1960,10 @@ bool VKGSRender::load_program() vk::enter_uninterruptible(); // Load current program from cache - std::tie(m_program, m_vertex_prog, m_fragment_prog) = m_prog_buffer->get_graphics_pipeline(vertex_program, fragment_program, m_pipeline_properties, + std::tie(m_program, m_vertex_prog, m_fragment_prog) = m_prog_buffer->get_graphics_pipeline( + vertex_program, vertex_program_invalidation_count, + fragment_program, fragment_program_invalidation_count, + m_pipeline_properties, shadermode != shader_mode::recompiler, true, m_pipeline_layout); vk::leave_uninterruptible(); diff --git a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h index 34cb08bae4..6483176c43 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h +++ b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h @@ -88,13 +88,13 @@ namespace vk template void add_pipeline_entry(RSXVertexProgram& vp, RSXFragmentProgram& fp, vk::pipeline_props& props, Args&& ...args) { - get_graphics_pipeline(vp, fp, props, false, false, std::forward(args)...); + get_graphics_pipeline(vp, umax, fp, umax, props, false, false, std::forward(args)...); } void preload_programs(const RSXVertexProgram& vp, const RSXFragmentProgram& fp) { - search_vertex_program(vp); - search_fragment_program(fp); + search_vertex_program(vp, umax); + search_fragment_program(fp, umax); } bool check_cache_missed() const