@@ -34,17 +34,16 @@ class CommandBufferManager
// is submitted, after that you should call these functions again.
VkCommandBuffer GetCurrentInitCommandBuffer()
{
m_frame_resources[m_current_frame].init_command_buffer_used = true;
return m_frame_resources[m_current_frame].command_buffers[0];
CmdBufferResources& cmd_buffer_resources = GetCurrentCmdBufferResources();
cmd_buffer_resources.init_command_buffer_used = true;
return cmd_buffer_resources.command_buffers[0];
}
VkCommandBuffer GetCurrentCommandBuffer() const
{
return m_frame_resources[m_current_frame].command_buffers[1];
}
VkDescriptorPool GetCurrentDescriptorPool() const
{
return m_frame_resources[m_current_frame].descriptor_pool;
const CmdBufferResources& cmd_buffer_resources = m_command_buffers[m_current_cmd_buffer];
return cmd_buffer_resources.command_buffers[1];
}
VkDescriptorPool GetCurrentDescriptorPool() const { return m_descriptor_pools[m_current_frame]; }
// Allocates a descriptors set from the pool reserved for the current frame.
VkDescriptorSet AllocateDescriptorSet(VkDescriptorSetLayout set_layout);

@@ -56,14 +55,19 @@ class CommandBufferManager

// Gets the fence that will be signaled when the currently executing command buffer is
// queued and executed. Do not wait for this fence before the buffer is executed.
u64 GetCurrentFenceCounter() const { return m_frame_resources[m_current_frame].fence_counter; }
u64 GetCurrentFenceCounter() const
{
auto& resources = m_command_buffers[m_current_cmd_buffer];
return resources.fence_counter;
}

// Returns the semaphore for the current command buffer, which can be used to ensure the
// swap chain image is ready before the command buffer executes.
VkSemaphore GetCurrentCommandBufferSemaphore()
{
m_frame_resources[m_current_frame].semaphore_used = true;
return m_frame_resources[m_current_frame].semaphore;
auto& resources = m_command_buffers[m_current_cmd_buffer];
resources.semaphore_used = true;
return resources.semaphore;
}

// Ensure that the worker thread has submitted any previous command buffers and is idle.
@@ -101,30 +105,35 @@ class CommandBufferManager
u32 present_image_index);
void BeginCommandBuffer();

struct FrameResources
struct CmdBufferResources
{
// [0] - Init (upload) command buffer, [1] - draw command buffer
VkCommandPool command_pool = VK_NULL_HANDLE;
std::array<VkCommandBuffer, 2> command_buffers = {};
VkDescriptorPool descriptor_pool = VK_NULL_HANDLE;
VkFence fence = VK_NULL_HANDLE;
VkSemaphore semaphore = VK_NULL_HANDLE;
u64 fence_counter = 0;
bool init_command_buffer_used = false;
bool semaphore_used = false;
u32 frame_index = 0;

std::vector<std::function<void()>> cleanup_resources;
};

CmdBufferResources& GetCurrentCmdBufferResources()
{
return m_command_buffers[m_current_cmd_buffer];
}

u64 m_next_fence_counter = 1;
u64 m_completed_fence_counter = 0;

std::array<FrameResources, NUM_COMMAND_BUFFERS> m_frame_resources;
std::array<VkDescriptorPool, NUM_FRAMES_IN_FLIGHT> m_descriptor_pools;
std::array<CmdBufferResources, NUM_COMMAND_BUFFERS> m_command_buffers;
u32 m_current_frame = 0;
u32 m_current_cmd_buffer = 0;

// Threaded command buffer execution
// Semaphore determines when a command buffer can be queued
Common::Semaphore m_submit_semaphore;
std::thread m_submit_thread;
std::unique_ptr<Common::BlockingLoop> m_submit_loop;
struct PendingCommandBufferSubmit
@@ -136,6 +145,8 @@ class CommandBufferManager
VkSemaphore m_present_semaphore = VK_NULL_HANDLE;
std::deque<PendingCommandBufferSubmit> m_pending_submits;
std::mutex m_pending_submit_lock;
std::condition_variable m_submit_worker_condvar;
bool m_submit_worker_idle = true;
Common::Flag m_last_present_failed;
VkResult m_last_present_result = VK_SUCCESS;
bool m_use_threaded_submission = false;
@@ -11,9 +11,11 @@

namespace Vulkan
{
// Number of command buffers. Having two allows one buffer to be
// executed whilst another is being built.
constexpr size_t NUM_COMMAND_BUFFERS = 2;
// Number of command buffers.
constexpr size_t NUM_COMMAND_BUFFERS = 8;

// Number of frames in flight, will be used to decide how many descriptor pools are used
constexpr size_t NUM_FRAMES_IN_FLIGHT = 2;

// Staging buffer usage - optimize for uploads or readbacks
enum STAGING_BUFFER_TYPE
@@ -223,7 +223,10 @@ bool VulkanContext::SelectInstanceExtensions(std::vector<const char*>* extension
WARN_LOG_FMT(VIDEO, "Vulkan: Debug report requested, but extension is not available.");

AddExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
AddExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false);
if (wstype != WindowSystemType::Headless)
{
AddExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false);
}

if (AddExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false))
{