我正在使用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渲染并没有多大的帮助。
答案 0 :(得分:1)
这不是一个很好的答案,但也许这里的一些事情可以帮助你。
首先:这真的很低效吗?这很难说,特别是OpenGL部分,因为OpenGL性能在很大程度上取决于何时需要/请求同步。
至于屏幕缓冲区的克隆:你只是复制180kb,这不是太多。我很快在我的机器上对它进行了基准测试,并且克隆一个180kb的向量需要大约5μs,这真的不是很多。
请注意,您可以在不使用方法的情况下创建RawImage2d
,因为所有字段都是公开的。这意味着如果您自己创建反向矢量,则可以避免使用简单的5μs克隆。 然而,用the documentation反转向量比克隆向量慢得多;在我的机器上,相同长度的矢量需要170μs。如果您只想实现每帧60fps = 17ms,但仍然不是很好,那么这可能仍然是可容忍的。
您可以考虑在原始数组中使用正确的行排序来避免此问题。或者你可以,而不是直接将纹理复制到帧缓冲区,只需绘制一个全屏四边形(每个屏幕角落一个顶点),其上有纹理。当然,你需要一个网格,一个着色器和所有这些东西,但你可以通过调整纹理坐标来“反转”图像。
最后,遗憾的是,我不太了解GPU执行OpenGL命令的时间。我猜测它不是最佳的,因为OpenGL没有足够的空间来安排你的命令,但必须立即执行它们(强制同步)。但也许这在你的情况下是不可避免的。