-
1. Data: 2014-06-28 12:48:05
Temat: cpu shading by sse intrinsics
Od: firr <p...@g...com>
w moim rasteryzerze mam blog do flat shadingu
trojkatów od 4rech swiateł - wyglada on wyjatkowo niechlujnie moim zdaniem ale do
końca nie wiem co
z nim zrobic
// input: float x1, y1, z1, x2, y2, z2, x3, y3, z3;
static float3 lightDir1= {0.2, -1.6, -1.7 };
static float3 lightDir2 = {0.5, -0.7, 20.3 };
static float3 lightDir3 = {-0.5,-0.3, -0.6 };
static float3 lightDir4 = {-0.5, 1.3, 0.6 };
static float3 lightColor1= {.4, .414, .515 };
static float3 lightColor2 = {.4145, .451, .543 };
static float3 lightColor3 = {.584, .51414, .43 };
static float3 lightColor4 = {.41, .44, .3414 };
float3 u = {x2-x1, y2-y1, z2-z1 };
float3 v = {x3-x2, y3-y2, z3-z2 };
float3 normal = cross_(u,v);
// normal.x = (y2-y1)*(z3-z2) - (z2-z1)*(y3-y2);
// normal.y = (z2-z1)*(x3-x2) - (x2-x1)*(z3-z2);
// normal.z = (x2-x1)*(y3-y2) - (y2-y1)*(x3-x2);
normalize(&normal);
float s1 = dot(normal, lightDir1);
float s2 = dot(normal, lightDir2);
float s3 = dot(normal, lightDir3);
float s4 = dot(normal, lightDir4);
if(s1<0) s1=0;
if(s2<0) s2=0;
if(s3<0) s3=0;
if(s4<0) s4=0;
int b = (color&0x000000ff);
int g = (color&0x0000ff00)>>8;
int r = (color&0x00ff0000)>>16;
float lr= .1 + (s1*lightColor1.x + s2*lightColor2.x + s3*lightColor3.x+
s4*lightColor4.x);
float lg= .1 +(s1*lightColor1.y + s2*lightColor2.y + s3*lightColor3.y+
s4*lightColor4.y);
float lb= .1 + (s1*lightColor1.z + s2*lightColor2.z + s3*lightColor3.z+
s4*lightColor4.z);
r*=lr;
g*=lg;
b*=lb;
if(r>255) r=255;
if(g>255) g=255;
if(b>255) b=255;
return rgb(b,g,r);
chodzi o dwie rzeczy
1) jak ew przyspieszyc czy ladniej to zapisac z poziomu c
2) jak przepisac to i przyspieszyc przy pomocy sse intrinsics (uzywam mingw gcc 4.7
wiec tak zeby poszlo pod tym kompilatorem)
glownie chodzi o ta drugą rzecz, nie mam moze nawet w sumie az tak duzo czasu na to
;/ ale z drugiej strony troche podlubac by sie przydalo ;\
-
2. Data: 2014-06-29 12:46:22
Temat: Re: cpu shading by sse intrinsics
Od: firr <p...@g...com>
uzyskalem przez zapytanie na innym forum taki kod
#include <pmmintrin.h>
struct FourVec3s { __m128 x; __m128 y; __m128 z; };
struct FourTris { FourVec3s a; FourVec3s b; FourVec3s c; __m128i colors; };
// transposed
static FourVec3s lightDirs = {{0.2, 0.5, -0.5, -0.5},
{-1.6,-0.7,-0.3, 1.3},
{-1.7, 20.3,-0.6, 0.6}};
// transposed
static FourVec3s lightColors = {{.4, .4145, .584, .41 },
{.414, .451, .51414,.44},
{.515, .543, .43, .3414}};
static __m128 modelRight = {1.0, 0.0, 0.0, 0.0};
static __m128 modelUp = {0.0, 1.0, 0.0, 0.0};
static __m128 modelDir = {0.0, 0.0, 1.0, 0.0};
static __m128 modelPos = {0.0, 0.0, 0.0, 1.0};
static inline __m128 splatX(__m128 v) { return
_mm_shuffle_ps(v,v,_MM_SHUFFLE(0,0,0,0)); }
static inline __m128 splatY(__m128 v) { return
_mm_shuffle_ps(v,v,_MM_SHUFFLE(1,1,1,1)); }
static inline __m128 splatZ(__m128 v) { return
_mm_shuffle_ps(v,v,_MM_SHUFFLE(2,2,2,2)); }
static inline __m128 add(__m128 l, __m128 r) { return _mm_add_ps(l, r); }
static inline __m128 sub(__m128 l, __m128 r) { return _mm_sub_ps(l, r); }
static inline __m128 mul(__m128 l, __m128 r) { return _mm_mul_ps(l, r); }
static inline __m128 and(__m128 l, __m128 r) { return _mm_and_ps(l, r); }
static inline __m128 less(__m128 l, __m128 r) { return _mm_cmplt_ps(l, r); }
static inline __m128 dot(const FourVec3s &l, const FourVec3s &r) { return
add(add(mul(l.x,r.x), mul(l.y,r.y)), mul(l.z,r.z)); }
// unpack 8 bit RgbaRgbaRgbaRgba into 32-bit RRRR gggg or bbbb
static inline __m128i unpackR(__m128i iv) { return
_mm_unpacklo_epi16(_mm_unpacklo_epi8(iv,_mm_setzero_
si128()),_mm_setzero_si128()); }
static inline __m128i unpackG(__m128i iv) { return
_mm_unpackhi_epi16(_mm_unpacklo_epi8(iv,_mm_setzero_
si128()),_mm_setzero_si128()); }
static inline __m128i unpackB(__m128i iv) { return
_mm_unpacklo_epi16(_mm_unpackhi_epi8(iv,_mm_setzero_
si128()),_mm_setzero_si128()); }
static inline __m128 intsToFloats(__m128i iv) { return _mm_cvtepi32_ps(iv); }
static inline __m128i floatToInts(__m128 fv) { return _mm_cvttps_epi32(fv); }
static inline __m128i packAndSaturate32To8(__m128i r ,__m128i g, __m128i b, __m128i
a) { return _mm_packs_epi16(_mm_packs_epi32(r,g),_mm_packs_epi32
(b,a)); }
static inline FourVec3s normalizeFourVec3s(const FourVec3s &v) {
__m128 length = _mm_sqrt_ps(add(add( mul(v.x,v.x), mul(v.y,v.y)), mul(v.z,v.z)
));
FourVec3s result = { _mm_div_ps(v.x,length), _mm_div_ps(v.y,length),
_mm_div_ps(v.z,length) };
return result;
}
__m128i Shade4Triangles(const FourTris &tris) {
__m128 x1 = add(add(add( mul(sub(tris.a.x, splatX(modelPos)),
splatX(modelRight)), // (*triangle).a.x - modelPos.x)*modelRight.x +
mul(sub(tris.a.y, splatY(modelPos)),
splatY(modelRight))), // ((*triangle).a.y - modelPos.y)*modelRight.y +
mul(sub(tris.a.z, splatZ(modelPos)),
splatZ(modelRight))), // ((*triangle).a.z - modelPos.z)*modelRight.z) +
splatX(modelPos));
// modelPos.x
__m128 y1 = add(add(add( mul(sub(tris.a.x, splatX(modelPos)), splatX(modelUp)),
mul(sub(tris.a.y, splatY(modelPos)), splatY(modelUp))),
mul(sub(tris.a.z, splatZ(modelPos)), splatZ(modelUp))),
splatY(modelPos));
__m128 z1 = add(add(add( mul(sub(tris.a.x, splatX(modelPos)), splatX(modelDir)),
mul(sub(tris.a.y, splatY(modelPos)), splatY(modelDir))),
mul(sub(tris.a.z, splatZ(modelPos)), splatZ(modelDir))),
splatZ(modelPos));
__m128 x2 = add(add(add( mul(sub(tris.b.x, splatX(modelPos)),
splatX(modelRight)),
mul(sub(tris.b.y, splatY(modelPos)),
splatY(modelRight))),
mul(sub(tris.b.z, splatZ(modelPos)),
splatZ(modelRight))),
splatX(modelPos));
__m128 y2 = add(add(add( mul(sub(tris.b.x, splatX(modelPos)), splatX(modelUp)),
mul(sub(tris.b.y, splatY(modelPos)), splatY(modelUp))),
mul(sub(tris.b.z, splatZ(modelPos)), splatZ(modelUp))),
splatY(modelPos));
__m128 z2 = add(add(add( mul(sub(tris.b.x, splatX(modelPos)), splatX(modelDir)),
mul(sub(tris.b.y, splatY(modelPos)), splatY(modelDir))),
mul(sub(tris.b.z, splatZ(modelPos)), splatZ(modelDir))),
splatZ(modelPos));
__m128 x3 = add(add(add( mul(sub(tris.c.x, splatX(modelPos)),
splatX(modelRight)),
mul(sub(tris.c.y, splatY(modelPos)),
splatY(modelRight))),
mul(sub(tris.c.z, splatZ(modelPos)),
splatZ(modelRight))),
splatX(modelPos));
__m128 y3 = add(add(add( mul(sub(tris.c.x, splatX(modelPos)), splatX(modelUp)),
mul(sub(tris.c.y, splatY(modelPos)), splatY(modelUp))),
mul(sub(tris.c.z, splatZ(modelPos)), splatZ(modelUp))),
splatY(modelPos));
__m128 z3 = add(add(add( mul(sub(tris.c.x, splatX(modelPos)), splatX(modelDir)),
mul(sub(tris.c.y, splatY(modelPos)), splatY(modelDir))),
mul(sub(tris.c.z, splatZ(modelPos)), splatZ(modelDir))),
splatZ(modelPos));
FourVec3s normal;
normal.x = sub( mul(sub(y1,y1),sub(z3,z2)), mul(sub(z2,z1),sub(y3,y2)) );
normal.y = sub( mul(sub(z2,z1),sub(x3,x2)), mul(sub(x2,x1),sub(z3,z2)) );
normal.z = sub( mul(sub(x2,x1),sub(y3,y2)), mul(sub(y2,y1),sub(x3,x2)) );
normal = normalizeFourVec3s(normal);
__m128 s1234 = dot(normal, lightDirs);
s1234 = and(s1234, less(_mm_setzero_ps(), s1234));
__m128 l = add(_mm_set_ps1(0.1f), add(add( mul(s1234,lightColors.x),
mul(s1234,lightColors.y)), mul(s1234,lightColors.z)));
__m128i r = floatToInts(mul(l,intsToFloats(unpackR(tris.colors))
));
__m128i g = floatToInts(mul(l,intsToFloats(unpackG(tris.colors))
));
__m128i b = floatToInts(mul(l,intsToFloats(unpackB(tris.colors))
));
return packAndSaturate32To8(r,g,b,_mm_setzero_si128());
}
aczkolwiek czeka mnie z tym mała 'rozkminka' bo nie wszystko jest jasne
-
3. Data: 2014-06-30 10:42:48
Temat: Re: cpu shading by sse intrinsics
Od: Wojciech Muła <w...@g...com>
On Saturday, June 28, 2014 12:48:05 PM UTC+2, firr wrote:
> chodzi o dwie rzeczy
>
> 1) jak ew przyspieszyc czy ladniej to zapisac z poziomu c
Nie licz za każdym razem normalnej, ani jej nie normalizuj (to
pierwiastek i trzy dzielenia - dwie najwolniejsze operacje na CPU).
Shader nie powinien liczyć normalnej, a jedynie intensywność światła.
Mieszasz odpowiedzialności i wychodzi sieczka.
> 2) jak przepisac to i przyspieszyc przy pomocy sse intrinsics (uzywam mingw gcc 4.7
wiec tak zeby poszlo pod tym kompilatorem)
Najpierw dobrze napisz wersję skalarną, potem zastanawiaj się jak
ją przyspieszyć SIMD-ami. Zresztą wątpliwe, czy zrobisz to lepiej niż
kompilator, popatrz na http://locklessinc.com/articles/vectorize/.
w.
-
4. Data: 2014-06-30 12:16:29
Temat: Re: cpu shading by sse intrinsics
Od: firr <p...@g...com>
W dniu poniedziałek, 30 czerwca 2014 10:42:48 UTC+2 użytkownik Wojciech Muła napisał:
> On Saturday, June 28, 2014 12:48:05 PM UTC+2, firr wrote:
>
> > chodzi o dwie rzeczy
>
> >
>
> > 1) jak ew przyspieszyc czy ladniej to zapisac z poziomu c
>
>
>
> Nie licz za każdym razem normalnej, ani jej nie normalizuj (to
>
> pierwiastek i trzy dzielenia - dwie najwolniejsze operacje na CPU).
>
> Shader nie powinien liczyć normalnej, a jedynie intensywność światła.
>
> Mieszasz odpowiedzialności i wychodzi sieczka.
>
>
>
> > 2) jak przepisac to i przyspieszyc przy pomocy sse intrinsics (uzywam mingw gcc
4.7 wiec tak zeby poszlo pod tym kompilatorem)
>
>
>
> Najpierw dobrze napisz wersję skalarną, potem zastanawiaj się jak
>
> ją przyspieszyć SIMD-ami. Zresztą wątpliwe, czy zrobisz to lepiej niż
>
> kompilator, popatrz na http://locklessinc.com/articles/vectorize/.
>
>
nie przypuszczam zeby bylo to watpliwe, ztcw te wektoryzery potrafia wykonac ledwie
szczatkowe
operacje
co do przepisywania na razie chyba porobie troszke prostsze testy (bo w tych
wiekszych troche sie gubie) - zobacze np czy zwykle obracanie wektorow coskolwiek
przyspiesza
(nie spodziewam sie za wiele ale trzeba sprawdzic)
cos w stylu - pseudokod roboczy
float modelRight_x;
float modelRight_y;
float modelRight_z;
float modelUp_x;
float modelUp_y;
float modelUp_z;
float modelDir_x;
float modelDir_y;
float modelDir_z;
float normal_x[100*1000];
float normal_y[100*1000];
float normal_z[100*1000];
float n_x[100*1000];
float n_y[100*1000];
float n_z[100*1000];
for(int i=0; i<100*1000; i++)
{
normal_x[i] = n_x[i]*modelRight_x + n_y[i]*modelRight_y + n_z[i]*modelRight_z;
normal_y[i] = n_x[i]*modelUp_x + n_y[i]*modelUp_y + n_z[i]*modelUp_z;
normal_z[i] = n_x[i]*modelDir_x + n_y[i]*modelDir_y + n_z[i]*modelDir_z;
}
float4 modelRight_4x = populate(modelRight_x);
for(int i=0; i<100*1000; i+=4)
{
add_ps(
normal_x[i] = add_ps(
mul_ps(n_x, modelRight_x),
mul_ps(n_y, modelRight_y) ),
mul_ps(n_z, modelRight_z))
normal_y[i] = add_ps(
mul_ps(n_x, modelUp_x),
mul_ps(n_y, modelUp_y) ),
mul_ps(n_z, modelUp_z))
normal_z[i] = add_ps(
mul_ps(n_x, modelDir_x),
mul_ps(n_y, modelDir_y) ),
mul_ps(n_z, modelDir_z))
}
-
5. Data: 2014-06-30 12:27:53
Temat: Re: cpu shading by sse intrinsics
Od: firr <p...@g...com>
ps co do liczeni normalnej to nie jest takie jasne bo skladowanie i czytanie z
megabajtów normalnych troche trwa gdy tymczasem shading robie juz po clippingu i
potrzebuje tylko co poniektórych (dla obecnego tie fightera okolo 15-25% ale dla
normalnych scen raczej mniej) - robilem wczesniej wstepne testy i liczenie on-the-fly
bylo jakby lepsze (na dokladniejsze testy na razie nie mam sily)
uczenie sie podstaw sse jest troche meczace , mam na przyklad taka niejasnosc, czy
jest jakis intrinsic/opkod do wczytywania intow/floatow do m128 nie z pamieci ale
jako immediate?
-
6. Data: 2014-07-02 01:20:51
Temat: Re: cpu shading by sse intrinsics
Od: firr <p...@g...com>
co jeszcze moge powiedziec o takim programowaniu
tymi intrinsicami
podobaja mi sie takie rzeczy jak
_mm_and_ps(values, _mm_cmplt_ps(zeros, values));
czyli takie porownania jakich nie ma w normalnym asmie (a chyba szkoda, (?)) tj nie
rozgaleziajace kodu a zwracajace 'maski' ktorych pozniej mozna uzyc
wtady mozna pisac bezifowo rozne takie wyrazenia jak
a += 17 & (b>10);
co jest rownowazne
if(b>10) a+=17;
w c tez to mozna napisac (jako ze wyzej jest to wlasnie napisane) ale nie wiem czy w
starym asemblerze (tym bez cmov) dalo sie to zapisac bezifowo - warunek ustawia niby
flagi ale nie
pamietam czy byla komenda ktora populowala flage na np cale slowo jedynek itp
jeszcze inna uwaga, ogolnie jak nawyknac 9juz chyba nawyklem) to to tzw wertykalne
kodowanie w intrisincowym sse jest zupelnie proste za wyjatkiem tego ze trzeba
ukladac te dane i akurat jak ja czytam ten kod wyzej to mozna sie pogubic
na jakiej ilosci danych operuje konkretny operand
(chyab trzeba sie troche do tego przyzwyczaic tak jak do wskaznikow)
nie che mi sie tu tlumaczyc o co mi chodzi ale mw o to
__m128 s1234 = dot(normal, lightDirs);
wiadomo ze to robi dota normalnej z lightDirs
i ustawia wynik jako s1234 ale ile dokladnie tego to bierze i jak nie jest dla mnie
jakos natychmiastowo jasne
(to jest wertykalny kod wiec wiadomo ze dziala na paczkach po 4 ale tutaj jest chyba
podwojnie wertykalny - wlasnie nawet nie wiem czy takich zapisow nie nalezy unikac,
chozi tez o pewna kwestie dotyczaca rozkladu danych
wiadomo ze dane musza byc by to tak nazwac zgrupowane w poprzek np
{x[100], y[100], z[100]}
zamiast
{x,y,z}[100]
(ta skladnia nie jest glupia nie wiem czy nie przydalaby sie nawet tak by okreslac
rozmaite layouty a pozniej uzywac x[i] do abstrakcyjnego latania po tych layoutach)
ale pytanie jest czy grupowac w male paczki po cztaery w poprzek tj
{x[4], y[4], z[4]}[25]
czy zupelnie w poprzek {x[100], y[100], z[100]}
zupelnie w poprzek wydaje sie senswniejsze ale
ten paczkowy layout ma pewne 'zalety' czy tez po prostu wlasnosci, mianowicie takie
ze zeby np
napisac takiego podwojnie wertylkalnego dota
wystarczy podac dwa wskazniki tj na jedna paczke i na drugą dot(&a, &b) a bez
rozkladu paczkowego trzeba podac ich szesc dot(&x,&y,&z, &x2,&y2,&z2) - chociaz ja
optuje chyba raczej za tym drugim zapisem jest o wiele bardziej czytelny
-
7. Data: 2014-07-02 18:12:25
Temat: Re: cpu shading by sse intrinsics
Od: Edek <e...@g...com>
Szarym od mżawki świtem Mon, 30 Jun 2014 01:42:48 -0700, Wojciech Muła
wyrzucił pustą ćwiartkę i oznajmił:
> On Saturday, June 28, 2014 12:48:05 PM UTC+2, firr wrote:
>> chodzi o dwie rzeczy
>>
>> 1) jak ew przyspieszyc czy ladniej to zapisac z poziomu c
>
> Nie licz za każdym razem normalnej, ani jej nie normalizuj (to pierwiastek
> i trzy dzielenia - dwie najwolniejsze operacje na CPU). Shader nie
> powinien liczyć normalnej, a jedynie intensywność światła.
> Mieszasz odpowiedzialności i wychodzi sieczka.
W tej jego grze rpg matematyka wymagałaby długiego rozwijania skilla,
ze względu na brak ajtemów dających +1000000 do inteligencji. W sumie
fajnie się patrzy na kogoś, kto bardzo chce używać sse a nie ma pojęcia
o kosztach podstawowych operacji matematycznych, o inwencji w przekształcaniu
i upraszczaniu obliczeń nie wspominając. Słodki żuczek, niech sobie leży
na pleckach i macha nóżkami, zaczynam zmieniać podejście do jego blogowania
na grupie.
--
Edek
-
8. Data: 2014-07-02 20:13:29
Temat: Re: cpu shading by sse intrinsics
Od: firr <p...@g...com>
ale jestem kurna zmeczony..
ogolnie moim doraznym celem byloby przepisanie
mojego softwarowego pipeline na sse i zobaczenie
czy to przyspieszy [pisze o tym bo jest to ciekawy
temat na grupe aczkolwiek z tego powodu ze jest za
mala raczej marne szanse by ktos podjal i rozwinal
temat] - gdyby to np dzialalo dwa razy
szybciej dla duzej rozdzielczosci (tam gdzi emam teraz 40-60ms)
to by bylo cudownie tyle ze na to o ile wiem raczej nie
ma szans (jako ze tego typu program to raczej przeplyw ramu
a obliczenia sa w sumi naskórkowe - garstka mnozen kilka
ifów - jeszcze troche ifów - i na koniec nieregularne
(trójkątne nomen omen) petelki, - w tych petelkach sa
dzielenia, (jadno na kazda scanline potrzebne do wyznaczania
nachyleń ale w sumie nie wiem czy tych dzielen na wspolczesnych
kompach trzeba unikac (kiedys owszem ztcw byly naprawde
wolne) - sa to w sumie dzilenia przez inta tak ze
moglbym to stablicowac i sprawdzic... tak ze ogolnie
rzecz biorac po przepisaniu tego (czesciowym bo samego
rysowania trojkatow raczej sie nie da), pewnie skonczy
sie labo na przyspieszeniu rzedu 20% albo wogole
(ze wzgledu na pewne dodatkowe kopiowania ktore trzeba
bedzie zrobic na uzytek sse) - zagadnienie w sumie ciekawe
jak ktos lubi niskopoziomowe kodowanie