[DX9] - CreateVertexBuffer - OutOfMemory

Cromon

Erfahrenes Mitglied
Hallo zusammen.

Ich sitze seit knapp 2 Wochen an einem mühsamen Problem bei meinem privaten Projekt. Leider kam ich in letzter Zeit aus beruflichen Gründen nicht wirklich dazu es genauer zu studieren. Nun hatte ich wieder mehr Zeit, bin aber noch immer nicht auf einen grünen Zweig gekommen.

Wie der Titel vermuten lässt geht es um die Funktion
IDirect3DDevice9::CreateVertexBuffer und den Fehler E_OUTOFMEMORY, welcher von der Funktion zurückgegeben wird.

Dieser Fehler ist für mich in dem Kontext einfach nicht verständlich. Ich habe eine Funktion, welche mir den Vertexbuffer erstellt und zurückliefert, die so aussieht:
Code:
IDirect3DVertexBuffer9* D3DManager::GetVertexBuffer(Vertex* src, ui32 nVertices, VertexFormat format)
{
	IDirect3DVertexBuffer9* ret;
	HRESULT errcode = 0;
	switch(format)
	{
	case VERTEX_3F:
		errcode = device->CreateVertexBuffer(nVertices * 3 * sizeof(float), 0, format, D3DPOOL_MANAGED, &ret, 0);
		break;
	case VERTEX_3FC:
		errcode = device->CreateVertexBuffer(nVertices * (3 * sizeof(float) + 4), 0, format, D3DPOOL_MANAGED, &ret, 0);
		break;
	case VERTEX_3FT:
		errcode = device->CreateVertexBuffer(nVertices * 5 * sizeof(float), 0, format, D3DPOOL_MANAGED, &ret, 0);
		break;
	case VERTEX_3FCT:
		errcode = device->CreateVertexBuffer(nVertices * (5 * sizeof(float) + 4), 0, format, D3DPOOL_MANAGED, &ret, 0);
		break;
	case VERTEX_3FRT:
		errcode = device->CreateVertexBuffer(nVertices * 6 * sizeof(float), 0, format, D3DPOOL_MANAGED, &ret, 0);
		break;
	default:
		return 0;
	}

	if(ret == 0)
		return 0;


	void* pData;

	ret->Lock(0, 0, &pData, 0);
	switch(format)
	{
	case VERTEX_3F:
		memcpy(pData, src, nVertices * 3 * sizeof(float));
		break;
	case VERTEX_3FC:
		memcpy(pData, src, nVertices * (3 * sizeof(float) + 4));
		break;
	case VERTEX_3FT:
		memcpy(pData, src, nVertices * 5 * sizeof(float));
		break;
	case VERTEX_3FCT:
		memcpy(pData, src, nVertices * (5 * sizeof(float) + 4));
		break;
	case VERTEX_3FRT:
		memcpy(pData, src, nVertices * (6 * sizeof(float)));
		break;
	}
	ret->Unlock();

	return ret;
}

Diese hat bisher bereits gute Dienste geleistet und erstellt für andere Objekte auch Dutzende von Vertexbuffern mit Tausenden von Vertices gebuffert.

Nun habe ich eines Tages einen neuen Modelltyp einbringen wollen. Auch dieser verwendet Vertexbuffer.

Das sieht folgendermassen aus:
Code:
	ui32 counter = 0;
	for(ui32 i = 0; i < 17; ++i)
	{
		for(ui32 j = 0; j < ((i % 2) ? 8 : 9); ++j)
		{
			float y, x, z;
			m_file->ReadInc(&y, 4);
			x = j * UNITSIZE;
			z = i * UNITSIZE * 0.5f;
			if(i % 2)
				x += 0.5f * UNITSIZE;
			Vertex3F vert;
			m_heights[counter] = y;
			vert.x = xbase + x;
			vert.y = ybase + y;
			vert.z = zbase + z;
			m_vertices[counter++] = vert;
		}
	}
	m_vertexbuffer = sD3DManager.GetVertexBuffer(m_vertices, 145, VERTEX_3F);

