[Gelöst] Speicherleiche bei Texturenerzeugung mit SDL und OpenGL
-
dot schrieb:
Ich versteh nicht ganz wo dein Problem liegt? Es passiert doch genau das, was du programmiert hast!? Bei jedem Aufruf dieser Funktion wird eine neue Textur erzeugt. Natürlich braucht diese Textur auch Speicher!? Die Frage die du dir stellen solltest ist: Warum ruf ich diese Funktion so oft auf und was passiert mit den erzeugten Texturen, wenn sie nichtmehr benötigt werden?
Ich will im Prinzip nur eine bereits erzeugte Textur aus dem Speicher bekommen, um keine Speicherleichen zu haben.
Innerhalb der Laufzeit sollen schließlich mehrere Texturen erzeugt werden, die später nicht mehr notwendig sind.
-
Wenn du eine bereits erzeugte Textur willst, dann verwend doch einfach die bereits erzeugte Textur, anstatt eine neue zu erzeugen!?
-
ich kann doch nicht alle Texturen, die irgendwann mal gebraucht werden könnten, in den Speicher laden. Dann hätte ich bei vielen Texturen einen Instant Overflow, anstatt Leichen zu stapeln.
-
Ki schrieb:
ich kann doch nicht alle Texturen, die irgendwann mal gebraucht werden könnten in den Speicher laden.
Wer sagt dass du das sollst?
Mir ist leider immer noch völlig unklar, was genau jetzt dein Problem ist. Wenn du eine Textur nichtmehr benötigst, dann gib sie eben frei. Und wenn du eine Textur benötigst, die du noch nicht geladen hast, dann lade sie. Und wenn sie aber doch schon geladen wurde, dann verwend die geladene, anstatt eine neue zu erzeugen. Wo genau scheiterts jetzt?
-
Ich scheitere am Freigeben des Speichers innerhalb der Funktion
loadTexture()
.Ich will
loadTexture()
nutzen, um in der Laufzeit einer Variable, z.B.texture
, eine Textur zuzuweisen. Die Textur soll nur im Gültigkeitsbereich dieser Variable existieren.
-
Persönlich würde ich versuchen, das zu vermeiden. Lieber am Anfang versuchen, alles direkt zu initialisieren, einzuladen und zu sortieren, als die Textur dann zu laden, wenn Sie gebraucht wird. Früher, als der Speicher noch wirklich rar war und man selbst den Soundchipspeicher verwendet hat, um alles, was man im Spiel wollte, unterzukriegen, konnte man das machen, aber heutzutage ist Speicher billig und das Leben kurz, da sollte man die CPU/GPU nicht in der Laufzeit mit dem Laden einer eventuell aufwendigen Textur belasten - stört nur den Spielfluss.
Meine unnötige Meinung zu dem Thema.
Dann kann innerhalb des Programms mit der Tabelle gearbeitet werden, und es muss nicht ständig auf die Festplatte zugegriffen werden.
-
Der aus dem Westen ... schrieb:
Persönlich würde ich versuchen, das zu vermeiden. Lieber am Anfang versuchen, alles direkt zu initialisieren, einzuladen und zu sortieren, als die Textur dann zu laden, wenn Sie gebraucht wird. Früher, als der Speicher noch wirklich rar war und man selbst den Soundchipspeicher verwendet hat, um alles, was man im Spiel wollte, unterzukriegen, konnte man das machen, aber heutzutage ist Speicher billig und das Leben kurz, da sollte man die CPU/GPU nicht in der Laufzeit mit dem Laden einer eventuell aufwendigen Textur belasten - stört nur den Spielfluss.
Mein Programm ist modular in Szenen aufgebaut. Jede Szene ist ein Objekt einer speziellen Tochterklasse einer gemeinsamen Elternklasse. Zu Beginn jeder Szene, also beim Anlegen des Objektes, werden daher die Texturen eingeladen.
-
Was hält dich davon ab, Verweise auf die geladenen Texturen zu erstellen? Eingeladen werden müssen die so oder so, aber wenn du die Texturen in einer internen Tabelle mit Schlüsseln verpackst, sparst du einiges an Laufzeit. Wenn die Szene dann aufgerufen wird, weißt du bloß die entsprechenden und bereits geladenen Texturen zu, und fertig. Würde ich zumindest so machen . so ersparst du dir ständige Zugriffe auf die Festplatte.
-
@TE
Du solltest dich mal mit den Grundlagen beschäftigen. loadImage() gibt ein GLUint zurück - keinen Pointer. Darauf delete? Schlechte Idee. glTexImage2D kopiert das Bild übrigens, da wird Speicher reserviert! Lies die Doku! Wie wäre es, glDeleteTexture aufzurufen?
Ich will loadTexture() nutzen, um in der Laufzeit einer Variable, z.B. texture, eine Textur zuzuweisen. Die Textur soll nur im Gültigkeitsbereich dieser Variable existieren.
Was gibt es besseres als eine Klasse? Im Konstruktor erstellst du die Texture, im Destruktor gibst du sie wieder frei. Einfacher geht es wirklich nicht. Dazu noch nen Move-Konstruktor und alles ist in Butter.
-
cooky451 schrieb:
@TE
Du solltest dich mal mit den Grundlagen beschäftigen. loadImage() gibt ein GLUint zurück - keinen Pointer. Darauf delete? Schlechte Idee. glTexImage2D kopiert das Bild übrigens, da wird Speicher reserviert! Lies die Doku! Wie wäre es, glDeleteTexture aufzurufen?
Wird wo gemacht?
cooky451 schrieb:
Was gibt es besseres als eine Klasse? Im Konstruktor erstellst du die Texture, im Destruktor gibst du sie wieder frei. Einfacher geht es wirklich nicht. Dazu noch nen Move-Konstruktor und alles ist in Butter.
Die Freigabe ist das, wonach ich in diesem Thread frage. Wie gibt man den Speicherbereich der Textur effektiv frei?
EDIT:
cooky451 schrieb:
glTexImage2D kopiert das Bild übrigens, da wird Speicher reserviert! Lies die Doku! Wie wäre es, glDeleteTexture aufzurufen?
glDeleteTexture war das, wonach ich brauchte, danke
-
Ki schrieb:
Wird wo gemacht?
Hast du gerade wegeditiert,nice. Der Code ist aber immer noch ziemlich hässlich.
Ki schrieb:
GLuint *image = new GLuint; *image = loadTexture("img.png"); delete image;
Oh man.. bist du Java programmierer?
Ich habe dir doch schon geschrieben, wie du du das freigibst. Lies die Beiträge hier. glDeleteTexture. [Edit: Na das hast du gefunden, immerhin. :p ]
Mal ein Beiespiel:
class Texture { GLUint id_; public: Texture(const std::string &filename) { // Hier Textur laden. Als "object" id_ nutzen. } Texture(Texture &&texture) : id_(texture.id_) // Move Konstruktor. { texture.id_ = 0; } ~Texture() { glDeleteTextures(1, &id_); // Hier wird die Textur freigegeben. } };
Anwendung:
void foo() { Texture texture("xyz.zyx"); // Hier wird die Textur geladen } // Destruktor gibt frei.
-
cooky451 schrieb:
Ki schrieb:
Wird wo gemacht?
Hast du gerade wegeditiert,nice. Der Code ist aber immer noch ziemlich hässlich.
Ich habe nur den Datentyp geändert, bei dem ich mich vertippt habe.
cooky451 schrieb:
Ki schrieb:
GLuint *image = new GLuint; *image = loadTexture("img.png"); delete image;
Oh man.. bist du Java programmierer?
Es liegt mir fern, Trolle zu unterstützen, aber du solltest vielleicht mal darüber nachdenkt, ob man schnelle Code-Beispiele nicht eventuell immer auf das notwendigste reduziert.
cooky451 schrieb:
Ich habe dir doch schon geschrieben, wie du du das freigibst. Lies die Beiträge hier. glDeleteTexture.
Las ich erst nach dem Posten, daher mein EDIT.
Klassen anlegen kann ich selbst, dennoch danke.
-
Ki schrieb:
Ich habe nur den Datentyp geändert, bei dem ich mich vertippt habe.
Ja.. und ein paar Sternchen gemacht, die die Bedeutung deines Codes völlig verändert haben.
Ki schrieb:
Es liegt mir fern, Trolle zu unterstützen, aber du solltest vielleicht mal darüber nachdenkt, ob man schnelle Code-Beispiele nicht eventuell immer auf das notwendigste reduziert.
Du schreibst also ernsthaft:
void foo() { int *i = new int; *i = 5; delete i; }
statt
void foo() { int i = 5; }
? Super.
Ki schrieb:
Klassen anlegen kann ich selbst, dennoch danke.
Ja, das sehe ich.
-
Auch wenn es amüsant ist, zu sehen, wie deine Arroganz deine Fähigkeit, Sachverhalte und den beabsichtigten Sinn dahinter korrekt zu reflektieren, trübt:
CLOSED
Deal with it.
Auf weiteren Streit werde ich nur via Mail eingehen.
-
Ki schrieb:
Auch wenn es amüsant ist, zu sehen, wie deine Arroganz deine Fähigkeit, Sachverhalte und den beabsichtigten Sinn dahinter korrekt zu reflektieren, trübt:
Ich würde mir seine Anmerkungen an deiner Stelle zu Herzen nehmen. Er hat dich auf ein Problem mit deinem Code hingewiesen, offenbar mangelt es dir noch an wesentlichen Grundlagen, was C++ angeht. Ich kann dir nur empfehlen, zumindest mal ernsthaft drüber zu reflektieren.
Ki schrieb:
Ich will
loadTexture()
nutzen, um in der Laufzeit einer Variable, z.B.texture
, eine Textur zuzuweisen. Die Textur soll nur im Gültigkeitsbereich dieser Variable existieren.Und die Lösung dafür, hat cooky451 dir in seinem vorletzten Post geliefert. Du solltest versuchen, ihn zu verstehen.
Der aus dem Westen ... schrieb:
Persönlich würde ich versuchen, das zu vermeiden. Lieber am Anfang versuchen, alles direkt zu initialisieren, einzuladen und zu sortieren, als die Textur dann zu laden, wenn Sie gebraucht wird.
Ja, das kannst du vielleicht bei einem Pong machen. Aber bei nem richtigen Spiel wird man alles mögliche unternehmen, um gerade bei Texturen den Speicherverbrauch unter Kontrolle zu halten. 512MB sind sehr schnell mal voll.
-
dot schrieb:
Ich würde mir seine Anmerkungen an deiner Stelle zu Herzen nehmen. Er hat dich auf ein Problem mit deinem Code hingewiesen, offenbar mangelt es dir noch an wesentlichen Grundlagen, was C++ angeht. Ich kann dir nur empfehlen, zumindest mal ernsthaft drüber zu reflektieren.
Ich verstehe die Aufregung darüber nicht. Ich habe bei einem simplen Beispiel für das "Löschen" einer Variable, nach dem ich gefragt wurde, den Datentyp wegen Schussligkeit falsch gesetzt. Spätestens beim kompilieren merkt man das doch.
dot schrieb:
Und die Lösung dafür, hat cooky451 dir in seinem vorletzten Post geliefert. Du solltest versuchen, ihn zu verstehen.
Für die Lösung bin ich auch, wie gesagt, sehr dankbar, aber man muss doch nicht immer mit allen Mitteln trollen, erst recht nicht in einem Forum. Mehr als das habe ich nicht kritisiert.
-
Um das mal aus meiner Sicht zu schildern, vielleicht hast du dann etwas mehr Verständnis dafür, Ki.
1. Der Eingangspost. Du hast dir scheinbar noch nicht mal die Doku zu jedem Befehl durchgelesen.
2. "Das Löschen", Version 1:SDL_Surface *s = new SDL_Surface; // Oder so. Ich habe keine Ahnung von SDL, aber das sah noch in Ordnung aus. s = loadImage("abc.png"); // Okay, hier hast du den Pointer verworfen und gleichzeitig zeigt s jetzt irgendwo in die Pampa. delete s; // Hier versuchtest du irgendwas zu löschen, wo auch immer "s" gerade hinzeigt.
Der Code ging ja schon mal gar nicht. Sah wie kopiert und überhaupt nicht verstanden aus. Nachdem ich dich dann darauf hingewiesen hatte, kam das Edit auf die jetzige Version. Da dir new und delete weglassen aber wohl als zu auffällig erschien, kam halt extremer Quatsch dabei raus. (Den du auf Nachfrage auch noch rechtfertigen wolltest. oO)
Dann noch Frage:
Ich will loadTexture() nutzen, um in der Laufzeit einer Variable, z.B. texture, eine Textur zuzuweisen. Die Textur soll nur im Gültigkeitsbereich dieser Variable existieren.
Nachdem ich dir dann eine Lösung gezeigt habe, kam:
Klassen anlegen kann ich selbst, dennoch danke.
Super.
-
dot schrieb:
Ja, das kannst du vielleicht bei einem Pong machen. Aber bei nem richtigen Spiel wird man alles mögliche unternehmen, um gerade bei Texturen den Speicherverbrauch unter Kontrolle zu halten. 512MB sind sehr schnell mal voll.
Mag sein, dass ich ein speicherverwöhnter , nichtsahnender Westentaschenprogrammierer bin (an meinem Notebook habe ich 8 GBs, die locker reichen
da sollen mir 512 MB mal kommen). Aber ich rede jetzt von den Rohdaten.
Wir entwickeln uns langsam in eine Richtung, in der ein Spiel durchaus komplett in den Arbeitsspeicher geladen werden kann. Gut, vielleicht habe ich in letzter Zeit kein allzu neues Spiel gespielt, aber wenn du 8 oder gar 16 GB an Speicher hast, sollte man in der Lage sein, große Teile des Spiels da rein laden zu können, und da berechne ich die 1-2 GB, die eventuelle Teile des Betriebssystems belegen, mit ein. Wenn ein Spiel 8 GB an Daten fasst und ich verhältnismässig dynamisch programmiere, kann ich dafür sorgen, dass kaum auf die Festplatte zugegriffen werden muss.
Oder noch besser, man teilt das Spiel in mehrere gedankliche Sektionen und lädt für jede Sektion den Pulk an Daten, den man für diese Sektion braucht. 4 GB in den Speicher geladen, und solange man sich in dieser Sektion aufhält, muss nur wegen automatischer Sicherung und eventuelles Logging auf die Festplatte zugegriffen werden.
Die einzige Behinderung, die mir da einfallen würde, wäre die Abwärtskompatibilität zu bereits bestehenden Architekturen - um Speicher über 4 GB nutzen zu können, brauchst du nun mal ein 64-Bit-Betriebssystem. Auf 32-Bit-OSs wäre das Programm nicht lauffähig, da es mit den Adressen nichts anzufangen wüßte. Oder sehe ich das so falsch?
@Ki: Auf mich wirkst du wie ein Troll. cooky451 berichtigt dich, und du reagierst recht arogant.
-
Dir ist wohl nicht klar, dass wir hier von VRAM und nicht vom normalen Arbeitsspeicher reden. Und selbst wenn wir 100GB VRAM hätten, dann würden wir die nicht dafür verschwenden wollen, einfach gedankenlos alle Texturen reinzupacken, sondern lieber die Auflösung der gerade benötigten Texturen verachtfachten oder sowas. Außerdem musst du mal 100GB an Texturen von der Platte zur GPU schaufeln. Bei den Ladezeiten die du dir da schaffst, wird keiner dein Spiel spielen wollen.
-
dot schrieb:
Dir ist wohl nicht klar, dass wir hier von VRAM und nicht vom normalen Arbeitsspeicher reden...
Das war das Stichwort. Ich bin bis jetzt davon ausgegangen, dass man die Sachen auch im Arbeitsspeicher parken kann, bis sie gebraucht werden. Immer von der Festplatte zu laden stelle ich mir langsamer vor, als den Mist beim Bedarf im Arbeitsspeicher zu cachen und von dort zu holen.