Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2771c99

Browse files
committedDec 10, 2024··
[d3d9] Add complete device import interop API
1 parent 15565e5 commit 2771c99

File tree

4 files changed

+253
-0
lines changed

4 files changed

+253
-0
lines changed
 

‎src/d3d9/d3d9_interfaces.h

+79
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,42 @@
33
#include "d3d9_include.h"
44
#include "../vulkan/vulkan_loader.h"
55

6+
#include "../dxvk/dxvk_device_info.h"
7+
8+
using D3D9VkQueueLockCallback = void(bool);
9+
10+
/**
11+
* \brief Device create info
12+
*/
13+
struct D3D9VkDeviceCreateInfo {
14+
VkDeviceCreateInfo info;
15+
dxvk::DxvkDeviceFeatures features;
16+
uint32_t graphicsQueueFamily;
17+
uint32_t transferQueueFamily;
18+
uint32_t sparseQueueFamily;
19+
VkDeviceQueueCreateInfo* pQueueCreateInfos;
20+
const char** ppEnabledExtensionNames;
21+
};
22+
23+
/**
24+
* \brief Device import info
25+
*/
26+
struct D3D9VkDeviceImportInfo {
27+
VkDevice device;
28+
D3DDEVTYPE deviceType;
29+
VkQueue graphicsQueue;
30+
uint32_t graphicsQueueFamily;
31+
VkQueue transferQueue;
32+
uint32_t transferQueueFamily;
33+
VkQueue sparseQueue;
34+
uint32_t sparseQueueFamily;
35+
uint32_t extensionCount;
36+
const char** extensionNames;
37+
const VkPhysicalDeviceFeatures2* features;
38+
D3D9VkQueueLockCallback* queueLockCallback;
39+
};
40+
41+
642
/**
743
* \brief D3D9 interface for Vulkan interop
844
*
@@ -48,6 +84,49 @@ ID3D9VkInteropInterface1 : public ID3D9VkInteropInterface {
4884
virtual HRESULT STDMETHODCALLTYPE GetInstanceExtensions(
4985
UINT* pExtensionCount,
5086
const char** ppExtensions) = 0;
87+
88+
/**
89+
* \brief Gets the device creation info for a D3D9 adapter
90+
*
91+
* When done using the info, call FreeDeviceCreateInfo to release it.
92+
*
93+
* \param [in] Adapter Adapter ordinal
94+
* \param [out] ppCreateInfo Device create info
95+
*/
96+
virtual HRESULT STDMETHODCALLTYPE GetDeviceCreateInfo(
97+
UINT Adapter,
98+
D3D9VkDeviceCreateInfo** ppCreateInfo) = 0;
99+
100+
/**
101+
* \brief Releases device creation info returned by GetDeviceCreateInfo
102+
*
103+
* \param [out] pCreateInfo Device create info
104+
*/
105+
virtual void STDMETHODCALLTYPE FreeDeviceCreateInfo(
106+
D3D9VkDeviceCreateInfo* pCreateInfo) = 0;
107+
108+
/**
109+
* \brief Create a D3D9 device for an existing Vulkan device
110+
*
111+
* It is suggested to create the device with the
112+
* VkDeviceCreateInfo returned by GetDeviceCreateInfo,
113+
* which will specify everything the device needs for
114+
* DXVK to function.
115+
*
116+
* \param [in] Adapter Adapter ordinal
117+
* \param [in] ... Arguments to IDirect3D9Ex::CreateDeviceEx
118+
* \param [in] pInfo Info about the created device
119+
* \param [out] ppReturnedDevice The D3D9 device
120+
*/
121+
virtual HRESULT STDMETHODCALLTYPE ImportDevice(
122+
UINT Adapter,
123+
D3DDEVTYPE DeviceType,
124+
HWND hFocusWindow,
125+
DWORD BehaviorFlags,
126+
D3DPRESENT_PARAMETERS* pPresentationParameters,
127+
D3DDISPLAYMODEEX* pFullscreenDisplayMode,
128+
D3D9VkDeviceImportInfo* pInfo,
129+
IDirect3DDevice9Ex** ppReturnedDevice) = 0;
51130
};
52131

