Delphi-PRAXiS

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)

EWeiss 15. Aug 2016 18:51

Beschleunigung von Laderoutine
 
Meine Laderoutine..

Delphi-Quellcode:
  // is ShowCover
  if ShowCover then
  begin

    if CoverPath <> '' then
    begin
      if CoverPath <> Path then
        ScanDirectory(CoverPath, 'jpg, jpeg, png', False);

      if aCovers.count > -1 then
      begin
        LstCoverPath.Clear;
        LstQuadTexture.Clear;
      end;

      if (aCovers.count <= QuadCount) then
      begin
        for I := 0 to (aCovers.count - 1) do
        begin
          // extract Filename
          aFileName := ExtractFileName(aCovers[I]);
          // extract extension
          aFileName := Copy(aFileName, 1, Length(aFileName) - Length(ExtractFileExt(aFileName)));
          // uppercase
          aFileName := AnsiUpperCase(aFileName);

          Name := ExtractFileName(GetAlbumArtisName);
          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);
            LstQuadTexture.Add(IntToStr(quadTexture[I]));
            LstCoverPath.Add(aCovers[I]);
          end;
        end; // end for i

        transAlpha := 1.0;
        if (LastAddCover = 0) or (LastAddCover = Round(NoCoverTexture)) then
          Result := False;
        if LstCoverPath.count <> 0 then
        begin
          InitAlbumIniPath;
          SaveINI;
        end;
        exit; // exit For
      end
      else // else aCovers.count
      begin
        if (aCovers.count > QuadCount) then
        begin
          aCovers.Delete(0);
          for I := 0 to (aCovers.count - 1) do
          begin
            // extract Filename
            aFileName := ExtractFileName(aCovers[I]);
            // without extension
            aFileName := Copy(aFileName, 1, Length(aFileName) - Length(ExtractFileExt(aFileName)));

            aFileName := AnsiUpperCase(aFileName);

            Name := AnsiUpperCase(GetAlbumArtisName);
            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 + 1]);

              LoadTexture(aCovers[I], quadTexture[I], False);
              LstQuadTexture.Add(IntToStr(quadTexture[I]));
              LstCoverPath.Add(aCovers[I]);
            end;
          end; // end for i
          transAlpha := 1.0;
          if LstCoverPath.count <> 0 then
          begin
            InitAlbumIniPath;
            SaveINI;
          end;
        end; // end aCovers.count
      end; // end else aCovers.count
    end; // end CoverPath
  end; //end ShowCover
Hat jemand eine Idee wie man das beschleunigen könnte.?
Das Problem ist das ich bei jeder neu eingelegten CD (Abspielen eines Albums)
Alle Covers neu eingelesen und zugeordnet werden müssen da ich das erste Cover des Karussells lösche um am ende ein neues zu addieren.
Aber nur dann wenn das Cover sich noch nicht im Karussell befindet.

Mir fällt im Moment keine schnellere Lösung ein.
Was die Anwendung blockt ist LoadTexture.
Den Prozess weiterlaufen lassen bringt keine Abhilfe weil man dann das ersetzen jedes Cover sehen kann.

gruss

EWeiss 15. Aug 2016 20:49

AW: Beschleunigung von Laderoutine
 
OK..
Ich habe es zumindest schon mal verkleinert.
Wegen 1 Zeile

Delphi-Quellcode:
aCovers.Delete(0);


einen else Part einzurichten war nicht gerade gut durchdacht.

