OpenGL Textur bei jedem Frame "aktualisieren"

Für Probleme bezüglich Grafik, Audio, GL, ACS, ...
Antworten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von corpsman »

Servus zusammen,

wie ja schon einige mitbekommen haben portiere ich gerade DOOM nach FPC.

Was mir nun aufgefallen ist, ist das das "Hochladen" eines Fertigen Frames nach OpenGL extrem Langsam ist. Aktuell "Aktualisiere" ich nach jedem Frame meine Textur wie folgt:

Code: Alles auswählen

// Die OpenGL Textur auswählen
 glBindTexture(GL_TEXTURE_2D, OpenGLTexture);
 // Konvertieren von 8-Bit nach RGB 
  For i := 0 To high(I_VideoBuffer) Do Begin
    rgb := Doom8BitTo24RGBBit[I_VideoBuffer[i]];
    OpenGLData[i][0] := (rgb) And $FF;
    OpenGLData[i][1] := (rgb Shr 8) And $FF;
    OpenGLData[i][2] := (rgb Shr 16) And $FF;
  End;
  // Hochladen des neuen FRames
  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, SCREENWIDTH, SCREENHEIGHT, GL_RGB, GL_UNSIGNED_BYTE, @OpenGLData[0]);        
Kennt jemand einen "Schnelleren" weg, wie ich immer die Komplette Textur austauschen kann ?
--
Just try it

Mathias
Beiträge: 6955
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von Mathias »

Kannst du Doom8BitTo24RGBBit nicht direkt in das VRAM laden.

OpenGL ist da sehr flexibel was die Formate anbelangt, Man kann ziemlich alles hochladen was 15, 16, 24 oder 32Bit ist.
Ausser bei OpenGL ES das ist wählerischer.

Schau doch mal was glTexSubImage2D alles für Formate kennt.

Das spart dir das ganze Gefummel mit shr und and.

Code: Alles auswählen

@OpenGLData[0]
Dies ist auch nicht so elegant. Es kann ja mal sein, das deine Textur aus 0x0 Pixel besteht, dann meldet Pascal eine Warnung.

Früher habe ich dies auch falsch gemacht. Als Beispiel bei Vektoren.

Code: Alles auswählen

  // ALt:
  glBufferData(GL_ARRAY_BUFFER, sizeof(QuadVertex), @QuadVertex, GL_STATIC_DRAW);
  
  // Neu
  glBufferData(GL_ARRAY_BUFFER, sizeof(QuadVertex), PVector3f(QuadVertex), GL_STATIC_DRAW);
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von corpsman »

hmm,
meine variable I_VideoBuffer ist immer gleich groß und hat 1 Byte werte, welche via "Doom8BitTo24RGBBit" was quasi eine 256 Farben Lookup Tabelle ist in RGB umgewandelt.
Wenn ich mir dass sparen will müsste es eine möglichkeit geben in OpenGL die Lookup zu hinterlegen und nur die 8-Bit werte hoch zu laden, dass alleine würde die Datenmenge ja auf ein drittel reduzieren ..
--
Just try it

Mathias
Beiträge: 6955
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von Mathias »

hmm,
meine variable I_VideoBuffer ist immer gleich groß und hat 1 Byte werte, welche via "Doom8BitTo24RGBBit" was quasi eine 256 Farben Lookup Tabelle ist in RGB umgewandelt.
Wenn ich mir dass sparen will müsste es eine möglichkeit geben in OpenGL die Lookup zu hinterlegen und nur die 8-Bit werte hoch zu laden, dass alleine würde die Datenmenge ja auf ein drittel reduzieren ..
Hast du die mal angeguckt, das seiht mit nach 8Bit aus.

GL_UNSIGNED_BYTE_3_3_2

Was mich sowieso verwundert, das es sehr langsam bei dir ist. Doom lief mal auf 386er.

Was willst du überhaupt machen, das ganze Doom mit OpenGL rendern, oder nur die Ausgabe auf den Bildschirm mit OpenGL ?
Das Ur-Doom kannte noch kein OpenGL, daher die Frage.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von Jorg3000 »

