如何避免堆分配将 Rendercommands 插入到 RenderCommandBuffer?

How to avoid heap allocation inserting Rendercommands to a RenderCommandBuffer?

我有一个渲染队列,用于对要渲染的元素列表进行排序。 现在 RenderQueue 创建了一个包含所有 "low level" 渲染操作的 RenderCommandBuffer,问题是 1000 个元素的性能从 1400 FPS 变为 40FPS

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

        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)); 
        });

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

详细信息很少,但我看到了两个调整机会。

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

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

这也意味着您在分配期间只会产生一个内存栅栏的成本,而不是在所有这些 shared_ptr 中递增和递减所有引用计数时遭受的数千次。

所以:

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);
}