diff --git a/Include/Extensions/NRIHelper.h b/Include/Extensions/NRIHelper.h index fb235cc1..a7e6862f 100644 --- a/Include/Extensions/NRIHelper.h +++ b/Include/Extensions/NRIHelper.h @@ -6,10 +6,8 @@ NRI_NAMESPACE_BEGIN NRI_STRUCT(VideoMemoryInfo) { - uint64_t budget; - uint64_t currentUsage; - uint64_t availableForReservation; - uint64_t currentReservation; + uint64_t budgetSize; // the OS-provided video memory budget. If "usageSize" > "budgetSize", the application may incur stuttering or performance penalties + uint64_t usageSize; // specifies the application’s current video memory usage }; NRI_STRUCT(TextureSubresourceUploadDesc) @@ -73,18 +71,18 @@ NRI_STRUCT(FormatProps) NRI_STRUCT(HelperInterface) { // Optimized memory allocation for a group of resources - uint32_t (NRI_CALL *CalculateAllocationNumber)(NRI_NAME_REF(Device) device, const NRI_NAME_REF(ResourceGroupDesc) resourceGroupDesc); + uint32_t (NRI_CALL *CalculateAllocationNumber)(const NRI_NAME_REF(Device) device, const NRI_NAME_REF(ResourceGroupDesc) resourceGroupDesc); NRI_NAME(Result) (NRI_CALL *AllocateAndBindMemory)(NRI_NAME_REF(Device) device, const NRI_NAME_REF(ResourceGroupDesc) resourceGroupDesc, NRI_NAME(Memory)** allocations); - // Populate resources with data (not for streaming data) + // Populate resources with data (not for streaming!) NRI_NAME(Result) (NRI_CALL *UploadData)(NRI_NAME_REF(CommandQueue) commandQueue, const NRI_NAME(TextureUploadDesc)* textureUploadDescs, uint32_t textureUploadDescNum, const NRI_NAME(BufferUploadDesc)* bufferUploadDescs, uint32_t bufferUploadDescNum); // WFI NRI_NAME(Result) (NRI_CALL *WaitForIdle)(NRI_NAME_REF(CommandQueue) commandQueue); -}; -// Information about video memory -NRI_API bool NRI_CALL nriQueryVideoMemoryInfo(const NRI_NAME_REF(Device) device, NRI_NAME(MemoryLocation) memoryLocation, NRI_NAME_REF(VideoMemoryInfo) videoMemoryInfo); + // Information about video memory + NRI_NAME(Result) (NRI_CALL *QueryVideoMemoryInfo)(const NRI_NAME_REF(Device) device, NRI_NAME(MemoryLocation) memoryLocation, NRI_NAME_REF(VideoMemoryInfo) videoMemoryInfo); +}; // Format utilities NRI_API NRI_NAME(Format) NRI_CALL nriConvertDXGIFormatToNRI(uint32_t dxgiFormat); diff --git a/Source/Creation/Creation.cpp b/Source/Creation/Creation.cpp index 3d343e72..dede3ebe 100644 --- a/Source/Creation/Creation.cpp +++ b/Source/Creation/Creation.cpp @@ -17,6 +17,7 @@ Result CreateDeviceD3D12(const DeviceCreationD3D12Desc& deviceCreationDesc, Devi #if NRI_USE_VULKAN Result CreateDeviceVK(const DeviceCreationDesc& deviceCreationDesc, DeviceBase*& device); Result CreateDeviceVK(const DeviceCreationVKDesc& deviceDesc, DeviceBase*& device); +bool QueryVideoMemoryInfoVK(const Device& device, VideoMemoryInfo& videoMemoryInfo); #endif DeviceBase* CreateDeviceValidation(const DeviceCreationDesc& deviceCreationDesc, DeviceBase& device); @@ -334,29 +335,6 @@ NRI_API Result NRI_CALL nriEnumerateAdapters(AdapterDesc* adapterDescs, uint32_t return Result::SUCCESS; } -NRI_API bool NRI_CALL nriQueryVideoMemoryInfo(const Device& device, MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) { - uint64_t luid = ((DeviceBase&)device).GetDesc().adapterDesc.luid; - - ComPtr dxgifactory; - if (FAILED(CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgifactory)))) - return false; - - ComPtr adapter; - if (FAILED(dxgifactory->EnumAdapterByLuid(*(LUID*)&luid, IID_PPV_ARGS(&adapter)))) - return false; - - DXGI_QUERY_VIDEO_MEMORY_INFO info = {}; - if (FAILED(adapter->QueryVideoMemoryInfo(0, - (memoryLocation == MemoryLocation::DEVICE || memoryLocation == MemoryLocation::DEVICE_UPLOAD) ? DXGI_MEMORY_SEGMENT_GROUP_LOCAL : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, - &info))) - return false; - - static_assert(sizeof(VideoMemoryInfo) == sizeof(DXGI_QUERY_VIDEO_MEMORY_INFO)); - memcpy(&videoMemoryInfo, &info, sizeof(info)); - - return true; -} - NRI_API void NRI_CALL nriReportLiveObjects() { ComPtr pDebug; HRESULT hr = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&pDebug)); @@ -488,15 +466,6 @@ NRI_API Result NRI_CALL nriEnumerateAdapters(AdapterDesc* adapterDescs, uint32_t return nriResult; } -NRI_API bool NRI_CALL nriQueryVideoMemoryInfo(const Device& device, MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) { - MaybeUnused(device); - MaybeUnused(memoryLocation); - MaybeUnused(videoMemoryInfo); - - // TODO: use VK_EXT_memory_budget - return false; -} - NRI_API void NRI_CALL nriReportLiveObjects() { } diff --git a/Source/D3D11/DeviceD3D11.hpp b/Source/D3D11/DeviceD3D11.hpp index f216098b..ef1e1d47 100644 --- a/Source/D3D11/DeviceD3D11.hpp +++ b/Source/D3D11/DeviceD3D11.hpp @@ -290,7 +290,7 @@ Result DeviceD3D11::FillFunctionTable(SwapChainInterface& swapChainInterface) co #pragma region[ Helper ] -static uint32_t NRI_CALL CountAllocationNum(Device& device, const ResourceGroupDesc& resourceGroupDesc) { +static uint32_t NRI_CALL CalculateAllocationNumber(const Device& device, const ResourceGroupDesc& resourceGroupDesc) { return ((DeviceD3D11&)device).CalculateAllocationNumber(resourceGroupDesc); } @@ -298,10 +298,17 @@ static Result NRI_CALL AllocateAndBindMemory(Device& device, const ResourceGroup return ((DeviceD3D11&)device).AllocateAndBindMemory(resourceGroupDesc, allocations); } +static Result NRI_CALL QueryVideoMemoryInfo(const Device& device, MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) { + uint64_t luid = ((DeviceD3D11&)device).GetDesc().adapterDesc.luid; + + return QueryVideoMemoryInfoDXGI(luid, memoryLocation, videoMemoryInfo); +} + Result DeviceD3D11::FillFunctionTable(HelperInterface& helperInterface) const { helperInterface = {}; - helperInterface.CalculateAllocationNumber = ::CountAllocationNum; + helperInterface.CalculateAllocationNumber = ::CalculateAllocationNumber; helperInterface.AllocateAndBindMemory = ::AllocateAndBindMemory; + helperInterface.QueryVideoMemoryInfo = ::QueryVideoMemoryInfo; Helper_CommandQueue_PartiallyFillFunctionTableD3D11(helperInterface); diff --git a/Source/D3D12/DeviceD3D12.hpp b/Source/D3D12/DeviceD3D12.hpp index 5d738020..ddba7c2c 100644 --- a/Source/D3D12/DeviceD3D12.hpp +++ b/Source/D3D12/DeviceD3D12.hpp @@ -258,7 +258,7 @@ Result DeviceD3D12::FillFunctionTable(CoreInterface& coreInterface) const { #pragma region[ Helper ] -static uint32_t NRI_CALL CountAllocationNum(Device& device, const ResourceGroupDesc& resourceGroupDesc) { +static uint32_t NRI_CALL CalculateAllocationNumber(const Device& device, const ResourceGroupDesc& resourceGroupDesc) { return ((DeviceD3D12&)device).CalculateAllocationNumber(resourceGroupDesc); } @@ -266,10 +266,17 @@ static Result NRI_CALL AllocateAndBindMemory(Device& device, const ResourceGroup return ((DeviceD3D12&)device).AllocateAndBindMemory(resourceGroupDesc, allocations); } +static Result NRI_CALL QueryVideoMemoryInfo(const Device& device, MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) { + uint64_t luid = ((DeviceD3D12&)device).GetDesc().adapterDesc.luid; + + return QueryVideoMemoryInfoDXGI(luid, memoryLocation, videoMemoryInfo); +} + Result DeviceD3D12::FillFunctionTable(HelperInterface& helperInterface) const { helperInterface = {}; - helperInterface.CalculateAllocationNumber = ::CountAllocationNum; + helperInterface.CalculateAllocationNumber = ::CalculateAllocationNumber; helperInterface.AllocateAndBindMemory = ::AllocateAndBindMemory; + helperInterface.QueryVideoMemoryInfo = ::QueryVideoMemoryInfo; Helper_CommandQueue_PartiallyFillFunctionTableD3D12(helperInterface); diff --git a/Source/Shared/SharedExternal.cpp b/Source/Shared/SharedExternal.cpp index c7f426c4..bb9b54ac 100644 --- a/Source/Shared/SharedExternal.cpp +++ b/Source/Shared/SharedExternal.cpp @@ -379,6 +379,29 @@ bool HasOutput() { return false; } +nri::Result QueryVideoMemoryInfoDXGI(uint64_t luid, nri::MemoryLocation memoryLocation, nri::VideoMemoryInfo& videoMemoryInfo) { + videoMemoryInfo = {}; + + ComPtr dxgifactory; + if (FAILED(CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgifactory)))) + return nri::Result::FAILURE; + + ComPtr adapter; + if (FAILED(dxgifactory->EnumAdapterByLuid(*(LUID*)&luid, IID_PPV_ARGS(&adapter)))) + return nri::Result::FAILURE; + + bool isLocal = memoryLocation == nri::MemoryLocation::DEVICE || memoryLocation == nri::MemoryLocation::DEVICE_UPLOAD; + + DXGI_QUERY_VIDEO_MEMORY_INFO info = {}; + if (FAILED(adapter->QueryVideoMemoryInfo(0, isLocal ? DXGI_MEMORY_SEGMENT_GROUP_LOCAL : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info))) + return nri::Result::FAILURE; + + videoMemoryInfo.budgetSize = info.Budget; + videoMemoryInfo.usageSize = info.CurrentUsage; + + return nri::Result::SUCCESS; +} + #else uint32_t NRIFormatToDXGIFormat(nri::Format format) { diff --git a/Source/Shared/SharedExternal.h b/Source/Shared/SharedExternal.h index 01ec6fca..935f3caf 100644 --- a/Source/Shared/SharedExternal.h +++ b/Source/Shared/SharedExternal.h @@ -252,6 +252,7 @@ struct ComPtr { }; bool HasOutput(); +nri::Result QueryVideoMemoryInfoDXGI(uint64_t luid, nri::MemoryLocation memoryLocation, nri::VideoMemoryInfo& videoMemoryInfo); struct DisplayDescHelper { public: diff --git a/Source/VK/DeviceVK.cpp b/Source/VK/DeviceVK.cpp index ac89dfca..c1248802 100644 --- a/Source/VK/DeviceVK.cpp +++ b/Source/VK/DeviceVK.cpp @@ -259,6 +259,9 @@ void DeviceVK::ProcessDeviceExtensions(Vector& desiredDeviceExts, b if (IsExtensionSupported(VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME, supportedExts)) desiredDeviceExts.push_back(VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME); + if (IsExtensionSupported(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, supportedExts)) + desiredDeviceExts.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); + // Optional if (IsExtensionSupported(VK_NV_LOW_LATENCY_2_EXTENSION_NAME, supportedExts)) desiredDeviceExts.push_back(VK_NV_LOW_LATENCY_2_EXTENSION_NAME); @@ -567,6 +570,9 @@ Result DeviceVK::Create(const DeviceCreationDesc& deviceCreationDesc, const Devi APPEND_EXT(shaderAtomicFloat2Features); } + if (IsExtensionSupported(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, desiredDeviceExts)) + m_IsMemoryBudgetSupported = true; + m_VK.GetPhysicalDeviceFeatures2(m_PhysicalDevice, &features); { // Create device @@ -1269,6 +1275,7 @@ Result DeviceVK::ResolveInstanceDispatchTable(const Vector& desired GET_INSTANCE_PROC(DestroyInstance); GET_INSTANCE_PROC(DestroyDevice); GET_INSTANCE_PROC(GetPhysicalDeviceMemoryProperties); + GET_INSTANCE_PROC(GetPhysicalDeviceMemoryProperties2); GET_INSTANCE_PROC(GetDeviceGroupPeerMemoryFeatures); GET_INSTANCE_PROC(GetPhysicalDeviceFormatProperties); GET_INSTANCE_PROC(CreateDevice); @@ -1832,4 +1839,39 @@ inline Result DeviceVK::AllocateAndBindMemory(const ResourceGroupDesc& resourceG return allocator.AllocateAndBindMemory(resourceGroupDesc, allocations); } +Result DeviceVK::QueryVideoMemoryInfo(MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) const { + videoMemoryInfo = {}; + + if (!m_IsMemoryBudgetSupported) + return Result::UNSUPPORTED; + + VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProps = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT}; + + VkPhysicalDeviceMemoryProperties2 memoryProps = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2}; + memoryProps.pNext = &budgetProps; + + const auto& vk = GetDispatchTable(); + vk.GetPhysicalDeviceMemoryProperties2(m_PhysicalDevice, &memoryProps); + + bool isLocal = memoryLocation == nri::MemoryLocation::DEVICE || memoryLocation == nri::MemoryLocation::DEVICE_UPLOAD; + + for (uint32_t i = 0; i < GetCountOf(budgetProps.heapBudget); i++) { + VkDeviceSize size = budgetProps.heapBudget[i]; + bool state = m_MemoryProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT; + + if (size && state == isLocal) + videoMemoryInfo.budgetSize += size; + } + + for (uint32_t i = 0; i < GetCountOf(budgetProps.heapUsage); i++) { + VkDeviceSize size = budgetProps.heapUsage[i]; + bool state = m_MemoryProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT; + + if (size && state == isLocal) + videoMemoryInfo.usageSize += size; + } + + return Result::SUCCESS; +} + #include "DeviceVK.hpp" diff --git a/Source/VK/DeviceVK.h b/Source/VK/DeviceVK.h index ae471106..b0b5963f 100644 --- a/Source/VK/DeviceVK.h +++ b/Source/VK/DeviceVK.h @@ -2,8 +2,6 @@ #pragma once -struct IDXGIAdapter; - namespace nri { struct CommandQueueVK; @@ -114,6 +112,7 @@ struct DeviceVK final : public DeviceBase { FormatSupportBits GetFormatSupport(Format format) const; uint32_t CalculateAllocationNumber(const ResourceGroupDesc& resourceGroupDesc) const; Result AllocateAndBindMemory(const ResourceGroupDesc& resourceGroupDesc, Memory** allocations); + Result QueryVideoMemoryInfo(MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) const; //================================================================================================================ // DeviceBase @@ -156,6 +155,7 @@ struct DeviceVK final : public DeviceBase { bool m_IsPresentIdSupported = false; bool m_IsPresentWaitSupported = false; bool m_IsLowLatencySupported = false; + bool m_IsMemoryBudgetSupported = false; private: Vector m_ConcurrentSharingModeQueueIndices; diff --git a/Source/VK/DeviceVK.hpp b/Source/VK/DeviceVK.hpp index efc843fc..dff7417e 100644 --- a/Source/VK/DeviceVK.hpp +++ b/Source/VK/DeviceVK.hpp @@ -415,7 +415,7 @@ Result DeviceVK::FillFunctionTable(MeshShaderInterface& meshShaderInterface) con #pragma region[ Helper ] -static uint32_t NRI_CALL CountAllocationNum(Device& device, const ResourceGroupDesc& resourceGroupDesc) { +static uint32_t NRI_CALL CalculateAllocationNumber(const Device& device, const ResourceGroupDesc& resourceGroupDesc) { return ((DeviceVK&)device).CalculateAllocationNumber(resourceGroupDesc); } @@ -423,10 +423,15 @@ static Result NRI_CALL AllocateAndBindMemory(Device& device, const ResourceGroup return ((DeviceVK&)device).AllocateAndBindMemory(resourceGroupDesc, allocations); } +static Result NRI_CALL QueryVideoMemoryInfo(const Device& device, MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) { + return ((DeviceVK&)device).QueryVideoMemoryInfo(memoryLocation, videoMemoryInfo); +} + Result DeviceVK::FillFunctionTable(HelperInterface& helperInterface) const { helperInterface = {}; - helperInterface.CalculateAllocationNumber = ::CountAllocationNum; + helperInterface.CalculateAllocationNumber = ::CalculateAllocationNumber; helperInterface.AllocateAndBindMemory = ::AllocateAndBindMemory; + helperInterface.QueryVideoMemoryInfo = ::QueryVideoMemoryInfo; Helper_CommandQueue_PartiallyFillFunctionTableVK(helperInterface); diff --git a/Source/VK/DispatchTable.h b/Source/VK/DispatchTable.h index 55f0abc1..65edc08e 100644 --- a/Source/VK/DispatchTable.h +++ b/Source/VK/DispatchTable.h @@ -17,6 +17,7 @@ struct DispatchTable { VULKAN_FUNCTION(DestroyInstance); VULKAN_FUNCTION(DestroyDevice); VULKAN_FUNCTION(GetPhysicalDeviceMemoryProperties); + VULKAN_FUNCTION(GetPhysicalDeviceMemoryProperties2); VULKAN_FUNCTION(GetDeviceGroupPeerMemoryFeatures); VULKAN_FUNCTION(GetPhysicalDeviceFormatProperties); VULKAN_FUNCTION(CreateDevice); diff --git a/Source/Validation/DeviceVal.cpp b/Source/Validation/DeviceVal.cpp index 71e48dda..6a9c158f 100644 --- a/Source/Validation/DeviceVal.cpp +++ b/Source/Validation/DeviceVal.cpp @@ -1168,6 +1168,10 @@ Result DeviceVal::AllocateAndBindMemory(const ResourceGroupDesc& resourceGroupDe return result; } +Result DeviceVal::QueryVideoMemoryInfo(MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) const { + return m_HelperAPI.QueryVideoMemoryInfo(m_Device, memoryLocation, videoMemoryInfo); +} + Result DeviceVal::CreateRayTracingPipeline(const RayTracingPipelineDesc& pipelineDesc, Pipeline*& pipeline) { RETURN_ON_FAILURE(this, pipelineDesc.pipelineLayout != nullptr, Result::INVALID_ARGUMENT, "CreateRayTracingPipeline: 'pipelineDesc.pipelineLayout' is NULL"); RETURN_ON_FAILURE(this, pipelineDesc.shaderLibrary != nullptr, Result::INVALID_ARGUMENT, "CreateRayTracingPipeline: 'pipelineDesc.shaderLibrary' is NULL"); diff --git a/Source/Validation/DeviceVal.h b/Source/Validation/DeviceVal.h index 509dcfb9..8c9195ec 100644 --- a/Source/Validation/DeviceVal.h +++ b/Source/Validation/DeviceVal.h @@ -131,6 +131,7 @@ struct DeviceVal final : public DeviceBase { uint32_t CalculateAllocationNumber(const ResourceGroupDesc& resourceGroupDesc) const; Result AllocateAndBindMemory(const ResourceGroupDesc& resourceGroupDesc, Memory** allocations); + Result QueryVideoMemoryInfo(MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) const; //================================================================================================================ // DeviceBase diff --git a/Source/Validation/DeviceVal.hpp b/Source/Validation/DeviceVal.hpp index 9718ef89..a356a6b9 100644 --- a/Source/Validation/DeviceVal.hpp +++ b/Source/Validation/DeviceVal.hpp @@ -287,7 +287,7 @@ Result DeviceVal::FillFunctionTable(WrapperD3D11Interface& wrapperD3D11Interface #pragma region[ Helper ] -static uint32_t NRI_CALL CountAllocationNum(Device& device, const ResourceGroupDesc& resourceGroupDesc) { +static uint32_t NRI_CALL CalculateAllocationNumber(const Device& device, const ResourceGroupDesc& resourceGroupDesc) { return ((DeviceVal&)device).CalculateAllocationNumber(resourceGroupDesc); } @@ -295,10 +295,15 @@ static Result NRI_CALL AllocateAndBindMemory(Device& device, const ResourceGroup return ((DeviceVal&)device).AllocateAndBindMemory(resourceGroupDesc, allocations); } +static Result NRI_CALL QueryVideoMemoryInfo(const Device& device, MemoryLocation memoryLocation, VideoMemoryInfo& videoMemoryInfo) { + return ((DeviceVal&)device).QueryVideoMemoryInfo(memoryLocation, videoMemoryInfo); +} + Result DeviceVal::FillFunctionTable(HelperInterface& helperInterface) const { helperInterface = {}; - helperInterface.CalculateAllocationNumber = ::CountAllocationNum; + helperInterface.CalculateAllocationNumber = ::CalculateAllocationNumber; helperInterface.AllocateAndBindMemory = ::AllocateAndBindMemory; + helperInterface.QueryVideoMemoryInfo = ::QueryVideoMemoryInfo; Helper_CommandQueue_PartiallyFillFunctionTableVal(helperInterface);