Das kann ich mir dann auch sparen..
Delphi-Quellcode:
if (aCovers.count <= QuadCount) then
Delphi-Quellcode:
    if CoverPath <> '' then
    begin
      if CoverPath <> Path then
        ScanDirectory(CoverPath, 'jpg, jpeg, png', False);

      if aCovers.count > -1 then
      begin
        LstCoverPath.Clear;
        LstQuadTexture.Clear;
      end;

      if (aCovers.count > QuadCount) then
        aCovers.Delete(0);
     
      for I := 0 to (aCovers.count - 1) do
      begin
        // extract Filename
        aFileName := ExtractFileName(aCovers[I]);
        // extract extension
        aFileName := Copy(aFileName, 1, Length(aFileName) - Length(ExtractFileExt(aFileName)));
        // uppercase
        aFileName := AnsiUpperCase(aFileName);

        Name := ExtractFileName(GetAlbumArtisName);
        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);
          LstQuadTexture.Add(IntToStr(quadTexture[I]));
          LstCoverPath.Add(aCovers[I]);
        end;
      end; // end for i

      transAlpha := 1.0;
      if (LastAddCover = 0) or (LastAddCover = Round(NoCoverTexture)) then
        Result := False;
      if LstCoverPath.count <> 0 then
      begin
        InitAlbumIniPath;
        SaveINI;
      end;
    end;
  end; //end ShowCover
Aber schneller ist das trotzdem nicht.

gruss

HolgerX 16. Aug 2016 04:31

AW: Beschleunigung von Laderoutine
 
Hmm..

Wann ändert sich der CoverPath?
Ändern sich die Bilder im CoverPath?

Wenn sich daran nichts seit Programmstart ändert, dann mach das ScanDirectory() nur einmal bei Programmstart und nicht bei jedem Wechsel.

Ist ein CD-Wechsel immer nur die nächste/vorherige CD ?
Wenn Ja, dann behalte doch die aktuell angezeigten Covers bereits aufbereitet im Speicher und verwerfe immer nur das herausfallende um dann das eine neue nach zu laden. Derzeit werden jedes mal alle Bilder neu geladen.

EWeiss 16. Aug 2016 04:57

AW: Beschleunigung von Laderoutine
 
Zitat:

Wann ändert sich der CoverPath?
Immer sobald sich das Album ändert.

Zitat:

Ändern sich die Bilder im CoverPath?
Selbe wie oben.

Zitat:

dann mach das ScanDirectory() nur einmal bei Programmstart und nicht bei jedem Wechsel.
Muss ich immer machen sobald sich ein Titel ändert sonst finde ich das Cover im Albumpfad nicht.

Zitat:

Ist ein CD-Wechsel immer nur die nächste/vorherige CD ?
Nein Unterschiedlich "Random" bzw.. das was in der Playliste steht.

Zitat:

Derzeit werden jedes mal alle Bilder neu geladen.
Ja und das ist mein Problem aber es geht nicht anders zumindest sehe ich im Moment keinen anderen weg.

1. Zu beginn wird das Karussell mit NoCoverTexturen gefüllt TextureID(20).
2. Ändert sich ein Album wird geprüft ob an der aktuellen Position eine NoCoverTexturen verwendet wird.
3. Wenn ja wird diese mit dem Cover ersetzt wenn vorhanden, solange bis alle NoCoverTexturen mit Covers belegt sind.
4. Sind im Karussell alle NoCoverTexturen gefüllt und der Counter mehr wie die maximale Anzahl an Covern wird das erste Cover gelöscht
und die anderen um einen platz nach hinten verschoben so das an letzter Position das alte durch das neue ersetzt wird.

5. Ist ein Cover vorhanden wird dieses verwendet ohne die alten zu ersetzen.
6. Ist kein Cover vorhanden dann wird die NoCoverTexturen für den Hintergrund verwendet die Covers im Karussell ändern sich dann nicht.

Es ist so eingerichtet das nicht immer das letzte ersetzt wird sondern alle Cover um eins nach hinten verschoben werden.
So hat man die Möglichkeit innerhalb von 25 Alben eines der vorherig verwendeten nochmals zum spielen auszuwählen.

Hmm.. :idea:
Müsste mal versuchen ob ich die vorherigen Covers mit den alten umstrukturieren kann ohne diese zu laden.
Noch keine Ahnung wie das dann mit dem Speicher aussieht wenn die vorherigen nicht gelöscht werden.

