回答你的问题:“我的问题如下:如何设计SDL2合适的渲染引擎,尽可能少的开销?”
快速解释可缩放的懒惰渲染器方案,以最大限度地减少SDL2渲染器开销:
“图层”由具有相同z属性的所有纹理组成 . 只要修改了该图层中的纹理,图层就会被标记为无效 . 在渲染器运行时管理图层,这是在设置的帧速率下 . 跟踪最大层和最高无效层 . 渲染器从最高的无效层开始,到最大层结束 . 每个图层都设置为渲染器目标并清除 . 然后将上一层复制到当前图层 . 然后,它遍历图层中的每个纹理,重新绘制标记为无效的纹理,并将每个纹理复制到当前图层的顶部 . 结果是前一层是背景,而当前层是在它上面绘制的 . 当图层标记为无效时,此纹理将被缓存并失效 . 在遍历任何无效图层后,将渲染目标设置回默认值(null),将最高纹理复制到屏幕并显示 .
在带有图层用户界面类型的环境的2d中,上面是可伸缩和懒惰的 . 在我的低端Celeron n2830上,我的测试应用程序在0%cpu使用率下空闲 . 即使我添加了一百个测试层,它或多或少都保持这种状态 . 因为它只是从哪个层向上变换,并且所有变化都以合理的帧速率排列,所以很少有工作最终完成 . 通过无效层迭代到最大层看起来渐渐变得更加友好,然后在每次运行时遍历所有层 . 以设定的间隔运行渲染器并执行所有绘制然后有助于节省时间,因为它将忽略无论如何都看不到的多余更改 . 使用一些应用程序代码以避免必须绘制内容和复制纹理是值得的 . 如果检查和属性查找,那些往往需要更长的时间 .
请注意,此设计适用于带有图层的2D,如用户界面 . 某些原则可能不一定在其他环境中很好地工作 .
此外,上面只支持纹理,而不支持表面 . 混合两者对我来说不值得复杂 . 让sdl2渲染器绘制到一个特定的纹理需要一些计算,但单独满足我的需求 . 如果你把两者混合起来,似乎很难避免一些额外的工作 . 加上纹理受益于gpu,这增加了cpu时间方面的效率 .
在我的系统中,window对象有一个draw方法 . 此方法使用渲染器排列绘制操作,而不是立即绘制它们 . Window对象具有area属性 . 为了支持没有area属性的对象,也许你可以应用一个包围你的对象的包装器不 . 这样当提示输入区域时,它仍然可以提供一个区域,即使它内部没有区域也是如此 . 或者可以使用将对象映射到某个区域的表,或者任何对象跟踪其纹理的方法调用 . 我不确定这种限制的性质 .
请注意,此绘制方法是绘制自身和渲染器绘图对象的对象的混合方法 . 对象似乎是自己绘制的,而渲染器实际上是在完成工作 .
简而言之:
纹理明显快于表面
排队批处理的绘制和复制操作
在绘制时缓存纹理
将所有纹理复制到它们后
缓存图层
使用缓存来避免将除了无效图层以外的所有图层渲染到最大图层