使用Glium进行高效的2D渲染

时间:2017-03-28 02:29:53

标签: rust glium

我正在使用Glium为我写作的模拟器进行渲染。我把一些有效的东西拼凑在一起(基于this example),但我怀疑它效率很低。这是相关的功能:

fn update_screen(display: &Display, screen: &Rc<RefCell<NesScreen>>) {
    let target = display.draw();

    // Write screen buffer
    let borrowed_scr = screen.borrow();
    let mut buf = vec![0_u8; 256 * 240 * 3];
    buf.clone_from_slice(&borrowed_scr.screen_buffer[..]);
    let screen = RawImage2d::from_raw_rgb_reversed(buf, SCREEN_DIMENSIONS);
    glium::Texture2d::new(display, screen)
        .unwrap()
        .as_surface()
        .fill(&target, MagnifySamplerFilter::Nearest);

    target.finish().unwrap();
}

在高层次上,这就是我正在做的事情:

  • 借用NesScreen,其中包含屏幕缓冲区,这是一个数组。
  • 将屏幕缓冲区克隆为矢量
  • 从矢量数据创建纹理并将其渲染

我怀疑是通过clone_from_slice克隆整个屏幕缓冲区效率非常低。 RawImage2d::from_raw_rgb_reversed函数获取传递给它的向量的所有权,因此我不确定如何以避免克隆的方式执行此操作。

所以,有两个问题:

  • 实际效率低下吗?我没有足够的经验来直观地了解内容。

  • 如果是这样,有没有更有效的方法呢?我对Glium进行了相当多的研究,但对于2D渲染并没有多大的帮助。

1 个答案:

答案 0 :(得分:1)

这不是一个很好的答案,但也许这里的一些事情可以帮助你。

首先:这真的很低效吗?这很难说,特别是OpenGL部分,因为OpenGL性能在很大程度上取决于何时需要/请求同步。

至于屏幕缓冲区的克隆:你只是复制180kb,这不是太多。我很快在我的机器上对它进行了基准测试,并且克隆一个180kb的向量需要大约5μs,这真的不是很多。

请注意,您可以在不使用方法的情况下创建RawImage2d,因为所有字段都是公开的。这意味着如果您自己创建反向矢量,则可以避免使用简单的5μs克隆。 然而,用the documentation反转向量比克隆向量慢得多;在我的机器上,相同长度的矢量需要170μs。如果您只想实现每帧60fps = 17ms,但仍然不是很好,那么这可能仍然是可容忍的

您可以考虑在原始数组中使用正确的行排序来避免此问题。或者你可以,而不是直接将纹理复制到帧缓冲区,只需绘制一个全屏四边形(每个屏幕角落一个顶点),其上有纹理。当然,你需要一个网格,一个着色器和所有这些东西,但你可以通过调整纹理坐标来“反转”图像。

最后,遗憾的是,我不太了解GPU执行OpenGL命令的时间。我猜测它不是最佳的,因为OpenGL没有足够的空间来安排你的命令,但必须立即执行它们(强制同步)。但也许这在你的情况下是不可避免的。