mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
gl: Implement transform constants patching
This commit is contained in:
parent
4cf7b7022e
commit
cc313bfba1
@ -3,8 +3,10 @@
|
|||||||
#include "../Overlays/Shaders/shader_loading_dialog_native.h"
|
#include "../Overlays/Shaders/shader_loading_dialog_native.h"
|
||||||
#include "GLGSRender.h"
|
#include "GLGSRender.h"
|
||||||
#include "GLCompute.h"
|
#include "GLCompute.h"
|
||||||
|
|
||||||
#include "Emu/Memory/vm_locking.h"
|
#include "Emu/Memory/vm_locking.h"
|
||||||
#include "Emu/RSX/rsx_methods.h"
|
#include "Emu/RSX/rsx_methods.h"
|
||||||
|
#include "Emu/RSX/NV47/HW/context_accessors.define.h"
|
||||||
|
|
||||||
#include "../Program/program_state_cache2.hpp"
|
#include "../Program/program_state_cache2.hpp"
|
||||||
|
|
||||||
@ -263,6 +265,7 @@ void GLGSRender::on_init_thread()
|
|||||||
m_vertex_instructions_buffer = std::make_unique<gl::legacy_ring_buffer>();
|
m_vertex_instructions_buffer = std::make_unique<gl::legacy_ring_buffer>();
|
||||||
m_fragment_instructions_buffer = std::make_unique<gl::legacy_ring_buffer>();
|
m_fragment_instructions_buffer = std::make_unique<gl::legacy_ring_buffer>();
|
||||||
m_raster_env_ring_buffer = std::make_unique<gl::legacy_ring_buffer>();
|
m_raster_env_ring_buffer = std::make_unique<gl::legacy_ring_buffer>();
|
||||||
|
m_scratch_ring_buffer = std::make_unique<gl::legacy_ring_buffer>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -277,6 +280,7 @@ void GLGSRender::on_init_thread()
|
|||||||
m_vertex_instructions_buffer = std::make_unique<gl::ring_buffer>();
|
m_vertex_instructions_buffer = std::make_unique<gl::ring_buffer>();
|
||||||
m_fragment_instructions_buffer = std::make_unique<gl::ring_buffer>();
|
m_fragment_instructions_buffer = std::make_unique<gl::ring_buffer>();
|
||||||
m_raster_env_ring_buffer = std::make_unique<gl::ring_buffer>();
|
m_raster_env_ring_buffer = std::make_unique<gl::ring_buffer>();
|
||||||
|
m_scratch_ring_buffer = std::make_unique<gl::ring_buffer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_attrib_ring_buffer->create(gl::buffer::target::texture, 256 * 0x100000);
|
m_attrib_ring_buffer->create(gl::buffer::target::texture, 256 * 0x100000);
|
||||||
@ -288,6 +292,7 @@ void GLGSRender::on_init_thread()
|
|||||||
m_texture_parameters_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
m_texture_parameters_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||||
m_vertex_layout_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
m_vertex_layout_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||||
m_raster_env_ring_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
m_raster_env_ring_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||||
|
m_scratch_ring_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||||
|
|
||||||
if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only)
|
if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only)
|
||||||
{
|
{
|
||||||
@ -501,6 +506,11 @@ void GLGSRender::on_exit()
|
|||||||
m_raster_env_ring_buffer->remove();
|
m_raster_env_ring_buffer->remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_scratch_ring_buffer)
|
||||||
|
{
|
||||||
|
m_scratch_ring_buffer->remove();
|
||||||
|
}
|
||||||
|
|
||||||
m_null_textures.clear();
|
m_null_textures.clear();
|
||||||
m_gl_texture_cache.destroy();
|
m_gl_texture_cache.destroy();
|
||||||
m_ui_renderer.destroy();
|
m_ui_renderer.destroy();
|
||||||
@ -823,18 +833,20 @@ void GLGSRender::load_program_env()
|
|||||||
if (update_transform_constants)
|
if (update_transform_constants)
|
||||||
{
|
{
|
||||||
// Vertex constants
|
// Vertex constants
|
||||||
const usz transform_constants_size = (!m_vertex_prog || m_vertex_prog->has_indexed_constants) ? 8192 : m_vertex_prog->constant_ids.size() * 16;
|
u32 mem_offset = 0;
|
||||||
if (transform_constants_size)
|
auto mem_alloc = [&](usz size) -> std::pair<void*, usz>
|
||||||
{
|
{
|
||||||
auto mapping = m_transform_constants_buffer->alloc_from_heap(static_cast<u32>(transform_constants_size), m_uniform_buffer_offset_align);
|
const auto mapping = m_transform_constants_buffer->alloc_from_heap(static_cast<u32>(size), m_uniform_buffer_offset_align);
|
||||||
auto buf = static_cast<u8*>(mapping.first);
|
mem_offset = mapping.second;
|
||||||
|
return { mapping.first, size };
|
||||||
|
};
|
||||||
|
|
||||||
const auto constant_ids = (transform_constants_size == 8192)
|
rsx::io_buffer io_buf(mem_alloc);
|
||||||
? std::span<const u16>{}
|
upload_transform_constants(io_buf);
|
||||||
: std::span<const u16>(m_vertex_prog->constant_ids);
|
|
||||||
fill_vertex_program_constants_data(buf, constant_ids);
|
|
||||||
|
|
||||||
m_transform_constants_buffer->bind_range(GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT, mapping.second, static_cast<u32>(transform_constants_size));
|
if (!io_buf.empty())
|
||||||
|
{
|
||||||
|
m_transform_constants_buffer->bind_range(GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT, mem_offset, ::size32(io_buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -946,6 +958,20 @@ void GLGSRender::load_program_env()
|
|||||||
rsx::pipeline_state::fragment_texture_state_dirty);
|
rsx::pipeline_state::fragment_texture_state_dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (transform_constants_size)
|
||||||
|
{
|
||||||
|
const auto constant_ids = (transform_constants_size == 8192)
|
||||||
|
? std::span<const u16>{}
|
||||||
|
: std::span<const u16>(m_vertex_prog->constant_ids);
|
||||||
|
|
||||||
|
buffer.reserve(transform_constants_size);
|
||||||
|
fill_vertex_program_constants_data(buffer.data(), constant_ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GLGSRender::update_vertex_env(const gl::vertex_upload_info& upload_info)
|
void GLGSRender::update_vertex_env(const gl::vertex_upload_info& upload_info)
|
||||||
{
|
{
|
||||||
if (manually_flush_ring_buffers)
|
if (manually_flush_ring_buffers)
|
||||||
@ -971,11 +997,60 @@ void GLGSRender::update_vertex_env(const gl::vertex_upload_info& upload_info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 count)
|
||||||
|
{
|
||||||
|
std::pair<u32, u32> data_range {};
|
||||||
|
void* data_source = nullptr;
|
||||||
|
const auto bound_range = m_transform_constants_buffer->bound_range();
|
||||||
|
|
||||||
|
if (!m_vertex_prog || m_vertex_prog->has_indexed_constants)
|
||||||
|
{
|
||||||
|
// We're working with a full range. We can do a direct patch in this case since no index translation is required.
|
||||||
|
const auto byte_count = count * 16;
|
||||||
|
const auto byte_offset = index * 16;
|
||||||
|
|
||||||
|
data_range = { bound_range.first + byte_offset, byte_count};
|
||||||
|
data_source = ®S(ctx)->transform_constants[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto allocate_mem = [&](usz size) -> std::pair<void*, usz>
|
||||||
|
{
|
||||||
|
m_scratch_buffer.resize(size);
|
||||||
|
return { m_scratch_buffer.data(), size };
|
||||||
|
};
|
||||||
|
|
||||||
|
rsx::io_buffer iobuf(allocate_mem);
|
||||||
|
upload_transform_constants(iobuf);
|
||||||
|
|
||||||
|
data_range = { bound_range.first, ::size32(iobuf) };
|
||||||
|
data_source = iobuf.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move data to memory that the GPU can work with
|
||||||
|
if (manually_flush_ring_buffers)
|
||||||
|
{
|
||||||
|
m_scratch_ring_buffer->reserve_storage_on_heap(data_range.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mapping = m_scratch_ring_buffer->alloc_from_heap(data_range.second, 16);
|
||||||
|
std::memcpy(mapping.first, data_source, data_range.second);
|
||||||
|
|
||||||
|
if (manually_flush_ring_buffers)
|
||||||
|
{
|
||||||
|
m_scratch_ring_buffer->unmap();
|
||||||
|
}
|
||||||
|
m_scratch_ring_buffer->notify();
|
||||||
|
|
||||||
|
// Do the transfer to patch the constants on the host device
|
||||||
|
m_scratch_ring_buffer->copy_to(m_transform_constants_buffer.get(), mapping.second, data_range.first, data_range.second);
|
||||||
|
}
|
||||||
|
|
||||||
bool GLGSRender::on_access_violation(u32 address, bool is_writing)
|
bool GLGSRender::on_access_violation(u32 address, bool is_writing)
|
||||||
{
|
{
|
||||||
const bool can_flush = is_current_thread();
|
const bool can_flush = is_current_thread();
|
||||||
const rsx::invalidation_cause cause =
|
const rsx::invalidation_cause cause = is_writing
|
||||||
is_writing ? (can_flush ? rsx::invalidation_cause::write : rsx::invalidation_cause::deferred_write)
|
? (can_flush ? rsx::invalidation_cause::write : rsx::invalidation_cause::deferred_write)
|
||||||
: (can_flush ? rsx::invalidation_cause::read : rsx::invalidation_cause::deferred_read);
|
: (can_flush ? rsx::invalidation_cause::read : rsx::invalidation_cause::deferred_read);
|
||||||
|
|
||||||
auto cmd = can_flush ? gl::command_context{ gl_state } : gl::command_context{};
|
auto cmd = can_flush ? gl::command_context{ gl_state } : gl::command_context{};
|
||||||
|
@ -108,6 +108,9 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
|
|||||||
// Identity buffer used to fix broken gl_VertexID on ATI stack
|
// Identity buffer used to fix broken gl_VertexID on ATI stack
|
||||||
std::unique_ptr<gl::buffer> m_identity_index_buffer;
|
std::unique_ptr<gl::buffer> m_identity_index_buffer;
|
||||||
|
|
||||||
|
// Used for hot-patching
|
||||||
|
std::unique_ptr<gl::ring_buffer> m_scratch_ring_buffer;
|
||||||
|
|
||||||
std::unique_ptr<gl::vertex_cache> m_vertex_cache;
|
std::unique_ptr<gl::vertex_cache> m_vertex_cache;
|
||||||
std::unique_ptr<gl::shader_cache> m_shaders_cache;
|
std::unique_ptr<gl::shader_cache> m_shaders_cache;
|
||||||
|
|
||||||
@ -142,7 +145,7 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
|
|||||||
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count> fs_sampler_state = {};
|
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count> fs_sampler_state = {};
|
||||||
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::vertex_textures_count> vs_sampler_state = {};
|
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::vertex_textures_count> vs_sampler_state = {};
|
||||||
std::unordered_map<GLenum, std::unique_ptr<gl::texture>> m_null_textures;
|
std::unordered_map<GLenum, std::unique_ptr<gl::texture>> m_null_textures;
|
||||||
std::vector<u8> m_scratch_buffer;
|
rsx::simple_array<u8> m_scratch_buffer;
|
||||||
|
|
||||||
// Occlusion query type, can be SAMPLES_PASSED or ANY_SAMPLES_PASSED
|
// Occlusion query type, can be SAMPLES_PASSED or ANY_SAMPLES_PASSED
|
||||||
GLenum m_occlusion_type = GL_ANY_SAMPLES_PASSED;
|
GLenum m_occlusion_type = GL_ANY_SAMPLES_PASSED;
|
||||||
@ -166,6 +169,7 @@ private:
|
|||||||
bool load_program();
|
bool load_program();
|
||||||
void load_program_env();
|
void load_program_env();
|
||||||
void update_vertex_env(const gl::vertex_upload_info& upload_info);
|
void update_vertex_env(const gl::vertex_upload_info& upload_info);
|
||||||
|
void upload_transform_constants(const rsx::io_buffer& buffer);
|
||||||
|
|
||||||
void update_draw_state();
|
void update_draw_state();
|
||||||
|
|
||||||
@ -182,12 +186,16 @@ public:
|
|||||||
|
|
||||||
bool scaled_image_from_memory(const rsx::blit_src_info& src_info, const rsx::blit_dst_info& dst_info, bool interpolate) override;
|
bool scaled_image_from_memory(const rsx::blit_src_info& src_info, const rsx::blit_dst_info& dst_info, bool interpolate) override;
|
||||||
|
|
||||||
|
// ZCULL
|
||||||
void begin_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
void begin_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
||||||
void end_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
void end_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
||||||
bool check_occlusion_query_status(rsx::reports::occlusion_query_info* query) override;
|
bool check_occlusion_query_status(rsx::reports::occlusion_query_info* query) override;
|
||||||
void get_occlusion_query_result(rsx::reports::occlusion_query_info* query) override;
|
void get_occlusion_query_result(rsx::reports::occlusion_query_info* query) override;
|
||||||
void discard_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
void discard_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
||||||
|
|
||||||
|
// GRAPH backend
|
||||||
|
void patch_transform_constants(rsx::context* ctx, u32 index, u32 count) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void clear_surface(u32 arg) override;
|
void clear_surface(u32 arg) override;
|
||||||
void begin() override;
|
void begin() override;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user