這是一個普遍的問題,雖然我使用 OpenCV 作為框架,但這個問題比 OpenCV 的領域更廣泛。
我正在開發一個影像處理工具,它將有效地從網路攝像頭獲取影像(產生位于的主機記憶體cv::Mat
),將其上傳到 CUDA 中的 GPU 設備記憶體(即cv::GpuMat
),使用 CUDA 進行一些處理并獲得結果finalCudaMat
,最后發送結果到 OpenGL(即cv::ogl::Buffer::mapDevice
finalCudaMat.copyTo(mappedOglBuffer)
)。一切都按預期作業。
由于整個程序涉及多個步驟,我使用 CUDA 流物件 ( cv::cuda::Stream
) 來使 CUDA 呼叫異步,而不是等待每個操作在 CPU 端完成。現在,如果有人最終將結果復制到 CPU 矩陣(即finalCudaMat.download(finalCpuMat)
),就像在習慣情況下一樣,通常需要等待流(cudaStream.waitForCompletion()
)以確保在使用 CPU 端矩陣之前結果準備就緒。
在我的例子中,結果永遠不會回傳到 CPU,因為它會繼續在螢屏上呈現(還涉及一些 OpenGL 操作和著色器)。
一種方法是,在開始將 GpuMat 復制到 OpenGL 緩沖區之前等待 CUDA 作業完成可能是合適的。因此,如果我在流中添加等待,一切正常,CUDA 操作大約需要 2.5 毫秒。
另一種方式,感覺就像我不需要等待流的完成(無論如何,所有結果都由 GPU 消耗——CPU 永遠不會再次參與)。因此,我可以在執行之前洗掉
cudaStream.waitForCompletion()
呼叫finalCudaMat.copyTo(mappedOglBuffer)
,并且一切似乎都作業正常。整個 CUDA 處理操作(基本上任何 GPU 任務減去 OpenGL 相關)對我來說顯然需要大約 1.8 毫秒。
過去,如果涉及兩個不同的 API(例如,在 Direct3D 9 上做某事,不要等待它完成,然后將生成的紋理復制到 Direct3D 10 紋理,并且清楚在某些幀上,影像變空或撕裂)。
在這一點上,差異很小,不會影響我的 60 FPS 吞吐量。但我想知道我是否通過洗掉等待流操作在技術上做正確的作業。對此有什么想法嗎?或者關于 OpenGL/CUDA 互操作的檔案可能對我有幫助?
uj5u.com熱心網友回復:
規則在本檔案中定義:https ://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#graphics-interoperability
特別是它說
在映射時通過 OpenGL、Direct3D 或其他 CUDA 背景關系訪問資源會產生未定義的結果。
這是一個非常強烈的暗示,表明所需的同步是由 執行的,其檔案cudaGraphicsUnmapResources
證實了這一點:
此功能提供了同步保證,即之前發布的任何 CUDA 作業將在任何后續發布的圖形作業開始
stream
之前完成。cudaGraphicsUnmapResources()
所以你不需要讓 CPU 等待 CUDA 完成,但你必須呼叫cudaGraphicsUnmapResources
它將在異步指令流中放置適當的屏障。請注意,與您的 CPU 傳輸代碼不同,此呼叫在CUDA 將資料復制到 OpenGL 緩沖區之后進行。
uj5u.com熱心網友回復:
正如 Ben Voigt 已經指出的,CUDA 需要與 OpenGL(或與之互操作的任何其他圖形 API)顯式同步。現在這使用了一種苦差事,其中必須向計算流提交回呼并使用它們手動處理例如OpenGL柵欄。
然而,由于 Vulkan 的出現以及對外部資源(以及 OpenGL 擴展)的支持,您實際上可以在 CUDA 和 OpenGL 命令流之間同步,方法是讓雙方都匯入平臺本機信號量 ( cudaImportExternalSemaphore
, GL_EXT_semaphore
) 并將它們用于相互同步。它通常仍然涉及通過 CPU 端驅動程式的整個往返行程,但由于該部分無論如何都必須管理命令流,所以它并不是真正的效率問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/490884.html
上一篇:向“輪廓”添加偏移量