vulkan: Add support for timeline semaphores

Unlike binary semaphores, timeline semaphores represent a (64bit
unsigned) value and the binary decision about whether they have signaled
or not is decided by comparing their value to a predefined value.
So this code adds the ability to pass that value.

In fact, it now requires this value, but that is not a problem because
Vulkan ignores the value for binary semaphores, so we can just pass
0 everywhere a binary sempahore is used.

There is no use of the code in those commit, but timeline semaphores
are used for explicit sync with dmabufs and D3D12 uses them exclusively.
This commit is contained in:
Benjamin Otte
2024-11-07 21:54:44 +01:00
parent a6d30b1694
commit 641b8c9cd0
5 changed files with 44 additions and 6 deletions

View File

@@ -49,10 +49,11 @@ typedef enum {
GDK_VULKAN_FEATURE_DMABUF = 1 << 0,
GDK_VULKAN_FEATURE_WIN32 = 1 << 1,
GDK_VULKAN_FEATURE_YCBCR = 1 << 2,
GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT = 1 << 3,
GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT = 1 << 4,
GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT = 1 << 5,
GDK_VULKAN_FEATURE_SWAPCHAIN_MAINTENANCE = 1 << 6,
GDK_VULKAN_FEATURE_TIMELINE_SEMAPHORE = 1 << 3,
GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT = 1 << 4,
GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT = 1 << 5,
GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT = 1 << 6,
GDK_VULKAN_FEATURE_SWAPCHAIN_MAINTENANCE = 1 << 7,
} GdkVulkanFeatures;
#define GDK_VULKAN_N_FEATURES 6

View File

