Path: blob/master/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java
41159 views
/*1* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.metal;2627import sun.awt.CGraphicsConfig;28import sun.awt.CGraphicsDevice;29import sun.awt.image.OffScreenImage;30import sun.awt.image.SunVolatileImage;31import sun.awt.image.SurfaceManager;32import sun.java2d.Disposer;33import sun.java2d.DisposerRecord;34import sun.java2d.Surface;35import sun.java2d.SurfaceData;36import sun.java2d.pipe.hw.AccelGraphicsConfig;37import sun.java2d.pipe.hw.AccelSurface;38import sun.java2d.pipe.hw.AccelTypedVolatileImage;39import sun.java2d.pipe.hw.ContextCapabilities;40import sun.lwawt.LWComponentPeer;41import sun.lwawt.macosx.CFRetainedResource;4243import java.awt.AWTException;44import java.awt.BufferCapabilities;45import java.awt.Component;46import java.awt.Graphics;47import java.awt.Graphics2D;48import java.awt.Image;49import java.awt.ImageCapabilities;50import java.awt.Rectangle;51import java.awt.Transparency;5253import java.awt.color.ColorSpace;54import java.awt.image.BufferedImage;55import java.awt.image.ColorModel;56import java.awt.image.DataBuffer;57import java.awt.image.DirectColorModel;58import java.awt.image.VolatileImage;59import java.awt.image.WritableRaster;60import java.io.File;61import java.security.AccessController;62import java.security.PrivilegedAction;6364import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_GRAD_SHADER;65import static sun.java2d.pipe.hw.AccelSurface.TEXTURE;66import static sun.java2d.pipe.hw.AccelSurface.RT_TEXTURE;67import static sun.java2d.pipe.hw.ContextCapabilities.*;6869import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER;7071public final class MTLGraphicsConfig extends CGraphicsConfig72implements AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig73{74private static boolean mtlAvailable;75private static ImageCapabilities imageCaps = new MTLImageCaps();7677@SuppressWarnings("removal")78private static final String mtlShadersLib = AccessController.doPrivileged(79(PrivilegedAction<String>) () ->80System.getProperty("java.home", "") + File.separator +81"lib" + File.separator + "shaders.metallib");828384private BufferCapabilities bufferCaps;85private long pConfigInfo;86private ContextCapabilities mtlCaps;87private final MTLContext context;88private final Object disposerReferent = new Object();89private final int maxTextureSize;9091private static native boolean isMetalFrameworkAvailable();92private static native boolean tryLoadMetalLibrary(int displayID, String shaderLib);93private static native long getMTLConfigInfo(int displayID, String mtlShadersLib);9495/**96* Returns maximum texture size supported by Metal. Must be97* called under MTLRQ lock.98*/99private static native int nativeGetMaxTextureSize();100101static {102mtlAvailable = isMetalFrameworkAvailable();103}104105private MTLGraphicsConfig(CGraphicsDevice device,106long configInfo, int maxTextureSize,107ContextCapabilities mtlCaps) {108super(device);109110this.pConfigInfo = configInfo;111this.mtlCaps = mtlCaps;112this.maxTextureSize = maxTextureSize;113context = new MTLContext(MTLRenderQueue.getInstance());114// add a record to the Disposer so that we destroy the native115// MTLGraphicsConfigInfo data when this object goes away116Disposer.addRecord(disposerReferent,117new MTLGCDisposerRecord(pConfigInfo));118}119120@Override121public Object getProxyKey() {122return this;123}124125public SurfaceData createManagedSurface(int w, int h, int transparency) {126return MTLSurfaceData.createData(this, w, h,127getColorModel(transparency),128null,129MTLSurfaceData.TEXTURE);130}131132public static MTLGraphicsConfig getConfig(CGraphicsDevice device,133int displayID)134{135if (!mtlAvailable) {136return null;137}138139if (!tryLoadMetalLibrary(displayID, mtlShadersLib)) {140return null;141}142143long cfginfo = 0;144int textureSize = 0;145MTLRenderQueue rq = MTLRenderQueue.getInstance();146rq.lock();147try {148cfginfo = getMTLConfigInfo(displayID, mtlShadersLib);149if (cfginfo != 0L) {150textureSize = nativeGetMaxTextureSize();151// TODO : This clamping code is same as in OpenGL.152// Whether we need such clamping or not in case of Metal153// will be pursued under 8260644154textureSize = textureSize <= 16384 ? textureSize / 2 : 8192;155MTLContext.setScratchSurface(cfginfo);156}157} finally {158rq.unlock();159}160if (cfginfo == 0) {161return null;162}163164ContextCapabilities caps = new MTLContext.MTLContextCaps(165CAPS_PS30 | CAPS_PS20 |166CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE |167CAPS_MULTITEXTURE | CAPS_TEXNONPOW2 | CAPS_TEXNONSQUARE |168CAPS_EXT_BIOP_SHADER | CAPS_EXT_GRAD_SHADER,169null);170return new MTLGraphicsConfig(device, cfginfo, textureSize, caps);171}172173public static boolean isMetalAvailable() {174return mtlAvailable;175}176177/**178* Returns true if the provided capability bit is present for this config.179* See MTLContext.java for a list of supported capabilities.180*/181public boolean isCapPresent(int cap) {182return ((mtlCaps.getCaps() & cap) != 0);183}184185public long getNativeConfigInfo() {186return pConfigInfo;187}188189/**190* {@inheritDoc}191*192* @see sun.java2d.pipe.hw.BufferedContextProvider#getContext193*/194@Override195public MTLContext getContext() {196return context;197}198199@Override200public BufferedImage createCompatibleImage(int width, int height) {201ColorModel model = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);202WritableRaster203raster = model.createCompatibleWritableRaster(width, height);204return new BufferedImage(model, raster, model.isAlphaPremultiplied(),205null);206}207208@Override209public ColorModel getColorModel(int transparency) {210switch (transparency) {211case Transparency.OPAQUE:212// REMIND: once the ColorModel spec is changed, this should be213// an opaque premultiplied DCM...214return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);215case Transparency.BITMASK:216return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);217case Transparency.TRANSLUCENT:218ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);219return new DirectColorModel(cs, 32,2200xff0000, 0xff00, 0xff, 0xff000000,221true, DataBuffer.TYPE_INT);222default:223return null;224}225}226227public boolean isDoubleBuffered() {228return true;229}230231private static class MTLGCDisposerRecord implements DisposerRecord {232private long pCfgInfo;233public MTLGCDisposerRecord(long pCfgInfo) {234this.pCfgInfo = pCfgInfo;235}236public void dispose() {237if (pCfgInfo != 0) {238MTLRenderQueue.disposeGraphicsConfig(pCfgInfo);239pCfgInfo = 0;240}241}242}243244@Override245public String toString() {246return ("MTLGraphicsConfig[" + getDevice().getIDstring() + "]");247}248249@Override250public SurfaceData createSurfaceData(CFRetainedResource layer) {251return MTLSurfaceData.createData((MTLLayer) layer);252}253254@Override255public Image createAcceleratedImage(Component target,256int width, int height)257{258ColorModel model = getColorModel(Transparency.OPAQUE);259WritableRaster wr = model.createCompatibleWritableRaster(width, height);260return new OffScreenImage(target, model, wr,261model.isAlphaPremultiplied());262}263264@Override265public void assertOperationSupported(final int numBuffers,266final BufferCapabilities caps)267throws AWTException {268// Assume this method is never called with numBuffers != 2, as 0 is269// unsupported, and 1 corresponds to a SingleBufferStrategy which270// doesn't depend on the peer. Screen is considered as a separate271// "buffer".272if (numBuffers != 2) {273throw new AWTException("Only double buffering is supported");274}275final BufferCapabilities configCaps = getBufferCapabilities();276if (!configCaps.isPageFlipping()) {277throw new AWTException("Page flipping is not supported");278}279if (caps.getFlipContents() == BufferCapabilities.FlipContents.PRIOR) {280throw new AWTException("FlipContents.PRIOR is not supported");281}282}283284@Override285public Image createBackBuffer(final LWComponentPeer<?, ?> peer) {286final Rectangle r = peer.getBounds();287// It is possible for the component to have size 0x0, adjust it to288// be at least 1x1 to avoid IAE289final int w = Math.max(1, r.width);290final int h = Math.max(1, r.height);291final int transparency = peer.isTranslucent() ? Transparency.TRANSLUCENT292: Transparency.OPAQUE;293return new SunVolatileImage(this, w, h, transparency, null);294}295296@Override297public void destroyBackBuffer(final Image backBuffer) {298if (backBuffer != null) {299backBuffer.flush();300}301}302303@Override304public void flip(final LWComponentPeer<?, ?> peer, final Image backBuffer,305final int x1, final int y1, final int x2, final int y2,306final BufferCapabilities.FlipContents flipAction) {307final Graphics g = peer.getGraphics();308try {309g.drawImage(backBuffer, x1, y1, x2, y2, x1, y1, x2, y2, null);310} finally {311g.dispose();312}313if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) {314final Graphics2D bg = (Graphics2D) backBuffer.getGraphics();315try {316bg.setBackground(peer.getBackground());317bg.clearRect(0, 0, backBuffer.getWidth(null),318backBuffer.getHeight(null));319} finally {320bg.dispose();321}322}323}324325private static class MTLBufferCaps extends BufferCapabilities {326public MTLBufferCaps(boolean dblBuf) {327super(imageCaps, imageCaps,328dblBuf ? FlipContents.UNDEFINED : null);329}330}331332@Override333public BufferCapabilities getBufferCapabilities() {334if (bufferCaps == null) {335bufferCaps = new MTLBufferCaps(isDoubleBuffered());336}337return bufferCaps;338}339340private static class MTLImageCaps extends ImageCapabilities {341private MTLImageCaps() {342super(true);343}344public boolean isTrueVolatile() {345return true;346}347}348349@Override350public ImageCapabilities getImageCapabilities() {351return imageCaps;352}353354@Override355public VolatileImage createCompatibleVolatileImage(int width, int height,356int transparency,357int type) {358if ((type != RT_TEXTURE && type != TEXTURE) ||359transparency == Transparency.BITMASK) {360return null;361}362363SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,364transparency, type);365Surface sd = vi.getDestSurface();366if (!(sd instanceof AccelSurface) ||367((AccelSurface)sd).getType() != type)368{369vi.flush();370vi = null;371}372373return vi;374}375376/**377* {@inheritDoc}378*379* @see sun.java2d.pipe.hw.AccelGraphicsConfig#getContextCapabilities380*/381@Override382public ContextCapabilities getContextCapabilities() {383return mtlCaps;384}385386@Override387public int getMaxTextureWidth() {388return Math.max(maxTextureSize / getDevice().getScaleFactor(),389getBounds().width);390}391392@Override393public int getMaxTextureHeight() {394return Math.max(maxTextureSize / getDevice().getScaleFactor(),395getBounds().height);396}397}398399400