Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Fr Jul 18, 2025 11:19

Foren-Übersicht » Programmierung » OpenGL
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Schnelle Texturänderung
BeitragVerfasst: Mo Apr 11, 2005 16:07 
Offline
DGL Member

Registriert: Mo Apr 11, 2005 15:56
Beiträge: 2
Wohnort: Berlin
Hallo!

Ich entwickle zur Zeit einen Raytracer. Nach diversen Optimierungen
(unter anderem mit SSE) möchte ich diesen nun per OpenGL Echtzeit-fähig
machen.

Die Ausgabe soll einfach über ein GL_QUADS mit einer Textur (die das
gerenderte Bild enthält) ablaufen.

Jetzt habe ich folgendes Problem:
Um die Textur zu verändern, also zu "refreshen", muss ich bei jedem Render-Vorgang
den Befehl glTexImage2D aufrufen. Und dieser schluckt mächtig Performance.

Ich vermute mal, das liegt daran, dass bei jedem Aufruf von glTexImage2D die
Textur in Hauptspeicher verschoben, dann verändert und dann wieder zurück
in VRAM verschoben wird.

Ich habe da mal ein kleines Beispielprogramm geschrieben, dass die
Problematik verdeutlichen soll (hat mit Raytracing nichts zu tun):

Code:
  1.  
  2. // Formular erstellen
  3. var
  4. Tex: GLUInt;
  5. Data: array of array of [0..3] of Byte;
  6.  
  7. procedure TMainForm.FormCreate(Sender: TObject);
  8. begin
  9.   {OpenGL Initializieren ... die üblichen Befehle halt}
  10.   SetLength(Data,512*512);
  11.  
  12.   glGenTextures(1, @tex);
  13.   glBindTexture(GL_TEXTURE_2D, tex);
  14.   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  15. end;
  16.  
  17.  
  18. // Mit TGLCadencer-Komponente von GLScene ausgeben
  19. procedure TMainForm.GLCadencer1Progress(Sender: TObject; const deltaTime,
  20. var
  21. I: Integer;
  22. begin
  23.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  24.   glLoadIdentity;
  25.  
  26.   // Zufällige Werte generieren  
  27.   FOR I:=0 TO High(Data) DO
  28.   BEGIN
  29.     Data[I,0]:=Random(256);
  30.     Data[I,1]:=Random(256);
  31.     Data[I,2]:=Random(256);
  32.     Data[I,3]:=Random(256);
  33.   END;
  34.  
  35.   // Die nächste Zeile muss durch irgendwas schnelleres
  36.   // ersetzt werden!!!
  37.   glTexImage2D(GL_TEXTURE_2D, 0, 3,512,512, 0,GL_RGBA, GL_UNSIGNED_BYTE, Data);
  38.  
  39.   glBegin(GL_QUADS);
  40.         glTexCoord2f(0,0); glVertex2s(0,0);
  41.         glTexCoord2f(0,1); glVertex2s(0,ClientHeight);
  42.         glTexCoord2f(1,1); glVertex2s(ClientWidth,ClientHeight);
  43.         glTexCoord2f(1,0); glVertex2s(ClientWidth,0);
  44.   glEnd;
  45.  
  46.   SwapBuffers(FormDC);
  47.  
  48.   // FPS ausgeben
  49.   Caption:=Format('%f fps',[1/deltaTime]);
  50. end;
  51.  

Dass Programm erreicht bei mir ca. 70 fps.

Jetzt meine Frage: Kann man das Programm so umschreiben,
dass beim zeichnen nicht jedes mal die ganze Textur in den Hauptspeicher
verschoben wird, sondern direkt im Grafikspeicher verändert werden kann?

Oder: Gibt es eine völlig andere Variante (außer glDrawPixels) die noch
schneller ist?

Weitere Frage: Falls das funktioniert, kann
ich dann auch Farbwerte aus dem VRAM auslesen? :?:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Apr 11, 2005 16:12 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
Es gibt noch ARB_pixel_buffer_object. Damit kann man unter anderem auch Texturen für z.B. Video streamen. In der Spezifikation sind auch Beispiele dazu: http://oss.sgi.com/projects/ogl-sample/ ... object.txt

Hier ist ein Ausschnitt:

Zitat:
Streaming textures using pixel buffer objects:

const int texWidth = 256;
const int texHeight = 256;
const int texsize = texWidth * texHeight * 4;
void *pboMemory, *texData;

// Define texture level zero (without an image); notice the
// explicit bind to the zero pixel unpack buffer object so that
// pass NULL for the image data leaves the texture image
// unspecified.
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texWidth, texHeight, 0,
GL_BGRA, GL_UNSIGNED_BYTE, NULL);

