summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Natalie <jenatali@microsoft.com>2023-05-04 12:36:05 -0700
committerMarge Bot <emma+marge@anholt.net>2023-05-15 17:14:20 +0000
commited25ea1bc9e062a0ae048132a72dd5f7a31d8a00 (patch)
treed01817ccf197dd3c2f9686cdb5f8e9965965c51a
parentfb613407905de9aea2db685c009f114d902229ab (diff)
downloadmesa-ed25ea1bc9e062a0ae048132a72dd5f7a31d8a00.tar.gz
dzn: External Win32 memory extension
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22879>
-rw-r--r--src/microsoft/vulkan/dzn_abi_helper.h12
-rw-r--r--src/microsoft/vulkan/dzn_device.c453
-rw-r--r--src/microsoft/vulkan/dzn_image.c5
-rw-r--r--src/microsoft/vulkan/dzn_private.h7
4 files changed, 421 insertions, 56 deletions
diff --git a/src/microsoft/vulkan/dzn_abi_helper.h b/src/microsoft/vulkan/dzn_abi_helper.h
index e3523d0fe64..67eb0087cf9 100644
--- a/src/microsoft/vulkan/dzn_abi_helper.h
+++ b/src/microsoft/vulkan/dzn_abi_helper.h
@@ -84,6 +84,18 @@ dzn_ID3D12Resource_GetDesc(ID3D12Resource *res)
return ret;
}
+static inline D3D12_HEAP_DESC
+dzn_ID3D12Heap_GetDesc(ID3D12Heap *heap)
+{
+ D3D12_HEAP_DESC ret;
+#ifdef _WIN32
+ ID3D12Heap_GetDesc(heap, &ret);
+#else
+ ret = ID3D12Heap_GetDesc(heap);
+#endif
+ return ret;
+}
+
static inline D3D12_CPU_DESCRIPTOR_HANDLE
dzn_ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
diff --git a/src/microsoft/vulkan/dzn_device.c b/src/microsoft/vulkan/dzn_device.c
index 44d99e903f9..5e45ca8fe6e 100644
--- a/src/microsoft/vulkan/dzn_device.c
+++ b/src/microsoft/vulkan/dzn_device.c
@@ -71,6 +71,13 @@
#define MAX_TIER2_MEMORY_TYPES 3
+const VkExternalMemoryHandleTypeFlags opaque_external_flag =
+#ifdef _WIN32
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
+#else
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+#endif
+
static const struct vk_instance_extension_table instance_extensions = {
.KHR_get_physical_device_properties2 = true,
.KHR_device_group_creation = true,
@@ -108,6 +115,10 @@ dzn_physical_device_get_extensions(struct dzn_physical_device *pdev)
.KHR_draw_indirect_count = true,
.KHR_driver_properties = true,
.KHR_dynamic_rendering = true,
+ .KHR_external_memory = true,
+#ifdef _WIN32
+ .KHR_external_memory_win32 = true,
+#endif
.KHR_image_format_list = true,
.KHR_imageless_framebuffer = true,
.KHR_get_memory_requirements2 = true,
@@ -580,6 +591,11 @@ dzn_physical_device_init_memory(struct dzn_physical_device *pdev)
mem->memoryHeaps[0].flags |= VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
mem->memoryTypes[0].propertyFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
mem->memoryTypes[1].propertyFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ /* Get one non-CPU-accessible memory type for shared resources to use */
+ mem->memoryTypes[mem->memoryTypeCount++] = (VkMemoryType){
+ .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
+ .heapIndex = 0,
+ };
}
assert(mem->memoryTypeCount <= MAX_TIER2_MEMORY_TYPES);
@@ -621,21 +637,26 @@ dzn_physical_device_get_heap_flags_for_mem_type(const struct dzn_physical_device
uint32_t
dzn_physical_device_get_mem_type_mask_for_resource(const struct dzn_physical_device *pdev,
- const D3D12_RESOURCE_DESC *desc)
+ const D3D12_RESOURCE_DESC *desc,
+ bool shared)
{
- if (pdev->options.ResourceHeapTier > D3D12_RESOURCE_HEAP_TIER_1)
+ if (pdev->options.ResourceHeapTier > D3D12_RESOURCE_HEAP_TIER_1 && !shared)
return (1u << pdev->memory.memoryTypeCount) - 1;
- D3D12_HEAP_FLAGS deny_flag;
- if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
- deny_flag = D3D12_HEAP_FLAG_DENY_BUFFERS;
- else if (desc->Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
- deny_flag = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
- else
- deny_flag = D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
+ D3D12_HEAP_FLAGS deny_flag = D3D12_HEAP_FLAG_NONE;
+ if (pdev->options.ResourceHeapTier <= D3D12_RESOURCE_HEAP_TIER_1) {
+ if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
+ deny_flag = D3D12_HEAP_FLAG_DENY_BUFFERS;
+ else if (desc->Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
+ deny_flag = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
+ else
+ deny_flag = D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
+ }
uint32_t mask = 0;
for (unsigned i = 0; i < pdev->memory.memoryTypeCount; ++i) {
+ if (shared && (pdev->memory.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
+ continue;
if ((pdev->heap_flags_for_mem_type[i] & deny_flag) == D3D12_HEAP_FLAG_NONE)
mask |= (1 << i);
}
@@ -936,9 +957,50 @@ dzn_physical_device_get_image_format_properties(struct dzn_physical_device *pdev
}
}
- /* TODO: support image import */
- if (external_info && external_info->handleType != 0)
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ if (external_info && external_info->handleType != 0) {
+ const VkExternalMemoryHandleTypeFlags d3d12_resource_handle_types =
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | opaque_external_flag;
+ const VkExternalMemoryHandleTypeFlags d3d11_texture_handle_types =
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | d3d12_resource_handle_types;
+ const VkExternalMemoryFeatureFlags import_export_feature_flags =
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
+ const VkExternalMemoryFeatureFlags dedicated_feature_flags =
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | import_export_feature_flags;
+
+ switch (external_info->handleType) {
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
+ external_props->externalMemoryProperties.compatibleHandleTypes = d3d11_texture_handle_types;
+ external_props->externalMemoryProperties.exportFromImportedHandleTypes = d3d11_texture_handle_types;
+ external_props->externalMemoryProperties.externalMemoryFeatures = dedicated_feature_flags;
+ break;
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
+ external_props->externalMemoryProperties.compatibleHandleTypes = d3d12_resource_handle_types;
+ external_props->externalMemoryProperties.exportFromImportedHandleTypes = d3d12_resource_handle_types;
+ external_props->externalMemoryProperties.externalMemoryFeatures = dedicated_feature_flags;
+ break;
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
+ external_props->externalMemoryProperties.compatibleHandleTypes =
+ external_props->externalMemoryProperties.exportFromImportedHandleTypes =
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | opaque_external_flag;
+ external_props->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
+ break;
+#ifdef _WIN32
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+#else
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
+#endif
+ external_props->externalMemoryProperties.compatibleHandleTypes = d3d11_texture_handle_types;
+ external_props->externalMemoryProperties.exportFromImportedHandleTypes = d3d11_texture_handle_types;
+ external_props->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
+ break;
+ default:
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ /* Linear textures not supported, but there's nothing else we can deduce from just a handle type */
+ if (info->tiling != VK_IMAGE_TILING_OPTIMAL)
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
if (info->tiling != VK_IMAGE_TILING_OPTIMAL &&
(usage & ~(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT)))
@@ -1143,10 +1205,38 @@ dzn_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
VkExternalBufferProperties *pExternalBufferProperties)
{
- pExternalBufferProperties->externalMemoryProperties =
- (VkExternalMemoryProperties) {
- .compatibleHandleTypes = (VkExternalMemoryHandleTypeFlags)pExternalBufferInfo->handleType,
- };
+ const VkExternalMemoryHandleTypeFlags d3d12_resource_handle_types =
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | opaque_external_flag;
+ const VkExternalMemoryFeatureFlags import_export_feature_flags =
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
+ const VkExternalMemoryFeatureFlags dedicated_feature_flags =
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | import_export_feature_flags;
+ switch (pExternalBufferInfo->handleType) {
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
+ pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = d3d12_resource_handle_types;
+ pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = d3d12_resource_handle_types;
+ pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = dedicated_feature_flags;
+ break;
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
+ pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes =
+ pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes =
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | opaque_external_flag;
+ pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
+ break;
+#ifdef _WIN32
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+#else
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
+#endif
+ pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes =
+ pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes =
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | d3d12_resource_handle_types;
+ pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
+ break;
+ default:
+ pExternalBufferProperties->externalMemoryProperties = (VkExternalMemoryProperties){ 0 };
+ break;
+ }
}
VkResult
@@ -2562,10 +2652,38 @@ dzn_device_memory_destroy(struct dzn_device_memory *mem,
if (mem->dedicated_res)
ID3D12Resource_Release(mem->dedicated_res);
+#ifdef _WIN32
+ if (mem->export_handle)
+ CloseHandle(mem->export_handle);
+#else
+ if ((intptr_t)mem->export_handle >= 0)
+ close((int)(intptr_t)mem->export_handle);
+#endif
+
vk_object_base_finish(&mem->base);
vk_free2(&device->vk.alloc, pAllocator, mem);
}
+static D3D12_HEAP_PROPERTIES
+deduce_heap_properties_from_memory(struct dzn_physical_device *pdevice,
+ const VkMemoryType *mem_type)
+{
+ D3D12_HEAP_PROPERTIES properties = { .Type = D3D12_HEAP_TYPE_CUSTOM };
+ properties.MemoryPoolPreference =
+ ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&
+ !pdevice->architecture.UMA) ?
+ D3D12_MEMORY_POOL_L1 : D3D12_MEMORY_POOL_L0;
+ if ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ||
+ ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && pdevice->architecture.CacheCoherentUMA)) {
+ properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
+ } else if (mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+ properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE;
+ } else {
+ properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE;
+ }
+ return properties;
+}
+
static VkResult
dzn_device_memory_create(struct dzn_device *device,
const VkMemoryAllocateInfo *pAllocateInfo,
@@ -2578,16 +2696,63 @@ dzn_device_memory_create(struct dzn_device *device,
const struct dzn_buffer *buffer = NULL;
const struct dzn_image *image = NULL;
+ VkExternalMemoryHandleTypeFlags export_flags = 0;
+ HANDLE import_handle = NULL;
+ bool imported_from_d3d11 = false;
+#ifdef _WIN32
+ const wchar_t *import_name = NULL;
+ const VkExportMemoryWin32HandleInfoKHR *win32_export = NULL;
+#endif
vk_foreach_struct_const(ext, pAllocateInfo->pNext) {
switch (ext->sType) {
case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: {
- UNUSED const VkExportMemoryAllocateInfo *exp =
+ const VkExportMemoryAllocateInfo *exp =
(const VkExportMemoryAllocateInfo *)ext;
- // TODO: support export
- assert(exp->handleTypes == 0);
+ export_flags = exp->handleTypes;
break;
}
+#ifdef _WIN32
+ case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR: {
+ const VkImportMemoryWin32HandleInfoKHR *imp =
+ (const VkImportMemoryWin32HandleInfoKHR *)ext;
+ switch (imp->handleType) {
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
+ imported_from_d3d11 = true;
+ FALLTHROUGH;
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
+ break;
+ default:
+ return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
+ }
+ import_handle = imp->handle;
+ import_name = imp->name;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR:
+ win32_export = (const VkExportMemoryWin32HandleInfoKHR *)ext;
+ break;
+#else
+ case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR: {
+ const VkImportMemoryFdInfoKHR *imp =
+ (const VkImportMemoryFdInfoKHR *)ext;
+ switch (imp->handleType) {
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
+ imported_from_d3d11 = true;
+ FALLTHROUGH;
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
+ break;
+ default:
+ return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
+ }
+ import_handle = (HANDLE)(intptr_t)imp->handle;
+ break;
+ }
+#endif
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: {
const VkMemoryDedicatedAllocateInfo *dedicated =
(const VkMemoryDedicatedAllocateInfo *)ext;
@@ -2626,6 +2791,17 @@ dzn_device_memory_create(struct dzn_device *device,
if (mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
image = NULL;
+ VkExternalMemoryHandleTypeFlags valid_flags =
+ opaque_external_flag |
+ (buffer || image ?
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT :
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT);
+ if (image && imported_from_d3d11)
+ valid_flags |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
+
+ if (export_flags & ~valid_flags)
+ return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
+
struct dzn_device_memory *mem =
vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*mem), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
@@ -2633,6 +2809,9 @@ dzn_device_memory_create(struct dzn_device *device,
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
vk_object_base_init(&device->vk, &mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY);
+#ifndef _WIN32
+ mem->export_handle = (HANDLE)(intptr_t)-1;
+#endif
/* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */
assert(pAllocateInfo->allocationSize > 0);
@@ -2643,21 +2822,78 @@ dzn_device_memory_create(struct dzn_device *device,
if (!image && !buffer)
heap_desc.Flags =
dzn_physical_device_get_heap_flags_for_mem_type(pdevice, pAllocateInfo->memoryTypeIndex);
- heap_desc.Properties.Type = D3D12_HEAP_TYPE_CUSTOM;
- heap_desc.Properties.MemoryPoolPreference =
- ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&
- !pdevice->architecture.UMA) ?
- D3D12_MEMORY_POOL_L1 : D3D12_MEMORY_POOL_L0;
- if ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ||
- ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && pdevice->architecture.CacheCoherentUMA)) {
- heap_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
- } else if (mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
- heap_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE;
- } else {
- heap_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE;
+ heap_desc.Properties = deduce_heap_properties_from_memory(pdevice, mem_type);
+ if (export_flags) {
+ heap_desc.Flags |= D3D12_HEAP_FLAG_SHARED;
+ assert(heap_desc.Properties.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE);
+ }
+
+ VkResult error = VK_ERROR_OUT_OF_DEVICE_MEMORY;
+
+#ifdef _WIN32
+ HANDLE handle_from_name = NULL;
+ if (import_name) {
+ if (FAILED(ID3D12Device_OpenSharedHandleByName(device->dev, import_name, GENERIC_ALL, &handle_from_name))) {
+ error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ goto cleanup;
+ }
+ import_handle = handle_from_name;
}
+#endif
- if (image) {
+ if (import_handle) {
+ error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ if (image || buffer) {
+ if (FAILED(ID3D12Device_OpenSharedHandle(device->dev, import_handle, &IID_ID3D12Resource, (void **)&mem->dedicated_res)))
+ goto cleanup;
+
+ /* Verify compatibility */
+ D3D12_RESOURCE_DESC desc = dzn_ID3D12Resource_GetDesc(mem->dedicated_res);
+ D3D12_HEAP_PROPERTIES opened_props = { 0 };
+ D3D12_HEAP_FLAGS opened_flags = 0;
+ ID3D12Resource_GetHeapProperties(mem->dedicated_res, &opened_props, &opened_flags);
+ if (opened_props.Type != D3D12_HEAP_TYPE_CUSTOM)
+ opened_props = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, opened_props.Type);
+
+ /* Don't validate format, cast lists aren't reflectable so it could be valid */
+ if (image) {
+ if (desc.Dimension != image->desc.Dimension ||
+ desc.MipLevels != image->desc.MipLevels ||
+ desc.Width != image->desc.Width ||
+ desc.Height != image->desc.Height ||
+ desc.DepthOrArraySize != image->desc.DepthOrArraySize ||
+ (image->desc.Flags & ~desc.Flags) ||
+ desc.SampleDesc.Count != image->desc.SampleDesc.Count)
+ goto cleanup;
+ } else if (desc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
+ desc.Width != buffer->desc.Width ||
+ buffer->desc.Flags & ~(desc.Flags))
+ goto cleanup;
+ if (opened_props.CPUPageProperty != heap_desc.Properties.CPUPageProperty ||
+ opened_props.MemoryPoolPreference != heap_desc.Properties.MemoryPoolPreference)
+ goto cleanup;
+ if ((heap_desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS) && desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
+ goto cleanup;
+ if ((heap_desc.Flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES) && (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
+ goto cleanup;
+ else if ((heap_desc.Flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) && !(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
+ goto cleanup;
+ } else {
+ if (FAILED(ID3D12Device_OpenSharedHandle(device->dev, import_handle, &IID_ID3D12Heap, (void **)&mem->heap)))
+ goto cleanup;
+
+ D3D12_HEAP_DESC desc = dzn_ID3D12Heap_GetDesc(mem->heap);
+ if (desc.Properties.Type != D3D12_HEAP_TYPE_CUSTOM)
+ desc.Properties = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, desc.Properties.Type);
+
+ if (desc.Alignment < heap_desc.Alignment ||
+ desc.SizeInBytes < heap_desc.SizeInBytes ||
+ (heap_desc.Flags & ~desc.Flags) ||
+ desc.Properties.CPUPageProperty != heap_desc.Properties.CPUPageProperty ||
+ desc.Properties.MemoryPoolPreference != heap_desc.Properties.MemoryPoolPreference)
+ goto cleanup;
+ }
+ } else if (image) {
if (device->dev10 && image->castable_format_count > 0) {
D3D12_RESOURCE_DESC1 desc = {
.Dimension = image->desc.Dimension,
@@ -2678,36 +2914,28 @@ dzn_device_memory_create(struct dzn_device *device,
image->castable_format_count,
image->castable_formats,
&IID_ID3D12Resource,
- (void **)&mem->dedicated_res))) {
- dzn_device_memory_destroy(mem, pAllocator);
- return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
- }
+ (void **)&mem->dedicated_res)))
+ goto cleanup;
} else if (FAILED(ID3D12Device1_CreateCommittedResource(device->dev, &heap_desc.Properties,
heap_desc.Flags, &image->desc,
D3D12_RESOURCE_STATE_COMMON,
NULL,
&IID_ID3D12Resource,
- (void **)&mem->dedicated_res))) {
- dzn_device_memory_destroy(mem, pAllocator);
- return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
- }
+ (void **)&mem->dedicated_res)))
+ goto cleanup;
} else if (buffer) {
if (FAILED(ID3D12Device1_CreateCommittedResource(device->dev, &heap_desc.Properties,
heap_desc.Flags, &buffer->desc,
D3D12_RESOURCE_STATE_COMMON,
NULL,
&IID_ID3D12Resource,
- (void **)&mem->dedicated_res))) {
- dzn_device_memory_destroy(mem, pAllocator);
- return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
- }
+ (void **)&mem->dedicated_res)))
+ goto cleanup;
} else {
if (FAILED(ID3D12Device1_CreateHeap(device->dev, &heap_desc,
&IID_ID3D12Heap,
- (void **)&mem->heap))) {
- dzn_device_memory_destroy(mem, pAllocator);
- return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
- }
+ (void **)&mem->heap)))
+ goto cleanup;
}
if ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
@@ -2734,15 +2962,38 @@ dzn_device_memory_create(struct dzn_device *device,
NULL,
&IID_ID3D12Resource,
(void **)&mem->map_res);
- if (FAILED(hr)) {
- dzn_device_memory_destroy(mem, pAllocator);
- return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
- }
+ if (FAILED(hr))
+ goto cleanup;
}
}
+ if (export_flags) {
+ error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ ID3D12DeviceChild *shareable = mem->heap ? (void *)mem->heap : (void *)mem->dedicated_res;
+#ifdef _WIN32
+ const SECURITY_ATTRIBUTES *pAttributes = win32_export ? win32_export->pAttributes : NULL;
+ DWORD dwAccess = win32_export ? win32_export->dwAccess : GENERIC_ALL;
+ const wchar_t *name = win32_export ? win32_export->name : NULL;
+#else
+ const SECURITY_ATTRIBUTES *pAttributes = NULL;
+ DWORD dwAccess = GENERIC_ALL;
+ const wchar_t *name = NULL;
+#endif
+ if (FAILED(ID3D12Device_CreateSharedHandle(device->dev, shareable, pAttributes,
+ dwAccess, name, &mem->export_handle)))
+ goto cleanup;
+ }
+
*out = dzn_device_memory_to_handle(mem);
return VK_SUCCESS;
+
+cleanup:
+#ifdef _WIN32
+ if (handle_from_name)
+ CloseHandle(handle_from_name);
+#endif
+ dzn_device_memory_destroy(mem, pAllocator);
+ return vk_error(device, error);
}
VKAPI_ATTR VkResult VKAPI_CALL
@@ -2939,6 +3190,11 @@ dzn_buffer_create(struct dzn_device *device,
if (device->bindless)
mtx_init(&buf->bindless_view_lock, mtx_plain);
+ const VkExternalMemoryBufferCreateInfo *external_info =
+ vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_BUFFER_CREATE_INFO);
+ if (external_info && external_info->handleTypes != 0)
+ buf->shared = true;
+
*out = dzn_buffer_to_handle(buf);
return VK_SUCCESS;
}
@@ -3089,7 +3345,7 @@ dzn_GetBufferMemoryRequirements2(VkDevice dev,
pMemoryRequirements->memoryRequirements.size = size;
pMemoryRequirements->memoryRequirements.alignment = alignment;
pMemoryRequirements->memoryRequirements.memoryTypeBits =
- dzn_physical_device_get_mem_type_mask_for_resource(pdev, &buffer->desc);
+ dzn_physical_device_get_mem_type_mask_for_resource(pdev, &buffer->desc, buffer->shared);
vk_foreach_struct(ext, pMemoryRequirements->pNext) {
switch (ext->sType) {
@@ -3537,3 +3793,94 @@ dzn_GetDeviceMemoryOpaqueCaptureAddress(VkDevice device,
{
return 0;
}
+
+#ifdef _WIN32
+VKAPI_ATTR VkResult VKAPI_CALL
+dzn_GetMemoryWin32HandleKHR(VkDevice device,
+ const VkMemoryGetWin32HandleInfoKHR *pGetWin32HandleInfo,
+ HANDLE *pHandle)
+{
+ VK_FROM_HANDLE(dzn_device_memory, mem, pGetWin32HandleInfo->memory);
+ if (!mem->export_handle)
+ return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
+
+ switch (pGetWin32HandleInfo->handleType) {
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
+ if (!DuplicateHandle(GetCurrentProcess(), mem->export_handle, GetCurrentProcess(), pHandle,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+ return VK_SUCCESS;
+ default:
+ return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
+ }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+dzn_GetMemoryWin32HandlePropertiesKHR(VkDevice _device,
+ VkExternalMemoryHandleTypeFlagBits handleType,
+ HANDLE handle,
+ VkMemoryWin32HandlePropertiesKHR *pMemoryWin32HandleProperties)
+{
+ VK_FROM_HANDLE(dzn_device, device, _device);
+ IUnknown *opened_object;
+ if (FAILED(ID3D12Device_OpenSharedHandle(device->dev, handle, &IID_IUnknown, (void **)&opened_object)))
+ return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
+
+ VkResult result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ ID3D12Resource *res = NULL;
+ ID3D12Heap *heap = NULL;
+ struct dzn_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk);
+
+ switch (handleType) {
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+ (void)IUnknown_QueryInterface(opened_object, &IID_ID3D12Resource, (void **)&res);
+ (void)IUnknown_QueryInterface(opened_object, &IID_ID3D12Heap, (void **)&heap);
+ break;
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
+ (void)IUnknown_QueryInterface(opened_object, &IID_ID3D12Resource, (void **)&res);
+ break;
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
+ (void)IUnknown_QueryInterface(opened_object, &IID_ID3D12Heap, (void **)&heap);
+ break;
+ default:
+ goto cleanup;
+ }
+ if (!res && !heap)
+ goto cleanup;
+
+ D3D12_HEAP_DESC heap_desc;
+ if (res)
+ ID3D12Resource_GetHeapProperties(res, &heap_desc.Properties, &heap_desc.Flags);
+ else
+ heap_desc = dzn_ID3D12Heap_GetDesc(heap);
+ if (heap_desc.Properties.Type != D3D12_HEAP_TYPE_CUSTOM)
+ heap_desc.Properties = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, heap_desc.Properties.Type);
+
+ for (uint32_t i = 0; i < pdev->memory.memoryTypeCount; ++i) {
+ const VkMemoryType *mem_type = &pdev->memory.memoryTypes[i];
+ D3D12_HEAP_PROPERTIES required_props = deduce_heap_properties_from_memory(pdev, mem_type);
+ if (heap_desc.Properties.CPUPageProperty != required_props.CPUPageProperty ||
+ heap_desc.Properties.MemoryPoolPreference != required_props.MemoryPoolPreference)
+ continue;
+
+ D3D12_HEAP_FLAGS required_flags = dzn_physical_device_get_heap_flags_for_mem_type(pdev, i);
+ if ((heap_desc.Flags & required_flags) != required_flags)
+ continue;
+
+ pMemoryWin32HandleProperties->memoryTypeBits |= (1 << i);
+ }
+ result = VK_SUCCESS;
+
+cleanup:
+ IUnknown_Release(opened_object);
+ if (res)
+ ID3D12Resource_Release(res);
+ if (heap)
+ ID3D12Heap_Release(heap);
+ return result;
+}
+#endif
diff --git a/src/microsoft/vulkan/dzn_image.c b/src/microsoft/vulkan/dzn_image.c
index 95793d2476c..18622360e06 100644
--- a/src/microsoft/vulkan/dzn_image.c
+++ b/src/microsoft/vulkan/dzn_image.c
@@ -882,7 +882,7 @@ dzn_GetImageMemoryRequirements2(VkDevice _device,
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
VkMemoryDedicatedRequirements *requirements =
(VkMemoryDedicatedRequirements *)ext;
- requirements->requiresDedicatedAllocation = false;
+ requirements->requiresDedicatedAllocation = image->vk.external_handle_types != 0;
requirements->prefersDedicatedAllocation = requirements->requiresDedicatedAllocation ||
image->vk.tiling == VK_IMAGE_TILING_OPTIMAL;
break;
@@ -911,7 +911,8 @@ dzn_GetImageMemoryRequirements2(VkDevice _device,
.size = info.SizeInBytes,
.alignment = info.Alignment,
.memoryTypeBits =
- dzn_physical_device_get_mem_type_mask_for_resource(pdev, &image->desc),
+ dzn_physical_device_get_mem_type_mask_for_resource(pdev, &image->desc,
+ image->vk.external_handle_types != 0),
};
/*
diff --git a/src/microsoft/vulkan/dzn_private.h b/src/microsoft/vulkan/dzn_private.h
index a5b312fb544..c4f903e2b35 100644
--- a/src/microsoft/vulkan/dzn_private.h
+++ b/src/microsoft/vulkan/dzn_private.h
@@ -233,7 +233,8 @@ dzn_physical_device_get_format_support(struct dzn_physical_device *pdev,
uint32_t
dzn_physical_device_get_mem_type_mask_for_resource(const struct dzn_physical_device *pdev,
- const D3D12_RESOURCE_DESC *desc);
+ const D3D12_RESOURCE_DESC *desc,
+ bool shared);
enum dxil_shader_model
dzn_get_shader_model(const struct dzn_physical_device *pdev);
@@ -342,6 +343,9 @@ struct dzn_device_memory {
VkDeviceSize map_size;
void *map;
+
+ /* If the resource is exportable, this is the pre-created handle for that */
+ HANDLE export_handle;
};
enum dzn_cmd_bindpoint_dirty {
@@ -1135,6 +1139,7 @@ struct dzn_buffer {
VkBufferCreateFlags create_flags;
VkBufferUsageFlags usage;
+ bool shared;
D3D12_BARRIER_ACCESS valid_access;
D3D12_GPU_VIRTUAL_ADDRESS gpuva;