超出 DirectX11 视频内存

DirectX11 Video Memory exceeded

我有一个渲染循环,用于侦听数位板输入并从 vertex/index 缓冲区(以及其他内容)中绘制。顶点数据可以增长,当它达到一定水平时,DispatchMsg(&msg) 遇到这个:

Unhandled exception at 0x5DDBDEF0 (msvcr110d.dll) in App.exe: 0xC0000005: Access violation writing location 0x00000000.

场景中分配的顶点和索引缓冲区的总大小每次都在同一水平附近:

Total Vertices count: 10391370
Total Indices count: 41565480
Total Vertices size: 249392880 (bytes)
Total Indices size: 997571520 (bytes)

在另一个样本中:

Total Vertices count: 9969300
Total Indices count: 39877200
Total Vert size: 239263200
Total Indices size: 957052800

顶点和索引缓冲区都是D3D11_USAGE_DEFAULT。场景中的总大小分配高于上面列出的,但较小的缓冲区经常被释放。最后的 vertex/index 缓冲区中也有一些填充。

每次(到达异常时)要派发的消息是581,我认为可能是:

#define WM_POINTERUPDATE                0x0245

我真的不介意场景渲染缓慢,但如果我达到某个最大内存分配(显存?)有没有办法让内存缓慢分页 to/from maim 内存速度?我尝试禁用调用像素、顶点着色器和绘图调用的 draw() 调用,但异常仍然发生。我更喜欢速度权衡或解决方法而不是例外。

找到答案并解决了问题。根据我的输入顶点数,CreateBuffer 失败或 malloc/HeapAlloc 失败。

我仍然不能 100% 确定 GPU 是否应该在某个点后将内存分页到主系统内存,或者这是否不可避免,因为在每一帧的计算过程中场景数据必须保留在 GPU 内存中(深度,照明等),但我认为 A)只有在我手动解除分配'ed/realloc'缓冲区(无论如何都会很慢)和 B)分配缓冲区的大小(顶点,索引。 .) 是问题所在,而不是对它们的 per-frame 计算。

我尝试切换到其他缓冲区使用方式 (USAGE_DYNAMIC),但分配失败仍然发生在相同级别。

我快速更改了缓冲区大小(需要填充的缓冲区),现在至少有 2000 万个顶点。我的 GPU 很旧,所以这还不错,但我知道有些渲染器可以做得更好。

将重点关注解决方法并尽可能减少细节。我想我可以通过细分获得大约 15 倍的细节,所以状态还不错。

如果有人有更多见解,可以将您的见解切换为正确答案,但不确定我是否要在这里走另一条路。

从您问题中的数字来看,您似乎为顶点和索引数据分配了大量内存(大约 1.2GB)。如果您的应用程序是 32 位(x86,而不是 x64),它只能访问 2GB 内存,因此很可能是您的进程内存不足。

GPU 可以访问部分系统内存(与 GPU 内存相比,这相当慢,但总比没有内存好)。例如,对于 NVidia GPU,NVidia 控制面板将其显示在 "System Information" > "Shared system memory" 下;这通常是系统中 RAM 总量的一半。据我所知,这个系统内存占用了你进程地址的一部分space。

如果您的 "pretty old" GPU 有 512MB 内存,则需要大约 768MB 的额外系统内存才能满足您的内存请求。这为您的应用程序留下了 1.2GB。我猜你的应用程序试图在数组中分配 1.2GB 的系统内存,这些内存将获取你想要上传到 GPU 的几何数据。这正好合适,但您的应用程序代码也需要位于某个地方。在这个假设的情况下,您已经 运行 内存不足。当然,您可以在将几何数据上传到 GPU 后摆脱系统内存阵列,但就在此时,系统没有足够的内存来创建您请求大小的 GPU 内存缓冲区.

将项目切换为 64 位(Visual Studio 中的 x64)将使您的进程占用更多内存(在大多数情况下,最多可达系统和页面文件中可用的内存),并解决你的问题。如果内存限制确实是问题所在。

另一件事:我注意到 - 假设你的数字是正确的 - 你为索引缓冲区的每个索引分配了 24 个字节,就像你为顶点缓冲区中的每个顶点分配的一样多。那是对的吗?索引(只是顶点缓冲区的偏移量)不应大于 4 个字节。您是否真的尝试分配实际需要的 6 倍 GPU 显存,还是您的应用程序计算错误?

如果您快速释放然后在 GPU 上重新创建缓冲区,那么 D3D 可能会保留 "old" 缓冲区一段时间(至少只要它仍然绑定到 GPU 管道),所以它可能因此而内存不足。因此,实际上解除绑定您即将释放的缓冲区可能会有所帮助(通过调用 IASetVertexBuffers(NULL, 0, 0, 0, 0)IASetIndexBuffer(NULL, DXGI_FORMAT_R16_UINT, 0))。