語法變數
使用下列語法規則來宣告 HLSL 變數。
[Storage_Class][Type_Modifier] 類型名稱[索引] [: Semantic] [: Packoffset] [: Register];[注釋][= Initial_Value]
參數
-
Storage_Class
-
選擇性的儲存體類別修飾詞,可提供有關變數範圍和存留期的編譯器提示;修飾詞可以依任何順序指定。
值 描述 extern 將全域變數標示為著色器的外部輸入;這是所有全域變數的預設標記。 無法與 靜態結合。 nointerpolation 請勿在將頂點著色器的輸出傳遞至圖元著色器之前插入。 精確 套用至變數時的 精確 關鍵字會限制用來產生指派給該變數之值的任何計算方式如下: - 個別的作業會分開。 例如,當多子和新增作業可能已合併到一個不想要的作業時, 精確 會強制作業保持分開。 相反地,您必須明確使用不想要的內建函式。
- 維護作業順序。 當指令順序可能已隨機排列以提升效能時, 精確 可確保編譯器會保留寫入的順序。
- IEEE 不安全的作業受到限制。 如果編譯器可能已使用不考慮 NaN 的快速數學運算, (不是數位) ,而 INF (無限) 值, 則精確 強制遵守 NaN 和 IN光圈值的 IEEE 需求。 如果沒有 精確,這些優化和數學運算並不安全。
- 限定變數 精確 不會讓使用變數 精確的作業。 由於精確只會傳播至對指派給精確限定變數之值的作業,因此正確讓所需的計算精確可能很棘手,因此建議您直接在宣告著色器輸出的位置標記著色器輸出,無論是在結構欄位上或輸出參數上,還是輸入函式的傳回型別。 藉由停用可能會影響最終結果的優化,藉由停用因累積有效位數差異差異而影響最終結果的優化,以這種方式控制優化的能力會維持修改輸出變數的結果不一致。 如果您想要著色器進行鑲嵌,以維護水緊密修補接點,或比對多個階段的深度值時,它很有用。 範例程式碼:
HLSLmatrix g_mWorldViewProjection;
float3 InPos 中的 void main (: Position, out precise float4 OutPos : SV_Position)
{
作業精確,因為它會參與精確的參數 OutPos
OutPos = mul ( float4 ( InPos, 1.0 ) , g_mWorldViewProjection ) ;
}
共用 標記變數以在效果之間共用;這是編譯器的提示。 groupshared 為計算著色器標示執行緒群組共用記憶體的變數。 在 D3D10 中,具有群組共用儲存類別的所有變數大小上限為 16 kb,在 D3D11 中,大小上限為 32 kb。 請參閱範例。 static 標記區域變數,使其一次初始化,並在函式呼叫之間保存。 如果宣告不包含初始化運算式,此值會設定為零。 應用程式看不到標示 為靜態 的全域變數。 均勻 標記變數,其資料在整個著色器執行期間為常數 (,例如頂點著色器中的材質色彩) ;全域變數預設會被視為 統一 。 volatile 標記經常變更的變數;這是編譯器的提示。 此儲存類別修飾詞僅適用于區域變數。
注意: HLSL 編譯器目前會忽略此儲存體類別修飾詞。 -
Type_Modifier
-
選擇性變數類型修飾詞。
值 描述 const 標記著色器無法變更的變數,因此必須在變數宣告中初始化它。 全域變數預設會被視為 const , (藉由將 /Gec 旗標提供給編譯器) 來隱藏此行為。 row_major 標記變數,將四個元件儲存在單一資料列中,以便儲存在單一常數暫存器中。 column_major 標記變數,將 4 個元件儲存在單一資料行中,以優化矩陣數學。 注意
如果您未指定類型修飾詞值,編譯器會使用 column_major 做為預設值。
-
類型
-
Name[Index]
-
可唯一識別著色器變數的 ASCII 字串。 若要定義選擇性陣列,請使用陣列大小的 索引 ,這是正整數 = 1。
-
語義
-
編譯器用來連結著色器輸入和輸出的選擇性參數使用資訊。 頂點和圖元著色器有數個預先定義的 語意 。 除非編譯器是在全域變數上宣告,或是傳遞至著色器的參數,否則編譯器會忽略語意。
-
Packoffset
-
手動封裝著色器常數的選擇性關鍵字。 請參閱 packoffset (DirectX HLSL) 。
-
註冊
-
手動將著色器變數指派給特定暫存器的選擇性關鍵字。 請參閱 註冊 (DirectX HLSL) 。
-
注釋 (s)
-
附加至全域變數之字串形式的選擇性中繼資料。 效果架構會使用注釋,並由 HLSL 忽略;若要查看更詳細的語法,請參閱 注釋語法。
-
Initial_Value
-
選擇性的初始值 (s) ;值數目應該符合 Type中的元件數目。 每個標示 extern 的全域變數都必須以常值初始化;標示 為靜態 的每個變數都必須以常數初始化。
未標示 為靜態 或 extern 的全域變數不會編譯為著色器。 編譯器不會自動設定全域變數的預設值,也無法在優化中使用它們。 若要初始化這種類型的全域變數,請使用反映來取得其值,然後將值複製到常數緩衝區。 例如,您可以使用ID3D11ShaderReflection::GetVariableByName方法來取得變數、使用ID3D11ShaderReflectionVariable::GetDesc方法來取得著色器變數描述,並從D3D11_SHADER_VARIABLE_DESC結構的DefaultValue成員取得初始值。 若要將值複製到常數緩衝區,您必須確定緩衝區是以 CPU 寫入存取權建立, (D3D11_CPU_ACCESS_WRITE) 。 如需如何建立常數緩衝區的詳細資訊,請參閱 如何:建立常數緩衝區。
您也可以使用 效果架構 自動處理反映和設定初始值。 例如,您可以使用 ID3DX11EffectPass::Apply 方法。
範例
以下是著色器變數宣告的數個範例。
float fVar;
float4 color;
float fVar = 3.1f;
int iVar[3];
int iVar[3] = {1,2,3};
uniform float4 position : SV_POSITION;
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 範例。
相關主題
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應