vk: Implement basic descriptor updates batching

This commit is contained in:
kd-11 2021-09-23 01:29:23 +03:00 committed by kd-11
parent 24642a4c18
commit 4752c4014b
13 changed files with 237 additions and 56 deletions

View File

@ -162,13 +162,13 @@ namespace vk
alloc_info.pSetLayouts = &m_descriptor_layout;
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
CHECK_RESULT(vkAllocateDescriptorSets(*g_render_device, &alloc_info, &m_descriptor_set));
CHECK_RESULT(vkAllocateDescriptorSets(*g_render_device, &alloc_info, m_descriptor_set.ptr()));
m_used_descriptors++;
bind_resources();
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_program->pipeline);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline_layout, 0, 1, &m_descriptor_set, 0, nullptr);
m_descriptor_set.bind(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline_layout);
}
void compute_task::run(VkCommandBuffer cmd, u32 invocations_x, u32 invocations_y, u32 invocations_z)

View File

@ -20,7 +20,7 @@ namespace vk
std::unique_ptr<vk::buffer> m_param_buffer;
vk::descriptor_pool m_descriptor_pool;
VkDescriptorSet m_descriptor_set = nullptr;
descriptor_set m_descriptor_set;
VkDescriptorSetLayout m_descriptor_layout = nullptr;
VkPipelineLayout m_pipeline_layout = nullptr;
u32 m_used_descriptors = 0;

View File

@ -791,28 +791,27 @@ void VKGSRender::emit_geometry(u32 sub_index)
else if (persistent_buffer != old_persistent_buffer || volatile_buffer != old_volatile_buffer)
{
// Need to update descriptors; make a copy for the next draw
VkDescriptorSet new_descriptor_set = allocate_descriptor_set();
std::vector<VkCopyDescriptorSet> copy_set(binding_table.total_descriptor_bindings);
VkDescriptorSet previous_set = m_current_frame->descriptor_set.value();
m_current_frame->descriptor_set = allocate_descriptor_set();
std::vector<VkCopyDescriptorSet> copy_cmds(binding_table.total_descriptor_bindings);
for (u32 n = 0; n < binding_table.total_descriptor_bindings; ++n)
{
copy_set[n] =
copy_cmds[n] =
{
VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET, // sType
nullptr, // pNext
m_current_frame->descriptor_set, // srcSet
previous_set, // srcSet
n, // srcBinding
0u, // srcArrayElement
new_descriptor_set, // dstSet
m_current_frame->descriptor_set.value(), // dstSet
n, // dstBinding
0u, // dstArrayElement
1u // descriptorCount
};
}
vkUpdateDescriptorSets(*m_device, 0, 0, binding_table.total_descriptor_bindings, copy_set.data());
m_current_frame->descriptor_set = new_descriptor_set;
m_current_frame->descriptor_set.push(copy_cmds);
update_descriptors = true;
}
@ -866,8 +865,7 @@ void VKGSRender::emit_geometry(u32 sub_index)
}
// Bind the new set of descriptors for use with this draw call
vkCmdBindDescriptorSets(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline_layout, 0, 1, &m_current_frame->descriptor_set, 0, nullptr);
m_current_frame->descriptor_set.bind(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline_layout);
m_frame_stats.setup_time += m_profiler.duration();
if (!upload_info.index_info)

View File

@ -196,8 +196,8 @@ namespace vk
{
VkSemaphore acquire_signal_semaphore = VK_NULL_HANDLE;
VkSemaphore present_wait_semaphore = VK_NULL_HANDLE;
VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
vk::descriptor_set descriptor_set;
vk::descriptor_pool descriptor_pool;
u32 used_descriptors = 0;
@ -227,7 +227,7 @@ namespace vk
{
present_wait_semaphore = other.present_wait_semaphore;
acquire_signal_semaphore = other.acquire_signal_semaphore;
descriptor_set = other.descriptor_set;
descriptor_set.swap(other.descriptor_set);
descriptor_pool = other.descriptor_pool;
used_descriptors = other.used_descriptors;
flags = other.flags;

View File

@ -235,7 +235,7 @@ namespace vk
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));
CHECK_RESULT(vkAllocateDescriptorSets(*m_device, &alloc_info, m_descriptor_set.ptr()));
m_used_descriptors++;
if (!m_sampler && !src.empty())
@ -256,7 +256,7 @@ namespace vk
}
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, program->pipeline);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, &m_descriptor_set, 0, nullptr);
m_descriptor_set.bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout);
VkBuffer buffers = m_vao.heap->value;
VkDeviceSize offsets = m_vao_offset;

View File

