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

时间:2013-05-10 15:46:01

标签: c# performance opengl textures pbo

我在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_Objecthttp://www.songho.ca/opengl/gl_pbo.html以及关于下载和使用建议的第一篇文章,如果我上传数据并立即绘制纹理(甚至使用TexSubImage2D?)那么我就赢了由公益组织获得更多速度。 这是正确的吗?因此,如果我使用PBO,我是否必须使用第二个PBO并将帧画一帧延迟?

我的主循环就像:

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

在另一个线程中进行视频解码。

是一种非常天真的方法,但有效。这样做的正确/更好的方法是什么?

1 个答案:

答案 0 :(得分:0)

您的纹理创建和更新代码路径对我来说没问题。但有一点是:在更新的情况下,您不必重新指定纹理对象参数,如过滤器和换行模式,这些状态将保持不变。使用即时模式绘制也不太可能带来最佳性能。

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