Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

the[V]oid

Alter Hase

  • »the[V]oid« ist der Autor dieses Themas

Beiträge: 775

Wohnort: Aachen

  • Private Nachricht senden

1

12.01.2010, 16:11

FPS suffert bei Verwendung bestimmten Shaders - Wer schuld?

Hallo

Wenn ich den folgenden Fragmentshader zwecks Bluring benutze, bricht meine FPS völlig ein:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
uniform sampler2D texture0;
uniform float filtersize;
uniform float width;
uniform float height;

void main()
{
    int nfiltersize = int( filtersize );
    float stepx = 1.0 / width;
    float stepy = 1.0 / height;
    vec3 colorsum = vec3( 0, 0, 0 );
    unsigned int count = unsigned int( 0 );
    for( int dx = -nfiltersize; dx <= nfiltersize; ++dx )
    {
        for( int dy = -nfiltersize; dy <= nfiltersize; ++dy )
        {
            vec2 offset = vec2( float( dx ) * stepx, float( dy ) * stepy );
            vec2 coord  = gl_TexCoord[0].st + offset;
            if( coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0 ) continue;
            colorsum += vec3( texture2D( texture0, coord ) );
            ++count;
        }
    }
    gl_FragColor = vec4( colorsum / float( count ), 1.0 );
}


Selbst wenn ich als nfiltersize nur die Werte 1 oder 2 verwende.
Nun meine Frage: Ist dieser Shader wirklich so leistungsfressend, oder muss ich den Fehler an anderer Stelle suchen?
Falls das erstere der Fall ist: Wie wird Bluring denn performanter implementiert?

Achja, und dass es ziemlich sinnfrei wist, floats für die gezeigten Uniforms zu verwenden, ist mir klar, aber ich habe meine Gründe ;)

Vielen Dank im Voraus
<< an dieser Stelle ist eine Signatur verstorben >>

2

12.01.2010, 16:52

Du hast sehr viele Textur lookups, dass ist das Problem ;-).

Im Wiki von DelphiGL gibts einen Shader von mir, der von Coolcat soweit es geht optimiert wurde: http://wiki.delphigl.com/index.php/shader_blur2

Viel Spaß damit ;-).

CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

3

12.01.2010, 17:27

Re: FPS suffert bei Verwendung bestimmten Shaders - Wer schu

Das Problem sind vermutlich nicht nur die Look-Ups, du hast gleich einen ganzen Haufen Probleme:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
uniform sampler2D texture0;
uniform float filtersize;
uniform float width;
uniform float height;

void main()
{
    int nfiltersize = int( filtersize );
    float stepx = 1.0 / width;
    float stepy = 1.0 / height;
    vec3 colorsum = vec3( 0, 0, 0 );
    unsigned int count = unsigned int( 0 ); // warum so viel gecaste, bleib doch einfach in float


    // dynamische Filtergröße verursacht Dynamic Branching, tödlich! Such dir eine feste Größe aus.

    for( int dx = -nfiltersize; dx <= nfiltersize; ++dx )
    {
        for( int dy = -nfiltersize; dy <= nfiltersize; ++dy )
        {
            vec2 offset = vec2( float( dx ) * stepx, float( dy ) * stepy );
            vec2 coord  = gl_TexCoord[0].st + offset;
            // Tödlich: Dynamic Branching ist DER Performance-Killer. Noch schlimmer: die Abfrage ist Quatsch, Textur-Clamping anschalten und weglassen, die GPU kann das im Bruchteil der Zeit!

            if( coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0 ) continue;
            colorsum += vec3( texture2D( texture0, coord ) );
            ++count;
        }
    }
    gl_FragColor = vec4( colorsum / float( count ), 1.0 );
}


Du blurst ein ganzes Rechteck in einem Pass, viel größere Wirkung bei gleicher Zahl der Texturzugriffe erhälst du, wenn du erst horizontal und dann vertikal je eindimensional blurst.
alphanew.net (last updated 2011-06-26) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

12.01.2010, 17:31

Re: FPS suffert bei Verwendung bestimmten Shaders - Wer schu

Zitat von »"the[V«

oid"]Wenn ich den folgenden Fragmentshader zwecks Bluring benutze, bricht meine FPS völlig ein:

[...]

Selbst wenn ich als nfiltersize nur die Werte 1 oder 2 verwende.


Inwiefern bricht alles ein? Was für eine Grafikkarte hast du?

Zitat von »"the[V«

oid"]Nun meine Frage: Ist dieser Shader wirklich so leistungsfressend, oder muss ich den Fehler an anderer Stelle suchen?
Falls das erstere der Fall ist: Wie wird Bluring denn performanter implementiert?