gruss

Zacherl 16. Aug 2016 05:09

AW: Beschleunigung von Laderoutine
 
Ich nehme an, du lädst jedes Mal z.b. bei Punkt 4 alle Cover neu? Falls ja, könntest du dein Array mit den Texturen auch als RingBuffer behandeln und nur intern eine Shift-Value verwalten, die angibt, an welcher Stelle des Arrays der "echte" Anfang zu finden ist. Dein Carousel renderst du dann nicht statisch von
Delphi-Quellcode:
Low(Array)
zu
Delphi-Quellcode:
High(Array)
, sondern einmal von
Delphi-Quellcode:
Array[StartIndex]
bis
Delphi-Quellcode:
High(Array)
und dahinter noch einmal von
Delphi-Quellcode:
Low(Array)
bist
Delphi-Quellcode:
Array[StartIndex - 1]
.

Sowas in der Art:
https://en.wikipedia.org/wiki/Circul...ircular_buffer

Wobei du dir das Ende nicht merken musst, da bei dir die leeren Elemente ja mit der NoTexture aufgefüllt werden.

EWeiss 16. Aug 2016 05:17

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von Zacherl (Beitrag 1344944)
Ich nehme an, du lädst jedes Mal z.b. bei Punkt 4 alle Cover neu? Falls ja, könntest du dein Array mit den Texturen auch als RingBuffer behandeln und nur intern eine Shift-Value verwalten, die angibt, an welcher Stelle des Arrays der "echte" Anfang zu finden ist. Dein Carousel renderst du dann nicht statisch von
Delphi-Quellcode:
Low(Array)
zu
Delphi-Quellcode:
High(Array)
, sondern einmal von
Delphi-Quellcode:
Array[StartIndex]
bis
Delphi-Quellcode:
High(Array)
und dahinter noch einmal von
Delphi-Quellcode:
Low(Array)
bist
Delphi-Quellcode:
Array[StartIndex - 1]
.

Sowas in der Art:
https://en.wikipedia.org/wiki/Circul...ircular_buffer

Danke werde das mal als Ansatz nehmen um das ZU häufige laden der Texturen zu vermeiden.
Das mit ScanDirectory ist das kleinste Problem damit wird ja nur das nächste Cover gesucht.
welches den Namen FOLDER bzw.. "Album - Artist" haben kann.

"Folder.jpg" oder "The Wall (1979) - Pink Floyd.jpg" als Beispiel.

Zitat:

Wobei du dir das Ende nicht merken musst, da bei dir die leeren Elemente ja mit der NoTexture aufgefüllt werden.
Nein ganz so ist es nicht diese sind bzw. bleiben nur mit NoTexture gefüllt solange sie nicht mit Covern ersetzt wurden.
Also beim ersten start wenn noch keine AlbumCover.ini existiert.

Wird nachher ein Pfad zu einem Bild in der INI nicht gefunden warum auch immer
wird diese gelöscht und alles geht von vorne los.

gruss

Billa 16. Aug 2016 06:31

AW: Beschleunigung von Laderoutine
 
Ohne den Source komplett nachvollzogen zu haben, eine Anregung:

Es geht doch um Anzeige?! Statt die Daten im "Karussell" zu bewegen, könnte man die Sache beschleunigen, indem man nur einen Index (also ein weiteres Array mit Verweisen auf das eigentliche Karussell) manipuliert.

Habe mal so etwas für eine Anzeige eines Rennverlaufs (mit Fotos der Jockeys/Pferde) gemacht. Da kam es bei den Änderungen auf Aktualität/Geschwindigkeit an. Allerdings war die Zahl der Teilnehmer "endlich", d.h. es kamen keine neuen hinzu.

Gruß

Mavarik 16. Aug 2016 07:47

AW: Beschleunigung von Laderoutine
 
