GL-Shader



  • Ein paar Fragen zu Opengl Schader in GlSl und zwar würde ich die Shadersprache gerne syntaktisch etwas erweitern, z.b. um eine Includeanweisung.

    Wen ich das richtig im Kopf habe werden Shader linear gelinkt, d.h. es gibt keine includefunktion für externe dateien richtig?

    Das zweite wäre dass jedes Shader-Programm in sich geschlossen gelinkt wird, es also nicht möglich ist eine "bibliothek" in den speicher zu laden und zu referenzieren oder geht das irgendwie?

    Ist es möglich Shader als bytecode zu erzeugen und zu übermitteln (serialisierung)?

    Ist es möglich etwa eine Datei mit statischen Funktionen oder gar ein Klassenmodell zu realisieren?



  • Pria schrieb:

    Wen ich das richtig im Kopf habe werden Shader linear gelinkt, d.h. es gibt keine includefunktion für externe dateien richtig?

    Pria schrieb:

    Das zweite wäre dass jedes Shader-Programm in sich geschlossen gelinkt wird, es also nicht möglich ist eine "bibliothek" in den speicher zu laden und zu referenzieren oder geht das irgendwie?

    Du kannst mehrere Strings an glShaderSource() übergeben.

    Pria schrieb:

    Ist es möglich Shader als bytecode zu erzeugen und zu übermitteln (serialisierung)?

    Jaein, du kannst mittlerweile den Bytecode eines kompilierten Shaders abfragen und cachen, es gibt allerdings kein standardisiertes Bytecodeformat. Es ist also nicht möglich, GLSL Shader zusammen mit dem Rest der Anwendung zu bauen und dann in Bytecode-Form auszuliefern. Imo ist das einer der ganz großen Mängel die OpenGL noch aufweist, wo anders wäre das bereits seit über 10 Jahren die Standardvorgehensweise...

    Pria schrieb:

    Ist es möglich etwa eine Datei mit statischen Funktionen oder gar ein Klassenmodell zu realisieren?

    Du kannst natürlich einen Präprozessor oder gar einen vollständigen Compiler für eine eigene Sprache entwickeln, der nach GLSL kompiliert. Cg macht das z.B. so...



  • dot schrieb:

    Du kannst mehrere Strings an glShaderSource() übergeben.

    Aber binärverweise in den speicher gehen warscheinlich nicht oder? Also quasi einmal die Bib einladen und dann mit anderen shadern nur noch drauf verweisen

    dot schrieb:

    Jaein, du kannst mittlerweile den Bytecode eines kompilierten Shaders abfragen und cachen, es gibt allerdings kein standardisiertes Bytecodeformat. Es ist also nicht möglich, GLSL Shader zusammen mit dem Rest der Anwendung zu bauen und dann in Bytecode-Form auszuliefern. Imo ist das einer der ganz großen Mängel die OpenGL noch aufweist, wo anders wäre das bereits seit über 10 Jahren die Standardvorgehensweise...

    Es würde ja bestimmt schon reichen wenn die Shader beim erstmaligen ladevorgang des Programms in eine Art Cache vorkompiliert würden und dann, natürlich solange sich die Hardware nicht grundlegend ändert, daraus eben geladen werden.

    dot schrieb:

    Du kannst natürlich einen Präprozessor oder gar einen vollständigen Compiler für eine eigene Sprache entwickeln, der nach GLSL kompiliert. Cg macht das z.B. so...

    [/quote]

    Ja das hatte ich onehin vor. In C# hatte ich das schonmal gemacht um die Syntax in etwa so abzuändern

    #pragma core glsl
    
    varying float xpos;
    varying float ypos;
    varying float zpos;
    
    #define Fragment
    {
       void main(void)
       {
          gl_FragColor = vec4 (1.0  * (vec3(xpos,ypos,zpos)), 1.0);
       }
    }
    
    #define Vertex
    {
       void main(void)
       {
         gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    
         xpos = clamp(gl_Vertex.x,0.0,1.0);
         ypos = clamp(gl_Vertex.y,0.0,1.0);
         zpos = clamp(gl_Vertex.z,0.0,1.0);
       }
    }
    

    Ich wollte das gerne ein wenig komfortabler gestalten und abschließend zu GlSl Source "vorkompilieren". Ein eigener richtiger Kompiler wie Cg fällt weg, da Cg im gegensatz zu GlSl nicht so gute Hardwareoptimierung machen kann wie die Build-In variante der Grafikkarte



  • Pria schrieb:

    #pragma core glsl
    
    varying float xpos;
    varying float ypos;
    varying float zpos;
    
    #define Fragment
    {
       void main(void)
       {
          gl_FragColor = vec4 (1.0  * (vec3(xpos,ypos,zpos)), 1.0);
       }
    }
    
    #define Vertex
    {
       void main(void)
       {
         gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    
         xpos = clamp(gl_Vertex.x,0.0,1.0);
         ypos = clamp(gl_Vertex.y,0.0,1.0);
         zpos = clamp(gl_Vertex.z,0.0,1.0);
       }
    }
    

    Sieht sehr aehnlich aus wie der Ansatz von GLSW...

    dot schrieb:

    Es ist also nicht möglich, GLSL Shader zusammen mit dem Rest der Anwendung zu bauen und dann in Bytecode-Form auszuliefern. Imo ist das einer der ganz großen Mängel die OpenGL noch aufweist, wo anders wäre das bereits seit über 10 Jahren die Standardvorgehensweise...

    In wie fern macht es einen Unterschied, ob man Source- oder "Byte"-Code ausliefert?



  • hellihjb schrieb:

    In wie fern macht es einen Unterschied, ob man Source- oder "Byte"-Code ausliefert?

    Einen Unterschied an sich macht es erstmal keinen, was ich als puren source habe muss ich aber erst noch durch den compiler und linker jagen, während das beim bytecode eben komplett entfällt



  • Pria schrieb:

    Einen Unterschied an sich macht es erstmal keinen, was ich als puren source habe muss ich aber erst noch durch den compiler und linker jagen, während das beim bytecode eben komplett entfällt

    Das waere zwar ganz toll, geht aber leider so nicht.
    Verschiedene Grafikkarte haben teils sehr unterschiedliche Architekturen und benoetigen voellig anderen Code um diese optimal auszulasten.
    Besagter Bytecode muss als auf jeden Fall auch nochmal durch den Shader-Compiler.



  • das mit sicherheit, die Frage die im Raum steht ist doch ob es sinn macht den Bytecode auszuliefern, wie der letztendlich auf die entsprechende Hardware umgemünzt wird, stand ja nicht zur debatte.

    Die Idee eines vorkonstruirten Shader-Caches, der beim ersten Start der Anwendung erzeugt und danach bei jedem weiteren Start nur noch in die Hardware geladen wird gefällt mir allerdings gerade ganz gut.

    Sicherheitsmechanismen hin oder her aber vom Grundgedanken müsste das eigentlich gehen.


  • Mod

    gaengig ist dass man sich vom driver vendor name, version usw. besorgt und dann einen shader cache anlegt, die naechsten male beim starten leadt man nur noch vom cache falls die info ueber den driver usw. sich nicht veraendert haben.



  • Pria schrieb:

    Ich wollte das gerne ein wenig komfortabler gestalten und abschließend zu GlSl Source "vorkompilieren". Ein eigener richtiger Kompiler wie Cg fällt weg, da Cg im gegensatz zu GlSl nicht so gute Hardwareoptimierung machen kann wie die Build-In variante derGrafikkarte

    Abgesehen davon, dass Cg zu GLSL kompiliert, würde mich interessieren, an was für konkrete Optimierungen du da denkst. Das ursprüngliche "Compile and Link" Model von GLSL ist zwar theoretisch nett, aber die Tatsache, dass Shader für verschiedene Stages in anderen APIs immer schon unabhängig voneinander variiert werden konnten und dieses Feature mit Program Pipeline Objects in OpenGL 4.3 nun schlussendlich auch nachgerüstet wurde, zeigt wohl, dass etwaige, theoretisch vorstellbaren Vorteile eines solchen Modells wohl kaum von praktischer Relevanz sein dürften...

    hellihjb schrieb:

    dot schrieb:

    Es ist also nicht möglich, GLSL Shader zusammen mit dem Rest der Anwendung zu bauen und dann in Bytecode-Form auszuliefern. Imo ist das einer der ganz großen Mängel die OpenGL noch aufweist, wo anders wäre das bereits seit über 10 Jahren die Standardvorgehensweise...

    In wie fern macht es einen Unterschied, ob man Source- oder "Byte"-Code ausliefert?

    Das macht einen gewaltigen Unterschied. Schon allein, weil du dir praktisch sicher sein kannst, dass irgendjemand da draußen einen Grafiktreiber hat, der deinen GLSL Code nicht kompilieren kann. Jeder, der schon ernsthaft mit OpenGL gearbeitet hat, kann dir davon wohl ein Lied singen. Bei OpenGL ist man ja rein prinzipiell meist schon stärker den Launen der Grafiktreiber ausgeliefert und GLSL erweitert das Problem gleich um eine ganze Dimension. Wenn ich z.B. nach ein paar Tagen mal wieder unterwegs was arbeiten möchte und meinen Laptop mit ATI Grafikkarte auspacke, weiß ich schon vorher, dass ich die nächste Stunde damit verbringen werd, erstmal jeden zweiten Shader nachzuwürzen, um ihn dem heiklen Gaumen meines Grafiktreibers schmackhaft zu machen. Denn GLSL Compiler im Grafiktreiber bedeutet, dass dein Code nicht von einem, nicht von zwei, nicht von zehn, sondern von einer unglaubliche Anzahl verschiedenster Versionen von verschiedenen Compilern von allen möglichen Grafikkartenherstellern der Welt akzeptiert werden muss, jede mit ihren individuellen Bugs und Eigenheiten...

    Abgesehen davon, will man, z.B. in kommerziellen Anwendungen, einfach aus Prinzip schon nicht unbedingt Source Code ausliefern.

    Und kompilieren einer Hochsprache zur Laufzeit beim Endkunden bedeutet nicht nur ungeahnte Möglichkeiten für Dinge, schiefzulaufen, sondern vor allem auch wahnsinnig viel verschwendete Zeit. Wie gesagt ist es mittlerweile zumindest möglich, einmal kompilierte Shader zu cachen, früher musste man tatsächlich bei jedem Programmstart alle Shader direkt vom Source weg neu kompilieren. Ich kann echt nicht nachvollziehen, wie jemand das jemals für eine gute Idee halten konnte.

    Auch hat man generell überhaupt keine Ahnung, wie es um die Qualität des generierten Maschinencode steht. Es gibt iirc zwar ein paar herstellerspezifische Extensions um an den Assemblercode ranzukommen, aber rein prinzipiell ist die Bandbreite möglicher Ergebnisse praktisch unbegrenzt...

    hellihjb schrieb:

    Pria schrieb:

    Einen Unterschied an sich macht es erstmal keinen, was ich als puren source habe muss ich aber erst noch durch den compiler und linker jagen, während das beim bytecode eben komplett entfällt

    Das waere zwar ganz toll, geht aber leider so nicht.
    Verschiedene Grafikkarte haben teils sehr unterschiedliche Architekturen und benoetigen voellig anderen Code um diese optimal auszulasten.
    Besagter Bytecode muss als auf jeden Fall auch nochmal durch den Shader-Compiler.

    Spätestens seit auch AMD nun von VLIW abgekommen ist und zu skalaren Architektur gewechselt hat, sind die Unterschiede wohl nichtmehr ganz so groß. Und selbst wenn: Da die Sache mit dem Bytecode seit jeher eigentlich die übliche Vorgehensweise ist, kannst du wohl davon ausgehen, dass alle erfolgreichen GPU Architekturen sehr effizient damit gefüttert werden können. Und der Bytecode muss natürlich noch für die jeweilige Hardware übersetzt werden; dafür braucht es aber keinen Hochsprachencompiler, sondern eher sowas wie einen JIT, was wesentlich schneller geht, da viele aufwändige Dinge wie Parsing, Code Generation und high-level Optimierungen bereits einmal beim Erzeugen des Bytecode gemacht wurden. Insbesondere: Ein offline Compiler kann sich praktisch beliebig viel Zeit zum Optimieren leisten. Und ich persönlich will Compilerfehler beim Build meiner Anwendung sehen und nicht zu Laufzeit...



  • Da es noch niemand gelinkt hat, dies ist die GL Erweiterung mit welcher man GLSL Binarys speichern und laden kann: GL_ARB_get_program_binary

    Das Laden funktioniert nur, wenn Binary Format und die Hardware/Treiber/etc... zueinander passen. Ansonsten muss neu compiliert werden.


  • Mod

    dot schrieb:

    Pria schrieb:

    Ich wollte das gerne ein wenig komfortabler gestalten und abschließend zu GlSl Source "vorkompilieren". Ein eigener richtiger Kompiler wie Cg fällt weg, da Cg im gegensatz zu GlSl nicht so gute Hardwareoptimierung machen kann wie die Build-In variante derGrafikkarte

    Abgesehen davon, dass Cg zu GLSL kompiliert

    das ist nur eine option die spaeter hinzukam, Cg hat urspruenglich zum OpenGL shader assembler und zu NVidias assembler extensions compiliert. das GLSL sah auch sehr fishy aus, als ob die nur den assembler genommen haetten und wieder c-style code rauswarfen.

    Das ursprüngliche "Compile and Link" Model von GLSL ist zwar theoretisch nett, aber die Tatsache, dass Shader für verschiedene Stages in anderen APIs immer schon unabhängig voneinander variiert werden konnten und dieses Feature mit Program Pipeline Objects in OpenGL 4.3 nun schlussendlich auch nachgerüstet wurde, zeigt wohl, dass etwaige, theoretisch vorstellbaren Vorteile eines solchen Modells wohl kaum von praktischer Relevanz sein dürften...

    das sind keine theoretischen vorteile, sondern was der treiber eh macht. alle stages der pipeline muessen zueinander passen, die meisten resourcen wie interpolatoren sind dynamisch allokiert. nutzt du weniger resourcen, kannst du mehr dinge 'in flight' haben, entsprechend gibt es nicht einfach irgendwo einen default wert den der pixelshader liest wenn der vertexshader den nicht ausgibt und es gibt keine register ohne boden in die der vertexshader schreibt ohne dass der pixelshader die nutzt, der treiber muss die shader dann so 'patchen' dass beides zusammenpasst.
    das opengl model reflektiert das halt besser, wenn auch es unkomfortabler zu nutzen ist, du sparst eine menge treiber zeit und kannst, statt nur gepatchte shader zu haben, sie schon aufeinander optimieren (also wenn der pixelshader einen wert nicht nutzt, muss der vertexshader alle relevanten operationen garnicht erst machen). deswegen braucht compilieren bei ogl 0 zeit und das linken dauert dann uU ein paar sekunden pro shader.

    hellihjb schrieb:

    dot schrieb:

    Es ist also nicht möglich, GLSL Shader zusammen mit dem Rest der Anwendung zu bauen und dann in Bytecode-Form auszuliefern. Imo ist das einer der ganz großen Mängel die OpenGL noch aufweist, wo anders wäre das bereits seit über 10 Jahren die Standardvorgehensweise...

    In wie fern macht es einen Unterschied, ob man Source- oder "Byte"-Code ausliefert?

    Das macht einen gewaltigen Unterschied. Schon allein, weil du dir praktisch sicher sein kannst, dass irgendjemand da draußen einen Grafiktreiber hat, der deinen GLSL Code nicht kompilieren kann. Jeder, der schon ernsthaft mit OpenGL gearbeitet hat, kann dir davon wohl ein Lied singen. Bei OpenGL ist man ja rein prinzipiell meist schon stärker den Launen der Grafiktreiber ausgeliefert und GLSL erweitert das Problem gleich um eine ganze Dimension. Wenn ich z.B. nach ein paar Tagen mal wieder unterwegs was arbeiten möchte und meinen Laptop mit ATI Grafikkarte auspacke, weiß ich schon vorher, dass ich die nächste Stunde damit verbringen werd, erstmal jeden zweiten Shader nachzuwürzen, um ihn dem heiklen Gaumen meines Grafiktreibers schmackhaft zu machen. Denn GLSL Compiler im Grafiktreiber bedeutet, dass dein Code nicht von einem, nicht von zwei, nicht von zehn, sondern von einer unglaubliche Anzahl verschiedenster Versionen von verschiedenen Compilern von allen möglichen Grafikkartenherstellern der Welt akzeptiert werden muss, jede mit ihren individuellen Bugs und Eigenheiten...

    das ist eine behauptung die du nicht wirklich verifizieren kannst, du kannst nicht wissen, ob der parser oder backend compiler die probleme macht. das parsen und das generieren des AST ist auch nichts das problem, intel (fuer GLSL&openCL(uebrigens auch fuer deren C++ compiler), NVidia (fuer GLSL,Cg,Cuda&OpenCL) nutzen meines wissens nach edgals front end, ich glaube sogar intellisense in VS wurde darauf umgestellt. das ding ist super schnell und ich waere sehr ueberrascht, wenn das source code parsen das problem waere.
    ich glaube dass du auch mit bytecode shadern in glsl die abstuertze und probleme haettest.

    Abgesehen davon, will man, z.B. in kommerziellen Anwendungen, einfach aus Prinzip schon nicht unbedingt Source Code ausliefern.

    👍

    Und kompilieren einer Hochsprache zur Laufzeit beim Endkunden bedeutet nicht nur ungeahnte Möglichkeiten für Dinge, schiefzulaufen, sondern vor allem auch wahnsinnig viel verschwendete Zeit.

    ich glaube das musst du in relation zu der restlichen arbeit sehen, 10kb GLSL zu parsen dauert sicherlich weit unter 1ms, das optimieren usw. kann dann sekunden dauern, du wuerdest vermutlich nichts an laufzeitverhaltensaenderung merken wenn die shader im bytecode waeren.

    Wie gesagt ist es mittlerweile zumindest möglich, einmal kompilierte Shader zu cachen, früher musste man tatsächlich bei jedem Programmstart alle Shader direkt vom Source weg neu kompilieren. Ich kann echt nicht nachvollziehen, wie jemand das jemals für eine gute Idee halten konnte.

    da bekommst du die shader aber schon nach der optimierung, z.b. PTX source code im falle von NVidia. bytecode muesste jedesmal wieder durch den optimizer usw. du wuerdest nur das parsen was wenig zeit zieht sparen.

    Auch hat man generell überhaupt keine Ahnung, wie es um die Qualität des generierten Maschinencode steht. Es gibt iirc zwar ein paar herstellerspezifische Extensions um an den Assemblercode ranzukommen, aber rein prinzipiell ist die Bandbreite möglicher Ergebnisse praktisch unbegrenzt...

    du kannst seit ein paar versionen den compilierten shader cachen, im falle von nvidia ist es normal lesbarer assembler source, das gleiche gilt fuer OpenCL.

    hellihjb schrieb:

    Pria schrieb:

    Einen Unterschied an sich macht es erstmal keinen, was ich als puren source habe muss ich aber erst noch durch den compiler und linker jagen, während das beim bytecode eben komplett entfällt

    Das waere zwar ganz toll, geht aber leider so nicht.
    Verschiedene Grafikkarte haben teils sehr unterschiedliche Architekturen und benoetigen voellig anderen Code um diese optimal auszulasten.
    Besagter Bytecode muss als auf jeden Fall auch nochmal durch den Shader-Compiler.

    Spätestens seit auch AMD nun von VLIW abgekommen ist und zu skalaren Architektur gewechselt hat, sind die Unterschiede wohl nichtmehr ganz so groß. Und selbst wenn: Da die Sache mit dem Bytecode seit jeher eigentlich die übliche Vorgehensweise ist, kannst du wohl davon ausgehen, dass alle erfolgreichen GPU Architekturen sehr effizient damit gefüttert werden können. Und der Bytecode muss natürlich noch für die jeweilige Hardware übersetzt werden; dafür braucht es aber keinen Hochsprachencompiler, sondern eher sowas wie einen JIT, was wesentlich schneller geht, da viele aufwändige Dinge wie Parsing, Code Generation und high-level Optimierungen bereits einmal beim Erzeugen des Bytecode gemacht wurden. Insbesondere: Ein offline Compiler kann sich praktisch beliebig viel Zeit zum Optimieren leisten. Und ich persönlich will Compilerfehler beim Build meiner Anwendung sehen und nicht zu Laufzeit...

    das ist nicht so ganz der fall.
    1. die GPUs unterscheiden sich an performance relevanten stellen schon sehr stark, selbst innerhalb derselben firma, sieht man daran dass spiele die super auf GTX680 laufen dann artefakte hatten beim release von der Titan. (ich glaube das war SC2 und TombRaider)
    2. abkehr von VLIW ist zwar gut aus compiler sicht, aber dennoch gibt es viel komplexitaet innerhalb des instruction sets. z.B. optimierte mir der letzte OpenCL compiler ein float3 array und ein float array zu einem float4 array, weil dann das indizieren zu einem float4 load wurde, trotz single-pipeline noch float4 instruktionen. genau so verhalten sich die GPUs sehr unterschiedlich was integer performance angeht (schau dir mal bitcoin mining benchmarks von ATI und NV an).
    3. der offline compiler versteckt oft sehr viel information die dem treiber helfen wuerden besseren code zu generieren, z.b. in zeiten von D3D9, als es keine divisionsfunktion gab, nur rcp und mul, genau wie dass normalize meistens in dot,rsq,mul zerlegt wurde. hardware hatte dafuer instruktionen. die treiber muessen sehr oft quasi reverse engineeren was der offline compiler wegoptimiert hat und dann besseren code fuer das eigentlich instruction set zu generieren. das ist mit ein grund weshalb neue treiber manchmal spiele 30% schneller machen (z.b. in Zeiten von G70 passiert).
    4. bytecode compilieren ist kein simples JIT, es wirkt nur so, weil die funktionen sofort zurueckspringen. in wirklichkeit wird tatsaechlich ein JIT gemacht als vorabversion, zudem wird dein shader in eine queue fuer ein compile thread gesteckt, der sich dann recht lange um deinen shader kuemmert, im hintergrund. wenn der shader fertig ist, fliegt der simple JIT shader raus.
    5. zu jedem grossen spiel wird ein neuer 'optimierter' treiber gebracht, dazu gehoert eine grosse shader datenbank wo die hersteller tatsaechlich offline und manchmall mit hilfe von engineers die optimierten shader erstellt haben, weil dein treiber lokal viel zu lange braeuchte um mit allen optimierungen die shader zu bauen. die letzten 10%-20% kosten viel rechenzeit. (kann bei shadern mit 500 instruktionen 10min compilierzeit sein um die 99% version zu bekommen).


Anmelden zum Antworten