diff --git a/rpcs3/Emu/RSX/GL/GLDMA.cpp b/rpcs3/Emu/RSX/GL/GLDMA.cpp new file mode 100644 index 0000000000..a1373e4a83 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/GLDMA.cpp @@ -0,0 +1,120 @@ +#include "stdafx.h" +#include "GLDMA.h" + +#include "Emu/Memory/vm.h" + +namespace gl +{ + static constexpr u32 s_dma_block_size = 0x10000; + std::unordered_map> g_dma_pool; + + void dma_block::allocate(u32 base_address, u32 block_size) + { + // Since this is a userptr block, we don't need to move data around on resize. Just "claim" a different chunk and move on. + if (m_data) + { + m_data->remove(); + } + + void* userptr = vm::get_super_ptr(base_address); + + m_data = std::make_unique(); + m_data->create(buffer::target::userptr, block_size, userptr); + m_base_address = base_address; + } + + void* dma_block::map(const utils::address_range& range) const + { + ensure(range.inside(this->range())); + return vm::get_super_ptr(range.start); + } + + void dma_block::resize(u32 new_length) + { + if (new_length < length()) + { + return; + } + + allocate(m_base_address, new_length); + } + + void dma_block::set_parent(const dma_block* other) + { + ensure(this->range().inside(other->range())); + ensure(other != this); + + m_parent = other; + if (m_data) + { + m_data->remove(); + m_data.reset(); + } + } + + bool dma_block::can_map(const utils::address_range& range) const + { + if (m_parent) + { + return m_parent->can_map(range); + } + + return range.inside(this->range()); + } + + void clear_dma_resources() + { + g_dma_pool.clear(); + } + + utils::address_range to_dma_block_range(u32 start, u32 length) + { + const auto start_block_address = start & ~s_dma_block_size; + const auto end_block_address = (start + length - 1) & ~s_dma_block_size; + return utils::address_range::start_end(start_block_address, end_block_address); + } + + const dma_block& get_block(u32 start, u32 length) + { + const auto block_range = to_dma_block_range(start, length); + auto& block = g_dma_pool[block_range.start]; + if (!block) + { + block = std::make_unique(); + block->allocate(block_range.start, length); + return *block; + } + + const auto range = utils::address_range::start_length(start, length); + if (block->can_map(range)) [[ likely ]] + { + return *block; + } + + const auto owner = block->head(); + const auto new_length = (block_range.end + 1) - owner->base_addr(); + const auto search_end = (block_range.end + 1); + + // 1. Resize to new length + auto new_owner = std::make_unique(); + new_owner->allocate(owner->base_addr(), new_length); + + // 2. Acquire all the extras + for (u32 id = owner->base_addr() + s_dma_block_size; + id < search_end; + id += s_dma_block_size) + { + ensure((id % s_dma_block_size) == 0); + g_dma_pool[id]->set_parent(new_owner.get()); + } + + block = std::move(new_owner); + return *block; + } + + dma_mapping_handle map_dma(u32 guest_address, u32 length) + { + auto& block = get_block(guest_address, length); + return { guest_address - block.base_addr(), block.get() }; + } +} diff --git a/rpcs3/Emu/RSX/GL/GLDMA.h b/rpcs3/Emu/RSX/GL/GLDMA.h new file mode 100644 index 0000000000..9a1d1289fa --- /dev/null +++ b/rpcs3/Emu/RSX/GL/GLDMA.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include "Utilities/address_range.h" + +#include "glutils/buffer_object.h" + +// TODO: Unify the DMA implementation across backends as part of RSX restructuring. +namespace gl +{ + using dma_mapping_handle = std::pair; + + dma_mapping_handle map_dma(u32 guest_addr, u32 length); + void clear_dma_resources(); + + // GL does not currently support mixed block types... + class dma_block + { + public: + dma_block() = default; + + void allocate(u32 base_address, u32 block_size); + void resize(u32 new_length); + void* map(const utils::address_range& range) const; + + void set_parent(const dma_block* other); + const dma_block* head() const { return m_parent; } + bool can_map(const utils::address_range& range) const; + + u32 base_addr() const { return m_base_address; } + u32 length() const { return m_data ? static_cast(m_data->size()) : 0; } + bool empty() const { return length() == 0; } + buffer* get() const { return m_data.get(); } + utils::address_range range() const { return utils::address_range::start_length(m_base_address, length()); } + + protected: + u32 m_base_address = 0; + const dma_block* m_parent = nullptr; + std::unique_ptr m_data; + }; +} diff --git a/rpcs3/Emu/RSX/GL/glutils/buffer_object.cpp b/rpcs3/Emu/RSX/GL/glutils/buffer_object.cpp index 97f44d8790..465ace0eee 100644 --- a/rpcs3/Emu/RSX/GL/glutils/buffer_object.cpp +++ b/rpcs3/Emu/RSX/GL/glutils/buffer_object.cpp @@ -6,7 +6,7 @@ namespace gl void buffer::allocate(GLsizeiptr size, const void* data_, memory_type type, GLenum usage) { if (const auto& caps = get_driver_caps(); - caps.ARB_buffer_storage_supported) + m_target != target::userptr && caps.ARB_buffer_storage_supported) { GLenum flags = 0; if (type == memory_type::host_visible) diff --git a/rpcs3/Emu/RSX/GL/glutils/buffer_object.h b/rpcs3/Emu/RSX/GL/glutils/buffer_object.h index 75b0936325..450ce37d9e 100644 --- a/rpcs3/Emu/RSX/GL/glutils/buffer_object.h +++ b/rpcs3/Emu/RSX/GL/glutils/buffer_object.h @@ -15,7 +15,8 @@ namespace gl element_array = GL_ELEMENT_ARRAY_BUFFER, uniform = GL_UNIFORM_BUFFER, texture = GL_TEXTURE_BUFFER, - ssbo = GL_SHADER_STORAGE_BUFFER + ssbo = GL_SHADER_STORAGE_BUFFER, + userptr = GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD }; enum class access diff --git a/rpcs3/Emu/RSX/GL/glutils/capabilities.cpp b/rpcs3/Emu/RSX/GL/glutils/capabilities.cpp index 3bc9cd37f2..f19ab3332b 100644 --- a/rpcs3/Emu/RSX/GL/glutils/capabilities.cpp +++ b/rpcs3/Emu/RSX/GL/glutils/capabilities.cpp @@ -33,7 +33,7 @@ namespace gl void capabilities::initialize() { - int find_count = 16; + int find_count = 17; int ext_count = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &ext_count); @@ -164,6 +164,13 @@ namespace gl find_count--; continue; } + + if (check(ext_name, "GL_AMD_pinned_memory")) + { + AMD_pinned_memory = true; + find_count--; + continue; + } } // Set GLSL version diff --git a/rpcs3/Emu/RSX/GL/glutils/capabilities.h b/rpcs3/Emu/RSX/GL/glutils/capabilities.h index 5ef9eb0260..c6abfaf3b6 100644 --- a/rpcs3/Emu/RSX/GL/glutils/capabilities.h +++ b/rpcs3/Emu/RSX/GL/glutils/capabilities.h @@ -25,6 +25,7 @@ namespace gl bool EXT_dsa_supported = false; bool EXT_depth_bounds_test = false; + bool AMD_pinned_memory = false; bool ARB_dsa_supported = false; bool ARB_bindless_texture_supported = false; bool ARB_buffer_storage_supported = false; diff --git a/rpcs3/GLGSRender.vcxproj b/rpcs3/GLGSRender.vcxproj index 5fe3de17f5..013888ead4 100644 --- a/rpcs3/GLGSRender.vcxproj +++ b/rpcs3/GLGSRender.vcxproj @@ -52,6 +52,7 @@ + @@ -88,6 +89,7 @@ + diff --git a/rpcs3/GLGSRender.vcxproj.filters b/rpcs3/GLGSRender.vcxproj.filters index 474f50b4a9..28670f9bb5 100644 --- a/rpcs3/GLGSRender.vcxproj.filters +++ b/rpcs3/GLGSRender.vcxproj.filters @@ -47,6 +47,7 @@ upscalers\fsr1 + @@ -118,6 +119,7 @@ upscalers +