這是一個普遍的問題,雖然我使用 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
上一篇:向“輪廓”添加偏移量
