mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 08:11:51 +00:00
vk: Refactor descriptor handling
This commit is contained in:
parent
7e131f8fb6
commit
c99ef4b09f
@ -5,10 +5,7 @@
|
|||||||
|
|
||||||
namespace rsx
|
namespace rsx
|
||||||
{
|
{
|
||||||
template <typename Ty>
|
template <typename Ty> requires std::is_trivially_destructible_v<Ty>
|
||||||
concept is_simple_pod_v = (std::is_trivially_constructible_v<Ty>) && (std::is_trivially_destructible_v <Ty>);
|
|
||||||
|
|
||||||
template <typename Ty> requires is_simple_pod_v<Ty>
|
|
||||||
struct simple_array
|
struct simple_array
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -16,13 +16,13 @@ namespace vk
|
|||||||
|
|
||||||
void compute_task::init_descriptors()
|
void compute_task::init_descriptors()
|
||||||
{
|
{
|
||||||
std::vector<VkDescriptorPoolSize> descriptor_pool_sizes;
|
rsx::simple_array<VkDescriptorPoolSize> descriptor_pool_sizes;
|
||||||
std::vector<VkDescriptorSetLayoutBinding> bindings;
|
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings;
|
||||||
|
|
||||||
const auto layout = get_descriptor_layout();
|
const auto layout = get_descriptor_layout();
|
||||||
for (const auto &e : layout)
|
for (const auto &e : layout)
|
||||||
{
|
{
|
||||||
descriptor_pool_sizes.push_back({e.first, u32(VK_MAX_COMPUTE_TASKS * e.second)});
|
descriptor_pool_sizes.push_back({e.first, e.second});
|
||||||
|
|
||||||
for (unsigned n = 0; n < e.second; ++n)
|
for (unsigned n = 0; n < e.second; ++n)
|
||||||
{
|
{
|
||||||
@ -38,7 +38,7 @@ namespace vk
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reserve descriptor pools
|
// Reserve descriptor pools
|
||||||
m_descriptor_pool.create(*g_render_device, descriptor_pool_sizes.data(), ::size32(descriptor_pool_sizes), VK_MAX_COMPUTE_TASKS, 3);
|
m_descriptor_pool.create(*g_render_device, descriptor_pool_sizes);
|
||||||
m_descriptor_layout = vk::descriptors::create_layout(bindings);
|
m_descriptor_layout = vk::descriptors::create_layout(bindings);
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo layout_info = {};
|
VkPipelineLayoutCreateInfo layout_info = {};
|
||||||
@ -146,7 +146,7 @@ namespace vk
|
|||||||
|
|
||||||
ensure(m_used_descriptors < VK_MAX_COMPUTE_TASKS);
|
ensure(m_used_descriptors < VK_MAX_COMPUTE_TASKS);
|
||||||
|
|
||||||
m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout, VK_TRUE, m_used_descriptors++);
|
m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout, VK_TRUE);
|
||||||
|
|
||||||
bind_resources();
|
bind_resources();
|
||||||
|
|
||||||
|
@ -993,7 +993,6 @@ void VKGSRender::end()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate descriptor set
|
// Allocate descriptor set
|
||||||
check_descriptors();
|
|
||||||
m_current_frame->descriptor_set = allocate_descriptor_set();
|
m_current_frame->descriptor_set = allocate_descriptor_set();
|
||||||
|
|
||||||
// Load program execution environment
|
// Load program execution environment
|
||||||
|
@ -395,9 +395,9 @@ namespace
|
|||||||
std::tuple<VkPipelineLayout, VkDescriptorSetLayout> get_shared_pipeline_layout(VkDevice dev)
|
std::tuple<VkPipelineLayout, VkDescriptorSetLayout> get_shared_pipeline_layout(VkDevice dev)
|
||||||
{
|
{
|
||||||
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
|
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
|
||||||
std::vector<VkDescriptorSetLayoutBinding> bindings(binding_table.total_descriptor_bindings);
|
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings(binding_table.total_descriptor_bindings);
|
||||||
|
|
||||||
usz idx = 0;
|
u32 idx = 0;
|
||||||
|
|
||||||
// Vertex stream, one stream for cacheable data, one stream for transient data
|
// Vertex stream, one stream for cacheable data, one stream for transient data
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
@ -595,7 +595,7 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||||||
m_secondary_cb_list.create(m_secondary_command_buffer_pool, vk::command_buffer::access_type_hint::all);
|
m_secondary_cb_list.create(m_secondary_command_buffer_pool, vk::command_buffer::access_type_hint::all);
|
||||||
|
|
||||||
//Precalculated stuff
|
//Precalculated stuff
|
||||||
std::tie(pipeline_layout, descriptor_layouts) = get_shared_pipeline_layout(*m_device);
|
std::tie(m_pipeline_layout, m_descriptor_layouts) = get_shared_pipeline_layout(*m_device);
|
||||||
|
|
||||||
//Occlusion
|
//Occlusion
|
||||||
m_occlusion_query_manager = std::make_unique<vk::query_pool_manager>(*m_device, VK_QUERY_TYPE_OCCLUSION, OCCLUSION_MAX_POOL_SIZE);
|
m_occlusion_query_manager = std::make_unique<vk::query_pool_manager>(*m_device, VK_QUERY_TYPE_OCCLUSION, OCCLUSION_MAX_POOL_SIZE);
|
||||||
@ -614,13 +614,16 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||||||
const auto& binding_table = m_device->get_pipeline_binding_table();
|
const auto& binding_table = m_device->get_pipeline_binding_table();
|
||||||
const u32 num_fs_samplers = binding_table.vertex_textures_first_bind_slot - binding_table.textures_first_bind_slot;
|
const u32 num_fs_samplers = binding_table.vertex_textures_first_bind_slot - binding_table.textures_first_bind_slot;
|
||||||
|
|
||||||
std::vector<VkDescriptorPoolSize> sizes;
|
rsx::simple_array<VkDescriptorPoolSize> descriptor_type_sizes =
|
||||||
sizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 6 * max_draw_calls });
|
{
|
||||||
sizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER , 3 * max_draw_calls });
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 6 },
|
||||||
sizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , (num_fs_samplers + 4) * max_draw_calls });
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER , 3 },
|
||||||
|
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , (num_fs_samplers + 4) },
|
||||||
|
|
||||||
// Conditional rendering predicate slot; refactor to allow skipping this when not needed
|
// Conditional rendering predicate slot; refactor to allow skipping this when not needed
|
||||||
sizes.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1 * max_draw_calls });
|
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1 }
|
||||||
|
};
|
||||||
|
m_descriptor_pool.create(*m_device, descriptor_type_sizes, max_draw_calls);
|
||||||
|
|
||||||
VkSemaphoreCreateInfo semaphore_info = {};
|
VkSemaphoreCreateInfo semaphore_info = {};
|
||||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
@ -665,7 +668,6 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||||||
{
|
{
|
||||||
vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &ctx.present_wait_semaphore);
|
vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &ctx.present_wait_semaphore);
|
||||||
vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &ctx.acquire_signal_semaphore);
|
vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &ctx.acquire_signal_semaphore);
|
||||||
ctx.descriptor_pool.create(*m_device, sizes.data(), static_cast<u32>(sizes.size()), max_draw_calls, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& memory_map = m_device->get_memory_mapping();
|
const auto& memory_map = m_device->get_memory_mapping();
|
||||||
@ -920,11 +922,12 @@ VKGSRender::~VKGSRender()
|
|||||||
{
|
{
|
||||||
vkDestroySemaphore((*m_device), ctx.present_wait_semaphore, nullptr);
|
vkDestroySemaphore((*m_device), ctx.present_wait_semaphore, nullptr);
|
||||||
vkDestroySemaphore((*m_device), ctx.acquire_signal_semaphore, nullptr);
|
vkDestroySemaphore((*m_device), ctx.acquire_signal_semaphore, nullptr);
|
||||||
ctx.descriptor_pool.destroy();
|
|
||||||
|
|
||||||
ctx.buffer_views_to_clean.clear();
|
ctx.buffer_views_to_clean.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_descriptor_pool.destroy();
|
||||||
|
|
||||||
// Textures
|
// Textures
|
||||||
m_rtts.destroy();
|
m_rtts.destroy();
|
||||||
m_texture_cache.destroy();
|
m_texture_cache.destroy();
|
||||||
@ -935,8 +938,8 @@ VKGSRender::~VKGSRender()
|
|||||||
m_text_writer.reset();
|
m_text_writer.reset();
|
||||||
|
|
||||||
//Pipeline descriptors
|
//Pipeline descriptors
|
||||||
vkDestroyPipelineLayout(*m_device, pipeline_layout, nullptr);
|
vkDestroyPipelineLayout(*m_device, m_pipeline_layout, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(*m_device, descriptor_layouts, nullptr);
|
vkDestroyDescriptorSetLayout(*m_device, m_descriptor_layouts, nullptr);
|
||||||
|
|
||||||
// Queries
|
// Queries
|
||||||
m_occlusion_query_manager.reset();
|
m_occlusion_query_manager.reset();
|
||||||
@ -1318,22 +1321,11 @@ void VKGSRender::check_present_status()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKGSRender::check_descriptors()
|
|
||||||
{
|
|
||||||
// Ease resource pressure if the number of draw calls becomes too high or we are running low on memory resources
|
|
||||||
const auto required_descriptors = rsx::method_registers.current_draw_clause.pass_count();
|
|
||||||
if (!m_current_frame->descriptor_pool.can_allocate(required_descriptors, 0))
|
|
||||||
{
|
|
||||||
// Should hard sync before resetting descriptors for spec compliance
|
|
||||||
flush_command_queue(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSet VKGSRender::allocate_descriptor_set()
|
VkDescriptorSet VKGSRender::allocate_descriptor_set()
|
||||||
{
|
{
|
||||||
if (!m_shader_interpreter.is_interpreter(m_program)) [[likely]]
|
if (!m_shader_interpreter.is_interpreter(m_program)) [[likely]]
|
||||||
{
|
{
|
||||||
return m_current_frame->descriptor_pool.allocate(descriptor_layouts, VK_TRUE, 0);
|
return m_descriptor_pool.allocate(m_descriptor_layouts, VK_TRUE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1414,7 +1406,7 @@ void VKGSRender::on_init_thread()
|
|||||||
if (!m_overlay_manager)
|
if (!m_overlay_manager)
|
||||||
{
|
{
|
||||||
m_frame->hide();
|
m_frame->hide();
|
||||||
m_shaders_cache->load(nullptr, pipeline_layout);
|
m_shaders_cache->load(nullptr, m_pipeline_layout);
|
||||||
m_frame->show();
|
m_frame->show();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1422,7 +1414,7 @@ void VKGSRender::on_init_thread()
|
|||||||
rsx::shader_loading_dialog_native dlg(this);
|
rsx::shader_loading_dialog_native dlg(this);
|
||||||
|
|
||||||
// TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support
|
// TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support
|
||||||
m_shaders_cache->load(&dlg, pipeline_layout);
|
m_shaders_cache->load(&dlg, m_pipeline_layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2009,7 +2001,7 @@ bool VKGSRender::load_program()
|
|||||||
|
|
||||||
// Load current program from cache
|
// 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, fragment_program, m_pipeline_properties,
|
||||||
shadermode != shader_mode::recompiler, true, pipeline_layout);
|
shadermode != shader_mode::recompiler, true, m_pipeline_layout);
|
||||||
|
|
||||||
vk::leave_uninterruptible();
|
vk::leave_uninterruptible();
|
||||||
|
|
||||||
@ -2268,7 +2260,7 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
|
|||||||
data_size = 20;
|
data_size = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCmdPushConstants(*m_current_command_buffer, pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, data_size, draw_info);
|
vkCmdPushConstants(*m_current_command_buffer, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, data_size, draw_info);
|
||||||
|
|
||||||
const usz data_offset = (id * 128) + m_vertex_layout_stream_info.offset;
|
const usz data_offset = (id * 128) + m_vertex_layout_stream_info.offset;
|
||||||
auto dst = m_vertex_layout_ring_info.map(data_offset, 128);
|
auto dst = m_vertex_layout_ring_info.map(data_offset, 128);
|
||||||
|
@ -120,8 +120,9 @@ private:
|
|||||||
volatile vk::host_data_t* m_host_data_ptr = nullptr;
|
volatile vk::host_data_t* m_host_data_ptr = nullptr;
|
||||||
std::unique_ptr<vk::buffer> m_host_object_data;
|
std::unique_ptr<vk::buffer> m_host_object_data;
|
||||||
|
|
||||||
VkDescriptorSetLayout descriptor_layouts;
|
vk::descriptor_pool m_descriptor_pool;
|
||||||
VkPipelineLayout pipeline_layout;
|
VkDescriptorSetLayout m_descriptor_layouts;
|
||||||
|
VkPipelineLayout m_pipeline_layout;
|
||||||
|
|
||||||
vk::framebuffer_holder* m_draw_fbo = nullptr;
|
vk::framebuffer_holder* m_draw_fbo = nullptr;
|
||||||
|
|
||||||
@ -229,7 +230,6 @@ private:
|
|||||||
void check_heap_status(u32 flags = VK_HEAP_CHECK_ALL);
|
void check_heap_status(u32 flags = VK_HEAP_CHECK_ALL);
|
||||||
void check_present_status();
|
void check_present_status();
|
||||||
|
|
||||||
void check_descriptors();
|
|
||||||
VkDescriptorSet allocate_descriptor_set();
|
VkDescriptorSet allocate_descriptor_set();
|
||||||
|
|
||||||
vk::vertex_upload_info upload_vertex_data();
|
vk::vertex_upload_info upload_vertex_data();
|
||||||
|
@ -176,7 +176,6 @@ namespace vk
|
|||||||
VkSemaphore present_wait_semaphore = VK_NULL_HANDLE;
|
VkSemaphore present_wait_semaphore = VK_NULL_HANDLE;
|
||||||
|
|
||||||
vk::descriptor_set descriptor_set;
|
vk::descriptor_set descriptor_set;
|
||||||
vk::descriptor_pool descriptor_pool;
|
|
||||||
|
|
||||||
rsx::flags32_t flags = 0;
|
rsx::flags32_t flags = 0;
|
||||||
|
|
||||||
@ -185,7 +184,7 @@ namespace vk
|
|||||||
u32 present_image = -1;
|
u32 present_image = -1;
|
||||||
command_buffer_chunk* swap_command_buffer = nullptr;
|
command_buffer_chunk* swap_command_buffer = nullptr;
|
||||||
|
|
||||||
//Heap pointers
|
// Heap pointers
|
||||||
s64 attrib_heap_ptr = 0;
|
s64 attrib_heap_ptr = 0;
|
||||||
s64 vtx_env_heap_ptr = 0;
|
s64 vtx_env_heap_ptr = 0;
|
||||||
s64 frag_env_heap_ptr = 0;
|
s64 frag_env_heap_ptr = 0;
|
||||||
@ -199,14 +198,12 @@ namespace vk
|
|||||||
|
|
||||||
u64 last_frame_sync_time = 0;
|
u64 last_frame_sync_time = 0;
|
||||||
|
|
||||||
//Copy shareable information
|
// Copy shareable information
|
||||||
void grab_resources(frame_context_t& other)
|
void grab_resources(frame_context_t& other)
|
||||||
{
|
{
|
||||||
present_wait_semaphore = other.present_wait_semaphore;
|
present_wait_semaphore = other.present_wait_semaphore;
|
||||||
acquire_signal_semaphore = other.acquire_signal_semaphore;
|
acquire_signal_semaphore = other.acquire_signal_semaphore;
|
||||||
descriptor_set.swap(other.descriptor_set);
|
descriptor_set.swap(other.descriptor_set);
|
||||||
descriptor_pool = other.descriptor_pool;
|
|
||||||
used_descriptors = other.used_descriptors;
|
|
||||||
flags = other.flags;
|
flags = other.flags;
|
||||||
|
|
||||||
attrib_heap_ptr = other.attrib_heap_ptr;
|
attrib_heap_ptr = other.attrib_heap_ptr;
|
||||||
@ -221,7 +218,7 @@ namespace vk
|
|||||||
rasterizer_env_heap_ptr = other.rasterizer_env_heap_ptr;
|
rasterizer_env_heap_ptr = other.rasterizer_env_heap_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Exchange storage (non-copyable)
|
// Exchange storage (non-copyable)
|
||||||
void swap_storage(frame_context_t& other)
|
void swap_storage(frame_context_t& other)
|
||||||
{
|
{
|
||||||
std::swap(buffer_views_to_clean, other.buffer_views_to_clean);
|
std::swap(buffer_views_to_clean, other.buffer_views_to_clean);
|
||||||
|
@ -35,14 +35,6 @@ namespace vk
|
|||||||
u64 g_num_processed_frames = 0;
|
u64 g_num_processed_frames = 0;
|
||||||
u64 g_num_total_frames = 0;
|
u64 g_num_total_frames = 0;
|
||||||
|
|
||||||
void reset_compute_tasks()
|
|
||||||
{
|
|
||||||
for (const auto &p : g_compute_tasks)
|
|
||||||
{
|
|
||||||
p.second->free_resources();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_overlay_passes()
|
void reset_overlay_passes()
|
||||||
{
|
{
|
||||||
for (const auto& p : g_overlay_passes)
|
for (const auto& p : g_overlay_passes)
|
||||||
@ -53,7 +45,7 @@ namespace vk
|
|||||||
|
|
||||||
void reset_global_resources()
|
void reset_global_resources()
|
||||||
{
|
{
|
||||||
vk::reset_compute_tasks();
|
// FIXME: These two shouldn't exist
|
||||||
vk::reset_resolve_resources();
|
vk::reset_resolve_resources();
|
||||||
vk::reset_overlay_passes();
|
vk::reset_overlay_passes();
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
#include "util/fnv_hash.hpp"
|
#include "util/fnv_hash.hpp"
|
||||||
|
|
||||||
#define VK_OVERLAY_MAX_DRAW_CALLS 1024
|
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
overlay_pass::overlay_pass()
|
overlay_pass::overlay_pass()
|
||||||
@ -49,26 +47,26 @@ namespace vk
|
|||||||
|
|
||||||
void overlay_pass::init_descriptors()
|
void overlay_pass::init_descriptors()
|
||||||
{
|
{
|
||||||
std::vector<VkDescriptorPoolSize> descriptor_pool_sizes =
|
rsx::simple_array<VkDescriptorPoolSize> descriptor_pool_sizes =
|
||||||
{
|
{
|
||||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_OVERLAY_MAX_DRAW_CALLS }
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (m_num_usable_samplers)
|
if (m_num_usable_samplers)
|
||||||
{
|
{
|
||||||
descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_OVERLAY_MAX_DRAW_CALLS * m_num_usable_samplers });
|
descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_num_usable_samplers });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_num_input_attachments)
|
if (m_num_input_attachments)
|
||||||
{
|
{
|
||||||
descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_OVERLAY_MAX_DRAW_CALLS * m_num_input_attachments });
|
descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, m_num_input_attachments });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve descriptor pools
|
// Reserve descriptor pools
|
||||||
m_descriptor_pool.create(*m_device, descriptor_pool_sizes.data(), ::size32(descriptor_pool_sizes), VK_OVERLAY_MAX_DRAW_CALLS, 2);
|
m_descriptor_pool.create(*m_device, descriptor_pool_sizes);
|
||||||
|
|
||||||
const auto num_bindings = 1 + m_num_usable_samplers + m_num_input_attachments;
|
const auto num_bindings = 1 + m_num_usable_samplers + m_num_input_attachments;
|
||||||
std::vector<VkDescriptorSetLayoutBinding> bindings(num_bindings);
|
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings(num_bindings);
|
||||||
|
|
||||||
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
bindings[0].descriptorCount = 1;
|
bindings[0].descriptorCount = 1;
|
||||||
@ -222,16 +220,7 @@ namespace vk
|
|||||||
else
|
else
|
||||||
program = build_pipeline(key, pass);
|
program = build_pipeline(key, pass);
|
||||||
|
|
||||||
ensure(m_used_descriptors < VK_OVERLAY_MAX_DRAW_CALLS);
|
m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout);
|
||||||
|
|
||||||
VkDescriptorSetAllocateInfo alloc_info = {};
|
|
||||||
alloc_info.descriptorPool = m_descriptor_pool;
|
|
||||||
alloc_info.descriptorSetCount = 1;
|
|
||||||
alloc_info.pSetLayouts = &m_descriptor_layout;
|
|
||||||
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
||||||
|
|
||||||
CHECK_RESULT(vkAllocateDescriptorSets(*m_device, &alloc_info, m_descriptor_set.ptr()));
|
|
||||||
m_used_descriptors++;
|
|
||||||
|
|
||||||
if (!m_sampler && !src.empty())
|
if (!m_sampler && !src.empty())
|
||||||
{
|
{
|
||||||
@ -288,6 +277,7 @@ namespace vk
|
|||||||
|
|
||||||
void overlay_pass::free_resources()
|
void overlay_pass::free_resources()
|
||||||
{
|
{
|
||||||
|
// FIXME: Allocation sizes are known, we don't need to use a data_heap structure
|
||||||
m_vao.reset_allocation_stats();
|
m_vao.reset_allocation_stats();
|
||||||
m_ubo.reset_allocation_stats();
|
m_ubo.reset_allocation_stats();
|
||||||
}
|
}
|
||||||
|
@ -199,11 +199,6 @@ void VKGSRender::frame_context_cleanup(vk::frame_context_t *ctx)
|
|||||||
// Resource cleanup.
|
// Resource cleanup.
|
||||||
// TODO: This is some outdated crap.
|
// TODO: This is some outdated crap.
|
||||||
{
|
{
|
||||||
if (m_text_writer)
|
|
||||||
{
|
|
||||||
m_text_writer->reset_descriptors();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_overlay_manager && m_overlay_manager->has_dirty())
|
if (m_overlay_manager && m_overlay_manager->has_dirty())
|
||||||
{
|
{
|
||||||
auto ui_renderer = vk::get_overlay_pass<vk::ui_overlay_renderer>();
|
auto ui_renderer = vk::get_overlay_pass<vk::ui_overlay_renderer>();
|
||||||
|
@ -246,9 +246,6 @@ namespace vk
|
|||||||
|
|
||||||
void reset_resolve_resources()
|
void reset_resolve_resources()
|
||||||
{
|
{
|
||||||
for (auto &e : g_resolve_helpers) e.second->free_resources();
|
|
||||||
for (auto &e : g_unresolve_helpers) e.second->free_resources();
|
|
||||||
|
|
||||||
if (g_depth_resolver) g_depth_resolver->free_resources();
|
if (g_depth_resolver) g_depth_resolver->free_resources();
|
||||||
if (g_depth_unresolver) g_depth_unresolver->free_resources();
|
if (g_depth_unresolver) g_depth_unresolver->free_resources();
|
||||||
if (g_stencil_resolver) g_stencil_resolver->free_resources();
|
if (g_stencil_resolver) g_stencil_resolver->free_resources();
|
||||||
|
@ -41,6 +41,11 @@ namespace vk
|
|||||||
return &g_resource_manager;
|
return &g_resource_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
garbage_collector* get_gc()
|
||||||
|
{
|
||||||
|
return &g_resource_manager;
|
||||||
|
}
|
||||||
|
|
||||||
void resource_manager::trim()
|
void resource_manager::trim()
|
||||||
{
|
{
|
||||||
// For any managed resources, try to keep the number of unused/idle resources as low as possible.
|
// For any managed resources, try to keep the number of unused/idle resources as low as possible.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "vkutils/image.h"
|
#include "vkutils/image.h"
|
||||||
|
#include "vkutils/garbage_collector.h"
|
||||||
#include "vkutils/query_pool.hpp"
|
#include "vkutils/query_pool.hpp"
|
||||||
#include "vkutils/sampler.h"
|
#include "vkutils/sampler.h"
|
||||||
|
|
||||||
@ -16,42 +17,6 @@ namespace vk
|
|||||||
u64 last_completed_event_id();
|
u64 last_completed_event_id();
|
||||||
void on_event_completed(u64 event_id, bool flush = false);
|
void on_event_completed(u64 event_id, bool flush = false);
|
||||||
|
|
||||||
class disposable_t
|
|
||||||
{
|
|
||||||
void* ptr;
|
|
||||||
std::function<void(void*)> deleter;
|
|
||||||
|
|
||||||
disposable_t(void* ptr_, std::function<void(void*)> deleter_) :
|
|
||||||
ptr(ptr_), deleter(deleter_) {}
|
|
||||||
public:
|
|
||||||
|
|
||||||
disposable_t() = delete;
|
|
||||||
disposable_t(const disposable_t&) = delete;
|
|
||||||
|
|
||||||
disposable_t(disposable_t&& other):
|
|
||||||
ptr(std::exchange(other.ptr, nullptr)),
|
|
||||||
deleter(other.deleter)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~disposable_t()
|
|
||||||
{
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
deleter(ptr);
|
|
||||||
ptr = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static disposable_t make(T* raw)
|
|
||||||
{
|
|
||||||
return disposable_t(raw, [](void *raw)
|
|
||||||
{
|
|
||||||
delete static_cast<T*>(raw);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct eid_scope_t
|
struct eid_scope_t
|
||||||
{
|
{
|
||||||
u64 eid;
|
u64 eid;
|
||||||
@ -83,7 +48,7 @@ namespace vk
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class resource_manager
|
class resource_manager : public garbage_collector
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
sampler_pool_t m_sampler_pool;
|
sampler_pool_t m_sampler_pool;
|
||||||
@ -151,7 +116,7 @@ namespace vk
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void dispose(vk::disposable_t& disposable)
|
void dispose(vk::disposable_t& disposable) override
|
||||||
{
|
{
|
||||||
get_current_eid_scope().m_disposables.emplace_back(std::move(disposable));
|
get_current_eid_scope().m_disposables.emplace_back(std::move(disposable));
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ namespace vk
|
|||||||
std::pair<VkDescriptorSetLayout, VkPipelineLayout> shader_interpreter::create_layout(VkDevice dev)
|
std::pair<VkDescriptorSetLayout, VkPipelineLayout> shader_interpreter::create_layout(VkDevice dev)
|
||||||
{
|
{
|
||||||
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
|
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
|
||||||
std::vector<VkDescriptorSetLayoutBinding> bindings(binding_table.total_descriptor_bindings);
|
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings(binding_table.total_descriptor_bindings);
|
||||||
|
|
||||||
u32 idx = 0;
|
u32 idx = 0;
|
||||||
|
|
||||||
@ -378,13 +378,15 @@ namespace vk
|
|||||||
{
|
{
|
||||||
const auto max_draw_calls = dev.get_descriptor_max_draw_calls();
|
const auto max_draw_calls = dev.get_descriptor_max_draw_calls();
|
||||||
|
|
||||||
std::vector<VkDescriptorPoolSize> sizes;
|
rsx::simple_array<VkDescriptorPoolSize> sizes =
|
||||||
sizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 6 * max_draw_calls });
|
{
|
||||||
sizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER , 3 * max_draw_calls });
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 6 },
|
||||||
sizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 68 * max_draw_calls });
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER , 3 },
|
||||||
sizes.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3 * max_draw_calls });
|
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 68 },
|
||||||
|
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3 }
|
||||||
|
};
|
||||||
|
|
||||||
m_descriptor_pool.create(dev, sizes.data(), ::size32(sizes), max_draw_calls, 2);
|
m_descriptor_pool.create(dev, sizes, max_draw_calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shader_interpreter::init(const vk::render_device& dev)
|
void shader_interpreter::init(const vk::render_device& dev)
|
||||||
@ -518,7 +520,7 @@ namespace vk
|
|||||||
|
|
||||||
VkDescriptorSet shader_interpreter::allocate_descriptor_set()
|
VkDescriptorSet shader_interpreter::allocate_descriptor_set()
|
||||||
{
|
{
|
||||||
return m_descriptor_pool.allocate(m_shared_descriptor_layout, VK_TRUE, 0);
|
return m_descriptor_pool.allocate(m_shared_descriptor_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
glsl::program* shader_interpreter::get(const vk::pipeline_props& properties, const program_hash_util::fragment_program_utils::fragment_program_metadata& metadata)
|
glsl::program* shader_interpreter::get(const vk::pipeline_props& properties, const program_hash_util::fragment_program_utils::fragment_program_metadata& metadata)
|
||||||
|
@ -40,16 +40,16 @@ namespace vk
|
|||||||
|
|
||||||
void init_descriptor_set(vk::render_device &dev)
|
void init_descriptor_set(vk::render_device &dev)
|
||||||
{
|
{
|
||||||
VkDescriptorPoolSize descriptor_pools[1] =
|
rsx::simple_array<VkDescriptorPoolSize> descriptor_pools =
|
||||||
{
|
{
|
||||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 120 },
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reserve descriptor pools
|
// Reserve descriptor pools
|
||||||
m_descriptor_pool.create(dev, descriptor_pools, 1, 120, 2);
|
m_descriptor_pool.create(dev, descriptor_pools);
|
||||||
|
|
||||||
// Scale and offset data plus output color
|
// Scale and offset data plus output color
|
||||||
std::vector<VkDescriptorSetLayoutBinding> bindings =
|
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
.binding = 0,
|
.binding = 0,
|
||||||
@ -205,7 +205,7 @@ namespace vk
|
|||||||
{
|
{
|
||||||
ensure(m_used_descriptors < 120);
|
ensure(m_used_descriptors < 120);
|
||||||
|
|
||||||
m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout, VK_TRUE, m_used_descriptors++);
|
m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout);
|
||||||
|
|
||||||
float scale[] = { scale_x, scale_y };
|
float scale[] = { scale_x, scale_y };
|
||||||
float colors[] = { color[0], color[1], color[2], color[3] };
|
float colors[] = { color[0], color[1], color[2], color[3] };
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
#include "descriptors.h"
|
#include "descriptors.h"
|
||||||
|
#include "garbage_collector.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
@ -63,7 +64,7 @@ namespace vk
|
|||||||
g_fxo->get<dispatch_manager>().flush_all();
|
g_fxo->get<dispatch_manager>().flush_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSetLayout create_layout(const std::vector<VkDescriptorSetLayoutBinding>& bindings)
|
VkDescriptorSetLayout create_layout(const rsx::simple_array<VkDescriptorSetLayoutBinding>& bindings)
|
||||||
{
|
{
|
||||||
VkDescriptorSetLayoutCreateInfo infos = {};
|
VkDescriptorSetLayoutCreateInfo infos = {};
|
||||||
infos.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
infos.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
@ -105,65 +106,56 @@ namespace vk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void descriptor_pool::create(const vk::render_device& dev, VkDescriptorPoolSize* sizes, u32 size_descriptors_count, u32 max_sets, u8 subpool_count)
|
void descriptor_pool::create(const vk::render_device& dev, const rsx::simple_array<VkDescriptorPoolSize>& pool_sizes, u32 max_sets)
|
||||||
{
|
{
|
||||||
ensure(subpool_count);
|
ensure(max_sets > 16);
|
||||||
|
|
||||||
|
auto scaled_pool_sizes = pool_sizes;
|
||||||
|
for (auto& size : scaled_pool_sizes)
|
||||||
|
{
|
||||||
|
ensure(size.descriptorCount < 32); // Sanity check. Remove before commit.
|
||||||
|
size.descriptorCount *= max_sets;
|
||||||
|
}
|
||||||
|
|
||||||
info.flags = dev.get_descriptor_update_after_bind_support() ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT : 0;
|
info.flags = dev.get_descriptor_update_after_bind_support() ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT : 0;
|
||||||
info.maxSets = max_sets;
|
info.maxSets = max_sets;
|
||||||
info.poolSizeCount = size_descriptors_count;
|
info.poolSizeCount = scaled_pool_sizes.size();
|
||||||
info.pPoolSizes = sizes;
|
info.pPoolSizes = scaled_pool_sizes.data();
|
||||||
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
|
||||||
m_owner = &dev;
|
m_owner = &dev;
|
||||||
m_device_pools.resize(subpool_count);
|
next_subpool();
|
||||||
|
|
||||||
for (auto& pool : m_device_pools)
|
|
||||||
{
|
|
||||||
CHECK_RESULT(vkCreateDescriptorPool(dev, &info, nullptr, &pool));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_current_pool_handle = m_device_pools[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void descriptor_pool::destroy()
|
void descriptor_pool::destroy()
|
||||||
{
|
{
|
||||||
if (m_device_pools.empty()) return;
|
if (m_device_subpools.empty()) return;
|
||||||
|
|
||||||
for (auto& pool : m_device_pools)
|
for (auto& pool : m_device_subpools)
|
||||||
{
|
{
|
||||||
vkDestroyDescriptorPool((*m_owner), pool, nullptr);
|
vkDestroyDescriptorPool((*m_owner), pool.handle, nullptr);
|
||||||
pool = VK_NULL_HANDLE;
|
pool.handle = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_owner = nullptr;
|
m_owner = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void descriptor_pool::reset(VkDescriptorPoolResetFlags flags)
|
void descriptor_pool::reset(u32 subpool_id, VkDescriptorPoolResetFlags flags)
|
||||||
{
|
{
|
||||||
m_descriptor_set_cache.clear();
|
std::lock_guard lock(m_subpool_lock);
|
||||||
m_current_pool_index = (m_current_pool_index + 1) % u32(m_device_pools.size());
|
|
||||||
m_current_pool_handle = m_device_pools[m_current_pool_index];
|
CHECK_RESULT(vkResetDescriptorPool(*m_owner, m_device_subpools[subpool_id].handle, flags));
|
||||||
CHECK_RESULT(vkResetDescriptorPool(*m_owner, m_current_pool_handle, flags));
|
m_device_subpools[subpool_id].busy = VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet descriptor_pool::allocate(VkDescriptorSetLayout layout, VkBool32 use_cache, u32 used_count)
|
VkDescriptorSet descriptor_pool::allocate(VkDescriptorSetLayout layout, VkBool32 use_cache)
|
||||||
{
|
{
|
||||||
if (use_cache)
|
if (use_cache)
|
||||||
{
|
{
|
||||||
if (m_descriptor_set_cache.empty())
|
if (m_descriptor_set_cache.empty())
|
||||||
{
|
{
|
||||||
// For optimal cache utilization, each pool should only allocate one layout
|
// For optimal cache utilization, each pool should only allocate one layout
|
||||||
if (m_cached_layout != layout)
|
m_cached_layout = layout;
|
||||||
{
|
|
||||||
m_cached_layout = layout;
|
|
||||||
m_allocation_request_cache.resize(max_cache_size);
|
|
||||||
|
|
||||||
for (auto& layout_ : m_allocation_request_cache)
|
|
||||||
{
|
|
||||||
layout_ = m_cached_layout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (m_cached_layout != layout)
|
else if (m_cached_layout != layout)
|
||||||
{
|
{
|
||||||
@ -175,6 +167,11 @@ namespace vk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!can_allocate(use_cache ? 4 : 1, m_current_subpool_offset))
|
||||||
|
{
|
||||||
|
next_subpool();
|
||||||
|
}
|
||||||
|
|
||||||
VkDescriptorSet new_descriptor_set;
|
VkDescriptorSet new_descriptor_set;
|
||||||
VkDescriptorSetAllocateInfo alloc_info = {};
|
VkDescriptorSetAllocateInfo alloc_info = {};
|
||||||
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
@ -184,8 +181,12 @@ namespace vk
|
|||||||
|
|
||||||
if (use_cache)
|
if (use_cache)
|
||||||
{
|
{
|
||||||
ensure(used_count < info.maxSets);
|
const auto alloc_size = std::min<u32>(info.maxSets - m_current_subpool_offset, max_cache_size);
|
||||||
const auto alloc_size = std::min<u32>(info.maxSets - used_count, max_cache_size);
|
m_allocation_request_cache.resize(alloc_size);
|
||||||
|
for (auto& layout_ : m_allocation_request_cache)
|
||||||
|
{
|
||||||
|
layout_ = m_cached_layout;
|
||||||
|
}
|
||||||
|
|
||||||
ensure(m_descriptor_set_cache.empty());
|
ensure(m_descriptor_set_cache.empty());
|
||||||
alloc_info.descriptorSetCount = alloc_size;
|
alloc_info.descriptorSetCount = alloc_size;
|
||||||
@ -204,6 +205,51 @@ namespace vk
|
|||||||
return new_descriptor_set;
|
return new_descriptor_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void descriptor_pool::next_subpool()
|
||||||
|
{
|
||||||
|
if (m_current_subpool_index != umax)
|
||||||
|
{
|
||||||
|
// Enqueue release using gc
|
||||||
|
auto release_func = [subpool_index=m_current_subpool_index, this]()
|
||||||
|
{
|
||||||
|
this->reset(subpool_index, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto cleanup_obj = std::make_unique<gc_wrapper_t>(release_func);
|
||||||
|
vk::get_gc()->dispose(cleanup_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard lock(m_subpool_lock);
|
||||||
|
|
||||||
|
m_current_subpool_offset = 0;
|
||||||
|
m_current_subpool_index = umax;
|
||||||
|
|
||||||
|
for (u32 index = 0; index < m_device_subpools.size(); ++index)
|
||||||
|
{
|
||||||
|
if (!m_device_subpools[index].busy)
|
||||||
|
{
|
||||||
|
m_current_subpool_index = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_current_subpool_index == umax)
|
||||||
|
{
|
||||||
|
VkDescriptorPool subpool = VK_NULL_HANDLE;
|
||||||
|
CHECK_RESULT(vkCreateDescriptorPool(*m_owner, &info, nullptr, &subpool));
|
||||||
|
|
||||||
|
m_device_subpools.push_back(
|
||||||
|
{
|
||||||
|
.handle = subpool,
|
||||||
|
.busy = VK_FALSE
|
||||||
|
});
|
||||||
|
|
||||||
|
m_current_subpool_index = m_device_subpools.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device_subpools[m_current_subpool_index].busy = VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
descriptor_set::descriptor_set(VkDescriptorSet set)
|
descriptor_set::descriptor_set(VkDescriptorSet set)
|
||||||
{
|
{
|
||||||
flush();
|
flush();
|
||||||
|
@ -10,30 +10,55 @@
|
|||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
struct gc_wrapper_t
|
||||||
|
{
|
||||||
|
std::function<void()> m_callback;
|
||||||
|
|
||||||
|
gc_wrapper_t(std::function<void()> callback)
|
||||||
|
: m_callback(callback)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~gc_wrapper_t()
|
||||||
|
{
|
||||||
|
m_callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class descriptor_pool
|
class descriptor_pool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
descriptor_pool() = default;
|
descriptor_pool() = default;
|
||||||
~descriptor_pool() = default;
|
~descriptor_pool() = default;
|
||||||
|
|
||||||
void create(const vk::render_device& dev, VkDescriptorPoolSize* sizes, u32 size_descriptors_count, u32 max_sets, u8 subpool_count);
|
void create(const vk::render_device& dev, const rsx::simple_array<VkDescriptorPoolSize>& pool_sizes, u32 max_sets = 1024);
|
||||||
void destroy();
|
void destroy();
|
||||||
void reset(VkDescriptorPoolResetFlags flags);
|
|
||||||
|
|
||||||
VkDescriptorSet allocate(VkDescriptorSetLayout layout, VkBool32 use_cache, u32 used_count);
|
VkDescriptorSet allocate(VkDescriptorSetLayout layout, VkBool32 use_cache = VK_TRUE);
|
||||||
|
|
||||||
operator VkDescriptorPool() { return m_current_pool_handle; }
|
operator VkDescriptorPool() { return m_current_pool_handle; }
|
||||||
FORCE_INLINE bool valid() const { return (!m_device_pools.empty()); }
|
FORCE_INLINE bool valid() const { return (!m_device_subpools.empty()); }
|
||||||
FORCE_INLINE u32 max_sets() const { return info.maxSets; }
|
FORCE_INLINE u32 max_sets() const { return info.maxSets; }
|
||||||
FORCE_INLINE bool can_allocate(u32 required_count, u32 used_count) const { return (used_count + required_count) <= info.maxSets; };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FORCE_INLINE bool can_allocate(u32 required_count, u32 already_used_count = 0) const { return (required_count + already_used_count) <= info.maxSets; };
|
||||||
|
void reset(u32 subpool_id, VkDescriptorPoolResetFlags flags);
|
||||||
|
void next_subpool();
|
||||||
|
|
||||||
|
struct logical_subpool_t
|
||||||
|
{
|
||||||
|
VkDescriptorPool handle;
|
||||||
|
VkBool32 busy;
|
||||||
|
};
|
||||||
|
|
||||||
const vk::render_device* m_owner = nullptr;
|
const vk::render_device* m_owner = nullptr;
|
||||||
VkDescriptorPoolCreateInfo info = {};
|
VkDescriptorPoolCreateInfo info = {};
|
||||||
|
|
||||||
rsx::simple_array<VkDescriptorPool> m_device_pools;
|
rsx::simple_array<logical_subpool_t> m_device_subpools;
|
||||||
VkDescriptorPool m_current_pool_handle = VK_NULL_HANDLE;
|
VkDescriptorPool m_current_pool_handle = VK_NULL_HANDLE;
|
||||||
u32 m_current_pool_index = 0;
|
u32 m_current_subpool_index = umax;
|
||||||
|
u32 m_current_subpool_offset = 0;
|
||||||
|
|
||||||
|
shared_mutex m_subpool_lock;
|
||||||
|
|
||||||
static constexpr size_t max_cache_size = 64;
|
static constexpr size_t max_cache_size = 64;
|
||||||
VkDescriptorSetLayout m_cached_layout = VK_NULL_HANDLE;
|
VkDescriptorSetLayout m_cached_layout = VK_NULL_HANDLE;
|
||||||
@ -122,6 +147,6 @@ namespace vk
|
|||||||
void init();
|
void init();
|
||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
VkDescriptorSetLayout create_layout(const std::vector<VkDescriptorSetLayoutBinding>& bindings);
|
VkDescriptorSetLayout create_layout(const rsx::simple_array<VkDescriptorSetLayoutBinding>& bindings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
rpcs3/Emu/RSX/VK/vkutils/garbage_collector.h
Normal file
56
rpcs3/Emu/RSX/VK/vkutils/garbage_collector.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include <util/types.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
class disposable_t
|
||||||
|
{
|
||||||
|
void* ptr;
|
||||||
|
std::function<void(void*)> deleter;
|
||||||
|
|
||||||
|
disposable_t(void* ptr_, std::function<void(void*)> deleter_) :
|
||||||
|
ptr(ptr_), deleter(deleter_) {}
|
||||||
|
public:
|
||||||
|
|
||||||
|
disposable_t() = delete;
|
||||||
|
disposable_t(const disposable_t&) = delete;
|
||||||
|
|
||||||
|
disposable_t(disposable_t&& other) :
|
||||||
|
ptr(std::exchange(other.ptr, nullptr)),
|
||||||
|
deleter(other.deleter)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~disposable_t()
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
deleter(ptr);
|
||||||
|
ptr = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static disposable_t make(T* raw)
|
||||||
|
{
|
||||||
|
return disposable_t(raw, [](void* raw)
|
||||||
|
{
|
||||||
|
delete static_cast<T*>(raw);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct garbage_collector
|
||||||
|
{
|
||||||
|
virtual void dispose(vk::disposable_t& object) = 0;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void dispose(std::unique_ptr<T>& object)
|
||||||
|
{
|
||||||
|
auto ptr = vk::disposable_t::make(object.release());
|
||||||
|
dispose(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
garbage_collector* get_gc();
|
||||||
|
}
|
@ -45,6 +45,7 @@
|
|||||||
<ClInclude Include="Emu\RSX\VK\vkutils\descriptors.h" />
|
<ClInclude Include="Emu\RSX\VK\vkutils\descriptors.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\vkutils\barriers.h" />
|
<ClInclude Include="Emu\RSX\VK\vkutils\barriers.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\vkutils\framebuffer_object.hpp" />
|
<ClInclude Include="Emu\RSX\VK\vkutils\framebuffer_object.hpp" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\vkutils\garbage_collector.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\vkutils\image.h" />
|
<ClInclude Include="Emu\RSX\VK\vkutils\image.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\vkutils\image_helpers.h" />
|
<ClInclude Include="Emu\RSX\VK\vkutils\image_helpers.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\vkutils\scratch.h" />
|
<ClInclude Include="Emu\RSX\VK\vkutils\scratch.h" />
|
||||||
|
@ -171,6 +171,9 @@
|
|||||||
<ClInclude Include="Emu\RSX\VK\upscalers\nearest_pass.hpp">
|
<ClInclude Include="Emu\RSX\VK\upscalers\nearest_pass.hpp">
|
||||||
<Filter>upscalers</Filter>
|
<Filter>upscalers</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\vkutils\garbage_collector.h">
|
||||||
|
<Filter>vkutils</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="vkutils">
|
<Filter Include="vkutils">
|
||||||
|
Loading…
Reference in New Issue
Block a user