在 OpenGL-OpenCL 纹理互操作中,PBO 如何从纹理接收数据?

In OpenGL-OpenCL texture interop, how does the PBO receive the data from the texture?

网络上关于 PBO 的大多数示例都是关于使 CPU-GPU 传输异步的。

我正在尝试将 PBO 用于其他用途 - 用于 OpenGL-OpenCL 互操作,如 this tutorial 中所述。引用自那里:

[...] Creating an intermediate (staging) Pixel-Buffer-Object for the OpenGL texture via clCreateFromGLBuffer, updating the buffer with OpenCL, and copying the results back to the texture.

教程说明我需要按如下方式创建 PBO:

GLuint pbo;
glGenBuffers(1, &pbo);
glBindBuffer(GL_ARRAY_BUFFER, pbo);
//specifying the buffer size
glBufferData(GL_ARRAY_BUFFER, width * height * sizeof(cl_uchar4), …);

我已将省略号替换为 NULL, GL_DYNAMIC_COPY,因为我不想从主机发送任何数据。

这是我最终得到的 createPbo 函数:

void createPbo(ivec2 sz, int elementSize) {
    glGenBuffers(1, &pbo);
    glBindBuffer(GL_ARRAY_BUFFER, pbo);
    glBufferData(GL_ARRAY_BUFFER, sz.x * sz.y * elementSize, NULL, GL_DYNAMIC_COPY);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, NULL);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}

在我的其余代码中,我执行了教程中的操作,并且代码运行良好。 问题是 glGetTexImage 调用:教程没有提到它,这意味着我可以跳过这个慢速复制吗?可以吗?


关于我的用例的注意事项:我正在尝试将 现有 OpenGL 纹理数据发送到 OpenCL,在那里对其进行操作,然后将其发送回 OpenGL。

不,你不能,因为数据是通过缓冲区 Mapping (glMapBuffer) 访问的。您不能直接映射纹理图像,但可以映射缓冲区对象的数据存储。因此,您需要将纹理图像中的数据复制到缓冲区的数据存储中。
glGetTexImage 执行“复制”过程(以及必要的格式和类型转换)。它从绑定到目标 GL_TEXTURE_2D 的纹理中获取数据,并将数据存储在绑定到目标 GL_PIXEL_PACK_BUFFER.

的缓冲区中

您可以在 OpenCL 中直接 访问 OpenGL 纹理的图像级别,而无需复制(至少不是作为显式 API 操作)作为 OpenCL 图像对象通过clCreateFromGLTexture.

你提到的教程也提到了这一点。您不需要缓冲区对象或像素缓冲区传输操作。

而且,为了完整起见,由于问题明确是关于如何在 OpenCL 中使用 GL 缓冲区共享,然后使用 GL 缓冲区更新纹理图像:

您引用的教程(在方法 2 中)也详细介绍了如何执行此操作。在这种情况下,我们不共享 GL 纹理的级别,但我们共享一个 GL 缓冲区对象作为 CL 缓冲区对象:

(以下或多或少是该教程来源的直接 copy/paste)

首先,创建我们要与 OpenCL 共享的 OpenGL 缓冲区对象,稍后我们将使用它来通过 PBO 传输更新纹理图像:

GLuint pbo;
glGenBuffers(1, &pbo);
glBindBuffer(GL_ARRAY_BUFFER, pbo);
//specifying the buffer size
glBufferData(GL_ARRAY_BUFFER, width * height * sizeof(cl_uchar4), …);

接下来,如果您想使用原始 GL 纹理的级别初始化 GL 缓冲区对象,您首先 需要 将 PBO 将该图像复制到 GL 缓冲区对象中:

glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBindTexture(GL_TEXTURE_2D, tex);
glGetTexImage(GL_TEXTURE_2D, 0, texFormat, texType, 0);

这会将 GL 纹理的第一层 PBO 复制到 GL 缓冲区对象中。

接下来,共享OpenCL中的GL缓冲区:

mem = clCreateFromGLBuffer(g_context, CL_MEM_WRITE_ONLY, pbo,  NULL);

然后,通过clEnqueueAcquireGLObjects()获取共享GL/CL缓冲区对象的所有权,执行更新CL缓冲区内容的内核,并通过clEnqueueReleaseGLObjects()释放所有权。

最后,使用从 GL 缓冲区对象传输出的 PBO 更新 OpenGL 纹理(当前绑定到 GL_TEXTURE_2D):

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, NULL);