renderer_vulkan: Use timeline semaphores if available
This commit is contained in:
@ -113,7 +113,8 @@ vk::Format Instance::GetFormatAlternative(vk::Format format) const {
|
|||||||
|
|
||||||
bool Instance::CreateDevice() {
|
bool Instance::CreateDevice() {
|
||||||
auto feature_chain = physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
|
auto feature_chain = physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
|
||||||
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
|
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT,
|
||||||
|
vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>();
|
||||||
|
|
||||||
// Not having geometry shaders will cause issues with accelerated rendering.
|
// Not having geometry shaders will cause issues with accelerated rendering.
|
||||||
const vk::PhysicalDeviceFeatures available = feature_chain.get().features;
|
const vk::PhysicalDeviceFeatures available = feature_chain.get().features;
|
||||||
@ -146,9 +147,10 @@ bool Instance::CreateDevice() {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
timeline_semaphores = AddExtension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME);
|
||||||
extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||||
push_descriptors = AddExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
push_descriptors = AddExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||||
AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
||||||
|
|
||||||
// Search queue families for graphics and present queues
|
// Search queue families for graphics and present queues
|
||||||
auto family_properties = physical_device.getQueueFamilyProperties();
|
auto family_properties = physical_device.getQueueFamilyProperties();
|
||||||
@ -220,6 +222,7 @@ bool Instance::CreateDevice() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(),
|
feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(),
|
||||||
|
feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create logical device
|
// Create logical device
|
||||||
|
@ -67,12 +67,18 @@ public:
|
|||||||
return present_queue;
|
return present_queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Feature support
|
/// Returns true when VK_KHR_timeline_semaphore is supported
|
||||||
|
bool IsTimelineSemaphoreSupported() const {
|
||||||
|
return timeline_semaphores;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true when VK_EXT_extended_dynamic_state is supported
|
||||||
bool IsExtendedDynamicStateSupported() const {
|
bool IsExtendedDynamicStateSupported() const {
|
||||||
// TODO: Enable this when the pipeline builder is confirmed functional
|
// TODO: Enable this when the pipeline builder is confirmed functional
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true when VK_KHR_push_descriptors is supported
|
||||||
bool IsPushDescriptorsSupported() const {
|
bool IsPushDescriptorsSupported() const {
|
||||||
return push_descriptors;
|
return push_descriptors;
|
||||||
}
|
}
|
||||||
@ -115,6 +121,8 @@ private:
|
|||||||
vk::Queue graphics_queue;
|
vk::Queue graphics_queue;
|
||||||
u32 present_queue_family_index = 0;
|
u32 present_queue_family_index = 0;
|
||||||
u32 graphics_queue_family_index = 0;
|
u32 graphics_queue_family_index = 0;
|
||||||
|
|
||||||
|
bool timeline_semaphores = false;
|
||||||
bool extended_dynamic_state = false;
|
bool extended_dynamic_state = false;
|
||||||
bool push_descriptors = false;
|
bool push_descriptors = false;
|
||||||
};
|
};
|
||||||
|
@ -19,6 +19,19 @@ TaskScheduler::TaskScheduler(const Instance& instance) : instance{instance} {
|
|||||||
|
|
||||||
command_pool = device.createCommandPool(command_pool_info);
|
command_pool = device.createCommandPool(command_pool_info);
|
||||||
|
|
||||||
|
// If supported, prefer timeline semaphores over binary ones
|
||||||
|
if (instance.IsTimelineSemaphoreSupported()) {
|
||||||
|
const vk::StructureChain timeline_info = {
|
||||||
|
vk::SemaphoreCreateInfo{},
|
||||||
|
vk::SemaphoreTypeCreateInfo{
|
||||||
|
.semaphoreType = vk::SemaphoreType::eTimeline,
|
||||||
|
.initialValue = 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
timeline = device.createSemaphore(timeline_info.get());
|
||||||
|
}
|
||||||
|
|
||||||
constexpr std::array pool_sizes = {
|
constexpr std::array pool_sizes = {
|
||||||
vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer, 1024},
|
vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer, 1024},
|
||||||
vk::DescriptorPoolSize{vk::DescriptorType::eUniformBufferDynamic, 1024},
|
vk::DescriptorPoolSize{vk::DescriptorType::eUniformBufferDynamic, 1024},
|
||||||
@ -64,6 +77,10 @@ TaskScheduler::~TaskScheduler() {
|
|||||||
vk::Device device = instance.GetDevice();
|
vk::Device device = instance.GetDevice();
|
||||||
device.waitIdle();
|
device.waitIdle();
|
||||||
|
|
||||||
|
if (timeline) {
|
||||||
|
device.destroySemaphore(timeline);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
device.destroyFence(command.fence);
|
device.destroyFence(command.fence);
|
||||||
device.destroyDescriptorPool(command.descriptor_pool);
|
device.destroyDescriptorPool(command.descriptor_pool);
|
||||||
@ -76,9 +93,27 @@ void TaskScheduler::Synchronize(u32 slot) {
|
|||||||
const auto& command = commands[slot];
|
const auto& command = commands[slot];
|
||||||
vk::Device device = instance.GetDevice();
|
vk::Device device = instance.GetDevice();
|
||||||
|
|
||||||
if (command.fence_counter > completed_fence_counter) {
|
u32 completed_counter = completed_fence_counter;
|
||||||
if (device.waitForFences(command.fence, true, UINT64_MAX) != vk::Result::eSuccess) {
|
if (instance.IsTimelineSemaphoreSupported()) {
|
||||||
LOG_ERROR(Render_Vulkan, "Waiting for fences failed!");
|
completed_counter = device.getSemaphoreCounterValue(timeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.fence_counter > completed_counter) {
|
||||||
|
if (instance.IsTimelineSemaphoreSupported()) {
|
||||||
|
const vk::SemaphoreWaitInfo wait_info = {
|
||||||
|
.semaphoreCount = 1,
|
||||||
|
.pSemaphores = &timeline,
|
||||||
|
.pValues = &command.fence_counter
|
||||||
|
};
|
||||||
|
|
||||||
|
if (device.waitSemaphores(wait_info, UINT64_MAX) != vk::Result::eSuccess) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Waiting for fence counter {} failed!", command.fence_counter);
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (device.waitForFences(command.fence, true, UINT64_MAX) != vk::Result::eSuccess) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Waiting for fence counter {} failed!", command.fence_counter);
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
completed_fence_counter = command.fence_counter;
|
completed_fence_counter = command.fence_counter;
|
||||||
@ -116,10 +151,47 @@ void TaskScheduler::Submit(bool wait_completion, bool begin_next,
|
|||||||
|
|
||||||
command_buffers[command_buffer_count++] = command.render_command_buffer;
|
command_buffers[command_buffer_count++] = command.render_command_buffer;
|
||||||
|
|
||||||
|
if (instance.IsTimelineSemaphoreSupported()) {
|
||||||
|
const u32 signal_semaphore_count = signal_semaphore ? 2u : 1u;
|
||||||
|
const std::array signal_values{command.fence_counter, 0ul};
|
||||||
|
const std::array signal_semaphores{timeline, signal_semaphore};
|
||||||
|
|
||||||
|
const u32 wait_semaphore_count = wait_semaphore ? 2u : 1u;
|
||||||
|
const std::array wait_values{command.fence_counter - 1, 1ul};
|
||||||
|
const std::array wait_semaphores{timeline, wait_semaphore};
|
||||||
|
|
||||||
|
const vk::TimelineSemaphoreSubmitInfoKHR timeline_si = {
|
||||||
|
.waitSemaphoreValueCount = wait_semaphore_count,
|
||||||
|
.pWaitSemaphoreValues = wait_values.data(),
|
||||||
|
.signalSemaphoreValueCount = signal_semaphore_count,
|
||||||
|
.pSignalSemaphoreValues = signal_values.data()
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<vk::PipelineStageFlags, 2> wait_stage_masks = {
|
||||||
|
vk::PipelineStageFlagBits::eAllCommands,
|
||||||
|
vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||||
|
};
|
||||||
|
|
||||||
|
const vk::SubmitInfo submit_info = {
|
||||||
|
.pNext = &timeline_si,
|
||||||
|
.waitSemaphoreCount = wait_semaphore_count,
|
||||||
|
.pWaitSemaphores = wait_semaphores.data(),
|
||||||
|
.pWaitDstStageMask = wait_stage_masks.data(),
|
||||||
|
.commandBufferCount = command_buffer_count,
|
||||||
|
.pCommandBuffers = command_buffers.data(),
|
||||||
|
.signalSemaphoreCount = signal_semaphore_count,
|
||||||
|
.pSignalSemaphores = signal_semaphores.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::Queue queue = instance.GetGraphicsQueue();
|
||||||
|
queue.submit(submit_info);
|
||||||
|
|
||||||
|
} else {
|
||||||
const u32 signal_semaphore_count = signal_semaphore ? 1u : 0u;
|
const u32 signal_semaphore_count = signal_semaphore ? 1u : 0u;
|
||||||
const u32 wait_semaphore_count = wait_semaphore ? 1u : 0u;
|
const u32 wait_semaphore_count = wait_semaphore ? 1u : 0u;
|
||||||
const vk::PipelineStageFlags wait_stage_masks =
|
const vk::PipelineStageFlags wait_stage_masks =
|
||||||
vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||||
|
|
||||||
const vk::SubmitInfo submit_info = {
|
const vk::SubmitInfo submit_info = {
|
||||||
.waitSemaphoreCount = wait_semaphore_count,
|
.waitSemaphoreCount = wait_semaphore_count,
|
||||||
.pWaitSemaphores = &wait_semaphore,
|
.pWaitSemaphores = &wait_semaphore,
|
||||||
@ -132,6 +204,7 @@ void TaskScheduler::Submit(bool wait_completion, bool begin_next,
|
|||||||
|
|
||||||
vk::Queue queue = instance.GetGraphicsQueue();
|
vk::Queue queue = instance.GetGraphicsQueue();
|
||||||
queue.submit(submit_info, command.fence);
|
queue.submit(submit_info, command.fence);
|
||||||
|
}
|
||||||
|
|
||||||
// Block host until the GPU catches up
|
// Block host until the GPU catches up
|
||||||
if (wait_completion) {
|
if (wait_completion) {
|
||||||
|
@ -75,6 +75,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
vk::CommandPool command_pool{};
|
vk::CommandPool command_pool{};
|
||||||
|
vk::Semaphore timeline{};
|
||||||
std::array<ExecutionSlot, SCHEDULER_COMMAND_COUNT> commands;
|
std::array<ExecutionSlot, SCHEDULER_COMMAND_COUNT> commands;
|
||||||
u32 current_command = 0;
|
u32 current_command = 0;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user