dzn: VK_EXT_external_memory_host

When ID3D12Device13 is available, we can support importing host memory.
Imported host memory can be used to back buffers and linear textures.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23886>
This commit is contained in:
Jesse Natalie 2023-05-05 13:02:41 -07:00 committed by Marge Bot
parent a831ee51ae
commit f0569cdba0
3 changed files with 151 additions and 8 deletions

View file

@ -147,6 +147,9 @@ dzn_physical_device_get_extensions(struct dzn_physical_device *pdev)
.KHR_timeline_semaphore = true,
.KHR_uniform_buffer_standard_layout = true,
.EXT_descriptor_indexing = pdev->shader_model >= D3D_SHADER_MODEL_6_6,
#if defined(_WIN32) && D3D12_SDK_VERSION >= 611
.EXT_external_memory_host = pdev->dev13,
#endif
.EXT_scalar_block_layout = true,
.EXT_separate_stencil_usage = true,
.EXT_shader_subgroup_ballot = true,
@ -203,6 +206,11 @@ dzn_physical_device_destroy(struct vk_physical_device *physical)
if (pdev->dev12)
ID3D12Device1_Release(pdev->dev12);
#if D3D12_SDK_VERSION >= 611
if (pdev->dev13)
ID3D12Device1_Release(pdev->dev13);
#endif
if (pdev->adapter)
IUnknown_Release(pdev->adapter);
@ -826,6 +834,10 @@ dzn_physical_device_create(struct vk_instance *instance,
pdev->dev11 = NULL;
if (FAILED(ID3D12Device1_QueryInterface(pdev->dev, &IID_ID3D12Device12, (void **)&pdev->dev12)))
pdev->dev12 = NULL;
#if D3D12_SDK_VERSION >= 611
if (FAILED(ID3D12Device1_QueryInterface(pdev->dev, &IID_ID3D12Device13, (void **)&pdev->dev13)))
pdev->dev13 = NULL;
#endif
dzn_physical_device_cache_caps(pdev);
dzn_physical_device_init_memory(pdev);
dzn_physical_device_init_uuids(pdev);
@ -1129,12 +1141,24 @@ dzn_physical_device_get_image_format_properties(struct dzn_physical_device *pdev
external_props->externalMemoryProperties.exportFromImportedHandleTypes = d3d11_texture_handle_types;
external_props->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
break;
#if defined(_WIN32) && D3D12_SDK_VERSION >= 611
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT:
if (pdev->dev13) {
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;
}
FALLTHROUGH;
#endif
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)
if (info->tiling != VK_IMAGE_TILING_OPTIMAL &&
external_info->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT)
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
@ -1340,6 +1364,10 @@ dzn_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
VkExternalBufferProperties *pExternalBufferProperties)
{
#if defined(_WIN32) && D3D12_SDK_VERSION >= 611
VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
#endif
const VkExternalMemoryHandleTypeFlags d3d12_resource_handle_types =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | opaque_external_flag;
const VkExternalMemoryFeatureFlags import_export_feature_flags =
@ -1368,6 +1396,17 @@ dzn_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | d3d12_resource_handle_types;
pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
break;
#if defined(_WIN32) && D3D12_SDK_VERSION >= 611
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT:
if (pdev->dev13) {
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;
}
FALLTHROUGH;
#endif
default:
pExternalBufferProperties->externalMemoryProperties = (VkExternalMemoryProperties){ 0 };
break;
@ -1912,6 +1951,14 @@ dzn_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
attr_div->maxVertexAttribDivisor = UINT32_MAX;
break;
}
#ifdef _WIN32
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT: {
VkPhysicalDeviceExternalMemoryHostPropertiesEXT *host_props =
(VkPhysicalDeviceExternalMemoryHostPropertiesEXT *)ext;
host_props->minImportedHostPointerAlignment = 65536;
break;
}
#endif
default:
dzn_debug_ignored_stype(ext->sType);
break;
@ -2231,6 +2278,11 @@ dzn_device_destroy(struct dzn_device *device, const VkAllocationCallbacks *pAllo
if (device->dev12)
ID3D12Device1_Release(device->dev12);
#if D3D12_SDK_VERSION >= 611
if (device->dev13)
ID3D12Device1_Release(device->dev13);
#endif
vk_device_finish(&device->vk);
vk_free2(&instance->vk.alloc, pAllocator, device);
}
@ -2332,6 +2384,13 @@ dzn_device_create(struct dzn_physical_device *pdev,
ID3D12Device1_AddRef(device->dev12);
}
#if D3D12_SDK_VERSION >= 611
if (pdev->dev13) {
device->dev13 = pdev->dev13;
ID3D12Device1_AddRef(device->dev13);
}
#endif
ID3D12InfoQueue *info_queue;
if (SUCCEEDED(ID3D12Device1_QueryInterface(device->dev,
&IID_ID3D12InfoQueue,
@ -2534,7 +2593,7 @@ dzn_device_memory_destroy(struct dzn_device_memory *mem,
struct dzn_device *device = container_of(mem->base.device, struct dzn_device, vk);
if (mem->map)
if (mem->map && mem->map_res)
ID3D12Resource_Unmap(mem->map_res, 0, NULL);
if (mem->map_res)
@ -2593,6 +2652,7 @@ dzn_device_memory_create(struct dzn_device *device,
VkExternalMemoryHandleTypeFlags export_flags = 0;
HANDLE import_handle = NULL;
bool imported_from_d3d11 = false;
void *host_pointer = NULL;
#ifdef _WIN32
const wchar_t *import_name = NULL;
const VkExportMemoryWin32HandleInfoKHR *win32_export = NULL;
@ -2628,6 +2688,12 @@ dzn_device_memory_create(struct dzn_device *device,
case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR:
win32_export = (const VkExportMemoryWin32HandleInfoKHR *)ext;
break;
case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: {
const VkImportMemoryHostPointerInfoEXT *imp =
(const VkImportMemoryHostPointerInfoEXT *)ext;
host_pointer = imp->pHostPointer;
break;
}
#else
case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR: {
const VkImportMemoryFdInfoKHR *imp =
@ -2716,7 +2782,7 @@ dzn_device_memory_create(struct dzn_device *device,
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);
assert(host_pointer || heap_desc.Properties.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE);
}
VkResult error = VK_ERROR_OUT_OF_DEVICE_MEMORY;
@ -2732,7 +2798,31 @@ dzn_device_memory_create(struct dzn_device *device,
}
#endif
if (import_handle) {
if (host_pointer) {
error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
#if defined(_WIN32) && D3D12_SDK_VERSION >= 611
if (!device->dev13)
goto cleanup;
if (FAILED(ID3D12Device13_OpenExistingHeapFromAddress1(device->dev13, host_pointer, heap_desc.SizeInBytes, &IID_ID3D12Heap, &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 ((heap_desc.Flags & ~desc.Flags) ||
desc.Properties.CPUPageProperty != heap_desc.Properties.CPUPageProperty ||
desc.Properties.MemoryPoolPreference != heap_desc.Properties.MemoryPoolPreference)
goto cleanup;
mem->map = host_pointer;
mem->res_flags = D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER;
#else
goto cleanup;
#endif
} else 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)))
@ -2830,7 +2920,8 @@ dzn_device_memory_create(struct dzn_device *device,
}
if ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
!(heap_desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS)){
!(heap_desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS) &&
!mem->map){
assert(!image);
if (buffer) {
mem->map_res = mem->dedicated_res;
@ -2920,6 +3011,11 @@ dzn_MapMemory(VkDevice _device,
return VK_SUCCESS;
}
if (mem->map && !mem->map_res) {
*ppData = ((uint8_t *)mem->map) + offset;
return VK_SUCCESS;
}
if (size == VK_WHOLE_SIZE)
size = mem->size - offset;
@ -2958,7 +3054,9 @@ dzn_UnmapMemory(VkDevice _device,
if (mem == NULL)
return;
assert(mem->map_res);
if (!mem->map_res)
return;
ID3D12Resource_Unmap(mem->map_res, 0, NULL);
mem->map = NULL;
@ -3273,6 +3371,8 @@ dzn_BindBufferMemory2(VkDevice _device,
buffer->res = mem->dedicated_res;
ID3D12Resource_AddRef(buffer->res);
} else {
D3D12_RESOURCE_DESC desc = buffer->desc;
desc.Flags |= mem->res_flags;
if (FAILED(ID3D12Device1_CreatePlacedResource(device->dev, mem->heap,
pBindInfos[i].memoryOffset,
&buffer->desc,
@ -3805,3 +3905,35 @@ cleanup:
ID3D12Heap_Release(heap);
return result;
}
#if defined(_WIN32) && D3D12_SDK_VERSION >= 611
VKAPI_ATTR VkResult VKAPI_CALL
dzn_GetMemoryHostPointerPropertiesEXT(VkDevice _device,
VkExternalMemoryHandleTypeFlagBits handleType,
const void *pHostPointer,
VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties)
{
VK_FROM_HANDLE(dzn_device, device, _device);
if (!device->dev13)
return VK_ERROR_FEATURE_NOT_PRESENT;
ID3D12Heap *heap;
if (FAILED(ID3D12Device13_OpenExistingHeapFromAddress1(device->dev13, pHostPointer, 1, &IID_ID3D12Heap, &heap)))
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
struct dzn_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk);
D3D12_HEAP_DESC heap_desc = dzn_ID3D12Heap_GetDesc(heap);
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;
pMemoryHostPointerProperties->memoryTypeBits |= (1 << i);
}
ID3D12Heap_Release(heap);
return VK_SUCCESS;
}
#endif

View file

@ -843,7 +843,7 @@ dzn_BindImageMemory2(VkDevice dev,
.Format = image->desc.Format,
.SampleDesc = image->desc.SampleDesc,
.Layout = image->desc.Layout,
.Flags = image->desc.Flags,
.Flags = image->desc.Flags | mem->res_flags,
};
hres = ID3D12Device10_CreatePlacedResource2(device->dev10, mem->heap,
@ -856,9 +856,11 @@ dzn_BindImageMemory2(VkDevice dev,
&IID_ID3D12Resource,
(void **)&image->res);
} else {
D3D12_RESOURCE_DESC desc = image->desc;
desc.Flags |= mem->res_flags;
hres = ID3D12Device1_CreatePlacedResource(device->dev, mem->heap,
bind_info->memoryOffset,
&image->desc,
&desc,
D3D12_RESOURCE_STATE_COMMON,
NULL,
&IID_ID3D12Resource,

View file

@ -202,6 +202,9 @@ struct dzn_physical_device {
ID3D12Device10 *dev10;
ID3D12Device11 *dev11;
ID3D12Device12 *dev12;
#if D3D12_SDK_VERSION >= 611
ID3D12Device13 *dev13;
#endif
D3D_FEATURE_LEVEL feature_level;
D3D_SHADER_MODEL shader_model;
D3D_ROOT_SIGNATURE_VERSION root_sig_version;
@ -287,6 +290,9 @@ struct dzn_device {
ID3D12Device10 *dev10;
ID3D12Device11 *dev11;
ID3D12Device12 *dev12;
#if D3D12_SDK_VERSION >= 611
ID3D12Device13 *dev13;
#endif
ID3D12DeviceConfiguration *dev_config;
struct dzn_meta_indirect_draw indirect_draws[DZN_NUM_INDIRECT_DRAW_TYPES];
@ -345,6 +351,9 @@ struct dzn_device_memory {
/* If the resource is exportable, this is the pre-created handle for that */
HANDLE export_handle;
/* These flags need to be added into all resources created on this heap */
D3D12_RESOURCE_FLAGS res_flags;
};
enum dzn_cmd_bindpoint_dirty {