From aa12817ccf0e1c008d200cef5d44c2883a62dec5 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Wed, 17 Mar 2021 21:55:40 +0000 Subject: [PATCH] vkd3d: Implement D3D12_HEAP_TYPE_WRITE_WATCH Needed for D3D12 APITrace Closes: #373 Signed-off-by: Joshua Ashton --- libs/vkd3d/memory.c | 95 ++++++++++++++++++++++++++++++++++++-- libs/vkd3d/vkd3d_private.h | 1 + 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/libs/vkd3d/memory.c b/libs/vkd3d/memory.c index 1f9acdc7..919154cf 100644 --- a/libs/vkd3d/memory.c +++ b/libs/vkd3d/memory.c @@ -261,6 +261,73 @@ static HRESULT vkd3d_allocation_assign_gpu_address(struct vkd3d_memory_allocatio return S_OK; } +static void *vkd3d_allocate_write_watch_pointer(const D3D12_HEAP_PROPERTIES *properties, VkDeviceSize size) +{ +#ifdef _WIN32 + DWORD protect; + void *ptr; + + switch (properties->Type) + { + case D3D12_HEAP_TYPE_DEFAULT: + return NULL; + case D3D12_HEAP_TYPE_UPLOAD: + protect = PAGE_READWRITE | PAGE_WRITECOMBINE; + break; + case D3D12_HEAP_TYPE_READBACK: + /* WRITE_WATCH fails for this type in native D3D12, + * otherwise it would be PAGE_READWRITE. */ + return NULL; + case D3D12_HEAP_TYPE_CUSTOM: + switch (properties->CPUPageProperty) + { + case D3D12_CPU_PAGE_PROPERTY_UNKNOWN: + return NULL; + case D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE: + return NULL; + case D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE: + protect = PAGE_READWRITE | PAGE_WRITECOMBINE; + break; + case D3D12_CPU_PAGE_PROPERTY_WRITE_BACK: + protect = PAGE_READWRITE; + break; + default: + ERR("Invalid CPU page property %#x.\n", properties->CPUPageProperty); + return NULL; + } + break; + default: + ERR("Invalid heap type %#x.\n", properties->Type); + return NULL; + } + + if (!(ptr = VirtualAlloc(NULL, (SIZE_T)size, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, protect))) + { + ERR("Failed to allocate write watch pointer %#x.\n", GetLastError()); + return NULL; + } + + return ptr; +#else + (void)properties; + (void)size; + + ERR("WRITE_WATCH not supported on this platform.\n"); + return NULL; +#endif +} + +static void vkd3d_free_write_watch_pointer(void *pointer) +{ +#ifdef _WIN32 + if (!VirtualFree(pointer, 0, MEM_RELEASE)) + ERR("Failed to free write watch pointer %#x.\n", GetLastError()); +#else + /* Not supported on other platforms. */ + (void)pointer; +#endif +} + static void vkd3d_memory_allocation_free(const struct vkd3d_memory_allocation *allocation, struct d3d12_device *device, struct vkd3d_memory_allocator *allocator) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; @@ -271,6 +338,9 @@ static void vkd3d_memory_allocation_free(const struct vkd3d_memory_allocation *a vkd3d_descriptor_debug_unregister_cookie(allocation->resource.cookie); #endif + if (allocation->flags & VKD3D_ALLOCATION_FLAG_ALLOW_WRITE_WATCH) + vkd3d_free_write_watch_pointer(allocation->cpu_address); + if ((allocation->flags & VKD3D_ALLOCATION_FLAG_GPU_ADDRESS) && allocation->resource.va) { vkd3d_va_map_remove(&allocator->va_map, &allocation->resource); @@ -298,6 +368,7 @@ static HRESULT vkd3d_memory_allocation_init(struct vkd3d_memory_allocation *allo VkMemoryRequirements memory_requirements; VkMemoryAllocateFlagsInfo flags_info; VkMemoryPropertyFlags type_flags; + void *host_ptr = info->host_ptr; uint32_t type_mask; VkResult vr; HRESULT hr; @@ -353,9 +424,18 @@ static HRESULT vkd3d_memory_allocation_init(struct vkd3d_memory_allocation *allo allocation->resource.size = memory_requirements.size; - if (info->host_ptr) + if (info->heap_flags & D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH) { - hr = vkd3d_import_host_memory(device, info->host_ptr, memory_requirements.size, + assert(!host_ptr); + + allocation->flags |= VKD3D_ALLOCATION_FLAG_ALLOW_WRITE_WATCH; + if (!(host_ptr = vkd3d_allocate_write_watch_pointer(&info->heap_properties, memory_requirements.size))) + return E_FAIL; + } + + if (host_ptr) + { + hr = vkd3d_import_host_memory(device, host_ptr, memory_requirements.size, type_flags, type_mask, &flags_info, &allocation->vk_memory, &allocation->vk_memory_type); } else @@ -370,7 +450,14 @@ static HRESULT vkd3d_memory_allocation_init(struct vkd3d_memory_allocation *allo /* Map memory if the allocation was requested to be host-visible, * but do not map if the allocation was meant to be device-local * since that may negatively impact performance. */ - if (type_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + if (host_ptr) + { + allocation->flags |= VKD3D_ALLOCATION_FLAG_CPU_ACCESS; + + /* No need to call map here, we already know the pointer. */ + allocation->cpu_address = host_ptr; + } + else if (type_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { allocation->flags |= VKD3D_ALLOCATION_FLAG_CPU_ACCESS; @@ -1163,7 +1250,7 @@ HRESULT vkd3d_allocate_memory(struct d3d12_device *device, struct vkd3d_memory_a HRESULT hr; if (!info->pNext && !info->host_ptr && info->memory_requirements.size < VKD3D_VA_BLOCK_SIZE && - !(info->heap_flags & D3D12_HEAP_FLAG_DENY_BUFFERS)) + !(info->heap_flags & (D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH))) hr = vkd3d_suballocate_memory(device, allocator, info, allocation); else hr = vkd3d_memory_allocation_init(allocation, device, allocator, info); diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index cfb576ec..47a8731a 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -565,6 +565,7 @@ enum vkd3d_allocation_flag VKD3D_ALLOCATION_FLAG_GLOBAL_BUFFER = (1u << 0), VKD3D_ALLOCATION_FLAG_GPU_ADDRESS = (1u << 1), VKD3D_ALLOCATION_FLAG_CPU_ACCESS = (1u << 2), + VKD3D_ALLOCATION_FLAG_ALLOW_WRITE_WATCH = (1u << 3), }; #define VKD3D_MEMORY_CHUNK_SIZE (VKD3D_VA_BLOCK_SIZE * 16)