From 5f1b8b3e6c9e61418c507213b899b28b71dedd0c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 27 Apr 2022 19:34:57 +0200 Subject: [PATCH] dzn: Use DXGI swapchains Makes things so much faster than doing CPU copies using StretchBlt(). Reviewed-by: Jesse Natalie Part-of: --- src/microsoft/vulkan/dzn_cmd_buffer.c | 28 +++++++------- src/microsoft/vulkan/dzn_device.c | 39 +++++++++++++++++++ src/microsoft/vulkan/dzn_image.c | 7 +++- src/microsoft/vulkan/dzn_private.h | 11 ++++++ src/microsoft/vulkan/dzn_wsi.c | 55 +++++++++++++++++++++++++-- 5 files changed, 121 insertions(+), 19 deletions(-) diff --git a/src/microsoft/vulkan/dzn_cmd_buffer.c b/src/microsoft/vulkan/dzn_cmd_buffer.c index db6cb22222d..48bef1e10f3 100644 --- a/src/microsoft/vulkan/dzn_cmd_buffer.c +++ b/src/microsoft/vulkan/dzn_cmd_buffer.c @@ -1088,20 +1088,22 @@ dzn_CmdPipelineBarrier2(VkCommandBuffer commandBuffer, const VkImageSubresourceRange *range = &ibarrier->subresourceRange; VK_FROM_HANDLE(dzn_image, image, ibarrier->image); - /* We use placed resource's simple model, in which only one resource - * pointing to a given heap is active at a given time. To make the - * resource active we need to add an aliasing barrier. - */ - D3D12_RESOURCE_BARRIER aliasing_barrier = { - .Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING, - .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, - .Aliasing = { - .pResourceBefore = NULL, - .pResourceAfter = image->res, - }, - }; + if (image->mem->swapchain_res != image->res) { + /* We use placed resource's simple model, in which only one resource + * pointing to a given heap is active at a given time. To make the + * resource active we need to add an aliasing barrier. + */ + D3D12_RESOURCE_BARRIER aliasing_barrier = { + .Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING, + .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, + .Aliasing = { + .pResourceBefore = NULL, + .pResourceAfter = image->res, + }, + }; - ID3D12GraphicsCommandList1_ResourceBarrier(cmdbuf->cmdlist, 1, &aliasing_barrier); + ID3D12GraphicsCommandList1_ResourceBarrier(cmdbuf->cmdlist, 1, &aliasing_barrier); + } dzn_cmd_buffer_queue_image_range_layout_transition(cmdbuf, image, range, ibarrier->oldLayout, diff --git a/src/microsoft/vulkan/dzn_device.c b/src/microsoft/vulkan/dzn_device.c index e82c689b99c..21dc6921f15 100644 --- a/src/microsoft/vulkan/dzn_device.c +++ b/src/microsoft/vulkan/dzn_device.c @@ -279,6 +279,9 @@ dzn_instance_create(const VkInstanceCreateInfo *pCreateInfo, vk_instance_dispatch_table_from_entrypoints(&dispatch_table, &dzn_instance_entrypoints, true); + vk_instance_dispatch_table_from_entrypoints(&dispatch_table, + &wsi_instance_entrypoints, + false); VkResult result = vk_instance_init(&instance->vk, &instance_extensions, @@ -2143,12 +2146,19 @@ dzn_device_create(struct dzn_physical_device *pdev, { struct dzn_instance *instance = container_of(pdev->vk.instance, struct dzn_instance, vk); + uint32_t graphics_queue_count = 0; uint32_t queue_count = 0; for (uint32_t qf = 0; qf < pCreateInfo->queueCreateInfoCount; qf++) { const VkDeviceQueueCreateInfo *qinfo = &pCreateInfo->pQueueCreateInfos[qf]; queue_count += qinfo->queueCount; + if (pdev->queue_families[qinfo->queueFamilyIndex].props.queueFlags & VK_QUEUE_GRAPHICS_BIT) + graphics_queue_count += qinfo->queueCount; } + /* Add a swapchain queue if there's no or too many graphics queues */ + if (graphics_queue_count != 1) + queue_count++; + VK_MULTIALLOC(ma); VK_MULTIALLOC_DECL(&ma, struct dzn_device, device, 1); VK_MULTIALLOC_DECL(&ma, struct dzn_queue, queues, queue_count); @@ -2257,9 +2267,35 @@ dzn_device_create(struct dzn_physical_device *pdev, dzn_device_destroy(device, pAllocator); return result; } + if (graphics_queue_count == 1 && + pdev->queue_families[qinfo->queueFamilyIndex].props.queueFlags & VK_QUEUE_GRAPHICS_BIT) + device->swapchain_queue = &queues[qindex - 1]; } } + if (!device->swapchain_queue) { + const float swapchain_queue_priority = 0.0f; + VkDeviceQueueCreateInfo swapchain_queue_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .flags = 0, + .queueCount = 1, + .pQueuePriorities = &swapchain_queue_priority, + }; + for (uint32_t qf = 0; qf < pdev->queue_family_count; qf++) { + if (pdev->queue_families[qf].props.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + swapchain_queue_info.queueFamilyIndex = qf; + break; + } + } + result = dzn_queue_init(&queues[qindex], device, &swapchain_queue_info, 0); + if (result != VK_SUCCESS) { + dzn_device_destroy(device, pAllocator); + return result; + } + device->swapchain_queue = &queues[qindex++]; + device->need_swapchain_blits = true; + } + assert(queue_count == qindex); *out = dzn_device_to_handle(device); return VK_SUCCESS; @@ -2372,6 +2408,9 @@ dzn_device_memory_destroy(struct dzn_device_memory *mem, if (mem->heap) ID3D12Heap_Release(mem->heap); + if (mem->swapchain_res) + ID3D12Resource_Release(mem->swapchain_res); + vk_object_base_finish(&mem->base); vk_free2(&device->vk.alloc, pAllocator, mem); } diff --git a/src/microsoft/vulkan/dzn_image.c b/src/microsoft/vulkan/dzn_image.c index d79714aae99..319235e9b06 100644 --- a/src/microsoft/vulkan/dzn_image.c +++ b/src/microsoft/vulkan/dzn_image.c @@ -817,9 +817,12 @@ dzn_BindImageMemory2(VkDevice dev, image->mem = mem; image->mem_offset = bind_info->memoryOffset; - HRESULT hres; + HRESULT hres = S_OK; - if (device->dev10 && image->castable_format_count > 0) { + if (mem->swapchain_res) { + image->res = mem->swapchain_res; + ID3D12Resource_AddRef(image->res); + } else if (device->dev10 && image->castable_format_count > 0) { D3D12_RESOURCE_DESC1 desc = { .Dimension = image->desc.Dimension, .Alignment = image->desc.Alignment, diff --git a/src/microsoft/vulkan/dzn_private.h b/src/microsoft/vulkan/dzn_private.h index 8b10a0610e1..9768d95557d 100644 --- a/src/microsoft/vulkan/dzn_private.h +++ b/src/microsoft/vulkan/dzn_private.h @@ -271,6 +271,12 @@ struct dzn_device { #define DZN_QUERY_REFS_RES_SIZE (DZN_QUERY_REFS_ALL_ZEROS_OFFSET + DZN_QUERY_REFS_SECTION_SIZE) ID3D12Resource *refs; } queries; + + /* Will be the app's graphics queue if there's exactly one, otherwise this will be + * a dedicated graphics queue to host swapchain blits. + */ + bool need_swapchain_blits; + struct dzn_queue *swapchain_queue; }; void dzn_meta_finish(struct dzn_device *device); @@ -290,6 +296,11 @@ struct dzn_device_memory { struct list_head link; + /* Swapchain image resource, NULL if the memory is not backed by + * a DXGI swapchain. + */ + ID3D12Resource *swapchain_res; + ID3D12Heap *heap; VkDeviceSize size; diff --git a/src/microsoft/vulkan/dzn_wsi.c b/src/microsoft/vulkan/dzn_wsi.c index 77a44ec17bc..6958f3b8488 100644 --- a/src/microsoft/vulkan/dzn_wsi.c +++ b/src/microsoft/vulkan/dzn_wsi.c @@ -31,6 +31,50 @@ dzn_wsi_proc_addr(VkPhysicalDevice physicalDevice, const char *pName) return vk_instance_get_proc_addr_unchecked(pdevice->vk.instance, pName); } +static void * +dzn_wsi_get_d3d12_command_queue(VkDevice dev) +{ + VK_FROM_HANDLE(dzn_device, device, dev); + + return device->swapchain_queue->cmdqueue; +} + +static VkQueue +dzn_wsi_get_blit_queue(VkDevice dev) +{ + VK_FROM_HANDLE(dzn_device, device, dev); + + return dzn_queue_to_handle(device->swapchain_queue); +} + +static bool +dzn_wsi_needs_blits(VkDevice dev) +{ + VK_FROM_HANDLE(dzn_device, device, dev); + return device->need_swapchain_blits; +} + +static VkResult +dzn_wsi_create_image_memory(VkDevice dev, void *resource, + const VkAllocationCallbacks *alloc, + VkDeviceMemory *out) +{ + VK_FROM_HANDLE(dzn_device, device, dev); + + struct dzn_device_memory *mem = + vk_zalloc2(&device->vk.alloc, alloc, sizeof(*mem), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!mem) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + vk_object_base_init(&device->vk, &mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY); + mem->swapchain_res = resource; + ID3D12Resource_AddRef(mem->swapchain_res); + + *out = dzn_device_memory_to_handle(mem); + return VK_SUCCESS; +} + void dzn_wsi_finish(struct dzn_physical_device *physical_device) { @@ -43,18 +87,21 @@ dzn_wsi_init(struct dzn_physical_device *physical_device) { VkResult result; - /* TODO: implement a proper, non-sw winsys for D3D12 */ - bool sw_device = true; - result = wsi_device_init(&physical_device->wsi_device, dzn_physical_device_to_handle(physical_device), dzn_wsi_proc_addr, &physical_device->vk.instance->alloc, - -1, NULL, sw_device); + -1, NULL, false); if (result != VK_SUCCESS) return result; + physical_device->wsi_device.win32.get_d3d12_command_queue = + dzn_wsi_get_d3d12_command_queue; + physical_device->wsi_device.win32.requires_blits = dzn_wsi_needs_blits; + physical_device->wsi_device.get_blit_queue = dzn_wsi_get_blit_queue; + physical_device->wsi_device.win32.create_image_memory = + dzn_wsi_create_image_memory; physical_device->wsi_device.supports_modifiers = false; physical_device->vk.wsi_device = &physical_device->wsi_device;