2017-05-03 63 views
4

在例如GLSL中編寫的着色器通常在運行時加載到圖形應用程序中。我想知道爲什麼不直接用着色器編譯應用程序,以便以後不必加載。像這樣:在圖形應用程序中,爲什麼着色器會在運行時加載到應用程序中?

#define glsl(version, glsl) "#version " #version "\n" #glsl 

namespace glsl { namespace vs { 
//VERTEX SHADERS 
//========================= 
// simple VS 
//========================= 
constexpr GLchar * const simple = glsl(450 core, 
    layout(location = 0) in vec3 position; 

    void main() { 
     gl_Position = vec4(position, 1.0f); 
    } 
    ); 

} namespace fs { 
//FRAGMENT SHADERS 
//========================= 
// simple FS 
//========================= 
constexpr GLchar * const simple = glsl(450 core, 
    out vec4 color; 

    void main() { 
     color = vec4(1.0f, 0.0f, 0.0f, 1.0f); 
    }  
    ); 

} } 

我不認爲這會導致exe文件太大,它會加快加載時間;除非我誤解了有多少着色器用於典型的圖形應用程序。我意識到你可能想要在編譯時更新着色器,但這確實發生了嗎?

有什麼理由不應該這樣做?

+3

這個問題可能更適合https://softwareengineering.stackexchange.com/,因爲它可能會產生大量的自以爲是或主觀的答案。 – Xirema

+1

我不這樣做的主要原因是因爲每當着色器被改變時你都必須重新編譯你的應用程序。在我目前的項目建設中,應用程序可能需要幾分鐘的時間,所以我們儘量避免這種情況。 – BDL

+0

你從哪裏得到這個想法? Shader編譯是一個代價高昂的過程(在同一臺機器上反覆執行並獲得相同的結果是毫無意義的)。建議使用預編譯(或至少緩存)着色器。例如看[QUALCOMM dev網絡文章](https://developer.qualcomm.com/blog/binary-shaders) – VTT

回答

3

有幾個原因:

  • 在開發過程中這是非常方便的「hotload」着色器,無需重新啓動應用程序,以便您可以在調試或性能調整的變化,並立即看到結果。當着色器作爲單獨的文件存儲時,這更簡單。
  • 正如評論中所述,根據您的平臺,通常將着色器從高級着色語言預編譯爲中間字節代碼表示或實際最終GPU代碼(例如,在GPU硬件爲固定目標)。 Shader編譯可能非常耗時,因此最好在脫機時執行,而不要在運行時執行。
  • 在小型/簡單應用程序中,您採用的方法實際上並不少見,您的應用程序越大,需要管理的着色器越多,這會變得更加痛苦。就我個人而言,我喜歡即使在小型個人項目上也可以加載着色器。
  • 這實際上是一個比shader更爲普遍的問題。在任何項目中,您都可以選擇何時在可執行文件中嵌入資源(可以直接在源代碼中或通過單獨的構建步驟(如Windows資源)),也可以將它們作爲單獨的文件存儲。這兩種方法都有優點和缺點,但嵌入的主要優點是應用程序可能需要的所有資源都嵌入可執行文件中,因此您不必擔心/處理可能丟失的資源。缺點是,如果你把所有內容都塞進可執行文件中(特別是對於像遊戲那樣擁有許多大型資產的項目),那麼你會增加構建時間,使加載變得困難並且會使資產組織問題變得更加困難。
-1

着色器編譯過程是OpenGL的glsl編譯器的一部分,雖然您可以將着色器作爲字符串硬編碼到內存中,但每次對着色器進行任何編輯時都需要重新編譯。

在遊戲編程中,當您對代碼,着色器,庫等的數百個部分進行小小調整時,通常不希望重新編譯整個項目。這是所有大型遊戲引擎都具有的主要原因之一腳本引擎,通常編寫額外的樣板代碼以將腳本集成到引擎中比編譯一個程序10次更好,只是爲了使對象的顏色/亮度/位置恰到好處。嘗試對所有着色器進行硬編碼,以便在運行時在內存中進行編譯,然後您將看到一天之後它變得多麼乏味!

1

你如何看待它會加快加載時間?它不!

如果你讀,你有fopen(或std::ifstreamCreateFile或其他)打開一個普通文件中的數據,如果你在訪問過程中圖像的某些部分不要緊,並從閱讀,或。在大多數情況下,訪問過程映像中大量頁面的性能可能會變差,因爲大多數操作系統都會在不可執行的只讀數據段中延遲填充頁面;對未填充頁面的mmaped讀取訪問實際上比只讀讀取要慢,因爲它涉及到頁表錯誤和後續I/O讀取以使用數據填充頁面。

強制性讀:http://lkml.iu.edu/hypermail/linux/kernel/0004.0/0728.html

OpenGL的API specifices GLSL源代碼是實際加載着色器的唯一方法。有一個緩存API(glShaderBinary,glProgramBinary),但是通過它加載的二進制文件是未指定的格式,可以隨時更改,並且它是一個有效的錯誤條件,驅動程序拒絕二進制文件出於任何原因強制加載原始GLSL源代碼。爲了實際獲得這樣的着色器二進制文件,首先加載一個常規GLSL着色器源代碼,編譯它,然後從OpenGL中檢索二進制BLOB。

+0

我說過,因爲這個過程已經坐在RAM中,而從文件中讀取則不在磁盤中。而用於完成某些事情的陳述越少,總會導致更快的代碼。 –

+0

@KeithBecker:這不符合你的想法。在分頁的虛擬內存環境中,操作系統不會將整個二進制文件加載到RAM中!這將非常浪費,而且根本就沒有必要。會發生什麼情況是,創建的頁面映射與磁盤交換內存的工作方式(實際上使用的是相同的代碼路徑)相同:進程文件基本上被視爲只讀交換文件,只有那些部分被拉入RAM這是實際使用的。你可以擁有一個GiB大的可執行文件,如果代碼片段只有幾個KB,它的加載速度就像一個微小的可執行文件一樣快。 – datenwolf

+0

@KeithBecker:任何不屬於代碼段的部分實際上都不會在啓動時加載到RAM中。操作系統創建一個頁面映射,當你最終訪問它時,這些部分被拉入內存。然而,這涉及到工作而不是直接讀入緩衝區。即相關頁面必須有錯誤,即內存管理員必須爲系統分配一些物理內存(這不是一個便宜的操作,實際上很慢)。 – datenwolf

相關問題