Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nvapi-gpu: Add NvAPI_GPU_GetMemoryInfo/Ex #198

Merged
merged 6 commits into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 102 additions & 2 deletions src/nvapi_gpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ extern "C" {
if (!nvapiAdapterRegistry->IsAdapter(adapter))
return ExpectedPhysicalGpuHandle(n);

*pSize = adapter->GetVRamSize();
*pSize = adapter->GetMemoryInfo().DedicatedVideoMemory / 1024;

return Ok(n);
}
Expand All @@ -382,11 +382,111 @@ extern "C" {
if (!nvapiAdapterRegistry->IsAdapter(adapter))
return ExpectedPhysicalGpuHandle(n);

*pSize = adapter->GetVirtualVRamSize();
*pSize = (adapter->GetMemoryInfo().DedicatedVideoMemory + adapter->GetMemoryInfo().DedicatedSystemMemory) / 1024;

return Ok(n);
}

NvAPI_Status __cdecl NvAPI_GPU_GetMemoryInfo(NvPhysicalGpuHandle hPhysicalGpu, NV_DISPLAY_DRIVER_MEMORY_INFO* pMemoryInfo) {
constexpr auto n = __func__;
thread_local bool alreadyLoggedOk = false;

if (log::tracing())
log::trace(n, log::fmt::hnd(hPhysicalGpu), log::fmt::ptr(pMemoryInfo));

if (nvapiAdapterRegistry == nullptr)
return ApiNotInitialized(n);

if (pMemoryInfo == nullptr)
return InvalidArgument(n);

auto adapter = reinterpret_cast<NvapiAdapter*>(hPhysicalGpu);
if (!nvapiAdapterRegistry->IsAdapter(adapter))
return ExpectedPhysicalGpuHandle(n);

auto memoryInfo = adapter->GetMemoryInfo();
auto memoryBudgetInfo = adapter->GetCurrentMemoryBudgetInfo();

switch (pMemoryInfo->version) {
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_1: {
auto pMemoryInfoV1 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V1*>(pMemoryInfo);
pMemoryInfoV1->dedicatedVideoMemory = memoryInfo.DedicatedVideoMemory;
pMemoryInfoV1->systemVideoMemory = memoryInfo.DedicatedSystemMemory;
pMemoryInfoV1->sharedSystemMemory = memoryInfo.SharedSystemMemory;

// ReservedVideoMemory is zero unless NVML is available
pMemoryInfoV1->availableDedicatedVideoMemory = memoryInfo.DedicatedVideoMemory - memoryInfo.ReservedVideoMemory;
break;
}
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_2: {
auto pMemoryInfoV2 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V2*>(pMemoryInfo);
pMemoryInfoV2->dedicatedVideoMemory = memoryInfo.DedicatedVideoMemory;
pMemoryInfoV2->systemVideoMemory = memoryInfo.DedicatedSystemMemory;
pMemoryInfoV2->sharedSystemMemory = memoryInfo.SharedSystemMemory;
pMemoryInfoV2->availableDedicatedVideoMemory = memoryInfo.DedicatedVideoMemory - memoryInfo.ReservedVideoMemory; // See comment above
pMemoryInfoV2->curAvailableDedicatedVideoMemory = memoryBudgetInfo.Budget;
break;
}
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_3: {
auto pMemoryInfoV3 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V3*>(pMemoryInfo);
pMemoryInfoV3->dedicatedVideoMemory = memoryInfo.DedicatedVideoMemory;
pMemoryInfoV3->systemVideoMemory = memoryInfo.DedicatedSystemMemory;
pMemoryInfoV3->sharedSystemMemory = memoryInfo.SharedSystemMemory;
pMemoryInfoV3->availableDedicatedVideoMemory = memoryInfo.DedicatedVideoMemory - memoryInfo.ReservedVideoMemory; // See comment above
pMemoryInfoV3->curAvailableDedicatedVideoMemory = memoryBudgetInfo.Budget;
pMemoryInfoV3->dedicatedVideoMemoryEvictionsSize = 0;
pMemoryInfoV3->dedicatedVideoMemoryEvictionCount = 0;
break;
}
default:
return IncompatibleStructVersion(n, pMemoryInfo->version);
}

return Ok(n, alreadyLoggedOk);
}

