Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

8258754: Gracefully fallback to the OpenGL rendering pipeline if Meta…

…l rendering pipeline initialization fails

Reviewed-by: kcr, prr
  • Loading branch information
aghaisas committed Jan 19, 2021
1 parent ffff4e1 commit 729546ecec4f32d3f689e9cbc7c04fcde6ea87c3
@@ -56,7 +56,10 @@
private volatile Rectangle bounds;
private volatile int scale;

private final GraphicsConfiguration config;
private GraphicsConfiguration config;
private static boolean metalPipelineEnabled = false;
private static boolean oglPipelineEnabled = false;


private static AWTPermission fullScreenExclusivePermission;

@@ -65,9 +68,51 @@

public CGraphicsDevice(final int displayID) {
this.displayID = displayID;
config = MacOSFlags.isMetalEnabled() ?
MTLGraphicsConfig.getConfig(this, displayID, 0) :
CGLGraphicsConfig.getConfig(this);

if (MacOSFlags.isMetalEnabled()) {
// Try to create MTLGraphicsConfig, if it fails, try to create CGLGraphicsConfig as a fallback
this.config = MTLGraphicsConfig.getConfig(this, displayID, 0);

if (this.config != null) {
metalPipelineEnabled = true;
} else {
// Try falling back to OpenGL pipeline
if (MacOSFlags.isMetalVerbose()) {
System.out.println("Metal rendering pipeline initialization failed. Using OpenGL rendering pipeline.");
}

this.config = CGLGraphicsConfig.getConfig(this);

if (this.config != null) {
oglPipelineEnabled = true;
}
}
} else {
// Try to create CGLGraphicsConfig, if it fails, try to create MTLGraphicsConfig as a fallback
this.config = CGLGraphicsConfig.getConfig(this);

if (this.config != null) {
oglPipelineEnabled = true;
} else {
// Try falling back to Metal pipeline
if (MacOSFlags.isOGLVerbose()) {
System.out.println("OpenGL rendering pipeline initialization failed. Using Metal rendering pipeline.");
}

this.config = MTLGraphicsConfig.getConfig(this, displayID, 0);

if (this.config != null) {
metalPipelineEnabled = true;
}
}
}

if (!metalPipelineEnabled && !oglPipelineEnabled) {
// This indicates fallback to other rendering pipeline also failed.
// Should never reach here
throw new InternalError("Error - unable to initialize any rendering pipeline.");
}

// initializes default device state, might be redundant step since we
// call "displayChanged()" later anyway, but we do not want to leave the
// device in an inconsistent state after construction
@@ -269,6 +314,10 @@ public DisplayMode getDisplayMode() {
return nativeGetDisplayModes(displayID);
}

public static boolean usingMetalPipeline() {
return metalPipelineEnabled;
}

private void initScaleFactor() {
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
double debugScale = SunGraphicsEnvironment.getDebugScale();
@@ -27,7 +27,7 @@

import sun.awt.image.SunVolatileImage;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.macos.MacOSFlags;
import sun.awt.CGraphicsDevice;
import sun.java2d.metal.MTLVolatileSurfaceManager;
import sun.java2d.opengl.CGLVolatileSurfaceManager;

@@ -51,7 +51,7 @@
public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
Object context)
{
return MacOSFlags.isMetalEnabled() ? new MTLVolatileSurfaceManager(vImg, context) :
return CGraphicsDevice.usingMetalPipeline() ? new MTLVolatileSurfaceManager(vImg, context) :
new CGLVolatileSurfaceManager(vImg, context);
}
}
@@ -26,6 +26,9 @@
package sun.java2d.macos;

import java.security.PrivilegedAction;
import sun.java2d.metal.MTLGraphicsConfig;
import sun.java2d.opengl.CGLGraphicsConfig;


