dzn: External Win32 memory extension

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22879>
This commit is contained in:
Jesse Natalie 2023-05-04 12:36:05 -07:00 committed by Marge Bot
parent fb61340790
commit ed25ea1bc9
4 changed files with 421 additions and 56 deletions

View file

@ -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)
{

View file

@ -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);
}
if (image) {
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 (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

View file

@ -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),
};
/*

View file

@ -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;