@@ -39,6 +39,7 @@ const GdkDebugKey gdk_vulkan_feature_keys[] = {
{ "dmabuf", GDK_VULKAN_FEATURE_DMABUF, "Never import Dmabufs" },
{ "win32", GDK_VULKAN_FEATURE_WIN32, "Never import Windows resources" },
{ "ycbcr", GDK_VULKAN_FEATURE_YCBCR, "Do not support Ycbcr textures (also disables dmabufs)" },
{ "timeline-semaphore", GDK_VULKAN_FEATURE_TIMELINE_SEMAPHORE, "Disable timeline semaphore support (disables Windows sync)"},
{ "semaphore-export", GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT, "Disable sync of exported dmabufs" },
{ "semaphore-import", GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT, "Disable sync of imported dmabufs" },
{ "incremental-present", GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT, "Do not send damage regions" },
@@ -632,6 +633,9 @@ physical_device_check_features (VkPhysicalDevice device)
physical_device_supports_extension (device, VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME))
features |= GDK_VULKAN_FEATURE_DMABUF;
if (physical_device_supports_extension (device, VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME))
features |= GDK_VULKAN_FEATURE_TIMELINE_SEMAPHORE;
#ifdef GDK_WINDOWING_WIN32
if (physical_device_supports_extension (device, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME))
features |= GDK_VULKAN_FEATURE_WIN32;
@@ -1579,6 +1583,11 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
g_ptr_array_add (device_extensions, (gpointer) VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
}
if (features & GDK_VULKAN_FEATURE_TIMELINE_SEMAPHORE)
{
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME);
}
#ifdef GDK_WINDOWING_WIN32
if (features & GDK_VULKAN_FEATURE_WIN32)
{
@@ -1589,6 +1598,8 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
#endif
if (features & (GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT | GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT))
{
if (!(features & GDK_VULKAN_FEATURE_TIMELINE_SEMAPHORE))
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
}
if (features & GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT)

View File

@@ -18,6 +18,13 @@
#define GDK_ARRAY_NO_MEMSET 1
#include "gdk/gdkarrayimpl.c"
#define GDK_ARRAY_NAME gsk_semaphore_values
#define GDK_ARRAY_TYPE_NAME GskSemaphoreValues
#define GDK_ARRAY_ELEMENT_TYPE uint64_t
#define GDK_ARRAY_PREALLOC 16
#define GDK_ARRAY_NO_MEMSET 1
#include "gdk/gdkarrayimpl.c"
#define GDK_ARRAY_NAME gsk_pipeline_stages
#define GDK_ARRAY_TYPE_NAME GskPipelineStages
#define GDK_ARRAY_ELEMENT_TYPE VkPipelineStageFlags
@@ -28,6 +35,7 @@
struct _GskVulkanSemaphores
{
GskSemaphores wait_semaphores;
GskSemaphoreValues wait_semaphore_values;
GskPipelineStages wait_stages;
GskSemaphores signal_semaphores;
};
@@ -260,9 +268,12 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame,
GskGpuOp *op)
{
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
GskVulkanDevice *device;
GskVulkanSemaphores semaphores;
GskVulkanCommandState state = { 0, };
device = GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame));
GSK_VK_CHECK (vkBeginCommandBuffer, self->vk_command_buffer,
&(VkCommandBufferBeginInfo) {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
@@ -279,6 +290,7 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame,
(VkDeviceSize[1]) { 0 });
gsk_semaphores_init (&semaphores.wait_semaphores);
gsk_semaphore_values_init (&semaphores.wait_semaphore_values);
gsk_pipeline_stages_init (&semaphores.wait_stages);
gsk_semaphores_init (&semaphores.signal_semaphores);
@@ -286,6 +298,7 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame,
{
gsk_vulkan_semaphores_add_wait (&semaphores,
self->vk_acquire_semaphore,
0,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
}
@@ -302,7 +315,7 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame,
GSK_VK_CHECK (vkEndCommandBuffer, self->vk_command_buffer);
GSK_VK_CHECK (vkQueueSubmit, gsk_vulkan_device_get_vk_queue (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame))),
GSK_VK_CHECK (vkQueueSubmit, gsk_vulkan_device_get_vk_queue (device),
1,
&(VkSubmitInfo) {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
@@ -313,10 +326,16 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame,
.waitSemaphoreCount = gsk_semaphores_get_size (&semaphores.wait_semaphores),
.pSignalSemaphores = gsk_semaphores_get_data (&semaphores.signal_semaphores),
.signalSemaphoreCount = gsk_semaphores_get_size (&semaphores.signal_semaphores),
.pNext = gsk_vulkan_device_has_feature (device, GDK_VULKAN_FEATURE_TIMELINE_SEMAPHORE) ? &(VkTimelineSemaphoreSubmitInfo) {
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
.waitSemaphoreValueCount = gsk_semaphore_values_get_size (&semaphores.wait_semaphore_values),
.pWaitSemaphoreValues = gsk_semaphore_values_get_data (&semaphores.wait_semaphore_values),
} : NULL,
},
self->vk_fence);
gsk_semaphores_clear (&semaphores.wait_semaphores);
gsk_semaphore_values_clear (&semaphores.wait_semaphore_values);
gsk_pipeline_stages_clear (&semaphores.wait_stages);
gsk_semaphores_clear (&semaphores.signal_semaphores);
}
@@ -384,9 +403,11 @@ gsk_vulkan_frame_get_vk_fence (GskVulkanFrame *self)
void
gsk_vulkan_semaphores_add_wait (GskVulkanSemaphores *self,
VkSemaphore semaphore,
guint64 semaphore_wait,
VkPipelineStageFlags stage)
{
gsk_semaphores_append (&self->wait_semaphores, semaphore);
gsk_semaphore_values_append (&self->wait_semaphore_values, semaphore_wait);
gsk_pipeline_stages_append (&self->wait_stages, stage);
}

View File

@@ -14,6 +14,7 @@ VkFence gsk_vulkan_frame_get_vk_fence (GskVulk
void gsk_vulkan_semaphores_add_wait (GskVulkanSemaphores *self,
VkSemaphore semaphore,
uint64_t semaphore_wait,
VkPipelineStageFlags stage);
void gsk_vulkan_semaphores_add_signal (GskVulkanSemaphores *self,
VkSemaphore semaphore);

View File

@@ -34,6 +34,7 @@ struct _GskVulkanImage
VkImageView vk_framebuffer_image_view;
GskVulkanYcbcr *ycbcr;
VkSemaphore vk_semaphore;
uint64_t vk_semaphore_wait;
struct {
VkDescriptorSet vk_descriptor_set;
gsize pool_id;
@@ -1501,7 +1502,10 @@ gsk_vulkan_image_transition (GskVulkanImage *self,
if (self->vk_pipeline_stage == VK_IMAGE_LAYOUT_GENERAL &&
self->vk_semaphore)
{
gsk_vulkan_semaphores_add_wait (semaphores, self->vk_semaphore, stage);
gsk_vulkan_semaphores_add_wait (semaphores,
self->vk_semaphore,
self->vk_semaphore_wait,
stage);
}
vkCmdPipelineBarrier (command_buffer,