Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi glDeleteTextures gibt Speicher nicht frei (https://www.delphipraxis.net/114309-gldeletetextures-gibt-speicher-nicht-frei.html)

EWeiss 23. Mai 2008 05:58


glDeleteTextures gibt Speicher nicht frei
 
trotz alledem das ich die texturen lösche wird der Speicher nicht freigegeben


Delphi-Quellcode:
    if assigned(quadTexture) then
    begin
      for I := 0 to QuadCount - 1 do
      begin
       glDeleteTextures(i, @quadTexture);
       quadTexture[i] := 0;
      end;
    end;

    glDeleteTextures(1, @BackTexture);    // Texture für Hintergrund
    glDeleteTextures(1, @GradientTex);    // Texture für DiskSpectrum
    glDeleteTextures(1, @MeterTexture);   // Texture für VUMeter
    glDeleteTextures(1, @PeaksTexture);   // Texture für Peaks
    glDeleteTextures(1, @SpectrumTexture); // Texture für Spectrum
    glDeleteTextures(1, @BarTexture);     // Texture für Slider
    glDeleteTextures(1, @PrivateTexture); // Texture für CDLabel
woran kann es liegen ?
Wüßte jetzt nicht was da falsch ist.

gruss Emil

marabu 23. Mai 2008 06:56

Re: glDeleteTextures gibt Speicher nicht frei
 
Moin Emil,

unabhängig von irgendwelchen Speicherfreigaben - müsste das nicht eher so aussehen?

Delphi-Quellcode:
begin
  if Assigned(QuadTexture) then
  begin
    glDeleteTextures(Length(QuadTexture), @QuadTexture[Low(QuadTexture)]);
    SetLength(QuadTextures, 0);
  end;
  if Assigned(BackTexture) then
    // ...
end;
Ich habe jetzt mal dynamische Texture-Arrays angenommen.

Freundliche Grüße

Corpsman 23. Mai 2008 07:16

Re: glDeleteTextures gibt Speicher nicht frei
 
@EWeiss

dir ist aber schon klar das deine Texture Variablen Pointer sind, oder ?

Das heist.

Wenn du eine Varaible

Delphi-Quellcode:
var b:TBitmap;
hast. dann kannst du B.free machen , und gibst den speicher frei.


Die Abfrage

Delphi-Quellcode:
if assigned(b) then begin
end;
würde aber immer noch True ergeben, da b.free sich selbst nicht auf NIL setzt.

Genau das selbe ist es mit den OpenGL Texturen

als Test.

Gib deine Textur an einem Punkt frei nachdem du noch rendern kannst. ( also meinetwegen direkt wieder nach dem Laden )

dann stellst du fest das OpenGL dir stattdessen

1. Blödsinn
oder
2. eine weise Textur anzeigt

=> der speicher wurde freigegeben.

EWeiss 23. Mai 2008 10:36

Re: glDeleteTextures gibt Speicher nicht frei
 
@marabu
Dynamisches Array ist ok
hab dann wohl einen Denkfehler ;)
Hab nicht daran gedacht das ganze Array auf einmal zu löschen.


werd mal schaun ob es dann freigegeben wird.

Delphi-Quellcode:
begin
  if Assigned(QuadTexture) then
  begin
    glDeleteTextures(Length(QuadTexture), @QuadTexture[Low(QuadTexture)]);
    SetLength(QuadTextures, 0);
  end;
  if Assigned(BackTexture) then
    // ...
end;
@Corpsman
Zitat:

dir ist aber schon klar das deine Texture Variablen Pointer sind, oder ?
Hmmm...
warum sollte es das nicht sein die Trexture ist ein Pointer auf GLUnit 'PGlUint'

Delphi-Quellcode:
quadTexture        : array of GLuint;
ist ein dynamisches array auf gluint da ist nix mit 'free'

EDIT:
Auch wenn ich das Array(Texturen) in einem zug frei gebe steigt die Speicherbelastung stetig..

gruss Emil

littleDave 23. Mai 2008 11:42

Re: glDeleteTextures gibt Speicher nicht frei
 
