JDK-8283401 : ArrayIndexOutOfBoundsException when disconnecting screen(s)
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: jfx19
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows
  • Submitted: 2022-03-18
  • Updated: 2023-09-20
  • Resolved: 2023-08-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
jfx22 b05Fixed
Related Reports
Relates :  
Description
Newest JavaFX EA build (19-ea+3)
OS = Windows (not sure if also reproducable for other OS)
---

Sometimes an ArrayIndexOutOfBoundsException is thrown when disconnecting screen(s).
It looks like this only can happen when there are multiple screens.
Also the main screen should be the second screen, so when it gets disconnected, everything will move to the first screen.

Related mailing list article: https://mail.openjdk.java.net/pipermail/openjfx-dev/2022-February/033607.html

So in short:
[Screen 1] [Screen 2*]
* =  main screen with JavaFX app
Disconnect Screen 2. -> Sometimes exception.
---

One time my JVM also crashed and generated a hs_err_pid file.
I attached it on this ticket.

The following stacktrace appeared:
java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
    at com.sun.prism.d3d.D3DPipeline.getD3DResourceFactory(D3DPipeline.java:217)
    at com.sun.prism.d3d.D3DPipeline.getResourceFactory(D3DPipeline.java:284)
    at com.sun.scenario.effect.impl.prism.ps.PPSRenderer.validate(PPSRenderer.java:101)
    at com.sun.scenario.effect.impl.prism.ps.PPSRenderer.getCompatibleImage(PPSRenderer.java:221)
    at com.sun.scenario.effect.impl.prism.ps.PPSRenderer.getCompatibleImage(PPSRenderer.java:67)
    at com.sun.scenario.effect.Effect.getCompatibleImage(Effect.java:479)
    at com.sun.javafx.sg.prism.NodeEffectInput.getImageDataForBoundedNode(NodeEffectInput.java:228)
    at com.sun.javafx.sg.prism.NodeEffectInput.filter(NodeEffectInput.java:131)
    at com.sun.scenario.effect.FilterEffect.filter(FilterEffect.java:185)
    at com.sun.scenario.effect.Offset.filter(Offset.java:160)
    at com.sun.scenario.effect.Merge.filter(Merge.java:148)
    at com.sun.scenario.effect.DelegateEffect.filter(DelegateEffect.java:70)
    at com.sun.scenario.effect.impl.prism.PrEffectHelper.render(PrEffectHelper.java:166)
    at com.sun.javafx.sg.prism.EffectFilter.render(EffectFilter.java:61)
    at com.sun.javafx.sg.prism.NGNode.renderEffect(NGNode.java:2384)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2069)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
    at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
    at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
    ... ( a lot of doRender(..), renderContent(..) calls... )
    at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:480)
    at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:329)
    at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:92)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:305)
    at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java)
    at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:126)
    at java.base/java.lang.Thread.run(Thread.java:829)

### REPRODUCE ###
To reproduce this, the scene must have at least one node with an effect:
VBox root = new VBox();
root.setEffect(new Blend());

Also the D3D Pipeline must be used.(See also stacktrace).

The main screen should be the screen which is then disconnected.

To easier reproduce it, there are some 'hacks' which work quite well to test this:
1. Create a static boolean variable in com.sun.prism.impl.ps.BaseShaderContext (e.g. shouldRecreate)
2. In D3DContext#testLostStateAndReset, the variable hr is now changed to D3DERR_DEVICEREMOVED when shouldRecreate is true
3. Create a test scene with a button. The action when the button is pressed should be something like this: BaseShaderContext.shouldRecreate = true
4. On Windows, press Windows + P and select the first option (PC screen only). This will basically 'disconnect' your screens. Interestingly D3D is not reporting a D3DERR_DEVICEREMOVED. 
If you click now on the button and let D3D recreate everything, the exception appears.

Note: The setup should be as above: E.g. use the last screen and make it also the main screen. 

My initial setup [ 1 ][ 2 ][ 3* ]
3 is the main screen with the JavaFX app.
Windows + P -> [ 2 ] (other screens are disconnected)
Now I recreate the D3D pipeline with the button -> Exception.
Comments
[~mhanl] This seems like a good candidate for backporting to jfx21u if you are interested in doing that. See [1] for instructions. [1] https://mail.openjdk.org/pipermail/openjfx-dev/2023-August/042200.html
20-09-2023

