在OpenGL中上传纹理非常缓慢

5

我编写了一个模拟器,正在将其移植到Linux。目前为了显示视频,我正在使用Direct3D 11,并将其移植到OpenGL(暂时在Windows上运行)。我渲染到一个1024x1024的纹理中,每帧都上传到内存中(原始硬件不太适合现代硬件加速,所以我全部使用软件来处理)。然而,我发现在OpenGL中上传纹理要慢得多。

在Direct3D中,每帧上传纹理会导致帧率从416降至395(下降5%)。在OpenGL中,它从427下降到297(下降30%!)。

以下是我的绘制函数中相关代码。

Direct3D:

D3D11_MAPPED_SUBRESOURCE resource;
deviceContext_->Map(texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
uint32_t *buf = reinterpret_cast<uint32_t *>(resource.pData);
memcpy(buf, ...);
deviceContext_->Unmap(texture, 0);

OpenGL:

glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA,
    GL_UNSIGNED_BYTE, textureBuffer);

有人能建议一下是什么原因导致了这个减速吗?

如果有帮助的话,我正在运行Windows 7 x64,并且使用NVIDIA GeForce GTX 550 Ti。

2个回答

12
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer);
在这里你犯了几个错误。首先,glTexImage2D 相当于每帧创建一个 Direct3D 纹理资源。但是你没有创建它,而是只是上传到它。你应该仅在感兴趣的 mipmap 层上使用一次 glTexImage2D;之后,所有上传都应该使用 glTexSubImage2D
其次,你的 内部格式(从左数第三个参数)是 GL_RGBA。你应该始终为图像格式使用显式大小。所以使用 GL_RGBA8。这不是真正的问题,但你现在应该养成好习惯。

第三,你正在使用GL_RGBA顺序作为你的像素传输格式(从右边数起的第三个参数,而不是左边)。这通常不是最优的像素传输格式,因为许多硬件倾向于使用GL_BGRA顺序。但如果你没有从产生数据的源头以那种顺序获取数据,那么就没有什么可以做的了。

第四,如果在上传和实际渲染之间有其他事情可以做,你可以使用异步像素传输操作。你将数据写入缓冲对象(可以映射,这样你就不必复制到其中)。然后你使用glTexSubImage2D将这些数据传输到OpenGL中。因为源数据和目标图像都是OpenGL内存的一部分,所以在glTexSubImage2D返回之前,它不必将数据从客户端内存复制出来。

当然,这可能对你没有太大帮助,因为在D3D的情况下,你已经有效地完成了该复制。

在OpenGL中,它从427降到297(下降30%!)。
更重要的统计数据是它只有1毫秒的差别。你应该以绝对时间而不是以每秒帧数或FPS下降百分比来查看你的时间调整。

非常感谢您提供的帮助!glTexSubImage2D对我帮助很大,现在帧率已经达到了373 fps(2.7毫秒)。关于BGRA的问题很有趣。实际上,我必须使用BGRA才能显示正确的颜色;我原以为这是我搞砸了的问题,打算稍后再去研究一下,所以我只是改变了我发布的代码。奇怪的是,从RGBA更改为BGRA会将帧速率降至328(3.0毫秒);这可能是为什么呢? - spencercw
3
就这个而言,将其渲染到一个PBO并立即使用它,而不是先进行渲染然后再复制,可以将帧率提高到424。现在需要对D3D渲染器进行一些更多的优化以追赶进度! - spencercw
@nichol-bolas “第四,如果在开始上传和实际渲染之间有其他事情可以做” - 当然你可以立即开始渲染吧?在此期间您不需要执行其他任何操作。驱动程序只会在DMA传输+像素解包操作完成后异步处理渲染命令。 - PBS

8

glTexImage2d函数不仅用于更新纹理,还会重新分配内存。尽量使用glTexSubImage2d函数来代替。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接