@ -44,7 +44,7 @@ namespace vk
vk::glsl::shader m_fragment_shader;
vk::descriptor_pool m_descriptor_pool;
VkDescriptorSet m_descriptor_set = nullptr;
descriptor_set m_descriptor_set;
VkDescriptorSetLayout m_descriptor_layout = nullptr;
VkPipelineLayout m_pipeline_layout = nullptr;
u32 m_used_descriptors = 0;

View File

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "VKProgramPipeline.h"
#include "vkutils/descriptors.h"
#include "vkutils/device.h"
#include <string>
@ -158,7 +159,7 @@ namespace vk
});
}
void program::bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string& uniform_name, VkDescriptorType type, VkDescriptorSet &descriptor_set)
void program::bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string& uniform_name, VkDescriptorType type, vk::descriptor_set &set)
{
for (const auto &uniform : uniforms[program_input_type::input_type_texture])
{
@ -168,7 +169,7 @@ namespace vk
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
nullptr, // pNext
descriptor_set, // dstSet
VK_NULL_HANDLE, // dstSet
uniform.location, // dstBinding
0, // dstArrayElement
1, // descriptorCount
@ -178,7 +179,7 @@ namespace vk
nullptr // pTexelBufferView
};
vkUpdateDescriptorSets(m_device, 1, &descriptor_writer, 0, nullptr);
set.push(descriptor_writer);
attribute_location_mask |= (1ull << uniform.location);
return;
}
@ -187,7 +188,7 @@ namespace vk
rsx_log.notice("texture not found in program: %s", uniform_name.c_str());
}
void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, VkDescriptorSet &descriptor_set, bool is_stencil_mirror)
void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, vk::descriptor_set &set, bool is_stencil_mirror)
{
ensure(domain != ::glsl::program_domain::glsl_compute_program);
@ -207,7 +208,7 @@ namespace vk
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
nullptr, // pNext
descriptor_set, // dstSet
VK_NULL_HANDLE, // dstSet
binding, // dstBinding
0, // dstArrayElement
1, // descriptorCount
@ -217,7 +218,7 @@ namespace vk
nullptr // pTexelBufferView
};
vkUpdateDescriptorSets(m_device, 1, &descriptor_writer, 0, nullptr);
set.push(descriptor_writer);
attribute_location_mask |= (1ull << binding);
return;
}
@ -225,18 +226,18 @@ namespace vk
rsx_log.notice("texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program)? "v" : "", texture_unit);
}
void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorSet &descriptor_set)
void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, vk::descriptor_set &set)
{
bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptor_set);
bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, set);
}
void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point, VkDescriptorSet &descriptor_set)
void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point, vk::descriptor_set &set)
{
const VkWriteDescriptorSet descriptor_writer =
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
nullptr, // pNext
descriptor_set, // dstSet
VK_NULL_HANDLE, // dstSet
binding_point, // dstBinding
0, // dstArrayElement
1, // descriptorCount
@ -246,17 +247,17 @@ namespace vk
&buffer_view // pTexelBufferView
};
vkUpdateDescriptorSets(m_device, 1, &descriptor_writer, 0, nullptr);
set.push(descriptor_writer);
attribute_location_mask |= (1ull << binding_point);
}
void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, VkDescriptorSet &descriptor_set)
void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, vk::descriptor_set &set)
{
for (const auto &uniform : uniforms[type])
{
if (uniform.name == binding_name)
{
bind_uniform(buffer_view, uniform.location, descriptor_set);
bind_uniform(buffer_view, uniform.location, set);
return;
}
}
@ -264,13 +265,13 @@ namespace vk
rsx_log.notice("vertex buffer not found in program: %s", binding_name.c_str());
}
void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, VkDescriptorSet &descriptor_set)
void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, vk::descriptor_set &set)
{
const VkWriteDescriptorSet descriptor_writer =
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
nullptr, // pNext
descriptor_set, // dstSet
VK_NULL_HANDLE, // dstSet
binding_point, // dstBinding
0, // dstArrayElement
1, // descriptorCount
@ -280,7 +281,7 @@ namespace vk
nullptr // pTexelBufferView
};
vkUpdateDescriptorSets(m_device, 1, &descriptor_writer, 0, nullptr);
set.push(descriptor_writer);
attribute_location_mask |= (1ull << binding_point);
}
}

View File