NvAPI_Status __cdecl NvAPI_GPU_GetMemoryInfoEx(NvPhysicalGpuHandle hPhysicalGpu, NV_GPU_MEMORY_INFO_EX* pMemoryInfo) {
constexpr auto n = __func__;
thread_local bool alreadyLoggedOk = false;

if (log::tracing())
log::trace(n, log::fmt::hnd(hPhysicalGpu), log::fmt::ptr(pMemoryInfo));

if (nvapiAdapterRegistry == nullptr)
return ApiNotInitialized(n);

if (pMemoryInfo == nullptr)
return InvalidArgument(n);

auto adapter = reinterpret_cast<NvapiAdapter*>(hPhysicalGpu);
if (!nvapiAdapterRegistry->IsAdapter(adapter))
return ExpectedPhysicalGpuHandle(n);

auto memoryInfo = adapter->GetMemoryInfo();
auto memoryBudgetInfo = adapter->GetCurrentMemoryBudgetInfo();

switch (pMemoryInfo->version) {
case NV_GPU_MEMORY_INFO_EX_VER_1: {
auto pMemoryInfoV1 = reinterpret_cast<NV_GPU_MEMORY_INFO_EX*>(pMemoryInfo);
pMemoryInfoV1->dedicatedVideoMemory = memoryInfo.DedicatedVideoMemory;
pMemoryInfoV1->systemVideoMemory = memoryInfo.DedicatedSystemMemory;
pMemoryInfoV1->sharedSystemMemory = memoryInfo.SharedSystemMemory;
// See comment in NvAPI_GPU_GetMemoryInfo
pMemoryInfoV1->availableDedicatedVideoMemory = memoryInfo.DedicatedVideoMemory - memoryInfo.ReservedVideoMemory;
pMemoryInfoV1->curAvailableDedicatedVideoMemory = memoryBudgetInfo.Budget;
pMemoryInfoV1->dedicatedVideoMemoryEvictionsSize = 0;
pMemoryInfoV1->dedicatedVideoMemoryEvictionCount = 0;
pMemoryInfoV1->dedicatedVideoMemoryPromotionsSize = 0;
pMemoryInfoV1->dedicatedVideoMemoryPromotionCount = 0;
break;
}
default:
return IncompatibleStructVersion(n, pMemoryInfo->version);
}

return Ok(n, alreadyLoggedOk);
}

NvAPI_Status __cdecl NvAPI_GPU_GetAdapterIdFromPhysicalGpu(NvPhysicalGpuHandle hPhysicalGpu, void* pOSAdapterId) {
constexpr auto n = __func__;

Expand Down
2 changes: 2 additions & 0 deletions src/nvapi_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ extern "C" {
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetBusType)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetPhysicalFrameBufferSize)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetVirtualFrameBufferSize)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetMemoryInfo)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetMemoryInfoEx)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetAdapterIdFromPhysicalGpu)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetLogicalGpuInfo)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetArchInfo)
Expand Down
56 changes: 37 additions & 19 deletions src/sysinfo/nvapi_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@
#include "../util/util_version.h"