Tach!
Falls es nicht das von Mathias genannte GL_UNSIGNED_BYTE_3_3_2 ist ...
... hätte ich alternativ einen Vorschlag zur erheblichen Beschleunigung der Konvertierungs-Schleife, nämlich indem jedes Pixel in GL_RGBA (32 Bit anstelle von 24 Bit GL_RGB) überführt wird.
Die Lookup-Tabelle müsste dann die fertigen 32-Bit-Werte enthalten, quasi folgende Abfolge: TColor32 = record Red, Green, Blue, Alpha: Byte; end;

Code: Alles auswählen

var
  DestPtr: PInt32;

  DestPtr:= @OpenGLData[0];  // GL_RGBA  32 bit

  for i := 0 to High(I_VideoBuffer) do
  begin
    DestPtr^ := Doom8BitTo32RGBBit[I_VideoBuffer[i]];
    inc(DestPtr);
  end;
Der Alpha-Kanal muss immer den Wert $FF haben (deckend).
Für diesen Ansatz spricht auch, dass GPUs für GL_RGBA (32 Bit) besser optimiert sein sollen als für GL_RGB.

Mathias
Beiträge: 6955
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von Mathias »

... hätte ich alternativ einen Vorschlag zur erheblichen Beschleunigung der Konvertierungs-Schleife, nämlich indem jedes Pixel in GL_RGBA (32 Bit anstelle von 24 Bit GL_RGB) überführt wird.
Früher war das ein echtes Problem. Ich hatte mal eine ET4000 mit 32Bit lief zie akzeptablem, aber mit 24Bit ging die voll in die Knie. Dies war im normalen Desktop Betrieb von Win3.1.

Ober heute noch der Fall ist, man müsste es probieren.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von corpsman »

Was willst du überhaupt machen, das ganze Doom mit OpenGL rendern, oder nur die Ausgabe auf den Bildschirm mit OpenGL ?
Das Ur-Doom kannte noch kein OpenGL, daher die Frage.
Ich übersetze gerade den Crispy DOOM Code nach FPC ( https://github.com/PascalCorpsman/FPC_DOOM ), OpenGL nutze ich eigentlich nur, zur Darstellung des Videopuffers so wie in das "Ur-Doom" berechnet hat, wahrscheinlich würde es auch gehen wenn ich alles in ein TBitmap rendere, wenn das schnell genug ist.
Und mit "Langsam" meine ich, ca 3 bis 5 ms bei einer Textur von 640x400 Pixel, wenn ich 1280x800 Pixel hoch lade gehen fast 20ms dafür drauf. Ist alles immer noch OK, weil ich Pro Frame 35ms hab.

Den Vorschlag von Jörg werde ich mal Ausprobieren und alles von 24-Bit auf 32-Bit umstellen. Wenn das schneller ist wäre das natürlich noch cooler ;)
--
Just try it

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von corpsman »

@Jorg3000
so ich habs nu mal getestet, deine Vorschläge waren "Fast" richtig.

Code: Alles auswählen

Var
  i: Integer;
  DestPtr: PUInt32;   
  begin
   glPushMatrix;
  // 1. Umkopieren der DOOM Puffer nach OpenGL
  glBindTexture(GL_TEXTURE_2D, OpenGLTexture);
  DestPtr := @OpenGLData[0];
  For i := 0 To high(I_VideoBuffer) Do Begin
    DestPtr^ := Doom8BitTo24RGBBit[I_VideoBuffer[i]];
    inc(DestPtr);
  End;

  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, SCREENWIDTH, SCREENHEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, @OpenGLData[0]);


Man muss PUInt32 nehmen, sonst gibts ne zugriffsverletzung weil ja alle werte im obersten Byte FF sind.

Bei 640x400 konnte ich nicht wirklich nen Unterschied messen, aber bei 1280x800 ists teilweise 10ms schneller, das bleibt also auf jeden Fall drin. Danke und ich hab wieder was gelernt...
--
Just try it

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von Jorg3000 »

Die zweite Optimierung wäre die Nutzung eines PBO
https://www.khronos.org/opengl/wiki/Pixel_Buffer_Object