@ -2,7 +2,8 @@
#include "VulkanAPI.h"
#include "VKCommonDecompiler.h"
#include "../Program/GLSLTypes.h"
#include "vkutils/descriptors.h"
#include <string>
#include <vector>
@ -99,14 +100,12 @@ namespace vk
program& link();
bool has_uniform(program_input_type type, const std::string &uniform_name);
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type, VkDescriptorSet &descriptor_set);
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, VkDescriptorSet &descriptor_set, bool is_stencil_mirror = false);
void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorSet &descriptor_set);
void bind_uniform(const VkBufferView &buffer_view, u32 binding_point, VkDescriptorSet &descriptor_set);
void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, VkDescriptorSet &descriptor_set);
void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, VkDescriptorSet &descriptor_set);
void bind_descriptor_set(const VkCommandBuffer cmd, VkDescriptorSet descriptor_set);
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type, vk::descriptor_set &set);
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, vk::descriptor_set &set, bool is_stencil_mirror = false);
void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, vk::descriptor_set &set);
void bind_uniform(const VkBufferView &buffer_view, u32 binding_point, vk::descriptor_set &set);
void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, vk::descriptor_set &set);
void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, vk::descriptor_set &set);
};
}
}

View File

@ -508,7 +508,7 @@ namespace vk
return program.release();
}
void shader_interpreter::update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images, VkDescriptorSet descriptor_set)
void shader_interpreter::update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images, vk::descriptor_set &set)
{
const VkDescriptorImageInfo* texture_ptr = sampled_images.data();
for (u32 i = 0, binding = m_fragment_textures_start; i < 4; ++i, ++binding, texture_ptr += 16)
@ -517,7 +517,7 @@ namespace vk
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
nullptr, // pNext
descriptor_set, // dstSet
VK_NULL_HANDLE, // dstSet
binding, // dstBinding
0, // dstArrayElement
16, // descriptorCount
@ -527,7 +527,7 @@ namespace vk
nullptr // pTexelBufferView
};
vkUpdateDescriptorSets(m_device, 1, &descriptor_writer, 0, nullptr);
set.push(descriptor_writer);
}
}

View File

@ -67,7 +67,7 @@ namespace vk
u32 get_vertex_instruction_location() const;
u32 get_fragment_instruction_location() const;
void update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images, VkDescriptorSet descriptor_set);
void update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images, vk::descriptor_set &set);
VkDescriptorSet allocate_descriptor_set();
};
}

View File

@ -22,7 +22,7 @@ namespace vk
vk::glsl::shader m_fragment_shader;
vk::descriptor_pool m_descriptor_pool;
VkDescriptorSet m_descriptor_set = nullptr;
vk::descriptor_set m_descriptor_set;
VkDescriptorSetLayout m_descriptor_layout = nullptr;
VkPipelineLayout m_pipeline_layout = nullptr;
u32 m_used_descriptors = 0;
@ -213,7 +213,7 @@ namespace vk
alloc_info.pSetLayouts = &m_descriptor_layout;
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
CHECK_RESULT(vkAllocateDescriptorSets(device, &alloc_info, &m_descriptor_set));
CHECK_RESULT(vkAllocateDescriptorSets(device, &alloc_info, m_descriptor_set.ptr()));
m_used_descriptors++;
float scale[] = { scale_x, scale_y };
@ -236,7 +236,7 @@ namespace vk
m_uniform_buffer_offset = (m_uniform_buffer_offset + 8192) % m_uniform_buffer_size;
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, &m_descriptor_set, 0, nullptr);
m_descriptor_set.bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout);
VkDeviceSize zero = 0;
vkCmdBindVertexBuffers(cmd, 0, 1, &m_vertex_buffer->value, &zero);

View File