Dein Shader setzt einiges an dynamic branching ein. Das if in der Schleife is z.b. evtl. nicht das tollste. Verwende stattdessen lieber einen entsprechenden Texture Addressmode. Wenn du die Textur an den Rändern spiegelst (Mirror Mode) kannst du dir die Behandlung des Randfalles komplett sparen.
Üblicherweise verwendet man (so wie in dem Artikel von Skeptiker) einen linear separierbaren Filter (meist Gausskernel).
Man blurred nur in eine Richtung und führt den Blur dafür zweimal hintereinander aus (einmal in X und einmal in Y Richtung). So kann man die Anzahl der notwendigen Samples von O(n²) auf O(n) drücken.
Weiters kann man die Größen der Rendertargets für den Blur entsprechend kleiner wählen und z.B. die Samplepunkte so setzen dass sie genau zwischen zwei Texel fallen und bekommt dann durch den linearen Texturfilter noch etwas zusätzliche Blurkraft praktisch 4 free ;)

the[V]oid

Alter Hase

  • »the[V]oid« ist der Autor dieses Themas

Beiträge: 775

Wohnort: Aachen

  • Private Nachricht senden

5

12.01.2010, 18:25

Danke schonmal für die vielen Antworten, hat mir sehr weitergeholfen.
Eine Frage habe ich da nur: Was genau ist jetzt Dynamic Branching? Und vorallem: Warum ist es tödlich?

@dot: GeForce 6600, FPS fällt auf ~5

Und: Was spricht dagegen, statt 2 Renderpasses mit unterschiedlicher Anwendung des Blur-Filters einen einzigen zu verwenden, wobei der Shader die Anwendung erst in die eine, dann in die anderen Richtung durchführt?
<< an dieser Stelle ist eine Signatur verstorben >>

CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

6

12.01.2010, 18:40

Zitat von »"the[V«

oid"]Eine Frage habe ich da nur: Was genau ist jetzt Dynamic Branching? Und vorallem: Warum ist es tödlich?

Als Dynamic Branching bezeichnet man verschiedene Code-Pfade (Branches), die durch zur Compile-Zeit nicht auflösbare Bedingungen in Abhängigkeit von irgendwelchen veränderlichen Shader-Konstanten oder gar Pixel-Werten ausgeführt werden. Die Stärke der GPU liegt darin, immer wieder dieselben Operationen parallel in Massen auszuführen. Eine Bedingung stört diese einheitliche Repetivität. Gezielt eingesetzt kann Dynamic Branching durchaus sinnvoll sein. Du hast aber gleich einen ganzen Haufen Bedingungen in deinem Code, die überflüssig sind, spätestens, wenn du dich zur Compile-Zeit auf eine fester Filtergröße festlegst.

Zitat von »"the[V«

oid"]Und: Was spricht dagegen, statt 2 Renderpasses mit unterschiedlicher Anwendung des Blur-Filters einen einzigen zu verwenden, wobei der Shader die Anwendung erst in die eine, dann in die anderen Richtung durchführt?

Der Witz dabei ist, dass du das bereits horizontal geblurte Bild auch noch vertikal blurst. Wenn du n Pixel horizontal und n vertikal zusammenrechnest, brauchst du in einem Pass für das Rechteck n*n Texturzugriffe. Rechnest du erst horizontal, dann vertikal n Pixel zusammen, brauchst du dagegen für dasselbe Rechteck nur 2n Zugriffe. Dies lässt sich nicht zu einem Pass zusammenfassen, da der zweite Blur-Pass ja die Ergebnisse des ersten benötigt.
alphanew.net (last updated 2011-06-26) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

12.01.2010, 18:52

Zitat von »"the[V«

oid"]Eine Frage habe ich da nur: Was genau ist jetzt Dynamic Branching? Und vorallem: Warum ist es tödlich?


Branching == Programmflusskontrolle, also so Zeug wie Schleifen, if, switch.
Dynamic Branching heißt dass der Programmfluss von dynamischen (also zur Laufzeit veränderlichen) Größen abhängt.

Die ersten programmierbaren GPUs konnten sowas gar nicht. Erst mit Shader Model 2_x und 3.0 gabs wirkliches dynamic branching im Shader.
Das Problem damit ist, dass die Architektur von GPUs auf massive Parallelverarbeitung ausgelegt ist und dynamic branching da ziemlich zur Bremse werden kann. Man kann durch dynamic branching aber auch Performance gewinnen wenn man dadurch z.B. aufwändige Berechnungen überspringen kann. Zumindest auf NVIDIA Karten ist es am Besten wenn möglichst viele benachbarte Pixel den selben Codepfad nehmen.

Zitat von »"the[V«

oid"]Und: Was spricht dagegen, statt 2 Renderpasses mit unterschiedlicher Anwendung des Blur-Filters einen einzigen zu verwenden, wobei der Shader die Anwendung erst in die eine, dann in die anderen Richtung durchführt?


Versuch das mal ;)

the[V]oid

Alter Hase

  • »the[V]oid« ist der Autor dieses Themas

Beiträge: 775