// Create and bind texture image buffer object
glGenBuffers(1, &texBuffer);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, texBuffer);

// Setup texture environment
...

texData = getNextImage();

while (texData) {

// Reset the contents of the texSize-sized buffer object
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, texSize, NULL,
GL_STREAM_DRAW);

// Map the texture image buffer (the contents of which
// are undefined due to the previous glBufferData)
pboMemory = glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB,
GL_WRITE_ONLY);

// Modify (sub-)buffer data
memcpy(pboMemory, texData, texsize);

// Unmap the texture image buffer
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);

// Update (sub-)teximage from texture image buffer
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight,
GL_BGRA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));

// Draw textured geometry
glBegin(GL_QUADS);
...
glEnd();

texData = getNextImage();
}


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Apr 12, 2005 07:30 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Die Extension ARB_Pixel_buffer_object ist ja noch ziemlich neu. Von daher würde ich auf jeden Fall noch nach einer Alternativlösung ausschau halten.

So ein ähnliches Problem hatte ich vor ein paar Tage auch. Es ist wesentlich schneller, wenn du das Bild komplett neu erzeugst. Warum das so ist kann ich mir allerdings auch nicht erklären. Ich hatte das mal mit 512x512 ausprobiert und das ging halbwegs. Ich glaube, wenn dort auch noch ein Alphakanal mit dabei war dann war das auch noch mal schneller. Musste mal ein bisschen mit rumprobieren.

Also in etwa so.
Code:
  1. glDeleteTextures(1, @Tex);
  2.   glGenTextures(1, @Tex);
  3.   glBindTexture(GL_TEXTURE_2D, Tex);
  4.   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  5.  
  6.   glTexImage2D(GL_TEXTURE_2D, 0, 3,512,512, 0,GL_RGBA, GL_UNSIGNED_BYTE, Data);


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Apr 12, 2005 10:43 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Ich hatte gerade ne OpenGL-Vorlesung hier an der Uni, und da wurde ein beispiel gezeigt wo ein AVI in ordentlicher geschwindigkeit auf einem Würfel ausgegeben wurde. Das Funktionierte per SubImages und soll wohl irgendwie so funktionieren, dass die neuen Bilddaten in den Initialisierten Speicherbereich der GraKa kopiert wird.

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Apr 12, 2005 11:03 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
glTexSubImage bzw. glCopyTexSubImage sollte man immer verwenden, damit der Speicher nicht neu belegt werden muß, wie das da in dem pbo Beispiel gemacht auch gemacht wird. Habe mal die Demo aus dem nvsdk ausprobiert und da war PBO+glTexSubImage 4x schnell als nur glTexSubImage.
Der Nachteil ist natürlich, daß es bislang trotz ARB Name nur mit GF Karten funktioniert. Das Prinzip ist, aber das gleiche wie bei den Vertex Buffern, man gibt bei den Texture Befehlen keinen Zeiger sondern einen Index in den gerade aktiven Buffer an und alles andere bleibt beim alten, so daß man diese Funktionalität leicht ein und ausschalten kann.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Apr 12, 2005 16:24 
Offline
DGL Member

Registriert: Mo Apr 11, 2005 15:56
Beiträge: 2
Wohnort: Berlin
Puh. Erst mal danke für eure vielen nützlichen Tipps.
Ich hab das mit dem glTexSubImage2D mal ausprobiert und
erreiche jetzt 85 statt 70 fps. Immerhin schon eine Steigerung.

Wenn die Textur jedoch genauso groß wie der Bildschirm ist,
sollte man jedoch lieber die Funktion glDrawPixels verwenden.
Damit erreiche ich ca. 115 fps.

Ich hab den umgeschriebenen Sourcecode mal hier aufgeführt:

