vk: Implement state tracking for command buffers
- Only tracks the heavy items for now. Binding the same pipeline or descriptor set causes some drivers to perform expensive operations (RADV, AMDVLK)
This commit is contained in:
@@ -74,7 +74,7 @@ namespace vk
|
|||||||
}
|
}
|
||||||
|
|
||||||
++reset_id;
|
++reset_id;
|
||||||
CHECK_RESULT(vkResetCommandBuffer(commands, 0));
|
vk::command_buffer::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poke()
|
bool poke()
|
||||||
|
|||||||
@@ -414,8 +414,8 @@ namespace vk
|
|||||||
bind_sets[count++] = set.commit(); // Commit variable changes and return handle to the new set
|
bind_sets[count++] = set.commit(); // Commit variable changes and return handle to the new set
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCmdBindPipeline(cmd, bind_point, m_pipeline);
|
cmd.bind_pipeline(m_pipeline, bind_point);
|
||||||
vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, count, bind_sets, 0, nullptr);
|
cmd.bind_descriptor_sets({ bind_sets, count }, bind_point, m_pipeline_layout);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1339,7 +1339,7 @@ namespace vk
|
|||||||
cmd.submit(submit_info, VK_TRUE);
|
cmd.submit(submit_info, VK_TRUE);
|
||||||
vk::wait_for_fence(&submit_fence, GENERAL_WAIT_TIMEOUT);
|
vk::wait_for_fence(&submit_fence, GENERAL_WAIT_TIMEOUT);
|
||||||
|
|
||||||
CHECK_RESULT(vkResetCommandBuffer(cmd, 0));
|
cmd.reset();
|
||||||
cmd.begin();
|
cmd.begin();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -70,6 +70,16 @@ namespace vk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void command_buffer::reset()
|
||||||
|
{
|
||||||
|
// Nuke the state cache
|
||||||
|
m_bound_pipeline = VK_NULL_HANDLE;
|
||||||
|
m_bound_descriptor_sets[0] = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
// Do the driver reset
|
||||||
|
CHECK_RESULT(vkResetCommandBuffer(commands, 0));
|
||||||
|
}
|
||||||
|
|
||||||
void command_buffer::begin()
|
void command_buffer::begin()
|
||||||
{
|
{
|
||||||
if (m_submit_fence && is_pending)
|
if (m_submit_fence && is_pending)
|
||||||
@@ -79,7 +89,7 @@ namespace vk
|
|||||||
|
|
||||||
//CHECK_RESULT(vkResetFences(pool->get_owner(), 1, &m_submit_fence));
|
//CHECK_RESULT(vkResetFences(pool->get_owner(), 1, &m_submit_fence));
|
||||||
m_submit_fence->reset();
|
m_submit_fence->reset();
|
||||||
CHECK_RESULT(vkResetCommandBuffer(commands, 0));
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_open)
|
if (is_open)
|
||||||
@@ -129,4 +139,51 @@ namespace vk
|
|||||||
queue_submit(submit_info, flush);
|
queue_submit(submit_info, flush);
|
||||||
clear_flags();
|
clear_flags();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void command_buffer::bind_pipeline(VkPipeline pipeline, VkPipelineBindPoint bind_point) const
|
||||||
|
{
|
||||||
|
if (m_bound_pipeline == pipeline)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bound_pipeline = pipeline;
|
||||||
|
vkCmdBindPipeline(commands, bind_point, pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_buffer::bind_descriptor_sets(
|
||||||
|
const std::span<VkDescriptorSet>& sets,
|
||||||
|
const std::span<u32>& dynamic_offsets,
|
||||||
|
VkPipelineBindPoint bind_point,
|
||||||
|
VkPipelineLayout pipe_layout) const
|
||||||
|
{
|
||||||
|
const u32 num_sets = ::size32(sets);
|
||||||
|
ensure(num_sets <= 2);
|
||||||
|
|
||||||
|
if (dynamic_offsets.empty() &&
|
||||||
|
!memcmp(sets.data(), m_bound_descriptor_sets.data(), sets.size_bytes()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(m_bound_descriptor_sets.data(), sets.data(), sets.size_bytes());
|
||||||
|
vkCmdBindDescriptorSets(commands, bind_point, pipe_layout, 0, num_sets, sets.data(), ::size32(dynamic_offsets), dynamic_offsets.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_buffer::bind_descriptor_sets(
|
||||||
|
const std::span<VkDescriptorSet>& sets,
|
||||||
|
VkPipelineBindPoint bind_point,
|
||||||
|
VkPipelineLayout pipe_layout) const
|
||||||
|
{
|
||||||
|
const u32 num_sets = ::size32(sets);
|
||||||
|
ensure(num_sets <= 2);
|
||||||
|
|
||||||
|
if (!memcmp(sets.data(), m_bound_descriptor_sets.data(), sets.size_bytes()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(m_bound_descriptor_sets.data(), sets.data(), sets.size_bytes());
|
||||||
|
vkCmdBindDescriptorSets(commands, bind_point, pipe_layout, 0, num_sets, sets.data(), 0, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ namespace vk
|
|||||||
command_pool* pool = nullptr;
|
command_pool* pool = nullptr;
|
||||||
VkCommandBuffer commands = nullptr;
|
VkCommandBuffer commands = nullptr;
|
||||||
|
|
||||||
|
// State cache
|
||||||
|
mutable std::array<VkDescriptorSet, 2> m_bound_descriptor_sets {{ VK_NULL_HANDLE }};
|
||||||
|
mutable VkPipeline m_bound_pipeline = VK_NULL_HANDLE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum access_type_hint
|
enum access_type_hint
|
||||||
{
|
{
|
||||||
@@ -97,40 +101,28 @@ namespace vk
|
|||||||
|
|
||||||
void create(command_pool& cmd_pool);
|
void create(command_pool& cmd_pool);
|
||||||
void destroy();
|
void destroy();
|
||||||
|
void reset();
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
void end();
|
void end();
|
||||||
void submit(queue_submit_t& submit_info, VkBool32 flush = VK_FALSE);
|
void submit(queue_submit_t& submit_info, VkBool32 flush = VK_FALSE);
|
||||||
|
|
||||||
|
// Abstractions with caching
|
||||||
|
void bind_pipeline(VkPipeline pipeline, VkPipelineBindPoint bind_point) const;
|
||||||
|
void bind_descriptor_sets(const std::span<VkDescriptorSet>& sets, VkPipelineBindPoint bind_point, VkPipelineLayout pipe_layout) const;
|
||||||
|
void bind_descriptor_sets(const std::span<VkDescriptorSet>& sets, const std::span<u32>& dynamic_offsets, VkPipelineBindPoint bind_point, VkPipelineLayout pipe_layout) const;
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
command_pool& get_command_pool() const
|
command_pool& get_command_pool() const { return *pool; }
|
||||||
{
|
u32 get_queue_family() const { return pool->get_queue_family(); }
|
||||||
return *pool;
|
bool is_recording() const { return is_open; }
|
||||||
}
|
|
||||||
|
|
||||||
u32 get_queue_family() const
|
void clear_flags() { flags = 0; }
|
||||||
{
|
void set_flag(command_buffer_data_flag flag) { flags |= flag; }
|
||||||
return pool->get_queue_family();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_flags()
|
|
||||||
{
|
|
||||||
flags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_flag(command_buffer_data_flag flag)
|
|
||||||
{
|
|
||||||
flags |= flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator VkCommandBuffer() const
|
operator VkCommandBuffer() const
|
||||||
{
|
{
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_recording() const
|
|
||||||
{
|
|
||||||
return is_open;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -453,7 +453,8 @@ namespace vk
|
|||||||
// Notify
|
// Notify
|
||||||
on_bind();
|
on_bind();
|
||||||
|
|
||||||
vkCmdBindDescriptorSets(cmd, bind_point, layout, 0, 1, &m_handle, ::size32(m_dynamic_offsets), m_dynamic_offsets.data());
|
VkDescriptorSet sets[1] = { m_handle };
|
||||||
|
cmd.bind_descriptor_sets(sets, m_dynamic_offsets, bind_point, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void descriptor_set::flush()
|
void descriptor_set::flush()
|
||||||
|
|||||||
Reference in New Issue
Block a user