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. 应用程序内存管理建议

  1. 基于预算分配

    复制代码
    // 检查是否有足够内存预算
    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 显示驱动程序的计算机上检索准确的图形内存值集。

相关推荐
VernonJsn7 小时前
visual studio 2022的windows驱动开发
ide·驱动开发·visual studio
嵌入式郑工14 小时前
RK3566 LubanCat 开发板 USB Gadget 配置完整复盘
linux·驱动开发·ubuntu
雾削木2 天前
树莓派 ESPHome 固件编译与烧录全攻略(解决超时与串口识别问题)
驱动开发
春日见3 天前
win11 分屏设置
java·开发语言·驱动开发·docker·单例模式·计算机外设
DarkAthena3 天前
【GaussDB】手动编译不同python版本的psycopg2驱动以适配airflow
驱动开发·python·gaussdb
松涛和鸣3 天前
DAY66 SPI Driver for ADXL345 Accelerometer
linux·网络·arm开发·数据库·驱动开发
嵌入式郑工4 天前
# RK3576 平台 RTC 时钟调试全过程
linux·驱动开发·ubuntu
GS8FG4 天前
针对Linux,RK3568平台下,I2C驱动的一点小小的领悟
linux·驱动开发
一路往蓝-Anbo4 天前
第 4 篇:策略模式 (Strategy) —— 算法的热插拔艺术
网络·驱动开发·stm32·嵌入式硬件·算法·系统架构·策略模式
A-花开堪折4 天前
RK3568 Android 11 驱动开发(五):串口驱动适配
驱动开发