Jede Instanz der Klasse tut dies, und insgesamt gibt es 256 Instanzen.

Hier kommt es jedoch zu einem Problem. Bei der ersten Klasseninstanz funktioniert alles wunderbar, bei der zweiten Instanz schlägt jedoch in der Funktion GetVertexBuffer die DX-Funktion CreateVertexBuffer fehl mit dem Fehler E_OUTOFMEMORY. Und genau da versteh ich nicht warum.

Ich hoffe jemand von euch sieht warum das so ist, ich bin langsam echt ratlos...

Gruss
Cromon
 
Die Fehlermeldung selbst ist ja sehr eindeutig, daher ist die eigendliche Frage warum Dein Grafik-Speicher voll ist. Ohne das Gesamtprojekt zu kennen kann man da nur raten.

Gerade beim Umgang mit COM-Objekten muß man sehr penibel darauf achten auch immer Release aufzurufen wenn man Resourcen nicht mehr braucht, andernfalls erzeugt man sehr schnell ein Resource-leak.
 
Ah, ich glaub ich hab das etwas schlecht formuliert. Die Fehlermeldung macht konkret keinen Sinn:
1. Ich verarbeite ca 10000 Vertices zu 5 Vertexbuffern -> alles in Ordnung
2. Ich verarbeite 2 * 145 Vertices zu 2 Vertexbuffern -> 1 geht in Ordnung, der zweite schlägt fehl

Selbstverständlich wird Punkt 2 alleine ausgeführt, das heisst im ganzen Projekt wird nur da ein Vertexbuffer erstellt und schon nach 145 Vertices ist Ende Fahnenstange. Lasse ich das weg und lade ein anderes Modell (mit bis zu 10000 Vertices) funktioniert alles einwandfrei. Von daher kann es gar nicht sein, dass kein Speicher mehr vorhanden ist.
 
Aus dem Codeabschnitt ist nicht erkennbar wie Vertex3F und VERTEX_3F definiert sind, von daher kann ich hier nur raten.

Grundsätzlich ist Deine GetVertexBuffer schlecht, weil Du hier Annahmen über die Größen der einzelnen Strukturen machst. z.B. gehst Du davon aus das die Struktur Vertex3F 3 * sizeof(float) groß ist. Diese Annahme kann je nach Compilereinstellung komplett falsch sein. (->memory Alignment)

Besser und sauberer wäre es die Größe wie folgt zu berrechnen: sizeof(Vertex3F).

Natürlich muss VERTEX_3F auch passend zu Vertex3F definiert sein.
 
Die Fehlermeldung selbst ist ja sehr eindeutig, daher ist die eigendliche Frage warum Dein Grafik-Speicher voll ist. Ohne das Gesamtprojekt zu kennen kann man da nur raten.
Anscheinend ist die Fehlermeldung nicht eindeutig genug. E_OUTOFMEMORY bedeutet nicht, dass der Grafikkartenspeicher voll ist (das wäre D3DERR_OUTOFVIDEOMEMORY), sondern dass eine Speicheranforderung während des Aufrufs fehlschlug. Warum dies nun so ist, weiß ich leider auch nicht. Vermutlich gibt es irgendwo ein Speicherleck im Programm.

Grüße, Matthias
 
Wie ich vermutet habe war die Fehlermeldung für das eigentlich Problem unbrauchbar und hat eigentlich auch nichts über das Problem ausgesagt. Speicher war zur Genüge vorhanden, allerdings war mein Fehler im Indexbuffer. Ich habe statt die Länge in Bytes die Länge in Indices (da ui16 also halb so viel wie nötig) angegeben, das hat zu einer Heapkorruption gefürt was beim nächsten allozieren dann zu einem Fehler in new bzw. malloc führte und dann in CreateVertexBuffer entsprechend OUTOFMEMORY (was man besser in E_ALLOCATIONERROR umbenannt hätte) führte.

Gruss
Cromon
 
Zurück