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 显示驱动程序的计算机上检索准确的图形内存值集。

相关推荐
ItJavawfc19 分钟前
驱动-Linux定时-timer_list
驱动开发·定时器·驱动定时器·timer_list
MaoXian_n4 小时前
[IMX] 03.时钟树 - Clock Tree
arm开发·驱动开发·单片机·嵌入式硬件
天夏已微凉1 天前
OpenHarmony系统HDF驱动开发介绍(补充)
驱动开发·音视频·harmonyos
不摆烂选手2 天前
Linux 阻塞和非阻塞 I/O 简明指南
linux·驱动开发·ubuntu·正点原子imx6ull学习笔记
__Benco2 天前
OpenHarmony平台驱动开发(十五),SDIO
驱动开发
7yewh2 天前
FPGA前瞻篇-计数器设计与实现实例
arm开发·驱动开发·嵌入式硬件·fpga开发·硬件架构·硬件工程·精益工程
程序员JerrySUN2 天前
《驱动开发硬核特训 · 专题篇》:深入理解 I2C 子系统
驱动开发
sukalot2 天前
window 显示驱动开发-将虚拟地址映射到内存段(二)
驱动开发
忧虑的乌龟蛋3 天前
嵌入式Linux I2C驱动开发详解
linux·驱动开发·嵌入式·iic·i2c·读数据·写数据