Warum speicherst Du das nicht zwischen?

Erzeuge Dir ein TDictionary mit den Covernamen und dem entsprechenden Bild und genauso das Dir...
Dann musst Du nur 1 Cover neu laden, rest is in Memory...

EWeiss 16. Aug 2016 09:22

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von Mavarik (Beitrag 1344947)
Warum speicherst Du das nicht zwischen?

Erzeuge Dir ein TDictionary mit den Covernamen und dem entsprechenden Bild und genauso das Dir...
Dann musst Du nur 1 Cover neu laden, rest is in Memory...

Ich erzeuge ja schon zwei TStringList und speichere die Daten zwischen..

Ich bin noch am Testen ist nicht ganz so einfach.
Das letzte Cover macht mir Schwierigkeiten beim verschieben.

Delphi-Quellcode:
        for I := 0 to (aCovers.count - 1) do
        begin
          quadTexture[I] := quadTexture[I + 1];
Das letzte ist dann nicht mehr initialisiert weil es auf den vorherigen platz verschoben wurde.
Dementsprechend kann ich das auch nicht freigeben.. weil nicht mehr gültig.

Siehe Anhang! Anfang und Ende..

EDIT:
Unterumständen muss ich dann die länge des Arrays neu setzen also den 24 Eintrag entfernen.
Werde nochmal testen. (bringt nix)

gruss

Mavarik 16. Aug 2016 09:54

AW: Beschleunigung von Laderoutine
 
OK- Ich verstehe nicht so ganz was Du da machst, aber eigentlich sollte das - so schnell sein, dass Du keine Verzögerung merkst... Von was sprechen wir hier?

Neutral General 16. Aug 2016 09:59

AW: Beschleunigung von Laderoutine
 
Nimm doch statt nem Array eine Liste. Das ist doch tausend mal einfacher als den Kram in Arrays rumzuschieben.
Außerdem ist die Zeile hier unnötig:
Delphi-Quellcode:
if aCovers.count > -1 then

Eine Liste hat immer mehr als -1 Einträge ;)

TiGü 16. Aug 2016 10:01

AW: Beschleunigung von Laderoutine
 
Wie sieht denn die LoadTexture-Methode aus?
Wäre es nicht auch zweckmäßig diese zu untersuchen, da du im ersten Post schreibst, das diese Methode blockt?

EWeiss 16. Aug 2016 10:07

AW: Beschleunigung von Laderoutine
 
Zitat:

OK- Ich verstehe nicht so ganz was Du da machst
Sorry aber ich verstehe nicht was du meinst.
Auf der einen Seite sagst du verstehst es nicht was ich mache aber im gleichen Atemzug
gehst du davon aus
Zitat:

aber eigentlich sollte das - so schnell sein, dass Du keine Verzögerung merkst
Zitat:

Von was sprechen wir hier?
Davon das laden der Cover zu beschleunigen..

Wenn es schnell genug wäre hätte ich mir die Frage danach sparen können und euch damit nicht belästigt.

Das Problem ist das ich die Covers jedes Mal alle neu einlade.
Nun habe ich versucht die Texturen umzustrukturieren.
Die erste Texture wird gelöscht und diese dann mit der darauffolgendem neu gefüllt.
Das geht schnell ohne das ich alle Texturen neu laden muss.

Das Problem das aber nun auftaucht ist das dann die letzte Texture ungültig wird weil sie verschoben wurde.
Dies hat zur folge das beim laden der letzten Texture die Nummerierung nicht fortläuft.

Das laden von 25 Texturen nach jedem Liedwechsel verursacht in etwa eine Ladezeit von 2> Sekunden was mein Plugin quasi anhält.
Das will ich vermeiden.

gruss

EWeiss 16. Aug 2016 10:12

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von TiGü (Beitrag 1344957)
Wie sieht denn die LoadTexture-Methode aus?
Wäre es nicht auch zweckmäßig diese zu untersuchen, da du im ersten Post schreibst, das diese Methode blockt?

