8267430: GraphicsDevice.setDisplayMode(REFRESH_RATE_UNKNOWN) throws IAE: Unable to set display mode!
Reviewed-by: serb
This commit is contained in:
parent
bf29a0115c
commit
991ca14279
@ -34,6 +34,7 @@ import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
@ -65,9 +66,11 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
|
||||
// Save/restore DisplayMode for the Full Screen mode
|
||||
private DisplayMode originalMode;
|
||||
private DisplayMode initialMode;
|
||||
|
||||
public CGraphicsDevice(final int displayID) {
|
||||
this.displayID = displayID;
|
||||
this.initialMode = getDisplayMode();
|
||||
|
||||
if (MacOSFlags.isMetalEnabled()) {
|
||||
// Try to create MTLGraphicsConfig, if it fails,
|
||||
@ -201,6 +204,7 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
public void invalidate(CGraphicsDevice device) {
|
||||
//TODO do we need to restore the full-screen window/modes on old device?
|
||||
displayID = device.displayID;
|
||||
initialMode = device.initialMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -307,14 +311,47 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If the modes are the same or the only difference is that
|
||||
* the new mode will match any refresh rate, no need to change.
|
||||
*/
|
||||
private boolean isSameMode(final DisplayMode newMode,
|
||||
final DisplayMode oldMode) {
|
||||
|
||||
return (Objects.equals(newMode, oldMode) ||
|
||||
(newMode.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN &&
|
||||
newMode.getWidth() == oldMode.getWidth() &&
|
||||
newMode.getHeight() == oldMode.getHeight() &&
|
||||
newMode.getBitDepth() == oldMode.getBitDepth()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayMode(final DisplayMode dm) {
|
||||
if (dm == null) {
|
||||
throw new IllegalArgumentException("Invalid display mode");
|
||||
}
|
||||
if (!Objects.equals(dm, getDisplayMode())) {
|
||||
nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(),
|
||||
dm.getBitDepth(), dm.getRefreshRate());
|
||||
if (!isSameMode(dm, getDisplayMode())) {
|
||||
try {
|
||||
nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(),
|
||||
dm.getBitDepth(), dm.getRefreshRate());
|
||||
} catch (Throwable t) {
|
||||
/* In some cases macOS doesn't report the initial mode
|
||||
* in the list of supported modes.
|
||||
* If trying to reset to that mode causes an exception
|
||||
* try one more time to reset using a different API.
|
||||
* This does not fix everything, such as it doesn't make
|
||||
* that mode reported and it restores all devices, but
|
||||
* this seems a better compromise than failing to restore
|
||||
*/
|
||||
if (isSameMode(dm, initialMode)) {
|
||||
nativeResetDisplayMode();
|
||||
if (!isSameMode(initialMode, getDisplayMode())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not reset to initial mode");
|
||||
}
|
||||
} else {
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,7 +362,22 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
|
||||
@Override
|
||||
public DisplayMode[] getDisplayModes() {
|
||||
return nativeGetDisplayModes(displayID);
|
||||
DisplayMode[] nativeModes = nativeGetDisplayModes(displayID);
|
||||
boolean match = false;
|
||||
for (DisplayMode mode : nativeModes) {
|
||||
if (initialMode.equals(mode)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
return nativeModes;
|
||||
} else {
|
||||
int len = nativeModes.length;
|
||||
DisplayMode[] modes = Arrays.copyOf(nativeModes, len+1, DisplayMode[].class);
|
||||
modes[len] = initialMode;
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean usingMetalPipeline() {
|
||||
@ -345,6 +397,8 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
|
||||
private static native double nativeGetScaleFactor(int displayID);
|
||||
|
||||
private static native void nativeResetDisplayMode();
|
||||
|
||||
private static native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate);
|
||||
|
||||
private static native DisplayMode nativeGetDisplayMode(int displayID);
|
||||
|
@ -261,6 +261,18 @@ JNI_COCOA_EXIT(env);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_CGraphicsDevice
|
||||
* Method: nativeResetDisplayMode
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_CGraphicsDevice_nativeResetDisplayMode
|
||||
(JNIEnv *env, jclass class)
|
||||
{
|
||||
CGRestorePermanentDisplayConfiguration();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_CGraphicsDevice
|
||||
* Method: nativeSetDisplayMode
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8267430
|
||||
* @key headful
|
||||
* @summary verify setting a display mode with unknow refresh rate works
|
||||
*/
|
||||
|
||||
import java.awt.DisplayMode;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
|
||||
public class UnknownRefrshRateTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
GraphicsDevice[] devices = ge.getScreenDevices();
|
||||
|
||||
for (GraphicsDevice d : devices) {
|
||||
|
||||
if (!d.isDisplayChangeSupported()) {
|
||||
continue;
|
||||
}
|
||||
DisplayMode odm = d.getDisplayMode();
|
||||
System.out.println("device=" + d + " original mode=" + odm);
|
||||
|
||||
DisplayMode[] modes = d.getDisplayModes();
|
||||
System.out.println("There are " + modes.length + " modes.");
|
||||
try {
|
||||
for (int i=0; i<modes.length; i++) {
|
||||
DisplayMode mode = modes[i];
|
||||
System.out.println("copying from mode " + i + " : " + mode);
|
||||
int w = mode.getWidth();
|
||||
int h = mode.getHeight();
|
||||
int bpp = mode.getBitDepth();
|
||||
int refRate = DisplayMode.REFRESH_RATE_UNKNOWN;
|
||||
DisplayMode newMode = new DisplayMode(w, h, bpp, refRate);
|
||||
d.setDisplayMode(newMode);
|
||||
Thread.sleep(2000);
|
||||
System.out.println("set " + d.getDisplayMode());
|
||||
}
|
||||
} finally {
|
||||
System.out.println("restoring original mode"+odm);
|
||||
d.setDisplayMode(odm);
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user