Skip to content

Commit e5870cf

Browse files
committedOct 21, 2020
8252133: The java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java fails if metal pipeline is active
Reviewed-by: prr
1 parent afc967f commit e5870cf

File tree

3 files changed

+85
-57
lines changed

3 files changed

+85
-57
lines changed
 

‎src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,14 @@ public int getScaleFactor() {
131131
return scale;
132132
}
133133

134-
public void invalidate(final int defaultDisplayID) {
134+
/**
135+
* Invalidates this device so it will point to some other "new" device.
136+
*
137+
* @param device the new device, usually the main screen
138+
*/
139+
public void invalidate(CGraphicsDevice device) {
135140
//TODO do we need to restore the full-screen window/modes on old device?
136-
displayID = defaultDisplayID;
141+
displayID = device.displayID;
137142
}
138143

139144
@Override

‎src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java

+77-54
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
2525

2626
package sun.awt;
2727

28-
import java.awt.AWTError;
2928
import java.awt.Font;
3029
import java.awt.GraphicsConfiguration;
3130
import java.awt.GraphicsDevice;
@@ -112,7 +111,7 @@ public CGraphicsEnvironment() {
112111
}
113112

114113
/* Populate the device table */
115-
initDevices();
114+
rebuildDevices();
116115

117116
/* Register our display reconfiguration listener */
118117
displayReconfigContext = registerDisplayReconfiguration();
@@ -121,33 +120,27 @@ public CGraphicsEnvironment() {
121120
}
122121
}
123122

123+
/**
124+
* Updates the list of devices and notify listeners.
125+
*/
126+
private void rebuildDevices() {
127+
initDevices();
128+
displayChanged();
129+
}
130+
124131
/**
125132
* Called by the CoreGraphics Display Reconfiguration Callback.
126133
*
127134
* @param displayId CoreGraphics displayId
128135
* @param removed true if displayId was removed, false otherwise.
129136
*/
130-
void _displayReconfiguration(final int displayId, final boolean removed) {
131-
synchronized (this) {
132-
if (removed && devices.containsKey(displayId)) {
133-
final CGraphicsDevice gd = devices.remove(displayId);
134-
oldDevices.add(new WeakReference<>(gd));
135-
}
136-
}
137-
initDevices();
138-
139-
// Need to notify old devices, in case the user hold the reference to it
140-
for (ListIterator<WeakReference<CGraphicsDevice>> it =
141-
oldDevices.listIterator(); it.hasNext(); ) {
142-
CGraphicsDevice gd = it.next().get();
143-
if (gd != null) {
144-
gd.invalidate(mainDisplayID);
145-
gd.displayChanged();
146-
} else {
147-
// no more references to this device, remove it
148-
it.remove();
149-
}
150-
}
137+
void _displayReconfiguration(int displayId, boolean removed) {
138+
// we ignore the passed parameters and check removed devices ourself
139+
// Note that it is possible that this callback is called when the
140+
// monitors are not added nor removed, but when the video card is
141+
// switched to/from the discrete video card, so we should try to map the
142+
// old to the new devices.
143+
rebuildDevices();
151144
}
152145

153146
@Override
@@ -163,44 +156,74 @@ protected void finalize() throws Throwable {
163156
/**
164157
* (Re)create all CGraphicsDevices, reuses a devices if it is possible.
165158
*/
166-
private void initDevices() {
167-
synchronized (this) {
168-
final Map<Integer, CGraphicsDevice> old = new HashMap<>(devices);
169-
devices.clear();
170-
171-
mainDisplayID = getMainDisplayID();
172-
173-
// initialization of the graphics device may change
174-
// list of displays on hybrid systems via an activation
175-
// of discrete video.
176-
// So, we initialize the main display first, and then
177-
// retrieve actual list of displays.
178-
if (!old.containsKey(mainDisplayID)) {
179-
old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID));
159+
private synchronized void initDevices() {
160+
Map<Integer, CGraphicsDevice> old = new HashMap<>(devices);
161+
devices.clear();
162+
mainDisplayID = getMainDisplayID();
163+
164+
// initialization of the graphics device may change list of displays on
165+
// hybrid systems via an activation of discrete video.
166+
// So, we initialize the main display first, then retrieve actual list
167+
// of displays, and then recheck the main display again.
168+
if (!old.containsKey(mainDisplayID)) {
169+
old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID));
170+
}
171+
172+
int[] displayIDs = getDisplayIDs();
173+
if (displayIDs.length == 0) {
174+
// we could throw AWTError in this case.
175+
displayIDs = new int[]{mainDisplayID};
176+
}
177+
for (int id : displayIDs) {
178+
devices.put(id, old.containsKey(id) ? old.remove(id)
179+
: new CGraphicsDevice(id));
180+
}
181+
// fetch the main display again, the old value might be outdated
182+
mainDisplayID = getMainDisplayID();
183+
184+
// unlikely but make sure the main screen is in the list of screens,
185+
// most probably one more "displayReconfiguration" is on the road if not
186+
if (!devices.containsKey(mainDisplayID)) {
187+
mainDisplayID = displayIDs[0]; // best we can do
188+
}
189+
// if a device was not reused it should be invalidated
190+
for (CGraphicsDevice gd : old.values()) {
191+
oldDevices.add(new WeakReference<>(gd));
192+
}
193+
// Need to notify old devices, in case the user hold the reference to it
194+
for (ListIterator<WeakReference<CGraphicsDevice>> it =
195+
oldDevices.listIterator(); it.hasNext(); ) {
196+
CGraphicsDevice gd = it.next().get();
197+
if (gd != null) {
198+
// If the old device has the same bounds as some new device
199+
// then map that old device to the new, or to the main screen.
200+
CGraphicsDevice similarDevice = getSimilarDevice(gd);
201+
if (similarDevice == null) {
202+
gd.invalidate(devices.get(mainDisplayID));
203+
} else {
204+
gd.invalidate(similarDevice);
205+
}
206+
gd.displayChanged();
207+
} else {
208+
// no more references to this device, remove it
209+
it.remove();
180210
}
211+
}
212+
}
181213

182-
for (final int id : getDisplayIDs()) {
183-
devices.put(id, old.containsKey(id) ? old.get(id)
184-
: new CGraphicsDevice(id));
214+
private CGraphicsDevice getSimilarDevice(CGraphicsDevice old) {
215+
for (CGraphicsDevice device : devices.values()) {
216+
if (device.getBounds().equals(old.getBounds())) {
217+
// for now we will use the bounds only
218+
return device;
185219
}
186220
}
187-
displayChanged();
221+
return null;
188222
}
189223

190224
@Override
191225
public synchronized GraphicsDevice getDefaultScreenDevice() throws HeadlessException {
192-
CGraphicsDevice d = devices.get(mainDisplayID);
193-
if (d == null) {
194-
// we do not expect that this may happen, the only response
195-
// is to re-initialize the list of devices
196-
initDevices();
197-
198-
d = devices.get(mainDisplayID);
199-
if (d == null) {
200-
throw new AWTError("no screen devices");
201-
}
202-
}
203-
return d;
226+
return devices.get(mainDisplayID);
204227
}
205228

206229
@Override

‎test/jdk/java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
/**
4343
* @test
44-
* @bug 4836241 6364134 8232200
44+
* @bug 4836241 6364134 8232200 8252133
4545
* @key headful
4646
* @summary verify that images are restored correctly after display mode
4747
* switches and that no other rendering or crash problems occur

0 commit comments

Comments
 (0)
Please sign in to comment.