Udostępnij za pośrednictwem


Składnia zmiennej

Użyj następujących reguł składni, aby zadeklarować zmienne HLSL.

[Storage_Class] [Type_Modifier] nazwa typu [indeksu] [: semantyczna] [: Packoffset] [: Register]; [Adnotacje] [= Initial_Value]

Parametry

Storage_Class

Opcjonalne modyfikatory klasy magazynu, które dają kompilatorowi wskazówki dotyczące zakresu zmiennej i okresu istnienia; modyfikatory można określić w dowolnej kolejności.

Wartość Opis
extern Oznaczanie zmiennej globalnej jako danych wejściowych zewnętrznych do cieniowania; jest to domyślne oznaczenie dla wszystkich zmiennych globalnych. Nie można połączyć z statycznym.
nointerpolation Nie interpoluj danych wyjściowych cieniowania wierzchołków przed przekazaniem ich do cieniowania pikseli.
precyzyjne precyzyjne słowo kluczowe stosowane do zmiennej ograniczy wszystkie obliczenia używane do tworzenia wartości przypisanej do tej zmiennej w następujący sposób:
  • Oddzielne operacje są przechowywane oddzielnie. Na przykład w przypadku, gdy operacja mul i add mogła zostać połączona w szalonej operacji, precyzyjne wymusza, aby operacje pozostały oddzielone. Zamiast tego należy jawnie użyć szalonej funkcji wewnętrznej.
  • Kolejność operacji jest utrzymywana. Jeśli kolejność instrukcji mogła zostać przetasowana w celu zwiększenia wydajności, precyzyjne gwarantuje, że kompilator zachowuje kolejność zgodnie z zapisem.
  • Niebezpieczne operacje IEEE są ograniczone. Gdzie kompilator mógł używać szybkich operacji matematycznych, które nie uwzględniają wartości NaN (a nie liczby) i INF (nieskończone), dokładne wymusza wymagania IEEE dotyczące wartości NaN i INF do przestrzegania. Bez precyzyjnegote optymalizacje i operacje matematyczne nie są bezpieczne IEEE.
  • Kwalifikowanie zmiennej precyzyjnych nie sprawia, że operacje korzystające ze zmiennej precyzyjne. Ponieważ precyzyjne propaguje tylko operacje, które przyczyniają się do wartości przypisanych do precyzyjnej-kwalifikowanej zmiennej, poprawnie wykonując żądane obliczenia precyzyjne mogą być trudne, dlatego zalecamy oznaczenie danych wyjściowych cieniowania precyzyjnych bezpośrednio, gdzie są deklarowane, czy znajdują się one w polu struktury, lub na parametrze wyjściowym lub zwracanym typie funkcji entry. Możliwość kontrolowania optymalizacji w ten sposób utrzymuje wariancję wyniku zmodyfikowanej zmiennej wyjściowej przez wyłączenie optymalizacji, które mogą mieć wpływ na końcowe wyniki z powodu różnic w skumulowanych różnicach precyzji. Jest to przydatne, gdy chcesz cieniować do tessellacji, aby zachować napięte szwy plam w wodzie lub dopasować wartości głębokości na wielu przejściach. przykładowy kod:
    g_mWorldViewProjection HLSLmatrix;
    void main(in float3 InPos : Position, out precise float4 OutPos : SV_Position)
    {
    operacja jest dokładna, ponieważ przyczynia się do dokładnego parametru OutPos
    OutPos = mul( float4( InPos, 1.0 ), g_mWorldViewProjection );
    }
udostępnione Oznacz zmienną do udostępniania między efektami; jest to wskazówka dla kompilatora.
grupydostępne Oznacz zmienną dla pamięci współużytkowanej grupy wątków dla cieniowania zasobów obliczeniowych. W D3D10 maksymalny całkowity rozmiar wszystkich zmiennych z grupową klasą magazynu udostępnionego wynosi 16 kb, w D3D11 maksymalny rozmiar wynosi 32 kb. Zobacz przykłady.
statyczne Oznacz zmienną lokalną tak, aby była inicjowana jednorazowo i utrwalana między wywołaniami funkcji. Jeśli deklaracja nie zawiera inicjatora, wartość jest ustawiona na zero. Zmienna globalna oznaczona statycznym nie jest widoczna dla aplikacji.
jednolite Oznacz zmienną, której dane są stałe podczas wykonywania cieniowania (na przykład kolor materiału w cieniatorze wierzchołka); zmienne globalne są domyślnie uznawane za jednolite.
volatile Oznacz zmienną, która często się zmienia; jest to wskazówka dla kompilatora. Ten modyfikator klasy magazynu dotyczy tylko zmiennej lokalnej.
Uwaga: kompilator HLSL obecnie ignoruje ten modyfikator klasy magazynu.

Type_Modifier

Opcjonalny modyfikator typu zmiennej.

Wartość Opis
const Oznacz zmienną, której nie można zmienić za pomocą cieniowania, dlatego należy ją zainicjować w deklaracji zmiennej. Zmienne globalne są domyślnie uznawane za const (pomijanie tego zachowania przez podanie flagi /Gec do kompilatora).
row_major Oznacz zmienną, która przechowuje cztery składniki w jednym wierszu, aby można je było przechowywać w jednym rejestrze stałym.
column_major Oznacz zmienną, która przechowuje 4 składniki w jednej kolumnie, aby zoptymalizować matematykę macierzy.

Nuta

Jeśli nie określisz wartości modyfikatora typu, kompilator używa column_major jako wartości domyślnej.

typ

Dowolny typ HLSL wymieniony w Typy danych (DirectX HLSL).

Nazwa[Index]