Woran erkennst du denn, dass die Texturen nicht freigegeben werden? Dem Arbeitsspeicher kannst du das eigentlich nicht ansehen, da die Texturen im Grafikkarten-RAM gespeichert werden. Wenn der Grafikkarten-Speicher voll ist, werden die Texturen dann in den Arbeitsspeicher geschoben, aber sonst nicht.

Noch was zu deinem Code
Delphi-Quellcode:
if assigned(quadTexture) then
begin
  for I := 0 to QuadCount - 1 do
  begin
    glDeleteTextures(i, @quadTexture);
    quadTexture[i] := 0;
  end;
end;
Dieser Code funktioniert nicht. glDeleteTextures erwartet zwei Parameter. Der erste Parameter sagt OGL, wieviele Texturen gelöscht werden sollen. Der zweite Parameter ist ein Pointer auf das erste Element eines glUint-arrays (wenn nur eine Textur gelöscht werden soll, dann muss es kein array sein).
Dein Code von oben müsste man also folgendermaßen umschreiben (nur wenn du ihn mit der for-schleife benutzen willst)
Delphi-Quellcode:
if assigned(quadTexture) then
begin
  for I := 0 to QuadCount - 1 do
  begin
    glDeleteTextures(1, @quadTexture[i]);
    quadTexture[i] := 0;
  end;
end;
//Edit:
Ach noch was: sind die anderen Variablen zufällig auch arrays? Wenn du den Pointer auf das erste Element eines arrays zurückgeben willst, würd ich das immer so machen:
Delphi-Quellcode:
@NameDesArrays[0]

EWeiss 23. Mai 2008 11:51

Re: glDeleteTextures gibt Speicher nicht frei
 
Zitat:

Woran erkennst du denn, dass die Texturen nicht freigegeben werden? Dem Arbeitsspeicher kannst du das eigentlich nicht ansehen, da die Texturen im Grafikkarten-RAM gespeichert werden. Wenn der Grafikkarten-Speicher voll ist, werden die Texturen dann in den Arbeitsspeicher geschoben, aber sonst nicht.
Danke für deine Antwort ;)

Ich erkenne es daran das nach etwa 20 Titeln die Anwendung 150MB speicher belegt :)
Beim start sind es 30MB und es steigt stetig wenn das Album sich ändert
und die Texturen neu eingeladen werden.

Zitat:

Dieser Code funktioniert nicht. glDeleteTextures erwartet zwei Parameter. Der erste Parameter sagt OGL, wieviele Texturen gelöscht werden sollen. Der zweite Parameter ist ein Pointer auf das erste Element eines glUint-arrays (wenn nur eine Textur gelöscht werden soll, dann muss es kein array sein).
Ja hast du recht .. war ein flüchtigkeits fehler
Habe ja oben die einzelnen Texturen auch mit
Delphi-Quellcode:
glDeleteTextures(1, @BackTexture);    // Texture für Hintergrund
1 gelöscht.

Die schleife ansich macht das gleiche wie marabus vorschlag.
Nur seiner ist eleganter kann mir die schleife dann sparen.

EDIT:
Zitat:

Ach noch was: sind die anderen Variablen zufällig auch arrays? Wenn du den Pointer auf das erste Element eines arrays zurückgeben willst, würd ich das immer so machen:
Nein sind einzelne Texturen.

gruss Emil

littleDave 23. Mai 2008 12:26

Re: glDeleteTextures gibt Speicher nicht frei
 
Ich glaube, dass das Problem nicht bei glDeleteTextures liegt. Ich glaube, es liegt er daran, dass du die Texturdaten nach dem Laden nicht freigibst.

Normalerweise schaut das Laden einer Textur ungefähr so aus
Delphi-Quellcode:
glEnable(GL_TEXTURE_2D);
glGenTextures(1, @Texture);
glBindTexture(GL_TEXTURE_2D, Texture);
// Textur mit Daten füllen
glTexImage2D(GL_TEXTURE_2D, 0, 3, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, pTexData);
(die einzelnen Parameter sind jetzt mal beliebig gewählt)

