R
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).