On Sat, 5 Aug 2023 13:00:36 GMT, Marius Hanl <mh...@openjdk.org> wrote:

> When the `D3DPipeline` is reinitialized, the adapter ordinal of all the 
> `Screen`s are outdated.
> As a consequence, when a `D3DResourceFactory` is created for a `Screen` 
> (adapter ordinal), the code may fail with an `ArrayIndexOutOfBoundsException` 
> as the ordinal is higher than what we would expect it to be.
> 
> Example:
> We have 3 screens. Adapter ordinal 0, 1, 2.
> If we now disconnect 2 screens, we only have one screen left. 
> The `D3DPipeline` is reinitialized as a 
> [D3DERR_DEVICEREMOVED](https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3derr)
>  is reported from Direct3d9.
> Now the remaining screen may have the adapter ordinal 1 (from before). But 
> since we only have 1 screen left, it should have the adapter ordinal 0. 
> 
> Direct3d9 will also return 0 as adapter ordinal if you call it. And that is 
> what we do to update the `Screen` and fix this problem.
> 
> See also the ticket for information how to reproduce this problem (Windows 
> only).

I tested the patch with a docking station and two external displays like this:
1. Put Windows into sleep mode
2. Disconnect the docking station / external monitor
3. Resume Windows

Without the patch, the exception occurs. With the patch applied, everything 
works as expected.

I notice that the logic to assign adapter ordinals is now duplicated in two 
places in the codebase. Have you thought about moving the implementation into 
the `Screen` class? Here's how that could work:

Remove `Screen.setAdapterOrdinal(int)` and add the following method to the 
`Screen` class:

    public static void updateAdapterOrdinals() {
        for (Screen screen : getScreens()) {
            screen.adapter = 
GraphicsPipeline.getPipeline().getAdapterOrdinal(screen);
        }
    }


Remove `QuantumToolkit.assignScreenAdapters()` and call 
`Screen.updateAdapterOrdinals()` from the two call sites instead. You can then 
just call `Screen.updateAdapterOrdinals()` from `D3DPipeline` as well.

For good measure, you could initialize `Screen.adapter` to `-1` and change 
`Screen.getAdapterOrdinal()` as follows:

    public int getAdapterOrdinal() {
+       if (adapter < 0) {
+           throw new IllegalStateException("Adapter ordinal is not 
initialized.");
+       }
+
        return adapter;
    }

-------------

PR Comment: https://git.openjdk.org/jfx/pull/1200#issuecomment-1671954361

Reply via email to