window 显示驱动开发-报告图形内存(四)
检索图形内存数字
创建图形应用程序的软件开发人员可以使用从 Windows Vista 开始的 Microsoft DirectX 版本 10 API 在运行 Windows 显示驱动程序模型 (WDDM) 显示驱动程序的计算机上检索准确的图形内存数集。 以下步骤演示如何检索图形内存编号:
由于新的图形内存报告仅在运行 Windows 显示驱动程序模型 (WDDM) 显示驱动程序的计算机上可用,因此应用程序必须首先调用以下函数以确认驱动程序模型
HasWDDMDriver()
{LPDIRECT3DCREATE9EX pD3D9Create9Ex = NULL;HMODULE hD3D9 = NULL;hD3D9 = LoadLibrary( L"d3d9.dll" );if ( NULL == hD3D9 ) {return false;}//// Try to create a IDirect3D9Ex interface (also known as a DX9L // interface).// This interface can only be created if the driver is written // according to the Windows Display Driver Model (WDDM).//pD3D9Create9Ex = (LPDIRECT3DCREATE9EX) GetProcAddress (hD3D9, "Direct3DCreate9Ex" );return pD3D9Create9Ex != NULL;
}
检索图形内存信息的 DirectX 应用程序开发指南
在 Windows Vista 及更高版本中,使用 WDDM 显示驱动程序的计算机可以通过 DirectX API 检索准确的图形内存信息。以下是开发图形应用程序时获取这些数据的完整方法:
1. 验证 WDDM 驱动程序模型
在尝试检索图形内存信息前,必须确认系统正在使用 WDDM 驱动程序:
#include <windows.h>
#include <dxgi.h>
#include <d3d11.h>bool IsWDDMDriver()
{IDXGIFactory* pFactory = nullptr;if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory))){return false;}IDXGIAdapter* pAdapter = nullptr;if (FAILED(pFactory->EnumAdapters(0, &pAdapter))){pFactory->Release();return false;}DXGI_ADAPTER_DESC desc;if (FAILED(pAdapter->GetDesc(&desc))){pAdapter->Release();pFactory->Release();return false;}pAdapter->Release();pFactory->Release();// WDDM 1.0+ 驱动程序会在描述中包含特定信息return true;
}
2. 使用 DirectX 10/11 API 获取内存信息
基本内存信息 (DXGI_ADAPTER_DESC)
void GetBasicVideoMemoryInfo()
{IDXGIFactory* pFactory = nullptr;CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory);IDXGIAdapter* pAdapter = nullptr;pFactory->EnumAdapters(0, &pAdapter);DXGI_ADAPTER_DESC adapterDesc;pAdapter->GetDesc(&adapterDesc);printf("显卡描述: %S\n", adapterDesc.Description);printf("专用显存: %.2f GB\n", adapterDesc.DedicatedVideoMemory / 1024.0 / 1024.0 / 1024.0);printf("专用系统内存: %.2f GB\n", adapterDesc.DedicatedSystemMemory / 1024.0 / 1024.0 / 1024.0);printf("共享系统内存: %.2f GB\n", adapterDesc.SharedSystemMemory / 1024.0 / 1024.0 / 1024.0);pAdapter->Release();pFactory->Release();
}
高级内存信息 (Windows 10+ 使用 IDXGIAdapter3)
对于 Windows 10 及更高版本,可以使用更详细的查询方法:
void GetAdvancedVideoMemoryInfo()
{IDXGIFactory1* pFactory = nullptr;CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory);IDXGIAdapter1* pAdapter = nullptr;pFactory->EnumAdapters1(0, &pAdapter);IDXGIAdapter3* pAdapter3 = nullptr;if (SUCCEEDED(pAdapter->QueryInterface(__uuidof(IDXGIAdapter3), (void**)&pAdapter3)){DXGI_QUERY_VIDEO_MEMORY_INFO localMemoryInfo;pAdapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &localMemoryInfo);DXGI_QUERY_VIDEO_MEMORY_INFO nonLocalMemoryInfo;pAdapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &nonLocalMemoryInfo);printf("本地内存段(显存):\n");printf(" 当前使用量: %.2f MB\n", localMemoryInfo.CurrentUsage / 1024.0 / 1024.0);printf(" 当前预算: %.2f MB\n", localMemoryInfo.Budget / 1024.0 / 1024.0);printf(" 可用保留: %.2f MB\n", localMemoryInfo.AvailableForReservation / 1024.0 / 1024.0);printf(" 当前保留: %.2f MB\n", localMemoryInfo.CurrentReservation / 1024.0 / 1024.0);printf("非本地内存段(系统共享内存):\n");printf(" 当前使用量: %.2f MB\n", nonLocalMemoryInfo.CurrentUsage / 1024.0 / 1024.0);printf(" 当前预算: %.2f MB\n", nonLocalMemoryInfo.Budget / 1024.0 / 1024.0);pAdapter3->Release();}pAdapter->Release();pFactory->Release();
}
3. 处理不同 Windows 版本的兼容性
void GetVideoMemoryInfoCompatible()
{if (IsWindows10OrGreater()){// Windows 10+ 使用更详细的查询GetAdvancedVideoMemoryInfo();}else{// Windows Vista/7/8 使用基本查询GetBasicVideoMemoryInfo();}
}
4. 应用程序内存管理建议
-
基于预算分配:
// 检查是否有足够内存预算 DXGI_QUERY_VIDEO_MEMORY_INFO memoryInfo; pAdapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memoryInfo);if (requiredMemory > memoryInfo.Budget - memoryInfo.CurrentUsage) {// 内存不足,需要调整资源或显示警告 }
2.内存压力事件处理
// 注册内存事件通知 (Windows 10+) pAdapter3->RegisterVideoMemoryBudgetChangeNotificationEvent(hEvent, &pdwCookie);
3.多GPU系统处理
// 枚举所有适配器 IDXGIAdapter* pAdapter = nullptr; for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i) {// 获取每个适配器的信息 }
5. 错误处理和回退机制
try {GetVideoMemoryInfoCompatible(); } catch (const std::exception& e) {// 记录错误并使用保守的默认值printf("获取图形内存信息失败: %s\n", e.what());printf("使用保守内存估计...\n");// 设置默认值或禁用高级图形功能 }
应用程序确定显示驱动程序模型为 WDDM 后,应用程序可以使用新的 DirectX 版本 10 API 获取图形内存编号。 应用程序从以下 DXGI_ADAPTER_DESC 数据结构中获取图形内存数字,该结构存在于 Dxgi.h 中,并包含在 DirectX 软件开发工具包 (SDK) 中。
typedef struct DXGI_ADAPTER_DESC {WCHAR Description[ 128 ];UINT VendorId;UINT DeviceId;UINT SubSysId;UINT Revision;SIZE_T DedicatedVideoMemory;SIZE_T DedicatedSystemMemory;SIZE_T SharedSystemMemory;LUID AdapterLuid;} DXGI_ADAPTER_DESC;
由于在 Windows Vista 和更高版本的桌面和 DirectX 游戏中广泛使用图形,因此在 Windows Vista 及更高版本上运行的软件应能够准确确定可用图形内存量。 WDDM 管理图形内存本身的虚拟化,并确保准确报告图形内存的各个方面。 应用程序开发人员和软件供应商应利用 DirectX 版本 10 API 在具有 Windows Vista 显示驱动程序的计算机上检索准确的图形内存值集。