效果著色器連結

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 會在執行時間選取正確的著色器版本,視著色器連結是否套用至圖形中的特定連結而定。

    如果轉換只會透過 ID2D1EffectCoNtext::LoadPixelShader) 提供完整的圖元著色器 Blob (,則不會連結到連續的轉換。

  • 協助程式函式

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

    協助程式函式:

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

  • 僅限圖元著色器

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

  • 簡單與複雜的取樣

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

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

    某些圖元著色器,例如 Gaussian 模糊,會計算來自多個輸入樣本的輸出,而不只是單一樣本。 這類圖元著色器稱為執行複雜的取樣。

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

    只有具有簡單輸入的著色器函式可以有其他著色器函式所提供的輸入。 具有複雜輸入的著色器函式必須提供輸入紋理來取樣。 這表示 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 效果相容的輸入簽章。

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_PRI加值稅E_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 < 著色器Model> 將 ShaderModel > 設定 < 為FXC 語法中所定義的適當圖元著色器設定檔。 這必須是 「HLSL 著色器連結」底下所列的其中一個設定檔。
<MyShaderFile.hlsl > 將 MyShaderFile > 設定 < 為 HLSL 檔案的名稱。
/D D2D_FUNCTION 此定義會指示 FXC 編譯著色器的匯出函式版本。
/D D2D_ENTRY= < 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 < 著色器Model> 將 ShaderModel > 設定 < 為FXC 語法中所定義的適當圖元著色器設定檔。 這必須是對應至步驟 1 中所指定連結設定檔的圖元著色器設定檔。
<MyShaderFile.hlsl > 將 MyShaderFile > 設定 < 為 HLSL 檔案的名稱。
/D D2D_FULL_SHADER 此定義會指示 FXC 編譯著色器的完整版本。
/D D2D_ENTRY= < entry> 將專案 > 設定 < 為您在 D2D_PS_ENTRY () 宏內定義的 HLSL 進入點名稱。
/E < 專案> 將專案 > 設定 < 為您在 D2D_PS_ENTRY () 宏內定義的 HLSL 進入點名稱。
/setprivate < MyShaderFile.fxlib > 此引數會指示 FXC 將步驟 1 中產生的匯出函式著色器內嵌至D3D_BLOB_PRI加值稅E_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 介面