c++ - 缓存 OpenGL 纹理

标签 c++ opengl caching optimization

我正在开发一款使用 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;
};

但在我看来,这使用起来有点难看,并且必须为软件渲染器伪造。

对此我还能做些什么吗?

最佳答案

这实际上听起来像是两个独立的问题(至少您提出的解决方案是这样)。我将就这两个问题给出一些建议,因为尚不完全清楚您要实现的目标。

<小时/>

1。冗余状态更改/绘制调用

您始终可以将渲染命令排队,然后在实际进行绘图之前按纹理/着色器/其他昂贵的状态对它们进行排序(不用担心,排序听起来比实际更复杂/昂贵)。

您真正要做的是创建不同的类别,根据需要的纹理(半透明还是不透明等)将绘图命令放入其中,然后在收到所有纹理后以系统的方式运行这些类别。完成框架所需的绘图命令。唯一真正的排序将发生在插入时,并且由于存储桶相对较小,因此比在绘制时尝试对随机命令进行排序要便宜得多。

自《雷神之锤》诞生以来,高性能游戏引擎实际上就是这样工作的。这个想法是尽可能减少纹理变化和绘制调用。在过去,绘制调用本身需要大量费用(需要将顶点数组内存从 CPU 复制到 GPU,以及某些 API 中的内核模式上下文切换),但现在它们仍然很昂贵,但原因不同。如果您可以将尽可能多的与顺序无关的绘制操作组合到单个调用中,通常会显着提高性能。

事实上,PowerVR在硬件层面做了类似的事情。它等待所有绘制命令,然后将屏幕划分为多个图 block ,在这些图 block 中它可以确定哪些命令是多余的(例如隐藏的表面),并在必须光栅化任何内容之前剔除它们。只要绘制操作不依赖于顺序(例如 Alpha 混合),它就会减少内存/功耗。

<小时/>

2。 GPU 存储的低效/非持久使用

在最坏的情况下,您始终可以考虑将纹理打包到图集中。这样,您就不必为了交换绑定(bind)纹理而中断绘制调用,您只需更智能地计算纹理坐标即可。

为此,您经常在 GUI 中的多个框架中打印相同的文本。您可以轻松编写软件来将渲染的字符串/格式化的段落/等缓存为纹理。如果您足够聪明,您可以将其扩展到整个 GUI 窗口,并且仅在必须重新绘制其中的某些内容时重新打包存储渲染窗口的纹理部分。

关于c++ - 缓存 OpenGL 纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20894307/

相关文章:

c++ - 结构数组的大小

c++ - 简单的 'keypress' 程序

objective-c - 在 OpenGL 中使用 malloc 分配的数据时出现内存问题

PHP APC 缓存,开箱即用吗?

java - Hazelcast:如何从 map 获取缓存时检测网络故障

caching - 如何在 Haskell 中进行复杂的 IO 处理和隐式缓存?

c++ - 如何读取 .inf 文件?

python - 用于通讯python的UNIX套接字-C++

c++ - OpenGL 3D 选择

c++ - 对 VBO 中的特定三角形使用不同的纹理