我有一个像素着色器测试,它进行一些渲染并将结果与参考图像进行比较,以验证着色器是否产生了预期的输出。当这个测试在 CI 机器上运行时,它是在没有 GPU 的 VM 上,所以我用 D3D_DRIVER_TYPE_REFERENCE 调用 D3D11CreateDevice 来使用参考光栅化器。我们多年来一直在 Windows 7 VM 上执行此操作而没有出现问题。
我们现在正尝试迁移到 Windows 10 VM 进行 CI 测试。当我在这里运行测试时,在使用 DXGI_ERROR_DEVICE_REMOVED 进行了一些成功测试(大约 5000-10000 次)后,各种 API 调用开始失败,调用 GetDeviceRemovedReason 会返回 DXGI_ERROR_DRIVER_INTERNAL_ERROR。经过一些调试后,我发现失败源于对 ID3D11DeviceContext::PSSetShader 的调用(是的,这会返回 void,但我是通过 KernelBase.dll!RaiseException 中的断点找到的)。据我所知,这个调用看起来与之前对 PSSetShader 的数千次调用完全一样。这似乎不是资源问题,发生错误时进程仅使用了 8MB 内存,并且句柄数没有增长。
我可以在多个Win10系统上重现该问题,并且在多个Win7系统上成功。两者最大的区别在于,在 Win7 上,API 调用通过 d3d11ref.dll,而在 Win10 上,它们通过 d3d10warp.dll。我并不真正熟悉差异是什么或为什么会选择其中一个,而且 MSDN 的文档在这个主题上非常不透明。我知道 d3d11ref.dll 和 d3d10warp.dll 都出现在失败和通过的系统上;我不知道为同一组调用加载一个或另一个的逻辑是什么,或者为什么 d3d10warp 库失败。
那么,有人可以解释两者之间的区别,和/或建议我如何让 d3d11ref.dll 在 Windows 10 中加载?据我所知,这是 d3d10warp.dll 中的一个错误,现在我只想避开它。
万一这很重要,我将调用 D3D11CreateDevice 并将所需的功能级别设置为 D3D_FEATURE_LEVEL_11_0,并验证是否返回了相同的级别。我为 creationFlags 传递 0,我的 D3D11_SDK_VERSION 在 d3d11.h 中定义为 7。下面是发生故障时 PSSetShader 上面的调用堆栈。这似乎是第一个失败的调用,并且在它之后带有返回码的每个调用也失败了。
KernelBase.dll!RaiseException()
KernelBase.dll!OutputDebugStringA()
d3d11.dll!CDevice::RemoveDevice(long)
d3d11.dll!NDXGI::CDevice::RemoveDevice()
d3d11.dll!CContext::UMSetError_()
d3d10warp.dll!UMDevice::MSCB_SetError(long,enum UMDevice::DDI_TYPE)
d3d10warp.dll!UMContext::SetShaderWithInterfaces(enum PIXELJIT_SHADER_STAGE,struct D3D10DDI_HSHADER,unsigned int,unsigned int const *,struct D3D11DDIARG_POINTERDATA const *)
d3d10warp.dll!UMDevice::PsSetShaderWithInterfaces(struct D3D10DDI_HDEVICE,struct D3D10DDI_HSHADER,unsigned int,unsigned int const *,struct D3D11DDIARG_POINTERDATA const *)
d3d11.dll!CContext::TID3D11DeviceContext_SetShaderWithInterfaces_<1,4>(class CContext *,struct ID3D11PixelShader *,struct ID3D11ClassInstance * const *,unsigned int)
d3d11.dll!CContext::TID3D11DeviceContext_SetShader_<1,4>()
MyTest.exe!MyFunctionThatCallsPSSetShader()
更新:启用 D3D 调试层后,当错误发生时,我会得到以下附加输出:
D3D11: Removing Device.
D3D11 WARNING: ID3D11Device::RemoveDevice: Device removal has been triggered for the following reason (DXGI_ERROR_DRIVER_INTERNAL_ERROR: There is strong evidence that the driver has performed an undefined operation; but it may be because the application performed an illegal or undefined operation to begin with.). [ EXECUTION WARNING #379: DEVICE_REMOVAL_PROCESS_POSSIBLY_AT_FAULT]
D3D11 ERROR: ID3D11DeviceContext::Map: Returning DXGI_ERROR_DEVICE_REMOVED, when a Resource was trying to be mapped with READ or READWRITE. [ RESOURCE_MANIPULATION ERROR #2097214: RESOURCE_MAP_DEVICEREMOVED_RETURN]
关于调用 Map 的第三行发生在我的测试未能注意到并处理移除的设备并随后尝试映射纹理之后,所以我认为这不相关。另一个是关于我的预期;驱动程序有错误,可能我的测试做错了什么导致它。我仍然不知道那可能是什么,或者为什么它在 Windows 7 中有效。
更新 2:我发现如果我在 Windows 7 兼容模式下在 Windows 10 上运行测试,则不会出现设备移除错误,并且我的所有测试都通过了。它仍在使用 d3d10warp.dll 而不是 d3d11ref.dll,所以这并不是问题所在。我不确定如何调查“我在做什么与 Windows 10 或其 WARP 设备不兼容”;这可能需要是 Microsoft 支持票证。