Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Ausschließlich GPU verwenden (https://www.delphipraxis.net/176402-ausschliesslich-gpu-verwenden.html)

EWeiss 2. Sep 2013 21:01


Ausschließlich GPU verwenden
 
Hat vielleicht jemand nen Tip wie ich für OpenGl ausschließlich die GPU verwenden kann?

gruss

Der schöne Günther 2. Sep 2013 22:57

AW: Ausschließlich GPU verwenden
 
OpenGL ist OpenGL.

Ausschließlich GPU für was genau? Hast du ein Performance-Problem? Welche OpenGL-Version wird genutzt? Welcher Grafikchip kommt zum Einsatz?

Medium 2. Sep 2013 23:00

AW: Ausschließlich GPU verwenden
 
Ein gewisses Maß an Verwaltungstätigkeiten hat man zwangsweise immer auf der CPU (Initialisieren, Resourcen mappen/umschaufeln, Re-Draws in der Renderschleife). Wenn du etwas genauer sagst was du gerne von der GPU alles erledigt haben willst, kann man vermutlich helfen. (Die Draw-Aufrufe u.ä. wird man z.B. einfach nicht los werden.)

EWeiss 2. Sep 2013 23:10

AW: Ausschließlich GPU verwenden
 
Ich habe bei Sonique Plugins mit GDI BitBlt... eine zu hohe CPU auslastung.
Deshalb habe ich das jetzt wahlweise auf OpenGL/GDI ausgelegt.

Eigentlich bin ich es gewohnt das wenn ich Zeichenoperationen mit OpenGL ausführe
diese von der GPU übernommen werden also max 2-4% CPU (bsp. Mein Winamp Plugin in GL)

Seltsamer weise geht die CPU aber nicht sonderlich runter.
Das war aber eigentlich der sinn der auswahlmöglichkeit.

gruss

Medium 2. Sep 2013 23:20

AW: Ausschließlich GPU verwenden
 
Das wird tiefergehend fürchte ich. Hast du statt des BitBlt einfach eine Textur genommen, und lässt die via OGL auf ein Quad zeichnen, oder läuft der komplette Unterbau dann ebenfalls mit OGL? (Wenn die Frage mit #2 beantwortet ist, werden wir um Code wohl nicht herum kommen fürchte ich.)

EWeiss 2. Sep 2013 23:30

AW: Ausschließlich GPU verwenden
 
Zitat:

Hast du statt des BitBlt einfach eine Textur genommen
Nicht im herkömmlichen sinne.
Delphi-Quellcode:
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, VisInfo^.w, VisInfo^.h,
           GL_BGRA_EXT, GL_UNSIGNED_BYTE, VisInfo^.VisBuf);
Im VisInfo^.VisBuf sind dann die Daten die für die Texture verwendet werden.

Zitat:

und lässt die via OGL auf ein Quad zeichnen
Ja

Wenn es am code liegt kein problem den vergleichsausschnitt kannst haben.

Delphi-Quellcode:
if not VisDataThread.UseOpenGL then
begin
  if SoInfo.Title <> '' then
  begin
    BassSoVis1.DrawSongName(VisCanvas);
    BassSoVis1.DrawTime(VisCanvas);
    GetFramesInSec;
    BassSoVis1.DrawFramesPerSecond(VisCanvas, FPS);
  end;

  if (not BitBlt(canvas, VisInfo^.x, VisInfo^.y, VisInfo^.w, VisInfo^.h, VisInfo^.VisDC, 0,
    0, SRCCOPY)) then
  begin
    asm
      FNCLEX end;
    Set8087CW(FPWord);

    VisInfo^.Rendering := False;

    BassFuncs^.SetError(BASS_ERROR_DEVICE);
    Exit;
  end;
end else
begin
  // OpenGL-Funtionen initialisieren
  if glDC = 0 then
  begin
    LastWidth      := 0;
      LastHeight   := 0;

    // Gdi initialisieren
    if InitGDI = 0 then
      Halt;

    if not InitOpenGL then
      Halt;

    glDC := canvas;

    // Renderkontext erstellen (32 Bit Farbtiefe,
    // 32 Bit Tiefenpuffer, Doublebuffering)
    h_RC := CreateRenderingContext(glDc,
                               [opDoubleBuffered], 32, 32, 0, 0, 0, 0);
    // Erstellten Renderkontext aktivieren
    ActivateRenderingContext(glDc, h_RC, True);

    // initialize TextSuite
    Init_TextSuite;

    VBL2(vsmSync);

      glClearColor(0.0, 0.0, 0.0, 0.0);
      glClear (GL_COLOR_BUFFER_BIT);

      glDisable(GL_DEPTH_TEST);
      glEnable(GL_BLEND);
      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      glEnable(GL_TEXTURE_2D);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

      glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
      glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VisInfo^.w, VisInfo^.h, 0,
      GL_BGRA_EXT, GL_UNSIGNED_BYTE, VisInfo^.VisBuf);
  end;

  w := VisInfo^.w;
   h := VisInfo^.h;

   if(LastWidth <> w) and (LastHeight <> h) then
   begin
      LastWidth      := w;
      LastHeight   := h;

      SetRect(NextVisRect,
         w - (64 + 16),
         h - (64 + 16),
         w - (64 + 16) + 64,
         h - (64 + 16) + 64);

      SetRect(PrevVisRect,
         (16),
         h - (64 + 16),
         (16) + 64,
         h - (64 + 16) + 64);

      glViewport(0, 0, w, h);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluOrtho2D(0.0, w, h, 0.0);
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
   end;

   glClearColor(0.0, 0.0, 0.0, 0.0);
   glClear (GL_COLOR_BUFFER_BIT);
   glLoadIdentity();

   glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, VisInfo^.w, VisInfo^.h,
    GL_BGRA_EXT, GL_UNSIGNED_BYTE, VisInfo^.VisBuf);

   glColor4f(1, 1, 1, 1);
   glEnable(GL_TEXTURE_2D);
   glBegin(GL_QUADS);
     glTexCoord2d(0.0, 0.0);
     glVertex2f( 0.0, 0.0);
     glTexCoord2d(0.0, 1.0);
     glVertex2f( 0.0, LastHeight);
     glTexCoord2d(1.0, 1.0);
     glVertex2f( LastWidth, LastHeight);
     glTexCoord2d(1.0, 0.0);
     glVertex2f(LastWidth, 0.0);
  glEnd();

  if Length(SoInfo.Title) > 0 then
  begin
    SongRender;
    GetFramesInSec;
  end;

   glFlush();
   SwapBuffers(glDC);