@ -53,4 +53,143 @@ namespace vk
m_current_pool_handle = m_device_pools[m_current_pool_index];
CHECK_RESULT(vkResetDescriptorPool(*m_owner, m_current_pool_handle, flags));
}
descriptor_set::descriptor_set(VkDescriptorSet set)
{
flush();
init();
m_handle = set;
}
descriptor_set::descriptor_set()
{
init();
}
void descriptor_set::init()
{
if (m_image_info_pool.capacity() == 0)
{
m_image_info_pool.reserve(max_cache_size + 16);
m_buffer_view_pool.reserve(max_cache_size + 16);
m_buffer_info_pool.reserve(max_cache_size + 16);
}
}
VkBufferView* descriptor_set::dup(const VkBufferView* in)
{
if (!in) return nullptr;
m_buffer_view_pool.push_back(*in);
return &m_buffer_view_pool.back();
}
VkDescriptorBufferInfo* descriptor_set::dup(const VkDescriptorBufferInfo* in)
{
if (!in) return nullptr;
m_buffer_info_pool.push_back(*in);
return &m_buffer_info_pool.back();
}
VkDescriptorImageInfo* descriptor_set::dup(const VkDescriptorImageInfo* in)
{
if (!in) return nullptr;
m_image_info_pool.push_back(*in);
return &m_image_info_pool.back();
}
void descriptor_set::swap(descriptor_set& other)
{
other.flush();
flush();
std::swap(m_handle, other.m_handle);
}
descriptor_set& descriptor_set::operator = (VkDescriptorSet set)
{
flush();
m_handle = set;
return *this;
}
VkDescriptorSet* descriptor_set::ptr()
{
// TODO: You shouldn't need this
// ensure(m_handle == VK_NULL_HANDLE);
return &m_handle;
}
VkDescriptorSet descriptor_set::value() const
{
return m_handle;
}
void descriptor_set::push(const VkWriteDescriptorSet& write_cmd)
{
if (m_pending_writes.size() >= max_cache_size)
{
flush();
}
m_pending_writes.push_back(
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = m_handle,
.dstBinding = write_cmd.dstBinding,
.dstArrayElement = write_cmd.dstArrayElement,
.descriptorCount = write_cmd.descriptorCount,
.descriptorType = write_cmd.descriptorType,
.pImageInfo = dup(write_cmd.pImageInfo),
.pBufferInfo = dup(write_cmd.pBufferInfo),
.pTexelBufferView = dup(write_cmd.pTexelBufferView)
});
}
void descriptor_set::push(std::vector<VkCopyDescriptorSet>& copy_cmd)
{
if (m_pending_copies.empty()) [[likely]]
{
m_pending_copies = std::move(copy_cmd);
}
else
{
const size_t old_size = m_pending_copies.size();
const size_t new_size = copy_cmd.size() + old_size;
m_pending_copies.resize(new_size);
std::copy(copy_cmd.begin(), copy_cmd.end(), m_pending_copies.begin() + old_size);
}
}
void descriptor_set::bind(VkCommandBuffer cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout)
{
flush();
vkCmdBindDescriptorSets(cmd, bind_point, layout, 0, 1, &m_handle, 0, nullptr);
}
void descriptor_set::bind(const command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout)
{
bind(static_cast<VkCommandBuffer>(cmd), bind_point, layout);
}
void descriptor_set::flush()
{
if (m_pending_writes.empty() && m_pending_copies.empty())
{
return;
}
const auto num_writes = ::size32(m_pending_writes);
const auto num_copies = ::size32(m_pending_copies);
vkUpdateDescriptorSets(*g_render_device, num_writes, m_pending_writes.data(), num_copies, m_pending_copies.data());
m_pending_writes.clear();
m_pending_copies.clear();
m_image_info_pool.clear();
m_buffer_info_pool.clear();
m_buffer_view_pool.clear();
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "../VulkanAPI.h"
#include "commands.h"
#include "device.h"
#include <vector>
@ -9,12 +10,6 @@ namespace vk
{
class descriptor_pool
{
const vk::render_device* m_owner = nullptr;
std::vector<VkDescriptorPool> m_device_pools;
VkDescriptorPool m_current_pool_handle = VK_NULL_HANDLE;
u32 m_current_pool_index = 0;
public:
descriptor_pool() = default;
~descriptor_pool() = default;
@ -25,5 +20,54 @@ namespace vk
bool valid() const;
operator VkDescriptorPool();
private:
const vk::render_device* m_owner = nullptr;
std::vector<VkDescriptorPool> m_device_pools;
VkDescriptorPool m_current_pool_handle = VK_NULL_HANDLE;
u32 m_current_pool_index = 0;
};
class descriptor_set
{
const size_t max_cache_size = 16384;
VkBufferView* dup(const VkBufferView* in);
VkDescriptorBufferInfo* dup(const VkDescriptorBufferInfo* in);
VkDescriptorImageInfo* dup(const VkDescriptorImageInfo* in);
void flush();
void init();
public:
descriptor_set(VkDescriptorSet set);
descriptor_set();
~descriptor_set() = default;
descriptor_set(const descriptor_set&) = delete;
void swap(descriptor_set& other);
descriptor_set& operator = (VkDescriptorSet set);
VkDescriptorSet* ptr();
VkDescriptorSet value() const;
void push(const VkWriteDescriptorSet& write_cmd);
void push(std::vector<VkCopyDescriptorSet>& copy_cmd);
void bind(VkCommandBuffer cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout);
void bind(const command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout);
private:
VkDescriptorSet m_handle = VK_NULL_HANDLE;
std::vector<VkBufferView> m_buffer_view_pool;
std::vector<VkDescriptorBufferInfo> m_buffer_info_pool;
std::vector<VkDescriptorImageInfo> m_image_info_pool;
std::vector<VkWriteDescriptorSet> m_pending_writes;
std::vector<VkCopyDescriptorSet> m_pending_copies;
};
void flush_descriptor_updates();
}