glDrawPixels与使用纹理在OpenGL中绘制2D缓冲区的比较

5
我有一个2d图形库,我想在OpenGL中使用它,以便能够混合2d和3d图形。最简单的方法似乎是使用glDrawPixels,但许多最近的教程和论坛建议使用glTexSubImage2D命令与纹理,然后使用该纹理绘制一个正方形。
我的问题是:为什么?有哪些优点?这只是增加了一个步骤(内存缓冲区->纹理->视频缓冲区,而不是内存缓冲区->视频缓冲区)。

glDrawPixels 被认为非常慢。 - j-p
比glTexSubImage2D慢?这两个命令的作用是相同的:从系统内存复制到视频内存。 - angros47
2D纹理是否与3D图形交错呢?如果它总是在顶部或底部,您可以直接使用窗口系统将其复制到后备缓冲区。 - Andreas
我的想法是在顶部使用带有Alpha通道的2D来绘制得分、HUD或简单GUI。我想在Windows中使用WGL,在Linux中使用GLX来创建上下文。用它们最好的方法是什么?我曾考虑过使用叠加层...但看起来大多数显卡都不支持它们。 - angros47
2个回答

3

这主要有两个原因:

  • glDrawPixels() 已经被弃用,在OpenGL核心配置文件或OpenGL ES中不再可用。
  • 当多次绘制图像时,通过将图像数据存储在纹理中,可以节省大量重复工作。

很少情况下您只需要绘制一次图像。更常见的是,在每次重新绘制时重复绘制它。使用 glDrawPixels() 需要每次将图像数据传递给OpenGL。如果将其存储在纹理中,则可以重复绘制它,并且OpenGL每次都可以重复使用相同的数据。

要绘制纹理的内容,不一定必须设置着色器、绘制矩形等等。您可以使用 glBlitFramebuffer() 将纹理内容复制到显示器上。


它可能已经被弃用了...但是用四边形替换它也没有帮助,因为绘制四边形的命令(如glOrtho、glLoadIdentity等)也已经被弃用,并且在GLES2上不可用,所以我仍然需要一个不同的渲染器(这将无法在版本1上工作...而且许多计算机仍然只支持版本1)。 - angros47
另外,我不想在每次重绘时使用相同的数据,因为缓冲区可能已经发生了变化,屏幕需要更新,所以我仍然需要向显卡发送数据。 - angros47

1
由于OpenGL使用视频内存,使用简单的“draw pixel”肯定会非常慢,因为你需要为每个绘制执行大量的GPU / CPU同步。
当你使用glTexSubImage2D时,就可以确保你的图像始终驻留在快速的视频内存中。
将纹理加载到视频内存中的一种方法可能是:
glCreateTextures(GL_TEXTURE_2D, 1, &texture->mId);

glTextureParameteri(mId, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameteri(mId, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

GLsizei numMipmaps = ((GLsizei)log2(std::max(surface->w, surface->h)) + 1);
glTextureStorage2D(*texture, numMipmaps, internalFormat, surface->w, surface->h);
glTextureSubImage2D(*texture, 0, 0, 0, surface->w, surface->h,
                    format, GL_UNSIGNED_BYTE, surface->pixels);

glGenerateTextureMipmap(*texture);

如果不想使用直接状态访问,请不要忘记绑定。

但是,如果您仍然希望执行像素绘制(例如用于程序渲染),则必须编写自己的片段着色器以尽可能快地进行。


但是即使glTexSubImage2D将数据传输到视频内存,如果在每帧使用它,仍需要进行大量的同步。如果图片是静态的,我可以只使用一次将副本留在视频内存中,但它不是静态的(而且2D图像不是由OpenGL渲染的,因此无法使用FBO)。 - angros47
如果纹理不是静态的,我猜有几种方法可以实现。第一种是加载所有可能的图像(gif由几个图像组成),第二种是使用一个持久映射,例如一个PBO? - Antoine Morrier
纹理是由CPU动态生成的,因此无法预加载(它是2D库的输出)。也不能直接在GPU上生成(2D库在常规内存缓冲区上工作)。 - angros47
我还没有尝试过...它们是否支持旧版本的OpenGl,比如1.4版(如果可能的话,我希望我的代码到处都能运行)? - angros47
我不知道它们何时被支持,但你必须知道最新版本的OpenGL的目的是降低在CPU和GPU两侧工作的成本。这正是你想要做的^^。在所有情况下,如果你不想使用“正确的方式”^^,使用glDrawPixels或通过glTexImage2D发送值将会很慢。 - Antoine Morrier
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接