PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Managed D3D - DeviceLost


KiBa
2003-08-07, 05:16:31
Moin,
versuche verzweifelt in meiner C#-Anwendung, welche Direct3D benutzt, auf das DeviceLost Ereignis bzw. Exception zu reagieren. Hab mal hier ein minimales Programm, wenn mir das mal bitte jemand "DeviceLost-resistent" machen würde, der sich damit auskennt... (die Doku kann man ja nur in die Tonne treten, teilweise copy&paste aus der C++-Doku und Device.TestCooperativeLevel ist so gut wie garnicht dokumentiert)


using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX.Direct3D;

public class CreateDevice : Form
{
Device device = null;

public CreateDevice()
{
DeviceType deviceType = DeviceType.Hardware;
CreateFlags createFlags = CreateFlags.HardwareVertexProcessing;
PresentParameters presentParams = new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.BackBufferWidth = 1024;
presentParams.BackBufferHeight = 768;
presentParams.BackBufferFormat = Format.A8R8G8B8;
device = new Device(0, deviceType, this, createFlags, presentParams);
}

private void Render()
{
device.Clear(ClearFlags.Target, Color.Blue, 1.0f, 0);
device.Present();
}

static void Main()
{
CreateDevice frm = new CreateDevice();
frm.Show();
while(frm.Created)
{
frm.Render();
Application.DoEvents();
}
}
}


Mein erster Versuch sah ungefähr so aus:


private void Render()
{
try
{
device.TestCooperativeLevel();
device.Clear(ClearFlags.Target, Color.Blue, 1.0f, 0);
device.Present();
}
catch (DeviceLostException)
{
}
catch (DeviceNotResetException)
{
device.Reset(device.PresentationParameters);
}
}


Funktioniert auch super, solange die presentParams.Windowed Variable true ist (kann man bei der Fensterdarstellung mit Strg-Alt-Entf testen, da passiert ein DeviceLost). Im Vollbildmodus hat das Programm ein ganz anderes Verhalten. (werd mit Exceptions an den unmöglichsten Stellen beworfen)
Wie macht mans richtig? Danke schon mal im Vorraus!
und... tschüß

Demirug
2003-08-08, 21:16:30
Sorry dich habe ich ganz vergessen. Mea Culpa

Die Doku die beim SDK dabei ist kann man wirklich in die Tonne werfen. Ich habe mich deswegen auch schon beschwert und das neue SDK wird eine bessere bekommen. In der MSDN Version im web gibt es auch eine Version die aktueller als die im SDK ist.

Aber nun zu deinem Problem.

Finger weg von den Exceptions die sollen nur geworfen werden wenn wirklich etwas total falsch läuft. Da ein Devicelost aber ein durchaus übliches Ereigniss ist gibt es dafür auch einen entsprechendes Verfahren.

Die Device Klasse unterstützt mehrer Events (Mit Events in C+ bist du vertraut?)

-DeviceCreated: Wir aufgerufen nachdem das Device erzeugt wurde. Das Event ist aber etwas komisch weil das Device ja im Konstruktor erzeugt wird und man da noch gar keine Eventhandler verbunden haben kann. Den tieferen Sinn bekomme ich irgendwann wohl noch heraus.

-DeviceLost: Wird gefeuert wenn das Device verloren geht. Man sollte alle Resourcen die zu dem Device gehören für ungültig erklären.

-DeviceReset: Wird gefeuert wenn das Device resetet wurde. In den Handlern für dieses Event sollte man alle Resourcen welche im Default Pool lagen neu erzeugen weil diese beim Reset verloren gegangen sind.

-DeviceResizing: Wird gefeuert wenn die Auflösung verändert wurde. Der Handler für diese Event kann das normale verhalten unterdrücken.

-Disposing: Wird gefeuert wenn das Device Disposed wurde man sollte hier alle dem Device zugeordneten Resourcen ebenfalls Disposen bzw Freigeben.

