rsx: Fix graphics corruption when switching between shader interpreter and recompiler at runtime

This commit is contained in:
kd-11 2025-02-02 02:12:23 +03:00
parent 911f0928cf
commit 611c77e724
4 changed files with 62 additions and 11 deletions

View file

@ -694,6 +694,7 @@ void GLGSRender::begin()
if (m_graphics_state & rsx::pipeline_state::invalidate_pipeline_bits)
{
// Shaders need to be reloaded.
m_prev_program = m_program;
m_program = nullptr;
}
}

View file

@ -767,7 +767,6 @@ bool GLGSRender::load_program()
}
}
const bool was_interpreter = m_shader_interpreter.is_interpreter(m_program);
m_vertex_prog = nullptr;
m_fragment_prog = nullptr;
@ -796,15 +795,32 @@ bool GLGSRender::load_program()
m_program = nullptr;
}
if (!m_program && (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only))
if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only)
{
// Fall back to interpreter
m_program = m_shader_interpreter.get(current_fp_metadata);
if (was_interpreter != m_shader_interpreter.is_interpreter(m_program))
const bool is_interpreter = !m_program;
const bool was_interpreter = m_shader_interpreter.is_interpreter(m_prev_program);
// First load the next program if not available
if (!m_program)
{
m_program = m_shader_interpreter.get(current_fp_metadata);
// Program has changed, reupload
m_interpreter_state = rsx::invalidate_pipeline_bits;
}
// If swapping between interpreter and recompiler, we need to adjust some flags to reupload data as needed.
if (is_interpreter != was_interpreter)
{
// Always reupload transform constants when going between interpreter and recompiler
m_graphics_state |= rsx::transform_constants_dirty;
// Always reload fragment constansts when moving from interpreter back to recompiler.
if (was_interpreter)
{
m_graphics_state |= rsx::fragment_constants_dirty;
}
}
}
return m_program != nullptr;
@ -989,6 +1005,11 @@ void GLGSRender::load_program_env()
handled_flags |= rsx::pipeline_state::fragment_constants_dirty;
}
if (m_shader_interpreter.is_interpreter(m_program))
{
ensure(m_transform_constants_buffer->bound_range().second >= 468 * 16);
}
m_graphics_state.clear(handled_flags);
}
@ -999,7 +1020,9 @@ bool GLGSRender::is_current_program_interpreted() const
void GLGSRender::upload_transform_constants(const rsx::io_buffer& buffer)
{
const usz transform_constants_size = (!m_vertex_prog || m_vertex_prog->has_indexed_constants) ? 8192 : m_vertex_prog->constant_ids.size() * 16;
const bool is_interpreter = m_shader_interpreter.is_interpreter(m_program);
const usz transform_constants_size = (is_interpreter || m_vertex_prog->has_indexed_constants) ? 8192 : m_vertex_prog->constant_ids.size() * 16;
if (transform_constants_size)
{
const auto constant_ids = (transform_constants_size == 8192)

View file

@ -78,6 +78,7 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
gl::sampler_state m_vs_sampler_states[rsx::limits::vertex_textures_count]; // Vertex textures
gl::glsl::program *m_program = nullptr;
gl::glsl::program* m_prev_program = nullptr;
const GLFragmentProgram *m_fragment_prog = nullptr;
const GLVertexProgram *m_vertex_prog = nullptr;

View file

@ -1982,14 +1982,32 @@ bool VKGSRender::load_program()
m_program = nullptr;
}
if (!m_program && (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only))
if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only)
{
if (!m_shader_interpreter.is_interpreter(m_prev_program))
const bool is_interpreter = !m_program;
const bool was_interpreter = m_shader_interpreter.is_interpreter(m_prev_program);
// First load the next program if not available
if (!m_program)
{
m_program = m_shader_interpreter.get(m_pipeline_properties, current_fp_metadata);
// Program has changed, reupload
m_interpreter_state = rsx::invalidate_pipeline_bits;
}
m_program = m_shader_interpreter.get(m_pipeline_properties, current_fp_metadata);
// If swapping between interpreter and recompiler, we need to adjust some flags to reupload data as needed.
if (is_interpreter != was_interpreter)
{
// Always reupload transform constants when going between interpreter and recompiler
m_graphics_state |= rsx::transform_constants_dirty;
// Always reload fragment constansts when moving from interpreter back to recompiler.
if (was_interpreter)
{
m_graphics_state |= rsx::fragment_constants_dirty;
}
}
}
return m_program != nullptr;
@ -2051,7 +2069,8 @@ void VKGSRender::load_program_env()
return std::make_pair(m_instancing_buffer_ring_info.map(constants_data_table_offset, size), size);
});
m_draw_processor.fill_constants_instancing_buffer(indirection_table_buf, constants_array_buf, m_vertex_prog);
const auto bound_vertex_prog = m_shader_interpreter.is_interpreter(m_program) ? nullptr : m_vertex_prog;
m_draw_processor.fill_constants_instancing_buffer(indirection_table_buf, constants_array_buf, bound_vertex_prog);
m_instancing_buffer_ring_info.unmap();
m_instancing_indirection_buffer_info = { m_instancing_buffer_ring_info.heap->value, indirection_table_offset, indirection_table_buf.size() };
@ -2224,6 +2243,11 @@ void VKGSRender::load_program_env()
handled_flags |= rsx::pipeline_state::fragment_constants_dirty;
}
if (m_shader_interpreter.is_interpreter(m_program))
{
ensure(m_vertex_constants_buffer_info.range >= 468 * 16);
}
m_graphics_state.clear(handled_flags);
}
@ -2234,7 +2258,9 @@ bool VKGSRender::is_current_program_interpreted() const
void VKGSRender::upload_transform_constants(const rsx::io_buffer& buffer)
{
const usz transform_constants_size = (!m_vertex_prog || m_vertex_prog->has_indexed_constants) ? 8192 : m_vertex_prog->constant_ids.size() * 16;
const bool is_interpreter = m_shader_interpreter.is_interpreter(m_program);
const usz transform_constants_size = (is_interpreter || m_vertex_prog->has_indexed_constants) ? 8192 : m_vertex_prog->constant_ids.size() * 16;
if (transform_constants_size)
{
check_heap_status(VK_HEAP_CHECK_TRANSFORM_CONSTANTS_STORAGE);