Ciąg ASCII, który jednoznacznie identyfikuje zmienną cieniowania. Aby zdefiniować opcjonalną tablicę, użyj indeksu dla rozmiaru tablicy, który jest dodatnią liczbą całkowitą = 1.

semantyczna

Opcjonalne informacje o użyciu parametrów używane przez kompilator do łączenia danych wejściowych i wyjściowych modułu cieniowania. Istnieje kilka wstępnie zdefiniowanych semantyki dla cieniowania wierzchołków i pikseli. Kompilator ignoruje semantykę, chyba że są zadeklarowane w zmiennej globalnej lub parametr przekazany do cieniowania.

Packoffset

Opcjonalne słowo kluczowe do ręcznego pakowania stałych cieniowania. Zobacz packoffset (DirectX HLSL).

rejestrowanie

Opcjonalne słowo kluczowe służące do ręcznego przypisywania zmiennej cieniowania do określonego rejestru. Zobacz register (DirectX HLSL).

adnotacji

Opcjonalne metadane w postaci ciągu dołączone do zmiennej globalnej. Adnotacja jest używana przez strukturę efektu i ignorowana przez HLSL; aby wyświetlić bardziej szczegółową składnię, zobacz składni adnotacji.

Initial_Value

Opcjonalne wartości początkowe; liczba wartości powinna być zgodna z liczbą składników w typie . Każda zmienna globalna oznaczona extern musi zostać zainicjowana z wartością literału; każda zmienna oznaczona statyczna musi zostać zainicjowana przy użyciu stałej.

Zmienne globalne, które nie są oznaczone statycznych lub extern nie są kompilowane w cieniowaniu. Kompilator nie ustawia automatycznie wartości domyślnych dla zmiennych globalnych i nie może ich używać w optymalizacji. Aby zainicjować ten typ zmiennej globalnej, użyj odbicia, aby pobrać jego wartość, a następnie skopiować wartość do buforu stałego. Na przykład można użyć metody ID3D11ShaderReflection::GetVariableByName, aby pobrać zmienną, użyj metody ID3D11ShaderReflectionVariable::GetDesc, aby uzyskać opis zmiennej cieniowania i uzyskać wartość początkową z DefaultValue składowej struktury D3D11_SHADER_VARIABLE_DESC. Aby skopiować wartość do buforu stałego, należy upewnić się, że bufor został utworzony z dostępem do zapisu procesora CPU (D3D11_CPU_ACCESS_WRITE). Aby uzyskać więcej informacji na temat tworzenia buforu stałego, zobacz How to: Create a Constant Buffer.

Możesz również użyć struktury efektów, aby automatycznie przetworzyć odbicie i ustawić wartość początkową. Można na przykład użyć metody ID3DX11EffectPass::Apply.

Ważny

Obsługa tej funkcji została usunięta w wersji Direct3D 12, w tym możliwość odzwierciedlenia domyślnych inicjatorów.

Przykłady

Oto kilka przykładów deklaracji zmiennych cieniowania.

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};

Udostępnione grupy

Biblioteka HLSL umożliwia wątkom cieniowania obliczeniowego wymianę wartości za pośrednictwem pamięci udostępnionej. Biblioteka HLSL udostępnia typy pierwotne barier, takie jak GroupMemoryBarrierWithGroupSync, i tak dalej, aby zapewnić poprawną kolejność odczytów i zapisów w pamięci udostępnionej w cieniowaniu oraz aby uniknąć wyścigów danych.

Nuta

Sprzęt wykonuje wątki w grupach (warps lub fronty falowe), a synchronizacja barier może czasami zostać pominięta, aby zwiększyć wydajność, gdy tylko synchronizowanie wątków należących do tej samej grupy jest poprawne. Jednak zdecydowanie odradzamy to pominięcie z następujących powodów:

  • To pominięcie powoduje, że kod nie jest przenośny, który może nie działać na niektórych sprzętach i nie działa na rasteryzatorach oprogramowania, które zwykle wykonują wątki w mniejszych grupach.
  • Ulepszenia wydajności, które można osiągnąć w przypadku tego pominięcia, będą niewielkie w porównaniu z użyciem bariery we wszystkich wątkach.

W wersji Direct3D 10 nie ma synchronizacji wątków podczas zapisywania w grupowych, co oznacza, że każdy wątek jest ograniczony do pojedynczej lokalizacji w tablicy do zapisu. Użyj wartości systemu SV_GroupIndex, aby zaindeksować do tej tablicy podczas zapisywania, aby upewnić się, że żadne dwa wątki nie mogą się zderzyć. Jeśli chodzi o odczytywanie, wszystkie wątki mają dostęp do całej tablicy do odczytu.

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();
    ...
}

Pakowania

Pakuj podskładniki wektorów i skalarów, których rozmiar jest wystarczająco duży, aby zapobiec przekraczaniu granic rejestru. Na przykład wszystkie te elementy są prawidłowe:

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

Nie można mieszać typów pakowania.

Podobnie jak słowo kluczowe register, element packoffset może być specyficzny dla elementu docelowego. Pakowanie podskładowe jest dostępne tylko w przypadku słowa kluczowego packoffset, a nie słowa kluczowego register. Wewnątrz deklaracji cbuffer słowo kluczowe register jest ignorowane dla obiektów docelowych Direct3D 10, ponieważ zakłada się, że jest zgodne z wieloma platformami.

Spakowane elementy mogą się nakładać, a kompilator nie wyświetli żadnego błędu ani ostrzeżenia. W tym przykładzie elementy Element2 i Element3 nakładają się na elementy Element1.x i Element1.y.

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

Przykład, który korzysta z pakietu packoffset, to: HLSLWithoutFX10 Sample.