Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[d3d9] Add device import interop API #4506

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading
Loading