Skip to content

Commit

Permalink
[d3d9] Add complete device import interop API
Browse files Browse the repository at this point in the history
  • Loading branch information
AlpyneDreams committed Dec 8, 2024
1 parent 7a46b5c commit 6e8559c
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/d3d9/d3d9_interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,42 @@
#include "d3d9_include.h"
#include "../vulkan/vulkan_loader.h"

#include "../dxvk/dxvk_device_info.h"

using D3D9VkQueueLockCallback = void(bool);

/**
* \brief Device create info
*/
struct D3D9VkDeviceCreateInfo {
VkDeviceCreateInfo info;
dxvk::DxvkDeviceFeatures features;
uint32_t graphicsQueueFamily;
uint32_t transferQueueFamily;
uint32_t sparseQueueFamily;
VkDeviceQueueCreateInfo* pQueueCreateInfos;
const char** ppEnabledExtensionNames;
};

/**
* \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
*
Expand Down Expand Up @@ -48,6 +84,49 @@ ID3D9VkInteropInterface1 : public ID3D9VkInteropInterface {
virtual HRESULT STDMETHODCALLTYPE GetInstanceExtensions(
UINT* pExtensionCount,
const char** ppExtensions) = 0;

/**
* \brief Gets the device creation info for a D3D9 adapter
*
* When done using the info, call FreeDeviceCreateInfo to release it.
*
* \param [in] Adapter Adapter ordinal
* \param [out] ppCreateInfo Device create info
*/
virtual HRESULT STDMETHODCALLTYPE GetDeviceCreateInfo(
UINT Adapter,
D3D9VkDeviceCreateInfo** ppCreateInfo) = 0;

/**
* \brief Releases device creation info returned by GetDeviceCreateInfo
*
* \param [out] pCreateInfo Device create info
*/
virtual void STDMETHODCALLTYPE FreeDeviceCreateInfo(
D3D9VkDeviceCreateInfo* 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;
};

/**
Expand Down
154 changes: 154 additions & 0 deletions src/d3d9/d3d9_interop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,160 @@ namespace dxvk {
return (count < maxCount) ? D3DERR_MOREDATA : D3D_OK;
}

HRESULT STDMETHODCALLTYPE D3D9VkInteropInterface::GetDeviceCreateInfo(
UINT Adapter,
D3D9VkDeviceCreateInfo** ppCreateInfo) {
if (unlikely(ppCreateInfo == nullptr))
return D3DERR_INVALIDCALL;
InitReturnPtr(ppCreateInfo);

D3D9VkDeviceCreateInfo* pCreateInfo = new D3D9VkDeviceCreateInfo;

auto* adapter = m_interface->GetAdapter(Adapter);
if (unlikely(adapter == nullptr))
return D3DERR_INVALIDCALL;

auto dxvkAdapter = adapter->GetDXVKAdapter();

pCreateInfo->features = D3D9DeviceEx::GetDeviceFeatures(dxvkAdapter);

DxvkDeviceCreateExtInfo extInfo;
DxvkDeviceCreateQueueInfo queueInfo;
bool success = dxvkAdapter->getDeviceCreateInfo(
m_interface->GetInstance(),
pCreateInfo->info,
pCreateInfo->features,
extInfo,
queueInfo);

if (!success) {
delete pCreateInfo;
return D3DERR_INVALIDCALL;
}

// Queue family indices
pCreateInfo->graphicsQueueFamily = queueInfo.queueFamilies.graphics;
pCreateInfo->transferQueueFamily = queueInfo.queueFamilies.transfer;
pCreateInfo->sparseQueueFamily = queueInfo.queueFamilies.sparse;

// Queue create infos
const size_t queueCount = queueInfo.queueInfos.size();
pCreateInfo->pQueueCreateInfos = queueCount ? new VkDeviceQueueCreateInfo[queueCount] : nullptr;
for (size_t i = 0; i < queueCount; i++) {
pCreateInfo->pQueueCreateInfos[i] = queueInfo.queueInfos[i];
}
pCreateInfo->info.pQueueCreateInfos = pCreateInfo->pQueueCreateInfos;
pCreateInfo->info.queueCreateInfoCount = queueCount;

// Extension names
const uint32_t extCount = extInfo.extensionNameList.count();
pCreateInfo->ppEnabledExtensionNames = extCount > 0 ? new const char*[extCount] : nullptr;
for (uint32_t i = 0; i < extCount; i++) {
const char* nameStr = extInfo.extensionNameList.name(i);
size_t nameLen = std::strlen(nameStr);
char* name = new char[nameLen + 1];
std::strncpy(name, nameStr, nameLen);
name[nameLen] = '\0';
pCreateInfo->ppEnabledExtensionNames[i] = name;
}
pCreateInfo->info.ppEnabledExtensionNames = pCreateInfo->ppEnabledExtensionNames;
pCreateInfo->info.enabledExtensionCount = extCount;

*ppCreateInfo = pCreateInfo;
return D3D_OK;
}

void STDMETHODCALLTYPE D3D9VkInteropInterface::FreeDeviceCreateInfo(
D3D9VkDeviceCreateInfo* pCreateInfo) {
if (!pCreateInfo)
return;

if (pCreateInfo->ppEnabledExtensionNames != nullptr) {
for (uint32_t i = 0; i < pCreateInfo->info.enabledExtensionCount; i++) {
delete pCreateInfo->ppEnabledExtensionNames[i];
}

delete[] pCreateInfo->ppEnabledExtensionNames;
}

if (pCreateInfo->pQueueCreateInfos != nullptr)
delete[] pCreateInfo->pQueueCreateInfos;
delete pCreateInfo;
}

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
///////////////////////////////
Expand Down
17 changes: 17 additions & 0 deletions src/d3d9/d3d9_interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ namespace dxvk {
UINT* pExtensionCount,
const char** ppExtensions);

HRESULT STDMETHODCALLTYPE GetDeviceCreateInfo(
UINT Adapter,
D3D9VkDeviceCreateInfo** ppCreateInfo);

void STDMETHODCALLTYPE FreeDeviceCreateInfo(
D3D9VkDeviceCreateInfo* 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;
Expand Down
3 changes: 3 additions & 0 deletions src/dxvk/dxvk_device_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ namespace dxvk {
* Stores core features and extension-specific features.
* If the respective extensions are not available, the
* extended features will be marked as unsupported.
*
* NOTE: This struct is exposed by interop interfaces, please add
* new fields at the end of the struct to maintain compatibility.
*/
struct DxvkDeviceFeatures {
VkPhysicalDeviceFeatures2 core;
Expand Down

0 comments on commit 6e8559c

Please sign in to comment.