C++ 渲染调用性能消耗

C++ 渲染调用性能消耗,c++,performance,rendering,vulkan,C++,Performance,Rendering,Vulkan,我的Vulkan程序运行得非常慢,我正试图找出原因。我注意到,即使是一些抽签调用,也会大大降低性能。 例如,以下是用于渲染几个网格的提取(伪代码): int32_t numCalls = 0; int32_t numIndices = 0; for(auto &mesh : meshes) { auto vertexBuffer = mesh.GetVertexBuffer(); auto indexBuffer = mesh.GetIndexBuffer();

我的Vulkan程序运行得非常慢,我正试图找出原因。我注意到,即使是一些抽签调用,也会大大降低性能。 例如,以下是用于渲染几个网格的提取(伪代码):

int32_t numCalls = 0;
int32_t numIndices = 0;
for(auto &mesh : meshes)
{
    auto vertexBuffer = mesh.GetVertexBuffer();
    auto indexBuffer = mesh.GetIndexBuffer();

    vk::DeviceSize offset = 0;
    drawCmd.bindVertexBuffers(0,1,&vertexBuffer,&offset); // drawCmd = CommandBuffer for all drawing commands (single thread)
    drawCmd.bindIndexBuffer(indexBuffer,offset,vk::IndexType::eUint16);

    drawCmd.drawIndexed(mesh.GetIndexCount(),1,0,0,0);

    numIndices += mesh.GetIndexCount();
    ++numCalls;
}
正在渲染238个网格,总顶点索引计数为52050。GPU绝对不会负担过重(着色器非常便宜)

如果我用上面的代码运行程序,帧的渲染时间约为46ms。没有它,只需9ms

我正在使用fifo呈现模式和2个交换链图像。此时只有一个主命令缓冲区(无辅助命令缓冲区/预记录缓冲区),所有帧的缓冲区相同

我的问题是,我真的不知道该找什么。这几个渲染调用应该不会造成什么影响,因此问题的根源一定在其他地方

有谁能给我一些建议,我应该如何处理这个问题?Vulkan公司已经有分析人员了吗?我只需要朝正确的方向轻推一下

//编辑:

因此,如果渲染全部238个网格,vkDeviceWaitIdle似乎需要大约32毫秒的时间来执行。(如果没有渲染,则小于1ms)。 大多数的拖延都源于此,但我仍然不知道该怎么办

因此,如果渲染全部238个网格,vkDeviceWaitIdle似乎需要大约32毫秒的时间来执行。(如果没有渲染,则小于1ms)。大多数的拖延都源于此,但我仍然不知道该怎么办

避免使用vkDeviceWaitIdle。这是最沉重的同步操作,将迫使GPU完成并刷新所有工作

尝试使用其他更轻量级的同步对象,如信号量、屏障、围栏和事件,并尽可能窄地指定访问掩码和管道阶段


狭窄的范围,特别是对于管道阶段,确保管道的其他部分可以继续工作,而使用vkDeviceWatiIdle,您可以暂停管道的所有部分。

绝对没有理由在渲染循环中使用
vkDeviceWaitIdle

相反,您应该向
vkQueueSubmit
调用添加一个vkFence,并使用
vkGetFenceStatus
查看是否可以触摸命令缓冲区使用的内存


这将像环形缓冲区一样使用,以便存储可变数据(视图矩阵等)的多个副本,直到GPU处理完它们。

auto vertexBuffer=mesh.GetVertexBuffer()这会导致一个可能成为瓶颈的副本。它不是,而是一个句柄(8字节)。索引缓冲区也是如此。实际的cpp代码基本上对帧时间没有任何影响。
vkDeviceWaitIdle
你为什么这么叫?这就像
glFinish
;这是你永远不应该做的事。除非您正在进行一次主要的应用程序状态转换(甚至可能不会)或应用程序崩溃。听起来vkDeviceWaitIdle是您的主要问题,但是,您是否启用了验证层?使用VK_LAYER_LUNARG_standard_验证会增加大量开销。