缓存OpenGL纹理
Caching OpenGL textures
我正在开发一款使用SDL的2D游戏。由于有些系统的CPU很弱,GPU很强,所以除了普通的SDL/软件外,我还有一个使用OpenGL的渲染器后端。
渲染器界面的简化版本如下所示:
class Renderer {
public:
virtual void render_surface(SDL_Surface* surface) = 0;
virtual void render_text(const std::string& text, const Font& font) = 0;
};
但这有一个问题:每当我使用OpenGL绘制曲面时,我都需要重复glBindTexture
调用,这让我损失了很多时间。目前,我有一个基于曲面内存地址的愚蠢缓存,但它显然不适用于动态生成的曲面,例如在render_text
中。
我能想到的唯一合适的解决方案是完全改变接口,并让调用方明智地缓存纹理:
class Renderer {
public:
virtual Texture load_surface(SDL_Surface* surface) = 0;
virtual Texture load_text(const std::string& text, const Font& font) = 0;
virtual void render_texture(const Texture& texture) = 0;
};
但这是IMO使用起来有点难看,并且必须为软件渲染器伪造。
对此我还能做些什么吗?
这实际上听起来像是两个独立的问题(至少您提出的解决方案是这样)。我将对这两个问题提出几点建议,因为目前还不完全清楚你想要实现什么。
1.冗余状态更改/绘制调用
您可以始终将渲染命令排队,然后在实际绘制之前按纹理/着色器/其他昂贵状态对它们进行排序(别担心,排序会使其听起来比实际情况更复杂/更昂贵)。
您真正要做的是根据需要的纹理、半透明还是不透明等创建不同的类别来放置绘图命令,然后在收到完成框架所需的所有绘图命令后,以系统的方式运行这些类别。唯一真正的排序将发生在插入时,因为bucket相对较小,所以与在绘图时尝试对一堆随机的命令进行排序相比,成本要低得多。
这就是高性能游戏引擎自《雷神之锤》问世以来的工作原理。这样做的目的是尽可能减少纹理变化并绘制调用。在过去,draw调用本身有很多开销(需要将顶点阵列内存从CPU复制到GPU,并在一些API中切换内核模式上下文),但现在它们仍然很昂贵,但原因不同。如果您可以将尽可能多的与订单无关的绘制操作组合到单个调用中,您通常会显著提高性能。
事实上,PowerVR在硬件层面也做了类似的事情。它等待所有绘制命令,然后将屏幕划分为多个瓦片,在那里它可以确定哪些命令是多余的(例如隐藏的表面),并在必须光栅化任何内容之前将其剔除。只要绘制操作不依赖于顺序(例如阿尔法混合),它就可以减少内存/功耗。
2.GPU存储的低效/非持久使用
在最坏的情况下,您可以随时考虑将纹理打包到图集中。这样,您就不需要为了交换绑定纹理而将breakdraw调用分开,只需要更智能地计算纹理坐标即可。
为此,您经常在GUI的多个帧中打印相同的文本。您可以轻松地编写软件,将渲染的字符串/格式化的段落等缓存为纹理。如果你很聪明的话,你可以将其扩展到整个GUI窗口,并且只有在必须重新绘制渲染窗口时,才能重新打包存储渲染窗口的纹理部分。
- OpenGL大的3D纹理(>2GB)非常慢
- OpenGL将纹理四边形渲染为(0,0)
- OpenGL 4.3 错误地将第 4 个纹理坐标映射到与第 3 个纹理坐标相同的位置
- Qt OpenGL 渲染到纹理性能问题
- 使用 C++在 OpenGL 中对 3D 多边形进行纹理处理
- 无法获取要在 OpenGL ES2 中显示的 RGB 纹理
- 在 OpenGL 中加载纹理C++
- 添加新纹理OpenGL时,模型消失了
- 初始化多个纹理 OpenGL、SDL C++ 时出现问题
- 将多个纹理 OpenGL 绑定到不同的四边形
- 如何加载纹理Opengl
- 读写一个纹理(OpenGL)
- 渲染时加载纹理 (OpenGL)
- 如何绑定纹理openGL的一部分
- 将两个图像堆栈的非电源加载到 3D 纹理 OpenGL C++
- 我的精灵在纹理opengl之间切换
- 使用深度纹理OpenGL/GLSL的深度遮挡(3.3/330)
- 加载多纹理opengl 2.0
- 将位置写入纹理OpenGL/GLSL
- 为纹理OpenGL C++加载多个.bmp文件时出现问题