共用方式為


變數語法

使用下列語法規則來宣告 HLSL 變數。

[Storage_Class] [Type_Modifier] Type Name[Index] [: Semantic] [: Packoffset] [: Register];[註釋] [= Initial_Value]

參數

Storage_Class

選擇性的儲存類別修飾詞,提供編譯程式有關變數範圍和存留期的提示;修飾詞可以依任何順序指定。

Description
extern 將全域變數標示為著色器的外部輸入;這是所有全域變數的預設標記。 無法與 靜態結合。
nointerpolation 請勿在將頂點著色器的輸出傳遞至圖元著色器之前插入。
精確 用至變數時的精確 關鍵詞會限制用來產生指派給該變數之值的任何計算方式如下:
  • 個別的作業會保持個別。 例如,如果 mul 和 add 作業可能已融合到瘋狂的作業中, 則精確 強制作業保持獨立。 相反地,您必須明確使用瘋狂的內部函數。
  • 維護作業順序。 如果指令順序可能已隨機顯示以改善效能, 請精確 確保編譯程式會保留寫入的順序。
  • IEEE 不安全的作業受到限制。 如果編譯程式可能已使用不考慮 NaN(不是數位)和 INF (無限) 值的快速數學運算, 則精確 強制遵守有關 NaN 和 INF 值的 IEEE 需求。 如果沒有 精確,這些優化和數學運算就不是 IEEE 安全。
  • 限定變數精確不會讓使用變數精確的作業。 由於精確傳播只會傳播給指派給精確限定變數值的作業,因此正確進行所需的計算可能會很棘手,因此我們建議您將著色器輸出標示為直接宣告它們的位置、無論是在結構字段上,還是在輸出參數上,或是輸入函式的傳回類型。 以這種方式控制優化的能力,藉由停用可能會影響最終結果的優化,因為累積有效位數差異的差異而影響最終結果,藉此維持已修改輸出變數的結果不因差異。 當您想要著色器進行鑲嵌,以維持水密修補接縫或比對多個傳遞的深度值時,它很有用。 範例程式碼
    HLSLmatrix g_mWorldViewProjection;
    void main(in float3 InPos: Position, out precise float4 OutPos : SV_Position)
    {
    作業是精確的,因為它有助於精確的參數 OutPos
    OutPos = mul( float4( InPos, 1.0 ),g_mWorldViewProjection ]。
    }
共用 標記變數以在效果之間共用;這是編譯程式的提示。
groupshared 標記計算著色器的線程群組共用記憶體變數。 在 D3D10 中,群組共用儲存類別之所有變數的大小上限為 16kb,在 D3D11 中,大小上限為 32 kb。 請參閱範例。
static 標記局部變數,使其一次初始化,並在函數調用之間保存。 如果宣告不包含初始化表達式,則值會設定為零。 應用程式看不到標示 為 static 的全域變數。
uniform 在著色器執行期間,標記數據為常數的變數(例如頂點著色器中的材質色彩):全域變數預設會視為 統一
volatile 標記經常變更的變數;這是編譯程式的提示。 此記憶體類別修飾詞僅適用於局部變數。
注意: HLSL 編譯程式目前會忽略此儲存類別修飾詞。

Type_Modifier

選擇性變數類型修飾詞。

Description
const 標記著色器無法變更的變數,因此必須在變數宣告中初始化它。 全域變數預設會 被視為 const (藉由提供 /Gec 旗標給編譯程式來隱藏此行為)。
row_major 標記變數,將四個元件儲存在單一數據列中,以便儲存在單一常數緩存器中。
column_major 標記變數,將 4 個元件儲存在單一數據行中,以將矩陣數學優化。

注意

如果您未指定類型修飾詞值,編譯程式會使用 column_major 做為預設值。

類型

數據類型 (DirectX HLSL) 中列出的任何 HLSL 類型。

Name[Index]

可唯一識別著色器變數的 ASCII 字串。 若要定義選擇性陣列,請使用 數位大小的索引 ,這是正整數 = 1。

語義

編譯程式用來連結著色器輸入和輸出的選擇性參數使用資訊。 頂點和像素著色器有數個預先定義的 意。 編譯程式會忽略語意,除非這些語意是在全域變數上宣告,或傳遞至著色器的參數。