Ich möchte den Prozess des Laden nicht unterbrechen..
Das macht man ja auch nicht wenn man normale Bitmaps laden tut.

Ich denke auch nicht das man hier etwas manipulieren sollte und ob sich da letztendlich was tut mag dahingestellt sein.
Aber gut hier die für JPG!

Delphi-Quellcode:
function CreateTexture(Width, Height, Format: word; pData: Pointer): integer;
var
  Texture: GLuint;
begin
  glGenTextures(1, @Texture);
  glBindTexture(GL_TEXTURE_2D, Texture);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  {Texture blends with object background}

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  { only first two can be used }
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  { all of the above can be used }

  if Format = GL_RGBA then
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, Width, Height, GL_RGBA,
      GL_UNSIGNED_BYTE, pData)
  else
    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, pData);

  Result := Texture;
end;
Delphi-Quellcode:
function LoadJPGTexture(Filename: string; var Texture: GLuint;
  LoadFromResource: boolean): boolean;
var
  Data: array of longword;
  W, Width: integer;
  H, Height: integer;
  BMP: TBitmap;
  JPG: TJPEGImage;
  C:   longword;
  Line: ^longword;
  ResStream: TResourceStream;     // used for loading from resource
begin
  Result := False;
  JPG   := TJPEGImage.Create;

  if LoadFromResource then // Load from resource
  begin
    try
      ResStream := TResourceStream.Create(hInstance,
        PChar(copy(Filename, 1, Pos('.', Filename) - 1)), 'JPEG');
      JPG.LoadFromStream(ResStream);
      ResStream.Free;
    except
      on
        EResNotFound do
      begin
        MessageBox(0, PChar('File not found in resource - ' + Filename),
          PChar('JPG Texture'), MB_OK);
        Exit;
      end
      else
      begin
        MessageBox(0, PChar('Couldn''t load JPG Resource - "' + Filename + '"'),
          PChar('BMP Unit'), MB_OK);
        Exit;
      end;
    end;
  end
  else
  begin
    try
      JPG.LoadFromFile(Filename);
    except
      MessageBox(0, PChar('Couldn''t load JPG - "' + Filename + '"'),
        PChar('BMP Unit'), MB_OK);
      Exit;
    end;
  end;

  // 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

  //  BMP.SaveToFile('D:\test.bmp');
  Width := BMP.Width;
  Height := BMP.Height;
  SetLength(Data, Width * Height);

  for H := 0 to Height - 1 do
  begin
    Line := BMP.scanline[Height - H - 1];  // flip JPEG
    for W := 0 to Width - 1 do
    begin
      c := Line^ and $FFFFFF; // Need to do a color swap
      Data[W + (H * Width)] := (((c and $FF) shl 16) + (c shr 16) + (c and $FF00)) or $FF000000;
      // 4 channel.
      Inc(Line);
    end;
  end;

  BMP.Free;
  JPG.Free;

  Texture := CreateTexture(Width, Height, GL_RGBA, addr(Data[0]));
  SetLength(Data, 0);

  Result := True;
end;
gruss

EWeiss 16. Aug 2016 10:16

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von Neutral General (Beitrag 1344956)
Nimm doch statt nem Array eine Liste. Das ist doch tausend mal einfacher als den Kram in Arrays rumzuschieben.
Außerdem ist die Zeile hier unnötig:
Delphi-Quellcode:
if aCovers.count > -1 then

Eine Liste hat immer mehr als -1 Einträge ;)

Ja du hast Recht ;) Ka was mich da geritten hat..
> wie 0 dann halt ändert aber nichts an meinem Problem.

Und ja es ist eine Liste kein Array.. (obwohl die liste letztendlich auch aus einem besteht.)

Solltest du das Array QuadTexture meinen. Ja das ist ein Array auf GLUint und hat seine Berechtigung.
Ich habe keinen Bock zwischen Strings und GLUint herum zu jonglieren.


