[d3d9] Add device import interop API

This commit is contained in:
Jeff 2024-11-29 03:06:35 -08:00
parent afc24ddbe9
commit 91e5e18141
No known key found for this signature in database
GPG key ID: 8B2B6A1CF435D14B
3 changed files with 164 additions and 0 deletions

View file

@ -3,6 +3,27 @@
#include "d3d9_include.h"
#include "../vulkan/vulkan_loader.h"
using D3D9VkQueueLockCallback = void(bool);
/**
* \brief Device import info
*/
struct D3D9VkDeviceImportInfo {
VkDevice device;
D3DDEVTYPE deviceType;
VkQueue graphicsQueue;
uint32_t graphicsQueueFamily;
VkQueue transferQueue;
uint32_t transferQueueFamily;
VkQueue sparseQueue;
uint32_t sparseQueueFamily;
uint32_t extensionCount;
const char** extensionNames;
const VkPhysicalDeviceFeatures2* features;
D3D9VkQueueLockCallback* queueLockCallback;
};
/**
* \brief D3D9 interface for Vulkan interop
*
@ -28,6 +49,39 @@ ID3D9VkInteropInterface : public IUnknown {
virtual void STDMETHODCALLTYPE GetPhysicalDeviceHandle(
UINT Adapter,
VkPhysicalDevice* pPhysicalDevice) = 0;
/**
* \brief Gets the VkDeviceCreateInfo for a D3D9 adapter
*
* \param [in] Adapter Adapter ordinal
* \param [out] pCreateInfo The Vulkan device create info
*/
virtual HRESULT STDMETHODCALLTYPE GetDeviceCreateInfo(
UINT Adapter,
VkDeviceCreateInfo* pCreateInfo) = 0;
/**
* \brief Create a D3D9 device for an existing Vulkan device
*
* It is suggested to create the device with the
* VkDeviceCreateInfo returned by GetDeviceCreateInfo,
* which will specify everything the device needs for
* DXVK to function.
*
* \param [in] Adapter Adapter ordinal
* \param [in] ... Arguments to IDirect3D9Ex::CreateDeviceEx
* \param [in] pInfo Info about the created device
* \param [out] ppReturnedDevice The D3D9 device
*/
virtual HRESULT STDMETHODCALLTYPE ImportDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
D3DDISPLAYMODEEX* pFullscreenDisplayMode,
D3D9VkDeviceImportInfo* pInfo,
IDirect3DDevice9Ex** ppReturnedDevice) = 0;
};
/**

View file

@ -51,6 +51,102 @@ namespace dxvk {
}
}
HRESULT STDMETHODCALLTYPE D3D9VkInteropInterface::GetDeviceCreateInfo(
UINT Adapter,
VkDeviceCreateInfo* pCreateInfo) {
if (unlikely(pCreateInfo == nullptr))
return D3DERR_INVALIDCALL;
auto* adapter = m_interface->GetAdapter(Adapter);
if (adapter == nullptr)
return D3DERR_INVALIDCALL;
auto dxvkAdapter = adapter->GetDXVKAdapter();
DxvkDeviceCreateInfo createInfo;
if (!dxvkAdapter->getDeviceCreateInfo(m_interface->GetInstance(), D3D9DeviceEx::GetDeviceFeatures(dxvkAdapter), false, createInfo))
return D3DERR_INVALIDCALL;
*pCreateInfo = createInfo.info;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE D3D9VkInteropInterface::ImportDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
D3DDISPLAYMODEEX* pFullscreenDisplayMode,
D3D9VkDeviceImportInfo* pInfo,
IDirect3DDevice9Ex** ppReturnedDevice) {
InitReturnPtr(ppReturnedDevice);
if (unlikely(ppReturnedDevice == nullptr
|| pPresentationParameters == nullptr))
return D3DERR_INVALIDCALL;
// Creating a device with D3DCREATE_PUREDEVICE only works in conjunction
// with D3DCREATE_HARDWARE_VERTEXPROCESSING on native drivers.
if (unlikely(BehaviorFlags & D3DCREATE_PUREDEVICE &&
!(BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)))
return D3DERR_INVALIDCALL;
HRESULT hr;
// Black Desert creates a D3DDEVTYPE_NULLREF device and
// expects it be created despite passing invalid parameters.
if (likely(DeviceType != D3DDEVTYPE_NULLREF)) {
hr = m_interface->ValidatePresentationParameters(pPresentationParameters);
if (unlikely(FAILED(hr)))
return hr;
}
auto* adapter = m_interface->GetAdapter(Adapter);
if (adapter == nullptr)
return D3DERR_INVALIDCALL;
auto dxvkAdapter = adapter->GetDXVKAdapter();
DxvkDeviceImportInfo info;
info.device = pInfo->device;
info.queue = pInfo->graphicsQueue;
info.queueFamily = pInfo->graphicsQueueFamily;
info.extensionCount = pInfo->extensionCount;
info.extensionNames = pInfo->extensionNames;
info.features = pInfo->features;
info.queueCallback = pInfo->queueLockCallback;
try {
auto dxvkDevice = dxvkAdapter->importDevice(m_interface->GetInstance(), info);
auto* device = new D3D9DeviceEx(
m_interface,
adapter,
DeviceType,
hFocusWindow,
BehaviorFlags,
dxvkDevice);
hr = device->InitialReset(pPresentationParameters, pFullscreenDisplayMode);
if (unlikely(FAILED(hr)))
return hr;
*ppReturnedDevice = ref(device);
}
catch (const DxvkError& e) {
Logger::err(e.message());
return D3DERR_NOTAVAILABLE;
}
return D3D_OK;
}
////////////////////////////////
// Texture Interop
///////////////////////////////

View file

@ -34,6 +34,20 @@ namespace dxvk {
UINT Adapter,
VkPhysicalDevice* pPhysicalDevice);
HRESULT STDMETHODCALLTYPE GetDeviceCreateInfo(
UINT Adapter,
VkDeviceCreateInfo* pCreateInfo);
HRESULT STDMETHODCALLTYPE ImportDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
D3DDISPLAYMODEEX* pFullscreenDisplayMode,
D3D9VkDeviceImportInfo* pInfo,
IDirect3DDevice9Ex** ppReturnedDevice);
private:
D3D9InterfaceEx* m_interface;