[D3D10] Fenster-Handling

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Unknown GER
Beiträge: 49
Registriert: 09.01.2003, 13:04

[D3D10] Fenster-Handling

Beitrag von Unknown GER »

Hallo, ich hab mich nun endlich durchgerungen, mir DirectX10 genauer anzusehen und möchte eine kleine, aber feine Anwendung schreiben. Ich habe entsprechend der Dokumentation versucht, das Zusammenspiel zwischen Fenster(-Events) und Direct3D sauber zu programmieren. Es folgen ein paar Code-Ausschnitte. Was meint ihr? Hab ich etwas vergessen oder falsch gemacht? Auf den ersten Blick scheint es zu funktionieren.

Nach der typischen Device-Erstellung assoziiere ich das Fenster mit DXGI, damit es automatisch auf ALT+ENTER reagieren kann:

Code: Alles auswählen

pFactory->MakeWindowAssociation(swapChainDesc.OutputWindow, 0);
Hab ich das richtig verstanden, dass wenn ich das Swap Chain Flag DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH setze, bei einem Fenster-zu-Vollbild-Wechsel der "bestmöglichste" Vollbildmodus ausgewählt wird, sprich der nach den Regeln der Dokumentation am besten zu den Ausmaßen des Fensters passt, wenn ich das Flag aber weglasse, der aktuell in Windows eingestellte Bildschirmmodus ausgewählt wird (was ich bevorzugen würde)?

Ein "Present" sieht bei mir wie folgt aus:

Code: Alles auswählen

void Device::present()
{
	static bool standby = false;

	if (!standby)
	{
		if (pSwapChain->Present(0, 0) == DXGI_STATUS_OCCLUDED)
			standby = true;
	}
	else
	{
		if (pSwapChain->Present(0, DXGI_PRESENT_TEST) == S_OK)
			standby = false;
	}
}
Die Reaktion auf ein WM_SIZE (ich verwende _com_ptr_t's, nicht wundern wegen der 0-Zuweisung u.ä.):

Code: Alles auswählen

void Device::resize(int width, int height)
{
	pDevice->OMSetRenderTargets(0, 0, 0);

	pRenderTargetView = 0; // Release

	DXGI_SWAP_CHAIN_DESC swapChainDesc;
	pSwapChain->GetDesc(&swapChainDesc);

	pSwapChain->ResizeBuffers(
		swapChainDesc.BufferCount,
		width,
		height,
		swapChainDesc.BufferDesc.Format,
		swapChainDesc.Flags);

	ID3D10Texture2DPtr pBackBuffer;
	pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2DPtr), reinterpret_cast<void**>(&pBackBuffer));
	
	pDevice->CreateRenderTargetView(pBackBuffer, 0, &pRenderTargetView);
	pDevice->OMSetRenderTargets(1, &pRenderTargetView.GetInterfacePtr(), 0);

	D3D10_VIEWPORT viewport;

	viewport.TopLeftX = 0;
	viewport.TopLeftY = 0;
	viewport.Width = width;
	viewport.Height = height;
	viewport.MinDepth = 0.0f;
	viewport.MaxDepth = 1.0f;

	pDevice->RSSetViewports(1, &viewport);
}
Ansonsten gibt es noch den Ablauf bei Programmende, der mich interessiert:

Code: Alles auswählen

Device::~Device()
{
	pDevice->OMSetRenderTargets(0, 0, 0);
	pSwapChain->SetFullscreenState(FALSE, 0);
}
Was mir noch einfallen würde, wäre evtl. bei einer WM_SIZE-Nachricht abzufangen, ob das Fenster minimiert wurde. Wie würde man darauf reagieren? Den kompletten "Resize" auslassen, dafür in den Standby-Modus gehen?
Zuletzt geändert von Unknown GER am 06.06.2009, 15:58, insgesamt 1-mal geändert.
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [DX10] Fenster-Handling

Beitrag von Krishty »

Hi,

Das ist immernoch Direct3D10 … ;)
Unknown GER hat geschrieben:Was meint ihr? Hab ich etwas vergessen oder falsch gemacht? Auf den ersten Blick scheint es zu funktionieren.
Sieht soweit ganz gut aus … aber MakeWindowAssociation(…, 0) ist überflüssig – diese Verbindung ist per default gesetzt, wenn du das Fenster-Handle beim Erzeugen der Swap-Chain angegeben hast und du brauchst die Funktion nur aufrufen, wenn du diese Fälle selbst abarbeiten möchtest.
Unknown GER hat geschrieben:Hab ich das richtig verstanden, dass wenn ich das Swap Chain Flag DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH setze, bei einem Fenster-zu-Vollbild-Wechsel der "bestmöglichste" Vollbildmodus ausgewählt wird, sprich der nach den Regeln der Dokumentation am besten zu den Ausmaßen des Fensters passt, wenn ich das Flag aber weglasse, der aktuell in Windows eingestellte Bildschirmmodus ausgewählt wird (was ich bevorzugen würde)?
Zumindest die Doku sagt das so.

Dein Device::Present() ist vorbildlich – die meisten (früher auch ich) vergessen den Standby-Modus und schmoren dann fast ihre Karte, wenn das Programm im Hintergrund läuft …
Unknown GER hat geschrieben:Was mir noch einfallen würde, wäre evtl. bei einer WM_SIZE-Nachricht abzufangen, ob das Fenster minimiert wurde. Wie würde man darauf reagieren? Den kompletten "Resize" auslassen, dafür in den Standby-Modus gehen?
Wenn WM_SIZE dich über eine Minimierung des Fensters informiert, übergibt es als Fenstergröße 0×0 Pixel. Dann musst du in den Standby-Modus, sonst gibt’s Warnungen, dass die Render-Targets zu klein sind und die GPU krepiert fast durch die enorme Framerate.
Unknown GER hat geschrieben:Ansonsten gibt es noch den Ablauf bei Programmende, der mich interessiert:
Vergiss OMSetRenderTargets() – um alle Ressourcen zu entbinden musst du ID3D10Device::ClearState() gefolgt von ID3D10Device::Flush() aufrufen.

Falls es bei dir beim Wechsel vom Fullscreen- in den Fenstermodus pingt, schau dir hier den letzten Beitrag an.

Gruß, Ky
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Unknown GER
Beiträge: 49
Registriert: 09.01.2003, 13:04

Re: [DX10] Fenster-Handling

Beitrag von Unknown GER »

Cool, danke für die schnelle Antwort. :)

MakeWindowAssociation() hab ich nun rausgeschmissen, da ich OutputWindow in der Swap Chain Description setze.

Das OMSetRenderTargets(0, 0, 0) im Destruktor hab ich durch ClearState() und Flush() ersetzt, das SetFullscreenState(FALSE, 0) hab ich drin gelassen.

In meiner resize-Methode frag ich nun gleich zu Beginn ab, ob Breite mal Höhe gleich Null ist und kehre in diesem Fall gleich wieder aus der Methode zurück. Present geht dann ohnehin in den Standby-Modus.

Wie sieht es denn mit dem OMSetRenderTargets(0, 0, 0) in der resize-Methode aus? Müsste ich dort auch alle Ressourcen freigeben und neu erstellen?

Pingen (Sound?) tut beim Wechsel zwischen Vollbild und Fenstermodus übrigens nichts. :)
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [DX10] Fenster-Handling

Beitrag von Krishty »

