如何避免堆分配插入rendercommand到RenderCommandBuffer
How to avoid heap allocation inserting Rendercommands to a RenderCommandBuffer?
我有一个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);
}