1. 程式人生 > >淺談 OpenGL 中相關阻塞問題

淺談 OpenGL 中相關阻塞問題

 

  昨天我遇到一個問題,問題如下:

    我使用了延遲渲染,我的渲染流程是:Pass1 --> CUDA平行計算 -->Pass2

    CUDA平行計算中需要使用Pass1渲染生成的兩張紋理,然而我在GPU端使用CUDA計算時發現紋理為空(資料全是0值),但是如果將兩張紋理的資料傳回CPU端,打印出來是有值的,且是正確的值。如果在CUDA平行計算之前先將紋理資料傳回CPU,這時發現CUDA平行計算中紋理是正常有值的。。。這個現象很奇怪,我開始想了想會不會是阻塞啥原因,但我對OpenGL阻塞過程不瞭解,沒看到過相關的資料,簡單思考了一下覺得不是阻塞的原因,我覺得可能是其中的一張紋理有問題,牽連導致這個問題。。。。。最終驗證發現還是OpenGL阻塞的原因。在CUDA平行計算之前加上 glFinish()函式即可。

  

  為啥加上glFinish()函式就解決了呢? 解釋這個之前,先說一下glFlush()和glFinish()函式的作用:

    一個OpenGL渲染程式會呼叫很多的OpenGL命令,而OpenGL是非同步的,CPU將這些耗時的命令傳送到GPU端,然後直接返回繼續執行,這些OpenGL相關指令儲存在GPU的快取中一條條的執行,但是CPU也不是直接傳送給GPU的,CPU自己有快取,先儲存在自己的快取中,之後再發送過去(有時機,例如遇到某些重新整理的命令等)。現在開始介紹以上兩個函式的作用。

    glFlush():將快取在CPU端的命令傳送到GPU上,清空快取,傳送完立即返回。

    glFinish():將快取在CPU端的命令傳送到GPU上,清空快取,傳送完,等待GPU執行完在返回。

  

  看到這裡就可以理解我加上 glFinish() 可以解決問題的原因了。我沒加 glFinish() 時,CUDA平行計算時,這時Pass1實際沒有執行完,故紋理為空,CUDA中拿不到正確的紋理資料,加上 glFinish() 後實際就是加入了GPU阻塞,等待Pass1執行完,然後執行CUDA平行計算。

 

  注:說到這裡,談點我思考的問題:

    1、在OpenGL渲染中,不管是 Pass1 --> CUDA平行計算 -->Pass2, 或者  Pass1 --> Pass2 或者Pass(只有一個Pass),我們統計兩次渲染之間的時間差值就可以計算幀率,為啥不會因為非同步問題計算不準呢? 因為 glfwSwapBuffers(glfw_window) 命令會將所有CPU端的命令傳送到GPU端,並等待其執行完,然後再交換前後緩衝。

    2、對於Pass1 --> Pass2這樣的延遲渲染,Pass1和Pass2都是作為命令傳送到GPU端,按序執行,故不會出現Pass2拿到的資料(由Pass1處理的)不正確情況,我們不需要加阻塞保障其執行。

       另外不要錯誤以為,CPU執行到Pass2處看見Pass1還在執行,CPU阻塞等待Pass1執行完然後傳送Pass2指令。

    3、為啥在CUDA平行計算前,對紋理進行一次資料傳回可以讓CUDA獲取正確的紋理資料 ?我覺得(差不多肯定是這樣,哈哈,自信……)拷貝紋理資料的OpenGL API雖然與GPU相關,但是其與CPU也相關,需要在CPU端的記憶體上接收傳回的資料,從CPU端考慮它也會阻塞的。

    4、Pass1 和 CUDA平行計算 都是在GPU上執行的,而CUDA拿不到正確的紋理資料,可以認為 Pass1 和 CUDA平行計算 同時在GPU上並行執行(我猜的,應該是吧……)。

    

      &n