著色器常數 (HLSL)

在著色器模型 4 中,著色器常數會儲存在記憶體中的一或多個緩衝區資源中。 它們可以組織成兩種類型的緩衝區:常數緩衝區(cbuffer)和紋理緩衝區(tbuffer)。 常數緩衝區已針對常數變數使用方式進行優化,其特點是低延遲存取和 CPU 更新頻率更高。 因此,其他大小、配置和存取限制會套用至這些資源。 紋理緩衝區會像紋理一樣存取,並針對任意索引的數據執行得更好。 無論您使用哪種類型的資源,應用程式可以建立的常數緩衝區或紋理緩衝區數目沒有限制。

宣告常數緩衝區或紋理緩衝區看起來與 C 中的結構宣告非常類似,並新增 register 和 packoffset 關鍵詞以手動指派緩存器或封裝數據。

*BufferType* *Name* \[: **register**(b\#)\] { *VariableDeclaration* \[: **packoffset**(c\#.xyzw)\]; ... };

參數

BufferType

[in]緩衝區類型。

BufferType 描述
cbuffer 常數緩衝區
tbuffer 紋理緩衝區

名稱

[in]包含唯一緩衝區名稱的 ASCII 字串。

register(b#)

[in]選擇性關鍵詞,用來手動封裝常數數據。 常數只能封裝在常數緩衝區中,其中起始緩存器是由緩存器號碼 (#) 提供。

VariableDeclaration

[in]變數宣告,類似於結構成員宣告。 這可以是任何 HLSL 類型或效果物件(除了紋理或取樣器物件除外)。

packoffset(c#.xyzw)

[in]選擇性關鍵詞,用來手動封裝常數數據。 常數可以封裝在任何常數緩衝區中,其中緩存器編號是由 (#) 提供。 子元件封裝(使用 xyzw swizzling)適用於大小符合單一緩存器(不要跨越緩存器界限)的常數。 例如,float4 無法封裝在從 y 元件開始的單一緩存器中,因為它不適合四個元件緩存器。

備註

常數緩衝區可允許著色器常數組成群組並同時認可 (而非進行個別呼叫以單獨認可每個常數),藉此減少更新著色器常數所需要的頻寬。

常數緩衝區是特殊化的緩衝區資源,其存取方式就像緩衝區一樣。 每個常數緩衝區最多可保存 4096 向量;每個向量最多包含四個 32 位值。 每個管線階段最多可以系結 14 個常數緩衝區(2 個額外的位置保留供內部使用)。

紋理緩衝區是特殊化的緩衝區資源,其存取方式就像紋理一樣。 紋理存取(與緩衝區存取相比)對於任意編製索引的數據,可以有更好的效能。 每個管線階段最多可以系結 128 個紋理緩衝區。

緩衝區資源的設計目的是將設定著色器常數的額外負荷降到最低。 效果架構(請參閱 ID3D10Effect 介面)將管理更新常數和紋理緩衝區,或者您可以使用 Direct3D API 來更新緩衝區(請參閱複製和存取資源數據 (Direct3D 10) 以取得資訊)。 應用程式也可以將數據從另一個緩衝區(例如轉譯目標或數據流輸出目標)複製到常數緩衝區。

如需在 D3D10 應用程式中使用常數緩衝區的詳細資訊,請參閱資源類型 (Direct3D 10)建立緩衝區資源 (Direct3D 10)。

如需在 D3D11 應用程式中使用常數緩衝區的詳細資訊,請參閱 Direct3D 11 中的緩衝區簡介和 如何:建立常數緩衝區

常數緩衝區不需要檢視系結至管線。 不過,紋理緩衝區需要檢視,而且必須在使用效果時系結至紋理位置(或必須使用 SetTextureBuffer 系結)。

有兩種方式可以封裝常數數據:使用 緩存器 (DirectX HLSL)packoffset (DirectX HLSL) 關鍵詞。

Direct3D 9 與 Direct3D 10 和 11 之間的差異:

  • 不同於 Direct3D 9 中常數的自動配置,它未執行封裝,而是將每個變數指派給一組 float4 緩存器,HLSL 常數變數遵循 Direct3D 10 和 11 中的封裝規則。

組織常數緩衝區

常數緩衝區可允許著色器常數組成群組並同時認可 (而非進行個別呼叫以單獨認可每個常數),藉此減少更新著色器常數所需要的頻寬。

有效率地使用常數緩衝區的最佳方式是根據其更新頻率,將著色器變數組織成常數緩衝區。 這可讓應用程式將更新著色器常數所需的頻寬降到最低。 例如,著色器可能會宣告兩個常數緩衝區,並根據更新的頻率來組織每個緩衝區中的數據:每個物件需要更新的數據(例如世界矩陣)會分組成可針對每個物件更新的常數緩衝區。 這與描述場景特徵的數據不同,因此可能會更新得比較少得多(當場景變更時)。

cbuffer myObject
{       
    float4x4 matWorld;
    float3   vObjectPosition;
    int      arrayIndex;
}
 
cbuffer myScene
{
    float3   vSunPosition;
    float4x4 matView;
}
        

預設常數緩衝區

有兩個可用的預設常數緩衝區,$Global和$Param。 在全域範圍中放置的變數會使用用於 cbuffer 的相同封裝方法,以隱含方式新增至 $Global cbuffer。 函式參數清單中的統一參數會在效果架構外部編譯著色器時,出現在$Param常數緩衝區中。 在效果架構內編譯時,所有制服都必須解析為全域範圍中定義的變數。

範例

以下是來自 Skinning10 Sample 的範例,這是由矩陣陣陣組成的紋理緩衝區。

tbuffer tbAnimMatrices
{
    matrix g_mTexBoneWorld[MAX_BONE_MATRICES];
};
      

這個範例宣告會手動指派常數緩衝區,以從特定緩存器開始,並依子元件封裝特定專案。

cbuffer MyBuffer : register(b3)
{
    float4 Element1 : packoffset(c0);
    float1 Element2 : packoffset(c1);
    float1 Element3 : packoffset(c1.y);
}
      

著色器模型 4