From 6640cc350c987c75c72f2a4832b740a2130c5fc9 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 23 Feb 2022 16:19:28 -0500 Subject: [PATCH] [d3d9] Add support for shared IDirect3DTexture9 resources. --- src/d3d9/d3d9_common_texture.cpp | 84 +++++++++++++++++++++++++++++--- src/d3d9/d3d9_common_texture.h | 9 ++-- src/d3d9/d3d9_device.cpp | 34 ++++++++++--- src/d3d9/d3d9_format.h | 4 +- src/d3d9/d3d9_options.h | 4 +- src/d3d9/d3d9_surface.cpp | 5 +- src/d3d9/d3d9_surface.h | 5 +- src/d3d9/d3d9_swapchain.cpp | 2 +- src/d3d9/d3d9_texture.cpp | 11 +++-- src/d3d9/d3d9_texture.h | 10 ++-- src/d3d9/d3d9_volume.cpp | 4 +- 11 files changed, 135 insertions(+), 37 deletions(-) diff --git a/src/d3d9/d3d9_common_texture.cpp b/src/d3d9/d3d9_common_texture.cpp index 8e5d237b..66a34c1e 100644 --- a/src/d3d9/d3d9_common_texture.cpp +++ b/src/d3d9/d3d9_common_texture.cpp @@ -3,6 +3,8 @@ #include "d3d9_util.h" #include "d3d9_device.h" +#include "../util/util_shared_res.h" + #include namespace dxvk { @@ -10,7 +12,8 @@ namespace dxvk { D3D9CommonTexture::D3D9CommonTexture( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc, - D3DRESOURCETYPE ResourceType) + D3DRESOURCETYPE ResourceType, + HANDLE* pSharedHandle) : m_device(pDevice), m_desc(*pDesc), m_type(ResourceType) { if (m_desc.Format == D3D9Format::Unknown) m_desc.Format = (m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) @@ -26,6 +29,9 @@ namespace dxvk { for (uint32_t i = 0; i < subresources; i++) { SetNeedsUpload(i, true); } + if (pSharedHandle) { + throw DxvkError("D3D9: Incompatible pool type for texture sharing."); + } } m_mapping = pDevice->LookupFormat(m_desc.Format); @@ -39,7 +45,7 @@ namespace dxvk { !(m_desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)); try { - m_image = CreatePrimaryImage(ResourceType, plainSurface); + m_image = CreatePrimaryImage(ResourceType, plainSurface, pSharedHandle); } catch (const DxvkError& e) { // D3DUSAGE_AUTOGENMIPMAP and offscreen plain is mutually exclusive @@ -47,12 +53,17 @@ namespace dxvk { if (m_desc.Usage & D3DUSAGE_AUTOGENMIPMAP || plainSurface) { m_desc.Usage &= ~D3DUSAGE_AUTOGENMIPMAP; m_desc.MipLevels = 1; - m_image = CreatePrimaryImage(ResourceType, false); + m_image = CreatePrimaryImage(ResourceType, false, pSharedHandle); } else throw e; } + if (pSharedHandle && *pSharedHandle == nullptr) { + *pSharedHandle = m_image->sharedHandle(); + ExportImageInfo(); + } + CreateSampleView(0); if (!IsManaged()) { @@ -206,7 +217,7 @@ namespace dxvk { } - Rc D3D9CommonTexture::CreatePrimaryImage(D3DRESOURCETYPE ResourceType, bool TryOffscreenRT) const { + Rc D3D9CommonTexture::CreatePrimaryImage(D3DRESOURCETYPE ResourceType, bool TryOffscreenRT, HANDLE* pSharedHandle) const { DxvkImageCreateInfo imageInfo; imageInfo.type = GetImageTypeFromResourceType(ResourceType); imageInfo.format = m_mapping.ConversionFormatInfo.FormatColor != VK_FORMAT_UNDEFINED @@ -230,6 +241,15 @@ namespace dxvk { imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.layout = VK_IMAGE_LAYOUT_GENERAL; imageInfo.shared = m_desc.IsBackBuffer; + if (pSharedHandle) { + imageInfo.sharing.type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; + if (*pSharedHandle) { + imageInfo.shared = true; + imageInfo.sharing.mode = *pSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import; + imageInfo.sharing.handle = *pSharedHandle; + } + // TODO: validate metadata? + } if (m_mapping.ConversionFormatInfo.FormatType != D3D9ConversionFormat_None) { imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT; @@ -280,7 +300,7 @@ namespace dxvk { // We must keep LINEAR images in GENERAL layout, but we // can choose a better layout for the image based on how // it is going to be used by the game. - if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL) + if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL && imageInfo.sharing.mode == DxvkSharedHandleMode::None) imageInfo.layout = OptimizeLayout(imageInfo.usage); // For some formats, we need to enable render target @@ -456,6 +476,58 @@ namespace dxvk { } + void D3D9CommonTexture::ExportImageInfo() { + /* From MSDN: + Textures being shared from D3D9 to D3D11 have the following restrictions. + + - Textures must be 2D + - Only 1 mip level is allowed + - Texture must have default usage + - Texture must be write only + - MSAA textures are not allowed + - Bind flags must have SHADER_RESOURCE and RENDER_TARGET set + - Only R10G10B10A2_UNORM, R16G16B16A16_FLOAT and R8G8B8A8_UNORM formats are allowed + */ + DXGI_FORMAT dxgiFormat = DXGI_FORMAT_UNKNOWN; + + switch (m_desc.Format) { + case D3D9Format::A2B10G10R10: dxgiFormat = DXGI_FORMAT_R10G10B10A2_UNORM; break; + case D3D9Format::A16B16G16R16F: dxgiFormat = DXGI_FORMAT_R16G16B16A16_FLOAT; break; + case D3D9Format::A8B8G8R8: dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM; break; + case D3D9Format::X8R8G8B8: dxgiFormat = DXGI_FORMAT_B8G8R8X8_UNORM; break; + default: + Logger::warn(str::format("D3D9: Unsupported format for shared textures", m_desc.Format)); + return; + } + + if (m_desc.Depth == 1 && m_desc.MipLevels == 1 && m_desc.MultiSample == D3DMULTISAMPLE_NONE && + m_desc.Usage & D3DUSAGE_RENDERTARGET && dxgiFormat != DXGI_FORMAT_UNKNOWN) { + HANDLE ntHandle = openKmtHandle(m_image->sharedHandle()); + + DxvkSharedTextureMetadata metadata; + + metadata.Width = m_desc.Width; + metadata.Height = m_desc.Height; + metadata.MipLevels = m_desc.MipLevels; + metadata.ArraySize = m_desc.ArraySize; + metadata.Format = dxgiFormat; + metadata.SampleDesc.Count = 1; + metadata.SampleDesc.Quality = 0; + metadata.Usage = D3D11_USAGE_DEFAULT; + metadata.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + metadata.CPUAccessFlags = 0; + metadata.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + metadata.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED; + + if (ntHandle == INVALID_HANDLE_VALUE || !setSharedMetadata(ntHandle, &metadata, sizeof(metadata))) + Logger::warn("D3D9: Failed to write shared resource info for a texture"); + + if (ntHandle != INVALID_HANDLE_VALUE) + ::CloseHandle(ntHandle); + } + } + + Rc D3D9CommonTexture::CreateView( UINT Layer, UINT Lod, @@ -531,4 +603,4 @@ namespace dxvk { } -} \ No newline at end of file +} diff --git a/src/d3d9/d3d9_common_texture.h b/src/d3d9/d3d9_common_texture.h index 57446453..e52ead2f 100644 --- a/src/d3d9/d3d9_common_texture.h +++ b/src/d3d9/d3d9_common_texture.h @@ -71,7 +71,8 @@ namespace dxvk { D3D9CommonTexture( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc, - D3DRESOURCETYPE ResourceType); + D3DRESOURCETYPE ResourceType, + HANDLE* pSharedHandle); ~D3D9CommonTexture(); @@ -513,7 +514,7 @@ namespace dxvk { */ VkDeviceSize GetMipSize(UINT Subresource) const; - Rc CreatePrimaryImage(D3DRESOURCETYPE ResourceType, bool TryOffscreenRT) const; + Rc CreatePrimaryImage(D3DRESOURCETYPE ResourceType, bool TryOffscreenRT, HANDLE* pSharedHandle) const; Rc CreateResolveImage() const; @@ -542,6 +543,8 @@ namespace dxvk { VkImageLayout OptimizeLayout( VkImageUsageFlags Usage) const; + void ExportImageInfo(); + static VkImageViewType GetImageViewTypeFromResourceType( D3DRESOURCETYPE Dimension, UINT Layer); @@ -550,4 +553,4 @@ namespace dxvk { }; -} \ No newline at end of file +} diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index d3e99829..b63e2c8f 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -457,12 +457,17 @@ namespace dxvk { return D3DERR_INVALIDCALL; try { - const Com texture = new D3D9Texture2D(this, &desc); - void* initialData = nullptr; - if (Pool == D3DPOOL_SYSTEMMEM && Levels == 1 && pSharedHandle != nullptr) + if (Pool == D3DPOOL_SYSTEMMEM && Levels == 1 && pSharedHandle != nullptr) { initialData = *(reinterpret_cast(pSharedHandle)); + pSharedHandle = nullptr; + } + + if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT) + return D3DERR_INVALIDCALL; + + const Com texture = new D3D9Texture2D(this, &desc, pSharedHandle); m_initializer->InitTexture(texture->GetCommonTexture(), initialData); *ppTexture = texture.ref(); @@ -491,6 +496,9 @@ namespace dxvk { if (unlikely(ppVolumeTexture == nullptr)) return D3DERR_INVALIDCALL; + if (pSharedHandle) + Logger::err("CreateVolumeTexture: Shared volume textures not supported"); + D3D9_COMMON_TEXTURE_DESC desc; desc.Width = Width; desc.Height = Height; @@ -536,6 +544,9 @@ namespace dxvk { if (unlikely(ppCubeTexture == nullptr)) return D3DERR_INVALIDCALL; + if (pSharedHandle) + Logger::err("CreateCubeTexture: Shared cube textures not supported"); + D3D9_COMMON_TEXTURE_DESC desc; desc.Width = EdgeLength; desc.Height = EdgeLength; @@ -580,6 +591,9 @@ namespace dxvk { if (unlikely(ppVertexBuffer == nullptr)) return D3DERR_INVALIDCALL; + if (pSharedHandle) + Logger::err("CreateVertexBuffer: Shared vertex buffers not supported"); + D3D9_BUFFER_DESC desc; desc.Format = D3D9Format::VERTEXDATA; desc.FVF = FVF; @@ -616,6 +630,9 @@ namespace dxvk { if (unlikely(ppIndexBuffer == nullptr)) return D3DERR_INVALIDCALL; + if (pSharedHandle) + Logger::err("CreateIndexBuffer: Shared index buffers not supported"); + D3D9_BUFFER_DESC desc; desc.Format = EnumerateFormat(Format); desc.Pool = Pool; @@ -3459,7 +3476,7 @@ namespace dxvk { return D3DERR_INVALIDCALL; try { - const Com surface = new D3D9Surface(this, &desc, nullptr); + const Com surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle); m_initializer->InitTexture(surface->GetCommonTexture()); *ppSurface = surface.ref(); return D3D_OK; @@ -3502,8 +3519,11 @@ namespace dxvk { if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc))) return D3DERR_INVALIDCALL; + if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT) + return D3DERR_INVALIDCALL; + try { - const Com surface = new D3D9Surface(this, &desc, nullptr); + const Com surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle); m_initializer->InitTexture(surface->GetCommonTexture()); *ppSurface = surface.ref(); return D3D_OK; @@ -3549,7 +3569,7 @@ namespace dxvk { return D3DERR_INVALIDCALL; try { - const Com surface = new D3D9Surface(this, &desc, nullptr); + const Com surface = new D3D9Surface(this, &desc, nullptr, pSharedHandle); m_initializer->InitTexture(surface->GetCommonTexture()); *ppSurface = surface.ref(); return D3D_OK; @@ -7296,7 +7316,7 @@ namespace dxvk { if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc))) return D3DERR_NOTAVAILABLE; - m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr); + m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr, nullptr); m_initializer->InitTexture(m_autoDepthStencil->GetCommonTexture()); SetDepthStencilSurface(m_autoDepthStencil.ptr()); } diff --git a/src/d3d9/d3d9_format.h b/src/d3d9/d3d9_format.h index 43ec8629..0c9ab168 100644 --- a/src/d3d9/d3d9_format.h +++ b/src/d3d9/d3d9_format.h @@ -1,6 +1,6 @@ #pragma once -#include "d3d9_include.h" +#include #include "d3d9_options.h" #include "../dxvk/dxvk_adapter.h" @@ -220,4 +220,4 @@ namespace dxvk { bool m_d32supportFinal; }; -} \ No newline at end of file +} diff --git a/src/d3d9/d3d9_options.h b/src/d3d9/d3d9_options.h index dff9b24f..029fe54e 100644 --- a/src/d3d9/d3d9_options.h +++ b/src/d3d9/d3d9_options.h @@ -3,8 +3,6 @@ #include "../util/config/config.h" #include "../dxvk/dxvk_device.h" -#include "d3d9_include.h" - namespace dxvk { enum class D3D9FloatEmulation { @@ -161,4 +159,4 @@ namespace dxvk { bool allowDirectBufferMapping; }; -} \ No newline at end of file +} diff --git a/src/d3d9/d3d9_surface.cpp b/src/d3d9/d3d9_surface.cpp index d1e28c57..300782e9 100644 --- a/src/d3d9/d3d9_surface.cpp +++ b/src/d3d9/d3d9_surface.cpp @@ -9,10 +9,11 @@ namespace dxvk { D3D9Surface::D3D9Surface( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc, - IUnknown* pContainer) + IUnknown* pContainer, + HANDLE* pSharedHandle) : D3D9SurfaceBase( pDevice, - new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_SURFACE), + new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_SURFACE, pSharedHandle), 0, 0, nullptr, pContainer) { } diff --git a/src/d3d9/d3d9_surface.h b/src/d3d9/d3d9_surface.h index 10086cac..3f420539 100644 --- a/src/d3d9/d3d9_surface.h +++ b/src/d3d9/d3d9_surface.h @@ -20,7 +20,8 @@ namespace dxvk { D3D9Surface( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc, - IUnknown* pContainer); + IUnknown* pContainer, + HANDLE* pSharedHandle); D3D9Surface( D3D9DeviceEx* pDevice, @@ -63,4 +64,4 @@ namespace dxvk { D3D9GDIDesc m_dcDesc; }; -} \ No newline at end of file +} diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 2cc5aaba..8dad6995 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -1038,7 +1038,7 @@ namespace dxvk { desc.IsAttachmentOnly = FALSE; for (uint32_t i = 0; i < m_backBuffers.size(); i++) - m_backBuffers[i] = new D3D9Surface(m_parent, &desc, this); + m_backBuffers[i] = new D3D9Surface(m_parent, &desc, this, nullptr); auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage(); diff --git a/src/d3d9/d3d9_texture.cpp b/src/d3d9/d3d9_texture.cpp index 73c4c570..4b2371ea 100644 --- a/src/d3d9/d3d9_texture.cpp +++ b/src/d3d9/d3d9_texture.cpp @@ -8,8 +8,9 @@ namespace dxvk { D3D9Texture2D::D3D9Texture2D( D3D9DeviceEx* pDevice, - const D3D9_COMMON_TEXTURE_DESC* pDesc) - : D3D9Texture2DBase( pDevice, pDesc, D3DRTYPE_TEXTURE ) { } + const D3D9_COMMON_TEXTURE_DESC* pDesc, + HANDLE* pSharedHandle) + : D3D9Texture2DBase( pDevice, pDesc, D3DRTYPE_TEXTURE, pSharedHandle ) { } HRESULT STDMETHODCALLTYPE D3D9Texture2D::QueryInterface(REFIID riid, void** ppvObject) { @@ -97,7 +98,7 @@ namespace dxvk { D3D9Texture3D::D3D9Texture3D( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc) - : D3D9Texture3DBase( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE ) { } + : D3D9Texture3DBase( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE, nullptr ) { } HRESULT STDMETHODCALLTYPE D3D9Texture3D::QueryInterface(REFIID riid, void** ppvObject) { @@ -179,7 +180,7 @@ namespace dxvk { D3D9TextureCube::D3D9TextureCube( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc) - : D3D9TextureCubeBase( pDevice, pDesc, D3DRTYPE_CUBETEXTURE ) { } + : D3D9TextureCubeBase( pDevice, pDesc, D3DRTYPE_CUBETEXTURE, nullptr ) { } HRESULT STDMETHODCALLTYPE D3D9TextureCube::QueryInterface(REFIID riid, void** ppvObject) { @@ -262,4 +263,4 @@ namespace dxvk { return D3D_OK; } -} \ No newline at end of file +} diff --git a/src/d3d9/d3d9_texture.h b/src/d3d9/d3d9_texture.h index 8d81dbee..317f72ee 100644 --- a/src/d3d9/d3d9_texture.h +++ b/src/d3d9/d3d9_texture.h @@ -23,9 +23,10 @@ namespace dxvk { D3D9BaseTexture( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc, - D3DRESOURCETYPE ResourceType) + D3DRESOURCETYPE ResourceType, + HANDLE* pSharedHandle) : D3D9Resource ( pDevice ) - , m_texture ( pDevice, pDesc, ResourceType ) + , m_texture ( pDevice, pDesc, ResourceType, pSharedHandle ) , m_lod ( 0 ) { const uint32_t arraySlices = m_texture.Desc()->ArraySize; const uint32_t mipLevels = m_texture.Desc()->MipLevels; @@ -130,7 +131,8 @@ namespace dxvk { D3D9Texture2D( D3D9DeviceEx* pDevice, - const D3D9_COMMON_TEXTURE_DESC* pDesc); + const D3D9_COMMON_TEXTURE_DESC* pDesc, + HANDLE* pSharedHandle); HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); @@ -240,4 +242,4 @@ namespace dxvk { dst = src; } -} \ No newline at end of file +} diff --git a/src/d3d9/d3d9_volume.cpp b/src/d3d9/d3d9_volume.cpp index 399566f3..52886d80 100644 --- a/src/d3d9/d3d9_volume.cpp +++ b/src/d3d9/d3d9_volume.cpp @@ -10,7 +10,7 @@ namespace dxvk { const D3D9_COMMON_TEXTURE_DESC* pDesc) : D3D9VolumeBase( pDevice, - new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE ), + new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE, nullptr ), 0, 0, nullptr, nullptr) { } @@ -109,4 +109,4 @@ namespace dxvk { m_face, m_mipLevel); } -} \ No newline at end of file +}