From 68aff5ded59dd11e62fb807651d384407db54c58 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 6 Dec 2024 20:57:12 -0800 Subject: [PATCH] [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 efe66cfd9..d7d664dbb 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 f545849a9..e95f13080 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,