Packoffset

手動封裝著色器常數的選擇性關鍵詞。 請參閱 packoffset (DirectX HLSL)

註冊

選擇性關鍵詞,用於手動將著色器變數指派給特定緩存器。 請參閱 register (DirectX HLSL)

Annotation(s)

附加至全域變數之字串形式的選擇性元數據。 效果架構會使用註釋,並由 HLSL 忽略;若要查看更詳細的語法,請參閱 註釋語法

Initial_Value

選擇性的初始值(s):值數目應該符合 Type 中的元件數目。 標記為 extern 的每個全域變數都必須使用常值初始化;每個標示為 static 的變數都必須使用常數初始化。

未標示 為靜態extern 的全域變數不會編譯成著色器。 編譯程式不會自動設定全域變數的預設值,而且無法在優化中使用它們。 若要初始化這種類型的全域變數,請使用反映來取得其值,然後將值複製到常數緩衝區。 例如,您可以使用ID3D11ShaderReflection::GetVariableByName方法來取得變數、使用ID3D11ShaderReflectionVariable::GetDesc方法來取得著色器變數描述,並從 D3D11_SHADER_VARIABLE_DESC 結構的 DefaultValue 成員取得初始值。 若要將值複製到常數緩衝區,您必須確定已使用 CPU 寫入存取權建立緩衝區(D3D11_CPU_ACCESS_WRITE)。 如需如何建立常數緩衝區的詳細資訊,請參閱 如何:建立常數緩衝區

您也可以使用 效果架構 來自動處理反映和設定初始值。 例如,您可以使用 ID3DX11EffectPass::Apply 方法。

重要

Direct3D 12 已移除此功能的支援,包括反映預設初始化表達式的功能。

範例

以下是著色器變數宣告的數個範例。

float fVar;
float4 color;

int iVar[3];

uniform float4 position : SV_POSITION; 

//Default initializers; supported up to Direct3D 11.

float fVar = 3.1f;
int iVar[3] = {1,2,3};
const float4 lightDirection = {0,0,1};

群組共用

HLSL 可讓計算著色器的線程透過共用記憶體交換值。 HLSL 提供屏障基本類型,例如 GroupMemoryBarrierWithGroupSync 等,以確保正確排序著色器中共用記憶體的讀取和寫入,並避免數據競爭。

注意

硬體會在群組中執行線程(變形或波前線),而屏障同步處理有時會省略,以在只同步處理屬於相同群組的線程正確時提高效能。 但基於下列原因,我們強烈建議您不要省略此省略:

  • 此遺漏會導致非可攜式程式代碼,這些程式代碼可能無法在某些硬體上運作,而且無法在通常以較小的群組執行線程的軟體轉譯程式上運作。
  • 相較於使用全線程屏障,您可能會透過此遺漏而達成的效能改進將會是次要的。

在 Direct3D 10 中,寫入群組 共用時不會同步處理線程,因此這表示每個線程都受限於數位中用於寫入的單一位置。 寫入時, 請使用SV_GroupIndex 系統值來編製此陣列的索引,以確保兩個線程都無法衝突。 在讀取方面,所有線程都可以存取整個陣列以供讀取。

struct GSData
{
    float4 Color;
    float Factor;
}

groupshared GSData data[5*5*1];

[numthreads(5,5,1)]
void main( uint index : SV_GroupIndex )
{
    data[index].Color = (float4)0;
    data[index].Factor = 2.0f;
    GroupMemoryBarrierWithGroupSync();
    ...
}

打包

封裝向量和純量的子元件,其大小足以防止跨越緩存器界限。 例如,這些全都是有效的:

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

無法混合封裝類型。

如同 register 關鍵詞,packoffset 可以是特定目標。 子元件封裝僅適用於 packoffset 關鍵詞,而非 register 關鍵詞。 在 cbuffer 宣告內,Direct3D 10 目標會忽略 register 關鍵詞,因為它假設為跨平臺相容性。

封裝的專案可能會重疊,編譯程式不會提供錯誤或警告。 在此範例中,Element2 和 Element3 會與 Element1.x 和 Element1.y 重疊。

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

使用 packoffset 的範例為: HLSLWithoutFX10 範例