复制从 OpenGL 纹理获得的 3D cudaArray 的内容

Copy the contents of a 3D cudaArray obtained from an OpenGL texture

我想将源自 OpenGL 纹理的 3D cudaArray 的内容复制到“经典”数组,反之亦然。

Note: In the following snippets, errors checks are omitted for clarity.

cudaArray 是这样“分配”的:

cudaArray* texture_array {nullptr};
cudaGraphicsResource* resource{nullptr};

cudaGraphicsGLRegisterImage(&resource, texture.id, GL_TEXTURE_3D, cudaGraphicsRegisterFlagsNone);
cudaGraphicsMapResources(1, &resource, cuda_stream);
cudaGraphicsSubResourceGetMappedArray(&texture_array, resource, array_index, mipmap);

本次操作成功,我可以通过以下方式获取到相关信息 cudaArrayGetInfo(&description, &extent, &flags, texture_array) 并使用格式为 uint16.

512 x 512 x 122 纹理获取类似于以下示例的内容
//C-style pseudo-code

description
{
    .x = 16,
    .y = 0,
    .z = 0,
    .w = 0,
    .f = cudaChannelFormatKindUnsigned,
};

extent
{
    .width  = 512,
    .height = 512,
    .depth  = 122
};

flags = 0;

第一次尝试:线性阵列

阅读 this answer to a post asking about pitched memory 后,我的第一次尝试是使用 cudaMemcpy3D 并模拟一个倾斜数组,其中 pitch 是这样的以字节为单位的行长度:

std::uint8_t* linear_array{nullptr};

const cudaExtent extent =
{
    .width  = texture.width  * texture.pixel_format_byte_size,
    .height = texture.height,
    .depth  = texture.depth
};
cudaMalloc(&linear_array, extent.width * extent.height * extent.depth);

然后像这样复制到它:

const cudaMemcpy3DParms copy_info =
{
    .srcArray = texture_array,
    .srcPos   =
    {
        .x = 0,
        .y = 0,
        .z = 0
    },
    .srcPtr =
    {
        .ptr   = nullptr,
        .pitch = 0, 
        .xsize = 0,
        .ysize = 0
    },

    .dstArray = nullptr,
    .dstPos   =
    {
        .x = 0,
        .y = 0,
        .z = 0
    },
    .dstPtr = 
    {
        .ptr   = linear_array,
        .pitch = extent.width, 
        .xsize = texture.width,
        .ysize = texture.height,
    }, 

    .extent = extent,
    .kind   = cudaMemcpyDefault,
};

cudaMemcpy3D(&copy_info)

但是,上面的代码在调用 cudaMemcpy3D 时会生成 cudaErrorInvalidValue。 不用说,如果我将两者颠倒(源变成目的地,反之亦然),也会发生同样的事情。

第二次尝试:倾斜阵列

对我来说有点复杂,因为我打算在 __global__ 函数中修改数据,但无论如何。

同样,我分配了一个(真实的)倾斜数组,如下所示:

cudaPitchedPtr ptr;
const cudaExtent extent =
{
    .width  = texture.width * texture.pixel_format_byte_size,
    .height = texture.height,
    .depth  = texture.depth,
};

cudaMalloc3D(&ptr, extent);

然后像这样复制到它:

const cudaMemcpy3DParms copy_info =
{
    .srcArray = texture_array,
    .srcPos   =
    {
        .x = 0,
        .y = 0,
        .z = 0
    },
    .srcPtr =
    {
        .ptr   = nullptr,
        .pitch = 0,
        .xsize = 0,
        .ysize = 0
    },

    .dstArray = nullptr,
    .dstPos   =
    {
        .x = 0,
        .y = 0,
        .z = 0
    },
    .dstPtr = ptr,

    .extent = extent,
    .kind = cudaMemcpyDefault
};

cudaMemcpy3D(&copy_info);

但我也接到 cudaErrorInvalidValue 电话 cudaMemcpy3D


我做错了什么? 当数组是来自图形 API 的纹理时,API 的限制是否禁止我调用 cudaMemcpy3D?如果是这样,我该怎么办?

经过各种测试(复制到另一个cudaArray和其他类似的东西),问题似乎来自误解。

文档明确指出:

" If a CUDA array is participating in the copy, the extent is defined in terms of that array's elements".

因此,copy_info.extent 必须是(在我的上下文中)cudaArrayGetInfo 检索到的范围。