0

我正在使用 Glium 为我正在编写的模拟器进行渲染。我拼凑了一些可行的东西(基于这个例子),但我怀疑它效率很低。这是相关的功能:

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 渲染并没有太多具体的内容。

4

1 回答 1

1

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


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

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

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

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

最后,不幸的是,我不太了解 GPU 执行 OpenGL 命令所需的时间。我这不是最佳选择,因为 OpenGL 没有太多空间来安排您的命令,但必须立即执行它们(强制同步)。但在你的情况下,这可能是无法避免的。

于 2017-03-28T14:19:31.923 回答