共用方式為


效果著色器連結

Direct2D 使用稱為效果著色器連結的優化,將多個效果渲染過程結合到單一階段。

效果著色器連結概觀

效果著色器鏈接優化建置在 HLSL 著色器連結之上,這是 Direct3D 11.2 功能,可藉由鏈接預先編譯的著色器函式,在運行時間產生圖元和頂點著色器。 以下圖片說明在效果圖形中效果著色器連結的概念。 第一個圖顯示具有四個轉譯轉換的典型 Direct2D 效果圖形。 如果沒有著色器連結,每個轉換都會消耗一個繪圖運算步驟,且需要一個中繼表面;此圖表總共需要 4 個步驟和 3 個中繼表面。

不連接著色器的情況下轉換圖形:4 次處理和 3 個中間結果。

第二幅圖顯示相同效果的圖表,其中每個渲染轉換都已取代為可連結的函式版本。 Direct2D 能夠鏈接整個圖表,並在一次傳遞中執行它,而不需要任何中繼。 這可大幅減少 GPU 運行時間,並減少尖峰 GPU 記憶體耗用量。

使用著色器連結進行圖形轉換:1 階段,0 個中間結果。

 

效果著色器連結會在效果內的個別轉換上運作;這表示即使具有單一效果的圖形,如果該效果有多個有效的轉換,則著色器連結可能會受益。

使用效果著色器連結

如果您要建置使用效果的 Direct2D 應用程式,則不需要執行任何動作來利用效果著色器連結。 Direct2D 會自動分析效果圖表,以判斷連結每個轉換的最佳方式。

效果作者負責以支援效果著色器連結的方式實作其效果;如需詳細資訊,請參閱下方 撰寫著色器連結相容自定義效果 一節。 所有內建效果都支援著色器連結。

Direct2D 只會在有利的情況下連結相鄰的渲染轉換。 判斷是否要連結兩個轉換時,它會考慮多個因素。 例如,如果其中一個變換使用了頂點或計算著色器,那麼將不會執行著色器連結,因為只有圖元著色器可以被連結。 此外,如果一个效果未撰寫成與著色器連結相容,則周圍的轉換效果將不會與其連結。

如果存在這類連結危險,Direct2D 將不會連結任何與危險相鄰的轉換,但仍會嘗試連結圖形的其餘部分。

轉換具有連結危害的圖表:2 次,1 次中繼。

撰寫著色器連結相容自定義效果

如果您要撰寫自己的自定義 Direct2D 效果,您必須確保其變換支援效果著色器連結。 這需要先前自定義效果實作方式的一些次要變更。 如果您的自定義效果內的轉換不支援著色器連結,Direct2D 將不會將它與效果圖形中相鄰的任何轉換連結。

身為自定義效果作者,您應該注意數個重要概念和需求:

  • 不會變更效果界面的實作

    您不需要修改任何實作各種效果介面的程式代碼,例如 ID2D1DrawTransform

  • 提供著色器的完整和導出函式版本

    您必須提供由 Direct2D 連結之效果著色器的匯出函式版本。 此外,您也必須繼續提供原始、完整的著色器;這是因為 Direct2D 會根據著色器連結是否套用至圖形中的特定連結,在運行時間選取正確的著色器版本。

    如果轉換只提供完整的圖元著色器 Blob(透過 ID2D1EffectContext::LoadPixelShader),它就不會連結到相鄰的轉換。

  • 輔助函式

    Direct2D 提供 HLSL 輔助函數和巨集, 可自動生成著色器的完整版本和匯出函數版本。 您可以在 d2d1effecthelpers.hlsli 中找到這些協助程式。 此外,HLSL 編譯程式 (FXC) 可讓您將匯出函式著色器插入完整著色器中的私用字段。 如此一來,您只需要撰寫著色器一次,並同時將這兩個版本傳遞至 Direct2D。 d2d1effecthelpers.hlsli 和 FXC 編譯程式都會包含在 Windows SDK 中。

    協助程式函式:

    您也可以為每個著色器手動撰寫兩個版本,並編譯兩次,前提是需符合 匯出函式規格 中所述的規格。

  • 像素著色器

    Direct2D 不支援連結計算或頂點著色器。 不過,如果您的效果同時使用頂點著色器和像素著色器,那麼像素著色器的輸出仍然可以連結。

  • 簡單與複雜取樣

    著色器函式連結的運作方式是將一個像素著色器的輸出連接到後續像素著色器傳遞的輸入。 只有當取用的圖元著色器只需要單一輸入值來執行計算時,才可能這樣做:這個值通常來自取樣頂點著色器所發出之紋理座標的輸入紋理。 這類圖元著色器據說會執行簡單的取樣。

    灰階轉換是簡單的取樣範例。特定輸出圖元的值只取決於對應輸入圖元的值。

    某些圖元著色器,例如高斯模糊,會從多個輸入樣本計算其輸出,而不只是單一樣本。 這類圖元著色器據說會執行複雜的取樣。

    高斯模糊是複雜的取樣範例。中心輸出圖元的值取決於多個輸入圖元。

    只有當著色器函式的輸入為簡單類型時,才可以由另一個著色器函式提供輸入。 具有複雜輸入的著色器函式必須提供要取樣的輸入紋理。 這表示 Direct2D 不會將著色器與複雜輸入連結至其前置專案。

    使用 Direct2D HLSL 協助程式時,您必須在 HLSL 中指出著色器使用複雜或簡單的輸入。