end;

gruss

Medium 3. Sep 2013 01:01

AW: Ausschließlich GPU verwenden
 
Dann wird der Flaschenhals wohl wirklich (vermutlich) in dem Erzeugen des Inhaltes des VisInfo^.VisBuf liegen. Alles was da passiert ist ja noch konventionelle GDI nehme ich an. Das bloße Ändern des Weges zum Framebuffer alleine wird da minimal an CPU Zeit sparen. Kommst du mit deinen FPS ans VSync ran, oder liegst du darunter? Wenn drunter, dann nudelt die Bilderzeugung höchstwahrscheinlich zu langsam und braucht definitiv Magnituden länger als sowohl das BitBlt als auch ein OGL Quad.

Alles das was zur Erzeugung des Inhaltes von VisBuf passiert einfach so auf die GPU auszulagern geht nicht. GPUs arbeiten völlig anders als herkömmliche CPUs und verstehen kein x86 oder x64 Code. Das müsste man in Handarbeit in Shader oder OpenCL portieren, und höchstwahrscheinlich auch stark umstrukturieren, da man sonst aus der Parallelität von GPUs keinen Nutzen ziehen kann. (Und ohne das sind die auch nicht schneller als eine CPU - im Gegenteil.)

Einfach zur Ausgabe das Bild auf ein Quad werfen bringt im Vergleich zu einem BitBlt verschwindend wenig. Beides sind sehr flotte Operationen, und werden durch die Bilderzeugung sehr wahrscheinlich zum Zwerg im Gesamtvorgang. Je nach dem was du da so alles malst natürlich.

EWeiss 3. Sep 2013 01:18

AW: Ausschließlich GPU verwenden
 
Danke für die Ausführlichen Informationen.
Theoretisch würde es gehn (vermutung) wenn ich OpenCL mit einbinden würde.
Aber ne extra DLL dafür? Dann lass ich es mal so wie es ist.

Zitat:

Alles was da passiert ist ja noch konventionelle GDI nehme ich an.
Jo das ist korrekt.

Delphi-Quellcode:
  FillChar(BmpInfo, SizeOf(BITMAPINFO), 0);
  BmpInfo.bmiHeader.biSize    := SizeOf(BITMAPINFOHEADER);
  BmpInfo.bmiHeader.biWidth   := nw;
  BmpInfo.bmiHeader.biHeight  := -nh -2;
  BmpInfo.bmiHeader.biPlanes  := 1;
  BmpInfo.bmiHeader.biBitCount := 32;

  VisBmp := CreateDIBSection(0, BmpInfo, DIB_RGB_COLORS, VisBuf, 0, 0);
  VisDC := CreateCompatibleDC(0);
  if (VisBmp = 0) or (VisBuf = nil) or (VisDC = 0) then
  begin
    if (VisBmp <> 0) then
      DeleteObject(VisBmp);
    if (VisDC <> 0) then
      DeleteDC(VisDC);

    BassFuncs^.SetError(DWORD(BASS_ERROR_UNKNOWN));
    Exit;
  end;
