Vulkan和旧的API内存使用情况

时间:2018-04-03 09:17:50

标签: vulkan

我是新来的vulkan。问题在于转换对象。当使用DX11和OpenGL时,我用来更新统一缓冲区,然后将绘图命令发送到gpu,但是在vulkan中,所有命令都是预先记录的。所以我认为我无法做到这一点。我在网上读到,为了转换每个对象,我可以使用一系列均匀缓冲区并在绘制时从中索引。这是改变vulkan中每个对象的唯一方法吗?

如果不是那么使用比旧API更多的内存?较旧的API可以具有单个统一缓冲区并在绘制调用之前更新它,但在vulkan中,我们为每个对象使用缓冲区。 Vulkan作为高性能API很受欢迎,但较旧的API使用较少的内存。

如果不是,我怎样才能更有效地做到这一点? 感谢。

2 个答案:

答案 0 :(得分:3)

在像OpenGL这样的高级图形API中,统一变量也位于全局/通用统一缓冲区中。为方便起见,它只是没有暴露给开发人员。但是统一变量更新的执行方式与Vulkan类似 - 这是向统一缓冲区的正常数据传输。

现在,如果您想在绘制对象之前更新统一变量,您可以在Vulkan中完全相同。有像vkCmdUpdateBuffer()或vkCmdCopyBuffer()这样的方法。但为什么开发人员不使用这种方法呢?由于同步和对性能的影响。在OpenGL中,这是由驱动程序自动完成的,但它与Vulkan具有相同的影响。它并没有暴露给开发人员。 Vulkan表明,如果您正在考虑性能,这不是最好的方法。保持一组统一缓冲区(每个对象一个)或一个统一缓冲区与一系列统一变量更好。您也可以使用推送常量来实现此目的。使用它们类似于旧的,类似OpenGL的更新存储在全局命名空间中的统一变量,但数据量有限(规范保证128字节)。

答案 1 :(得分:2)

因此,假装Vulkan是OpenGL \ immediate API是完全有效的:

for( int i = 0; i < N; ++i ){
    cmdbuff.begin(); cmdUpdateUniform(u[i]); cmdbuff.end();
    vkQueueSubmit( q, cmdbuff ); // lookitme ama glUniform*()
    // some sychronization omitted 

    cmdbuff.begin(); vkCmdDraw(obj[i]); cmdbuff.end();
    vkQueueSubmit( q, cmdbuff ); // lookitme ama glDraw*()
    vkQueueWaitIdle( q ); // lookitme ama glFinish()
}
但是,这有一个问题。 OpenGL驱动程序会尝试使用延迟与吞吐量交易来优化这一点。但是在Vulkan中,我们希望对延迟有一定程度的控制,因此Vulkan驱动程序不会(不应该)以这种方式对其进行优化。

因此我们可以尝试猜测OpenGL驱动程序会做什么:

cmdbuff.begin();
for( int i = 0; i < N; ++i ){
    cmdUpdateUniform(u[i]);  // probably vkCmdUpdateBuffer     
    // some sychronization omitted   
    vkCmdDraw(obj[i]);
}
cmdbuff.end();

vkQueueSubmit( q, cmdbuff );

正如您所看到的那样,内存使用已经恢复(vkCmdUpdateBuffer将所有制服存储在命令缓冲区中),如果OpenGL驱动程序希望具有高性能,则可能必须执行相同操作(尝试聚合所有绘制)到一个GPU提交)。

这种方法也存在一个小问题。所有vkCmdDraw使用相同的uniform \ buffer内存,因此之前的vkCmdDraw需要在更新之前完成使用该统一。允许驱动程序继续进行,并且不必同步vkCmdDraw和随后的统一更新,可能会有好处。

你在网上看到的信息。一种方法是使用一系列制服并使用索引访问适当的制服。 另一种方法是通过pDynamicOffsets绑定不同的描述符或vkCmdBindDescriptorSets

<小时/> 关于内存使用的注意事项:

4x4 sp矩阵是64 B.假设你让我们说1024个3D对象是64 kB。在这个时代,作为主要的GP GPU内存是微不足道的,即使是单一的纹理或其他资源,你也需要相形见绌。

如果您的内存使用率显着提高,问题可能出在其他地方。