In pTexData befinden sich jetzt die einzelnen RGB-Werte der Textur (in diesem Beispiel 768 KB). Diese Daten solltest du nach dem Laden wieder freigeben. Am besten mit FreeMem(pTexData);. Sonst spuken diese Daten im RAM herum, obwohl du sie nicht mehr brauchst.
Jetzt ist auch noch die Frage, wie du die Texturdaten aus der Datei in den Speicher bekommst (also pTexData mit RGB-Daten füllst). Wenn du z.B. TBitmap verwendest kann es noch sein, dass du die Instanz TBitmap nicht mehr freigibst.

Das ist jetzt alles nur eine Vermutung. Was du auch noch machen kannst: schau dir mal die Werte an, die die einzelnen Textur-Indizes haben (in meinem Beispiel den Wert von Texture). Soweit ich beobachtet habe sucht OpenGL den niedrigsten freien Wert und setzt ihn dann in die Variable. Wenn die Werte jetzt immer größer werden, werden die Texturen vielleicht nicht freigegeben. Ich bin mir da aber überhaupt nicht sicher, ob das überhaupt funktionierten kann.

EWeiss 23. Mai 2008 12:42

Re: glDeleteTextures gibt Speicher nicht frei
 
Ich lade sie so..

Delphi-Quellcode:
    if Assigned(QuadTexture) then
    begin
      glDeleteTextures(Length(QuadTexture), @QuadTexture[Low(QuadTexture)]);
      SetLength(QuadTexture, 0);
    end;

    glDeleteTextures(1, @BackTexture);    // Texture für Hintergrund
    glDeleteTextures(1, @GradientTex);    // Texture für DiskSpectrum
    glDeleteTextures(1, @MeterTexture);   // Texture für VUMeter
    glDeleteTextures(1, @PeaksTexture);   // Texture für Peaks
    glDeleteTextures(1, @SpectrumTexture); // Texture für Spectrum
    glDeleteTextures(1, @BarTexture);     // Texture für Slider
    glDeleteTextures(1, @PrivateTexture); // Texture für CDLabel

    if assigned(aCovers) then
     aCovers.Free;

    // Lade Cover für Quader
    aCovers := TStringList.Create;
    if CoverPath <> '' then
    begin
      if CoverPath <> Path then
        ScanDirectory(CoverPath, 'bmp, tga, jpg', True);

      tmpC := 0;
      if (aCovers.count <= QuadCount) then
      begin
        for i := 0 to aCovers.count-1 do
        begin
          if (ExtractFileName(AnsiLeftStr(aCovers.Strings[i], Length(aCovers.Strings[i]) - 4)) = 'COVER')
            or (ExtractFileName(AnsiLeftStr(aCovers.Strings[i], Length(aCovers.Strings[i]) - 4)) = 'CDLABEL') then
            begin
              if FileExists(Path + UpperCase('Data\images\CompDisk\Default\NoCover.jpg')) then
                LoadTexture(Path + 'Data\images\CompDisk\Default\NoCover.jpg', quadTexture[i], False);
              dec(tmpC);
            end else
            begin
              LoadTexture(aCovers.Strings[i], quadTexture[tmpC], False);
            end;
            inc(tmpC);

        end;

        if (QuadCount >= (aCovers.count - 1)) then
        begin
          for q := (aCovers.count - 1) to QuadCount do
            if FileExists(Path + UpperCase('Data\images\CompDisk\Default\NoCover.jpg')) then
              LoadTexture(Path + 'Data\images\CompDisk\Default\NoCover.jpg', quadTexture[q-1], False);
        end;
        exit;
      end;


      tmpA := 0;
      if (aCovers.count >= QuadCount) then
      begin
        for i := 0 to aCovers.count-1 do
        begin
          if (ExtractFileName(AnsiLeftStr(aCovers.Strings[i], Length(aCovers.Strings[i]) - 4)) = 'COVER')
            or (ExtractFileName(AnsiLeftStr(aCovers.Strings[i], Length(aCovers.Strings[i]) - 4)) = 'CDLABEL') then
            begin
              if FileExists(Path + UpperCase('Data\images\CompDisk\Default\NoCover.jpg')) then
                LoadTexture(Path + 'Data\images\CompDisk\Default\NoCover.jpg', quadTexture[i], False);
              dec(tmpA);
            end else
            begin
              if (tmpA) <= QuadCount-1 then
                LoadTexture(aCovers.Strings[i], quadTexture[tmpA], False);
            end;
            inc(tmpA);
          end;

          if (QuadCount >= (aCovers.count - 1)) then
          begin
          for q := (aCovers.count - 1) to QuadCount do
            if FileExists(Path + UpperCase('Data\images\CompDisk\Default\NoCover.jpg')) then
              LoadTexture(Path + 'Data\images\CompDisk\Default\NoCover.jpg', quadTexture[q-1], False);
          end;
      end;
    end;
