High Level Shader Language
High Level Shader Language (zkráceně HLSL) je vyšší programovací jazyk pro psaní shaderů vyvinutý společností Microsoft s podporou DirectX (verze 8 a vyšší) XNA, Xbox a Xbox 360. HLSL je velmi podobný jazyku Cg od společnosti NVIDIA, přičemž syntaxe obou jazyků vychází z jazyka C.
Popis
editovatJazyk vznikl v rámci procesu postupné transformace fixního vykreslovacího řetězce na řetězec programovatelný a stal se jednou z vyspělejších alternativ k tehdy používaným nižším programovacím jazykům pro psaní shaderů.
Shader Model
editovatV rámci vývoje grafických karet a vykreslovacího řetězce se postupně měnily i vlastnosti a schopnosti jednotlivých shaderů. Aby bylo možné rozlišit jaké technologie z hlediska shaderů konkrétní hardware či software podporuje, jsou potupně zaváděny tzv. verze Shader Modelu (samostatně pro vertex shader i pixel shader). Bohužel tento údaj je zcela porovnatelný pouze v rámci produktů jedné společnosti, protože neexistuje žádná pevná specifikace, která by jasně definovala požadavky pro jednotlivé verze Shader modelů. Vývoj shaderů je řízen výrobci GPU — společnostmi nVidia a ATI (nyní AMD) — a společností Microsoft, která vyvíjí grafické rozhraní Direct3D. Společnost Microsoft uveřejnila svou vlastní specifikaci pro Shader model[1].
Shader Model 1.0
editovatFixní vykreslovací řetězec omezoval realizaci vlastního formátu pro uložení vrcholu. Toto omezení odstranilo zavedení Vertex Shaderu 1.0 a 1.1.
Jeho instrukční sada je velice omezená. Většina instrukcí, které známe z běžných procesorů zde schází. Naopak jsou zde speciální instrukce, které se hodí pro výpočet osvětlení apod. Délka programu vertex shaderu je zde omezena podle použité grafické karty nejčastěji na 128 instrukcí.
Struktura Pixel Shaderu verzí 1.1 až 1.3, se od sebe příliš neliší. Instrukční sada této verze se spíše podobá CISC procesoru, tzn. že obsahuje poměrně velké množství specializovaných instrukcí převážně na nabírání texelu z textury. Podívejme se na schematický obrázek shaderu:
Další verze Pixel Shader 1.4 už přinesla změny převážně v instrukční sadě a způsobu výběru texelu. Přesto je tato verze plně zpětně kompatibilní se starší řadou. Přibyly dva texturové a tři odkládací registry.
Shader Model 2.0
editovatVe vertex shaderu verze 2.0 se objevilo hned několik vylepšení. Bylo přidáno několik nových aritmetických instrukcí a délka programu byla prodloužena na 256 instrukcí. Umožňuje skoky, podmíněné příkazy nebo smyčky, takže program ve vertex shaderu se může libovolně větvit.
Kromě několika nových texturových instrukcí, Pixel Shader 2.0 přináší aritmetické instrukce podobné těm ve vertex shaderu. Maximální délka programu byla zvětšena na 32 texturovacích a 64 aritmetických instrukcí. Byly přidány instrukce pro vektorové výpočty (normalizace vektoru, násobení maticí, vektorový součin).
Shader Model 3.0
editovatVertex Shader 3.0 přinesla prodloužení programu na 512 instrukcí. Specifikace jednotky vertex shaderu byla rozšířena o čtení dat z textury. Počet pracovních registrů byl zvýšen na 32 a ke statickému řízení toku programu přibylo dynamické.
Jednotka Pixel Shaderu 3.0 se v programátorském modelu velice přiblížila jednotce vertex shaderu. Maximální počet instrukcí byl navýšen na 512, počet pracovních registrů vzrostl na 32 a počet registrů konstant na 224. Pixel shader verze 3.0 umí statické i dynamické řízení toku programu.
Shader Model 4.0
editovatVe čtvrté verzi Shader Modelu nabízejí všechny shadery stejný základní programátorský model. Každý ze tří shaderů (vertex, geometry, pixel) pak přidává funkčnost, která je specifická pro danou fázi grafického řetězce. Délka programu shaderu není omezena.
HLSL profily překladu
editovatProfilem překladu lze specifikovat cílovou verzi vertex/pixel shaderu. Dostupné profily shrnuje následující tabulka:
Profil | Verze DirectX | Specifikace |
---|---|---|
vs_1_1 | 8.0 | Vertex Shader verze 1.1 |
vs_2_0 | 9.0 | Vertex Shader verze 2.0 |
vs_2_x | 9.0a, 9.0b | rozšířený Vertex shader verze 2.0 |
vs_2_a | 9.0a | optimalizováno pro model shaderu na NVIDIA GeForce FX |
vs_3_0 | 9.0c | Vertex shader verze 3.0 |
vs_4_0 | 10.0 | Vertex shader verze 4.0 |
vs_4_1 | 10.1 | Vertex shader verze 4.1 |
vs_5_0 | 11.0 | Vertex shader verze 5.0 |
ps_1_1 | 8.0 | Pixel Shader verze 1.1 |
ps_1_2 | 8.1 | Pixel Shader verze 1.2 |
ps_1_3 | 8.1 | Pixel Shader verze 1.3 |
ps_1_4 | 8.1 | Pixel Shader verze 1.4 |
ps_2_0 | 9.0 | Pixel Shader verze 2.0 |
ps_2_0a | 9.0a | optimalizováno pro model shaderu na NVIDIA GeForce FX |
ps_2_0b | 9.0b | optimalizováno pro model shaderu na ATI Radeon X700, X800, X850 |
ps_2_x | 9.0 | rozšířený Pixel Shader verze 1.1 |
ps_3_0 | 9.0c | Pixel Shader verze 3.0 |
ps_4_0 | 10.0 | Pixel Shader verze 4.0 |
ps_4_1 | 10.0 | Pixel Shader verze 4.1 |
ps_5_0 | 10.0 | Pixel Shader verze 5.0 |
Operátory
editovatHLSL poskytuje operátory známé z jazyka C, navíc je k dispozici speciální operátor swizzle[2].
Kvalifikátory
editovatvarying
— proměnný datový typ. Hodnota se mění každým vykonání shaderu (typicky pozice, normála aj.)uniform
— globální proměnné v shaderu, které jsou inicializovány externě aplikací nebo běhovým prostředím. Hodnota zůstává konstantní pro každé vykonání shaderu. (typicky barva materiálu, transformační matice)const
— proměnnou nelze v rámci shaderu změnitstatic
— lokální proměnná, jejichž hodnota po skončení průběhu funkce zůstává zachována.
Datové typy
editovatSkalární typy
editovatbool
— pravdivostní datový typ (true/false)int
— 32bit, celé číslo se znaménkemuint
— 32bit, celé číslo bez znaménkahalf
— 16bit, číslo s plovoucí desetinnou čárkoufloat
— 32bit, číslo s plovoucí desetinnou čárkoudouble
— 64bit, číslo s plovoucí desetinnou čárkou
Vektorové typy
editovatVektor je homogenní datový typ. HLSL podporuje až čtyř složkové vektory. Vektorový typ můžete definovat dvěma ekvivalentními způsoby. V následující ukázce je definován třísložkový vektor, kde každá složka je datového typu float:
float3 prikladVektor;
vector <float, 3> prikladVektor;
Vektor můžeme při deklaraci přímo inicializovat:
float3 fVector = { 0.2f, 0.3f, 0.4f };
vector <float, 3> fVector = { 0.2f, 0.3f, 0.4f };
K jednotlivým složkám vektoru smíme přistupovat pomocí definovaných složek x, y, z, w nebo r, g, b, a. Oba způsoby jsou ekvivalentní, ovšem nesmějí se vzájemně kombinovat.
float4 vektor;
vektor.x = 9; /* správně */
vektor.yz = 0; /* správně */
vektor.a = 5; /* správně */
vektor.rg = 0; /* správně */
vektor.ay = 0; /* nelze */
Matice
editovatPostup při deklaraci i inicializaci matice je podobný jako u vektoru. Obecný formát deklarace matice je následující:
datový_typ počet_řádkůxpočet_sloupců identifikátor
Ukázka deklarace matice 4x4 typu float:
float4x4 prikladMatice;
vector <float, 3> prikladVektor;
Inicializace matice:
float2x2 fMatrix = { 0.0f, 0.1, 2.1f, 2.2f };
Přistoupit k jednotlivým složkám matice můžeme dvěma způsoby:
- číslování od nuly
_m00, _m01, _m02, _m03
_m10, _m11, _m12, _m13
_m20, _m21, _m22, _m23
_m30, _m31, _m32, _m33
- číslování od jedničky
_11, _12, _13, _14
_21, _22, _23, _24
_31, _32, _33, _34
_41, _42, _43, _44
V obou případech první číslo značí číslo řádku a druhé číslo sloupce.
Příklad[2]
float4x4 matice;
matice._11 = 1;
matice._m00_m11_m22_m33 = 1;
float2x2 fMatrix = { 1.0f, 1.1f, // row 1
2.0f, 2.1f }; // row 2
float temp;
temp = fMatrix[0][0]; // cteni slozky 0, 0
temp = fMatrix[0][1]; // cteni slozky 0, 1
float2 temp2;
temp2 = fMatrix[0];
Sampler, Texture a Shader Type
editovat- Sampler — handler na texturový objekt
- Texture — strukturovaná kolekce dat pro ukládání texelů. Texel je nejmenší možnou jednotkou textury, z které lze číst nebo do ní zapisovat (lze asociovat s pixelem). Každý texel obsahuje tři nebo čtyři složky uspořádané podle daného formátu. Na rozdíl od bufferu lze texturu filtrovat pomocí sampleru čtením shaderovací jednotkou. Typ textury určuje jak bude textura filtrována. Textury mohou být: Texture1D, Texture1DArray, Texture2D, Texture2DArray, Texture3D, TextureCube[2]
- Shader Type — objekt realizující shader
Buffer
editovatGenerické datové úložiště. Data v bufferu jsou přístupná jako pole prvků. Ukázka:
Buffer<float4> g_Buffer;
Vstupní a výstupní proměnné
editovatParametry procházející skrz grafický vykreslovací řetězec je třeba označit jako vstup nebo výstup.
Syntaxe pro označení identifikátoru: Shader má definovány množiny vstupních a výstupních sémantických atributů (POSITION, BLENDWEIGHT, BLENDINDICES, NORMAL, PSIZE, TEXCOORD, TANGENT, BINORMAL, TESSFACTOR, POSITIONT, COLOR, FOG, DEPTH, SAMPLE). Pro vstupní proměnné se kterými programátor chce dále pracovat je třeba vytvořit speciální strukturu. Identifikátory jednotlivých složek této struktury jsou odděleny symbolem : od sémantického atributu. Obdobně se postupuje i při výběru parametrů, které chceme předat na výstup vertex shaderu.
struct VertexShaderInput
{
float4 vPosition : POSITION;
float3 vNormal : NORMAL;
float4 vBlendWeights : BLENDWEIGHT;
};
struct VertexShaderOutput
{
float4 vPosition : POSITION;
float4 vDiffuse : COLOR;
};
Ve výše uvedené ukázce je atribut vPosition je označen jako POSITION, což znamená že ve výsledném programu bude proměnná namapována na výstupní registr.
Řídící struktury a funkce
editovatHLSL nabízí klasické řídící struktury jejichž konstrukce je stejná jako v jazyce C, navíc jsou rozšířeny o tzv. atributy[2]. Jazyk podporuje tvorbu uživatelských funkcí a současně disponuje souborem funkcí vestavěných, které jsou zaměřeny zejména na grafické operace. Tyto funkce dělíme na matematické funkce a specializované funkce pracující s texturami.
if else
editovatPříkaz if slouží k větvení programu. Vyhodnocením podmínkového výrazu rozhodne zdali se daný blok příkazů provede (podmínka je pravdivá) nebo ne (podmínka je nepravdivá). K příkazu if lze přidat příkaz else. Příkaz else určuje blok příkazů, které se provedou pouze pokud je podmínka nepravdivá. Formát konstrukce if, else je následující:
[Atribut] if ( výraz )
{
blok příkazů 1;
}
else
{
blok příkazů 2;
}
Zadání položky Atribut je volitelné a určuje způsob kompilace příkazu if. Může nabývat hodnot (flatten, branch):
Příklad
[branch] if(x)
{
x = sqrt(x);
}
switch
editovatPříkaz switch slouží k výběru jedné z několika větví programu, která se má provést v závislosti na nějaké celočíselné hodnotě. Jeho formát je následující:
[Atribut] switch( celočíselný výraz)
{
case hodnota1 :
{ blok příkazů; }
break;
case hodnota2 :
{ blok příkazů;}
break;
...
case hodnotaN :
{ blok příkazů; }
break;
default :
{ blok příkazů; }
break;
}
Zadání položky Atribut je volitelné a určuje způsob kompilace příkazu switch. Může nabývat těchto hodnot (flatten, branch, forcecase, call).
Příklad
[branch] switch( a )
{
case 0:
return 0;
case 1:
return 1;
case 2:
return 3;
default:
return 6;
}
for
editovatPříkaz cyklu for umožňuje opakovat jeden, nebo více příkazů. Konstrukce cyklu for:
[Atribut] for ( inicializace; test podmínky; inkrementace )
{
blok příkazů;
}
Zadání položky Atribut je volitelné a určuje způsob kompilace příkazu for. Může nabývat těchto hodnot (unroll, loop, fastopt, allow_uav_condition).
Příklad
float value = 0;
[loop]
for (uint i = 0; i < 4; i++)
{
value++;
}
while
editovatCyklus while je cyklus s podmínkou na začátku. Napřed se testuje podmínka, je-li platná, pak se provede tělo cyklu a znovu se testuje podmínka. Není-li platná, program pokračuje za cyklem. Není-li tedy podmínka platná při prvním příchodu na cyklus, neprovede se cyklus ani jednou. Jeho formát vypadá takto:
[Atribut] while ( test podmínky )
{
blok příkazů;
}
Zadání položky Atribut je volitelné a určuje způsob kompilace příkazu for. Může nabývat těchto hodnot (unroll, loop, fastopt).
Jazyk HLSL umožňuje použít i do while
variantu cyklu.
break, continue
editovatPříkazy pro řízení cyklu.
Příkaz discard
editovatPříkaz discard ruší zpracování fragmentu nebo vrcholu. Alternativou k tomuto příkazu je funkce clip()
.
Seznam aritmetických funkcí
editovatacos, asin, atan, ceil, cos, cosh, degrees, dot, lerp, log, log10, mul, pow, radians, rsqrt, sin, sincos, sinh, step, sqrt, tan, tanh
.
Seznam geometrických funkcí
editovatdistance, length, normalize, reflect, refract
Seznam funkcí pro diferenciální výpočty
editovatddx, ddy
Funkce pro práci s texturami
editovatPrvním argumentem při zavolání texturovací funkce je vždy objekt typu sampler. Použitá funkce musí vždy souhlasit s dimenzí textury.
Seznam funkcí pro práci s texturami:
Funkce | Popis |
---|---|
tex1D , tex2D , tex3D , texCUBE
|
Vzorkuje texturu. |
tex1Dbias , tex2Dbias , tex3Dbias , texCUBEbias
|
Vzorkuje texturu s mipmap biasem. Můžeme tak ovlivnit, které úrovně mipmapy se budou vzorkovat. Jako bias se použije 4. souřadnice (a nebo w). |
tex1Dproj , tex2Dproj , tex3Dproj , texCUBEproj
|
Texturové souřadnice se před vzorkováním vydělí 4. složkou (a nebo w) tj. provede se projekce souřadnic. |
Jednotlivé texturovací funkce mohou mít více přetížených alternativ.
Direktivy preprocesoru
editovatPro řízení předzpracování zdrojového kódu, je k dispozici sada preprocesorových direktiv známých z jazyka C.
Komentáře
editovatStejné jako v jazycích C, C++
/* krátká verze */
// celořádková verze
Proces překladu
editovatProgramy napsané v HLSL musejí být nejprve přeloženy do byte kódu překladačem, který je součástí knihovny D3DX (součást DirectX Graphics). Výsledný byte kód je binární reprezentací jazyka podobného jazyku symbolických instrukcí. Takto přeložený program už může být použit jako vstup pro metodu rozhraní Direct3D, která se postará o vytvoření strojové verze shaderu.
HLSL kód[3]:
float4 main(float4 t: TEXCOORD0) : SV__target
{
if (t.x > t.y)
return t.xyzw;
else
return t.wzyx;
}
Odpovídající DX9 kód[3]:
add r0.x, -v0.x, v0.y
cmp oC0, r0.x, v0.wzyx, v0
Odpovídající DX10 kód (sémantika původního kódu zůstává více zachována)[3]:
float4 main(float4 t: TEXCOORD0) : SV__target
{
lt r0.x, v0.y, v0.x
if_nz r0.x // <--- POZOR! Opravdu bylo záměrem vytvořit větvení?
mov o0.xyzw, v0.xyzw
ret
else
mov o0.xyzw, v0.wzyx
ret
endif
}
Pro ukládání shaderovacích programů do souboru byl zaveden nový formát s příponou FX.
Ukázka vertex shaderu
editovatUkázka vertex shaderu pro Direct3D 9[4].
vector vClr;
struct VS_INPUT
{
float4 vPosition : POSITION;
float3 vNormal : NORMAL;
float4 vBlendWeights : BLENDWEIGHT;
};
struct VS_OUTPUT
{
float4 vPosition : POSITION;
float4 vDiffuse : COLOR;
};
float4x4 mWld1;
float4x4 mWld2;
float4x4 mWld3;
float4x4 mWld4;
float Len;
float4 vLight;
float4x4 mTot;
VS_OUTPUT VS_Skinning_Example(const VS_INPUT v, uniform float len=100)
{
VS_OUTPUT out;
// Pozice
float3 vPosition =
mul(v.vPosition, (float4x3) mWld1) * v.vBlendWeights.x +
mul(v.vPosition, (float4x3) mWld2) * v.vBlendWeights.y +
mul(v.vPosition, (float4x3) mWld3) * v.vBlendWeights.z +
mul(v.vPosition, (float4x3) mWld4) * v.vBlendWeights.w;
// Normála
float3 vNormal =
mul(v.vNormal, (float3x3) mWld1) * v.vBlendWeights.x +
mul(v.vNormal, (float3x3) mWld2) * v.vBlendWeights.y +
mul(v.vNormal, (float3x3) mWld3) * v.vBlendWeights.z +
mul(v.vNormal, (float3x3) mWld4) * v.vBlendWeights.w;
// Výstup
out.vPosition = mul(float4(vPosition + vNormal * Len, 1), mTot);
out.vDiffuse = dot(vLight,vNormal);
return out;
}
Ukázka geometry shaderu
editovatUkázka vertex shaderu pro Direct3D 10[5].
void GSScene(triangleadj GSSceneIn input[6], inout TriangleStream<PSSceneIn> OutputStream)
{
PSSceneIn output = (PSSceneIn)0;
for (uint i=0; i<6; i+=2)
{
output.Pos = input[i].Pos;
output.Norm = input[i].Norm;
output.Tex = input[i].Tex;
OutputStream.Append(output);
}
OutputStream.RestartStrip();
}
Ukázka pixel shaderu
editovatUkázka jednoduchého pixel shaderu[6].
float4 PS(float vPos : VPOS, float2 tex : TEXCOORD0) : COLOR
{
...
return float4(1.0f, 0.3f, 0.7f, 1.0f);
}
Odkazy
editovatReference
editovat- ↑ Shader Models vs Shader Profiles (anglicky)
- ↑ a b c d Language Syntax (DirectX HLSL) (anglicky)
- ↑ a b c Advanced D3D10 Rendering (anglicky)
- ↑ Writing HLSL Shaders in Direct3D 9 (anglicky)
- ↑ Getting Started with the Stream-Output Stage (Direct3D 10)
- ↑ XNA Meeting Point — Ambient light Archivováno 17. 1. 2012 na Wayback Machine. (anglicky)
Související články
editovat- Ostatní jazyky pro psaní shaderů
- OpenGL Shading Language (GLSL) — Vyšší programovací jazyk určený primárně pro použití s OpenGL
- Cg programming language — Jazyk vyvinutý společností NVIDIA
Externí odkazy
editovat- Programming Guide for HLSL, from Microsoft (anglicky)
- Introduction to the DirectX 9 High Level Shading Language, (ATI) AMD developer central (anglicky)
- Riemer's HLSL Introduction & Tutorial (includes sample code) Archivováno 19. 11. 2008 na Wayback Machine. (anglicky)
- Simple HLSL Shader Tutorial (anglicky)
- HLSL Introduction (anglicky)
- Hardware pro počítačovou grafiku
- Kurz DirectX Archivováno 2. 3. 2012 na Wayback Machine.