DGL
https://delphigl.com/forum/

UnifomBlockObject
https://delphigl.com/forum/viewtopic.php?f=20&t=11450
Seite 1 von 4

Autor:  mathias [ Di Okt 27, 2015 20:13 ]
Betreff des Beitrags:  UnifomBlockObject

Ich habe eine kleine Classe für UBO geschrieben.
Wen ich nur ein UBO im Project habe, dann funktioniert das Ganze auch.
Erzeuge ich aber ein zweites UBO, dann kommen sie gegenseitig in die Quere.

Code:
  1. type
  2.  
  3.   { TUBO }
  4.  
  5.   TUBO = class(TObject)
  6.   private
  7.     buffer : GLuint;
  8.   public
  9.     constructor Create(Shader: TShader; UniformName: PGLchar);
  10.     destructor Destroy; override;
  11.  
  12.     procedure LoadBuffer(data: PGLvoid; size: GLsizeiptr);
  13.   end;
  14.  
  15.  
  16. implementation
  17.  
  18. { TUBO }
  19.  
  20. constructor TUBO.Create(Shader: TShader; UniformName: PGLchar);
  21. begin
  22.   inherited Create;
  23.   glGenBuffers(1, @buffer);
  24.  
  25.   glUniformBlockBinding(Shader.ID, glGetUniformBlockIndex(Shader.ID, UniformName), 0);
  26.   glBindBuffer(GL_UNIFORM_BUFFER, buffer);
  27. end;
  28.  
  29. destructor TUBO.Destroy;
  30. begin
  31.   glDeleteBuffers(1, @buffer);
  32.   inherited Destroy;
  33. end;
  34.  
  35. procedure TUBO.LoadBuffer(data: PGLvoid; size: GLsizeiptr);
  36. begin
  37.   glBufferData(GL_UNIFORM_BUFFER, size, data, GL_DYNAMIC_DRAW);
  38.   glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
  39. end;
  40.  
  41. end.    


In InitScene habe ich folgenden Aufruf:
Code:
  1.   UBOLight := TUBO.Create(Shader, 'allUniforms');
  2.   UBOLight.LoadBuffer(@Mat, SizeOf(Mat));
  3.  
  4.   UBOScale := TUBO.Create(Shader, 'scale');
  5.   UBOScale.LoadBuffer(@scale, SizeOf(scale));


allUniforms beinhalte diverse Lichtparameter, welche sich auch ändern lassen.
scale ist ein Test-wert welcher probehalber in der Matrix etwas verändert.
Das Problem ist aber sobald ich die beiden Zeilen mit UBOScale aufrufe, wird das Licht modifiziert, anstelle von scale.
Ich denke, das ich in der Classe etwas falsch mache.

Shader.ID zeigt auf die ProgrammID des Shaders.

So wie es aussieht, haben die dort ein ähnliches Problem; http://stackoverflow.com/questions/9155 ... rm-buffers

