From b6d1487ad5679a6e20e1a959fcc8b8c3ef1baf92 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 12 Dec 2020 11:08:04 +0000 Subject: [PATCH] vkd3d: Implement D3D12_HEAP_TYPE_WRITE_WATCH Needed for D3D12 APITrace. Closes: #373 Signed-off-by: Joshua Ashton --- libs/vkd3d/resource.c | 119 ++++++++++++++++++++++++++++++++++++- libs/vkd3d/vkd3d_private.h | 1 + 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index ad08b885..0fd5e3ca 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -462,6 +462,70 @@ static ULONG STDMETHODCALLTYPE d3d12_heap_AddRef(d3d12_heap_iface *iface) static ULONG d3d12_resource_decref(struct d3d12_resource *resource); +static void *d3d12_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, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, protect))) + { + ERR("Failed to allocate write watch pointer %#x.\n", GetLastError()); + return NULL; + } + + return ptr; +#else + ERR("WRITE_WATCH not supported on this platform.\n"); + return NULL; +#endif +} + +static void d3d12_free_write_watch_pointer(const D3D12_HEAP_DESC* desc, void *pointer) +{ +#ifdef _WIN32 + if (VirtualFree(pointer, 0, MEM_RELEASE) == 0) + ERR("Failed to free write watch pointer %#x.\n", GetLastError()); +#else + /* Not supported on other platforms. */ +#endif +} + static void d3d12_heap_cleanup(struct d3d12_heap *heap) { struct d3d12_device *device = heap->device; @@ -472,6 +536,9 @@ static void d3d12_heap_cleanup(struct d3d12_heap *heap) VK_CALL(vkFreeMemory(device->vk_device, heap->vk_memory, NULL)); + if (heap->write_watch_ptr) + d3d12_free_write_watch_pointer(&heap->desc, heap->write_watch_ptr); + if (heap->is_private) device = NULL; @@ -723,13 +790,13 @@ static HRESULT d3d12_heap_allocate_storage(struct d3d12_heap *heap, { if (d3d12_resource_is_buffer(resource)) { - hr = vkd3d_allocate_buffer_memory(device, resource->vk_buffer, NULL, + hr = vkd3d_allocate_buffer_memory(device, resource->vk_buffer, host_memory, &heap->desc.Properties, heap->desc.Flags | D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS, &heap->vk_memory, &heap->vk_memory_type, &vk_memory_size); } else { - hr = vkd3d_allocate_image_memory(device, resource->vk_image, + hr = vkd3d_allocate_image_memory(device, resource->vk_image, host_memory, &heap->desc.Properties, heap->desc.Flags, &heap->vk_memory, &heap->vk_memory_type, &vk_memory_size); } @@ -788,6 +855,7 @@ static HRESULT d3d12_heap_allocate_storage(struct d3d12_heap *heap, static HRESULT d3d12_heap_init(struct d3d12_heap *heap, struct d3d12_device *device, const D3D12_HEAP_DESC *desc, const struct d3d12_resource *resource) { + const struct vkd3d_vk_device_procs* vk_procs = &device->vk_procs; bool buffers_allowed; HRESULT hr; @@ -839,7 +907,52 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap, return hr; } - if (FAILED(hr = d3d12_heap_allocate_storage(heap, device, resource, NULL))) + if (heap->desc.Flags & D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH) + { + VkDeviceSize size = heap->desc.SizeInBytes; + + if (resource) + { + VkMemoryRequirements2 memory_requirements2; + if (d3d12_resource_is_buffer(resource)) + { + VkBufferMemoryRequirementsInfo2 info; + + memory_requirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; + memory_requirements2.pNext = NULL; + + info.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2; + info.pNext = NULL; + info.buffer = resource->vk_buffer; + + VK_CALL(vkGetBufferMemoryRequirements2(device->vk_device, &info, &memory_requirements2)); + } + else + { + VkImageMemoryRequirementsInfo2 info; + + assert(d3d12_resource_is_texture(resource)); + + memory_requirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; + memory_requirements2.pNext = NULL; + + info.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; + info.pNext = NULL; + info.image = resource->vk_image; + + VK_CALL(vkGetImageMemoryRequirements2(device->vk_device, &info, &memory_requirements2)); + } + + size = memory_requirements2.memoryRequirements.size; + } + + if (device->vk_info.EXT_external_memory_host) + heap->write_watch_ptr = d3d12_allocate_write_watch_pointer(&heap->desc.Properties, size); + else + WARN("VK_EXT_external_memory_host is not supported. This may break replay in tracing tools.\n"); + } + + if (FAILED(hr = d3d12_heap_allocate_storage(heap, device, resource, heap->write_watch_ptr))) { d3d12_heap_cleanup(heap); return hr; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index f8e03472..e82cb968 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -415,6 +415,7 @@ struct d3d12_heap VkDeviceMemory vk_memory; void *map_ptr; + void *write_watch_ptr; uint32_t vk_memory_type; struct d3d12_resource *buffer_resource;