Code:
  1.  
  2. var
  3.   MainForm: TMainForm;
  4.   Tex:      GLUInt;
  5.   Data:     array of array [0..3] of Byte;
  6.   RC        : HGLRC;
  7.   DC        : HDC;
  8.  
  9. const
  10.   TexSize = 512;
  11.  
  12. // Formular erstellen
  13. procedure TMainForm.FormCreate(Sender: TObject);
  14. var
  15. I: Integer;
  16. begin
  17.   {OpenGL Initializieren ... die üblichen Befehle halt}
  18.   SetLength(Data,TexSize*TexSize);
  19.  
  20.   glBindBufferARB(0, 0);
  21.   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TexSize, TexSize, 0,
  22.                GL_RGBA, GL_UNSIGNED_BYTE, data);
  23.  
  24.   // Buffer erstellen und zuweisen
  25.   glGenBuffersARB(1, @tex);
  26.   glBindBufferARB(0, tex);
  27.  
  28.   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  29. end;
  30.  
  31. procedure TMainForm.GLCadencer1Progress(Sender: TObject; const deltaTime,
  32.   newTime: Double);
  33. var
  34. I: Integer;
  35. begin
  36.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  37.   glLoadIdentity;
  38.  
  39.   FOR I:=0 TO High(Data) DO
  40.   BEGIN
  41.     Data[I,0]:=Random(256);
  42.     Data[I,1]:=Random(256);
  43.     Data[I,2]:=Random(256);
  44.     Data[I,3]:=Random(256);
  45.   END;
  46.  
  47.   // Neue TexSubImage2D-Variente
  48.   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexSize, TexSize,GL_RGBA, GL_UNSIGNED_BYTE,data);
  49.  
  50.   // Die Blendingfunktionen werden für die spätere
  51.   // Optimierung meines Raytracers benötigt, können
  52.   // aber vernachlässigt werden
  53.   glDepthFunc(GL_ALWAYS);
  54.   glBlendFunc(GL_SRC_ALPHA,GL_ONE);
  55.   glEnable(GL_BLEND);
  56.  
  57.   glBegin(GL_QUADS);
  58.         glTexCoord2f(0,0); glVertex2s(0,0);
  59.         glTexCoord2f(0,1); glVertex2s(0,ClientHeight);
  60.         glTexCoord2f(1,1); glVertex2s(ClientWidth,ClientHeight);
  61.         glTexCoord2f(1,0); glVertex2s(ClientWidth,0);
  62.   glEnd;
  63.  
  64.   SwapBuffers(DC);
  65.   Caption:=Format('%f fps',[1/deltaTime]);
  66. end;


Ich hoffe, so ist es die schnellste Variante (wenn nicht, bitte antworten!).

Das in der ARB_pixel_buffer_object-Spezifikation genannte Beispiel mit dem
PBOMemory hat bei mir irgendwie nicht funktioniert. Vielleicht könnte jemand
mein Programm umschreiben, damit es so ähnlich wie das Beispiel arbeitet.

Jetzt hab schon wieder zwei neue Fragen:
1) Funktioniert die NVidia-Demo in der Spezifikation wirklich nur auf GeForce-Karten?
Ich nämlich ne Radeon 9800 Pro, wär ganz schön wenn ich das da auch mal ausprobieren könnte...
2) Wie verwende ich den von Lars Middendorf genannten Befehl \"glCopyTexSubImage\" ?[/pascal]


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Apr 13, 2005 22:28 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
glCopyTexImage kopiert die Texture aus dem Framebuffer. Es gibt da wie auch bei glTexImage2d das schnellere Gegenstück glCopyTexSubImage, deshalb habe ich das mit angeführt. Für dich ist es eventuell weniger nützlich.
ATI unterstützt ARB_pixel_buffer_object leider noch nicht. Bei denen hat sich im Bereich OpenGL in letzter Zeit eh sehr wenig getan.
Noch eine Idee: Man kann auf den GF6 Karten mit ihren 65536 Befehlen im Fragmentshader den Raytracer auch auf der GPU laufen lassen. Die Koordinaten der ganzen Objekte kann man in Texturen speichern und dann ganz normal seinen Quelltext mit glsl schreiben. Es funktionieren auch if, for und while Anweisungen im Fragment Shader.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 19 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.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.008s | 14 Queries | GZIP : On ]