在OpenGL(包括PBO)中使用纹理/精灵的最佳方式

本文关键字:纹理 精灵 方式 最佳 OpenGL 包括 PBO | 更新日期: 2023-09-27 18:13:13

我有一个c#小游戏,主要使用固定精灵(从磁盘加载的位图)和一些视频。

现在我们的方法是

加载:

texture.ID = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, texture.ID);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, w, h, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, w, h, PixelFormat.Bgra, PixelType.UnsignedByte, data);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureParameterName.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureParameterName.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
GL.Ext.GenerateMipmap(GenerateMipmapTarget.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, 0);

GL.BindTexture(TextureTarget.Texture2D, texture.ID);
GL.MatrixMode(MatrixMode.Texture);
GL.PushMatrix();
    GL.Begin(BeginMode.Quads);
    GL.TexCoord2(x1, y1);
    GL.Vertex3(rx1, ry1, rect.Z);
    GL.TexCoord2(x1, y2);
    GL.Vertex3(rx1, ry2, rect.Z);
    GL.TexCoord2(x2, y2);
    GL.Vertex3(rx2, ry2, rect.Z);
    GL.TexCoord2(x2, y1);
    GL.Vertex3(rx2, ry1, rect.Z);
    GL.End();
GL.PopMatrix();
GL.BindTexture(TextureTarget.Texture2D, 0);

和更新:

GL.BindTexture(TextureTarget.Texture2D, texture.ID);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, w, h, PixelFormat.Bgra, PixelType.UnsignedByte, data);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureParameterName.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureParameterName.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
GL.Ext.GenerateMipmap(GenerateMipmapTarget.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, 0);

所有的纹理都保留到它们被使用,所以加载只在启动时完成一次(通常)首先,对这个方法有什么评论吗?现在我想使用PBO正确地更新纹理(主要是视频)A)使用PBO来添加纹理(来自bmp)是一个好主意吗?我会创建一个pbo,将数据从bmp复制到pbo,然后使用TexSubImage2D。是否有任何性能点,或者开销是否太高?B)更新也一样:当前代码:

GL.BindBuffer(BufferTarget.PixelUnpackBuffer, texture.PBO);
IntPtr buffer = GL.MapBuffer(BufferTarget.PixelUnpackBuffer, BufferAccess.WriteOnly);
Marshal.Copy(data, 0, buffer, data.Length);
GL.UnmapBuffer(BufferTarget.PixelUnpackBuffer);
GL.BindTexture(TextureTarget.Texture2D, texture.ID);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, w, h, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);

这真的有效吗?还是没有好处?

我阅读了http://www.opengl.org/wiki/Pixel_Buffer_Object和http://www.songho.ca/opengl/gl_pbo.html,关于下载和使用的第一篇文章建议,如果我上传数据并立即绘制该纹理(甚至使用TexSubImage2D?),那么我将不会通过PBO获得更多的速度。这样对吗?所以如果我用PBO,我是否需要用第二个PBO来画延时帧?

我的主循环就像:

{
  DoSomeInputHandling();
  CopyDecodedVideoFrameToTexture();
  DrawTexture();
}

视频解码在另一个线程。

是一个相当幼稚的方法,但是有效。做这件事的正确/更好的方法是什么?

在OpenGL(包括PBO)中使用纹理/精灵的最佳方式

您的纹理创建和更新代码路径对我来说OK。但有一点:你不需要在更新情况下重新指定纹理对象参数,如过滤器和包装模式,这些状态将保持原样。使用即时模式进行绘图也不太可能产生最佳性能。

使用pbo可以避免数据的额外副本。例如,您在另一个线程中的视频解码可以直接写入mapappend PBO内存(当然,您需要一些同步方案来保证当线程想要写入对象时,对象被映射),因此消除您在代码中建议的额外副本。实现PBO乒乓(或环形缓冲区)方法可能会提高性能,并进一步分解单独的代码部分,但代价是增加延迟。我不知道这是不是你所关心的。