1

情景

我正在创建两个相当大、大小相同的 OpenGL 3D 纹理。第一个是单通道 16 位纹理,第二个有四个通道,每个纹素 8 位。比我需要向 CUDA 注册他们两个。

我正在开发的应用程序是 32 位的。系统特性:Win 7 64bit,NVIDIA GeForce 540M 2GB

问题

当使用 512x512x391 或更大的纹理时,我的调用给cudaGraphicsGLRegisterImage了我一个cudaErrorMemoryAllocation,尽管这个返回值甚至不是可能的返回值列表的一部分,由cudaGraphicsGLRegisterImage. 可以在第 94 页上找到此列表。以前没有执行过内存扩展操作。但是,它确实适用于较小的纹理,例如 512x512x71。

在调用之前查询可用的设备内存cudaGraphicsGLRegisterImage会发现大约 1778 MB 是可用的。

审议

  1. 一种解释可能是返回值是某个先前调用的错误代码。我基本上可以通过在调用cudaGetLastError之前放置一个权利并检查它的返回值来消除这种可能性:它给了我一个.cudaGraphicsGLRegisterImagecudaSuccess

  2. 我进行了一些计算。两个 3D 纹理所需的内存为:

    (512 * 512 * 391) 纹素 * (4 通道 * 每纹素 1 字节 + 1 通道 * 每纹素 2 字节) = 586.5 MB

    并不多,尤其是当我的图形设备有 2 GB 的专用内存时。

  3. 我还检查了进程获取的总内存,以确保这不是 Win32-2GB 限制问题:根据任务管理器,总进程的内存大小约为 279 MB,就在cudaGraphicsGLRegisterImage调用。

  4. 根据这个帖子cudaGraphicsRegisterImage操作的内存成本应该非常低。

一些代码

获取两个 3D 纹理:

glTexImage3D( GL_TEXTURE_3D, 0, GL_INTENSITY16
            , size.x, size.y, size.z
            , 0, GL_RED, GL_UNSIGNED_SHORT, bufferPtr );

glTexImage3D( GL_TEXTURE_3D, 0, GL_RGBA8
            , size.x, size.y, size.z
            , 0, GL_RGB, GL_BYTE, nullptr );

我已经放弃了纹理生成和绑定以获得更好的概览。

使用 CUDA 进行纹理配准:

size_t free, total;
CHECK_CUDA( cudaMemGetInfo( &free, &total ) );
qDebug() << "Free Memory:" << free / ( 1024 * 1024 ) << "MB";

enum resourceIndices{ FIRST_RESOURCE = 0, SECOND_RESOURCE = 1 };
cudaGraphicsResource* resources[ 2 ];

CHECK_CUDA( cudaGetLastError() );
CHECK_CUDA( cudaGraphicsGLRegisterImage( &resources[ FIRST_RESOURCE ]
                                       , firstTextureID
                                       , GL_TEXTURE_3D
                                       , cudaGraphicsRegisterFlagsReadOnly ) );

CHECK_CUDA( cudaGraphicsGLRegisterImage( &resources[ SECOND_RESOURCE ]
                                       , secondTextureID
                                       , GL_TEXTURE_3D
                                       , cudaGraphicsRegisterFlagsSurfaceLoadStore ) );

CHECK_CUDA只是检查返回值并抛出异常。cudaGraphicsGLRegisterImage它在第一次调用时失败。

4

1 回答 1

1

您的代码片段对我来说看起来不错。但是,您说您使用的是 32 位系统。这可能是问题所在:您的进程只有 2GiB 的地址空间。根据这个地址空间的分配方式,很可能没有足够大的连续切片。因此,即使仍有足够的内存,您也可能只是用完了可用的地址空间。而且由于每块 CUDA 内存都映射到进程地址空间,甚至是设备内存,这很可能会发生。

这是 32 位系统上众所周知的问题,称为地址空间碎片。这实际上是 64 位系统的真正好处:与其说是可寻址的内存量,不如说是地址空间的绝对大小,它大大简化了内存管理,因为它很难填满,地址空间碎片不是一个实际问题。

我的建议:在 64 位系统上测试你的程序。

于 2012-10-24T09:40:42.507 回答