2016-05-15 70 views
2

我的Vulkan程序運行速度非常慢,我試圖找出原因。我注意到,即使是一些平局也已經耗盡了他們應有的表現。 例如,這裏的渲染幾個網格的提取物(僞):Render-call performance drain

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個swapchain圖像。此時只有一個主要命令緩衝區(沒有輔助命令緩衝區/預先記錄的緩衝區),所有幀都具有相同的緩衝區。

我的問題是,我真的不知道要尋找什麼。這幾個渲染調用應該幾乎沒有影響,所以問題的根源必須在其他地方。

誰能給我任何提示我應該怎麼解決呢? Vulkan的任何配置文件已經在使用了嗎?我只需要朝正確的方向輕推。

//編輯:

所以,它看起來像vkDeviceWaitIdle大約爲32ms來執行,如果所有的238個網格渲染。 (如果沒有渲染,則爲< 1ms)。 大部分的阻礙源於此,但我仍然不知道該怎麼辦。

+1

'自動vertexBuffer = mesh.GetVertexBuffer();'這導致其可能是瓶頸的副本。 –

+1

不是,它是一個句柄(8 Byte)。索引緩衝區也一樣。實際的cpp代碼根本不會影響幀時間。 – Silverlan

+1

'vkDeviceWaitIdle'你打電話給的是什麼?這就像'glFinish';這是你應該*永遠不要*的東西。除非你正在做一個主要的應用程序狀態轉換(可能還沒有)或者應用程序拆卸。 –

回答

4

所以,看起來像vkDeviceWaitIdle大約需要32ms執行,如果所有238個網格都被渲染。 (如果沒有渲染,則爲< 1ms)。大部分阻力源於此,但我仍然不知道該怎麼做。

避免使用vkDeviceWaitIdle。這是可用的最重的同步操作,並將強制GPU完成並沖洗所有工作。

嘗試使用其他更輕量級的同步對象,如信號燈,屏障,柵欄和事件,並指定儘可能窄的訪問掩碼和流水線階段。

狹窄的範圍,特別是對於管道階段,確保管道的其他部分可以繼續工作,而對於vkDeviceWatiIdle,您可能會停止管道的所有部分。

2

絕對沒有理由在渲染循環中使用vkDeviceWaitIdle

相反,您應該爲vkQueueSubmit調用添加一個vkFence,並使用vkGetFenceStatus來查看是否可以觸摸命令緩衝區使用的內存。

這將像環形緩衝區一樣使用,因此存儲可變數據(視圖矩陣等)的多個副本,直到GPU完成它們。