I now opened a bug report for my issue. But as I'm trying to figure out the
implementation of the D3D pipeline I found two things:
1. Only somewhat related to my issue, but I found that the existing recovery
method for D3DERR_DEVICELOST / D3DERR_DEVICENOTRESET is not working when a
device lost error is forced via the command line "dxcap -forcetdr". To
reproduce: just run any JavaFX app with prism.verbose and run the command (in
an admin console). The window will stay white and
D3DContext::testLostStateAndReset : D3DERR_DEVICELOST is printed over and over.
I'm unsure if this test method is valid, but regardless: the app does not come
into the D3DERR_DEVICENOTRESET state and therefore nResetDevice will not be
called. When I'm chaning the implementation to
if (hr == D3DERR_DEVICELOST) {
// Reinitialize the D3DPipeline. This will dispose and recreate
// the resource factory and context for each adapter.
D3DPipeline.getInstance().reinitialize();
}
then rendering works again.
2. D3DContextInit.cc seem to lack the implementation for D3D9Ex to call ResetEx
But as Reset and ResetEx behave differently ("Unlike previous versions of
DirectX, calling IDirect3DDevice9Ex::ResetEx does not cause surfaces, textures
or state information to be lost.", regarding to this doc
https://learn.microsoft.com/en-us/windows/win32/api/d3d9/nf-d3d9-idirect3ddevice9ex-resetex),
I'm not sure if ResetEx should be called instead of Reset.
Von: Thorsten Fischer
Gesendet: Freitag, 21. Juli 2023 10:48
An: [email protected]
Betreff: JavaFX does not recover after graphic card driver crash
Hi all,
first off all I want to say ‚thank you‘ to everyone in this community for all
the effort you put in. I'm using JavaFX for years now and I'm really happy to
work with it :)
I have the following issue/question: One of my customers experiences an
application crash when running their JavaFX application for a longer period on
a notebook with integrated Intel graphics. First of all, I think JavaFX does
not cause the issue, but is rather affected by it. We built a workaround in
JavaFX, but I'd like to discuss what a good solution would look like, so that
it can be integrated into the JFX code base.
So, randomly between a couple of days to about 3 weeks the graphic card driver
crashes. In the Windows (10) event log you can read: "Display driver igfx
stopped responding and has successfully recovered.". In the console of the app
it says: "D3DContext::testLostStateAndReset : Unknown D3D error 0x88760874".
The app then just shows a black screen and keeps printing this error over and
over to the console (rendering is triggered regularly in this app) and never
recovers, even though the driver has been recovered and the whole system is
running and is usable (again).
The error code 0x88760874 translates to D3DERR_DEVICEHUNG
(https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3derr), what
corresponds to the error in the Windows event log.
Now our initial workaround (within D3DContext.java#testLostStateAndReset) is
basically the same as for D3DERR_DEVICEREMOVED, but with a loop to give the OS
time to recover:
public static final int D3DERR_DEVICEHUNG = 0X88760874;
and at the end:
if (hr == D3DERR_DEVICEHUNG) {
setLost();
long retryMillis = TimeUnit.MINUTES.toMillis(5);
long sleepingMillis =
TimeUnit.SECONDS.toMillis(1);
for (int i = 0; i < retryMillis; i +=
sleepingMillis) {
int cooperativeLevel =
D3DResourceFactory.nTestCooperativeLevel(pContext);
System.err.println("Checking
Cooperative Level: " + cooperativeLevel);
if (cooperativeLevel == D3D_OK) {
break;
} else {
try {
Thread.sleep(sleepingMillis);
} catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
// reinitialize after 5 mins anyway, even if
result is not OK.
// Reinitialize the D3DPipeline. This will
dispose and recreate
// the resource factory and context for each
adapter.
D3DPipeline.getInstance().reinitialize();
}
Yesterday we experienced with this workaround, that the app did actually
recover after 20 seconds. The System.err output generated inside the loop only
showed again the D3DERR_DEVICEHUNG error code, and after 20 sec. console showed
the initialization output.
Very obviously Thread.sleep is not a good solution. To avoid it I thought about
introducing another flag like isLost (-> "isHung") and
if (hr == D3DERR_DEVICEHUNG) {
setLost();
setHung();
}
if (isHung && hr == D3D_OK) {
isLost = false; // ?
isHung = false;
// Reinitialize the D3DPipeline. This will dispose and recreate
// the resource factory and context for each adapter.
D3DPipeline.getInstance().reinitialize();
}
But before I continue with this direction (and because it takes weeks to
reproduce this): Can anybody confidently tell me what a better/good solution
may look like?
Thank you,
Thorsten