Skip to content

Commit

Permalink
JBR-5025 Reduce latency during display reconfiguration in Metal
Browse files Browse the repository at this point in the history
Moved metal load library checks to CGraphicsEnvironment
  • Loading branch information
avu authored and alexey.ushakov@jetbrains.com committed Dec 4, 2022
1 parent a0d5f30 commit c8e95ca
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 154 deletions.
79 changes: 13 additions & 66 deletions src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
Expand Down Expand Up @@ -61,8 +61,6 @@ public final class CGraphicsDevice extends GraphicsDevice
private volatile Insets screenInsets;

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


private static AWTPermission fullScreenExclusivePermission;
Expand All @@ -76,71 +74,24 @@ public CGraphicsDevice(final int displayID) {
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
Expand Down Expand Up @@ -401,10 +352,6 @@ public DisplayMode[] getDisplayModes() {
}
}

public static boolean usingMetalPipeline() {
return metalPipelineEnabled;
}

private void initScaleFactor() {
int _scale = scale;
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -30,13 +30,18 @@
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.MacosxSurfaceManagerFactory;
import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.SurfaceManagerFactory;
Expand All @@ -55,6 +60,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.
*/
Expand All @@ -71,9 +81,35 @@ 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;
}
}

// Install the correct surface manager factory.
SurfaceManagerFactory.setInstance(new MacosxSurfaceManagerFactory());
}
Expand All @@ -92,6 +128,12 @@ public static void init() { }
*/
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);
/**
Expand Down Expand Up @@ -124,6 +166,10 @@ public CGraphicsEnvironment() {
}
}

public static String getMtlShadersLibPath() {
return mtlShadersLib;
}

/**
* Updates the list of devices and notify listeners.
*/
Expand Down
4 changes: 4 additions & 0 deletions src/java.desktop/macosx/classes/sun/java2d/MacOSFlags.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,8 @@ public static boolean isOGLEnabled() {
public static boolean isOGLVerbose() {
return oglVerbose;
}

public static String getRenderPipelineName() {
return metalEnabled? "Metal" : oglEnabled ? "OpenGL" : "Unknown";
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, 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
Expand All @@ -25,9 +25,9 @@

package sun.java2d;

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

Expand All @@ -51,7 +51,7 @@ public class MacosxSurfaceManagerFactory extends SurfaceManagerFactory {
public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
Object context)
{
return CGraphicsDevice.usingMetalPipeline() ? new MTLVolatileSurfaceManager(vImg, context) :
return CGraphicsEnvironment.usingMetalPipeline() ? new MTLVolatileSurfaceManager(vImg, context) :
new CGLVolatileSurfaceManager(vImg, context);
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -59,9 +59,6 @@
import java.awt.image.DirectColorModel;
import java.awt.image.VolatileImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.security.AccessController;
import java.security.PrivilegedAction;

import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_GRAD_SHADER;
import static sun.java2d.pipe.hw.AccelSurface.TEXTURE;
Expand All @@ -73,22 +70,9 @@
public final class MTLGraphicsConfig extends CGraphicsConfig
implements AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig
{
@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 mtlAvailable;
private static boolean mtlUsed = false;
private static ImageCapabilities imageCaps = new MTLImageCaps();

@SuppressWarnings("removal")
private static final String mtlShadersLib = AccessController.doPrivileged(
(PrivilegedAction<String>) () ->
System.getProperty("java.home", "") + File.separator +
"lib" + File.separator + "shaders.metallib");


private BufferCapabilities bufferCaps;
private long pConfigInfo;
private ContextCapabilities mtlCaps;
Expand All @@ -97,7 +81,6 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
private final int maxTextureSize;

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

/**
Expand Down Expand Up @@ -140,28 +123,12 @@ public SurfaceData createManagedSurface(int w, int h, int transparency) {
public static MTLGraphicsConfig getConfig(CGraphicsDevice device,
int displayID, StringBuilder errorMessage)
{
if (!mtlAvailable) {
return null;
}

long cfginfo = 0;
int textureSize = 0;
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.
Expand All @@ -185,14 +152,9 @@ public static MTLGraphicsConfig getConfig(CGraphicsDevice device,
CAPS_EXT_BIOP_SHADER | CAPS_EXT_GRAD_SHADER,
null);

mtlUsed = true;
return new MTLGraphicsConfig(device, cfginfo, textureSize, caps);
}

public static boolean isMetalUsed() {
return mtlUsed;
}

public static boolean isMetalAvailable() {
return mtlAvailable;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, 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
Expand Down Expand Up @@ -68,7 +68,7 @@

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;
Expand Down Expand Up @@ -1412,7 +1412,7 @@ protected final void paintPeer(final Graphics g) {
}

protected static final void flushOnscreenGraphics(){
RenderQueue rq = CGraphicsDevice.usingMetalPipeline() ?
RenderQueue rq = CGraphicsEnvironment.usingMetalPipeline() ?
MTLRenderQueue.getInstance() : OGLRenderQueue.getInstance();
rq.lock();
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
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;
Expand All @@ -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);
Expand Down
Loading

0 comments on commit c8e95ca

Please sign in to comment.