namespace dxvk {
NvapiAdapter::NvapiAdapter(Vulkan& vulkan, Nvml& nvml)
: m_vulkan(vulkan), m_nvml(nvml) {}
NvapiAdapter::NvapiAdapter(Vulkan& vulkan, Nvml& nvml, Com<IDXGIAdapter3> dxgiAdapter)
: m_vulkan(vulkan), m_nvml(nvml), m_dxgiAdapter(std::move(dxgiAdapter)) {}

NvapiAdapter::~NvapiAdapter() = default;

bool NvapiAdapter::Initialize(Com<IDXGIAdapter1>& dxgiAdapter, uint32_t index, std::vector<NvapiOutput*>& outputs) {
if (FAILED(dxgiAdapter->GetDesc1(&m_dxgiDesc)))
bool NvapiAdapter::Initialize(uint32_t index, std::vector<NvapiOutput*>& outputs) {
DXGI_ADAPTER_DESC1 dxgiDesc{};
if (FAILED(m_dxgiAdapter->GetDesc1(&dxgiDesc)))
return false; // Should never happen since we already know that we are dealing with a recent DXVK version

// Report vendor / device IDs from DXVK to honor ID overrides
m_dxgiVendorId = dxgiDesc.VendorId;
m_dxgiDeviceId = dxgiDesc.DeviceId;

// Report VRAM size from DXVK to honor memory overrides
m_memoryInfo.DedicatedSystemMemory = dxgiDesc.DedicatedSystemMemory;
m_memoryInfo.DedicatedVideoMemory = dxgiDesc.DedicatedVideoMemory;
m_memoryInfo.SharedSystemMemory = dxgiDesc.SharedSystemMemory;

// Get the Vulkan handle from the DXGI adapter to get access to Vulkan device properties which has some information we want.
Com<IDXGIVkInteropAdapter> dxgiVkInteropAdapter;
if (FAILED(dxgiAdapter->QueryInterface(IID_PPV_ARGS(&dxgiVkInteropAdapter)))) {
if (FAILED(m_dxgiAdapter->QueryInterface(IID_PPV_ARGS(&dxgiVkInteropAdapter)))) {
log::info("Querying Vulkan handle from DXGI adapter failed, please ensure that DXVK's dxgi.dll is present");
return false;
}
Expand Down Expand Up @@ -84,7 +94,7 @@ namespace dxvk {
return false;

if ((HasNvProprietaryDriver() || HasNvkDriver())
&& m_dxgiDesc.VendorId != NvidiaPciVendorId
&& dxgiDesc.VendorId != NvidiaPciVendorId
&& env::getEnvVariable("DXVK_ENABLE_NVAPI") != "1")
return false; // DXVK NVAPI-hack is enabled, skip this adapter

Expand All @@ -104,7 +114,7 @@ namespace dxvk {
// Query all outputs from DXVK
// Mosaic setup is not supported, thus one display output refers to one GPU
Com<IDXGIOutput> dxgiOutput;
for (auto i = 0U; dxgiAdapter->EnumOutputs(i, &dxgiOutput) != DXGI_ERROR_NOT_FOUND; i++) {
for (auto i = 0U; m_dxgiAdapter->EnumOutputs(i, &dxgiOutput) != DXGI_ERROR_NOT_FOUND; i++) {
auto nvapiOutput = new NvapiOutput(this, index, i);
nvapiOutput->Initialize(dxgiOutput);
outputs.push_back(nvapiOutput);
Expand All @@ -120,9 +130,15 @@ namespace dxvk {

nvmlDevice_t nvmlDevice{};
auto result = m_nvml.DeviceGetHandleByPciBusId_v2(pciId, &nvmlDevice);
if (result == NVML_SUCCESS)
if (result == NVML_SUCCESS) {
m_nvmlDevice = nvmlDevice;
else

nvmlMemory_v2_t memory{};
jp7677 marked this conversation as resolved.
Show resolved Hide resolved
memory.version = nvmlMemory_v2;
if (m_nvml.DeviceGetMemoryInfo_v2(m_nvmlDevice, &memory) == NVML_SUCCESS) {
m_memoryInfo.ReservedVideoMemory = memory.reserved;
}
} else
log::info(str::format("NVML failed to find device with PCI BusId [", pciId, "]: ", m_nvml.ErrorString(result)));
}

Expand Down Expand Up @@ -163,13 +179,11 @@ namespace dxvk {
}

uint32_t NvapiAdapter::GetDeviceId() const {
// Report vendor / device IDs from DXVK to honor ID overrides
return (m_dxgiDesc.DeviceId << 16) | m_dxgiDesc.VendorId;
return (m_dxgiDeviceId << 16) | m_dxgiVendorId;
}

uint32_t NvapiAdapter::GetExternalDeviceId() const {
// Report device ID from DXVK to honor ID overrides
return m_dxgiDesc.DeviceId;
return m_dxgiDeviceId;
}

uint32_t NvapiAdapter::GetSubSystemId() const {
Expand Down Expand Up @@ -201,14 +215,18 @@ namespace dxvk {
| m_vkPciBusProperties.pciDevice;
}

uint32_t NvapiAdapter::GetVRamSize() const {
// Report VRAM size from DXVK to honor memory overrides
return m_dxgiDesc.DedicatedVideoMemory / 1024;
const NvapiAdapter::MemoryInfo& NvapiAdapter::GetMemoryInfo() const {
return m_memoryInfo;
}

uint32_t NvapiAdapter::GetVirtualVRamSize() const {
// Report VRAM size from DXVK to honor memory overrides
return (m_dxgiDesc.DedicatedVideoMemory + m_dxgiDesc.DedicatedSystemMemory) / 1024;
NvapiAdapter::MemoryBudgetInfo NvapiAdapter::GetCurrentMemoryBudgetInfo() const {
DXGI_QUERY_VIDEO_MEMORY_INFO dxgiMemInfo{};
if (FAILED(m_dxgiAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &dxgiMemInfo)))
return MemoryBudgetInfo{};

return MemoryBudgetInfo{
.Budget = dxgiMemInfo.Budget,
.CurrentUsage = dxgiMemInfo.CurrentUsage};
}

std::optional<LUID> NvapiAdapter::GetLuid() const {
Expand Down
25 changes: 19 additions & 6 deletions src/sysinfo/nvapi_adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,21 @@ namespace dxvk {
class NvapiAdapter {

public:
explicit NvapiAdapter(Vulkan& vulkan, Nvml& nvml);
explicit NvapiAdapter(Vulkan& vulkan, Nvml& nvml, Com<IDXGIAdapter3> dxgiAdapter);
~NvapiAdapter();

bool Initialize(Com<IDXGIAdapter1>& dxgiAdapter, uint32_t index, std::vector<NvapiOutput*>& outputs);
struct MemoryInfo {
uint64_t DedicatedVideoMemory;
uint64_t ReservedVideoMemory;
uint64_t DedicatedSystemMemory;
uint64_t SharedSystemMemory;
};
struct MemoryBudgetInfo {
uint64_t Budget;
uint64_t CurrentUsage;
};

bool Initialize(uint32_t index, std::vector<NvapiOutput*>& outputs);
[[nodiscard]] std::string GetDeviceName() const;
[[nodiscard]] bool HasNvProprietaryDriver() const;
[[nodiscard]] bool HasNvkDriver() const;
Expand All @@ -25,11 +36,10 @@ namespace dxvk {
[[nodiscard]] uint32_t GetPciBusId() const;
[[nodiscard]] uint32_t GetPciDeviceId() const;
[[nodiscard]] uint32_t GetBoardId() const;
[[nodiscard]] uint32_t GetVRamSize() const;
[[nodiscard]] uint32_t GetVirtualVRamSize() const;
[[nodiscard]] std::optional<LUID> GetLuid() const;
[[nodiscard]] NV_GPU_ARCHITECTURE_ID GetArchitectureId() const;

[[nodiscard]] const MemoryInfo& GetMemoryInfo() const;
[[nodiscard]] MemoryBudgetInfo GetCurrentMemoryBudgetInfo() const;
[[nodiscard]] bool HasNvml() const;
[[nodiscard]] bool HasNvmlDevice() const;
[[nodiscard]] std::string GetNvmlErrorString(nvmlReturn_t result) const;
Expand All @@ -48,6 +58,7 @@ namespace dxvk {
private:
Vulkan& m_vulkan;
Nvml& m_nvml;
Com<IDXGIAdapter3> m_dxgiAdapter;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess no way around to keep an adapter alive. I hope this won't give us tear down issues in titles.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless adapters are singletons (which I don't think they are) it should be fine. But if it proves to be a problem we can always try switching to manual usage of VK_EXT_memory_budget on our own.


std::set<std::string> m_vkExtensions;
VkPhysicalDeviceProperties m_vkProperties{};
Expand All @@ -58,7 +69,9 @@ namespace dxvk {
VkPhysicalDeviceFeatures m_vkFeatures{};
VkPhysicalDeviceDepthClipControlFeaturesEXT m_vkDepthClipControlFeatures{};
uint32_t m_vkDriverVersion{};
DXGI_ADAPTER_DESC1 m_dxgiDesc{};
uint32_t m_dxgiVendorId{};
uint32_t m_dxgiDeviceId{};
MemoryInfo m_memoryInfo{};

nvmlDevice_t m_nvmlDevice{};

Expand Down
8 changes: 6 additions & 2 deletions src/sysinfo/nvapi_adapter_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,12 @@ namespace dxvk {
// Query all D3D11 adapter from DXVK to honor any DXVK device filtering
Com<IDXGIAdapter1> dxgiAdapter;
for (auto i = 0U; m_dxgiFactory->EnumAdapters1(i, &dxgiAdapter) != DXGI_ERROR_NOT_FOUND; i++) {
auto nvapiAdapter = new NvapiAdapter(*m_vulkan, *m_nvml);
if (nvapiAdapter->Initialize(dxgiAdapter, i, m_nvapiOutputs))
Com<IDXGIAdapter3> dxgiAdapter3;
if (FAILED(dxgiAdapter->QueryInterface(IID_PPV_ARGS(&dxgiAdapter3))))
continue;

auto nvapiAdapter = new NvapiAdapter(*m_vulkan, *m_nvml, dxgiAdapter3);
if (nvapiAdapter->Initialize(i, m_nvapiOutputs))
m_nvapiAdapters.push_back(nvapiAdapter);
else
delete nvapiAdapter;
Expand Down
7 changes: 7 additions & 0 deletions src/sysinfo/nvml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace dxvk {
GETPROCADDR(nvmlShutdown);
GETPROCADDR(nvmlErrorString);
GETPROCADDR(nvmlDeviceGetHandleByPciBusId_v2);
GETPROCADDR(nvmlDeviceGetMemoryInfo_v2);
GETPROCADDR(nvmlDeviceGetPciInfo_v3);
GETPROCADDR(nvmlDeviceGetClockInfo);
GETPROCADDR(nvmlDeviceGetTemperature);
Expand Down Expand Up @@ -76,6 +77,12 @@ namespace dxvk {
return m_nvmlDeviceGetHandleByPciBusId_v2(pciBusId, device);
}

nvmlReturn_t Nvml::DeviceGetMemoryInfo_v2(nvmlDevice_t device, nvmlMemory_v2_t* memory) const {
return m_nvmlDeviceGetMemoryInfo_v2
? m_nvmlDeviceGetMemoryInfo_v2(device, memory)
: NVML_ERROR_FUNCTION_NOT_FOUND;
}

nvmlReturn_t Nvml::DeviceGetPciInfo_v3(nvmlDevice_t device, nvmlPciInfo_t* pci) const {
return m_nvmlDeviceGetPciInfo_v3
? m_nvmlDeviceGetPciInfo_v3(device, pci)
Expand Down
2 changes: 2 additions & 0 deletions src/sysinfo/nvml.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace dxvk {
[[nodiscard]] virtual bool IsAvailable() const;
[[nodiscard]] virtual const char* ErrorString(nvmlReturn_t result) const;
[[nodiscard]] virtual nvmlReturn_t DeviceGetHandleByPciBusId_v2(const char* pciBusId, nvmlDevice_t* device) const;
[[nodiscard]] virtual nvmlReturn_t DeviceGetMemoryInfo_v2(nvmlDevice_t device, nvmlMemory_v2_t* memory) const;
[[nodiscard]] virtual nvmlReturn_t DeviceGetPciInfo_v3(nvmlDevice_t device, nvmlPciInfo_t* pci) const;
[[nodiscard]] virtual nvmlReturn_t DeviceGetClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int* clock) const;
[[nodiscard]] virtual nvmlReturn_t DeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int* temp) const;
Expand Down Expand Up @@ -39,6 +40,7 @@ namespace dxvk {
DECLARE_PFN(nvmlShutdown);
DECLARE_PFN(nvmlErrorString);
DECLARE_PFN(nvmlDeviceGetHandleByPciBusId_v2);
DECLARE_PFN(nvmlDeviceGetMemoryInfo_v2);
DECLARE_PFN(nvmlDeviceGetPciInfo_v3);
DECLARE_PFN(nvmlDeviceGetClockInfo);
DECLARE_PFN(nvmlDeviceGetTemperature);
Expand Down
Loading