Autor:  glAwesome [ Mi Okt 28, 2015 11:38 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Der zweite Parameter von glBindBufferBase muss glaube ich das sein, was glGetUniformBlockIndex zurückgibt (nicht 0).

Edit: Okay, du verwendest glUniformBlockBinding, da weiß ich nicht, ob das noch stimmt. Habe mich selbst erst kürzlich halbwegs in UBOs eingearbeitet.

Autor:  mathias [ Mi Okt 28, 2015 15:01 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Wen es eine andere Lösung gibt, würde ich es anders machen.

Autor:  Sascha Willems [ Mi Okt 28, 2015 18:44 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Code:
  1. glUniformBlockBinding(Shader.ID, glGetUniformBlockIndex(Shader.ID, UniformName), 0);

Dein Binding Point ist immer 0, der muss bei mehreren Block Objekten aber jeweils eindeutig sein. Mit obigem Code benutzen beide UBOs den selben Binding Point, UboScale überschreibt also UboLight.

Die Bindungen müssen zum Shader passen :
Code:
  1. layout(binding = 0) uniform MeinUBOa
  2. ...
  3. layout(binding = 1) uniform MeinUBOb
  4.  

Autor:  mathias [ Mi Okt 28, 2015 19:51 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Zitat:
Die Bindungen müssen zum Shader passen :

Dies geht leider nicht, da wird Version 4.2 verlangt, aber ich habe nur 3.3.

Code:
  1. 0(18) : error C7532: layout qualifier 'binding' requires "#version 420" or later
  2. 0(18) : error C0000: ... or #extension GL_ARB_shading_language_420pack : enable


Aber für was sollte die BindingNr gut sein ?
Für was ist dann glGetUniformBlockIndex gut ?

Autor:  Sascha Willems [ Mi Okt 28, 2015 21:02 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Dann leg die Binding Points selbst fest :

Code:
  1.   glUniformBlockBinding(Shader.ID, glGetUniformBlockIndex(Shader.ID, UniformName), bindingPointA);
  2.   glBindBufferBase(GL_UNIFORM_BUFFER, bindingPointA, buffer);
  3.  
  4.   glUniformBlockBinding(Shader.ID, glGetUniformBlockIndex(Shader.ID, UniformName), bindingPointB);
  5.   glBindBufferBase(GL_UNIFORM_BUFFER, bindingPointB, buffer);
  6.  


Wichtig ist dass jeder Block sein eigenes Binding hat.

Autor:  mathias [ Mi Okt 28, 2015 21:04 ]
Betreff des Beitrags:  Re: UnifomBlockObject

So wie es aussieht, habe ich es jetzt zum laufen gebracht.

Code:
  1.   TUBO = class(TObject)
  2.   private
  3.     BindingPoint,
  4.     buffer: GLuint;
  5.   const
  6.     BPInc: GLuint = 0; // Hochzähler für BindingPoint
  7.   public
  8.     constructor Create(Shader: TShader; UniformName: PGLchar);
  9.     destructor Destroy; override;
  10.  
  11.     procedure UpdateBuffer(Data: PGLvoid; size: GLsizeiptr);
  12.   end;
  13.  
  14.  
  15. implementation
  16.  
  17. { TUBO }
  18.  
  19. constructor TUBO.Create(Shader: TShader; UniformName: PGLchar);
  20. var
  21.   id: GLint;
  22. begin
  23.   inherited Create;
  24.   BindingPoint := BPInc;
  25.   Inc(BPInc);
  26.   glGenBuffers(1, @buffer);
  27.   id := glGetUniformBlockIndex(Shader.ID, UniformName);
  28.   if id = -1 then begin
  29.     ShowMessage(UniformName + ' ' + IntToStr(id));
  30.     Exit;
  31.   end;
  32.   glUniformBlockBinding(Shader.ID, id, BindingPoint);
  33. end;
  34.  
  35. destructor TUBO.Destroy;
  36. begin
  37.   glDeleteBuffers(1, @buffer);
  38.   inherited Destroy;
  39. end;
  40.  
  41. procedure TUBO.UpdateBuffer(Data: PGLvoid; size: GLsizeiptr);
  42. begin
  43.   glBindBuffer(GL_UNIFORM_BUFFER, buffer);
  44.   glBufferData(GL_UNIFORM_BUFFER, size, Data, GL_DYNAMIC_DRAW);
  45.   glBindBufferBase(GL_UNIFORM_BUFFER, BindingPoint, buffer);
  46. end;


Die Fehler-Abfrage geht noch nicht, ich habe es von glGetUniformLocation übernommen, dort wird ein glint zurückgeliefert und bei glGetUniformBlockIndex ein gluint.
Aber ein gluint kann logischerweise niemals -1 haben.

Im Shader hatte ich auch noch einen kleine Fehler, beim Shader muss es dringend ein struct sein:
Code:
  1. uniform scale{  // geht nicht
  2.   float s;
  3. };
  4.  
  5. uniform float scale  // geht
  6.  



Und so kann ich jetzt zu Laufzeit die werte ändern:

Code:
  1. procedure TForm1.SpeedButton4Click(Sender: TObject);
  2. begin
  3.   scale := Random(40) - 20;
  4.  
  5.   UBOScale.UpdateBuffer(@scale, SizeOf(scale));
  6. end;
  7.  
  8. procedure TForm1.SpeedButtonClick(Sender: TObject);
  9. begin
  10.   MatNr := StrToInt(TSpeedButton(Sender).Caption);
  11.   Mat := Material[MatNr];
  12.  
  13.   UBOLight.UpdateBuffer(@Mat, SizeOf(Mat));
  14. end;

Autor:  mathias [ Mi Okt 28, 2015 21:21 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Zitat:
Dann leg die Binding Points selbst fest :

Habe ich jetzt eingebaut, so wie ich es gemacht sieht obiges Post, geht.

Danke für die Infos. :D

Wäre es noch zu empfehlen ein std140 in den Shader zu schreiben ?
Code:
  1. layout(std140) uniform scale{
  2.   float s;
  3. };  

Autor:  Sascha Willems [ Mi Okt 28, 2015 21:25 ]
Betreff des Beitrags:  Re: UnifomBlockObject

mathias hat geschrieben:
Wäre es noch zu empfehlen ein std140 in den Shader zu schreiben ?
Code:
  1. layout(std140) uniform scale{
  2.   float s;
  3. };  


Wenn es das ist was du willst, dann ja. Bei std140 wird nix wegoptimiert, was sehr praktisch ist wenn man Structs verwendet die dann in deiner Anwendung das selbe Layout haben wie im Shader. Die kann man dann 1:1 hochladen.

Details dazu : https://www.opengl.org/wiki/Interface_B ... ory_layout

Autor:  mathias [ Mi Okt 28, 2015 21:28 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Zitat:
was sehr praktisch ist wenn man Structs verwendet die dann in deiner Anwendung das selbe Layout haben wie im Shader.

Das wäre eigentlich das Ziel, sonst würde ist nicht viel Sinn machen.

Autor:  glAwesome [ Do Okt 29, 2015 16:19 ]
Betreff des Beitrags:  Re: UnifomBlockObject

mathias hat geschrieben:
Code:
  1. procedure TUBO.UpdateBuffer(Data: PGLvoid; size: GLsizeiptr);
  2. begin
  3.   glBindBuffer(GL_UNIFORM_BUFFER, buffer);
  4.   glBufferData(GL_UNIFORM_BUFFER, size, Data, GL_DYNAMIC_DRAW);
  5.   glBindBufferBase(GL_UNIFORM_BUFFER, BindingPoint, buffer);
  6. end;

Zum updaten von Buffer Objects solltest du aber glBufferSubData verwenden. glBufferData ist nur zum Anlegen des Puffers sinnvoll, weil es neuen Speicher alloziert, statt den alten weiterzuverwenden.

Autor:  mathias [ Do Okt 29, 2015 16:56 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Meinst du so sei es besser ?
Code:
  1. constructor TUBO.Create(Shader: TShader; UniformName: PGLchar; size: GLsizeiptr);
  2. var
  3.   id: GLuint;  // ????
  4. begin
  5.   inherited Create;
  6.   BindingPoint := BPInc;
  7.   Inc(BPInc);
  8.   glGenBuffers(1, @buffer);
  9.   id := glGetUniformBlockIndex(Shader.ID, UniformName);
  10.   if id = GLuint(-1) then begin
  11.     ShowMessage(UniformName + ' ' + IntToStr(GLint(id)));
  12.     Exit;
  13.   end;
  14.   glUniformBlockBinding(Shader.ID, id, BindingPoint);
  15.  
  16.   glBindBuffer(GL_UNIFORM_BUFFER, buffer);
  17.   glBufferData(GL_UNIFORM_BUFFER, size, nil, GL_DYNAMIC_DRAW);
  18. end;
  19.  
  20. procedure TUBO.UpdateBuffer(Data: PGLvoid; size: GLsizeiptr);
  21. begin
  22.   glBindBuffer(GL_UNIFORM_BUFFER, buffer);
  23.   glBufferSubData(GL_UNIFORM_BUFFER, 0, size, Data);
  24.  
  25.   glBindBufferBase(GL_UNIFORM_BUFFER, BindingPoint, buffer);
  26. end;  

Autor:  glAwesome [ Fr Okt 30, 2015 11:27 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Ja, so meinte ich das mit glBufferSubData. Bei glBindBufferBase bin ich mir unsicher. Müsste es nicht reichen, das nur einmal in Create aufzurufen?

Autor:  mathias [ So Nov 01, 2015 17:40 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Hier nochmals der komplette Code meine UBO-Classe.
Es funktioniert alles prächtig, solange ich nicht allzu viele UBOs habe.
glBufferSubData habe ich versuchsweise mal ausgeklammert, aber das Ergebnis ist das Gleiche.
Code:
  1. type
  2.  
  3.   { TUBO }
  4.  
  5.   TUBO = class(TObject)
  6.   private
  7.     BindingPoint, buffer: GLuint;
  8.   public
  9.     constructor Create(Shader: TShader; UniformName: PGLchar; size: GLsizeiptr);
  10.     destructor Destroy; override;
  11.  
  12.     procedure UpdateBuffer(Data: PGLvoid; size: GLsizeiptr);
  13.   end;
  14.  
  15.  
  16. implementation
  17.  
  18. { TUBO }
  19.  
  20. constructor TUBO.Create(Shader: TShader; UniformName: PGLchar; size: GLsizeiptr);
  21. const
  22.   BPInc: GLuint = 0;
  23. var
  24.   id: GLuint;
  25. begin
  26.   inherited Create;
  27.   BindingPoint := BPInc;
  28.   Inc(BPInc);
  29.   glGenBuffers(1, @buffer);
  30.   LogForm.add('UBO:' + IntToStr(BPInc));
  31.   id := glGetUniformBlockIndex(Shader.ID, UniformName);
  32.   if id = GL_INVALID_INDEX then begin
  33.     ShowMessage(UniformName + ' ' + IntToStr(GL_INVALID_INDEX));
  34.     Exit;
  35.   end;
  36.   glUniformBlockBinding(Shader.ID, id, BindingPoint);
  37.  
  38.   //  glBindBuffer(GL_UNIFORM_BUFFER, buffer);
  39.   //  glBufferData(GL_UNIFORM_BUFFER, size, nil, GL_DYNAMIC_DRAW);
  40. end;
  41.  
  42. destructor TUBO.Destroy;
  43. begin
  44.   glDeleteBuffers(1, @buffer);
  45.   inherited Destroy;
  46. end;
  47.  
  48. procedure TUBO.UpdateBuffer(Data: PGLvoid; size: GLsizeiptr);
  49. begin
  50.   glBindBuffer(GL_UNIFORM_BUFFER, buffer);
  51.   glBufferData(GL_UNIFORM_BUFFER, size, Data, GL_DYNAMIC_DRAW);
  52.   //  glBufferSubData(GL_UNIFORM_BUFFER, 0, size, Data);
  53.  
  54.   glBindBufferBase(GL_UNIFORM_BUFFER, BindingPoint, buffer);
  55. end;
  56.  
  57. end.

Autor:  mathias [ So Nov 08, 2015 16:49 ]
Betreff des Beitrags:  Re: UnifomBlockObject

Irgendwas stimmt mit meinem UBO immer noch nicht.
Für kleinere Scenen mit ca. 20 Mesh, funktioniert alles prima.
Wen ich mit meinem OBJ-Loader ein Object lade, das sich aus ca. 800 Meshes zusammensetzt, kommt es zur Darstellungsfehler.
Mein schwacher Intel-Atom hat sogar mit weniger Elementen Probleme.

Jedes Mesh bekommt einen eigenen Shader.
Jeder Shader hat eine Beleuchtungsberechnung, dafür habe ich 2 UBOs eine für Licht, die andere das Material.

Ich habe jedes Mesh in eine Classe gepackt, somit hat jedes Mesh die eigene Beleuchtung-Daten.

Löse ich Ganze mit normalen Uniform-Übergaben, dann läuft alles Fehlerfrei, auch auf dem Atom.
Ist evt. die GPUs mit zu vielen UBOs überfordert ?

Seite 1 von 4 Alle Zeiten sind UTC + 1 Stunde
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/