Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Schrompf

Alter Hase

  • »Schrompf« ist der Autor dieses Themas

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

1

24.09.2015, 12:23

[DX9] DeviceReset scheitert an Fensterfokus?

Moin,

ich probiere jetzt auch hier mal mein Glück. Splatter, letzter Bug, den ich jemals dafür fixen werde. Ehrlich jetzt. Das ist mein letztes Wort.

Wenn man aus dem Vollbild heraus Alt-Tabt, geht das Device verloren. Logisch. Wenn ich allerdings zurück ins Spiel gehe, sei es per Alt+Tab oder per Klick auf die Anwendung in der Taskleiste, kommt das Spiel nicht wieder. Es hängt stattdessen in der aus zig Tutorials seit Jahrzehnten etablierten Device-Reset-Schleife

Quellcode

1
2
3
4
5
6
7
  HRESULT hr = D3DERR_DEVICELOST;
  while( hr == D3DERR_DEVICELOST ) 
  {
    hr = d3dDevice->Reset( &d3dpp);
    if (FAILED(hr) && hr != D3DERR_DEVICELOST )
      WirfAusnahmeOptional( "D3D9-Reset gescheitert");
  }


...und zwar endlos. Es kommt also kein sonstiger Fehlercode, sondern immer nur DEVICELOST. Und DirectX Debug gibt in einer ebensolangen Endlosschleife aus:

Quellcode

1
2
3
Direct3D9: (ERROR) :ResetEx fails. D3DERR_DEVICELOST returned.
Direct3D9: (ERROR) :ResetEx failed and ResetEx/TestCooperativeLevel/Release are the only legal APIs to be called subsequently
Direct3D9: (WARN) :Window does not have focus. TestCooperativeLevel fails


Hat jemand eine Idee, woran das liegen könnte? Ich meine... das Fenster ist doch sicher fokussiert, wenn ich es mit dem Klick auf den Taskleiten-Eintrag wieder hochhole, oder?
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

2

24.09.2015, 13:31

Laut meinem angestaubten Direct3D9 Wissen muss man TestCooperativeLevel jeden Frame aufrufen, wenn kein OK mehr zurückgegeben wird darf man nicht mehr rendern. Sobald dann ein device not reset zurück gegeben wird, kann man Reset aufrufen und alle Ressourcen neu erstellen.
Ich hatte das mal getestet vor ein paar Jahren und müsste so funktionieren. Der Code ist aber leider unauffindbar.

https://msdn.microsoft.com/en-us/library…v=vs.85%29.aspx hab ich dazu noch gefunden.
Remarks ist ganz interressant zu lesen.

Schrompf

Alter Hase

  • »Schrompf« ist der Autor dieses Themas

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

3

24.09.2015, 14:19

Danke. Der Teil funktioniert leider stressfrei. Das Problem war hier zweiteilig: zum Einen hat GLFW in seiner WinMsgProc kein WM_ACTIVATE behandelt, weswegen ich überhaupt nie mitbekommen habe, dass der Vollbildmodus verlassen wurde. Und zum Anderen kam bei Reaktivierung zuerst ein WM_SIZE und danach erst ein WM_SETFOCUS - letzteres ist aber Grundbedingung, damit DeviceReset funktioniert, ich habe aber bei ersterem bereits den DeviceReset durchgeführt, weil die Nachricht ja auch bei Änderung der Fenstergröße kommt.

Hm. Wieder was gelernt. Aber es wird wirklich langsam Zeit, dass DX9 ausstirbt.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

25.09.2015, 00:36

Wenn du diese Schleife so ausführst, werden ja zwischendurch gar keine Fensternachrichten mehr behandelt, oder?

Schrompf

Alter Hase

  • »Schrompf« ist der Autor dieses Themas

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

5

25.09.2015, 10:48

Ja. Aber das ist so wie gesagt Standard, soweit ich das gesehen habe. Es ist ja nur die Reset-Schleife. Und laut Internet kann die gern mal ein bisschen scheitern hier und da, weswegen man da verwhilen soll, bis es erfolgreich war.

Ich hatte auch mal eine Option erprobt, nach dem xten Fehlversuch es seinzulassen. Aber was dann? Wenn ich dann weitermache, scheitert ja jeder DrawCall. Und *eigentlich* sollte der Fokus ja unmittelbar danach kommen. Grmpf.

Ich hab es gestern noch soweit gebracht, dass es regulär eigentlich funktionieren sollte, in der Praxis aber dann nur regelmäßig jedes zweite Mal den Fullscreen wiederherstellen konnte. Woher das kommt... tja. Jetzt sind erstmal andere Sachen wichtiger, heut nachmittag geht's dann weiter.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

6

25.09.2015, 11:15

Es wäre vielleicht besser, diesen Reset in deiner Hauptschleife zu machen. Also so:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
while (!quit) {
    
    processWindowMessages();
    
    if (deviceLost()) {
        if (!tryToReset()) {
            // Nächstes Mal wieder versuchen.
            continue;
        }
    }
    
    // Spiellogik, Rendering, ...
}

Dann würde das Fenster zumindest noch reagieren. Und du könntest vielleicht sogar eine Meldung anzeigen wie "Device lost, trying to reset ...".

7

25.09.2015, 12:40

Hast du denn auch deine ganzen Ressourcen resettet? Soweit ich mich erinnere muss man so Sachen wie Texturen, Fonts, etc. auch resetten. Soweit ich mich erinnere hat das auch was damit zu tun, in welchem Speicher die Ressourcen liegen, sprich Grafikspeicher, Hauptspeicher... Dabei muss man glaube ich auch auf die Reihenfolge der Resets achten. Bei mir sieht das ganze so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
if (getStatus() == DEVICE_NOT_RESET) {
            Sprite::onLostDevice();
            Font::onLostDevice();

            if (FAILED(device->Reset(&presentationParameters))) {
                throw(InternalErrorException("Direct3DDevice could not be reset", "Direct3DDevice::reset"));
            }

            Sprite::onResetDevice();
            Font::onResetDevice();
        }


Viele Grüße

newby

EDIT:
Bei DeviceLost musst du glaube ich garnicht versuchen zu resetten, der Zustand heißt glaube ich DEVICE_NOT_RESET oder so ;)

Werbeanzeige