From 02d3e0d31f6069227451984a5cdb9d9fbd704ecb Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 23 Feb 2022 15:56:31 -0500 Subject: [PATCH] [dxvk] Add shared handle access to DxvkImage memory. Based off preliminary work from Josh. --- src/d3d11/d3d11_swapchain.cpp | 4 +- src/d3d9/d3d9_swapchain.cpp | 2 +- src/dxvk/dxvk_device.cpp | 4 +- src/dxvk/dxvk_image.cpp | 130 +++++++++++++++++++++++++++++++--- src/dxvk/dxvk_image.h | 19 ++++- src/dxvk/dxvk_memory.h | 31 +++++++- 6 files changed, 171 insertions(+), 19 deletions(-) diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index c60d9c41..f6032841 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -445,7 +445,7 @@ namespace dxvk { VkImage imageHandle = m_presenter->getImage(i).image; Rc image = new DxvkImage( - m_device->vkd(), imageInfo, imageHandle); + m_device.ptr(), imageInfo, imageHandle); m_imageViews[i] = new DxvkImageView( m_device->vkd(), image, viewInfo); @@ -662,4 +662,4 @@ namespace dxvk { return str::format("D3D", apiVersion, " FL", flHi, "_", flLo); } -} \ No newline at end of file +} diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index d6e52dd6..2cc5aaba 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -997,7 +997,7 @@ namespace dxvk { VkImage imageHandle = m_presenter->getImage(i).image; Rc image = new DxvkImage( - m_device->vkd(), imageInfo, imageHandle); + m_device.ptr(), imageInfo, imageHandle); m_imageViews[i] = new DxvkImageView( m_device->vkd(), image, viewInfo); diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index bb373e06..711f615a 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -135,14 +135,14 @@ namespace dxvk { Rc DxvkDevice::createImage( const DxvkImageCreateInfo& createInfo, VkMemoryPropertyFlags memoryType) { - return new DxvkImage(m_vkd, createInfo, m_objects.memoryManager(), memoryType); + return new DxvkImage(this, createInfo, m_objects.memoryManager(), memoryType); } Rc DxvkDevice::createImageFromVkImage( const DxvkImageCreateInfo& createInfo, VkImage image) { - return new DxvkImage(m_vkd, createInfo, image); + return new DxvkImage(this, createInfo, image); } Rc DxvkDevice::createImageView( diff --git a/src/dxvk/dxvk_image.cpp b/src/dxvk/dxvk_image.cpp index 4a5ceaaa..ab0e07c4 100644 --- a/src/dxvk/dxvk_image.cpp +++ b/src/dxvk/dxvk_image.cpp @@ -1,16 +1,18 @@ #include "dxvk_image.h" +#include "dxvk_device.h" + namespace dxvk { std::atomic DxvkImageView::s_cookie = { 0ull }; DxvkImage::DxvkImage( - const Rc& vkd, + const DxvkDevice* device, const DxvkImageCreateInfo& createInfo, DxvkMemoryAllocator& memAlloc, VkMemoryPropertyFlags memFlags) - : m_vkd(vkd), m_info(createInfo), m_memFlags(memFlags) { + : m_vkd(device->vkd()), m_device(device), m_info(createInfo), m_memFlags(memFlags) { // Copy the compatible view formats to a persistent array m_viewFormats.resize(createInfo.viewFormatCount); @@ -42,6 +44,17 @@ namespace dxvk { info.queueFamilyIndexCount = 0; info.pQueueFamilyIndices = nullptr; info.initialLayout = createInfo.initialLayout; + + m_shared = canShareImage(info, createInfo.sharing); + + VkExternalMemoryImageCreateInfo externalInfo; + if (m_shared) { + externalInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; + externalInfo.pNext = nullptr; + externalInfo.handleTypes = createInfo.sharing.type; + + formatList.pNext = &externalInfo; + } if (m_vkd->vkCreateImage(m_vkd->device(), &info, nullptr, &m_image.image) != VK_SUCCESS) { @@ -83,7 +96,29 @@ namespace dxvk { dedMemoryAllocInfo.pNext = VK_NULL_HANDLE; dedMemoryAllocInfo.buffer = VK_NULL_HANDLE; dedMemoryAllocInfo.image = m_image.image; - + + VkExportMemoryAllocateInfo exportInfo; + if (m_shared && createInfo.sharing.mode == DxvkSharedHandleMode::Export) { + exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; + exportInfo.pNext = nullptr; + exportInfo.handleTypes = createInfo.sharing.type; + + dedMemoryAllocInfo.pNext = &exportInfo; + } + +#ifdef _WIN32 + VkImportMemoryWin32HandleInfoKHR importInfo; + if (m_shared && createInfo.sharing.mode == DxvkSharedHandleMode::Import) { + importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + importInfo.pNext = nullptr; + importInfo.handleType = createInfo.sharing.type; + importInfo.handle = createInfo.sharing.handle; + importInfo.name = nullptr; + + dedMemoryAllocInfo.pNext = &importInfo; + } +#endif + m_vkd->vkGetImageMemoryRequirements2( m_vkd->device(), &memReqInfo, &memReq); @@ -117,10 +152,10 @@ namespace dxvk { DxvkImage::DxvkImage( - const Rc& vkd, + const DxvkDevice* device, const DxvkImageCreateInfo& info, VkImage image) - : m_vkd(vkd), m_info(info), m_image({ image }) { + : m_vkd(device->vkd()), m_device(device), m_info(info), m_image({ image }) { m_viewFormats.resize(info.viewFormatCount); for (uint32_t i = 0; i < info.viewFormatCount; i++) @@ -135,8 +170,87 @@ namespace dxvk { if (m_image.memory.memory() != VK_NULL_HANDLE) m_vkd->vkDestroyImage(m_vkd->device(), m_image.image, nullptr); } - - + + + bool DxvkImage::canShareImage(const VkImageCreateInfo& createInfo, const DxvkSharedHandleInfo& sharingInfo) const { + if (sharingInfo.mode == DxvkSharedHandleMode::None) + return false; + + if (!m_device->extensions().khrExternalMemoryWin32) { + Logger::err("Failed to create shared resource: VK_KHR_EXTERNAL_MEMORY_WIN32 not supported"); + return false; + } + + VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo; + externalImageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; + externalImageFormatInfo.pNext = VK_NULL_HANDLE; + externalImageFormatInfo.handleType = sharingInfo.type; + + VkPhysicalDeviceImageFormatInfo2 imageFormatInfo; + imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; + imageFormatInfo.pNext = &externalImageFormatInfo; + imageFormatInfo.format = createInfo.format; + imageFormatInfo.type = createInfo.imageType; + imageFormatInfo.tiling = createInfo.tiling; + imageFormatInfo.usage = createInfo.usage; + imageFormatInfo.flags = createInfo.flags; + + VkExternalImageFormatProperties externalImageFormatProperties; + externalImageFormatProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; + externalImageFormatProperties.pNext = nullptr; + externalImageFormatProperties.externalMemoryProperties = {}; + + VkImageFormatProperties2 imageFormatProperties; + imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; + imageFormatProperties.pNext = &externalImageFormatProperties; + imageFormatProperties.imageFormatProperties = {}; + + VkResult vr = m_device->adapter()->vki()->vkGetPhysicalDeviceImageFormatProperties2( + m_device->adapter()->handle(), &imageFormatInfo, &imageFormatProperties); + + if (vr != VK_SUCCESS) { + Logger::err(str::format("Failed to create shared resource: getImageProperties failed:", vr)); + return false; + } + + if (sharingInfo.mode == DxvkSharedHandleMode::Export) { + bool ret = externalImageFormatProperties.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT; + if (!ret) + Logger::err("Failed to create shared resource: image cannot be exported"); + return ret; + } + + if (sharingInfo.mode == DxvkSharedHandleMode::Import) { + bool ret = externalImageFormatProperties.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; + if (!ret) + Logger::err("Failed to create shared resource: image cannot be imported"); + return ret; + } + + return false; + } + + + HANDLE DxvkImage::sharedHandle() const { + HANDLE handle = INVALID_HANDLE_VALUE; + + if (!m_shared) + return INVALID_HANDLE_VALUE; + +#ifdef _WIN32 + VkMemoryGetWin32HandleInfoKHR handleInfo; + handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + handleInfo.pNext = nullptr; + handleInfo.handleType = m_info.sharing.type; + handleInfo.memory = m_image.memory.memory(); + if (m_vkd->vkGetMemoryWin32HandleKHR(m_vkd->device(), &handleInfo, &handle) != VK_SUCCESS) + Logger::warn("DxvkImage::DxvkImage: Failed to get shared handle for image"); +#endif + + return handle; + } + + DxvkImageView::DxvkImageView( const Rc& vkd, const Rc& image, @@ -247,4 +361,4 @@ namespace dxvk { } } -} \ No newline at end of file +} diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index 5b1a8b15..b3b8a58e 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -65,6 +65,9 @@ namespace dxvk { // be used with this image uint32_t viewFormatCount = 0; const VkFormat* viewFormats = nullptr; + + // Shared handle info + DxvkSharedHandleInfo sharing; }; @@ -124,7 +127,7 @@ namespace dxvk { public: DxvkImage( - const Rc& vkd, + const DxvkDevice* device, const DxvkImageCreateInfo& createInfo, DxvkMemoryAllocator& memAlloc, VkMemoryPropertyFlags memFlags); @@ -138,7 +141,7 @@ namespace dxvk { * otherwise some image operations may fail. */ DxvkImage( - const Rc& vkd, + const DxvkDevice* device, const DxvkImageCreateInfo& info, VkImage image); @@ -313,16 +316,26 @@ namespace dxvk { result.layerCount = info().numLayers; return result; } + + /** + * \brief Create a new shared handle to dedicated memory backing the image + * \returns The shared handle with the type given by DxvkSharedHandleInfo::type + */ + HANDLE sharedHandle() const; private: Rc m_vkd; + const DxvkDevice* m_device; DxvkImageCreateInfo m_info; VkMemoryPropertyFlags m_memFlags; DxvkPhysicalImage m_image; + bool m_shared = false; small_vector m_viewFormats; + bool canShareImage(const VkImageCreateInfo& createInfo, const DxvkSharedHandleInfo& sharingInfo) const; + }; @@ -555,4 +568,4 @@ namespace dxvk { }; -} \ No newline at end of file +} diff --git a/src/dxvk/dxvk_memory.h b/src/dxvk/dxvk_memory.h index 3d331b6b..795dd74d 100644 --- a/src/dxvk/dxvk_memory.h +++ b/src/dxvk/dxvk_memory.h @@ -17,8 +17,33 @@ namespace dxvk { VkDeviceSize memoryAllocated = 0; VkDeviceSize memoryUsed = 0; }; - - + + + enum class DxvkSharedHandleMode { + None, + Import, + Export, + }; + + /** + * \brief Shared handle info + * + * The shared resource information for a given resource. + */ + struct DxvkSharedHandleInfo { + DxvkSharedHandleMode mode = DxvkSharedHandleMode::None; + VkExternalMemoryHandleTypeFlagBits type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM; + union { +#ifdef _WIN32 + HANDLE handle = INVALID_HANDLE_VALUE; +#else + // Placeholder for other handle types, such as FD + void *dummy; +#endif + }; + }; + + /** * \brief Device memory object * @@ -370,4 +395,4 @@ namespace dxvk { }; -} \ No newline at end of file +}