1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-05 01:24:14 +01:00

[d3d9] Add ID3D9VkInteropDevice

Provides access to the device and instance handles
as well as the queue that is used for rendering.
This commit is contained in:
Joshua Ashton 2022-09-21 21:02:36 +00:00 committed by Joshie
parent e976218e17
commit d221bb7a9c
5 changed files with 317 additions and 1 deletions

View File

@ -54,7 +54,8 @@ namespace dxvk {
, m_multithread ( BehaviorFlags & D3DCREATE_MULTITHREADED )
, m_isSWVP ( (BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) ? true : false )
, m_csThread ( dxvkDevice, dxvkDevice->createContext(DxvkContextType::Primary) )
, m_csChunk ( AllocCsChunk() ) {
, m_csChunk ( AllocCsChunk() )
, m_d3d9Interop ( this ) {
// If we can SWVP, then we use an extended constant set
// as SWVP has many more slots available than HWVP.
bool canSWVP = CanSWVP();
@ -191,6 +192,11 @@ namespace dxvk {
return S_OK;
}
if (riid == __uuidof(ID3D9VkInteropDevice)) {
*ppvObject = ref(&m_d3d9Interop);
return S_OK;
}
// We want to ignore this if the extended device is queried and we weren't made extended.
if (riid == __uuidof(IDirect3DDevice9Ex))
return E_NOINTERFACE;

View File

@ -27,6 +27,7 @@
#include "d3d9_swvp_emu.h"
#include "d3d9_spec_constants.h"
#include "d3d9_interop.h"
#include <unordered_set>
#include <vector>
@ -118,6 +119,7 @@ namespace dxvk {
friend class D3D9SwapChainEx;
friend class D3D9ConstantBuffer;
friend class D3D9UserDefinedAnnotation;
friend D3D9VkInteropDevice;
public:
D3D9DeviceEx(
@ -1317,6 +1319,8 @@ namespace dxvk {
#ifdef D3D9_ALLOW_UNMAPPING
lru_list<D3D9CommonTexture*> m_mappedTextures;
#endif
D3D9VkInteropDevice m_d3d9Interop;
};
}

View File

@ -74,10 +74,134 @@ ID3D9VkInteropTexture : public IUnknown {
VkImageCreateInfo* pInfo) = 0;
};
/**
* \brief D3D9 device interface for Vulkan interop
*
* Provides access to the device and instance handles
* as well as the queue that is used for rendering.
*/
MIDL_INTERFACE("2eaa4b89-0107-4bdb-87f7-0f541c493ce0")
ID3D9VkInteropDevice : public IUnknown {
/**
* \brief Queries Vulkan handles used by DXVK
*
* \param [out] pInstance The Vulkan instance
* \param [out] pPhysDev The physical device
* \param [out] pDevide The device handle
*/
virtual void STDMETHODCALLTYPE GetVulkanHandles(
VkInstance* pInstance,
VkPhysicalDevice* pPhysDev,
VkDevice* pDevice) = 0;
/**
* \brief Queries the rendering queue used by DXVK
*
* \param [out] pQueue The Vulkan queue handle
* \param [out] pQueueIndex Queue index
* \param [out] pQueueFamilyIndex Queue family index
*/
virtual void STDMETHODCALLTYPE GetSubmissionQueue(
VkQueue* pQueue,
uint32_t* pQueueIndex,
uint32_t* pQueueFamilyIndex) = 0;
/**
* \brief Transitions a Texture to a given layout
*
* Executes an explicit image layout transition on the
* D3D device. Note that the image subresources \e must
* be transitioned back to its original layout before
* using it again from D3D9.
* Synchronization is left up to the caller.
* This function merely emits a call to transition the
* texture on the DXVK internal command stream.
* \param [in] pTexture The image to transform
* \param [in] pSubresources Subresources to transform
* \param [in] OldLayout Current image layout
* \param [in] NewLayout Desired image layout
*/
virtual void STDMETHODCALLTYPE TransitionTextureLayout(
ID3D9VkInteropTexture* pTexture,
const VkImageSubresourceRange* pSubresources,
VkImageLayout OldLayout,
VkImageLayout NewLayout) = 0;
/**
* \brief Flushes outstanding D3D rendering commands
*
* Must be called before submitting Vulkan commands
* to the rendering queue if those commands use the
* backing resource of a D3D9 object.
*/
virtual void STDMETHODCALLTYPE FlushRenderingCommands() = 0;
/**
* \brief Locks submission queue
*
* Should be called immediately before submitting
* Vulkan commands to the rendering queue in order
* to prevent DXVK from using the queue.
*
* While the submission queue is locked, no D3D9
* methods must be called from the locking thread,
* or otherwise a deadlock might occur.
*/
virtual void STDMETHODCALLTYPE LockSubmissionQueue() = 0;
/**
* \brief Releases submission queue
*
* Should be called immediately after submitting
* Vulkan commands to the rendering queue in order
* to allow DXVK to submit new commands.
*/
virtual void STDMETHODCALLTYPE ReleaseSubmissionQueue() = 0;
/**
* \brief Locks the device
*
* Can be called to ensure no D3D9 device methods
* can be executed until UnlockDevice has been called.
*
* This will do nothing if the D3DCREATE_MULTITHREADED
* is not set.
*/
virtual void STDMETHODCALLTYPE LockDevice() = 0;
/**
* \brief Unlocks the device
*
* Must only be called after a call to LockDevice.
*/
virtual void STDMETHODCALLTYPE UnlockDevice() = 0;
/**
* \brief Wait for a resource to finish being used
*
* Waits for the GPU resource associated with the
* resource to finish being used by the GPU.
*
* Valid D3DLOCK flags:
* - D3DLOCK_READONLY: Only waits for writes
* - D3DLOCK_DONOTWAIT: Does not wait for the resource (may flush)
*
* \param [in] pResource Resource to be waited upon
* \param [in] MapFlags D3DLOCK flags
* \returns true if the resource is ready to use,
* false if the resource is till in use
*/
virtual bool STDMETHODCALLTYPE WaitForResource(
IDirect3DResource9* pResource,
DWORD MapFlags) = 0;
};
#ifdef _MSC_VER
struct __declspec(uuid("3461a81b-ce41-485b-b6b5-fcf08ba6a6bd")) ID3D9VkInteropInterface;
struct __declspec(uuid("d56344f5-8d35-46fd-806d-94c351b472c1")) ID3D9VkInteropTexture;
struct __declspec(uuid("2eaa4b89-0107-4bdb-87f7-0f541c493ce0")) ID3D9VkInteropDevice;
#else
__CRT_UUID_DECL(ID3D9VkInteropInterface, 0x3461a81b,0xce41,0x485b,0xb6,0xb5,0xfc,0xf0,0x8b,0xa6,0xa6,0xbd);
__CRT_UUID_DECL(ID3D9VkInteropTexture, 0xd56344f5,0x8d35,0x46fd,0x80,0x6d,0x94,0xc3,0x51,0xb4,0x72,0xc1);
__CRT_UUID_DECL(ID3D9VkInteropDevice, 0x2eaa4b89,0x0107,0x4bdb,0x87,0xf7,0x0f,0x54,0x1c,0x49,0x3c,0xe0);
#endif

View File

@ -1,6 +1,9 @@
#include "d3d9_interop.h"
#include "d3d9_interface.h"
#include "d3d9_common_texture.h"
#include "d3d9_device.h"
#include "d3d9_texture.h"
#include "d3d9_buffer.h"
namespace dxvk {
@ -113,4 +116,127 @@ namespace dxvk {
return S_OK;
}
////////////////////////////////
// Device Interop
///////////////////////////////
D3D9VkInteropDevice::D3D9VkInteropDevice(
D3D9DeviceEx* pInterface)
: m_device(pInterface) {
}
D3D9VkInteropDevice::~D3D9VkInteropDevice() {
}
ULONG STDMETHODCALLTYPE D3D9VkInteropDevice::AddRef() {
return m_device->AddRef();
}
ULONG STDMETHODCALLTYPE D3D9VkInteropDevice::Release() {
return m_device->Release();
}
HRESULT STDMETHODCALLTYPE D3D9VkInteropDevice::QueryInterface(
REFIID riid,
void** ppvObject) {
return m_device->QueryInterface(riid, ppvObject);
}
void STDMETHODCALLTYPE D3D9VkInteropDevice::GetVulkanHandles(
VkInstance* pInstance,
VkPhysicalDevice* pPhysDev,
VkDevice* pDevice) {
auto device = m_device->GetDXVKDevice();
auto adapter = device->adapter();
auto instance = device->instance();
if (pDevice != nullptr)
*pDevice = device->handle();
if (pPhysDev != nullptr)
*pPhysDev = adapter->handle();
if (pInstance != nullptr)
*pInstance = instance->handle();
}
void STDMETHODCALLTYPE D3D9VkInteropDevice::GetSubmissionQueue(
VkQueue* pQueue,
uint32_t* pQueueIndex,
uint32_t* pQueueFamilyIndex) {
auto device = m_device->GetDXVKDevice();
DxvkDeviceQueue queue = device->queues().graphics;
if (pQueue != nullptr)
*pQueue = queue.queueHandle;
if (pQueueIndex != nullptr)
*pQueueIndex = queue.queueIndex;
if (pQueueFamilyIndex != nullptr)
*pQueueFamilyIndex = queue.queueFamily;
}
void STDMETHODCALLTYPE D3D9VkInteropDevice::TransitionTextureLayout(
ID3D9VkInteropTexture* pTexture,
const VkImageSubresourceRange* pSubresources,
VkImageLayout OldLayout,
VkImageLayout NewLayout) {
auto texture = static_cast<D3D9VkInteropTexture *>(pTexture)->GetCommonTexture();
m_device->EmitCs([
cImage = texture->GetImage(),
cSubresources = *pSubresources,
cOldLayout = OldLayout,
cNewLayout = NewLayout
] (DxvkContext* ctx) {
ctx->transformImage(
cImage, cSubresources,
cOldLayout, cNewLayout);
});
}
void STDMETHODCALLTYPE D3D9VkInteropDevice::FlushRenderingCommands() {
m_device->Flush();
m_device->SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
}
void STDMETHODCALLTYPE D3D9VkInteropDevice::LockSubmissionQueue() {
m_device->GetDXVKDevice()->lockSubmission();
}
void STDMETHODCALLTYPE D3D9VkInteropDevice::ReleaseSubmissionQueue() {
m_device->GetDXVKDevice()->unlockSubmission();
}
void STDMETHODCALLTYPE D3D9VkInteropDevice::LockDevice() {
m_lock = m_device->LockDevice();
}
void STDMETHODCALLTYPE D3D9VkInteropDevice::UnlockDevice() {
m_lock = D3D9DeviceLock();
}
static Rc<DxvkResource> GetDxvkResource(IDirect3DResource9 *pResource) {
switch (pResource->GetType()) {
case D3DRTYPE_SURFACE: return static_cast<D3D9Surface*> (pResource)->GetCommonTexture()->GetImage();
// Does not inherit from IDirect3DResource9... lol.
//case D3DRTYPE_VOLUME: return static_cast<D3D9Volume*> (pResource)->GetCommonTexture()->GetImage();
case D3DRTYPE_TEXTURE: return static_cast<D3D9Texture2D*> (pResource)->GetCommonTexture()->GetImage();
case D3DRTYPE_VOLUMETEXTURE: return static_cast<D3D9Texture3D*> (pResource)->GetCommonTexture()->GetImage();
case D3DRTYPE_CUBETEXTURE: return static_cast<D3D9TextureCube*> (pResource)->GetCommonTexture()->GetImage();
case D3DRTYPE_VERTEXBUFFER: return static_cast<D3D9VertexBuffer*>(pResource)->GetCommonBuffer()->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>();
case D3DRTYPE_INDEXBUFFER: return static_cast<D3D9IndexBuffer*> (pResource)->GetCommonBuffer()->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>();
default: return nullptr;
}
}
bool STDMETHODCALLTYPE D3D9VkInteropDevice::WaitForResource(
IDirect3DResource9* pResource,
DWORD MapFlags) {
return m_device->WaitForResource(GetDxvkResource(pResource), DxvkCsThread::SynchronizeAll, MapFlags);
}
}

View File

@ -1,11 +1,13 @@
#pragma once
#include "d3d9_interfaces.h"
#include "d3d9_multithread.h"
namespace dxvk {
class D3D9InterfaceEx;
class D3D9CommonTexture;
class D3D9DeviceEx;
class D3D9VkInteropInterface final : public ID3D9VkInteropInterface {
@ -69,4 +71,58 @@ namespace dxvk {
};
class D3D9VkInteropDevice final : public ID3D9VkInteropDevice {
public:
D3D9VkInteropDevice(
D3D9DeviceEx* pInterface);
~D3D9VkInteropDevice();
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
void** ppvObject);
void STDMETHODCALLTYPE GetVulkanHandles(
VkInstance* pInstance,
VkPhysicalDevice* pPhysDev,
VkDevice* pDevice);
void STDMETHODCALLTYPE GetSubmissionQueue(
VkQueue* pQueue,
uint32_t* pQueueIndex,
uint32_t* pQueueFamilyIndex);
void STDMETHODCALLTYPE TransitionTextureLayout(
ID3D9VkInteropTexture* pTexture,
const VkImageSubresourceRange* pSubresources,
VkImageLayout OldLayout,
VkImageLayout NewLayout);
void STDMETHODCALLTYPE FlushRenderingCommands();
void STDMETHODCALLTYPE LockSubmissionQueue();
void STDMETHODCALLTYPE ReleaseSubmissionQueue();
void STDMETHODCALLTYPE LockDevice();
void STDMETHODCALLTYPE UnlockDevice();
bool STDMETHODCALLTYPE WaitForResource(
IDirect3DResource9* pResource,
DWORD MapFlags);
private:
D3D9DeviceEx* m_device;
D3D9DeviceLock m_lock;
};
}