Registriert: Di Sep 06, 2005 18:34 Beiträge: 362 Wohnort: Hamburg
Hey,
interessante Idee … ich frage mich aber ob das nicht unnötig komplex ist? Was genau wollt ihr denn damit erreichen?
In meinem aktuellen Projekt habe ich nur include-directives und ein paar vordefinierte defines implementiert und komme super damit klar. Dadurch kann ich große include-dateien machen die sehr viel code enthalten der am Ende raus kompiliert wird weil der compiler alles raus schmeißt was keinen Beitrag zur Ausgabe hat.
Euren Ansatz mit dem Pre-Compiler, also dem eigentlichen compiler diesen Optimierungsschritt abzunehmen, verstehe ich ehrlich gesagt nicht.
_________________ Der Mensch hat neben dem Trieb der Fortpflanzung und dem zu essen und zu trinken zwei Leidenschaften: Krach zu machen und nicht zuzuhören. (Kurt Tucholsky)
Schwabbeldiwapp, hier kommt die Grütze. (Der Quästor)
Das sieht sehr praktisch aus. Mich würden bei so etwas Code Elemente wie, {$FUNC 'CalcColor' 'void'} eher stören. Das wird am Ende ja wieder Eins-zu-Eins zu glsl übersetzt, warum behält man dann nicht einfach die gegebene glsl-Syntax und parsed diese?
Registriert: Di Apr 29, 2008 18:56 Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,
@Shaijan: wenn Alles in einem Shader steht, kann man das kaum noch debuggen oder optimieren, weil man erst jedesmal gucken muss was wegoptimiert werden würde ud was nicht. Es ist einfach übersichtlicher das im PreCompiler aufzuräumen.
@mori: Das gefällt uns auch noch nicht wirklich. Aber der PreCompiler muss irgendwoher wissen, das eine Funktion folgt. Diese wird dann nur im finalen Shader eingefügt, wenn diese auch wirklich aufgerufen wird. Wir brauchen da nen anderen Syntax, sonst müssten wir nen glsl Interpreter bauen um das sauber auszulesen. Daran hatten wir auch schon gedacht, aber das ist einfach zuviel / unnötige Arbeit.
Habe für meinen Shader eine Klasse umgebaut -ist hier auch irgendwo zu finden-, die mehrere Teilshader lädt und verwaltet. Das ist aber etwas unübersichtlich und teilweise auch ganz schön kompliziert.
Registriert: Di Apr 29, 2008 18:56 Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,
ja das ist sowas ähnliches wie das Projekt von Aya. Aber wenn ich das bei ihr richtig verstanden hab, dann berechnen ihre Funktionen noch etwas und geben das dann aus. Unser Projekt wird mehr oder weniger nur ein besseres IFDEF das eine Art Klassenbaum aufbaut. Der eigentliche Code der geschrieben wird landet 1 zu 1 im Shader.
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2622 Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich würde mal CG von Nvidia bzw. nvFX von der Open Source Community empfehlen an zu gucken. nvFX nvFX Vortrag Ich hab selber noch nicht mit nvFX gearbeitet, weil wir bisher immer cg verwendet haben aber für private Projekte würde mir nvFX mehr zu sagen.
Alleine der Gedanke, ein GLSL fähigen Parser zu schreiben und den dann so zu erweitern, dass er zusätzliche Post-Prozessor Befehle kennt würde mir wiederstreben. Da man für jede neue Spec ihn wieder an fässt. Der Ansatz von nvFX ist mir da lieber, die gucken sich den Shader nicht an aber haben ein eigenen Parser generiert :\
Ich würde eher auf Json setzen und mit Pässen arbeiten, das hat sich in der Vergangenheit als ausreichend erwiesen. Man baut Pässe und ein Pass bekommt Bedingungen wie z.B. ein Shader Model minimum, ID und Shader Code. Logik auf ein Json Baum auf zu bauen mach ich ein mal und egal wie die Shader-Sprache sich ändert, ich muss den Code nicht an fassen, weil ich um den Shader herrum die Logik baue. Das sehe ich an eurem aktuellem Konzept als größtes Problem.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Di Apr 29, 2008 18:56 Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,
ich glaub du hast das missverstanden, oder ich hab's nicht genau genug beschrieben. Wir bauen _keinen_ glsl Parser. Im Gegenteil, wir parsen gar keinen glsl Code. Das System kennt verschiedene Code-Teile (Funktionen, globale Variablen, Constanten, Uniforms und Varyings). Aus diesen Code-Teilen wird dann ein Shader zusammen gesetzt. Dabei werden nur die Code-Teile eingefügt, die gewisse Bedingungen erfüllen. Welche Bedingungen das sind legt man mit Attributen und If-Blöcken fest. Die Attribute können in der Applikation gesetzt/geändert werden und werden dann im If-Block ausgewertet. Die Code-Teile bilden eine Art Klasse, die alles zusammenfasst. Die "Klassen" kann man untereinander vererben und somit gewisse Code-Teile überschreiben und/oder erweitern. Speziell für unsere Deferred Engine würde der Klassenbaum dann ungefähr wie folgt aussehen:
Code:
Globale Shader Klasse
Pass 1
Technik 1
Technik 2
...
Technik n
Pass 2
...
Die Techniken sind sowas wie Phong-Light, Blur, Normal-Mapping usw. Der Shader-Pass leitet dann eine "Klasse" von diesen Techniken ab (Stichwort: Mehrfachvererbung) und bringt diese in der richtigen Reihenfolge zusammen. Zum Schluss kommt die globale Shader Klasse die dann die einzelnen Passes miteinander vereint. Das Ganze ist komplett unabhängig vom eigentlichen Shader-Code. Das einzige was von der Shader-Sprache abhängig ist, sind die Konstanten und Variablen, da diese vom System in der jeweiligen Sprache generiert werden müssen. Da geb ich dir Recht, das ist unschön. Vlt sollten wir das dahingehend ändern, das es wirklich komplett sprachunabhängig wird. Dann könnte man das System auch für andere Shader-Sprachen nutzen.
Registriert: Di Apr 29, 2008 18:56 Beiträge: 1213
Programmiersprache: Delphi/FPC
Das ist richtig. Alles was die Form {$ ... } hat wird vom PreCompiler interpretiert. Der glsl-Code dazwischen bleibt davon komplett unberührt und wird als normaler Text interpretiert. Diese Textblöcke werden dann entsprechend zusammengesetzt und dann mit dem normalen glsl Compiler übersetzt und gelinkt.
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2622 Wohnort: Berlin
Programmiersprache: Go, C/C++
Ja genau das meinte ich doch auch mit Parser.
Unabhängig von der Lösung die ich vorher gepostet hab mal was mich an dem aktuellen Draft stört. Shader Code und Konfigurationsdaten vermischen sich, es wird logik in den Beschreibungen abgebildet und es ist durch die Wahl des Markup schwer zu lesen. Ich finde, dass ein Shader ein für sich selbst stehender Block sein sollte, wo keine Metasprache oder Scripting drin vor kommen sollte. Im Beispiel wäre es folgender Bereich.
Das würde sehr klar machen, was Funktionalität von eurem glsl PreCompiler ist und was von GLSL selber kommt. Ein Start und End Makierung würden helfen.
Ich mag Data-Driven Design und das ganze richt stark nach DDD aber
Code:
{$IF 'colormap'}...{$ELSE}...{$END}
ist Scripting und dies macht es komplizierter zu debuggen, wenn sowas komplexer wird. Es macht es auch wesentlich schwerer zu verstehen, vorallem, wenn man nicht gerade die Grammatik genau kennt. Der Vorteil ist, dass du die einzelnen Daten sehr kompakt zusammen gebracht hast. Alternativ könntest du eine mehrdimensionale Statemachine aufbauen. Jedes Attribut bringt eine Dimension hinzu und wie bei C++ Templates würde ich die Fälle spezialisieren, die du brauchst.
Die Variante ohne states ist wie ein Template bei C++, alle State Kombinationen treffen auf diese zu, alle weiteren spezialisieren bestimmte State kombinationen. Man merkt sich intern also das Template und die spezialisierungen.
Das Markup finde ich ein bisschen gruselig, ich bin eigentlich xml und json gewohnt aber das ist geschmacks sache, wenn alle eure formate dieses Markup benutzen, dann ist es okey.
Wir verwenden auf arbeit für NormalMap, SpecMap, Diffusemap default Texturen, dass sind 4x4 Pixel DXT1-5 Maps. Dadurch haben wir nicht zig Shadervarianten und müssen für alle kombinationen nur ein Shader binden und ein 4x4Pixel DXT1-5 hat nur ein Texel zugriff und kostet weniger als Shader bindings, da die das Batching massiv vereinfachen.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Di Apr 29, 2008 18:56 Beiträge: 1213
Programmiersprache: Delphi/FPC
Was den Syntax des Markups angeht geb ich dir Recht, der gefällt uns auch noch nich richtig (wie oben schon erwähnt). Den haben wir bis jetzt nur in dem PreCompiler und da der neue eh noch nicht implementiert ist, lässt sich das auch ohne Probleme noch ändern. XML passt aber meiner Meinung nach auch nicht richtig, bzw. ich konnte mich damit bis jetzt noch nicht anfreunden.
Die $GLSL-Tags sind ne gute Idee, die werden wir aber denke ich eher als {$FUNC}dependencies here{$BEGIN}code here{$END} umsetzten. So wie man das von Pascal/Delphi kennt.
Was die mehrdimensionale Statemachine angeht, kann ich deine Einwände verstehen, aber das macht den Shader-Code meiner Meinung nach unwartbar, da man sehr viel doppelten Code hat. Beim Debuggen haben wir es bis jetzt so gemacht, das wir uns den generierten Shader in eine Temp-Datei gespeichert haben, um zu sehen was fehlt. Mit entsprechenden Kommentaren im Code, aus welcher Shader-Datei der Code ursprünglich stammt, konnte man das dann schnell nachvollziehen. Das ging bis jetzt eigentlich ganz gut.
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2622 Wohnort: Berlin
Programmiersprache: Go, C/C++
Als ich euer Beispiel gelesen habe, hatte ich immer ein Node-Graph vor Augen, den ich verfolgt habe. In Unity3D und Unreal Engine 3-4 kann man ja die Shader über Nodes zusammen klickern und bekommt dann für die einzelnen Nodes Theoretische Laufzeiten, Kompilierzeit für den Shader und eine Vorschau. Dabei will ich nicht sagen, dass ihr ein Tool bauen sollt, sondern dass ich mir schon eine Gedächnisstütze genommen habe um den Shader zu lesen. Jeder Branch macht es schwerer zu verstehen, von daher war mein Vorschlag für jede genutzte Kombination den vollständigen Shader zu haben, weil dann keine Branches mehr kommen und alles auf einem Blick zu sehen ist.
Wie gesagt, ich mag lieber alles auf ein Blick und einfacher zu lesen als es kompakt zu bekommen. Der Compiler wird am Ende es kompakt machen und man kann ja auch immer noch weitere Funktionen bauen um nicht so viel Code zu doppeln.
Mal eine ganz andere Möglichkeit. The Order 1886 benutzt Material Templates und ein eigenen Compiler. Video zu slides Slides Die benutzen wie Bitsquid Materialien Description, dann weisen die den Inputs Daten zu und der Compiler baut dann Shader.
SpeedTree baut es auch über ein kleines Tool, man hat eine Template Sammlung, wo alle Shader für D3D9-11, OGL, OGLES, XBOX und so weiter drin sind und das Tool fügt das ganze zusammen. Die verwenden fx und das tool tut vorher noch marker verarbeiten. $DEFINES$ $HEADER$ $PIXEL_MAIN_FUNCTION_DECL$ Das war dann auch schon so ziemlich alles und der cg code besteht aus unmengen von if, else, endif und includes. Die Inline shader sind selbst erklärend und die Templates sind Sammlungen von Funktionen. Das System finde ich aber auch blöd ^^
Ich selber schreibe mir glsl code und zerlegt den in funktionen und mit Pre-Processor Anweisungen von GLSL selber regel ich das ganze. GLSL110 Preprocessor Specs Allerdings hab ich bisher auch nicht mit Physical based rendering und defferred shading gearbeitet, wo die variation größer wird.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7804 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
So wie ich das sehe trifft das Thema auf großes Interesse, aber die konkrete Umsetzung ist noch Optimierungsfähig. Eventuell wird mit dem Input ja noch ein richtiges burner tool draus.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Ist diese uglcShaderFile auch außerhalb eures Projektes nutzbar? Wie funktioniert das ganze denn, irgendwie bin ich nicht ganz durchgestiegen? Geht auch Delphi? Gruss Jens
Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.