渲染呼叫性能消耗

时间:2016-05-15 14:37:28

标签: 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();

    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

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

我的问题是,我真的不知道该找什么。这几个渲染调用几乎不会产生影响,因此问题的根源必须在其他地方。

任何人都可以给我任何提示我应该如何解决这个问题? Vulkan周围的任何剖析器已经存在吗?我只需要朝着正确的方向轻推。

//编辑:

因此,如果渲染了所有238个网格,看起来vkDeviceWaitIdle需要大约32ms才能执行。 (如果没有渲染,则为<1ms)。 大多数停滞都来自那里,但我仍然不知道该怎么办。

2 个答案:

答案 0 :(得分:4)

  

因此,如果渲染了所有238个网格,看起来vkDeviceWaitIdle需要大约32ms才能执行。 (如果没有渲染,则它<1ms)。大部分拖延都来自那里,但我仍然不知道该怎么办。

避免使用vkDeviceWaitIdle。它是最重的同步操作,可以强制GPU完成并清除所有工作。

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

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

答案 1 :(得分:2)

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

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

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