public class MacOSFlags {

@@ -35,7 +38,12 @@
* metalEnabled: usage: "-Dsun.java2d.metal=[true|false]"
*/

private static boolean oglEnabled;
private static boolean oglVerbose;
private static boolean metalEnabled;
private static boolean metalVerbose;

private enum PropertyState {ENABLED, DISABLED, UNSPECIFIED};

static {
initJavaFlags();
@@ -44,43 +52,117 @@

private static native boolean initNativeFlags();

private static boolean getBooleanProp(String p, boolean defaultVal) {
private static PropertyState getBooleanProp(String p, PropertyState defaultVal) {
String propString = System.getProperty(p);
boolean returnVal = defaultVal;
PropertyState returnVal = defaultVal;
if (propString != null) {
if (propString.equals("true") ||
propString.equals("t") ||
propString.equals("True") ||
propString.equals("T") ||
propString.equals("")) // having the prop name alone
{ // is equivalent to true
returnVal = true;
returnVal = PropertyState.ENABLED;
} else if (propString.equals("false") ||
propString.equals("f") ||
propString.equals("False") ||
propString.equals("F"))
{
returnVal = false;
returnVal = PropertyState.DISABLED;
}
}
return returnVal;
}


private static boolean getPropertySet(String p) {
private static boolean isBooleanPropTrueVerbose(String p) {
String propString = System.getProperty(p);
return (propString != null) ? true : false;
if (propString != null) {
if (propString.equals("True") ||
propString.equals("T"))
{
return true;
}
}
return false;
}

private static void initJavaFlags() {
java.security.AccessController.doPrivileged(
(PrivilegedAction<Object>) () -> {
metalEnabled = getBooleanProp("sun.java2d.metal", false);
PropertyState oglState = getBooleanProp("sun.java2d.opengl", PropertyState.UNSPECIFIED);
PropertyState metalState = getBooleanProp("sun.java2d.metal", PropertyState.UNSPECIFIED);

// Handle invalid combinations to use the default rendering pipeline
// Current default rendering pipeline is OpenGL
// (The default can be changed to Metal in future just by toggling two states in this if condition block)
if ((oglState == PropertyState.UNSPECIFIED && metalState == PropertyState.UNSPECIFIED) ||
(oglState == PropertyState.DISABLED && metalState == PropertyState.DISABLED) ||
(oglState == PropertyState.ENABLED && metalState == PropertyState.ENABLED)) {
oglState = PropertyState.ENABLED; // Enable default pipeline
metalState = PropertyState.DISABLED; // Disable non-default pipeline
}

if (metalState == PropertyState.UNSPECIFIED) {
if (oglState == PropertyState.DISABLED) {
oglEnabled = false;
metalEnabled = true;
} else {
oglEnabled = true;
metalEnabled = false;
}
} else if (metalState == PropertyState.ENABLED) {
oglEnabled = false;
metalEnabled = true;
} else if (metalState == PropertyState.DISABLED) {
oglEnabled = true;
metalEnabled = false;
}

oglVerbose = isBooleanPropTrueVerbose("sun.java2d.opengl");
metalVerbose = isBooleanPropTrueVerbose("sun.java2d.metal");

if (oglEnabled && !metalEnabled) {
// Check whether OGL is available
if (!CGLGraphicsConfig.isCGLAvailable()) {
if (oglVerbose) {
System.out.println("Could not enable OpenGL pipeline (CGL not available)");
}
oglEnabled = false;
metalEnabled = MTLGraphicsConfig.isMetalAvailable();
}
} else if (metalEnabled && !oglEnabled) {
// Check whether Metal framework is available
if (!MTLGraphicsConfig.isMetalAvailable()) {
if (metalVerbose) {
System.out.println("Could not enable Metal pipeline (Metal framework not available)");
}
metalEnabled = false;
oglEnabled = CGLGraphicsConfig.isCGLAvailable();
}
}

// At this point one of the rendering pipeline must be enabled.
if (!metalEnabled && !oglEnabled) {
throw new InternalError("Error - unable to initialize any rendering pipeline.");
}

return null;
});
}

public static boolean isMetalEnabled() {
return metalEnabled;
}

public static boolean isMetalVerbose() {
return metalVerbose;
}

public static boolean isOGLEnabled() {
return oglEnabled;
}

public static boolean isOGLVerbose() {
return oglVerbose;
}
}
@@ -78,7 +78,8 @@
private final Object disposerReferent = new Object();
private final int maxTextureSize;

private static native boolean initMTL();
private static native boolean isMetalFrameworkAvailable();
private static native boolean tryLoadMetalLibrary(int displayID, String shaderLib);
private static native long getMTLConfigInfo(int displayID, String mtlShadersLib);

/**
@@ -88,7 +89,7 @@
private static native int nativeGetMaxTextureSize();

static {
mtlAvailable = initMTL();
mtlAvailable = isMetalFrameworkAvailable();
}

private MTLGraphicsConfig(CGraphicsDevice device, int pixfmt,
@@ -126,6 +127,10 @@ public static MTLGraphicsConfig getConfig(CGraphicsDevice device,
return null;
}

if (!tryLoadMetalLibrary(displayID, mtlShadersLib)) {
return null;
}

long cfginfo = 0;
int textureSize = 0;
final String[] ids = new String[1];
@@ -164,6 +169,10 @@ public static MTLGraphicsConfig getConfig(CGraphicsDevice device,
return new MTLGraphicsConfig(device, pixfmt, cfginfo, textureSize, caps);
}

public static boolean isMetalAvailable() {
return mtlAvailable;
}

/**
* Returns true if the provided capability bit is present for this config.
* See MTLContext.java for a list of supported capabilities.
@@ -68,13 +68,13 @@

import com.sun.java.swing.SwingUtilities3;
import sun.awt.AWTAccessor;
import sun.awt.CGraphicsDevice;
import sun.awt.PaintEventDispatcher;
import sun.awt.RepaintArea;
import sun.awt.SunToolkit;
import sun.awt.event.IgnorePaintEvent;
import sun.awt.image.SunVolatileImage;
import sun.java2d.SunGraphics2D;
import sun.java2d.macos.MacOSFlags;
import sun.java2d.metal.MTLRenderQueue;
import sun.java2d.opengl.OGLRenderQueue;
import sun.java2d.pipe.Region;
@@ -1417,7 +1417,7 @@ protected final void paintPeer(final Graphics g) {
}

protected static final void flushOnscreenGraphics(){
RenderQueue rq = MacOSFlags.isMetalEnabled() ?
RenderQueue rq = CGraphicsDevice.usingMetalPipeline() ?
MTLRenderQueue.getInstance() : OGLRenderQueue.getInstance();
rq.lock();
try {
@@ -28,8 +28,8 @@
import java.awt.*;
import java.awt.event.FocusEvent;

import sun.awt.CGraphicsDevice;
import sun.java2d.SurfaceData;
import sun.java2d.macos.MacOSFlags;
import sun.java2d.metal.MTLLayer;
import sun.java2d.opengl.CGLLayer;
import sun.lwawt.LWWindowPeer;
@@ -56,7 +56,7 @@
@Override // PlatformWindow
public void initialize(Window target, final LWWindowPeer peer, PlatformWindow owner) {
this.peer = peer;
if (MacOSFlags.isMetalEnabled()) {
if ( CGraphicsDevice.usingMetalPipeline()) {
this.windowLayer = new MTLLayer(peer);
} else {
this.windowLayer = new CGLLayer(peer);
@@ -71,7 +71,7 @@ public LWWindowPeer getPeer() {

@Override
public long getLayerPtr() {
if (MacOSFlags.isMetalEnabled()) {
if (CGraphicsDevice.usingMetalPipeline()) {
return ((MTLLayer)windowLayer).getPointer();
} else {
return ((CGLLayer)windowLayer).getPointer();
@@ -80,7 +80,7 @@ public long getLayerPtr() {

@Override
public void dispose() {
if (MacOSFlags.isMetalEnabled()) {
if ( CGraphicsDevice.usingMetalPipeline()) {
((MTLLayer)windowLayer).dispose();
} else {
((CGLLayer)windowLayer).dispose();
@@ -115,7 +115,7 @@ public FontMetrics getFontMetrics(Font f) {

@Override
public SurfaceData getScreenSurface() {
if (MacOSFlags.isMetalEnabled()) {
if ( CGraphicsDevice.usingMetalPipeline()) {
return ((MTLLayer)windowLayer).getSurfaceData();
} else {
return ((CGLLayer)windowLayer).getSurfaceData();
@@ -124,7 +124,7 @@ public SurfaceData getScreenSurface() {

@Override
public SurfaceData replaceSurfaceData() {
if (MacOSFlags.isMetalEnabled()) {
if ( CGraphicsDevice.usingMetalPipeline()) {
return ((MTLLayer)windowLayer).replaceSurfaceData();
} else {
return ((CGLLayer)windowLayer).replaceSurfaceData();

0 comments on commit 729546e

Please sign in to comment.