C++ 如何避免将Rendercommands插入RenderCommandBuffer的堆分配?

C++ 如何避免将Rendercommands插入RenderCommandBuffer的堆分配?,c++,c++11,memory,game-engine,heap-memory,C++,C++11,Memory,Game Engine,Heap Memory,我有一个RenderQueue,它对要渲染的元素列表进行排序。 现在RenderQueue创建了一个包含所有“低级”渲染操作的RenderCommandBuffer,问题是1000个元素的性能从1400 FPS提高到40 FPS 我分析了应用程序,问题就在这里(每帧分配): std::for_each(element.meshCommands.begin()、element.meshCommands.end()、[&](自动和命令){ std::vector p{{“MVP”,VPmatrix*

我有一个RenderQueue,它对要渲染的元素列表进行排序。 现在RenderQueue创建了一个包含所有“低级”渲染操作的RenderCommandBuffer,问题是1000个元素的性能从1400 FPS提高到40 FPS

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

std::for_each(element.meshCommands.begin()、element.meshCommands.end()、[&](自动和命令){
std::vector p{{“MVP”,VPmatrix*command.second};
m_commandBuffer.addCommand(std::make_shared(element.material,p));
m_commandBuffer.addCommand(std::make_shared(element.material));
m_commandBuffer.addCommand(std::make_shared(meshProperty.mesh));
});

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

详细信息不多,但我看到了两个调整的机会

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

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

这还意味着,在分配过程中,您只需要承担一个内存围栏的费用,而不是在增加和减少所有这些
shared\u ptr
s中的所有引用计数时所承受的数千个

因此:


细节不多,但我看到了两个调整的机会

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

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

这还意味着,在分配过程中,您只需要承担一个内存围栏的费用,而不是在增加和减少所有这些
shared\u ptr
s中的所有引用计数时所承受的数千个

因此:


自定义分配器通常是。那里有一些图书馆和讲座。EA已经公开了他们自己的stl,你为什么要使用
shared_ptr
来实现这样的功能?另外,请发布你用来构建应用程序的编译器选项,特别是优化设置。如果这是一个“调试”或您正在测试的未优化构建,那么结果将毫无意义。对于原始指针,结果或多或少是相同的。由于每帧大量分配而导致的性能损失。这些结果当然是在发布版本中进行的全面优化。我会检查EA的stl谢谢。通常是自定义分配器。那里有一些图书馆和讲座。EA已经公开了他们自己的stl,你为什么要使用
shared_ptr
来实现这样的功能?另外,请发布你用来构建应用程序的编译器选项,特别是优化设置。如果这是一个“调试”或您正在测试的未优化构建,那么结果将毫无意义。对于原始指针,结果或多或少是相同的。由于每帧大量分配而导致的性能损失。这些结果当然是在发布版本中进行的全面优化。我会检查EA的stl谢谢。哇谢谢,我发现了std::variant。现在的问题是,我的命令不是POD,我认为如果我的命令包含std::string或std::vector之类的类型,这将不起作用。在将命令更改为仅保存POD类型后,我将尝试这种方法。谢谢@帧缓冲区它将与非POD类型一起工作。它们必须是move-constructable或movetable,它们肯定是这样的。但是这些类型会在内部调用“new”来分配它们的内容?这会影响性能,还是我错了?@FrameBuffer,视情况而定。如果字符串很短,则不会。如果字符串很长,则有许多技术可以减少字符串和向量中的内存分配。一个是自定义分配器(参见boost的池分配器)。例如,您可以为每个命令传递分配一个内存池。现在的问题是,我的命令不是POD,我认为如果我的命令包含std::string或std::vector之类的类型,这将不起作用。在将命令更改为仅保存POD类型后,我将尝试这种方法。谢谢@帧缓冲区它将与非POD类型一起工作。它们必须是move-constructable或movetable,它们肯定是这样的。但是这些类型会在内部调用“new”来分配它们的内容?这会影响性能,还是我错了?@FrameBuffer,视情况而定。如果字符串很短,则不会。如果字符串很长,则有许多技术可以减少字符串和向量中的内存分配。一个是自定义分配器(参见boost的池分配器)。例如,您可以为每个命令传递分配一个内存池。
        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)); 
        });
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);
}