inspiriert von meinem Gemecker und der Meinung des Internets (tm) dazu möchte ich euch ein Problem vorstellen. In meinem neugeschriebenen Renderer gibt es ein Rudel Funktionen, die GPU-Ressourcen erzeugen. Z.b. ein ganz banalen VertexBuffer.
Den VertexBuffer kann man mit Initial-Füllung oder auch uninitialisiert erzeugen, wenn man ihn später beschreibt. Ich habe bei mir die Use Cases reduziert auf zwei Optionen: entweder initial befüllt und dann unveränderlich, oder nachträglich veränderlich und dann für häufigere Schreibzugriffe optimiert. Das aber nur am Rande. Die Daten für den Konstruktor und für die Schreib-Funktionen habe ich in eine kleine Klasse gekapselt, die außerdem die Lebenszeit verwaltet. Die sieht gekürzt so aus:
Code: Alles auswählen
/// Beschreibt, wie mit einem übergebenen Datensatz zu verfahren ist.
enum class TDatenNutzung
{
/// Verwiesene Daten sind bald wieder weg, müssen also kopiert werden, wenn sie nach Ende der Funktion noch gebraucht werden
MussKopieren,
/// Verwiesene Daten sollen in den Besitz des Aufgerufenen übergeben werden und müssen von ihm gelöscht werden, wenn fertig
MussUebernehmen,
/// Verwiesene Daten bleiben längerfristig verfügbar und können auch später gelesen werden, ohne sie zu duplizieren.
DarfVerweisen
};
/// Beschreibt einen Satz Daten, mit dem eine Ressource initialisiert werden kann, plus die Verwendungsmethode.
template <typename Datum>
struct TInitDaten
{
Datum mDaten;
TDatenNutzung mNutzung;
};
Eigentlich kam ich mir ziemlich clever vor, als ich mir das System ausgedacht hatte. Man kann jetzt irgendwelche Daten entweder referenzieren oder in den Besitz der Ressource übergeben, und die Klasse selbst hat ein paar schlichte Funktionen, um Besitz sicherzustellen oder die Daten zu entsorgen, je nachdem was die DatenNutzung vorgibt. Das vereint sich außerdem prima mit dem Direct3D9-Renderer, für den DeviceLoss und damit Verlust aller VideoRAM-Ressourcen ja noch eine reale Bedrohung ist. Dafür hält der DX9-Renderer, wenn gewünscht, noch eine Hauptspeicherkopie vor, die nach bester std::move()-Gepflogenheit auch direkt übernommen werden kann, wenn die Quelldaten eh verzichtbar sind.
Die Frage ist jetzt: kann man das irgendwie clever RAII-Mit-C++11-Move-mäßig lösen? Gibt es irgendwelche Dummheiten, die ich übersehen habe?
Ausgangspunkt ist mein Ärger über GCC, wie im Jammer-Thread beschrieben. Alle Ressourcen-Funktionen nehmen halt als Default-Parameter ein temporäres invalides Daten-Objekt für den Fall, dass die Ressource ohne Initialdaten-Befüllung erstellt werden soll. Und das wird dann noch über ein paar Zwischenfunktionen weitergereicht. All diese Zwischenfunktionen nehmen also eine nicht-konstante Referenz auf so ein Datenobjekt, weil sie die übergebenen Daten dann ja u.U. löschen müssen. Also z.B. so:
Code: Alles auswählen
Traum_VertexBuffer* ErzeugeVertexBuffer( size_t pGroesse, size_t pFlags = 0, TInitDaten<TDatenBlock>& pDaten = TInitDaten<TDatenBlock>());
Kurzzusammenfassung:
TInitDaten<> ist ein Verweis auf einen Datenblock mit Angabe der "Haltbarkeit". Mögliche Verwendungszwecke sind:
a) Daten müssen kopiert werden, wenn man sie länger braucht
b) Daten müssen übernommen werden, wechseln also den Besitzer.
c) Daten dürfen schwach referenziert werden, weil der Aufrufer garantiert, dass sie da bleiben.
Im Falle a) werden die Daten kopiert, wenn sie länger gebraucht werden, also z.B. für DX9-Hauptspeicherkopie oder bei verzögertem Schreiben aus parallelem Thread.
Im Falle b) werden die Daten übernommen und vom Aufgerufenen am Ende entsorgt, müssen dann aber nicht kopiert werden.
Im Falle c) ist eh alles smooth, aber der Aufrufer muss garantieren, dass die Daten länger leben als jeder Verweis. Wird aktuell für Texturatlanten verwendet, weil die für pixelgenaue Kollision auch Lesezugriffe auf die Grafikdaten erlauben.
Im Falle a) sind die verwiesenen Daten konstant, aber u.U. nicht der Verweis selbst.
Im Falle b) ist der Verweis konstant, die verwiesenen Daten aber für Veränderungen freigegeben.
Im Falle c) sind sowohl der Verweis als auch die verwiesenen Daten konstant.
Ideen?