OpenCL与OpenGL共享折腾二三事
Published
Contents
为了让图形课的作业可以用 OpenCL 做实时绘制,于是乎开始折腾如何让 OpenCL 中的图片可以高效的渲染到屏幕上,饶了一大圈学了不少 OpenGL 的用法,最后最好的解决方案也只能是共享texture/image
,然后在 OpenGL中在绘制一遍。
PBO
首先是尝试使用 PBO(Pixel Buffer Object) 来和OpenCL交互,使用起来非常方便,和之前文章提到的 VBO 用法是一样的。
创建了 PBO 以后,直接用以下代码就可以绘制到
//绑定pbo
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[index]);
//绘制,因为我们已经 bind pbo 了,所以 data 参数设置为 0, opengl就会从pbo中读数据
void glDrawPixels(width, height, format, type, 0);
看 OpenGL 的介绍:“glDrawPixels — write a block of pixels to the frame buffer”,应该很快吧,都直接写到帧缓存里了。
但是实际结果是比较慢的,800*600 需要花将近4ms,fps300多,1920*1080就要接近10ms,自己直接把数据从 OpenCL 拷到 CPU 再拷到 OpenGL,发现速度是一样的。
事后认真看了下 PBO 的介绍,发现 PBO 分两种:
GL_PIXEL_UNPACK_BUFFER_ARB
用于从CPU传送数据给GPUGL_PIXEL_PACK_BUFFER_ARB
用于从GPU传送数据给CPU
我一开始就理解错了,这玩意本来就只是用来和 CPU 传送数据的,于是这个方法失败
FBO
于是乎开始折腾 FBO, 网上找到这么个 PPT 讲的比较清楚,这个 PPT 中实现的内容大概是用 OpenGL 渲染出一个图片以后,传给 OpenCL 做一次高斯模糊再显示出来,用法如下:
// 创建并绑定FBO
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
// 创建一个RenderBuffer
glGenRenderbuffersEXT(1, &rb_color);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb_color);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
// 吧rbo挂载到FBO的颜色缓冲区
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, rb_color);
// 从gl创建cl buffer
cl_mem cl_scene;
cl_scene = clCreateFromGLRenderbuffer(cxGPUContext, CL_MEM_READ_ONLY, rb_color, 0);
用法也比较简单,在 OpenCL 可以直接使用 image2d_t
对象接触,但是问题又来了,bind frame buffer以后屏幕就什么也显示不出来了,从文章中仔细阅读FBO以后大概理解了FBO的工作原理。
FBO(FrameBufferObject),被用来让用户创建FrameBuffer,一开始我们的图像系统为我们已经创建好了一个FrameBuffer,被称之为Default Framebuffer,它由若干个ColorBuffer
,一个DepthBuffer
,一个StencilBuffer
构成,而 FBO 允许用户自己通过创建 RenderBuffer
和 Texture
来挂载管理这些不同的 buffer,他的用途多半用在渲染到 texture。
问题就出在,如果你bind了自己创建的frameBuffer,那么 OpenGL 就会吧图像渲染到你的 frameBuffer 里去,而 Default FrameBuffer 里还是空的,于是屏幕就黑了。
由于对 OpenGL 了解不深刻,也不清楚怎么直接管理 Default FrameBuffer ,尝试了下直接 bind renderbuffer 到 Default FrameBuffer 上去返回无效操作
,于是乎这个方法也作废了…
不过总的来说 FBO 还是很有用的。
update
在 OpenGPU 论坛上提问以后得到了大神的回复,使用 glBlitFramebuffer
,这个函数是 OpenGL3.0的标准。
尝试了一番以后发现速度和第三个方法差不多。
Texture/image
最后的方法还是回归到直接让 OpenGL 和 OpenCL 共享 Texture,然后用 OpenGL 绘制。
绘制的话直接用了以下代码:
glEnable(GL_TEXTURE_RECTANGLE);
bind();
glBegin ( GL_QUADS );
glTexCoord2f ( 0, 0 ); glVertex2f ( -1.0F, -1.0F );
glTexCoord2f ( 0, height ); glVertex2f ( -1.0F, 1.0F );
glTexCoord2f ( width, height ); glVertex2f ( 1.0F, 1.0F );
glTexCoord2f ( width, 0 ); glVertex2f ( 1.0F, -1.0F );
glEnd ( );
unBind();
glDisable(GL_TEXTURE_RECTANGLE);
似乎有更快的方法,使用 glDrawPixels
,但是上面这方法绘制1080P每一帧也只用了 0.1ms ,于是乎懒得再继续折腾了
另外有个蛋疼的事情是, OpenCL 中的 float3 实际上就是 float4,如果你用一个 float3 指针指向一个地址修改,他会把最后第四位赋值为 0,这点挺坑爹的。
参考文章
blog comments powered by Disqus