Vulkan:一次创建管道、命令缓冲区等有什么缺点吗?
Vulkan: Any downsides to creating pipelines, command-buffers, etc one at a time?
一些 Vulkan 对象(例如 vkPipelines、vkCommandBuffers)可以 created/allocated 数组(使用大小 + 指针参数)。乍一看,这样做似乎是为了更容易使用常见的使用模式进行编码。但在某些情况下(例如:创建 C++ RAII 包装器时),最好一次创建一个。当然,要做到这一点很简单。
但是,我想知道这样做是否有任何明显的缺点?
(我想这可能会因创建的实际对象类型而异 - 但我认为对每个对象提出相同的问题并不是一个好主意)
假设在这两种情况下,对象很可能以先创建后销毁的方式创建,并且 - 虽然对象是单独创建和销毁的 - 这可能会在循环中发生。
另请注意:
- vkCommandBuffers 也在数组中释放。
- vkPipelines被单独销毁。
有什么理由我应该修改我的 RAII 包装器以允许基于数组的 creation/destruction?例如,它会(显着)节省内存吗?单次创建会不会降低性能?
Vulkan API 是围绕现代图形硬件设计的。如果您知道要预先创建一定数量的对象,则应使用批处理函数(如果存在),因为驱动程序可能能够优化 creation/allocation,从而获得更好的性能。
可能(也可能不会)有更好的性能(取决于驱动程序和您的工作负载类型)。但显然 有潜力 以获得更好的性能。
如果您在应用程序中创建一个或十个命令缓冲区,则没有关系。
在大多数情况下,它会小于 5%。因此,如果您不关心这一点(例如,您的应用程序已经运行 500 FPS),那么没关系。
话又说回来,C++ 是一种多才多艺的语言。我认为这不是问题。您只需要一个静态成员函数或一个 class 即可 construct/initialize N 个对象(可能有一个模式名称)。
破坏可能更棘手。您可以再次拥有会破坏 N 个对象的静态成员函数。但它不会被自动调用,周围有 null/husk 个对象很烦人。并且析构函数仍将在 VK_NULL_HANDLE
上被调用。还有一个问题,池重置或销毁会使所有命令缓冲区 C++ 对象无效,因此可能没有办法做到这一点 cleanly/simply。
请记住,vkPipeline
创建不需要外部同步。这意味着该进程将处理它自己的互斥量等等。因此,尽可能避免锁定这些内部互斥量是有意义的。
另外,这个过程慢。所以能够将它打包并执行到另一个线程中是非常有用的。
命令缓冲区创建没有这些问题。因此,您应该可以随意分配所需的任何 CB。但是,多次创建绝不会 损害 性能,而且可能会有所帮助。所以没有理由避免它。
一些 Vulkan 对象(例如 vkPipelines、vkCommandBuffers)可以 created/allocated 数组(使用大小 + 指针参数)。乍一看,这样做似乎是为了更容易使用常见的使用模式进行编码。但在某些情况下(例如:创建 C++ RAII 包装器时),最好一次创建一个。当然,要做到这一点很简单。
但是,我想知道这样做是否有任何明显的缺点?
(我想这可能会因创建的实际对象类型而异 - 但我认为对每个对象提出相同的问题并不是一个好主意)
假设在这两种情况下,对象很可能以先创建后销毁的方式创建,并且 - 虽然对象是单独创建和销毁的 - 这可能会在循环中发生。
另请注意:
- vkCommandBuffers 也在数组中释放。
- vkPipelines被单独销毁。
有什么理由我应该修改我的 RAII 包装器以允许基于数组的 creation/destruction?例如,它会(显着)节省内存吗?单次创建会不会降低性能?
Vulkan API 是围绕现代图形硬件设计的。如果您知道要预先创建一定数量的对象,则应使用批处理函数(如果存在),因为驱动程序可能能够优化 creation/allocation,从而获得更好的性能。
可能(也可能不会)有更好的性能(取决于驱动程序和您的工作负载类型)。但显然 有潜力 以获得更好的性能。
如果您在应用程序中创建一个或十个命令缓冲区,则没有关系。
在大多数情况下,它会小于 5%。因此,如果您不关心这一点(例如,您的应用程序已经运行 500 FPS),那么没关系。
话又说回来,C++ 是一种多才多艺的语言。我认为这不是问题。您只需要一个静态成员函数或一个 class 即可 construct/initialize N 个对象(可能有一个模式名称)。
破坏可能更棘手。您可以再次拥有会破坏 N 个对象的静态成员函数。但它不会被自动调用,周围有 null/husk 个对象很烦人。并且析构函数仍将在 VK_NULL_HANDLE
上被调用。还有一个问题,池重置或销毁会使所有命令缓冲区 C++ 对象无效,因此可能没有办法做到这一点 cleanly/simply。
请记住,vkPipeline
创建不需要外部同步。这意味着该进程将处理它自己的互斥量等等。因此,尽可能避免锁定这些内部互斥量是有意义的。
另外,这个过程慢。所以能够将它打包并执行到另一个线程中是非常有用的。
命令缓冲区创建没有这些问题。因此,您应该可以随意分配所需的任何 CB。但是,多次创建绝不会 损害 性能,而且可能会有所帮助。所以没有理由避免它。