Wohnort: Aachen

  • Private Nachricht senden

8

12.01.2010, 18:53

Zitat von »"CodingCat"«

Als Dynamic Branching bezeichnet man verschiedene Code-Pfade (Branches), die durch zur Compile-Zeit nicht auflösbare Bedingungen in Abhängigkeit von irgendwelchen veränderlichen Shader-Konstanten oder gar Pixel-Werten ausgeführt werden. Die Stärke der GPU liegt darin, immer wieder dieselben Operationen parallel in Massen auszuführen. Eine Bedingung stört diese einheitliche Repetivität. Gezielt eingesetzt kann Dynamic Branching durchaus sinnvoll sein. Du hast aber gleich einen ganzen Haufen Bedingungen in deinem Code, die überflüssig sind, spätestens, wenn du dich zur Compile-Zeit auf eine fester Filtergröße festlegst.


Was ist mit Konstanten, werden diese zur Compilezeit aufgelöst? Also zum Beispiel sowas hier definieren und dann überall im Code width verwenden:

C-/C++-Quelltext

1
const float width = 800;

Ist das gleichwertig, wie wenn ich direkt überall 800 einsetze, wo ich sonst width schreiben würde?

Zitat von »"CodingCat"«

Der Witz dabei ist, dass du das bereits horizontale geblurte Bild auch noch vertikal blurst. Wenn du n Pixel horizontal und n vertikal zusammenrechnest, brauchst du in einem Pass für das Rechteck n*n Texturzugriffe. Rechnest du erst horizontal, dann vertikal n Pixel zusammen, brauchst du dagegen für dasselbe Rechteck nur 2n Zugriffe. Dies lässt sich nicht zu einem Pass zusammenfassen, da der zweite Blur-Pass ja die Ergebnisse des ersten benötigt.


Also ich betrachte jetzt mal den Code, auf den vorhin Skeptiker verwiesen hatte. Hier erkenne ich folgende Struktur:

Quellcode

1
2
3
4
5
6
7
void main()
{
    for( int i=0; i < N; ++i )
    { 
        // Texturzugriff!
    }
}


Somit kämen wir auf N Texturzugriffe für einen Renderpass. Für zwei Renderpasses wären es natürlich 2N. Was ich meinte, ist sowas hier:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void impl()
{
    for( int i=0; i < N; ++i )
    { 
        // Texturzugriff!
    }
}

void main()
{
    // setze Variablen
    impl();
    // setze Variablen
    impl();
}


Und das dann mit nur einem Renderpass. Das wären doch ebenso 2N Texturzugriffe, oder bin ich völlig blöde?! :?
<< an dieser Stelle ist eine Signatur verstorben >>

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

12.01.2010, 18:55

Zitat von »"the[V«

oid"]Und das dann mit nur einem Renderpass. Das wären doch ebenso 2N Texturzugriffe, oder bin ich völlig blöde?! :?


Korrekt, 2N Zugriffe aber wenn dus ausprobierst wirst du sehen dass so nur in die letzte der beiden Richtungen geblurred wird. Der Witz an der Sache mit dem hintereinander ist ja dass der zweite Blur auf den schon in eine Richtung geblurten Daten arbeitet, dazu musst du das Zwischenergebnis aber in einer separaten Textur haben ;)

the[V]oid

Alter Hase

  • »the[V]oid« ist der Autor dieses Themas

Beiträge: 775

Wohnort: Aachen

  • Private Nachricht senden

10

12.01.2010, 19:00

Zitat von »"dot"«

Zitat von »"the[V«

oid"]Und das dann mit nur einem Renderpass. Das wären doch ebenso 2N Texturzugriffe, oder bin ich völlig blöde?! :?


Korrekt, 2N Zugriffe aber wenn dus ausprobierst wirst du sehen dass der Blur so nur in die letzte der beiden Richtungen gemacht wird. Der Witz an der Sache mit dem hintereinander ist ja dass der zweite Blur auf den schon in eine Richtung geblurten Daten arbeitet, dazu musst du das Zwischenergebnis aber in einer separaten Textur haben ;)


Habs ausprobiet. Wird er nicht. Zugegeben, das was ich eben geschrieben hatte, war etwas vereinfacht. Das hier entspricht eher dem, was ich ausprobiert habe:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
vec3 impl()
{
   vec3 color;
   for( int i=0; i < N; ++i )
   {
      // Texturzugriff!

   }
   return color;
}

void main()
{
   // setze Variablen

   vec3 color = impl();
   // setze Variablen

   color += impl();
   gl_FragColor = vec4( color / 2, 1.0 );
}


Wird zwar vielleicht nicht immer ganz korrekte Ergebenisse liefern, dafür spart man sich aber das Wechseln zwischen verschiedenen Render-Targets, oder nicht?
<< an dieser Stelle ist eine Signatur verstorben >>

Werbeanzeige