連結相容效果著色器的範例

使用 D2D 協助程式時,下列代碼段代表簡單的連結相容效果著色器:

#define D2D_INPUT_COUNT 1
#define D2D_INPUT0_SIMPLE
#include “d2d1effecthelpers.hlsli”

D2D_PS_ENTRY(LinkingCompatiblePixelShader)
{
    float4 input = D2DGetInput(0);
    input.rgb *= input.a;
    return input;
}          

在這個簡短的範例中,請注意,不會宣告任何函式參數、在輸入函式之前宣告每個輸入的輸入和類型數目、呼叫 D2DGetInput來擷取輸入,而且必須在包含協助程式檔案之前定義預處理器指示詞。

連結相容的著色器必須同時提供一般單通道圖元著色器和匯出著色器函式。 D2D_PS_ENTRY 巨集可讓這些元素從相同的程式碼產生,當與著色器編譯腳本搭配使用時。

編譯完整的著色器時,巨集會展開成下列程式碼,該程式碼具有 D2D Effects 相容的輸入簽章。

Texture2D<float4> InputTexture0;
SamplerState InputSampler0;

float4 LinkingCompatiblePixelShader(
    float4 pos   : SV_POSITION,
    float4 posScene : SCENE_POSITION,
    float4 uv0  : TEXCOORD0
    ) : SV_Target
    {
        float4 input = InputTexture0.Sample(InputSampler0, uv0.xy);
        input.rgb *= input.a;
        return input;
    }    

編譯相同程式代碼的匯出函式版本時,會產生下列程式代碼:

// Shader function version
export float4 LinkingCompatiblePixelShader_Function(
    float4 input0 : INPUT0)
    {
        input.rgb *= input.a;
        return input;
    }      

請注意,通常藉由取樣 Texture2D 擷取的紋理輸入已取代為函式輸入 (input0)。

若要檢視詳細步驟描述,說明您如何撰寫一個與連結相容的效果,請參閱 自訂效果教學課程,以及 Direct2D 自訂影像效果範例資源

編譯連結相容著色器

若要鏈接,傳遞至 D2D 的像素著色器 Blob 必須同時包含著色器的完整和導出函式版本。 這可藉由將編譯的導出函式內嵌至D3D_BLOB_PRIVATE_DATA區域來完成。

使用 D2D 協助程式函式撰寫著色器時,必須在編譯期間定義 D2D 編譯目標。 編譯目標類型是D2D_FULL_SHADER和D2D_FUNCTION。

編譯連結相容的效果著色器是一個由兩個步驟組成的過程:

注意

使用 Visual Studio 編譯效果時,您應該建立批處理檔來執行 FXC 命令,並以編譯步驟之前執行的自定義建置步驟執行此批處理檔。

 

