diff --git a/src/d3d9/d3d9_common_texture.cpp b/src/d3d9/d3d9_common_texture.cpp index cd29209de1af..85163d854f97 100644 --- a/src/d3d9/d3d9_common_texture.cpp +++ b/src/d3d9/d3d9_common_texture.cpp @@ -306,7 +306,8 @@ namespace dxvk { imageInfo.numLayers = m_desc.ArraySize; imageInfo.mipLevels = m_desc.MipLevels; imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT - | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + | VK_IMAGE_USAGE_TRANSFER_DST_BIT + | m_desc.ImageUsage; imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | m_device->GetEnabledShaderStages(); imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT diff --git a/src/d3d9/d3d9_common_texture.h b/src/d3d9/d3d9_common_texture.h index faee07d9b0fc..22c3fd4f7794 100644 --- a/src/d3d9/d3d9_common_texture.h +++ b/src/d3d9/d3d9_common_texture.h @@ -48,6 +48,9 @@ namespace dxvk { bool IsBackBuffer; bool IsAttachmentOnly; bool IsLockable; + + // Additional paramters for ID3D9VkInteropDevice + VkImageUsageFlags ImageUsage = 0; }; struct D3D9ColorView { diff --git a/src/d3d9/d3d9_interfaces.h b/src/d3d9/d3d9_interfaces.h index c0717eae5a03..89cf407244b5 100644 --- a/src/d3d9/d3d9_interfaces.h +++ b/src/d3d9/d3d9_interfaces.h @@ -34,7 +34,7 @@ ID3D9VkInteropInterface : public IUnknown { * \brief D3D9 texture interface for Vulkan interop * * Provides access to the backing resource of a - * D3D9 texture. + * D3D9 texture or surface. */ MIDL_INTERFACE("d56344f5-8d35-46fd-806d-94c351b472c1") ID3D9VkInteropTexture : public IUnknown { @@ -74,6 +74,27 @@ ID3D9VkInteropTexture : public IUnknown { VkImageCreateInfo* pInfo) = 0; }; + +/** + * \brief D3D9 image description + */ +struct D3D9VkExtImageDesc { + D3DRESOURCETYPE Type; // Can be SURFACE, TEXTURE, CUBETEXTURE, VOLUMETEXTURE + UINT Width; + UINT Height; + UINT Depth; // Can be > 1 for VOLUMETEXTURE + UINT MipLevels; // Can be > 1 for TEXTURE, CUBETEXTURE, VOLUMETEXTURE + DWORD Usage; + D3DFORMAT Format; + D3DPOOL Pool; + D3DMULTISAMPLE_TYPE MultiSample; // Must be NONE unless Type is SURFACE + DWORD MultisampleQuality; + bool Discard; // Depth stencils only + bool IsAttachmentOnly; // If false, then VK_IMAGE_USAGE_SAMPLED_BIT will be added + bool IsLockable; + VkImageUsageFlags ImageUsage; // Additional image usage flags +}; + /** * \brief D3D9 device interface for Vulkan interop * @@ -194,6 +215,17 @@ ID3D9VkInteropDevice : public IUnknown { virtual bool STDMETHODCALLTYPE WaitForResource( IDirect3DResource9* pResource, DWORD MapFlags) = 0; + + /** + * \brief Creates a custom image/surface/texture + * + * \param [in] desc Image description + * \param [out, retval] ppResult Pointer to a resource of the D3DRESOURCETYPE given by desc.Type + * \returns D3D_OK, D3DERR_INVALIDCALL, or D3DERR_OUTOFVIDEOMEMORY + */ + virtual HRESULT STDMETHODCALLTYPE CreateImage( + const D3D9VkExtImageDesc* desc, + IDirect3DResource9** ppResult) = 0; }; /** diff --git a/src/d3d9/d3d9_interop.cpp b/src/d3d9/d3d9_interop.cpp index 6f072f620603..069b26edc577 100644 --- a/src/d3d9/d3d9_interop.cpp +++ b/src/d3d9/d3d9_interop.cpp @@ -4,6 +4,7 @@ #include "d3d9_device.h" #include "d3d9_texture.h" #include "d3d9_buffer.h" +#include "d3d9_initializer.h" namespace dxvk { @@ -239,4 +240,107 @@ namespace dxvk { return m_device->WaitForResource(GetDxvkResource(pResource), DxvkCsThread::SynchronizeAll, MapFlags); } + HRESULT STDMETHODCALLTYPE D3D9VkInteropDevice::CreateImage( + const D3D9VkExtImageDesc* params, + IDirect3DResource9** ppResult) { + InitReturnPtr(ppResult); + + if (unlikely(ppResult == nullptr)) + return D3DERR_INVALIDCALL; + + if (unlikely(params == nullptr)) + return D3DERR_INVALIDCALL; + + ///////////////////////////// + // Image desc validation + + // Cannot create a volume by itself, use D3DRTYPE_VOLUMETEXTURE + if (unlikely(params->Type == D3DRTYPE_VOLUME)) + return D3DERR_INVALIDCALL; + + // Only allowed: SURFACE, TEXTURE, CUBETEXTURE, VOLUMETEXTURE + if (unlikely(params->Type < D3DRTYPE_SURFACE || params->Type > D3DRTYPE_CUBETEXTURE)) + return D3DERR_INVALIDCALL; + + // Only volume textures can have depth > 1 + if (unlikely(params->Type != D3DRTYPE_VOLUMETEXTURE && params->Depth > 1)) + return D3DERR_INVALIDCALL; + + if (params->Type == D3DRTYPE_SURFACE) { + // Surfaces can only have 1 mip level + if (unlikely(params->MipLevels > 1)) + return D3DERR_INVALIDCALL; + + if (unlikely(params->MultiSample > D3DMULTISAMPLE_16_SAMPLES)) + return D3DERR_INVALIDCALL; + } else { + // Textures can't be multisampled + if (unlikely(params->MultiSample != D3DMULTISAMPLE_NONE)) + return D3DERR_INVALIDCALL; + } + + D3D9_COMMON_TEXTURE_DESC desc; + desc.Width = params->Width; + desc.Height = params->Height; + desc.Depth = params->Depth; + desc.ArraySize = params->Type == D3DRTYPE_CUBETEXTURE ? 6 : 1; + desc.MipLevels = params->MipLevels; + desc.Usage = params->Usage; + desc.Format = EnumerateFormat(params->Format); + desc.Pool = params->Pool; + desc.Discard = params->Discard; + desc.MultiSample = params->MultiSample; + desc.MultisampleQuality = params->MultisampleQuality; + desc.IsBackBuffer = FALSE; + desc.IsAttachmentOnly = params->IsAttachmentOnly; + desc.IsLockable = params->IsLockable; + desc.ImageUsage = params->ImageUsage; + + D3DRESOURCETYPE textureType = params->Type; + if (params->Type == D3DRTYPE_SURFACE) + textureType = D3DRTYPE_TEXTURE; + else if (params->Type == D3DRTYPE_VOLUME) + textureType = D3DRTYPE_VOLUMETEXTURE; + + if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(m_device, textureType, &desc))) + return D3DERR_INVALIDCALL; + + switch (params->Type) { + case D3DRTYPE_SURFACE: + return CreateTextureResource(desc, ppResult); + + case D3DRTYPE_TEXTURE: + return CreateTextureResource(desc, ppResult); + + case D3DRTYPE_VOLUMETEXTURE: + return CreateTextureResource(desc, ppResult); + + case D3DRTYPE_CUBETEXTURE: + return CreateTextureResource(desc, ppResult); + + default: + return D3DERR_INVALIDCALL; + } + } + + template + HRESULT D3D9VkInteropDevice::CreateTextureResource( + const D3D9_COMMON_TEXTURE_DESC& desc, + IDirect3DResource9** ppResult) { + try { + const Com texture = new ResourceType(m_device, &desc); + m_device->m_initializer->InitTexture(texture->GetCommonTexture()); + *ppResult = texture.ref(); + + if (desc.Pool == D3DPOOL_DEFAULT) + m_device->m_losableResourceCounter++; + + return D3D_OK; + } + catch (const DxvkError& e) { + Logger::err(e.message()); + return D3DERR_OUTOFVIDEOMEMORY; + } + } + } diff --git a/src/d3d9/d3d9_interop.h b/src/d3d9/d3d9_interop.h index 742f69a9beea..b939b6f860e6 100644 --- a/src/d3d9/d3d9_interop.h +++ b/src/d3d9/d3d9_interop.h @@ -8,6 +8,7 @@ namespace dxvk { class D3D9InterfaceEx; class D3D9CommonTexture; class D3D9DeviceEx; + struct D3D9_COMMON_TEXTURE_DESC; class D3D9VkInteropInterface final : public ID3D9VkInteropInterface { @@ -118,8 +119,17 @@ namespace dxvk { IDirect3DResource9* pResource, DWORD MapFlags); + HRESULT STDMETHODCALLTYPE CreateImage( + const D3D9VkExtImageDesc* desc, + IDirect3DResource9** ppResult); + private: + template + HRESULT CreateTextureResource( + const D3D9_COMMON_TEXTURE_DESC& desc, + IDirect3DResource9** ppResult); + D3D9DeviceEx* m_device; D3D9DeviceLock m_lock; diff --git a/src/d3d9/d3d9_surface.h b/src/d3d9/d3d9_surface.h index 3f4205390aaa..d35bad7d38e7 100644 --- a/src/d3d9/d3d9_surface.h +++ b/src/d3d9/d3d9_surface.h @@ -20,8 +20,8 @@ namespace dxvk { D3D9Surface( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc, - IUnknown* pContainer, - HANDLE* pSharedHandle); + IUnknown* pContainer = nullptr, + HANDLE* pSharedHandle = nullptr); D3D9Surface( D3D9DeviceEx* pDevice, diff --git a/src/d3d9/d3d9_texture.h b/src/d3d9/d3d9_texture.h index fe9ff638ac32..50d981433c5f 100644 --- a/src/d3d9/d3d9_texture.h +++ b/src/d3d9/d3d9_texture.h @@ -132,7 +132,7 @@ namespace dxvk { D3D9Texture2D( D3D9DeviceEx* pDevice, const D3D9_COMMON_TEXTURE_DESC* pDesc, - HANDLE* pSharedHandle); + HANDLE* pSharedHandle = nullptr); HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);