2

在 Wikipedia 和其他来源对 OpenGL 4.0 的描述中,我读到了这个特性:

绘制由 OpenGL 或 OpenCL 等外部 API 生成的数据,无需 CPU 干预。

这是指什么?

编辑

似乎这必须指的是 Draw_Indirect 我相信它以某种方式扩展了绘图阶段以包括来自着色器程序或互操作程序的反馈(基本上是 OpenCL/CUDA) 看起来好像有一些警告和技巧来让电话继续停留在 GPU 上持续第二次运行后的任何延长时间,但这应该是可能的。

如果有人可以提供更多关于在没有 CPU 的情况下使用绘图命令的信息,或者可以更好地描述间接绘图,请随时这样做。将不胜感激。

4

3 回答 3

3

我相信您可能指的是GL_ARB_draw_indirect功能,它允许 OpenGL 从 GPU 缓冲区对象中获取 DrawArrays 或 DrawElements 参数,这些参数可以由 OpenGL 或 OpenCL 填充。

如果我没记错的话,它包含在核心 OpenGL 4 中。

于 2011-02-19T01:36:18.250 回答
2

I haven't figured out how particularly OpenGL 4.0 makes this feature work, since it has existed before as well as far as I have understood. I'm not sure if this answers your question, but I'll tell what I know about the subject anyway.

It refers to a situation where some other library than OpenGL, such as OpenCL or CUDA, produces some data directly into the memory of the graphics card, and then OpenGL continues from where the other library left, and uses that data as

  • pixel buffer object (PBO) when they want to draw the data to the screen as it is
  • texture when they want to use the graphics data as a part of some other scene
  • vertex buffer object (VBO) when they want to use the produced data as some arbitrary attribute input for vertex shader. (one example of this might be a particle system which is simulated with CUDA and rendered with OpenGL)

In a situation like this, it's a very good idea to keep the data in the graphics card all the time and not copy it around, especially not copy it through CPU, because the PCIe bus is very slow when compared to the memory bus of the graphics card.

Here's some sample code to do the trick with CUDA and OpenGL for VBOs and PBOs:

// in the beginning
glGenBuffers(&id, 1);

// for every frame
cudaGLRegisterBufferObject(id);
CUdeviceptr ptr;
cudaGLMapBufferObject(&ptr, id);
// <launch kernel here>
cudaGLUnmapBufferObject(id);
// <now use the buffer "id" with OpenGL>
cudaGLUnregisterBufferObject(id);

And here's how you can load the data into a texture:

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, id);
glBindTexture(GL_TEXTURE_2D, your_tex_id);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, 0);

Also note that if you use some more unusual format instead of GL_RGBA it might be slower because it has to convert all the values.

I don't know OpenCL but the idea is the same. Only function names are different.

Another way to do the same thing is what is called host pinned memory. In that approach you map some CPU memory address range to the graphics card memory.

于 2011-02-18T23:57:47.983 回答
0

要了解此功能是什么,您必须了解以前的工作原理。

在 4.0 之前,OpenCL 可以用数据填充 OpenGL 缓冲区对象。实际上,常规的 OpenGL 命令可以用数据填充 OpenGL 缓冲区对象,或者通过变换反馈或通过渲染到缓冲区纹理。该数据可以是用于渲染的顶点数据。

只有 CPU 可以启动顶点数据的渲染(通过调用其中一个glDraw*函数。即便如此,这里也不需要显式同步(在 OpenCL/OpenGL 互操作要求之外)。具体来说,CPU 没有读取由 GPU 操作写入的数据。

但这会导致一个问题。如果 OpenCL 或任何 GPU 操作总是将已知数量的顶点写入缓冲区,那么一切都很好。但是,情况并非必须如此。GPU 进程通常希望写入任意数量的顶点。显然需要有一个最大限制(缓冲区的大小)。但除此之外,你希望它能够写任何它想要的东西。

问题是 OpenCL 决定了要写多少。但是CPU现在需要该数字才能使用其中一项glDraw功能。如果 OpenCL 写入了 22,000 个顶点,那么 CPU 需要将 22,000 个传递给glDrawArrays.

ARB_draw_indirect (GL 4.0的核心功能)所做的是允许 GPU 进程将值写入缓冲区对象,该对象表示您将传递给glDraw*函数的参数。唯一未涵盖的参数是原始类型。

请注意,CPU仍然控制渲染发生的时间。CPU 仍然决定从哪些缓冲区中提取顶点数据。因此 OpenCL 可以编写其中的几个glDraw*命令,但在 CPU 实际调用glDrawElementsIndirect其中一个命令之前,实际上并没有渲染任何内容。

所以你可以做的是运行一个 OpenCL 进程,它将一些数据写入现有的缓冲区对象。然后使用通常的顶点设置绑定这些缓冲区,就像使用 VAO 一样。OpenCL 进程会将适当的渲染命令数据写入其他缓冲区对象,您将绑定为间接缓冲区。然后你glDraw*Indirect用来渲染这些命令。

CPU 在任何时候都不必从 GPU 读回数据。

于 2012-03-17T07:35:20.823 回答