PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Pixelshader: nach "Optimierung" langsamer


ollix
2007-02-11, 19:23:07
Hi,

ich habe vor einiger Zeit mal einen kleinen 3x3 und 5x5 Gauß-Weichzeichner mit dynamischem Kernel implementiert, der eine Textur an einer bestimmten Stelle abtastet und einen weichgezeichneten Texel zurückliefert. Jetzt dachte ich mir, guck mal ob das schneller geht und habe mal einige Instruktionen zusammengefaßt in der Hoffnung, da die GPU ja gerne auf Vektoren rechnen bzw. um die SIMD Einheiten zu nutzen, das das schneller geht.


vec4 gaussian_blur_3x3_opt(sampler2D tex, vec2 UV, float amount)
{
float sigma = mix( 0.1, 2.0, amount);
vec2 ka = gaussian_1D( sigma, 0, 1 );
vec3 weights = ka.xxy * ka.xyy;
weights /= dot(weights, vec3( 1, 4, 4));

float kernel[9];
kernel[4] = weights.x;
kernel[1] = kernel[3] = kernel[5] = kernel[7] = weights.y;
kernel[0] = kernel[2] = kernel[6] = kernel[8] = weights.z;

vec2 offsets[9];
offsets[0] = vec2(-GAUSS_RADIUS, -GAUSS_RADIUS); offsets[1] = vec2(0, -GAUSS_RADIUS); offsets[2] = vec2(GAUSS_RADIUS, -GAUSS_RADIUS);
offsets[3] = vec2(-GAUSS_RADIUS, 0); offsets[4] = vec2(0, 0); offsets[5] = vec2(GAUSS_RADIUS, 0);
offsets[6] = vec2(-GAUSS_RADIUS, GAUSS_RADIUS); offsets[7] = vec2(0, GAUSS_RADIUS); offsets[8] = vec2(GAUSS_RADIUS, GAUSS_RADIUS);

vec4 Tblur = vec4(0);
for (int i = 0; i < 9; ++i)
{
vec2 UV_0 = UV + offsets[i];
Tblur += kernel[i] * texture2D(tex, UV_0);
}

return Tblur;
}

vec2 gaussian_1D( float sigma, int x1, int x2 )
{
float c = 1.0 / (TWOPI_SQRT * sigma);
vec2 order = -0.5 * pow( vec2(x1,x2), vec2(2) );
return c * exp( order );
}

Die Berechnung erfolgte ursprünglich durch:
float ka0 = gaussian_1D( sigma, 0 );
float ka1 = gaussian_1D( sigma, 1 );
float sumfrac = 1.0 / (4.0*(ka1*ka1) + 4.0*(ka1*ka0) + (ka0*ka0));

float kernel[9];
kernel[0] = kernel[2] = kernel[6] = kernel[8] = (ka1*ka1)*sumfrac;
kernel[1] = kernel[3] = kernel[5] = kernel[7] = (ka1*ka0)*sumfrac;
kernel[4] = (ka0*ka0)*sumfrac;
Es wurde eigentlich nur die Berechnung eines Gaußwertes durch gaussian_1D() von einem für zwei (sowie drei und vier) Elemente implementiert und die Skalierung der Gewichte auf 1 bzw. das Aufsummieren über eine dotproduct Operation mit der entsprechenden Wertigkeit. Ansonsten ist alles gleich. Ich dachte vielleicht ist es dadurch ja ein bissle schneller, aber im Gegenteil. Die ursprüngliche Variante läuft in einem Test mit ~270fps, die optimierte Variante mit ~249fps auf meiner NV40. Der Unterschied ist nicht groß, aber woran liegt das bzw. wie könnte man das besser machen?

danke

transstilben
2007-02-12, 19:02:28
Ich hab das bisher auch noch nicht gemacht, aber kann man denn die Vertex- und Pixel-Shader nicht debuggen (Mit Visual Studio 8 / DirektX SDK) ?
Dort sollte man doch dann auch sehen können, was aus dem Shader-Code geworden ist (das Kompilat), oder ?
Schön wäre ja dann soetwas wie "VTune" von Intel (Ein Analysetool, das die Laufzeiten/Latenzen einzelner Instruktionen anzeigt) nur eben für die GPU.
Gibt es denn keine Tools die ein "Profiling" von Shadern bzgl. Performance machen können ?

Chris Lux
2007-02-12, 19:58:30
Ich hab das bisher auch noch nicht gemacht, aber kann man denn die Vertex- und Pixel-Shader nicht debuggen (Mit Visual Studio 8 / DirektX SDK) ?
Dort sollte man doch dann auch sehen können, was aus dem Shader-Code geworden ist (das Kompilat), oder ?
Schön wäre ja dann soetwas wie "VTune" von Intel (Ein Analysetool, das die Laufzeiten/Latenzen einzelner Instruktionen anzeigt) nur eben für die GPU.
Gibt es denn keine Tools die ein "Profiling" von Shadern bzgl. Performance machen können ?
gdebugger [1], dazu braucht man dann einen sogenannten instrumented driver (bei nvidia auf der freien developer seite zu haben). dieser treiber stellt bestimmte counter bereit, die von der software ausgewertet werden können. ist ein klasse tool!

[1] http://www.gremedy.com/

Gast
2007-02-13, 09:09:01
findet man am einfachsten raus woran es liegt mittels:
http://developer.nvidia.com/object/nvperfhud_home.html
http://developer.nvidia.com/object/nvshaderperf_home.html

was besseres gibt's nicht :)

Chris Lux
2007-02-13, 09:48:43
findet man am einfachsten raus woran es liegt mittels:
http://developer.nvidia.com/object/nvperfhud_home.html
perfHUD ist Direct3D only, leider :/

SavageX
2007-02-13, 10:09:16
Ganz naiv tippe ich mal auf die Schleife. Alles, was irgendwie konditional riecht, ist mir in Pixelshadern suspekt (zumindest für NV40).

class Foo: pass
2007-02-13, 13:20:11
Ganz naiv tippe ich mal auf die Schleife. Alles, was irgendwie konditional riecht, ist mir in Pixelshadern suspekt (zumindest für NV40).
AFAIK sind if statements eine schlechte Idee im shader code, aber dass Schleifen auch Probleme bereiten. :confused:
Ich dachte immer der compiler macht sowieso ein loop unrolling sofern die hardware keine Schleifen unterstützt.

lg,
Stefan

ollix
2007-02-13, 13:44:08
Danke!

perfHUD ist Direct3D only, leider :/ Jo :( Und meine 30 Tage beim gDEBugger sind leider schon lange vorbei. :(

AFAIK sind if statements eine schlechte Idee im shader code, aber dass Schleifen auch Probleme bereiten. :confused:
Ich dachte immer der compiler macht sowieso ein loop unrolling sofern die hardware keine Schleifen unterstützt. Dachte ich eigentlich auch. Aber die Schleifen bleiben ja auch gleich bei beiden Varianten. Das einzige was geändert wird ist die Berechnung der Gaußwerte und die Skalierung/Normierung der Gewichte. :confused:

del_4901
2007-02-13, 20:53:48
Also das riecht stark anch einem Compiler/Driver Bug.
Vllt. ist ja auch die Caching Strategie verwurstet. (das der Compiler es in einen anderen Bereich legt).

Variante 3: der Optimizer kennt den alten Code und ersetzt ihn durch besseren.