aCovers ist ne TStringList

Ok kann man besser machen ;)
Das laden funktioniert ja lediglich das freigeben nicht

Zum laden benutze ich den Textureloader von Sulaco

gruss Emil

littleDave 23. Mai 2008 13:21

Re: glDeleteTextures gibt Speicher nicht frei
 
Ok, der Texturloader vom Jan Horn sollte nicht das Problem sein, den hab ich früher auch verwendet.
Ich glaube, du lädst die Texturen doppelt. Die if-Abfragen
Delphi-Quellcode:
if (aCovers.count <= QuadCount) then
// ...
if (aCovers.count >= QuadCount) then
überlagern sich, falls aCovers.Count = QuadCount ist. Außerdem: kann es ein, dass du aCovers nicht mehr freigibst (oder hast du das aCovers.Free einfach nur nicht mit in den Post kopiert)?

Ich würd die Lade-Routine mal umschreiben, im Moment ist die noch relativ umständlich:

Delphi-Quellcode:
if FileExists(Path + UpperCase('Data\images\CompDisk\Default\NoCover.jpg')) then
   LoadTexture(Path + 'Data\images\CompDisk\Default\NoCover.jpg', NoCoverTexture, False)
else
   NoCoverTexture := 0;

aCovers := TStringList.Create;
try
  if CoverPath <> Path then
     ScanDirectory(CoverPath, 'bmp, tga, jpg', True);

  aFilledQuads := 0;
  for i:=0 to aCovers.Count-1 do
  begin
    // den Dateinamen extrahieren
    aFileName := ExtractFileName(aCovers[i]);
    // die Dateiendung abscheiden
    aFileName := Copy(aFileName, 1, length(aFileName) - length(ExtractFileExt(aFileName)));
    // Upper-Case machen
    aFileName := AnsiUpperCase(aFileName);

    if (aFileName = 'COVER') or (aFileName = 'CDLABEL') then
    begin
      LoadTexture(aCovers[i], quadTexture[i], False);
    end else
      QuadTexture[i] := NoCoverTexture;

    inc(aFilledQuads);
   
    // Schleife beenden, falls alle Elemente von quadTexture gefüllt sind
    if i >= High(quadTexture) then
       break;
  end;
 
  // Falls noch ein paar ungefüllte Quads übrig sind, werden die auch noch mit der
  // NoCoverTexture gefüllt
  for i:=aFilledQuads to High(quadTexture) do
    QuadTexture[i] := NoCoverTexture;
finally
  aCovers.Free;
end;
Keine Garantie auf Korrektheit, hab den Quelltext ohne offene IDE geschrieben

EWeiss 23. Mai 2008 13:30

Re: glDeleteTextures gibt Speicher nicht frei
 
Zitat:

überlagern sich, falls aCovers.Count = QuadCount ist. Außerdem: kann es ein, dass du aCovers nicht mehr freigibst (oder hast du das aCovers.Free einfach nur nicht mit in den Post kopiert)?
Steht oben ;)
Zitat:

if assigned(aCovers) then
aCovers.Free;
Werde deine Routine mal testen.
Danke!

aCovers.free darf in Finaly nicht freigegeben werden da später im Code noch verwendet
Erst bei erneuten aufruf wenn neue Cover eingeladen werden.

gruss Emil


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:21 Uhr.
Seite 1 von 3  1 23      

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