JBR-5025 Reduce latency during display reconfiguration in Metal

Moved metal load library checks to CGraphicsEnvironment

(cherry picked from commit eeee663bb4)
This commit is contained in:
Alexey Ushakov
2022-11-18 23:14:34 +04:00
committed by Vitaly Provodin
parent e54eae93fe
commit 47c48c9345
10 changed files with 108 additions and 140 deletions

View File

@@ -60,8 +60,6 @@ public final class CGraphicsDevice extends GraphicsDevice
private volatile Insets screenInsets;
private GraphicsConfiguration config;
private static boolean metalPipelineEnabled = false;
private static boolean oglPipelineEnabled = false;
// Save/restore DisplayMode for the Full Screen mode
@@ -73,71 +71,24 @@ public final class CGraphicsDevice extends GraphicsDevice
this.initialMode = getDisplayMode();
StringBuilder errorMessage = new StringBuilder();
if (MacOSFlags.isMetalEnabled()) {
// Try to create MTLGraphicsConfig, if it fails,
// try to create CGLGraphicsConfig as a fallback
this.config = MTLGraphicsConfig.getConfig(this, displayID, errorMessage);
this.config = CGraphicsEnvironment.usingMetalPipeline() ?
MTLGraphicsConfig.getConfig(this, displayID, errorMessage) :
CGLGraphicsConfig.getConfig(this);
if (this.config != null) {
metalPipelineEnabled = true;
} else {
if (MTLGraphicsConfig.isMetalUsed()) {
// Should not fall back to OpenGL if Metal has been used before
// (it could cause CCE during replace of surface data)
throw new IllegalStateException("Error - unable to initialize Metal" +
" after recreation of graphics device." + errorMessage);
}
// 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;
}
if (this.config == null) {
if (MacOSFlags.isMetalVerbose() || MacOSFlags.isOGLVerbose()) {
System.out.println(MacOSFlags.getRenderPipelineName() +
" rendering pipeline initialization failed");
}
throw new IllegalStateException("Error - unable to initialize " +
MacOSFlags.getRenderPipelineName());
} 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, errorMessage);
if (this.config != null) {
metalPipelineEnabled = true;
}
if (MacOSFlags.isMetalVerbose() || MacOSFlags.isOGLVerbose()) {
System.out.println(MacOSFlags.getRenderPipelineName() +
" pipeline enabled on screen " + displayID);
}
}
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." + errorMessage);
}
if (metalPipelineEnabled && MacOSFlags.isMetalVerbose()) {
System.out.println("Metal pipeline enabled on screen " + displayID);
} else if (oglPipelineEnabled && MacOSFlags.isOGLVerbose()) {
System.out.println("OpenGL pipeline enabled on screen " + displayID);
}
// 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
@@ -381,10 +332,6 @@ public final class CGraphicsDevice extends GraphicsDevice
}
}
public static boolean usingMetalPipeline() {
return metalPipelineEnabled;
}
private void initScaleFactor() {
int _scale = scale;
if (SunGraphicsEnvironment.isUIScaleEnabled()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@@ -30,13 +30,18 @@ import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.io.File;
import java.lang.annotation.Native;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import sun.java2d.MacOSFlags;
import sun.java2d.SunGraphicsEnvironment;
import sun.util.logging.PlatformLogger;
@@ -53,6 +58,11 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
private static final PlatformLogger logger =
PlatformLogger.getLogger(CGraphicsEnvironment.class.getName());
@Native private final static int MTL_SUPPORTED = 0;
@Native private final static int MTL_NO_DEVICE = 1;
@Native private final static int MTL_NO_SHADER_LIB = 2;
@Native private final static int MTL_ERROR = 3;
/**
* Fetch an array of all valid CoreGraphics display identifiers.
*/
@@ -69,9 +79,34 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
*/
public static void init() { }
@SuppressWarnings("removal")
private static final String mtlShadersLib = AccessController.doPrivileged(
(PrivilegedAction<String>) () ->
System.getProperty("java.home", "") + File.separator +
"lib" + File.separator + "shaders.metallib");
private static native int initMetal(String shaderLib);
static {
// Load libraries and initialize the Toolkit.
Toolkit.getDefaultToolkit();
metalPipelineEnabled = false;
if (MacOSFlags.isMetalEnabled()) {
int res = initMetal(mtlShadersLib);
if (res != MTL_SUPPORTED) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("Cannot initialize Metal: " +
switch (res) {
case MTL_ERROR -> "Unexpected error.";
case MTL_NO_DEVICE -> "No MTLDevice.";
case MTL_NO_SHADER_LIB -> "No Metal shader library.";
default -> "Unexpected error (" + res + ").";
});
}
} else {
metalPipelineEnabled = true;
}
}
}
/**
@@ -88,6 +123,12 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
*/
private native void deregisterDisplayReconfiguration(long context);
private static boolean metalPipelineEnabled;
public static boolean usingMetalPipeline() {
return metalPipelineEnabled;
}
/** Available CoreGraphics displays. */
private final Map<Integer, CGraphicsDevice> devices = new HashMap<>(5);
/**
@@ -120,6 +161,10 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
}
}
public static String getMtlShadersLibPath() {
return mtlShadersLib;
}
/**
* Updates the list of devices and notify listeners.
*/

View File

@@ -146,4 +146,8 @@ public class MacOSFlags {
public static boolean isOGLVerbose() {
return oglVerbose;
}
public static String getRenderPipelineName() {
return metalEnabled? "Metal" : oglEnabled ? "OpenGL" : "Unknown";
}
}

View File

@@ -25,9 +25,9 @@
package sun.java2d.metal;
import java.lang.annotation.Native;
import sun.awt.CGraphicsConfig;
import sun.awt.CGraphicsDevice;
import sun.awt.CGraphicsEnvironment;
import sun.awt.image.OffScreenImage;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.SurfaceManager;
@@ -60,7 +60,6 @@ import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
import java.awt.image.VolatileImage;
import java.awt.image.WritableRaster;
import java.io.File;
import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_GRAD_SHADER;
import static sun.java2d.pipe.hw.AccelSurface.TEXTURE;
@@ -72,20 +71,8 @@ import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER;
public final class MTLGraphicsConfig extends CGraphicsConfig
implements AccelGraphicsConfig, SurfaceManager.Factory
{
@Native private final static int LOAD_LIB_ERROR = -1;
@Native private final static int LOAD_LIB_OK = 0;
@Native private final static int LOAD_LIB_NO_DEVICE = 1;
@Native private final static int LOAD_LIB_NO_SHADER_LIB = 2;
private static boolean mtlUsed = false;
private static ImageCapabilities imageCaps = new MTLImageCaps();
private static final String mtlShadersLib =
System.getProperty("java.home", "") + File.separator +
"lib" + File.separator + "shaders.metallib";
private BufferCapabilities bufferCaps;
private long pConfigInfo;
private ContextCapabilities mtlCaps;
@@ -93,7 +80,6 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
private final Object disposerReferent = new Object();
private final int maxTextureSize;
private static native int tryLoadMetalLibrary(int displayID, String shaderLib);
private static native long getMTLConfigInfo(int displayID, String mtlShadersLib);
/**
@@ -132,19 +118,7 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
MTLRenderQueue rq = MTLRenderQueue.getInstance();
rq.lock();
try {
int res = tryLoadMetalLibrary(displayID, mtlShadersLib);
if (res != LOAD_LIB_OK) {
errorMessage.append(" Cannot load metal library: " +
switch (res) {
case LOAD_LIB_ERROR -> "Unexpected error.";
case LOAD_LIB_NO_DEVICE -> "No MTLDevice.";
case LOAD_LIB_NO_SHADER_LIB -> "No Metal shader library.";
default -> throw new IllegalStateException("Unexpected value: " + res);
});
return null;
}
cfginfo = getMTLConfigInfo(displayID, mtlShadersLib);
cfginfo = getMTLConfigInfo(displayID, CGraphicsEnvironment.getMtlShadersLibPath());
if (cfginfo != 0L) {
textureSize = nativeGetMaxTextureSize();
// TODO : This clamping code is same as in OpenGL.
@@ -168,14 +142,9 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
CAPS_EXT_BIOP_SHADER | CAPS_EXT_GRAD_SHADER,
null);
mtlUsed = true;
return new MTLGraphicsConfig(device, cfginfo, textureSize, caps);
}
public static boolean isMetalUsed() {
return mtlUsed;
}
/**
* Returns true if the provided capability bit is present for this config.
* See MTLContext.java for a list of supported capabilities.

View File

@@ -66,7 +66,7 @@ import javax.swing.SwingUtilities;
import com.sun.java.swing.SwingUtilities3;
import sun.awt.AWTAccessor;
import sun.awt.CGraphicsDevice;
import sun.awt.CGraphicsEnvironment;
import sun.awt.PaintEventDispatcher;
import sun.awt.RepaintArea;
import sun.awt.SunToolkit;
@@ -1399,7 +1399,7 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent>
}
protected static final void flushOnscreenGraphics(){
RenderQueue rq = CGraphicsDevice.usingMetalPipeline() ?
RenderQueue rq = CGraphicsEnvironment.usingMetalPipeline() ?
MTLRenderQueue.getInstance() : OGLRenderQueue.getInstance();
rq.lock();
try {

View File

@@ -28,7 +28,7 @@ package sun.lwawt.macosx;
import java.awt.*;
import java.awt.event.FocusEvent;
import sun.awt.CGraphicsDevice;
import sun.awt.CGraphicsEnvironment;
import sun.java2d.SurfaceData;
import sun.java2d.metal.MTLLayer;
import sun.java2d.opengl.CGLLayer;
@@ -55,7 +55,7 @@ public class CPlatformEmbeddedFrame implements PlatformWindow {
@Override // PlatformWindow
public void initialize(Window target, final LWWindowPeer peer, PlatformWindow owner) {
this.peer = peer;
if (CGraphicsDevice.usingMetalPipeline()) {
if (CGraphicsEnvironment.usingMetalPipeline()) {
this.windowLayer = new MTLLayer(peer);
} else {
this.windowLayer = new CGLLayer(peer);

View File

@@ -35,7 +35,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import sun.awt.CGraphicsEnvironment;
import sun.awt.CGraphicsDevice;
import sun.java2d.metal.MTLLayer;
import sun.lwawt.LWWindowPeer;
@@ -64,8 +63,7 @@ public class CPlatformView extends CFRetainedResource {
public void initialize(LWWindowPeer peer, CPlatformResponder responder) {
initializeBase(peer, responder);
this.windowLayer = CGraphicsDevice.usingMetalPipeline()? createMTLLayer() : createCGLayer();
this.windowLayer = CGraphicsEnvironment.usingMetalPipeline()? createMTLLayer() : createCGLayer();
setPtr(nativeCreateView(0, 0, 0, 0, getWindowLayerPtr()));
}

View File

@@ -488,7 +488,7 @@ public final class LWCToolkit extends LWToolkit {
@Override
public void sync() {
// flush the rendering pipeline
if (CGraphicsDevice.usingMetalPipeline()) {
if (CGraphicsEnvironment.usingMetalPipeline()) {
MTLRenderQueue.sync();
} else {
OGLRenderQueue.sync();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@@ -23,6 +23,9 @@
* questions.
*/
#import <Metal/Metal.h>
#import <Trace.h>
#import "sun_awt_CGraphicsEnvironment.h"
#import "AWT_debug.h"
#import "JNIUtilities.h"
@@ -179,3 +182,36 @@ JNI_COCOA_ENTER(env);
JNI_COCOA_EXIT(env);
}
JNIEXPORT jint JNICALL Java_sun_awt_CGraphicsEnvironment_initMetal
(JNIEnv *env, jclass mtlgc, jstring shadersLibName)
{
__block jint ret = sun_awt_CGraphicsEnvironment_MTL_ERROR;
JNI_COCOA_ENTER(env);
__block NSString* path = NormalizedPathNSStringFromJavaString(env, shadersLibName);
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if (device != nil) {
NSError* error = nil;
id<MTLLibrary> lib = [device newLibraryWithFile:path error:&error];
if (lib != nil) {
ret = sun_awt_CGraphicsEnvironment_MTL_SUPPORTED;
} else {
J2dRlsTraceLn(J2D_TRACE_ERROR, "CGraphicsEnvironment_initMetal - "
"Failed to load Metal shader library.");
ret = sun_awt_CGraphicsEnvironment_MTL_NO_SHADER_LIB;
}
} else {
J2dRlsTraceLn(J2D_TRACE_ERROR, "CGraphicsEnvironment_initMetal - "
"Failed to create MTLDevice.");
ret = sun_awt_CGraphicsEnvironment_MTL_NO_DEVICE;
}
}];
JNI_COCOA_EXIT(env);
return ret;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, 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
@@ -54,37 +54,6 @@ MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo)
free(mtlinfo);
}
JNIEXPORT jint JNICALL
Java_sun_java2d_metal_MTLGraphicsConfig_tryLoadMetalLibrary
(JNIEnv *env, jclass mtlgc, jint displayID, jstring shadersLibName)
{
__block jint ret = sun_java2d_metal_MTLGraphicsConfig_LOAD_LIB_ERROR;
JNI_COCOA_ENTER(env);
__block NSString* path = NormalizedPathNSStringFromJavaString(env, shadersLibName);
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
id<MTLDevice> device = CGDirectDisplayCopyCurrentMetalDevice(displayID);
if (device != nil) {
NSError* error = nil;
id<MTLLibrary> lib = [device newLibraryWithFile:path error:&error];
if (lib != nil) {
ret = sun_java2d_metal_MTLGraphicsConfig_LOAD_LIB_OK;
} else {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_tryLoadMetalLibrary - Failed to load Metal shader library.");
ret = sun_java2d_metal_MTLGraphicsConfig_LOAD_LIB_NO_SHADER_LIB;
}
} else {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_tryLoadMetalLibrary - Failed to create MTLDevice.");
ret = sun_java2d_metal_MTLGraphicsConfig_LOAD_LIB_NO_DEVICE;
}
}];
JNI_COCOA_EXIT(env);
return ret;
}
/**
* Determines whether the Metal pipeline can be used for a given screen number and