Unknown GER hat geschrieben:Wie sieht es denn mit dem OMSetRenderTargets(0, 0, 0) in der resize-Methode aus? Müsste ich dort auch alle Ressourcen freigeben und neu erstellen?
D3D10seidank nicht … dort musst du nur alle Referenzen zur Swap-Chain freigeben (deshalb OMSetRenderTargets(0, 0, 0)), damit diese neu erzeugt werden kann, alle anderen Ressourcen bleiben unberührt.
Unknown GER hat geschrieben:Jetzt hab ich nur das kleine Problem, dass er, nachdem ich ein minimiertes Fenster wieder anzeige, erst dann den Standby-Modus verlässt, wenn ich mit dem Mauszeiger das Fenster berühre. Das kann man doch bestimmt in den Fensternachrichten abfangen und entsprechend reagieren?
Das ist sonderlich … meinst du mit „berühren“, dass du die Maus draufbewegen musst, oder dass du klicken musst? (Beides sollte eigentlich nicht der Fall sein …) Ich würde den Code mal im Debugger durchgehen, um sicher zu gehen, dass WM_SIZE sofort die richtigen Parameter übermittelt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Unknown GER
Beiträge: 49
Registriert: 09.01.2003, 13:04

Re: [D3D10] Fenster-Handling

Beitrag von Unknown GER »

Das kleine Problem hat sich von selbst gelöst, es hat immer genau zufällig solange gedauert, bis ich mit dem Mauszeiger über das Fenster bin, bis das Bild wieder da war (und das auch nur wenn ich die Schleife voll durchpowern lass, bis die Kondensatoren der Grafikkarte pfeifen). :mrgreen: Ich muss jetzt wohl nur noch eine Minimalgröße des Fensters (auf 8x8 oder so) festlegen, da bei dem Fall, wenn ich die Fensterhöhe mit der Maus auf 0 kleinziehe, noch eine Ausnahme geworfen wird. Da müsste es eine MINMAXINFO-Nachricht oder so geben, wenn ich mich recht erinnere. :)
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [D3D10] Fenster-Handling

Beitrag von Krishty »

Unknown GER hat geschrieben:Das kleine Problem hat sich von selbst gelöst, es hat immer genau zufällig solange gedauert, bis ich mit dem Mauszeiger über das Fenster bin, bis das Bild wieder da war (und das auch nur wenn ich die Schleife voll durchpowern lass, bis die Kondensatoren der Grafikkarte pfeifen). :mrgreen:
Oh stimmt, ich habe über meine ganzen alten Geschichten über aufdrehende GPUs vergessen zu erwähnen, dass man nach einem Test-Present einen Augenblick warten sollte. Aber gut, dass es sich erledigt hat – wo du jetzt eine quasi-perfekte Fensterprozedur hast, könntest du vielleicht ein wenig von deinem Code in ein Tutorial schreiben, damit Anfänger direkt wissen, was sie warum zu beachten haben?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Unknown GER
Beiträge: 49
Registriert: 09.01.2003, 13:04

Re: [D3D10] Fenster-Handling

Beitrag von Unknown GER »

Das mit dem Tutorial ist eine gute Idee, ich möchte mich aber vorher noch eine Weile damit beschäftigen, um wirklich fundiertes Wissen wiedergeben zu können.

Wie sieht es eigentlich mit WM_PAINT aus? Was ist der effektivste Weg, in einer D3D(10)-Anwendung damit umzugehen, ohne das GDI meint, auch "mitarbeiten" zu müssen? Mit einer typischen while-PeekMessage-Schleife wird man seinen Render-Code wohl vom else-Zweig dieser Schleife direkt aus aufrufen, anstelle als Reaktion auf die WM_PAINT-Nachricht. DefWindowProc() stellt laut Doku aber mehr mit WM_PAINT an, als eigentlich nötig (Hintergrund evtl. zeichnen etc.). Die Doku sagt aber auch, dass wenn man WM_PAINT selbst handlet, man auch BeginPaint() und EndPaint() aufzurufen habe, gefolgt von einem return 0. Gibt es Erfahrungen dazu? Würde ein return 0 als Antwort auf diese Nachricht ausreichen? Und was kann man ggf. mit dem Class Style (CS_*) der Fenster-Klasse bewirken?
Antworten