OpenGL Shader



  • In einem unserer Projekte hatten wir den Fall, dass die gleichen Shader (Vertex- und Fragmentshader) bei gleicher Vorverarbeitung verschiedene Arten der Darstellung unterstützen mussten. Der Code war dann gespickt mit "if's auf uniforms", was nicht so sehr performant war. Nun sind die einzelnen Funktionalitäten bzw. Buildingblock in verschiedenen Dateien, die beim Umschalten zwischen den Darstellung zu Shadern zusammengebastelt werden.



  • @dot
    Was ist der Vorteil von Linken vs. einfach verschiedene Files "zusammen-includen" und dann compilieren? Dauert das Compilieren zu lange?

    Und wird der Code wenn man "linkt" auch vergleichbar gut optimiert, oder bezahlt man dieses nette Feature mit schlechterer Shader Performance (verglichen mit alles im selben Source-File implementiert, bei gleicher Aufteilung auf Funktionen also ohne manuelles Inlining)?



  • hustbaer schrieb:

    @dot
    Was ist der Vorteil von Linken vs. einfach verschiedene Files "zusammen-includen" und dann compilieren?

    Der vermutlich einzige relevante Unterschied ist, dass man es nicht selber machen muss. Wobei ich ehrlich gesagt nicht mit Erfahrungswerten aufwarten kann (ich wollte nur die Frage beantworten, wofür man das brauchen könnte) und OpenGL direkt liefert einem ja auch keine Möglichkeit, einen Blick auf den erzeugen Shadercode zu werfen. Gibt aber entsprechende Extensions von ATI und NVIDIA, man könnte also mal ausprobieren, ob es am Ende tatsächlich einen Unterschied macht...


  • Mod

    das sind zwei verschiedene dinge. beim includen bastelt man sich nur den source zusammen, beim linken wird hingegen der eigentliche code generiert (ist nicht wie linken bei c/c++). man kann opengl direkt shader binaries uebergeben oder source der zum shader binary gemacht wird, linken muss man aber auf jeden fall, damit alle shader die zusammen verwendet werden aneinander angepasst werden (und nicht erst vom treiber zur laufzeit).



  • Ja, ich vermute aber, dass es am Ende kaum einen Unterschied macht, ob man jetzt den Quelltext zusammenpappt oder Shaderfragmente "linked". Ich würde mal davon ausgehen, dass der Shadercompiler beim Kompilieren einfach einen Zwischencode ausspuckt und "Shaderbinaries" nicht viel mehr sind als ein AST, sowas wie LLVM Intermediate Code oder was auch immer, jedenfalls noch relativ high level und der eigentliche Code erst vom Treiber zur Laufzeit generiert wird, so wie das bei Direct3D auch der Fall ist. Wobei die OpenGL Shader Binaries ja nicht portabel sind, daher könnte es theoretisch natürlich schon der Real Deal sein...


  • Mod

    dot schrieb:

    Ja, ich vermute aber, dass es am Ende kaum einen Unterschied macht, ob man jetzt den Quelltext zusammenpappt oder Shaderfragmente "linked".

    man linkt keine shader fragmente, sondern die einzelnen shader stages. (esseiden latest ogl hat was neues was anders ist als das linken bisher).

    dot schrieb:

    ...der eigentliche Code erst vom Treiber zur Laufzeit generiert wird, so wie das bei Direct3D auch der Fall ist.

    rapso schrieb:

    linken muss man aber auf jeden fall, damit alle shader die zusammen verwendet werden aneinander angepasst werden (und nicht erst vom treiber zur laufzeit)



  • rapso schrieb:

    dot schrieb:

    Ja, ich vermute aber, dass es am Ende kaum einen Unterschied macht, ob man jetzt den Quelltext zusammenpappt oder Shaderfragmente "linked".

    man linkt keine shader fragmente, sondern die einzelnen shader stages. (esseiden latest ogl hat was neues was anders ist als das linken bisher).

    Das Linken der einzelnen Stages ist wohl eher eine rein theoretische Möglichkeit; ich bezweifle, dass das jenseits der API irgendeine Relevanz hat bzw. tatsächlich auch so umgesetzt ist oder jemals war, denn in Direct3D kann man seit je her die Shader der einzelnen Stages unabhängig voneinander setzen und in OpenGL 4.3 wurde genau das mit den Program Pipeline Objects afaik nun letztendlich auch exposed...


  • Mod

    dot schrieb:

    rapso schrieb:

    dot schrieb:

    Ja, ich vermute aber, dass es am Ende kaum einen Unterschied macht, ob man jetzt den Quelltext zusammenpappt oder Shaderfragmente "linked".

    man linkt keine shader fragmente, sondern die einzelnen shader stages. (esseiden latest ogl hat was neues was anders ist als das linken bisher).

    Das Linken der einzelnen Stages ist wohl eher eine rein theoretische Möglichkeit; ich bezweifle, dass das jenseits der API irgendeine Relevanz hat bzw. tatsächlich auch so umgesetzt ist oder jemals war, denn in Direct3D kann man seit je her die Shader der einzelnen Stages unabhängig voneinander setzen und in OpenGL 4.3 wurde genau das mit den Program Pipeline Objects afaik nun letztendlich auch exposed...

    tjo, deine zweifel sind valide aber leider falsch. wenn du lange schader hast, 'compilieren' die sehr schnell, jedoch dauert es durchaus lange sie zu linken (das gilt auch wenn du mit opengl ES 2 emulation arbeitest). mit ati ist das noch ertraeglich, mit nvidia kann es ne minute dauern ein paar zig shader zu linken (und ogl es 2 emulatoren unterstuetzen keine binaries, was echt eine scheiss turn around zeit sein kann).

    unter direct3d hast du zwei wege die der treiber geht.
    1. du bist ein AAA titel, dann haben die treiber die kombinationen in ihrer datenbank und ersetzen deine shader durch diese
    2. du bist ein vanilla entwickler, dann bekommst du eine vanilla version vom shader und wenn du glueck hast, wird der zweite thread vom treiber die kombination im hintergrund optimieren (das was zu link zeit bei ogl passiert). wenn sich leute wundern, dass manche neue treiber soviel schneller bei fragment limitierten spielen sind als die vorherigen es waren -> ShaderDB.



  • rapso schrieb:

    dot schrieb:

    rapso schrieb:

    dot schrieb:

    Ja, ich vermute aber, dass es am Ende kaum einen Unterschied macht, ob man jetzt den Quelltext zusammenpappt oder Shaderfragmente "linked".

    man linkt keine shader fragmente, sondern die einzelnen shader stages. (esseiden latest ogl hat was neues was anders ist als das linken bisher).

    Das Linken der einzelnen Stages ist wohl eher eine rein theoretische Möglichkeit; ich bezweifle, dass das jenseits der API irgendeine Relevanz hat bzw. tatsächlich auch so umgesetzt ist oder jemals war, denn in Direct3D kann man seit je her die Shader der einzelnen Stages unabhängig voneinander setzen und in OpenGL 4.3 wurde genau das mit den Program Pipeline Objects afaik nun letztendlich auch exposed...

    tjo, deine zweifel sind valide aber leider falsch. wenn du lange schader hast, 'compilieren' die sehr schnell, jedoch dauert es durchaus lange sie zu linken (das gilt auch wenn du mit opengl ES 2 emulation arbeitest). mit ati ist das noch ertraeglich, mit nvidia kann es ne minute dauern ein paar zig shader zu linken (und ogl es 2 emulatoren unterstuetzen keine binaries, was echt eine scheiss turn around zeit sein kann).

    unter direct3d hast du zwei wege die der treiber geht.
    1. du bist ein AAA titel, dann haben die treiber die kombinationen in ihrer datenbank und ersetzen deine shader durch diese
    2. du bist ein vanilla entwickler, dann bekommst du eine vanilla version vom shader und wenn du glueck hast, wird der zweite thread vom treiber die kombination im hintergrund optimieren (das was zu link zeit bei ogl passiert). wenn sich leute wundern, dass manche neue treiber soviel schneller bei fragment limitierten spielen sind als die vorherigen es waren -> ShaderDB.

    Ich glaube du hast das vertauscht.
    Das Compilieren der Shader kann Minuten dauern, das linken geht dann in Millisekunden. Das linken ist doch nur die Überspielung des compilierten Codes in die Ausführungseinheiten der GPU. Viele Spiele linken hunderte verschiedener Shader, je nachdem welcher Effekt gerade gezeigt werden soll.


  • Mod

    MisterX schrieb:

    rapso schrieb:

    dot schrieb:

    rapso schrieb:

    dot schrieb:

    Ja, ich vermute aber, dass es am Ende kaum einen Unterschied macht, ob man jetzt den Quelltext zusammenpappt oder Shaderfragmente "linked".

    man linkt keine shader fragmente, sondern die einzelnen shader stages. (esseiden latest ogl hat was neues was anders ist als das linken bisher).

    Das Linken der einzelnen Stages ist wohl eher eine rein theoretische Möglichkeit; ich bezweifle, dass das jenseits der API irgendeine Relevanz hat bzw. tatsächlich auch so umgesetzt ist oder jemals war, denn in Direct3D kann man seit je her die Shader der einzelnen Stages unabhängig voneinander setzen und in OpenGL 4.3 wurde genau das mit den Program Pipeline Objects afaik nun letztendlich auch exposed...

    tjo, deine zweifel sind valide aber leider falsch. wenn du lange schader hast, 'compilieren' die sehr schnell, jedoch dauert es durchaus lange sie zu linken (das gilt auch wenn du mit opengl ES 2 emulation arbeitest). mit ati ist das noch ertraeglich, mit nvidia kann es ne minute dauern ein paar zig shader zu linken (und ogl es 2 emulatoren unterstuetzen keine binaries, was echt eine scheiss turn around zeit sein kann).

    unter direct3d hast du zwei wege die der treiber geht.
    1. du bist ein AAA titel, dann haben die treiber die kombinationen in ihrer datenbank und ersetzen deine shader durch diese
    2. du bist ein vanilla entwickler, dann bekommst du eine vanilla version vom shader und wenn du glueck hast, wird der zweite thread vom treiber die kombination im hintergrund optimieren (das was zu link zeit bei ogl passiert). wenn sich leute wundern, dass manche neue treiber soviel schneller bei fragment limitierten spielen sind als die vorherigen es waren -> ShaderDB.

    Ich glaube du hast das vertauscht.
    Das Compilieren der Shader kann Minuten dauern, das linken geht dann in Millisekunden. Das linken ist doch nur die Überspielung des compilierten Codes in die Ausführungseinheiten der GPU. Viele Spiele linken hunderte verschiedener Shader, je nachdem welcher Effekt gerade gezeigt werden soll.

    wie ich schon sagte, erst wenn alle shader bekannt sind, kann der treiber diese kompilieren. wenn du ein fragment program hast das nur eine farbe aus den interpolatoren liest, muss das vertexprogram nicht mehr als das berechnen und kann dann entsprechend optimiert werden. auf der anderen seite, wenn ein vertexprogram z.b. 1.f als referenz value fuer 'kill' uebergibt, wird das fragment programm nie ein pixel verwerfen und der compiler kann entsprechend 'kill' rausoptimieren und auch die culling optimierungen nach dem rasterizer eingeschaltet lassen.
    das weiss der compilierungsaufruf nicht im voraus, zumal du ein und dasselbe program mit mehreren anderen kombinieren kannst, erst das "linken" compiliert.

    aber ich nehmen gerne nochmal die timmings meiner engine beim starten (bei gelegenheit, nicht gerade heute abend), vielleicht irre ich mich ja fatal (in erinnerung und logik).


Anmelden zum Antworten