gruss

EWeiss 16. Aug 2016 11:07

AW: Beschleunigung von Laderoutine
 
So geht's jetzt.
Mal sehen ob ich an anderer stelle noch was optimieren kann.

Delphi-Quellcode:
  // is ShowCover
  if ShowCover then
  begin
    if CoverPath <> '' then
    begin
      if CoverPath <> Path then
        ScanDirectory(CoverPath, 'jpg, jpeg, png', False);

      if aCovers.count > 0 then
        LstCoverPath.Clear;

      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
      else
      begin
        for I := 0 to (aCovers.count - 1) do
        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
              LoadTexture(aCovers[I], quadTexture[I], False);

            // add to List
            LstCoverPath.Add(aCovers[I]);
          end;
        end; // end for i
      end;

      transAlpha := 1.0;
      if (LastAddCover = 0) or (LastAddCover = Round(NoCoverTexture)) then
        Result := False;
      if LstCoverPath.count <> 0 then
      begin
        InitAlbumIniPath;
        SaveINI;
      end;
    end;
  end; //end ShowCover
Danke für die Hilfe..

gruss

Mavarik 16. Aug 2016 11:17

AW: Beschleunigung von Laderoutine
 
OK...

Warum speicherst Du nicht die fertigen Data's

Dann brauchst Du nur die Pointer um legen...

EWeiss 16. Aug 2016 11:31

AW: Beschleunigung von Laderoutine
 
Zitat:

Zitat von Mavarik (Beitrag 1344962)
OK...

Warum speicherst Du nicht die fertigen Data's

Dann brauchst Du nur die Pointer um legen...

Ich weiß jetzt nicht welche Daten du meinst die ich abspeichern soll.
Bei den Covers mache ich es ja schon.

Und wenn es am spielen ist ändern diese sich immer abhängig vom Album natürlich das gerade wechselt.
Es ist jetzt zumindest so das die Texturen wechseln wenn das Lied abspielt und nicht erst ein paar Sekunden später.

Nur am Anfang werden alle Covers geladen dann nur noch jeweils eins.

gruss

TiGü 16. Aug 2016 12:28

AW: Beschleunigung von Laderoutine
 
Was Mavarik meint ist wohl folgendes:
Warum lädst und erzeugst du die Texturen für jedes Abspielen eines einzelnen Songs neu?
Es wäre doch sinnvoller, beim "Betreten" eines Albumordners einmalig das JPEG zu laden und die Textur zu erzeugen und abzuspeichern. Hierfür würde sich das erwähnte Dictionary anbieten mit den Albumordner-string als Key und die OpenGL-Texture als Value.

EWeiss 16. Aug 2016 12:39

AW: Beschleunigung von Laderoutine
 
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.
Dann werden die Texturen jetzt lediglich im Array verschoben so das ich sie nicht neu laden muss.
Wie gesagt NUR dann wenn nicht vorhanden wird geladen. Da ist mit Dictionary nichts zu machen.
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.

So speichere ich nur die 25 Alben bzw. so viele wie sich im Karussell befinden ab 5 und aufwärts max 25
Zudem habe ich keinen Einfluss darauf welches Album gerade gespielt wird.
Das ist ein Plugin das sich die Daten über die Audio-Anwendung holt welche dieses verwendet.

Zitat:

Es wäre doch sinnvoller, beim "Betreten" eines Albumordners einmalig das JPEG zu laden und die Textur zu erzeugen und abzuspeichern.
Ich tue nichts anderes nur die Texture abspeichern halte ich für unnötig.
Letztendlich ist das auch nur ein *.jpg oder anderer typ.
Warum soll ich diese dann abspeichern wenn sie schon im Albums Pfad vorhanden ist.
Die Texture ID bringt mir gar nichts.

gruss

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 22:38 Uhr.

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