vulkan: Win32 sync import/export support

Acked-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22879>
This commit is contained in:
Jesse Natalie 2023-05-04 21:06:41 -07:00 committed by Marge Bot
parent 952a523abb
commit c9146794d4
3 changed files with 244 additions and 13 deletions

View file

@ -25,7 +25,9 @@
#include "util/os_time.h"
#ifndef _WIN32
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
@ -47,6 +49,12 @@ vk_sync_semaphore_import_types(const struct vk_sync_type *type,
if (type->export_sync_file && semaphore_type == VK_SEMAPHORE_TYPE_BINARY)
handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
if (type->import_win32_handle) {
handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT;
if (type->features & VK_SYNC_FEATURE_TIMELINE)
handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT;
}
return handle_types;
}
@ -62,6 +70,12 @@ vk_sync_semaphore_export_types(const struct vk_sync_type *type,
if (type->export_sync_file && semaphore_type == VK_SEMAPHORE_TYPE_BINARY)
handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
if (type->export_win32_handle) {
handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT;
if (type->features & VK_SYNC_FEATURE_TIMELINE)
handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT;
}
return handle_types;
}
@ -184,6 +198,20 @@ vk_common_CreateSemaphore(VkDevice _device,
return result;
}
#ifdef _WIN32
const VkExportSemaphoreWin32HandleInfoKHR *export_win32 =
vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR);
if (export_win32) {
result = vk_sync_set_win32_export_params(device, &semaphore->permanent, export_win32->pAttributes,
export_win32->dwAccess, export_win32->name);
if (result != VK_SUCCESS) {
vk_sync_finish(device, &semaphore->permanent);
vk_object_free(device, pAllocator, semaphore);
return result;
}
}
#endif
*pSemaphore = vk_semaphore_to_handle(semaphore);
return VK_SUCCESS;
@ -247,18 +275,23 @@ vk_common_GetPhysicalDeviceExternalSemaphoreProperties(
VkExternalSemaphoreHandleTypeFlagBits export =
vk_sync_semaphore_export_types(sync_type, semaphore_type);
if (handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
const struct vk_sync_type *opaque_sync_type =
get_semaphore_sync_type(pdevice, semaphore_type,
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
VkExternalSemaphoreHandleTypeFlagBits opaque_types[] = {
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT,
};
for (uint32_t i = 0; i < ARRAY_SIZE(opaque_types); ++i) {
if (handle_type != opaque_types[i]) {
const struct vk_sync_type *opaque_sync_type =
get_semaphore_sync_type(pdevice, semaphore_type, opaque_types[i]);
/* If we're a different vk_sync_type than the one selected when only
* OPAQUE_FD is set, then we can't import/export OPAQUE_FD. Put
* differently, there can only be one OPAQUE_FD sync type.
*/
if (sync_type != opaque_sync_type) {
import &= ~VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
export &= ~VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
/* If we're a different vk_sync_type than the one selected when only
* an opaque type is set, then we can't import/export that opaque type. Put
* differently, there can only be one OPAQUE_FD/WIN32_HANDLE sync type.
*/
if (sync_type != opaque_sync_type) {
import &= ~opaque_types[i];
export &= ~opaque_types[i];
}
}
}
@ -380,7 +413,123 @@ vk_common_SignalSemaphore(VkDevice _device,
return VK_SUCCESS;
}
#ifndef _WIN32
#ifdef _WIN32
VKAPI_ATTR VkResult VKAPI_CALL
vk_common_ImportSemaphoreWin32HandleKHR(VkDevice _device,
const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo)
{
VK_FROM_HANDLE(vk_device, device, _device);
VK_FROM_HANDLE(vk_semaphore, semaphore, pImportSemaphoreWin32HandleInfo->semaphore);
assert(pImportSemaphoreWin32HandleInfo->sType ==
VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR);
const HANDLE handle = pImportSemaphoreWin32HandleInfo->handle;
const wchar_t *name = pImportSemaphoreWin32HandleInfo->name;
const VkExternalSemaphoreHandleTypeFlagBits handle_type =
pImportSemaphoreWin32HandleInfo->handleType;
struct vk_sync *temporary = NULL, *sync;
if (pImportSemaphoreWin32HandleInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
/* From the Vulkan 1.2.194 spec:
*
* VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-03322
*
* "If flags contains VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, the
* VkSemaphoreTypeCreateInfo::semaphoreType field of the semaphore
* from which handle or name was exported must not be
* VK_SEMAPHORE_TYPE_TIMELINE"
*/
if (unlikely(semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE)) {
return vk_errorf(device, VK_ERROR_UNKNOWN,
"Cannot temporarily import into a timeline "
"semaphore");
}
const struct vk_sync_type *sync_type =
get_semaphore_sync_type(device->physical, semaphore->type, handle_type);
VkResult result = vk_sync_create(device, sync_type, 0 /* flags */,
0 /* initial_value */, &temporary);
if (result != VK_SUCCESS)
return result;
sync = temporary;
} else {
sync = &semaphore->permanent;
}
assert(handle_type &
vk_sync_semaphore_handle_types(sync->type, semaphore->type));
VkResult result;
switch (pImportSemaphoreWin32HandleInfo->handleType) {
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT:
result = vk_sync_import_win32_handle(device, sync, handle, name);
break;
default:
result = vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE);
}
if (result != VK_SUCCESS) {
if (temporary != NULL)
vk_sync_destroy(device, temporary);
return result;
}
/* From a spec correctness point of view, we could probably replace the
* semaphore's temporary payload with the new vk_sync at the top. However,
* we choose to be nice to applications and only replace the semaphore if
* the import succeeded.
*/
if (temporary) {
vk_semaphore_reset_temporary(device, semaphore);
semaphore->temporary = temporary;
}
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL
vk_common_GetSemaphoreWin32HandleKHR(VkDevice _device,
const VkSemaphoreGetWin32HandleInfoKHR *pGetWin32HandleInfo,
HANDLE *pHandle)
{
VK_FROM_HANDLE(vk_device, device, _device);
VK_FROM_HANDLE(vk_semaphore, semaphore, pGetWin32HandleInfo->semaphore);
assert(pGetWin32HandleInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR);
struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore);
VkResult result;
switch (pGetWin32HandleInfo->handleType) {
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT:
result = vk_sync_export_win32_handle(device, sync, pHandle);
if (result != VK_SUCCESS)
return result;
break;
default:
unreachable("Invalid semaphore export handle type");
}
/* From the Vulkan 1.2.194 spec:
*
* "Export operations have the same transference as the specified
* handle types import operations. [...] If the semaphore was using
* a temporarily imported payload, the semaphores prior permanent
* payload will be restored."
*/
vk_semaphore_reset_temporary(device, semaphore);
return VK_SUCCESS;
}
#else
VKAPI_ATTR VkResult VKAPI_CALL
vk_common_ImportSemaphoreFdKHR(VkDevice _device,

View file

@ -400,3 +400,47 @@ vk_sync_export_sync_file(struct vk_device *device,
assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
return sync->type->export_sync_file(device, sync, sync_file);
}
VkResult
vk_sync_import_win32_handle(struct vk_device *device,
struct vk_sync *sync,
void *handle,
const wchar_t *name)
{
VkResult result = sync->type->import_win32_handle(device, sync, handle, name);
if (unlikely(result != VK_SUCCESS))
return result;
sync->flags |= VK_SYNC_IS_SHAREABLE |
VK_SYNC_IS_SHARED;
return VK_SUCCESS;
}
VkResult
vk_sync_export_win32_handle(struct vk_device *device,
struct vk_sync *sync,
void **handle)
{
assert(sync->flags & VK_SYNC_IS_SHAREABLE);
VkResult result = sync->type->export_win32_handle(device, sync, handle);
if (unlikely(result != VK_SUCCESS))
return result;
sync->flags |= VK_SYNC_IS_SHARED;
return VK_SUCCESS;
}
VkResult
vk_sync_set_win32_export_params(struct vk_device *device,
struct vk_sync *sync,
const void *security_attributes,
uint32_t access,
const wchar_t *name)
{
assert(sync->flags & VK_SYNC_IS_SHARED);
return sync->type->set_win32_export_params(device, sync, security_attributes, access, name);
}

View file

@ -272,6 +272,29 @@ struct vk_sync_type {
VkResult (*export_sync_file)(struct vk_device *device,
struct vk_sync *sync,
int *sync_file);
/** Permanently imports the given handle or name into this vk_sync
*
* This replaces the guts of the given vk_sync with whatever is in the object.
* In a sense, this vk_sync now aliases whatever vk_sync the handle was
* exported from.
*/
VkResult (*import_win32_handle)(struct vk_device *device,
struct vk_sync *sync,
void *handle,
const wchar_t *name);
/** Export the guts of this vk_sync to a handle and/or name */
VkResult (*export_win32_handle)(struct vk_device *device,
struct vk_sync *sync,
void **handle);
/** Vulkan puts these as creation params instead of export params */
VkResult (*set_win32_export_params)(struct vk_device *device,
struct vk_sync *sync,
const void *security_attributes,
uint32_t access,
const wchar_t *name);
};
enum vk_sync_flags {
@ -361,6 +384,21 @@ VkResult MUST_CHECK vk_sync_export_sync_file(struct vk_device *device,
struct vk_sync *sync,
int *sync_file);
VkResult MUST_CHECK vk_sync_import_win32_handle(struct vk_device *device,
struct vk_sync *sync,
void *handle,
const wchar_t *name);
VkResult MUST_CHECK vk_sync_export_win32_handle(struct vk_device *device,
struct vk_sync *sync,
void **handle);
VkResult MUST_CHECK vk_sync_set_win32_export_params(struct vk_device *device,
struct vk_sync *sync,
const void *security_attributes,
uint32_t access,
const wchar_t *name);
VkResult MUST_CHECK vk_sync_move(struct vk_device *device,
struct vk_sync *dst,
struct vk_sync *src);