步驟 1:編譯導出函式

fxc /T <shadermodel> <MyShaderFile>.hlsl /D D2D_FUNCTION /D D2D_ENTRY=<entry> /Fl <MyShaderFile>.fxlib           

若要編譯著色器的導出函式版本,您必須將下列旗標傳遞至 FXC。

描述
/T <ShaderModel> 將 ShaderModel <> 設定為適當的像素著色器配置檔,按照 FXC 語法 的定義。 這必須是「HLSL 著色器連結」底下所列的其中一個設定檔。
<MyShaderFile>.hlsl 將 <MyShaderFile> 設定為 HLSL 檔案的名稱。
/D D2D_FUNCTION 此定義會指示 FXC 編譯著色器的導出函式版本。
/D D2D_ENTRY=<項目> 將 <條目> 設定為您在 D2D_PS_ENTRY 巨集中定義的 HLSL 入口點名稱。
/Fl <MyShaderFile>.fxlib 將 <MyShaderfile> 設定為您要儲存著色器的導出函式版本。 請注意,.fxlib 延伸模組僅供方便識別。

步驟 2:編譯完整的著色器並內嵌匯出函式

fxc /T ps_<shadermodel> <MyShaderFile>.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=<entry> /E <entry> /setprivate <MyShaderFile>.fxlib /Fo <MyShader>.cso /Fh <MyShader>.h           

若要使用內嵌匯出版本編譯著色器的完整版本,您必須將下列旗標傳遞至 FXC。

描述
/T <ShaderModel> 將 ShaderModel> 設為適當的圖元著色器配置檔 <,依據 FXC 語法 中定義。 這必須是對應至步驟 1 中所指定連結配置檔的像素著色器配置檔。
<MyShaderFile>.hlsl 將 <MyShaderFile> 設定為 HLSL 檔案的名稱。
/D D2D_FULL_SHADER 此定義會指示 FXC 編譯著色器的完整版本。
/D D2D_ENTRY=<項目> 將 <項目> 設定為您在 D2D_PS_ENTRY() 巨集內定義的 HLSL 入口點名稱。
/E <項目> 將 <項目> 設為您在 D2D_PS_ENTRY() 巨集內定義的 HLSL 進入點名稱。
/setprivate <MyShaderFile>.fxlib 這個自變數會指示 FXC 將步驟 1 中產生的匯出函式著色器內嵌至D3D_BLOB_PRIVATE_DATA區域。
/Fo <MyShader>.cso 請將 <MyShader> 設定為儲存最終合併編譯著色器的位置。
/Fh <MyShader>.h 將 <MyShader> 設定為您要儲存最終合併標頭的位置。

匯出功能規格

雖然不建議這麼做,但在不使用 D2D 提供的協助程序的情況下撰寫相容的效果著色器是可行的。 請務必小心,以確保完整的著色器和導出函式輸入簽章都符合 D2D 規格。

完整著色器的規格與舊版 Windows 相同。 簡言之,圖元著色器的輸入參數必須是SV_POSITION、SCENE_POSITION,以及每個效果輸入一個TEXCOORD。

針對導出函式,函式必須傳回 float4,而且其輸入必須是下列其中一種類型:

  • 簡單輸入

    float4 d2d_inputN : INPUTN         
    

    針對簡單的輸入,D2D 會在輸入紋理和著色器函式之間插入 Sample 函式,或輸入將由另一個著色器函式的輸出提供。

  • 複雜輸入

    float4 d2d_uvN  : TEXCOORDN                
    

    對於複雜的輸入,D2D 只會傳遞紋理座標,如 Windows 8 檔中所述。

  • 輸出位置

    float4 d2d_posScene : SCENE_POSITION                
    

    只能定義一個SCENE_POSITION輸入。 此參數只應在必要時包含,因為每個連結著色器只能使用此參數一個函式。

語意必須定義為上述,因為 D2D 會檢查語意,以決定如何將函式連結在一起。 如果有任何函式輸入不符合上述其中一種類型,則會拒絕函式以進行著色器連結。

HLSL 輔助工具

ID3D11Linker 介面

ID3D11FunctionLinkingGraph 介面