RSX: Return VP shader as is if no changes were made

This commit is contained in:
Elad 2025-03-05 13:51:49 +02:00
parent ae39c5b8cb
commit 75dc2a12e2
7 changed files with 51 additions and 37 deletions

View file

@ -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())

View file

@ -135,13 +135,13 @@ struct GLProgramBuffer : public program_state_cache<GLTraits>
template <typename... Args>
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>(args)...);
get_graphics_pipeline(vp, umax, fp, umax, props, false, false, std::forward<Args>(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

View file

@ -167,24 +167,30 @@ protected:
pipeline_storage_type __null_pipeline_handle;
/// bool here to inform that the program was preexisting.
std::tuple<const vertex_program_type&, bool> search_vertex_program(const RSXVertexProgram& rsx_vp, bool force_load = true)
std::tuple<const vertex_program_type&, bool> 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<const RSXVertexProgram, vertex_program_type>* prev_vp = nullptr;
thread_local usz prev_count = umax;
static atomic_t<usz> invl_count = 0;
thread_local usz prev_map_count = umax, prev_rsx_count = umax;
static atomic_t<usz> 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<const fragment_program_type&, bool> search_fragment_program(const RSXFragmentProgram& rsx_fp, bool force_load = true)
std::tuple<const fragment_program_type&, bool> 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<const RSXFragmentProgram, fragment_program_type>* prev_fp = nullptr;
thread_local usz prev_count = umax;
static atomic_t<usz> invl_count = 0;
thread_local usz prev_map_count = umax, prev_rsx_count = umax;
static atomic_t<usz> 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<typename... Args>
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);

View file

@ -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();

View file

@ -242,6 +242,8 @@ namespace rsx
rsx::atomic_bitmask_t<rsx::eng_interrupt_reason> m_eng_interrupt_mask;
rsx::bitmask_t<rsx::pipeline_state> 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 = {};

View file

@ -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();

View file

@ -88,13 +88,13 @@ namespace vk
template <typename... Args>
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>(args)...);
get_graphics_pipeline(vp, umax, fp, umax, props, false, false, std::forward<Args>(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