Hab da aber durch das testen noch einen Schwerwiegenden fehler entdeckt.
Das
Delphi-Quellcode:
   glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, VisInfo^.w, VisInfo^.h,
     GL_BGRA_EXT, GL_UNSIGNED_BYTE, VisInfo^.VisBuf);
kann nicht gehn
dabei war es vorher richtig ;)
Delphi-Quellcode:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VisInfo^.w, VisInfo^.h, 0,
       GL_BGRA_EXT, GL_UNSIGNED_BYTE, VisInfo^.VisBuf);
War eins der probleme zum Beispiel beim resitz.

Zitat:

Kommst du mit deinen FPS ans VSync ran
Sorry wie kann ich das feststellen?
Grundsätzlich denke ich erstmal nein weil ich das Timing auf 25 ms gesetzt habe.
Bei 16ms komme ich an die 60 FPS nur im Vollbild läßt sich dann die Anwendung nicht wieder zurückschalten
Key eingaben schlagen dann fehl.



gruss

Medium 3. Sep 2013 08:44

AW: Ausschließlich GPU verwenden
 
Zitat:

Zitat von EWeiss (Beitrag 1226940)
Theoretisch würde es gehn (vermutung) wenn ich OpenCL mit einbinden würde.

Ganz so einfach ist es leider nicht. OpenCL ist eine komplett eigene Sprache, d.h. man müsste völlig neuen Code fabrizieren, der zudem auch noch nach einem etwas anderen Paradigma als klassisches Delphi arbeitet. Auch das Drumrum würde man höchstwahrscheinlich massiv umstricken müssen. :?

Zitat:

Grundsätzlich denke ich erstmal nein weil ich das Timing auf 25 ms gesetzt habe.
Bei 16ms komme ich an die 60 FPS nur im Vollbild läßt sich dann die Anwendung nicht wieder zurückschalten
Key eingaben schlagen dann fehl.
Das spricht dafür, dass meine Befürchtung zutrifft. Vermutlich rauscht du mit den 16ms so gerade ans Limit, so dass dein Programm so gerade keine Zeit mehr findet ab und an die Windows-Nachrichtenschleife abzuarbeiten. Auf langsameren Kisten oder mit höherer Auflösung könnte das auch mit 25ms u.U. wieder problematisch werden. (Üblicherweise verlässt man sich auf die Nachrichtenschleife in Anwendungen die eine eigene Render-Loop haben aber auch nicht auf diese, sondern baut mittels GetAsyncKeystate() und Konsorten eine komplett eigene Tastatur- und Mausbehandlung. Dann hat man auch bei 100% CPU immer in jedem Frame eine Behandlung von Eingaben.)

EWeiss 3. Sep 2013 16:50

AW: Ausschließlich GPU verwenden
 
Zitat:

sondern baut mittels GetAsyncKeystate() und Konsorten eine komplett eigene Tastatur- und Mausbehandlung. Dann hat man auch bei 100% CPU immer in jedem Frame eine Behandlung von Eingaben.)
Das problem dabei ich habe keinen einfluss auf das was andere in ihrer Anwendung so ausführen.
Sicher ist nur das wenn diese meine DLL verwenden auf irgendetwas Rendern müssen was über ein Handle verfügt.
Daszu kommt auch noch das die Sonique Plugins eigentlich für eine Auflösung von 512x512 geschrieben wurden
und einfach Programmtechnisch mit den heutigen Vollbild Auflösungen nicht mehr zurecht kommen.

Solange ich im Rahmen bleibe komme ich schon mit 16ms(10) an die 99 FPS und drüber.

Die Leute möchten gerne 0% CPU max FPS und wenn möglich das ganze noch unter Win95 Anwendbar.

gruss

EWeiss 6. Sep 2013 05:12

AW: Ausschließlich GPU verwenden
 
Hab immer noch ein performance problem.

Meine vorgehensweise ist folgende.

Erstelle ein VisWindow innerhalb meiner DLL das ParentWindow ist das der Anwendung welche die DLL verwendet.
Beim Initialisieren des Plugin wird das Handle übergeben (PAnel oder was auch immer) auf dem das VisWindow als Parent gesetzt wird.

Wenn das Timing auf 25ms (Timer) gesetzt wird funktioniert soweit alles
will ich aber in realzeit min 10ms rendern bin ich nicht mehr in der lage die Anwendung zu beenden
ohne das vorher das Plugin beendet wird.
Ich kann aber nicht in der Renderfunktion Peekmessage(DoEvents) verwenden das verursacht jede menge anderer probleme.

Was bleiben dann noch für andere möglichkeiten damit die Anwendung bedienbar bleibt?
Die CPU auslastung ist gerade mal 30% trotzdem kann ich die Anwendung nicht beenden.

gruss

Medium 8. Sep 2013 15:40

AW: Ausschließlich GPU verwenden
 
Wie schon zuvor genannt kannst du mit GetAsyncKeystate() in deiner Loop eine eigene Quasi-Message-Behandlung einbauen. Dann ist sichergestellt, dass die wirklich in jedem Frame 1 Mal durchlaufen wird, und man muss sich nicht mehr auf das Durchkommen von Windows-Messages verlassen. Das machen Spiele in aller Regel genau so / verflucht ähnlich.

EWeiss 8. Sep 2013 16:00

AW: Ausschließlich GPU verwenden
 
Zitat:

Zitat von Medium (Beitrag 1227612)
Wie schon zuvor genannt kannst du mit GetAsyncKeystate() in deiner Loop eine eigene Quasi-Message-Behandlung einbauen.

GetAsyncKeystate?
Hat das nicht eher mit behandlungen von Key eingaben zu tun?

Hab mir jetzt auf dieser weise geholfen.
Ein selbstgebautes doevents welches bei der WM_QUIT Message ein "PostQuitMessage(0)" sendet.

Aber würde mich doch einmal interessieren was , wie du dir das vorstellst mit GetAsyncKeystate.
Denn mit meiner MEthode habe ich leichte Artefakte beim resitz.

Ein DoEvents mit GetAsyncKeystate?
Ohne innerhalb des Renderevents wird die Zeit nicht mehr gerendert.
Delphi-Quellcode:
PAnsiChar(ansistring(strSongpos + ' / ' + strSongLength)), fLargeFontID, TS_ALIGN_LEFT);
Zitat:

damit die Anwendung bedienbar bleibt?
GetAsyncKeystate hat keinerlei einfluss auf das Paint/refresh event der Anwendung welches
durch den loop verhindert wird. Das kann ich widerrum nur mit einem DoEvents oder processmessagen erreichen.


gruss

Medium 9. Sep 2013 00:06

AW: Ausschließlich GPU verwenden
 
Oh, ups. Da habe ich ein wenig zu schnell gelesen fürchte ich. Ich dachte, dass das Programmende über einen Tastendruck ausgelöst wird, dass dein Vis erhält. Da mir die Schnittstelle zwischen deinem Plugin und seinem Host nicht ganz klar ist, wird's knapp mit konkreten Tips. Das Ende wird also von der Host-Anwendung ausgelöst, und diese schickt dann ein WM_QUIT an dein Plugin? Wenn es nicht ggf. noch andere Indikatoren gibt, die du unabhängig von der Message-Queue heranziehen könntest, wäre der einzige wirklich saubere Weg fürchte ich das Selbstbauen der Queue innerhalb deines Renderloops. Allerdings ist das etwas ins Unreine gedacht, da ich mich mit dem Ersetzen/Selbstschreiben einer WndProc, und ob und wie das Umzubiegen wäre, noch nicht befasst habe.

Was mich auch etwas verwirrt, ist dein aktueller Workaround. Du bekommst die WM_QUIT Message also doch mit? Wenn ja, dann verstehe ich das gesamte Problem noch nicht, weil dann könntest du ja daraufhin dein Plugin einfach beenden. Noch mehr irritiert mich das PostQuitMessage(0), da dies nichts weiter macht, als dass Windows dir dann nochmals ein WM_QUIT schickt. Wenn ich das MSDN da richtig verstanden habe, müsstest du dir damit eine Quasi-Endlosschleife gebaut haben. Ganz viel :gruebel:

EWeiss 9. Sep 2013 00:11

AW: Ausschließlich GPU verwenden
 
Zitat:

Du bekommst die WM_QUIT Message also doch mit?
Nein .. Nicht von der Anwendung.
Beim Click auf den X Button.

Das sollte es vielleicht etwas erklären ;)
WM_QUIT in einer Message Loop ist nicht gleich WM_QUIT innerhalb einer Proc.

Hier wird mir nur mitgeteilt das ich NUN die Anwendung beenden kann.. wenn ich denn will.

Delphi-Quellcode:
      while PeekMessage(ProcMsg, 0, 0, 0, PM_REMOVE) do
      begin
        if (ProcMsg.message = WM_QUIT) then
        begin
          PostQuitMessage(0);
          exit;
       end;

       TranslateMessage(ProcMsg);
       DispatchMessage(ProcMsg);
      end;
Das ist quasi ein DoEvent mit abschließender PostQuitMessage die dann dafür sorgt das die Anwendung beendet werden kann.
Mache ich das nicht muss ich erst das Plugin beenden.

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:24 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz