如何避免堆分配插入rendercommand到RenderCommandBuffer

How to avoid heap allocation inserting Rendercommands to a RenderCommandBuffer?

本文关键字:rendercommand RenderCommandBuffer 插入 分配 何避免      更新时间:2023-10-16

我有一个RenderQueue,排序的元素列表呈现。现在,RenderQueue创建了一个RenderCommandBuffer与所有的"低级"渲染操作,问题是,性能从1400 FPS到40FPS的1000个元素

我分析了应用程序,问题在这里(每帧分配):

        std::for_each(element.meshCommands.begin(), element.meshCommands.end(), [&] (auto &command) {
            std::vector<std::pair<std::string, glm::mat4> > p{ { "MVP", VPmatrix * command.second} };
            m_commandBuffer.addCommand(std::make_shared<SetShaderValuesCommand>(element.material,p));
            m_commandBuffer.addCommand(std::make_shared<BindMaterialCommand>(element.material));
            m_commandBuffer.addCommand(std::make_shared<RenderMeshCommand>(meshProperty.mesh)); 
        });

我知道我可以按材质分组我的网格,但问题或多或少是相同的。每帧分配许多对象。你将如何避免这种情况?游戏引擎如何处理这个问题?内存池?

细节很少,但我看到了两个调优机会。

m_commandBuffer是某种多态容器。我完全理解您为什么这样构建它,但是它提出了一个问题——每个元素必须单独分配。

通过将所有渲染操作合并到variant中,并将m_commandBuffer实现为这些变量的向量(或队列),您可能会获得更好的性能。这允许您使用1个内存分配为1000个命令reserve()空间,而不是(至少)您目前需要的1000个。

这也意味着在分配过程中您只产生一个内存围栏的成本,而不是在所有这些shared_ptr s中增加和减少所有引用计数时所遭受的数千个内存围栏的成本。

:

using Command = boost::variant< SetShaderValuesCommand, BindMaterialCommand, RenderMeshCommand>;
using CommandQueue = std::deque<Command>;

执行命令变成:

for (auto& cmd : m_commandBuffer) {
  boost::apply_visitor([](auto& actualCmd) { 
    actualCmd.run(); /* or whatever is the interface */
  }, cmd);
}