KiBa
2003-08-09, 01:59:53
Original geschrieben von Demirug
Sorry dich habe ich ganz vergessen. Mea Culpa
Ts, ts, unverantwortlich, mich hier solange warten zu lassen... ;)
Die Doku die beim SDK dabei ist kann man wirklich in die Tonne werfen. Ich habe mich deswegen auch schon beschwert und das neue SDK wird eine bessere bekommen. In der MSDN Version im web gibt es auch eine Version die aktueller als die im SDK ist.
Danke für den Hinweis, gut dass ich nicht der Einzige bin, dem die Doku für Managed-DirectX nicht passt...
Finger weg von den Exceptions die sollen nur geworfen werden wenn wirklich etwas total falsch läuft. Da ein Devicelost aber ein durchaus übliches Ereigniss ist gibt es dafür auch einen entsprechendes Verfahren.
Nun, zumindest bei der TestCooperativeLevel Methode werden die Exceptions geworfen...
Die Device Klasse unterstützt mehrer Events (Mit Events in C+ bist du vertraut?)
jupp...
-DeviceCreated: Wir aufgerufen nachdem das Device erzeugt wurde. Das Event ist aber etwas komisch weil das Device ja im Konstruktor erzeugt wird und man da noch gar keine Eventhandler verbunden haben kann. Den tieferen Sinn bekomme ich irgendwann wohl noch heraus.
Das Event macht wirklich keinen Sinn außer direkt nach new Device()... (wo sich natürlich noch kein Handler registriert hat). Oder könnte es noch woanders ausgelöst werden?
-DeviceLost: Wird gefeuert wenn das Device verloren geht. Man sollte alle Resourcen die zu dem Device gehören für ungültig erklären.
Das stimmt nicht, das Event wird eben nicht (nur) beim Verlieren des Devices ausgelöst. Ist halt nicht dokumentiert, hat mich aber trotzdem auf die Lösung gebracht:
DeviceLost wird ausgelöst, wenn die Ressourcen für ungültig erklärt werden sollen. z.B. direkt nach einem DeviceResizing Event kommen nacheinander die DeviceLost und DeviceReset Events, ohne dass das Device verloren gegangen wäre oder ich Reset() aufgerufen hätte. Das soll einem wohl die Möglichkeit geben, die Ressourcen zu löschen und neu zu laden, wenn das Fenster resized wird...
-DeviceResizing: Wird gefeuert wenn die Auflösung verändert wurde. Der Handler für diese Event kann das normale verhalten unterdrücken.
Und genau dies musste ich tun... (mit der Property Cancel der EventArgs) Dann werden auch keine DeviceLost und DeviceReset Events mehr ausgelöst und es kommt nicht mehr zu einer unbehandelten DeviceLost Ausnahme in der D3D-dll.
Vielen Dank für die Anregung... ;)

Hab da aber noch 2 kleine Problemchen:
1. Wenn ich bei dem Codebeispiel bei den CreateFlags ein PureDevice angebe, dann kann er das Device nicht erstellen, obwohl in den Caps die Unterstützung dafür zugesichert wurde. Damals unter C++ und DX8 hat das noch ohne Probleme funktioniert, hast du eine Idee?
2. Bei der Enumeration werden keine Multisamplingmodi mehr aufgelistet und auch in der CapsViewer meldet keine. Hab da mal nen Thread im Hilfe-Forum aufgemacht, vielleicht kannst du mir da ja helfen:
http://www.forum-3dcenter.org/vbulletin/showthread.php?s=&threadid=87074

und nochmal thx...

Demirug
2003-08-09, 02:40:28
Original geschrieben von KiBa
Das stimmt nicht, das Event wird eben nicht (nur) beim Verlieren des Devices ausgelöst. Ist halt nicht dokumentiert, hat mich aber trotzdem auf die Lösung gebracht:
DeviceLost wird ausgelöst, wenn die Ressourcen für ungültig erklärt werden sollen. z.B. direkt nach einem DeviceResizing Event kommen nacheinander die DeviceLost und DeviceReset Events, ohne dass das Device verloren gegangen wäre oder ich Reset() aufgerufen hätte. Das soll einem wohl die Möglichkeit geben, die Ressourcen zu löschen und neu zu laden, wenn das Fenster resized wird...

Das Verhalten ist so vollkommen richtig weil:

Ein Reset erzwingt das man das Device verliert was ein LostDevice Event auslöst.

Nachdem das DeviceResizing Event gefeuert wurde und die standard Behandlung nicht blockiert wurde wird ein Reset des Device ausgeführt.

Und genau dies musste ich tun... (mit der Property Cancel der EventArgs) Dann werden auch keine DeviceLost und DeviceReset Events mehr ausgelöst und es kommt nicht mehr zu einer unbehandelten DeviceLost Ausnahme in der D3D-dll.Vielen Dank für die Anregung... ;)

Wenn du nach dem Resizen des Fensters keinen Reset ausführst hat dein Backbuffer aber noch die alte Grösse. Ist das so gewünscht?


