Seite 1 von 1
[D3D10] Fenster-Handling
Verfasst: 06.06.2009, 15:02
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?
Re: [DX10] Fenster-Handling
Verfasst: 06.06.2009, 15:17
von Krishty
Hi,
Das ist immernoch Direct
3D10 … ;)
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
Re: [DX10] Fenster-Handling
Verfasst: 06.06.2009, 15:53
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. :)
Re: [DX10] Fenster-Handling
Verfasst: 06.06.2009, 16:06
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.
Re: [D3D10] Fenster-Handling
Verfasst: 06.06.2009, 16:29
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. :)
Re: [D3D10] Fenster-Handling
Verfasst: 06.06.2009, 16:48
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?
Re: [D3D10] Fenster-Handling
Verfasst: 10.06.2009, 11:39
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?