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

Efficient 2D rendering with 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();
}

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

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

那么,两个问题:

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


首先:这真的很低效吗?这真的很难说,尤其是 OpenGL 部分,因为 OpenGL 性能在很大程度上取决于何时同步 required/requested。

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

请注意,您可以在不使用方法的情况下创建 RawImage2d,因为所有字段都是 public。这意味着如果您自己创建一个反向向量,您可以避免简单的 5µs 克隆。 但是,用the method glium uses反转向量比仅仅克隆向量要慢很多;在我的机器上,相同长度的向量需要 170µs。如果你只想达到每帧 60fps = 17ms,这可能仍然 可以容忍 ,但仍然不是很好。

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

最后,不幸的是,我不太了解 GPU 执行 OpenGL 命令所花费的时间。我 猜测 这不是最佳选择,因为 OpenGL 没有太多空间来安排您的命令,但必须立即执行它们(强制同步)。但也许这对你来说是不可避免的。