Hab da aber noch 2 kleine Problemchen:
1. Wenn ich bei dem Codebeispiel bei den CreateFlags ein PureDevice angebe, dann kann er das Device nicht erstellen, obwohl in den Caps die Unterstützung dafür zugesichert wurde. Damals unter C++ und DX8 hat das noch ohne Probleme funktioniert, hast du eine Idee?

Hast du versucht ein PureDevice in Verbindung mit SoftwareVertexProcessing zu erzeugen? Das geht nicht weil bei einem PureDevice die Runtime keinerlei Funktion mehr übernimmt.

2. Bei der Enumeration werden keine Multisamplingmodi mehr aufgelistet und auch in der CapsViewer meldet keine. Hab da mal nen Thread im Hilfe-Forum aufgemacht, vielleicht kannst du mir da ja helfen:
http://www.forum-3dcenter.org/vbulletin/showthread.php?s=&threadid=87074

und nochmal thx...

Dazu kann ich jetzt spontan auch nichts sagen.

Beim Entwickeln ist es ratsam die Debug Runtime zu benutzten. Um die Meldungen zu bekommen sollte man den dbmon im Utilities benutzten. Es gibt zwar noch einen anderen Weg aber der macht den Debugger langsam.

KiBa
2003-08-09, 04:33:59
Original geschrieben von Demirug
Das Verhalten ist so vollkommen richtig weil:

Ein Reset erzwingt das man das Device verliert was ein LostDevice Event auslöst.

Nachdem das DeviceResizing Event gefeuert wurde und die standard Behandlung nicht blockiert wurde wird ein Reset des Device ausgeführt.
Danke für die Erklärung. Ist ja auch logisch, da eine Veränderung der Backbuffergröße nur mit einem Reset funktioniert. Wäre das in der Doku ordentlich dokumentiert (und zwar beim DeviceResizing Event), hätte ich wohl nicht so lange mit der Lösung gebraucht...
Wenn du nach dem Resizen des Fensters keinen Reset ausführst hat dein Backbuffer aber noch die alte Grösse. Ist das so gewünscht?
Im Fenstermodus lass ich es ja wie es ist (automatisches Reset), im Vollbildmodus allerdings (wo bei einem Taskwechsel unlogischerweise das Event auch auftritt) muss ich es verhindern, da die Microsoft-Heinis wahrscheinlich einfach so nen Reset machen, ohne vorher mit TestCooperativeLevel überhaupt zu fragen, ob dies möglich ist. (das ist es im Vollbildmodus nicht, was dann zu der DeviceLost Exception in der D3D-dll führt; ist vielleicht ein Bug...)
Hast du versucht ein PureDevice in Verbindung mit SoftwareVertexProcessing zu erzeugen? Das geht nicht weil bei einem PureDevice die Runtime keinerlei Funktion mehr übernimmt.
Nein, du hast mich aber trotzdem auf meinen Fehler aufmerksam gemacht: ich habe nur PureDevice angegeben ohne HardwareVertexProcessing. Und das ist sogar (ausnahmsweise) dokumentiert, man glaubt es kaum...
Beim Entwickeln ist es ratsam die Debug Runtime zu benutzten. Um die Meldungen zu bekommen sollte man den dbmon im Utilities benutzten. Es gibt zwar noch einen anderen Weg aber der macht den Debugger langsam.
Mmh, in C++ war ich die Debugausgabe im Debugger gewohnt, wie krieg ich das in Managed-DirectX auch hin?

Demirug
2003-08-09, 04:50:38
Original geschrieben von KiBa
Im Fenstermodus lass ich es ja wie es ist (automatisches Reset), im Vollbildmodus allerdings (wo bei einem Taskwechsel unlogischerweise das Event auch auftritt) muss ich es verhindern, da die Microsoft-Heinis wahrscheinlich einfach so nen Reset machen, ohne vorher mit TestCooperativeLevel überhaupt zu fragen, ob dies möglich ist. (das ist es im Vollbildmodus nicht, was dann zu der DeviceLost Exception in der D3D-dll führt; ist vielleicht ein Bug...)

Ja könnte ein Bug sein mal ausprobieren ob das mit den neuen DLLs auch noch so ist wenn ja haue ich das MS gleich mal um die Ohren.

Mmh, in C++ war ich die Debugausgabe im Debugger gewohnt, wie krieg ich das in Managed-DirectX auch hin?

Bei den Projekteigenschaften unter Debuggen muss man "Nicht verwaltetes Debuggen aktivieren" auf True setzten. Das macht aber wie gesagt den Deugger langsamer.