0

我有一个 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,我是否必须使用第二个 PBO 并延迟一帧绘制帧?

我的主循环是这样的:

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

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

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

4

1 回答 1

0

你的纹理创建和更新代码路径对我来说没问题。但有一件事:您不必在更新案例中重新指定纹理对象参数,如过滤器和包装模式,这些状态将保持原样。使用即时模式进行绘图也不太可能带来最佳性能。

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

于 2013-05-10T21:46:18.287 回答