A Cg programozási nyelv

Típusok, típuskonstrukciók



Kötési szemantikák (binding sematics)

A shader programok minden esetben adatokat dolgoznak fel, amit a szerelőszalag előző lépésétől kapnak, és a következő lépésének adnak tovább.

Ezek a legtöbb esetben nem egyetlen változónyi adatok, ezért a programok fogadhatják több paraméterként, vagy egy struktúrában. Például :

struct input { float4 foo; float4 bar; float4 foobar; };

Ha ebben a példában ez egy pixel shader bemenete lenne, a fordító nem tudná megállapítani, hogy a program milyen adatokat vár a GPU-tól.

Hogy ne kelljen minden lehetséges adatot feltüntetni, a kötési szemantikákkal megadható, hogy melyik változóba, pontosan milyen értéket vár, vagy ad vissza a program:

struct output { float4 foo : POSITION; float4 bar : COLOR0; float4 foobar : TEXCOORD0; }; output myfunc(float4 pos : POSITION) {/*...*/}

A kötési szemantikák nem csak struktúrák, hanem függvény paraméterek esetén is használhatók.

Egy szemantika többször is szerepelhet bemenő paraméterek esetén, de azok külön-külön, érték szerint kerülnek átadásra.

output myfunc(float4 pos1 : POSITION, float4 pos2 : POSITION) { // pos1 == pos2 pos1.x = 0; // pos1 != pos2 }

A használható kötési szemantikákat a profilok szabályozzák.

Típusok

A Cg szabvány a következő típusokat specifikálja:

int 32 bites egész, vagy float
float az IEEE egyszeres pontosságú lebegőpontos ábrázoláshoz lehető legközelebbi
double >= float >= half lebegőpontos típusok
fixed legalább [-2,2) intervallumot tartalmazó, legalább 10 bites fixpontos számok, de lehet half vagy float. Túl-/alulcsordulás esetén a típus maximum/minimum értéket veszi fel.
bool igaz/hamis értékek típusa
cint, cfloat fordítási idejű, 32 bites egész és lebegőpontos
void
sampler* textúrákhoz való hozzáférést biztosító kezelők, csak formális paraméterek lehetnek, csak olvashatóak. Fajtái: sampler, sampler1D, sampler2D, sampler3D, samplerCUBE, samplerRECT

void típus

Mivel a nyelv nem támogatja a mutatók használatát, ezért nincs olyan eset amikor a void tényleges típusként szerepelhet. Nem megengedett void típusú változók létrehozása, vagy void típusú paraméterek használata.

A void kulcsszó csak függvénydeklarációkban használható, a függvény visszatérési értéke ként, vagy az üres paraméter lista jelzésére.

bool típus

A ?:, ||, &&, ! műveletek értelmezve vannak bool tömbökre is, ilyenkor az adott művelet szimultán végrehajtódik a tömb minden elemére.

sampler* típusok

A sampler* típusokon keresztül a GPU memória egyes területei olvashatók. Nem hozható létre sampler* típusú változó függvényben, csak globális változóként, amit a CPU-n futó program állít be, vagy függvény formális paraméterei között szerepelhet sampler* típusú paraméter.

Egy sampler* által "mutatott" memóriaterület címezhető egy, két vagy három paraméterrel, a sampler* tényleges fajtájától függően. Az értékek beolvasása a tex* függvények segítségével történik.

Egy egyszerű sampler* használatra példa az alábbi fragment-program:

sampler2D smp; float4 g(float2 uv : TEXCOORD0, float4 col : COLOR) : COLOR { return tex2D(smp, uv)*0.25+col*0.75; }

Tömbök

A C nyelv tömbjeihez hasonlóan deklarálhatók és használhatók, azzal a különbséggel, hogy az értékadás minden esetben az egész tömböt másolja.

A programozási nyelvekben megszokottakkal ellentétben a Cg nem minden tömb típusa tekinthető összetett típusnak. A célhardver alapegysége a lebegőpontos szám-négyes. A fordító minden Cg változót ilyen négyeseken reprezentál.

Tömbök deklarálhatók packed kulcsszóval. Ilyenkor a fordító feladata, hogy ezt a lehető leghatékonyabba tárolja. Ez az optimalizálás, és hogy milyen tömbökre használható a kulcsszó implementáció-függő, de legalább négyelemű vektorok és 4x4-es mátrixok támogatva kell legyenek. Mivel négy float érték elhelyezhető a GPU egyetlen regiszterében, így nagyon hatékony kód generálható.

Például:

packed float[4] x, y, z; z = x+y; // egyetlen művelet!

A numerikus változókból készített packed [1..4] elemű vektorok, és [1..4]x[1..4]-es mátrixok típusai előre definiálva vannak a nyelvben, azaz alapértelmezettek a következők:

typedef packed TYPE TYPE1[1]; typedef packed TYPE TYPE2[2]; typedef packed TYPE TYPE3[3]; typedef packed TYPE TYPE4[4];
packed TYPE1 TYPE1x1[1]; packed TYPE1 TYPE3x1[3]; packed TYPE2 TYPE1x2[1]; packed TYPE2 TYPE3x2[3]; packed TYPE3 TYPE1x3[1]; packed TYPE3 TYPE3x3[3]; packed TYPE4 TYPE1x4[1]; packed TYPE4 TYPE3x4[3]; packed TYPE1 TYPE2x1[2]; packed TYPE1 TYPE4x1[4]; packed TYPE2 TYPE2x2[2]; packed TYPE2 TYPE4x2[4]; packed TYPE3 TYPE2x3[2]; packed TYPE3 TYPE4x3[4]; packed TYPE3 TYPE2x4[2]; packed TYPE3 TYPE4x4[4];

Ahol a TYPE az int, fixed, double, float, half típusok mindegyikére szerepel.

Ezekhez a típusokhoz beépített konstruktorok léteznek, minden kombinációra:

float2(scalar, scalar) float4(float3, scalar) float3x3(1,2,3,4,5,6,7,8,9) float3x3(float3,float3,float3) float3x3(1,float2,float3,float3,1,1,1)

A tömbök indexelhetők a C-ben megszokott módon felül az alábbiakon:

Vektorok elemei indexelhetők .xyzw és .rgba alakban, mátrixok elemei pedig ._m<row><col>[_m<row><col>][...] alakban.

Az .xyzw és .rgba alakú címek jelentését szemlélteti a következő ábra:

indexing

Példák:

pos.x = 0.4 matrix._m13 // mindig igaz: colour.b == coulour[2] matrix._m01 == matrix[0][1]

Műveletek tömbökkel

A Cg nyelv specifikációja számos, más nyelvekből általában hiányzó lehetőséget definiál, amik leegyszerűsítik a vektorokkal és mátrixokkal történő munkát.

Swizzling

A swizzling a speciális Cg-beli indexek kombinálhatóságát jelenti, változók értékeinek olvasásakor.

A swizzling segítségével egy vektor vagy mátrix elemei közül elérhető egyszerre több is, akár különböző sorrendben vagy indexenként többször:

void foobar(float4 p : POSITION, out float4 v : POSITION) { v = p.xxyy; } // -- float2 p2; float3 p3; float4 p4; float4x4 m; p2 = p4.xw; p3 = p2.yxy; p4 = p2.rgrg; p4 = m._m00_m11_m22_m33;

A két fajta vektor indexelés (.xyzw és .rgba) nem keverhető egy változón belül.

float4 p, q; p = q.rgzw; // Hiba!

Maszkolás

A maszkolás nagyban hasonlít a swizzling-re, de értékadások bal oldalán álló vektorokra és mátrixokra alkalmazható.

Segítségével megadható, hogy az értékadás mely elemekre vonatkozzon. Emiatt természetesen hiba egy elemre többször is hivatkozni.

void foobar(float4 p : POSITION, out float4 v : POSITION) { // ... v.xz = p.yx; } // -- float3 pos, pos2; float4 colour; float4x4 matrix; pos.xy = float2(1,2); matrix._m11_m12_m13 = colour.rgb; pos.xz = pos2; matrix._m11_m11 = pos; // Hiba!

Elkenés (smearing)

A nyelv támogat minden általában elvárt vektorok és mátrixok közti műveletet, mint például a skalárral szorzás, osztás, vektor összeadás, kivonás. Használhatók a még tagonként műveletek két vektorok szorzása, osztása.

Az elkenés egy skalárból a másik operandusnak megfelelő elemszámú vektor vagy mátrix készítése.

Ezzel értelmezhetők például az alábbi műveletek:

float4 pos, colour, norm; pos = 1/pos; colour = 0.5+colour; norm.rgb = norm.w/norm.xyz*pos.xyz; half4x4 m = 1;

Típus módosítók

Az egyes típusokhoz használhatók az alábbi, C nyelvben nem szereplő módosítók: