Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Beschleunigung von Laderoutine (https://www.delphipraxis.net/189976-beschleunigung-von-laderoutine.html)

TiGü 16. Aug 2016 15:40

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von EWeiss (Beitrag 1344970)
Zitat:

Warum lädst und erzeugst du die Texturen für jedes Abspielen eines einzelnen Songs neu?
Tue ich ja nicht nur am Anfang irgendwie muss ich ja mein QuadTexture Array mit Daten füllen.

Ist das Album im Karussell enthalten wird nichts geladen da im Array QuadTextures vorhanden.

Warum?
Behalte doch einfach die OpenGL-Texture während der Laufzeit des Plug-Ins?
Wenn ich das richtig verstehe, schmeißt du ja die Texturen weg, sobald die Grenze von (aCovers.count > QuadCount) überschritten ist.
Der Flaschenhals ist ja das übertragen des JPEG-Bildes auf das Bitmap-Bild.
Hier kannst du übrigens ein paar Zeilen einsparen:

Anstatt:
Delphi-Quellcode:
  // Create Bitmap
  BMP := TBitmap.Create;
  BMP.pixelformat := pf32bit;
  BMP.Width := JPG.Width;
  BMP.Height := JPG.Height;
  BMP.canvas.draw(0, 0, JPG); // Copy the JPEG onto the Bitmap
Kannst du auch das schreiben:
Delphi-Quellcode:
  BMP := TBitmap.Create;
  BMP.Pixelformat := pf32bit;
  BMP.Assign(JPG);
Zitat:

Zitat von EWeiss (Beitrag 1344970)
Es würde viel zu lange dauern 1000 Alben beim Start in ein Dictionary einzulesen und dann zu vergleichen wenn ein neuer Titel abgespielt wird.

Musst ja nicht beim Start über den ganzen Root-Ordner suchen, hat auch keiner vorgeschlagen.
Das Vergleichen mit den neuen Titel/Albumpfad ist übrigens super schnell per TDictonary.

Zitat:

Zitat von EWeiss (Beitrag 1344970)
Ich tue nichts anderes nur die Texture abspeichern halte ich für unnötig.

Wäre doch aber sinnvoller, da das neuladen ja anscheinend deine Performance-Bremse ist.

Letztendlich ist das auch nur ein *.jpg oder anderer typ.
Zitat:

Zitat von EWeiss (Beitrag 1344970)
Warum soll ich diese dann abspeichern wenn sie schon im Albums Pfad vorhanden ist.

Ich glaube du hast das falsch verstanden. Nicht abspeichern im Sinne von "auf die Festplatte schreiben" sondern abspeichern im Sinne von: im Arbeitsspeicher halten! Siehe TDictionary.

EWeiss 16. Aug 2016 15:51

AW: Beschleunigung von Laderoutine
 
Kannst mir das mal als Beispiele auf meine Routine übertragen?
So das ich das mal testen kann.

Ich bin mir auch nicht sicher ob D2010 TDictionary unterstützt (Habe es vorher noch nicht verwendet.)
Ok gibt es..

Zitat:

im Arbeitsspeicher halten! Siehe TDictionary.
Ah jo so wie ich sie im Array halte..

Zitat:

Behalte doch einfach die OpenGL-Texture während der Laufzeit des Plug-Ins?
Die frage wäre dann hier wie lange macht der Speicher das mit wenn ich innerhalb von 5 > 6 Stunden die ganzen Covers lade und im Speicher halte.

Das!
Delphi-Quellcode:
  BMP := TBitmap.Create;
  BMP.Pixelformat := pf32bit;
  BMP.Assign(JPG);
geht nicht.
Danach wird mein Plugin einfach beendet.

gruss

TiGü 17. Aug 2016 10:38

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von EWeiss (Beitrag 1345004)
Kannst mir das mal als Beispiele auf meine Routine übertragen?
So das ich das mal testen kann.

Du pflegst ja eher einen struktuierten Programmierstil, daher so:

Delphi-Quellcode:
...

uses
  System.Generics.Collections;

...

var
  EWeissCoverDictionary: TDictionary<string, GLuint>;

procedure Construct;
begin
  EWeissCoverDictionary := TDictionary<string, GLuint>.Create;
end;

procedure LoadCovers(const CoverPath: string; out Texture: GLuint);
begin
  if not EWeissCoverDictionary.TryGetValue(CoverPath, Texture) then
  begin
    LoadTexture(CoverPath, Texture, False);
    EWeissCoverDictionary.Add(CoverPath, Texture);
  end;
end;

procedure MachKaputtWasEuchKaputtMacht;
var
  Texture: GLuint;
begin
  for Texture in EWeissCoverDictionary.Values do
  begin
    glDeleteTextures(1, @Texture);
  end;
  EWeissCoverDictionary.Free;
end;
Zitat:

Zitat von EWeiss (Beitrag 1345004)
Das!
Delphi-Quellcode:
  BMP := TBitmap.Create;
  BMP.Pixelformat := pf32bit;
  BMP.Assign(JPG);
geht nicht.
Danach wird mein Plugin einfach beendet.

Haste dir schonmal nen try-except darum gebastelt und dir die Exception.Message ausgeben lassen?

EWeiss 17. Aug 2016 11:42

AW: Beschleunigung von Laderoutine
 
Zitat:

EWeissCoverDictionary
Cool so bin ich verewigt.

Werde es mir mal anschauen danke für das Beispiel.
Obwohl ich eigentlich mit dem aktuellen Stand zufrieden bin.
Hab das Teil im Hintergrund so ca. 5 Stunden laufen lassen.
Keine Probleme und der speicherverbrauch liegt so bei 48 MB.

EDIT:
Habe mir da mal angeschaut.

Letztendlich ist es so das es keinen sinn macht alle Covers incl. Texturen zu speichern.
Im habe maximal 25 Cover im Karussell wird das 26 Geladen dann wird das erste gelöscht
die anderen rücken dann nach und das 25 ist das aktuell spielende Album.
Wenn ich das erste Cover lösche welchen sinn macht es dann dieses gespeichert zu lassen
es kann aus dem Plugin dann nicht mehr abgespielt werden.

Der sinn des Karussell ist das man ein beliebiges Album nochmals spielen kann.
Ein gelöschtes Album kann man aber nicht mehr spielen von daher muss ich es auch nicht abspeichern
weder im Array, Dictionary noch in einer Datei.

Trotz allem ist schon interessant.

gruss

Zacherl 17. Aug 2016 14:06

AW: Beschleunigung von Laderoutine
 
Bei der von mir vorgeschlagenen Lösung würdest du jeweils maximal 25 Texturen behalten, aber müsstest trotzdem immer nur Eine neu laden.

Init:
Delphi-Quellcode:
InsertIndex := 0;
for I := Low(TextureArray) to High(TextureArray) do
begin
  TextureArray[I] := NoCoverTexture;
end;
Neues Album laden:
Delphi-Quellcode:
if (TextureArray[InsertIndex] <> NoCoverTexture) then
begin
  DeleteTexture(TextureArray[InsertIndex]);
end;
LoadTexture(Pfad, TextureArray[InsertIndex]);
Inc(InsertIndex);
if (InsertIndex = Length(A)) then
begin
  InsertIndex := Low(A);
end;
Zeichnen vom Carousel:
Delphi-Quellcode:
for I := InsertIndex to High(TextureArray) do
begin
  RenderTexture(TextureArray[I]);
end;
for I := Low(TextureArray) to InsertIndex - 1 do
begin
  RenderTexture(TextureArray[I]);
end;

TiGü 17. Aug 2016 17:01

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von EWeiss (Beitrag 1345043)
Letztendlich ist es so das es keinen sinn macht alle Covers incl. Texturen zu speichern.
Im habe maximal 25 Cover im Karussell wird das 26 Geladen dann wird das erste gelöscht
die anderen rücken dann nach und das 25 ist das aktuell spielende Album.
Wenn ich das erste Cover lösche welchen sinn macht es dann dieses gespeichert zu lassen
es kann aus dem Plugin dann nicht mehr abgespielt werden.

Lösche doch einfach nicht???

EWeiss 17. Aug 2016 18:42

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von TiGü (Beitrag 1345064)

Lösche doch einfach nicht???

Warum?

Wie soll ich dann das nächste Album addieren wenn das Maximum erreicht ist?
Was soll ich mit einem Cover das keine Verwendung mehr findet?
Warum soll ich unnötiger weise den Speicher mehr belasten als nötig?

gruss

EWeiss 17. Aug 2016 19:06

AW: Beschleunigung von Laderoutine
 
Zitat:

Bei der von mir vorgeschlagenen Lösung würdest du jeweils maximal 25 Texturen behalten, aber müsstest trotzdem immer nur Eine neu laden.
Danke das tut meine Version auch.. Trotz allem Danke für dein Beispiel.

Beim Start werden all Texturen mit NoCoverTexturen befüllt.
Delphi-Quellcode:
    // fill all Quads with NoCoverTexture
    if FileExists(FullDataPath + 'images\Default\NoCover.JPG') then
    begin
      LoadTexture(FullDataPath + 'images\Default\NoCover.JPG', NoCoverTexture, False);

      for q := 0 to QuadCount - 1 do
        quadTexture[q] := NoCoverTexture;
    end
    else
      NoCoverTexture := 0;
Anschließend wird die INI eingeladen.
Delphi-Quellcode:
procedure LoadINI;
var
  I: Integer;
  str: string;
  tmpList: TStringList;

begin

  tmpList := TStringList.Create;
  try
    With AlbumIni do
    begin
      aCovers.Clear;
      CoverCount := StrToInt(ReadString('AlbumCover', 'Count', '0'));
      if CoverCount > 0 then
      begin
        for I := 0 to CoverCount - 1 do
        begin
          str := ReadString('AlbumCover', 'Folder' + IntToStr(I), '');
          if (Length(str) > 0) then
            if FileExists(str) then
              aCovers.Add(str)
            else
              tmpList.Add(str);
        end;
      end;
    end;
  finally
    if tmpList.count > 0 then
    begin
      AlbumIni.EraseSection('AlbumCover');
      for I := 0 to aCovers.count - 1 do
        AlbumIni.WriteString('AlbumCover', 'Folder' + IntToStr(I), aCovers.strings[I]);
    end;

    tmpList.Free;
  end;

  AlbumIni.Free;

end;
In aCovers stehen jetzt alle 25 Pfade zu den Album Covers.
Jetzt werden all NoCoverTexturen mit den vorhandenen Covers gefüllt.

Delphi-Quellcode:
          if (aFileName = 'FOLDER') or (aFileName = Name) then
          begin
            if quadTexture[I] = NoCoverTexture then
              LoadTexture(aCovers[I], quadTexture[I], False);
            // add to List
            LstCoverPath.Add(aCovers[I]);
          end;
Und hier wird jetzt nur noch 1 Cover geladen..
Delphi-Quellcode:
      if (aCovers.count > QuadCount) then
      begin
        // delete first Cover
        aCovers.Delete(0);
        // move textures from destination to source
        for I := 0 to (aCovers.count - 1) do
        begin
          quadTexture[I] := quadTexture[I + 1];
          // add to List
          LstCoverPath.Add(aCovers[I]);
          // Load last Testure
          if I = (QuadCount - 1) then
          begin
            // extract Filename
            aFileName := ExtractFileName(aCovers[I]);
            // extract extension
            aFileName := Copy(aFileName, 1, Length(aFileName) - Length(ExtractFileExt(aFileName)));
            // uppercase
            aFileName := AnsiUpperCase(aFileName);

            Name := ExtractFileName(GetAlbumArtistName);
            if Name <> '' then
              Name := Copy(Name, 1, Length(Name) - Length(ExtractFileExt(Name)));
            if (aFileName = 'FOLDER') or (aFileName = Name) then
            begin
              if quadTexture[I] <> NoCoverTexture then
                glDeleteTextures(1, @quadTexture[I]);

              LoadTexture(aCovers[I], quadTexture[I], False);
            end;
          end;
        end;
      end
Der erste Eintrag in der Liste für die Pfade zu den Cover Bildern wird geöscht.
Delphi-Quellcode:
aCovers.Delete(0);


Hier werden die Texturen verschoben
Delphi-Quellcode:
quadTexture[I] := quadTexture[I + 1];


Jetzt wird die Liste zu den Cover Bildern aktualisiert
Delphi-Quellcode:
LstCoverPath.Add(aCovers[I]);


Wenn I das gleiche wie Maximaler Cover Count -1 dann wird die letzte Texture gelöscht
Delphi-Quellcode:
glDeleteTextures(1, @quadTexture[I]);


und nur noch einmalig für dieses Album geladen
Delphi-Quellcode:
LoadTexture(aCovers[I], quadTexture[I], False);


Das geht schnell ohne merklichen Performance Verlust.

Ich weiß das Rendern von dir ist nur ein Beispiel aber da steckt im Original einiges mehr an Funktionen drin
Delphi-Quellcode:
procedure RenderAlbum(aDeltaTime: single);
// Diese Funktion zeichnet die Quader. ColorScale skaliert dabei die Farbwerte der oberen beiden Ecken
procedure DrawQuads();
var
  I: Integer; // index der for-schleife
  QuadAngle: single; // die Rotation des aktuellen Quads
  aPos: TGLVectord3; // die finale Position des aktuellen Quads [aPos = array[0..2] of single]
begin

  glEnable(GL_TEXTURE_2D);

  glInitNames;
  glPushName(0);

  // alle Quads durchgehen
  for I := 0 to QuadCount - 1 do
  begin

    // Position initialisieren (aPos[0] = 0, aPos[1] = 0, aPos[2] = 10)
    aPos := Vector_Make3f(0, 0, 12);

    // Die Rotation des Quads (um den Mittelpunkt des Kreises, der durch die Quads gebildet wird)
    // + ListAnge, also die Rotation, die mit der Maus gemacht wird
    QuadAngle := DegToRad(360 / (QuadCount) * I) + ListAngle;

    // Den Positionvektor um den Mittelpunkt des Kreises um die Y-Achse rotieren
    aPos := Vector_Rotatef3(aPos, Vector_Make3f(0, 0, 0), QuadAngle, False, True, False);

    glBindTexture(GL_TEXTURE_2D, quadTexture[I]);

    if I = CurrentQuad then
    begin
      // Jetzt brauchen wir Blending
      glEnable(GL_BLEND);
      // nun die Blending-Funktion setzen
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glColor4f(1, 1, 1, 0.7);
      // move to foreground
      StayOnTop(aPos, 1.5);
      // show only available cover
      if not(quadTexture[I] = NoCoverTexture) then
      begin
        win.IMGTexture := quadTexture[I];
        win.bRenderGUI := True;
      end;
    end
    else
    begin
      // Original Farben setzen
      glColor4f(1, 1, 1, 1);
      // Blenden ausschalten
      glDisable(GL_BLEND);
    end;

    if not(LastAddCover = Round(NoCoverTexture)) then
      if LastAddCover = Trunc(quadTexture[I]) then
      begin
        glColor3f(1.0, 1.0, 1.0);
        glDisable(GL_TEXTURE_2D);
        // rahmen zeichnen
        glLineWidth(1);
        glBegin(GL_LINE_LOOP);
        glVertex3f(aPos[0] - QuadSizeS, aPos[1] + QuadSizeS * 2, aPos[2]);
        glVertex3f(aPos[0] - QuadSizeS, aPos[1], aPos[2]);
        glVertex3f(aPos[0] + QuadSizeS, aPos[1], aPos[2]);
        glVertex3f(aPos[0] + QuadSizeS, aPos[1] + QuadSizeS * 2, aPos[2]);
        glEnd;
        glEnable(GL_TEXTURE_2D);

        // Quad zeichnen
        glBegin(GL_QUADS);
        glTexCoord2f(0, 1);
        glVertex3f(aPos[0] - QuadSizeS, aPos[1] + QuadSizeS * 2, aPos[2]);
        glTexCoord2f(0, 0);
        glVertex3f(aPos[0] - QuadSizeS, aPos[1], aPos[2]);
        glTexCoord2f(1, 0);
        glVertex3f(aPos[0] + QuadSizeS, aPos[1], aPos[2]);
        glTexCoord2f(1, 1);
        glVertex3f(aPos[0] + QuadSizeS, aPos[1] + QuadSizeS * 2, aPos[2]);
        glEnd();
      end;

    // Quad zeichnen
    glBegin(GL_QUADS);
    glTexCoord2f(0, 1);
    glVertex3f(aPos[0] - QuadSize, aPos[1] + QuadSize * 2, aPos[2]);
    glTexCoord2f(0, 0);
    glVertex3f(aPos[0] - QuadSize, aPos[1], aPos[2]);
    glTexCoord2f(1, 0);
    glVertex3f(aPos[0] + QuadSize, aPos[1], aPos[2]);
    glTexCoord2f(1, 1);
    glVertex3f(aPos[0] + QuadSize, aPos[1] + QuadSize * 2, aPos[2]);
    glEnd();

    glLoadName(I + 1);
  end;
  glPopName;

end;

begin

  glDepthMask(ByteBool(GL_TRUE));

  // Kamera ausrichten, damit man was sieht
  glTranslatef(0, -7, -30);

  // Maus verarbeiten
  if FMousePos.X > 0 then
  begin
    if FMousePos.X < 30 then
      ListAngle := ListAngle - pi / 4 * aDeltaTime
    else if FMousePos.X > _FNormal.Image1.Width - 30 then
      ListAngle := ListAngle + pi / 4 * aDeltaTime;
  end;

  // Wichtig für die Spiegelung
  glDisable(GL_CULL_FACE);

  glEnable(GL_BLEND);
  // Jetzt spiegel wir alles an der x-z-Ebene
  glScalef(1, -1, 1);
  // Jetzt zeichnen wir zuerst die Reflektionen der Quads
  DrawQuads();

  glDisable(GL_BLEND);
  // Dann spiegel wir wieder zurück
  glScalef(1, -1, 1);
  // und zeichnen die eigentlichen Quads
  DrawQuads();

  // Jetzt brauchen wir Blending
  glEnable(GL_BLEND);
  // nun die Blending-Funktion setzen
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glBegin(GL_QUADS);
  glColor4f(0.0, 0.0, 0.0, 0.7);
  glVertex3f(-15, 0, 15);
  glVertex3f(-15, 0, -15);
  glVertex3f(15, 0, -15);
  glVertex3f(15, 0, 15);
  glEnd();
  glDisable(GL_BLEND);

  glLoadIdentity;

end;

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:22 Uhr.
Seite 3 von 3     123   

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