This repository has been archived by the owner on Aug 27, 2022. It is now read-only.
8258754: Gracefully fallback to the OpenGL rendering pipeline if Metal rendering pipeline initialization fails #147
Closed
Closed
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
e752955
fallback to opengl if metal initialization fails
aghaisas b4bfed4
do metal framework availability check once and cache it
aghaisas 9a6849a
Merge
aghaisas 9856b1d
implement fallback for OpenGL pipeline as well
aghaisas d23bd72
Cover all combinations of OGL and Metal pipelines
aghaisas 93ad231
Address review comments
aghaisas c36b416
Merge branch 'master' into fallback_to_opengl
aghaisas 7822546
handle invalid requests to use default pipeline
aghaisas 2600550
fix review comment
aghaisas 617235c
remove redundant check
aghaisas File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 @@ public class MacOSFlags { | |
* 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 @@ public class MacOSFlags { | |
|
||
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; | ||
aghaisas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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); | ||
aghaisas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right here we could add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good suggestion. |
||
// 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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to use metal and OGL at the same time on different devices? I think it is better to move these checks to the CGraphicsEnvironment.makeScreenDevice(), similar Win32GraphicsEnvironment.makeScreenDevice()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure why someone wants to use different pipelines on different devices? and should we support it?
On Windows we do that as a fallback to overcome a limitation of WGL - that's what I could infer from code in W32GraphicsDevice.getDefaultConfiguration()
I doubt whether we can add these checks in CGraphicsEnvironment.makeScreenDevice() - as we do not have specific MTLGraphicsDevice and CGLGraphicsDevice classes. That's the reason this method is currently unsupported.
Win32GraphicsEnvironment.makeScreenDevice() - creates either D3DGraphicsDevice or Win32GraphicsDevice based on whether isD3DEnabled.
Win32GraphicsDevice in turn uses either WGLGraphicsConfig or Win32GraphicsConfig based on whether OGL is enabled.
I felt CGraphicsDevice (similar to Win32GraphicsDevice) can differentiate between metal or OGL. Hence, I have added checks here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it is unsupported then why you should check that for every device creation? What happens if one device was created using metal and then another device will use OGL?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved the Metal framework availability check to be done only once now.
There is still a check if MTLGraphicsConfig.getConfig() fails by any chance.
CGraphicsDevice contains GraphicsConfiguration - which is created in the constructor - It can be either MTLGraphicsConfiguration or OpenGLConfiguration. This check needs to be done while creating the config.
For Win32GraphicsDevice - the config is not created in the constructor, but at a later stage in getDefaultConfiguration(). So only the place of checking for OGL or falling back to GDI is different, but the concept is the same.
The whole idea of one device using metal and another device using OGL is hypothetical. The condition check cannot pass for one device and fail for another.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it makes no sense to even consider using different pipelines on different devices. The change you made to do the check once seems best.