53132
/**

‎src/d3d9/d3d9_interop.cpp

+154
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,160 @@ namespace dxvk {
7676
return (count < maxCount) ? D3DERR_MOREDATA : D3D_OK;
7777
}
7878

79+
HRESULT STDMETHODCALLTYPE D3D9VkInteropInterface::GetDeviceCreateInfo(
80+
UINT Adapter,
81+
D3D9VkDeviceCreateInfo** ppCreateInfo) {
82+
if (unlikely(ppCreateInfo == nullptr))
83+
return D3DERR_INVALIDCALL;
84+
InitReturnPtr(ppCreateInfo);
85+
86+
D3D9VkDeviceCreateInfo* pCreateInfo = new D3D9VkDeviceCreateInfo;
87+
88+
auto* adapter = m_interface->GetAdapter(Adapter);
89+
if (unlikely(adapter == nullptr))
90+
return D3DERR_INVALIDCALL;
91+
92+
auto dxvkAdapter = adapter->GetDXVKAdapter();
93+
94+
pCreateInfo->features = D3D9DeviceEx::GetDeviceFeatures(dxvkAdapter);
95+
96+
DxvkDeviceCreateExtInfo extInfo;
97+
DxvkDeviceCreateQueueInfo queueInfo;
98+
bool success = dxvkAdapter->getDeviceCreateInfo(
99+
m_interface->GetInstance(),
100+
pCreateInfo->info,
101+
pCreateInfo->features,
102+
extInfo,
103+
queueInfo);
104+
105+
if (!success) {
106+
delete pCreateInfo;
107+
return D3DERR_INVALIDCALL;
108+
}
109+
110+
// Queue family indices
111+
pCreateInfo->graphicsQueueFamily = queueInfo.queueFamilies.graphics;
112+
pCreateInfo->transferQueueFamily = queueInfo.queueFamilies.transfer;
113+
pCreateInfo->sparseQueueFamily = queueInfo.queueFamilies.sparse;
114+
115+
// Queue create infos
116+
const size_t queueCount = queueInfo.queueInfos.size();
117+
pCreateInfo->pQueueCreateInfos = queueCount ? new VkDeviceQueueCreateInfo[queueCount] : nullptr;
118+
for (size_t i = 0; i < queueCount; i++) {
119+
pCreateInfo->pQueueCreateInfos[i] = queueInfo.queueInfos[i];
120+
}
121+
pCreateInfo->info.pQueueCreateInfos = pCreateInfo->pQueueCreateInfos;
122+
pCreateInfo->info.queueCreateInfoCount = queueCount;
123+
124+
// Extension names
125+
const uint32_t extCount = extInfo.extensionNameList.count();
126+
pCreateInfo->ppEnabledExtensionNames = extCount > 0 ? new const char*[extCount] : nullptr;
127+
for (uint32_t i = 0; i < extCount; i++) {
128+
const char* nameStr = extInfo.extensionNameList.name(i);
129+
size_t nameLen = std::strlen(nameStr);
130+
char* name = new char[nameLen + 1];
131+
std::strncpy(name, nameStr, nameLen);
132+
name[nameLen] = '\0';
133+
pCreateInfo->ppEnabledExtensionNames[i] = name;
134+
}
135+
pCreateInfo->info.ppEnabledExtensionNames = pCreateInfo->ppEnabledExtensionNames;
136+
pCreateInfo->info.enabledExtensionCount = extCount;
137+
138+
*ppCreateInfo = pCreateInfo;
139+
return D3D_OK;
140+
}
141+
142+
void STDMETHODCALLTYPE D3D9VkInteropInterface::FreeDeviceCreateInfo(
143+
D3D9VkDeviceCreateInfo* pCreateInfo) {
144+
if (!pCreateInfo)
145+
return;
146+
147+
if (pCreateInfo->ppEnabledExtensionNames != nullptr) {
148+
for (uint32_t i = 0; i < pCreateInfo->info.enabledExtensionCount; i++) {
149+
delete pCreateInfo->ppEnabledExtensionNames[i];
150+
}
151+
152+
delete[] pCreateInfo->ppEnabledExtensionNames;
153+
}
154+
155+
if (pCreateInfo->pQueueCreateInfos != nullptr)
156+
delete[] pCreateInfo->pQueueCreateInfos;
157+
delete pCreateInfo;
158+
}
159+
160+
HRESULT STDMETHODCALLTYPE D3D9VkInteropInterface::ImportDevice(
161+
UINT Adapter,
162+
D3DDEVTYPE DeviceType,
163+
HWND hFocusWindow,
164+
DWORD BehaviorFlags,
165+
D3DPRESENT_PARAMETERS* pPresentationParameters,
166+
D3DDISPLAYMODEEX* pFullscreenDisplayMode,
167+
D3D9VkDeviceImportInfo* pInfo,
168+
IDirect3DDevice9Ex** ppReturnedDevice) {
169+
InitReturnPtr(ppReturnedDevice);
170+
171+
if (unlikely(ppReturnedDevice == nullptr
172+
|| pPresentationParameters == nullptr))
173+
return D3DERR_INVALIDCALL;
174+
175+
// Creating a device with D3DCREATE_PUREDEVICE only works in conjunction
176+
// with D3DCREATE_HARDWARE_VERTEXPROCESSING on native drivers.
177+
if (unlikely(BehaviorFlags & D3DCREATE_PUREDEVICE &&
178+
!(BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)))
179+
return D3DERR_INVALIDCALL;
180+
181+
HRESULT hr;
182+
// Black Desert creates a D3DDEVTYPE_NULLREF device and
183+
// expects it be created despite passing invalid parameters.
184+
if (likely(DeviceType != D3DDEVTYPE_NULLREF)) {
185+
hr = m_interface->ValidatePresentationParameters(pPresentationParameters);
186+
187+
if (unlikely(FAILED(hr)))
188+
return hr;
189+
}
190+
191+
auto* adapter = m_interface->GetAdapter(Adapter);
192+
193+
if (adapter == nullptr)
194+
return D3DERR_INVALIDCALL;
195+
196+
auto dxvkAdapter = adapter->GetDXVKAdapter();
197+
198+
DxvkDeviceImportInfo info;
199+
info.device = pInfo->device;
200+
info.queue = pInfo->graphicsQueue;
201+
info.queueFamily = pInfo->graphicsQueueFamily;
202+
info.extensionCount = pInfo->extensionCount;
203+
info.extensionNames = pInfo->extensionNames;
204+
info.features = pInfo->features;
205+
info.queueCallback = pInfo->queueLockCallback;
206+
207+
try {
208+
auto dxvkDevice = dxvkAdapter->importDevice(m_interface->GetInstance(), info);
209+
210+
auto* device = new D3D9DeviceEx(
211+
m_interface,
212+
adapter,
213+
DeviceType,
214+
hFocusWindow,
215+
BehaviorFlags,
216+
dxvkDevice);
217+
218+
hr = device->InitialReset(pPresentationParameters, pFullscreenDisplayMode);
219+
220+
if (unlikely(FAILED(hr)))
221+
return hr;
222+
223+
*ppReturnedDevice = ref(device);
224+
}
225+
catch (const DxvkError& e) {
226+
Logger::err(e.message());
227+
return D3DERR_NOTAVAILABLE;
228+
}
229+
230+
return D3D_OK;
231+
}
232+
79233
////////////////////////////////
80234
// Texture Interop
81235
///////////////////////////////

‎src/d3d9/d3d9_interop.h

+17
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,23 @@ namespace dxvk {
3838
UINT* pExtensionCount,
3939
const char** ppExtensions);
4040

41+
HRESULT STDMETHODCALLTYPE GetDeviceCreateInfo(
42+
UINT Adapter,
43+
D3D9VkDeviceCreateInfo** ppCreateInfo);
44+
45+
void STDMETHODCALLTYPE FreeDeviceCreateInfo(
46+
D3D9VkDeviceCreateInfo* pCreateInfo);
47+
48+
HRESULT STDMETHODCALLTYPE ImportDevice(
49+
UINT Adapter,
50+
D3DDEVTYPE DeviceType,
51+
HWND hFocusWindow,
52+
DWORD BehaviorFlags,
53+
D3DPRESENT_PARAMETERS* pPresentationParameters,
54+
D3DDISPLAYMODEEX* pFullscreenDisplayMode,
55+
D3D9VkDeviceImportInfo* pInfo,
56+
IDirect3DDevice9Ex** ppReturnedDevice);
57+
4158
private:
4259

4360
D3D9InterfaceEx* m_interface;

‎src/dxvk/dxvk_device_info.h

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ namespace dxvk {
3838
* Stores core features and extension-specific features.
3939
* If the respective extensions are not available, the
4040
* extended features will be marked as unsupported.
41+
*
42+
* NOTE: This struct is exposed by interop interfaces, please add
43+
* new fields at the end of the struct to maintain compatibility.
4144
*/
4245
struct DxvkDeviceFeatures {
4346
VkPhysicalDeviceFeatures2 core;

0 commit comments

Comments
 (0)
Please sign in to comment.