So wie ich das verstehe, wird ein PBO als Vermittler-Speicher eingesetzt. Beim Setzen des neuen Frames per glTexSubImage2D() wird nicht mehr die CPU belastet, indem sie den RAM-Speicherbereich selber zur GPU "hochladen" muss, sondern man schreibt zuvor schon direkt in den GPU-Speicher - und das glTexSubImage2D() schaltet es nur noch aktiv.
Oder falls ich es falsch verstanden habe, holt sich die GPU die Daten selber aus dem RAM - zumindest soll die CPU dadurch nicht mehr belastet werden - und somit kann die CPU währenddessen schon den nächsten Frame vorbereiten.
Ich schicke dir morgen mal ein Beispiel per Privatnachricht.

Mathias
Beiträge: 6955
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von Mathias »

Versuche mal dies, vielleicht geht es direkt.

Code: Alles auswählen

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE_3_3_2, @I_VideoBuffer[i]);
OpenGL nutze ich eigentlich nur, zur Darstellung des Videopuffers so wie in das "Ur-Doom" berechnet hat, wahrscheinlich würde es auch gehen wenn ich alles in ein TBitmap rendere, wenn das schnell genug ist.
TBitmap ist eines der störrischten Formaten die ich kenne. Mit dem habe ich schon fast die Zähne ausgebissen und bin nie auf den grünen Zweig gekommen.

Um einen Pixelbuffer in der Schnelle in die LCL zu bringen habe ich schon dies genommen.
Da habe ich ein 8bit Graustufenbild in den VRAM kopiert.

Code: Alles auswählen

  glDrawPixels(imageWidht, imageHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, Pointer(image));
Mal was anderes, muss dein DOOM zwingend in der LCL laufen ?
Wen du es 1:1 übersetzen willst, gibt es anderes als die LCL.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von corpsman »

Da kommt Erwartungsgemäß murks raus

Code: Alles auswählen

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE_3_3_2, @I_VideoBuffer[i]);
Ich hab mal die Verwendete Farbpalette als Bild extrahiert:
DOOM1_Colormap.png
DOOM1_Colormap.png (3.9 KiB) 15737 mal betrachtet
Das sieht nicht aus wie RGB8 ..

By the way, finde es cool wie wir hier an einer Kleinigkeit rumdocktern, danke für eure Begeisterung (y)
--
Just try it

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von corpsman »

Mal was anderes, muss dein DOOM zwingend in der LCL laufen ?
Wen du es 1:1 übersetzen willst, gibt es anderes als die LCL.
Im ersten Step wollte ich das Doom überhaupt mal unter FPC zum laufen bekommen. Ich weis man kann da auch SDL und alles mögliche Einsetzen, aber mein Default Setup ist eigentlich immer OpenGLControl, LCL und max noch Bass.dll, wie schon geschrieben ist ja eigentlich auch alles schnell genug, spätestens seit dem Pointer Patch von Jorg3000 kann ich das Game in 1280x800 1a laufen lassen und hab immer noch Pro Frame 10ms puffer.
Die Diskussion ist daher rein Ideeller Natur, und durch eure Vorschläge lerne ich noch viel Dazu und damit auch alle die das hier mit lesen ;).
--
Just try it

Mathias
Beiträge: 6955
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Textur bei jedem Frame "aktualisieren"

Beitrag von Mathias »

Das sieht nicht aus wie RGB8 ..
Stimmt, bei VGA konnte man die 256 Farben frei definieren von eine Auswahl mit 4mio. Farben.

Aber ich wollte es trotzdem mal testen.
So funktioniert es, wen die Daten OpenGL gerecht vorliegen. Mit reinem OpenGL core geht es nicht.

Code: Alles auswählen

const
  Textur8bit: packed array[0..1, 0..1] of byte = (
    (%11100000, %00011100), (%00000011, %11111100));  // Rot, Grün, Blau, Gelb
...
  glTexImage2D(GL_TEXTURE_2D, 0, GL_R3_G3_B2, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE_3_3_2, @Textur8bit);      
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten