mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-06 20:58:37 +01:00
[d3d9] Add complete device import interop API
This commit is contained in:
parent
68aff5ded5
commit
5159a65d43
4 changed files with 253 additions and 0 deletions
|
@ -3,6 +3,42 @@
|
||||||
#include "d3d9_include.h"
|
#include "d3d9_include.h"
|
||||||
#include "../vulkan/vulkan_loader.h"
|
#include "../vulkan/vulkan_loader.h"
|
||||||
|
|
||||||
|
#include "../dxvk/dxvk_device_info.h"
|
||||||
|
|
||||||
|
using D3D9VkQueueLockCallback = void(bool);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Device create info
|
||||||
|
*/
|
||||||
|
struct D3D9VkDeviceCreateInfo {
|
||||||
|
VkDeviceCreateInfo info;
|
||||||
|
uint32_t graphicsQueueFamily;
|
||||||
|
uint32_t transferQueueFamily;
|
||||||
|
uint32_t sparseQueueFamily;
|
||||||
|
VkDeviceQueueCreateInfo* pQueueCreateInfos;
|
||||||
|
const char** ppEnabledExtensionNames;
|
||||||
|
dxvk::DxvkDeviceFeatures features;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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
|
* \brief D3D9 interface for Vulkan interop
|
||||||
*
|
*
|
||||||
|
@ -48,6 +84,49 @@ ID3D9VkInteropInterface1 : public ID3D9VkInteropInterface {
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetInstanceExtensions(
|
virtual HRESULT STDMETHODCALLTYPE GetInstanceExtensions(
|
||||||
UINT* pExtensionCount,
|
UINT* pExtensionCount,
|
||||||
const char** ppExtensions) = 0;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -76,6 +76,160 @@ namespace dxvk {
|
||||||
return (count < maxCount) ? D3DERR_MOREDATA : D3D_OK;
|
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
|
// Texture Interop
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
|
@ -38,6 +38,23 @@ namespace dxvk {
|
||||||
UINT* pExtensionCount,
|
UINT* pExtensionCount,
|
||||||
const char** ppExtensions);
|
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:
|
private:
|
||||||
|
|
||||||
D3D9InterfaceEx* m_interface;
|
D3D9InterfaceEx* m_interface;
|
||||||
|
|
|
@ -38,6 +38,9 @@ namespace dxvk {
|
||||||
* Stores core features and extension-specific features.
|
* Stores core features and extension-specific features.
|
||||||
* If the respective extensions are not available, the
|
* If the respective extensions are not available, the
|
||||||
* extended features will be marked as unsupported.
|
* 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 {
|
struct DxvkDeviceFeatures {
|
||||||
VkPhysicalDeviceFeatures2 core;
|
VkPhysicalDeviceFeatures2 core;
|
||||||
|
|
Loading…
Add table
Reference in a new issue