From 33981e6a21ef20091b39445f4a694401956d4ced Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 26 Jan 2025 19:43:52 +0000 Subject: [PATCH 1/3] [dxvk] Store AMD overalloc info in DxvkDeviceFeatures --- src/dxvk/dxvk_adapter.cpp | 6 +++--- src/dxvk/dxvk_device_info.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/dxvk/dxvk_adapter.cpp b/src/dxvk/dxvk_adapter.cpp index 1285c4eeb68..efe66cfd9a8 100644 --- a/src/dxvk/dxvk_adapter.cpp +++ b/src/dxvk/dxvk_adapter.cpp @@ -453,8 +453,8 @@ namespace dxvk { this->logFeatures(enabledFeatures); // Report the desired overallocation behaviour to the driver - VkDeviceMemoryOverallocationCreateInfoAMD overallocInfo = { VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD }; - overallocInfo.overallocationBehavior = VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD; + enabledFeatures.amdOverallocation = { VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD }; + enabledFeatures.amdOverallocation.overallocationBehavior = VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD; // Create the requested queues float queuePriority = 1.0f; @@ -487,7 +487,7 @@ namespace dxvk { info.pEnabledFeatures = &enabledFeatures.core.features; if (devExtensions.amdMemoryOverallocationBehaviour) - overallocInfo.pNext = std::exchange(info.pNext, &overallocInfo); + enabledFeatures.amdOverallocation.pNext = std::exchange(info.pNext, &enabledFeatures.amdOverallocation); VkDevice device = VK_NULL_HANDLE; VkResult vr = m_vki->vkCreateDevice(m_handle, &info, nullptr, &device); diff --git a/src/dxvk/dxvk_device_info.h b/src/dxvk/dxvk_device_info.h index 87f444a9d66..16747b2e16b 100644 --- a/src/dxvk/dxvk_device_info.h +++ b/src/dxvk/dxvk_device_info.h @@ -77,6 +77,7 @@ namespace dxvk { VkBool32 nvxBinaryImport; VkBool32 nvxImageViewHandle; VkBool32 khrWin32KeyedMutex; + VkDeviceMemoryOverallocationCreateInfoAMD amdOverallocation; }; } \ No newline at end of file From 68aff5ded59dd11e62fb807651d384407db54c58 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 6 Dec 2024 20:57:12 -0800 Subject: [PATCH 2/3] [dxvk] Support getting device create info without creating device --- src/dxvk/dxvk_adapter.cpp | 79 ++++++++++++++++++++++++++------------- src/dxvk/dxvk_adapter.h | 62 +++++++++++++++++++++++++----- 2 files changed, 106 insertions(+), 35 deletions(-) diff --git a/src/dxvk/dxvk_adapter.cpp b/src/dxvk/dxvk_adapter.cpp index efe66cfd9a8..d7d664dbb63 100644 --- a/src/dxvk/dxvk_adapter.cpp +++ b/src/dxvk/dxvk_adapter.cpp @@ -272,16 +272,21 @@ namespace dxvk { } - Rc DxvkAdapter::createDevice( - const Rc& instance, - DxvkDeviceFeatures enabledFeatures) { - DxvkDeviceExtensions devExtensions; + bool DxvkAdapter::getDeviceCreateInfo( + const Rc& instance, + VkDeviceCreateInfo& info, + DxvkDeviceFeatures& enabledFeatures, + DxvkDeviceCreateExtInfo& extInfo, + DxvkDeviceCreateQueueInfo& queueInfo) const { + auto& [devExtensions, extensionsEnabled, extensionNameList, enableCudaInterop] = extInfo; + auto& [queueFamilies, queueInfos] = queueInfo; + auto devExtensionList = getExtensionList(devExtensions); // Only enable Cuda interop extensions in 64-bit builds in // order to avoid potential driver or address space issues. // VK_KHR_buffer_device_address is expensive on some drivers. - bool enableCudaInterop = !env::is32BitHostPlatform() && + enableCudaInterop = !env::is32BitHostPlatform() && m_deviceExtensions.supports(devExtensions.nvxBinaryImport.name()) && m_deviceExtensions.supports(devExtensions.nvxImageViewHandle.name()) && m_deviceFeatures.vk12.bufferDeviceAddress; @@ -298,17 +303,15 @@ namespace dxvk { if (!m_deviceExtensions.supports(devExtensions.extPageableDeviceLocalMemory.name())) devExtensions.amdMemoryOverallocationBehaviour.setMode(DxvkExtMode::Optional); - DxvkNameSet extensionsEnabled; - if (!m_deviceExtensions.enableExtensions( devExtensionList.size(), devExtensionList.data(), &extensionsEnabled)) - throw DxvkError("DxvkAdapter: Failed to create device"); + return false; // Enable additional extensions if necessary extensionsEnabled.merge(m_extraExtensions); - DxvkNameList extensionNameList = extensionsEnabled.toNameList(); + extensionNameList = extensionsEnabled.toNameList(); // Always enable robust buffer access enabledFeatures.core.features.robustBufferAccess = VK_TRUE; @@ -443,34 +446,22 @@ namespace dxvk { // Create pNext chain for additional device features initFeatureChain(enabledFeatures, devExtensions, instance->extensions()); - // Log feature support info an extension list - Logger::info(str::format("Device properties:" - "\n Device : ", m_deviceInfo.core.properties.deviceName, - "\n Driver : ", m_deviceInfo.vk12.driverName, " ", m_deviceInfo.driverVersion.toString())); - - Logger::info("Enabled device extensions:"); - this->logNameList(extensionNameList); - this->logFeatures(enabledFeatures); - // Report the desired overallocation behaviour to the driver enabledFeatures.amdOverallocation = { VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD }; enabledFeatures.amdOverallocation.overallocationBehavior = VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD; // Create the requested queues - float queuePriority = 1.0f; - std::vector queueInfos; + static const float queuePriority = 1.0f; std::unordered_set queueFamiliySet; - DxvkAdapterQueueIndices queueFamilies = findQueueFamilies(); + queueFamilies = findQueueFamilies(); queueFamiliySet.insert(queueFamilies.graphics); queueFamiliySet.insert(queueFamilies.transfer); if (queueFamilies.sparse != VK_QUEUE_FAMILY_IGNORED) queueFamiliySet.insert(queueFamilies.sparse); - this->logQueueFamilies(queueFamilies); - for (uint32_t family : queueFamiliySet) { VkDeviceQueueCreateInfo graphicsQueue = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; graphicsQueue.queueFamilyIndex = family; @@ -479,7 +470,9 @@ namespace dxvk { queueInfos.push_back(graphicsQueue); } - VkDeviceCreateInfo info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, enabledFeatures.core.pNext }; + info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + info.pNext = enabledFeatures.core.pNext; + info.flags = 0; info.queueCreateInfoCount = queueInfos.size(); info.pQueueCreateInfos = queueInfos.data(); info.enabledExtensionCount = extensionNameList.count(); @@ -489,6 +482,34 @@ namespace dxvk { if (devExtensions.amdMemoryOverallocationBehaviour) enabledFeatures.amdOverallocation.pNext = std::exchange(info.pNext, &enabledFeatures.amdOverallocation); + return true; + } + + Rc DxvkAdapter::createDevice( + const Rc& instance, + DxvkDeviceFeatures enabledFeatures) { + VkDeviceCreateInfo info; + DxvkDeviceCreateExtInfo extInfo; + DxvkDeviceCreateQueueInfo queueInfo; + + // Get device creation info + if (!getDeviceCreateInfo(instance, info, enabledFeatures, extInfo, queueInfo)) + throw DxvkError("DxvkAdapter: Failed to create device"); + + auto& [devExtensions, extensionsEnabled, extensionNameList, enableCudaInterop] = extInfo; + auto& [queueFamilies, queueInfos] = queueInfo; + + // Log feature support info, extension list, and queue families + Logger::info(str::format("Device properties:" + "\n Device : ", m_deviceInfo.core.properties.deviceName, + "\n Driver : ", m_deviceInfo.vk12.driverName, " ", m_deviceInfo.driverVersion.toString())); + + Logger::info("Enabled device extensions:"); + this->logNameList(extensionNameList); + this->logFeatures(enabledFeatures); + this->logQueueFamilies(queueFamilies); + + // Create device! VkDevice device = VK_NULL_HANDLE; VkResult vr = m_vki->vkCreateDevice(m_handle, &info, nullptr, &device); @@ -661,11 +682,17 @@ namespace dxvk { // Create device loader Rc vkd = new vk::DeviceFn(m_vki, false, args.device); - // We only support one queue when importing devices, and no sparse. + // By default, we only use one queue when importing devices, and no sparse. DxvkDeviceQueueSet queues = { }; queues.graphics = { args.queue, args.queueFamily }; queues.transfer = queues.graphics; + if (args.transferQueue != VK_NULL_HANDLE && args.transferQueueFamily != VK_QUEUE_FAMILY_IGNORED) + queues.transfer = { args.transferQueue, args.transferQueueFamily }; + + if (args.sparseQueue != VK_NULL_HANDLE && args.sparseQueueFamily != VK_QUEUE_FAMILY_IGNORED) + queues.sparse = { args.sparseQueue, args.sparseQueueFamily }; + return new DxvkDevice(instance, this, vkd, enabledFeatures, queues, args.queueCallback); } @@ -992,7 +1019,7 @@ namespace dxvk { std::vector DxvkAdapter::getExtensionList( - DxvkDeviceExtensions& devExtensions) { + DxvkDeviceExtensions& devExtensions) const { return {{ &devExtensions.amdMemoryOverallocationBehaviour, &devExtensions.amdShaderFragmentMask, diff --git a/src/dxvk/dxvk_adapter.h b/src/dxvk/dxvk_adapter.h index f545849a9f7..e95f1308028 100644 --- a/src/dxvk/dxvk_adapter.h +++ b/src/dxvk/dxvk_adapter.h @@ -70,17 +70,41 @@ namespace dxvk { }; + /** + * \brief Device creation extension info + */ + struct DxvkDeviceCreateExtInfo { + DxvkDeviceExtensions deviceExtensions; + DxvkNameSet extensionsEnabled; + DxvkNameList extensionNameList; + bool enableCudaInterop; + }; + + /** + * \brief Device creation queue info + */ + struct DxvkDeviceCreateQueueInfo { + DxvkAdapterQueueIndices queueFamilies; + std::vector queueInfos; + }; + /** * \brief Device import info */ struct DxvkDeviceImportInfo { - VkDevice device; - VkQueue queue; - uint32_t queueFamily; - uint32_t extensionCount; - const char** extensionNames; - const VkPhysicalDeviceFeatures2* features; - DxvkQueueCallback queueCallback; + VkDevice device; + VkQueue queue; + uint32_t queueFamily; + uint32_t extensionCount; + const char** extensionNames; + const VkPhysicalDeviceFeatures2* features; + DxvkQueueCallback queueCallback; + + // Optional additional queues + VkQueue transferQueue = VK_NULL_HANDLE; + uint32_t transferQueueFamily = VK_QUEUE_FAMILY_IGNORED; + VkQueue sparseQueue = VK_NULL_HANDLE; + uint32_t sparseQueueFamily = VK_QUEUE_FAMILY_IGNORED; }; /** @@ -212,12 +236,32 @@ namespace dxvk { void enableExtensions( const DxvkNameSet& extensions); + /** + * \brief Gets DXVK device creation info + * + * Gets device creation info required for DXVK + * to function based on enabledFeatures + * + * \param [in] instance Parent instance + * \param [out] info Device create info + * \param [in,out] enabledFeatures Device features + * \param [out] extInfo Device extension list + * \param [out] queueInfo Device queue list + * \returns true if succeeded + */ + bool getDeviceCreateInfo( + const Rc& instance, + VkDeviceCreateInfo& info, + DxvkDeviceFeatures& enabledFeatures, + DxvkDeviceCreateExtInfo& extInfo, + DxvkDeviceCreateQueueInfo& queueInfo) const; + /** * \brief Creates a DXVK device * * Creates a logical device for this adapter. * \param [in] instance Parent instance - * \param [in] enabledFeatures Device features + * \param [in] requestedFeatures Device features * \returns Device handle */ Rc createDevice( @@ -343,7 +387,7 @@ namespace dxvk { VkQueueFlags flags) const; std::vector getExtensionList( - DxvkDeviceExtensions& devExtensions); + DxvkDeviceExtensions& devExtensions) const; static void initFeatureChain( DxvkDeviceFeatures& enabledFeatures, From 5159a65d4360cbf476a9940713a39b6757565f47 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 6 Dec 2024 20:57:37 -0800 Subject: [PATCH 3/3] [d3d9] Add complete device import interop API --- src/d3d9/d3d9_interfaces.h | 79 ++++++++++++++++++ src/d3d9/d3d9_interop.cpp | 154 ++++++++++++++++++++++++++++++++++++ src/d3d9/d3d9_interop.h | 17 ++++ src/dxvk/dxvk_device_info.h | 3 + 4 files changed, 253 insertions(+) diff --git a/src/d3d9/d3d9_interfaces.h b/src/d3d9/d3d9_interfaces.h index c4956e597b3..216fdb75584 100644 --- a/src/d3d9/d3d9_interfaces.h +++ b/src/d3d9/d3d9_interfaces.h @@ -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; + 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 * @@ -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; }; /** diff --git a/src/d3d9/d3d9_interop.cpp b/src/d3d9/d3d9_interop.cpp index 079f2919a65..d09a1c78321 100644 --- a/src/d3d9/d3d9_interop.cpp +++ b/src/d3d9/d3d9_interop.cpp @@ -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 /////////////////////////////// diff --git a/src/d3d9/d3d9_interop.h b/src/d3d9/d3d9_interop.h index b5ef1e2661d..db602dfde82 100644 --- a/src/d3d9/d3d9_interop.h +++ b/src/d3d9/d3d9_interop.h @@ -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; diff --git a/src/dxvk/dxvk_device_info.h b/src/dxvk/dxvk_device_info.h index 16747b2e16b..15fa6b44c84 100644 --- a/src/dxvk/dxvk_device_info.h +++ b/src/dxvk/dxvk_device_info.h @@ -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;