Changeset: a5183e53 Author: Marius Hanl <mhanl@openjdk.org> Date: 2023-08-11 22:26:22 +0000 URL: https://git.openjdk.org/jfx/commit/a5183e539eea3b175825a27b022c07316080c667
11-08-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jfx/pull/1200 Date: 2023-08-05 13:00:36 +0000
05-08-2023

One interesting note: When 'disconnecting' 2 screens from a 3 screen setup, the screen ordinal from the remaining screen is set to 1. When the D3DPipeline is reinitialized the adapter count is correctly reported as 1. Now when the D3DResourceFactory is retrieved, we get an index out of bounds as reported above. Setup: [ 1 ][ 2 ][ 3* ] ; 3 = Main screen, ordinal is: [ 2 ][ 1 ][ 0 ] When 1 and 3 are disconnected, 2 will by the main screen. And before it had the ordinal 1, and it still has now. And obviously this will result in an IOOBE. A simple Math.min() helped and works here. But it is a bit weird that the screen still has ordinal 1.
19-05-2023

I think this particular bug is caused by PPSRenderer caching, and later using, a stale Screen instance. This change was introduced in JDK-8239589. Since Screen instances can't be used after being disposed, an error can occur. Note that the exception only occurs if the adapter ordinal is out of bounds of the D3DResourceFactory array, so it may be the case that if the adapter ordinal of the stale screen just happens to not be an invalid index into the array, the code appears to function normally. Maybe a solution could be to check whether the cached Screen is not disposed before using it.
12-02-2023

I tried that yesterday a few time as well. No luck reproducing it.
10-02-2023

Something that may be related: 1. Put Windows into sleep mode 2. Disconnect the docking station / external monitor 3. Resume Windows The JavaFX window will be black, sometimes the exception occurs.
09-02-2023

I tried it about 15 times, but can't reproduce it. My setup is a dual screen case where I made the external monitor the primary screen. I Then launched the program (I tried a couple of different ones including Ensemble8 with various animating objects in case that made a difference) on the external monitor (which was primary at that time), and unplugged it so everything moved to the builtin monitor. No exception was seen. I tried repeating this several times sometimes restarting the program and sometimes not. I don't have a docking station so this was done by plugging in and unplugging an HDMI cable.
09-02-2023

I have a setup where I can test this today. If I can reproduce it, I'll add a comment with whatever information I can find.
09-02-2023

Same for me. I checked some more cases and I could also reproduce it when manually disconnecting screens by cable, although the usecase with the docking station worked more often.
09-02-2023

I am also encountering this bug with the exact same stack trace. This happens on a Windows 11 laptop that is connected to a docking station with two screens. When the docking station is disconnected, the error sometimes appears.
09-02-2023

Update: I sometimes also got this when switching to other screens. E.g. I connect myself to a docking station where two screen are plugged in. Then I will disconnect the cable and go to another docking station with another 2 screens. I will check this the upcoming days.
28-06-2022

I'll take a look at it, although not right away, so if you do find something out, that would be helpful. Testing would be helpful, too.
18-03-2022

Turns out I was remembering that this had been discussed on the openjfx-dev mailing list: https://mail.openjdk.java.net/pipermail/openjfx-dev/2022-February/033607.html Thank you for filing it.
18-03-2022

[~kcr] Sounds good. No, one time the JavaFX application just worked while I still saw the exception in the console, while another time it was completely black and didn't rendered anymore. And another time I got the described crash (with the hs_err_pid file). Unfortunately I'm not very familiar with the more "low level java code" or C++ (if needed). But if there is an idea or a potential fix I would be glad helping/testing it.
18-03-2022

[~mhanl] I seems to recall someone reporting a similar bug a while ago. If I can find it, then I'll close this as a duplicate. The crash should not be happening though. Does that happen all the time once you get the exception? UPDATE: I see from the Description that the crash was a one time occurrence. We should look at that, too.
18-03-2022