超过DirectX11视频内存

DirectX11 Video Memory exceeded

本文关键字:内存 视频 DirectX11 超过      更新时间:2023-10-16

我有一个渲染循环,它监听笔板输入并从顶点/索引缓冲区绘制(以及其他内容)。顶点数据可以增长,当它达到特定级别时,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。场景中的总大小分配高于上面列出的,但较小的缓冲区经常被释放。在末尾的顶点/索引缓冲区中也有一些填充。

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

#define WM_POINTERUPDATE                0x0245

我真的不介意场景渲染缓慢,但如果我达到了某个最大内存分配(视频内存?),是否有一种方法可以让内存以速度为代价缓慢地从无效内存分页?我尝试禁用draw()调用,该调用调用调用像素、顶点着色器和绘图调用,但异常仍然发生。我更喜欢速度折衷或变通方法,而不是例外。

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

GPU可以访问部分系统内存(与GPU内存相比,这相当慢,但总比没有内存好)。例如,对于NVidia GPU,英伟达控制面板在"系统信息">"共享系统内存"下显示;这通常是系统中RAM总量的一半。据我所知,这个系统内存占用了进程地址空间的一部分。

如果你的"相当旧"的GPU有512MB的内存,它将需要大约768MB的额外系统内存来满足你的内存请求。这为您的应用程序留下了1.2GB的空间。我猜你的应用程序试图在阵列中分配1.2GB的系统内存,这些内存将把你想要上传到GPU的几何数据。这很合适,但您的应用程序代码也需要在某个地方。在这种假设的情况下,您的内存已经用完了。当然,一旦你将几何数据上传到GPU,你就可以去掉系统内存阵列,但此时此刻,系统没有足够的内存来创建你要求的大小的GPU内存缓冲区。

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

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

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

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

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

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

我对缓冲区大小(需要填充的缓冲区)进行了快速更改,现在至少有2000万个顶点。我的GPU很旧,所以这还不错,尽管我知道有些渲染器可以远远超出这个范围。

将重点放在变通办法上,尽可能减少细节。我想我可以通过镶嵌获得大约15倍的细节,所以状态不错。

如果有人有更多的见解,可以把你的答案换成正确的答案,但不确定我是否会在这里走另一条路。