rsx: Fix dynamic constants patching when draw call is skipped

- Also adds an optimization to skip reuploads when patch occurs outside our critical range.
This commit is contained in:
kd-11 2025-01-11 21:02:13 +03:00
parent 912388cc6a
commit 58b55d7576
5 changed files with 49 additions and 7 deletions

View file

@ -790,7 +790,7 @@ namespace rsx
const int translated_offset = full_reupload
? instance_config.patch_load_offset
: prog->TranslateConstantsRange(instance_config.patch_load_offset, instance_config.patch_load_count);
: prog->translate_constants_range(instance_config.patch_load_offset, instance_config.patch_load_count);
if (translated_offset >= 0)
{

View file

@ -1045,13 +1045,19 @@ void GLGSRender::update_vertex_env(const gl::vertex_upload_info& upload_info)
void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 count)
{
if (!m_vertex_prog)
if (!m_program || !m_vertex_prog)
{
// Shouldn't be reachable, but handle it correctly anyway
m_graphics_state |= rsx::pipeline_state::transform_constants_dirty;
return;
}
if (!m_vertex_prog->overlaps_constants_range(index, count))
{
// Nothing meaningful to us
return;
}
std::pair<u32, u32> data_range {};
void* data_source = nullptr;
const auto bound_range = m_transform_constants_buffer->bound_range();
@ -1065,7 +1071,7 @@ void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
data_range = { bound_range.first + byte_offset, byte_count};
data_source = &REGS(ctx)->transform_constants[index];
}
else if (auto xform_id = m_vertex_prog->TranslateConstantsRange(index, count); xform_id >= 0)
else if (auto xform_id = m_vertex_prog->translate_constants_range(index, count); xform_id >= 0)
{
const auto write_offset = xform_id * 16;
const auto byte_count = count * 16;

View file

@ -110,7 +110,7 @@ namespace rsx
multisampled_textures == other.multisampled_textures;
}
int VertexProgramBase::TranslateConstantsRange(int first_index, int count) const
int VertexProgramBase::translate_constants_range(int first_index, int count) const
{
// The constant ids should be sorted, so just find the first one and check for continuity
int index = -1;
@ -157,4 +157,31 @@ namespace rsx
// OOB or partial match
return -1;
}
bool VertexProgramBase::overlaps_constants_range(int first_index, int count) const
{
if (has_indexed_constants)
{
return true;
}
const int last_index = first_index + count - 1;
// Early rejection test
if (constant_ids.empty() || first_index > constant_ids.back() || last_index < first_index)
{
return false;
}
// Check for any hits
for (auto& idx : constant_ids)
{
if (idx >= first_index && idx <= last_index)
{
return true;
}
}
return false;
}
}

View file

@ -67,6 +67,9 @@ namespace rsx
// Translates an incoming range of constants against our mapping.
// If there is no linear mapping available, return -1, otherwise returns the translated index of the first slot
// TODO: Move this somewhere else during refactor
int TranslateConstantsRange(int first_index, int count) const;
int translate_constants_range(int first_index, int count) const;
// Returns true if this program consumes any constants in the range [first, first + count - 1]
bool overlaps_constants_range(int first_index, int count) const;
};
}

View file

@ -2443,13 +2443,19 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
void VKGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 count)
{
if (!m_vertex_prog)
if (!m_program || !m_vertex_prog)
{
// Shouldn't be reachable, but handle it correctly anyway
m_graphics_state |= rsx::pipeline_state::transform_constants_dirty;
return;
}
if (!m_vertex_prog->overlaps_constants_range(index, count))
{
// Nothing meaningful to us
return;
}
// Hot-patching transform constants mid-draw (instanced draw)
std::pair<VkDeviceSize, VkDeviceSize> data_range;
void* data_source = nullptr;
@ -2463,7 +2469,7 @@ void VKGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
data_range = { m_vertex_constants_buffer_info.offset + byte_offset, byte_count };
data_source = &REGS(ctx)->transform_constants[index];
}
else if (auto xform_id = m_vertex_prog->TranslateConstantsRange(index, count); xform_id >= 0)
else if (auto xform_id = m_vertex_prog->translate_constants_range(index, count); xform_id >= 0)
{
const auto write_offset = xform_id * 16;
const auto byte_count = count * 16;