OpenGL 运行时访问注册表,以确定要加载哪些 OpenGL 可安装客户端驱动程序 (ICD) 。 若要加载 OpenGL ICD,OpenGL 运行时:
- 通过调用 D3DKMTQueryAdapterInfo 函数,确定与 OpenGL ICD 关联的名称、版本和标志,该函数在 pData 参数指向的 D3DKMT_QUERYADAPTERINFO 结构的 Type 成员中设置KMTQAITYPE_UMOPENGLINFO值。
- 检查 D3DKMTQueryAdapterInfo 返回的 OpenGL ICD 的版本号,以验证 OpenGL ICD 的版本。
- 使用 OpenGL ICD 的名称加载 OpenGL ICD。
- 初始化对 OpenGL ICD 函数的访问。
若要查找 OpenGL ICD 的名称, D3DKMTQueryAdapterInfo 在以下项中搜索注册表:
HKLM/System/CurrentControlSet/Control/Class/{Adapter GUID}/0000/
一、注册表查询协议
1.1 多架构注册表布局
graph TD
A[HKLM\System\CurrentControlSet\Control\Class\{Adapter GUID}] --> B[0000]
B --> C[32位系统]
C -->|键值| D1(OpenGLDriverNameWoW)
C -->|键值| D2(OpenGLVersionWoW)
B --> E[64位系统]
E -->|键值| F1(OpenGLDriverName)
E -->|键值| F2(OpenGLVersion)
关键注册表项说明
键名 | 数据类型 | 示例值 | 适用环境 |
---|---|---|---|
OpenGLDriverName | REG_SZ | "nvoglv64.dll" | 原生64位应用 |
OpenGLDriverNameWoW | REG_SZ | "nvoglv32.dll" | 32位应用在64位系统 |
OpenGLVersion | REG_DWORD | 0x00070000 | 版本号(7.0) |
二、D3DKMT查询流程
2.1 适配器信息获取
D3DKMT_QUERYADAPTERINFO info = {0};
info.hAdapter = hAdapterFromEnum;
info.Type = KMTQAITYPE_UMOPENGLINFO;
NTSTATUS status = D3DKMTQueryAdapterInfo(&info);
if (NT_SUCCESS(status)) {
D3DDDI_UMOPENGLINFO* pOglInfo = (D3DDDI_UMOPENGLINFO*)info.pPrivateDriverData;
// 解析pOglInfo结构体
}
UMOPENGLINFO数据结构:
typedef struct _D3DDDI_UMOPENGLINFO {
ULONG Version; // 0x00070000表示OpenGL 7.0
CHAR DriverName[260];
ULONG Flags; // 见下表
} D3DDDI_UMOPENGLINFO;
三、安全加载实现
3.1 版本验证逻辑
bool ValidateICDVersion(DWORD dwRuntimeVer, DWORD dwDriverVer) {
// 主版本号比较
WORD rtMajor = HIWORD(dwRuntimeVer);
WORD drvMajor = HIWORD(dwDriverVer);
// 次版本号比较
WORD rtMinor = LOWORD(dwRuntimeVer) >> 8;
WORD drvMinor = LOWORD(dwDriverVer) >> 8;
return (drvMajor > rtMajor) ||
((drvMajor == rtMajor) && (drvMinor >= rtMinor));
}
3.2 动态加载最佳实践
HMODULE LoadICDSecurely(LPCSTR pszDriverName) {
// 1. 验证数字签名
if (!VerifyDriverSignature(pszDriverName)) {
return NULL;
}
// 2. 设置安全加载标志
DWORD dwOldFlags;
SetThreadErrorMode(SEM_FAILCRITICALERRORS, &dwOldFlags);
// 3. 显式指定加载路径
char szSysPath[MAX_PATH];
GetSystemDirectoryA(szSysPath, MAX_PATH);
strcat_s(szSysPath, "\\drivers\\");
strcat_s(szSysPath, pszDriverName);
// 4. 加载库
HMODULE hMod = LoadLibraryExA(szSysPath, NULL,
LOAD_LIBRARY_SEARCH_SYSTEM32);
// 恢复错误模式
SetThreadErrorMode(dwOldFlags, NULL);
return hMod;
}
四、多架构支持矩阵
运行时环境 | 注册表键 | 驱动文件名后缀 | 内存模型 |
---|---|---|---|
32位系统 | OpenGLDriverName | 32 | 32-bit |
64位系统原生应用 | OpenGLDriverName | 64 | 64-bit |
64位系统WoW模式 | OpenGLDriverNameWoW | 32 | 32-bit |
五、故障排查指南
5.1 常见错误码
错误代码 | 原因分析 | 解决方案 |
---|---|---|
ERROR_FILE_NOT_FOUND | ICD文件路径错误 | 检查System32/drivers目录 |
ERROR_INVALID_IMAGE | 驱动签名无效 | 重新安装WHQL签名驱动 |
ERROR_BAD_EXE_FORMAT | 架构不匹配 | 匹配正确的WoW/native版本 |
5.2 WinDbg调试命令
!gpuinfo -opengl // 显示已加载ICD信息
!verify /d nvoglv64.dll // 验证驱动签名
此键还包含 Microsoft Direct3D 用户模式显示驱动程序的名称。 此项包含 32 位 Windows Vista 显示驱动程序的四个注册表项(用于 32 位 Windows Vista)和四个用于 64 位 Windows Vista 上的 32 位 Windows Vista 显示驱动程序的注册表项。 以下条目适用于在 32 位 Windows Vista 上使用的 32 位 Windows Vista 显示驱动程序:
条目 | 类型 | 说明 |
---|---|---|
UserModeDriverName | REG_SZ | Direct3D 用户模式显示驱动程序的名称,无论操作系统是否支持 OpenGL ICD,Direct3D 呈现设备操作都需要此名称。 |
OpenGLDriverName | REG_SZ | OpenGL ICD 的名称。 例如,如果 OpenGL ICD Mydriver.dll,则此项的值 Mydriver.dll。 |
OpenGLVersion | REG_DWORD | OpenGL 运行时用于验证 OpenGL ICD 版本的 OpenGL ICD 的版本号。 |
OpenGLFlags | REG_DWORD | 标志位掩码。 目前,为兼容性设置了位 0 (0x00000001) 。 设置第 1 位 (0x00000002) 时,OpenGL 运行时不会在运行时调用 ICD 的交换缓冲区函数之前调用 ICD 的 finish 函数。 |
以下条目适用于 64 位 Windows Vista 上使用的 32 位 Windows Vista 显示驱动程序:
条目 | 类型 | 说明 |
---|---|---|
UserModeDriverNameWow | REG_SZ | 适用于 64 位 Windows Vista 的 32 位 Microsoft Direct3D 用户模式显示驱动程序的名称。 |
OpenGLDriverNameWow | REG_SZ | 64 位 Windows Vista 的 32 位 OpenGL ICD 的名称。 |
OpenGLVersionWow | REG_DWORD | 适用于 64 位 Windows Vista 的 32 位 OpenGL ICD 的版本号。 |
OpenGLFlagsWow | REG_DWORD | 适用于 64 位 Windows Vista 的 32 位 OpenGL ICD 的标志位掩码。 |