vulkan/wsi: Signal semaphores and fences from the dma-buf

Instead of attempting to signal based on the memory object, use the new
DMA_BUF_IOCTL_EXPORT_SYNC_FILE to get a sync_file for the dma-buf and
use that to signal the semaphore or fence.  Because this happens before
we transfer ownership back to the driver, the resulting sync_file should
only contain dma_fences from the compositor and/or display and shouldn't
be mixed up with the driver in any way.  This gives us a real semaphore
and fence (as opposed to the dummy objects we've used int the past)
without over-synchronization.

Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4037>
This commit is contained in:
Jason Ekstrand 2021-03-15 12:06:53 -05:00 committed by Marge Bot
parent 18bd05827d
commit 30b57f10b3
4 changed files with 299 additions and 5 deletions

View file

@ -64,6 +64,7 @@ wsi_device_init(struct wsi_device *wsi,
wsi->sw = sw_device;
#define WSI_GET_CB(func) \
PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
WSI_GET_CB(GetPhysicalDeviceExternalSemaphoreProperties);
WSI_GET_CB(GetPhysicalDeviceProperties2);
WSI_GET_CB(GetPhysicalDeviceMemoryProperties);
WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties);
@ -83,6 +84,23 @@ wsi_device_init(struct wsi_device *wsi,
GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props);
GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL);
for (VkExternalSemaphoreHandleTypeFlags handle_type = 1;
handle_type <= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
handle_type <<= 1) {
const VkPhysicalDeviceExternalSemaphoreInfo esi = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
.handleType = handle_type,
};
VkExternalSemaphoreProperties esp = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
};
GetPhysicalDeviceExternalSemaphoreProperties(pdevice, &esi, &esp);
if (esp.externalSemaphoreFeatures &
VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT)
wsi->semaphore_export_handle_types |= handle_type;
}
list_inithead(&wsi->hotplug_fences);
#define WSI_GET_CB(func) \
@ -116,6 +134,7 @@ wsi_device_init(struct wsi_device *wsi,
WSI_GET_CB(GetPhysicalDeviceFormatProperties);
WSI_GET_CB(GetPhysicalDeviceFormatProperties2KHR);
WSI_GET_CB(GetPhysicalDeviceImageFormatProperties2);
WSI_GET_CB(GetSemaphoreFdKHR);
WSI_GET_CB(ResetFences);
WSI_GET_CB(QueueSubmit);
WSI_GET_CB(WaitForFences);
@ -349,6 +368,8 @@ wsi_swapchain_finish(struct wsi_swapchain *chain)
vk_free(&chain->alloc, chain->buffer_blit_semaphores);
}
chain->wsi->DestroySemaphore(chain->device, chain->dma_buf_semaphore,
&chain->alloc);
int cmd_pools_count = chain->buffer_blit_queue != VK_NULL_HANDLE ?
1 : chain->wsi->queue_family_count;
@ -843,6 +864,14 @@ wsi_signal_semaphore_for_image(struct vk_device *device,
vk_semaphore_reset_temporary(device, semaphore);
#ifndef _WIN32
VkResult result = wsi_create_sync_for_dma_buf_wait(chain, image,
VK_SYNC_FEATURE_GPU_WAIT,
&semaphore->temporary);
if (result != VK_ERROR_FEATURE_NOT_PRESENT)
return result;
#endif
if (chain->wsi->signal_semaphore_with_memory) {
return device->create_sync_for_memory(device, image->memory,
false /* signal_memory */,
@ -867,6 +896,14 @@ wsi_signal_fence_for_image(struct vk_device *device,
vk_fence_reset_temporary(device, fence);
#ifndef _WIN32
VkResult result = wsi_create_sync_for_dma_buf_wait(chain, image,
VK_SYNC_FEATURE_CPU_WAIT,
&fence->temporary);
if (result != VK_ERROR_FEATURE_NOT_PRESENT)
return result;
#endif
if (chain->wsi->signal_fence_with_memory) {
return device->create_sync_for_memory(device, image->memory,
false /* signal_memory */,
@ -1036,16 +1073,50 @@ wsi_common_queue_present(const struct wsi_device *wsi,
VkFence fence = swapchain->fences[image_index];
struct wsi_memory_signal_submit_info mem_signal = {
bool has_signal_dma_buf = false;
#ifndef _WIN32
result = wsi_prepare_signal_dma_buf_from_semaphore(swapchain, image);
if (result == VK_SUCCESS) {
assert(submit_info.signalSemaphoreCount == 0);
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &swapchain->dma_buf_semaphore;
has_signal_dma_buf = true;
} else if (result == VK_ERROR_FEATURE_NOT_PRESENT) {
result = VK_SUCCESS;
has_signal_dma_buf = false;
} else {
goto fail_present;
}
#endif
struct wsi_memory_signal_submit_info mem_signal;
if (!has_signal_dma_buf) {
/* If we don't have dma-buf signaling, signal the memory object by
* chaining wsi_memory_signal_submit_info into VkSubmitInfo.
*/
result = VK_SUCCESS;
has_signal_dma_buf = false;
mem_signal = (struct wsi_memory_signal_submit_info) {
.sType = VK_STRUCTURE_TYPE_WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA,
.memory = image->memory,
};
__vk_append_struct(&submit_info, &mem_signal);
}
result = wsi->QueueSubmit(submit_queue, 1, &submit_info, fence);
if (result != VK_SUCCESS)
goto fail_present;
#ifndef _WIN32
if (has_signal_dma_buf) {
result = wsi_signal_dma_buf_from_semaphore(swapchain, image);
if (result != VK_SUCCESS)
goto fail_present;
}
#else
assert(!has_signal_dma_buf);
#endif
if (wsi->sw)
wsi->WaitForFences(device, 1, &swapchain->fences[image_index],
true, ~0ull);

View file

@ -102,6 +102,8 @@ struct wsi_device {
VkPhysicalDevicePCIBusInfoPropertiesEXT pci_bus_info;
VkExternalSemaphoreHandleTypeFlags semaphore_export_handle_types;
bool supports_modifiers;
uint32_t maxImageDimension2D;
VkPresentModeKHR override_present_mode;
@ -209,6 +211,7 @@ struct wsi_device {
WSI_CB(GetPhysicalDeviceFormatProperties);
WSI_CB(GetPhysicalDeviceFormatProperties2KHR);
WSI_CB(GetPhysicalDeviceImageFormatProperties2);
WSI_CB(GetSemaphoreFdKHR);
WSI_CB(ResetFences);
WSI_CB(QueueSubmit);
WSI_CB(WaitForFences);

View file

@ -26,16 +26,221 @@
#include "util/macros.h"
#include "util/os_file.h"
#include "util/xmlconfig.h"
#include "vk_device.h"
#include "vk_format.h"
#include "vk_physical_device.h"
#include "vk_util.h"
#include "drm-uapi/drm_fourcc.h"
#include <errno.h>
#include <linux/dma-buf.h>
#include <linux/sync_file.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <xf86drm.h>
struct dma_buf_export_sync_file_wsi {
__u32 flags;
__s32 fd;
};
struct dma_buf_import_sync_file_wsi {
__u32 flags;
__s32 fd;
};
#define DMA_BUF_IOCTL_EXPORT_SYNC_FILE_WSI _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file_wsi)
#define DMA_BUF_IOCTL_IMPORT_SYNC_FILE_WSI _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file_wsi)
static VkResult
wsi_dma_buf_export_sync_file(int dma_buf_fd, int *sync_file_fd)
{
/* Don't keep trying an IOCTL that doesn't exist. */
static bool no_dma_buf_sync_file = false;
if (no_dma_buf_sync_file)
return VK_ERROR_FEATURE_NOT_PRESENT;
struct dma_buf_export_sync_file_wsi export = {
.flags = DMA_BUF_SYNC_RW,
.fd = -1,
};
int ret = drmIoctl(dma_buf_fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE_WSI, &export);
if (ret) {
if (errno == ENOTTY) {
no_dma_buf_sync_file = true;
return VK_ERROR_FEATURE_NOT_PRESENT;
} else {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
*sync_file_fd = export.fd;
return VK_SUCCESS;
}
static VkResult
wsi_dma_buf_import_sync_file(int dma_buf_fd, int sync_file_fd)
{
/* Don't keep trying an IOCTL that doesn't exist. */
static bool no_dma_buf_sync_file = false;
if (no_dma_buf_sync_file)
return VK_ERROR_FEATURE_NOT_PRESENT;
struct dma_buf_import_sync_file_wsi import = {
.flags = DMA_BUF_SYNC_RW,
.fd = sync_file_fd,
};
int ret = drmIoctl(dma_buf_fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE_WSI, &import);
if (ret) {
if (errno == ENOTTY) {
no_dma_buf_sync_file = true;
return VK_ERROR_FEATURE_NOT_PRESENT;
} else {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
return VK_SUCCESS;
}
static VkResult
prepare_signal_dma_buf_from_semaphore(struct wsi_swapchain *chain,
const struct wsi_image *image)
{
VkResult result;
if (!(chain->wsi->semaphore_export_handle_types &
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT))
return VK_ERROR_FEATURE_NOT_PRESENT;
int sync_file_fd = -1;
result = wsi_dma_buf_export_sync_file(image->dma_buf_fd, &sync_file_fd);
if (result != VK_SUCCESS)
return result;
result = wsi_dma_buf_import_sync_file(image->dma_buf_fd, sync_file_fd);
close(sync_file_fd);
if (result != VK_SUCCESS)
return result;
/* If we got here, all our checks pass. Create the actual semaphore */
const VkExportSemaphoreCreateInfo export_info = {
.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
};
const VkSemaphoreCreateInfo semaphore_info = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
.pNext = &export_info,
};
result = chain->wsi->CreateSemaphore(chain->device, &semaphore_info,
&chain->alloc,
&chain->dma_buf_semaphore);
if (result != VK_SUCCESS)
return result;
return VK_SUCCESS;
}
VkResult
wsi_prepare_signal_dma_buf_from_semaphore(struct wsi_swapchain *chain,
const struct wsi_image *image)
{
VkResult result;
/* We cache result - 1 in the swapchain */
if (unlikely(chain->signal_dma_buf_from_semaphore == 0)) {
result = prepare_signal_dma_buf_from_semaphore(chain, image);
assert(result <= 0);
chain->signal_dma_buf_from_semaphore = (int)result - 1;
} else {
result = (VkResult)(chain->signal_dma_buf_from_semaphore + 1);
}
return result;
}
VkResult
wsi_signal_dma_buf_from_semaphore(const struct wsi_swapchain *chain,
const struct wsi_image *image)
{
VkResult result;
const VkSemaphoreGetFdInfoKHR get_fd_info = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
.semaphore = chain->dma_buf_semaphore,
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
};
int sync_file_fd = -1;
result = chain->wsi->GetSemaphoreFdKHR(chain->device, &get_fd_info,
&sync_file_fd);
if (result != VK_SUCCESS)
return result;
result = wsi_dma_buf_import_sync_file(image->dma_buf_fd, sync_file_fd);
close(sync_file_fd);
return result;
}
static const struct vk_sync_type *
get_sync_file_sync_type(struct vk_device *device,
enum vk_sync_features req_features)
{
for (const struct vk_sync_type *const *t =
device->physical->supported_sync_types; *t; t++) {
if (req_features & ~(*t)->features)
continue;
if ((*t)->import_sync_file != NULL)
return *t;
}
return NULL;
}
VkResult
wsi_create_sync_for_dma_buf_wait(const struct wsi_swapchain *chain,
const struct wsi_image *image,
enum vk_sync_features req_features,
struct vk_sync **sync_out)
{
VK_FROM_HANDLE(vk_device, device, chain->device);
VkResult result;
const struct vk_sync_type *sync_type =
get_sync_file_sync_type(device, req_features);
if (sync_type == NULL)
return VK_ERROR_FEATURE_NOT_PRESENT;
int sync_file_fd = -1;
result = wsi_dma_buf_export_sync_file(image->dma_buf_fd, &sync_file_fd);
if (result != VK_SUCCESS)
return result;
struct vk_sync *sync = NULL;
result = vk_sync_create(device, sync_type, VK_SYNC_IS_SHAREABLE, 0, &sync);
if (result != VK_SUCCESS)
goto fail_close_sync_file;
result = vk_sync_import_sync_file(device, sync, sync_file_fd);
if (result != VK_SUCCESS)
goto fail_destroy_sync;
close(sync_file_fd);
*sync_out = sync;
return VK_SUCCESS;
fail_destroy_sync:
vk_sync_destroy(device, sync);
fail_close_sync_file:
close(sync_file_fd);
return result;
}
bool
wsi_common_drm_devices_equal(int fd_a, int fd_b)
{

View file

@ -25,6 +25,7 @@
#include "wsi_common.h"
#include "vulkan/runtime/vk_object.h"
#include "vulkan/runtime/vk_sync.h"
struct wsi_image;
struct wsi_swapchain;
@ -97,6 +98,9 @@ struct wsi_swapchain {
VkSemaphore* buffer_blit_semaphores;
VkPresentModeKHR present_mode;
int signal_dma_buf_from_semaphore;
VkSemaphore dma_buf_semaphore;
struct wsi_image_info image_info;
uint32_t image_count;
@ -193,6 +197,17 @@ void
wsi_destroy_image(const struct wsi_swapchain *chain,
struct wsi_image *image);
VkResult
wsi_prepare_signal_dma_buf_from_semaphore(struct wsi_swapchain *chain,
const struct wsi_image *image);
VkResult
wsi_signal_dma_buf_from_semaphore(const struct wsi_swapchain *chain,
const struct wsi_image *image);
VkResult
wsi_create_sync_for_dma_buf_wait(const struct wsi_swapchain *chain,
const struct wsi_image *image,
enum vk_sync_features sync_features,
struct vk_sync **sync_out);
struct wsi_interface {
VkResult (*get_support)(VkIcdSurfaceBase *surface,