我有一个RenderQueue,可以对要渲染的元素列表进行排序。 现在RenderQueue创建了一个具有所有“低级”渲染操作的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));
});
我知道我可以通过材料对网格进行分组,但问题或多或少是相同的。每帧分配许多对象。你将如何避免这种情况?游戏引擎如何处理这个问题?内存池?
答案 0 :(得分:2)
细节很少,但我看到两个调整的机会。
m_commandBuffer
是某种多态容器。我完全理解你为什么要用这种方式构建它,但它提出了一个问题 - 每个元素必须单独分配。
通过将所有渲染操作合并到variant
中,可以获得更好的性能,并将m_commandBuffer实现为此类变体的向量(或队列)。这允许您为1000个命令reserve()
空间分配1个内存,而不是当前需要的(至少)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);
}