如何避免堆分配将 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);
}
我有一个渲染队列,用于对要渲染的元素列表进行排序。 现在 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);
}