changeset 56022:c932937c547f

8229915: Migrate the metal changes from sandbox to lanai repository Reviewed-by: aghaisas Contributed-by: alexey.ushakov@jetbrains.com, ajit.ghaisas@oracle.com, jayathirth.d.v@oracle.com
author jdv
date Thu, 22 Aug 2019 17:57:55 +0530
parents f0c73a5683e7
children d62427fd1866
files make/lib/Awt2dLibraries.gmk src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java src/java.desktop/macosx/classes/sun/java2d/macos/MacOSFlags.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLBlitLoops.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLBufImgOps.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLContext.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLDrawImage.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLLayer.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLMaskBlit.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLMaskFill.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLPaints.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderQueue.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderer.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceDataProxy.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLTextRenderer.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLUtilities.java src/java.desktop/macosx/classes/sun/java2d/metal/MTLVolatileSurfaceManager.java src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java src/java.desktop/macosx/native/libawt_lwawt/awt/AWTSurfaceLayers.m src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m src/java.desktop/macosx/native/libawt_lwawt/awt/common.h src/java.desktop/macosx/native/libawt_lwawt/awt/shaders.metal src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBufImgOps.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBufImgOps.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLContext.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLContext.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLFuncs.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLFuncs.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGraphicsConfig.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGraphicsConfig.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLMaskBlit.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLMaskBlit.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLMaskFill.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLMaskFill.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderer.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderer.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLSurfaceData.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLSurfaceData.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLSurfaceDataBase.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTextRenderer.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTextRenderer.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTexturePool.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTexurePool.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLUtils.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLUtils.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m src/java.desktop/share/classes/javax/swing/RepaintManager.java src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java src/java.desktop/share/native/libawt/java2d/SurfaceData.c
diffstat 70 files changed, 11952 insertions(+), 154 deletions(-) [+]
line wrap: on
line diff
--- a/make/lib/Awt2dLibraries.gmk	Mon Aug 19 19:58:50 2019 +0200
+++ b/make/lib/Awt2dLibraries.gmk	Thu Aug 22 17:57:55 2019 +0530
@@ -246,6 +246,7 @@
     LIBS_macosx := -lmlib_image \
         -framework Cocoa \
         -framework OpenGL \
+        -framework Metal \
         -framework JavaNativeFoundation \
         -framework JavaRuntimeSupport \
         -framework ApplicationServices \
@@ -821,6 +822,7 @@
         -framework Foundation \
         -framework Security \
         -framework Cocoa \
+        -framework Metal \
         -framework JavaNativeFoundation
   else ifeq ($(call isTargetOs, windows), true)
     LIBSPLASHSCREEN_LIBS += kernel32.lib user32.lib gdi32.lib delayimp.lib $(WIN_JAVA_LIB) jvm.lib
@@ -883,6 +885,7 @@
       libawt_lwawt/awt \
       libawt_lwawt/font \
       libawt_lwawt/java2d/opengl \
+      libawt_lwawt/java2d/metal \
       include \
       common/awt/debug \
       common/java2d/opengl \
@@ -918,6 +921,7 @@
           -framework AudioToolbox \
           -framework Carbon \
           -framework Cocoa \
+          -framework Metal \
           -framework Security \
           -framework ExceptionHandling \
           -framework JavaNativeFoundation \
@@ -941,6 +945,11 @@
 ################################################################################
 
 ifeq ($(call isTargetOs, macosx), true)
+  XCODE_PATH := $(shell /usr/bin/xcode-select -p)
+  CompileMetalShaders :
+  $(XCODE_PATH)/Platforms/MacOSX.platform/usr/bin/metal -O2 -std=osx-metal1.1 -o $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxui/shaders.air $(TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/awt/shaders.metal \
+  $(XCODE_PATH)/Platforms/MacOSX.platform/usr/bin/metal-ar r $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxui/shaders.metal-ar $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxui/shaders.air \
+  $(XCODE_PATH)/Platforms/MacOSX.platform/usr/bin/metallib -o $(INSTALL_LIBRARIES_HERE)/shaders.metallib $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxui/shaders.metal-ar \
 
   $(eval $(call SetupJdkLibrary, BUILD_LIBOSXUI, \
       NAME := osxui, \
@@ -956,6 +965,7 @@
           -L$(INSTALL_LIBRARIES_HERE), \
       LIBS := -lawt -losxapp -lawt_lwawt \
           -framework Cocoa \
+          -framework Metal \
           -framework Carbon \
           -framework ApplicationServices \
           -framework JavaNativeFoundation \
@@ -964,6 +974,7 @@
   ))
 
   TARGETS += $(BUILD_LIBOSXUI)
+  $(BUILD_LIBOSXUI): CompileMetalShaders
 
   $(BUILD_LIBOSXUI): $(BUILD_LIBAWT)
 
--- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java	Thu Aug 22 17:57:55 2019 +0530
@@ -34,6 +34,7 @@
 import sun.java2d.SurfaceData;
 import sun.java2d.opengl.CGLLayer;
 import sun.lwawt.LWGraphicsConfig;
+import sun.lwawt.macosx.CFRetainedResource;
 import sun.lwawt.macosx.CPlatformView;
 
 public abstract class CGraphicsConfig extends GraphicsConfiguration
@@ -87,7 +88,7 @@
      * Creates a new SurfaceData that will be associated with the given
      * CGLLayer.
      */
-    public abstract SurfaceData createSurfaceData(CGLLayer layer);
+    public abstract SurfaceData createSurfaceData(CFRetainedResource layer);
 
     @Override
     public final boolean isTranslucencyCapable() {
--- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java	Thu Aug 22 17:57:55 2019 +0530
@@ -36,6 +36,8 @@
 import java.util.Objects;
 
 import sun.java2d.SunGraphicsEnvironment;
+import sun.java2d.macos.MacOSFlags;
+import sun.java2d.metal.MTLGraphicsConfig;
 import sun.java2d.opengl.CGLGraphicsConfig;
 
 public final class CGraphicsDevice extends GraphicsDevice
@@ -60,7 +62,9 @@
 
     public CGraphicsDevice(final int displayID) {
         this.displayID = displayID;
-        config = CGLGraphicsConfig.getConfig(this, displayID, 0);
+        config = MacOSFlags.isMetalEnabled() ?
+                MTLGraphicsConfig.getConfig(this, displayID, 0) :
+                CGLGraphicsConfig.getConfig(this, displayID, 0);
     }
 
     /**
--- a/src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java	Thu Aug 22 17:57:55 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -27,6 +27,8 @@
 
 import sun.awt.image.SunVolatileImage;
 import sun.awt.image.VolatileSurfaceManager;
+import sun.java2d.macos.MacOSFlags;
+import sun.java2d.metal.MTLVolatileSurfaceManager;
 import sun.java2d.opengl.CGLVolatileSurfaceManager;
 
 /**
@@ -49,6 +51,7 @@
     public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
                                                         Object context)
     {
-        return new CGLVolatileSurfaceManager(vImg, context);
+        return MacOSFlags.isMetalEnabled() ? new MTLVolatileSurfaceManager(vImg, context) :
+                new CGLVolatileSurfaceManager(vImg, context);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/macos/MacOSFlags.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.macos;
+
+import java.security.PrivilegedAction;
+
+public class MacOSFlags {
+
+    /**
+     * Description of command-line flags.  All flags with [true|false]
+     * values
+     *      metalEnabled: usage: "-Dsun.java2d.metal=[true|false]"
+     */
+
+    private static boolean metalEnabled;
+
+    static {
+        initJavaFlags();
+        initNativeFlags();
+    }
+
+    private static native boolean initNativeFlags();
+
+    private static boolean getBooleanProp(String p, boolean defaultVal) {
+        String propString = System.getProperty(p);
+        boolean 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;
+            } else if (propString.equals("false") ||
+                       propString.equals("f") ||
+                       propString.equals("False") ||
+                       propString.equals("F"))
+            {
+                returnVal = false;
+            }
+        }
+        return returnVal;
+    }
+
+
+    private static boolean getPropertySet(String p) {
+        String propString = System.getProperty(p);
+        return (propString != null) ? true : false;
+    }
+
+    private static void initJavaFlags() {
+        java.security.AccessController.doPrivileged(
+                (PrivilegedAction<Object>) () -> {
+                    metalEnabled = getBooleanProp("sun.java2d.metal", false);
+                    return null;
+                });
+    }
+
+    public static boolean isMetalEnabled() {
+        return metalEnabled;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLBlitLoops.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,945 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.java2d.SurfaceData;
+import sun.java2d.loops.*;
+import sun.java2d.pipe.Region;
+import sun.java2d.pipe.RenderBuffer;
+import sun.java2d.pipe.RenderQueue;
+import sun.java2d.pipe.hw.AccelSurface;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.lang.annotation.Native;
+import java.lang.ref.WeakReference;
+
+import static sun.java2d.pipe.BufferedOpCodes.BLIT;
+import static sun.java2d.pipe.BufferedOpCodes.SURFACE_TO_SW_BLIT;
+
+final class MTLBlitLoops {
+
+    static void register() {
+        Blit blitIntArgbPreToSurface =
+                new MTLSwToSurfaceBlit(SurfaceType.IntArgbPre,
+                        MTLSurfaceData.PF_INT_ARGB_PRE);
+        Blit blitIntArgbPreToTexture =
+                new MTLSwToTextureBlit(SurfaceType.IntArgbPre,
+                        MTLSurfaceData.PF_INT_ARGB_PRE);
+        TransformBlit transformBlitIntArgbPreToSurface =
+                new MTLSwToSurfaceTransform(SurfaceType.IntArgbPre,
+                        MTLSurfaceData.PF_INT_ARGB_PRE);
+        MTLSurfaceToSwBlit blitSurfaceToIntArgbPre =
+                new MTLSurfaceToSwBlit(SurfaceType.IntArgbPre,
+                        MTLSurfaceData.PF_INT_ARGB_PRE);
+
+        GraphicsPrimitive[] primitives = {
+                // surface->surface ops
+                new MTLSurfaceToSurfaceBlit(),
+                new MTLSurfaceToSurfaceScale(),
+                new MTLSurfaceToSurfaceTransform(),
+
+                // render-to-texture surface->surface ops
+                new MTLRTTSurfaceToSurfaceBlit(),
+                new MTLRTTSurfaceToSurfaceScale(),
+                new MTLRTTSurfaceToSurfaceTransform(),
+
+                // surface->sw ops
+                new MTLSurfaceToSwBlit(SurfaceType.IntArgb,
+                        MTLSurfaceData.PF_INT_ARGB),
+                blitSurfaceToIntArgbPre,
+
+                // sw->surface ops
+                blitIntArgbPreToSurface,
+                new MTLSwToSurfaceBlit(SurfaceType.IntRgb,
+                        MTLSurfaceData.PF_INT_RGB),
+                new MTLSwToSurfaceBlit(SurfaceType.IntRgbx,
+                        MTLSurfaceData.PF_INT_RGBX),
+                new MTLSwToSurfaceBlit(SurfaceType.IntBgr,
+                        MTLSurfaceData.PF_INT_BGR),
+                new MTLSwToSurfaceBlit(SurfaceType.IntBgrx,
+                        MTLSurfaceData.PF_INT_BGRX),
+                new MTLSwToSurfaceBlit(SurfaceType.ThreeByteBgr,
+                        MTLSurfaceData.PF_3BYTE_BGR),
+                new MTLSwToSurfaceBlit(SurfaceType.Ushort565Rgb,
+                        MTLSurfaceData.PF_USHORT_565_RGB),
+                new MTLSwToSurfaceBlit(SurfaceType.Ushort555Rgb,
+                        MTLSurfaceData.PF_USHORT_555_RGB),
+                new MTLSwToSurfaceBlit(SurfaceType.Ushort555Rgbx,
+                        MTLSurfaceData.PF_USHORT_555_RGBX),
+                new MTLSwToSurfaceBlit(SurfaceType.ByteGray,
+                        MTLSurfaceData.PF_BYTE_GRAY),
+                new MTLSwToSurfaceBlit(SurfaceType.UshortGray,
+                        MTLSurfaceData.PF_USHORT_GRAY),
+                new MTLGeneralBlit(MTLSurfaceData.MTLSurface,
+                        CompositeType.AnyAlpha,
+                        blitIntArgbPreToSurface),
+
+                new MTLAnyCompositeBlit(MTLSurfaceData.MTLSurface,
+                        blitSurfaceToIntArgbPre,
+                        blitSurfaceToIntArgbPre,
+                        blitIntArgbPreToSurface),
+                new MTLAnyCompositeBlit(SurfaceType.Any,
+                        null,
+                        blitSurfaceToIntArgbPre,
+                        blitIntArgbPreToSurface),
+
+                new MTLSwToSurfaceScale(SurfaceType.IntRgb,
+                        MTLSurfaceData.PF_INT_RGB),
+                new MTLSwToSurfaceScale(SurfaceType.IntRgbx,
+                        MTLSurfaceData.PF_INT_RGBX),
+                new MTLSwToSurfaceScale(SurfaceType.IntBgr,
+                        MTLSurfaceData.PF_INT_BGR),
+                new MTLSwToSurfaceScale(SurfaceType.IntBgrx,
+                        MTLSurfaceData.PF_INT_BGRX),
+                new MTLSwToSurfaceScale(SurfaceType.ThreeByteBgr,
+                        MTLSurfaceData.PF_3BYTE_BGR),
+                new MTLSwToSurfaceScale(SurfaceType.Ushort565Rgb,
+                        MTLSurfaceData.PF_USHORT_565_RGB),
+                new MTLSwToSurfaceScale(SurfaceType.Ushort555Rgb,
+                        MTLSurfaceData.PF_USHORT_555_RGB),
+                new MTLSwToSurfaceScale(SurfaceType.Ushort555Rgbx,
+                        MTLSurfaceData.PF_USHORT_555_RGBX),
+                new MTLSwToSurfaceScale(SurfaceType.ByteGray,
+                        MTLSurfaceData.PF_BYTE_GRAY),
+                new MTLSwToSurfaceScale(SurfaceType.UshortGray,
+                        MTLSurfaceData.PF_USHORT_GRAY),
+                new MTLSwToSurfaceScale(SurfaceType.IntArgbPre,
+                        MTLSurfaceData.PF_INT_ARGB_PRE),
+
+                new MTLSwToSurfaceTransform(SurfaceType.IntRgb,
+                        MTLSurfaceData.PF_INT_RGB),
+                new MTLSwToSurfaceTransform(SurfaceType.IntRgbx,
+                        MTLSurfaceData.PF_INT_RGBX),
+                new MTLSwToSurfaceTransform(SurfaceType.IntBgr,
+                        MTLSurfaceData.PF_INT_BGR),
+                new MTLSwToSurfaceTransform(SurfaceType.IntBgrx,
+                        MTLSurfaceData.PF_INT_BGRX),
+                new MTLSwToSurfaceTransform(SurfaceType.ThreeByteBgr,
+                        MTLSurfaceData.PF_3BYTE_BGR),
+                new MTLSwToSurfaceTransform(SurfaceType.Ushort565Rgb,
+                        MTLSurfaceData.PF_USHORT_565_RGB),
+                new MTLSwToSurfaceTransform(SurfaceType.Ushort555Rgb,
+                        MTLSurfaceData.PF_USHORT_555_RGB),
+                new MTLSwToSurfaceTransform(SurfaceType.Ushort555Rgbx,
+                        MTLSurfaceData.PF_USHORT_555_RGBX),
+                new MTLSwToSurfaceTransform(SurfaceType.ByteGray,
+                        MTLSurfaceData.PF_BYTE_GRAY),
+                new MTLSwToSurfaceTransform(SurfaceType.UshortGray,
+                        MTLSurfaceData.PF_USHORT_GRAY),
+                transformBlitIntArgbPreToSurface,
+
+                new MTLGeneralTransformedBlit(transformBlitIntArgbPreToSurface),
+
+                // texture->surface ops
+                new MTLTextureToSurfaceBlit(),
+                new MTLTextureToSurfaceScale(),
+                new MTLTextureToSurfaceTransform(),
+
+                // sw->texture ops
+                blitIntArgbPreToTexture,
+                new MTLSwToTextureBlit(SurfaceType.IntRgb,
+                        MTLSurfaceData.PF_INT_RGB),
+                new MTLSwToTextureBlit(SurfaceType.IntRgbx,
+                        MTLSurfaceData.PF_INT_RGBX),
+                new MTLSwToTextureBlit(SurfaceType.IntBgr,
+                        MTLSurfaceData.PF_INT_BGR),
+                new MTLSwToTextureBlit(SurfaceType.IntBgrx,
+                        MTLSurfaceData.PF_INT_BGRX),
+                new MTLSwToTextureBlit(SurfaceType.ThreeByteBgr,
+                        MTLSurfaceData.PF_3BYTE_BGR),
+                new MTLSwToTextureBlit(SurfaceType.Ushort565Rgb,
+                        MTLSurfaceData.PF_USHORT_565_RGB),
+                new MTLSwToTextureBlit(SurfaceType.Ushort555Rgb,
+                        MTLSurfaceData.PF_USHORT_555_RGB),
+                new MTLSwToTextureBlit(SurfaceType.Ushort555Rgbx,
+                        MTLSurfaceData.PF_USHORT_555_RGBX),
+                new MTLSwToTextureBlit(SurfaceType.ByteGray,
+                        MTLSurfaceData.PF_BYTE_GRAY),
+                new MTLSwToTextureBlit(SurfaceType.UshortGray,
+                        MTLSurfaceData.PF_USHORT_GRAY),
+                new MTLGeneralBlit(MTLSurfaceData.MTLTexture,
+                        CompositeType.SrcNoEa,
+                        blitIntArgbPreToTexture),
+        };
+        GraphicsPrimitiveMgr.register(primitives);
+    }
+
+    /**
+     * The following offsets are used to pack the parameters in
+     * createPackedParams().  (They are also used at the native level when
+     * unpacking the params.)
+     */
+    @Native private static final int OFFSET_SRCTYPE = 16;
+    @Native private static final int OFFSET_HINT    =  8;
+    @Native private static final int OFFSET_TEXTURE =  3;
+    @Native private static final int OFFSET_RTT     =  2;
+    @Native private static final int OFFSET_XFORM   =  1;
+    @Native private static final int OFFSET_ISOBLIT =  0;
+
+    /**
+     * Packs the given parameters into a single int value in order to save
+     * space on the rendering queue.
+     */
+    private static int createPackedParams(boolean isoblit, boolean texture,
+                                          boolean rtt, boolean xform,
+                                          int hint, int srctype)
+    {
+        return
+                ((srctype           << OFFSET_SRCTYPE) |
+                        (hint              << OFFSET_HINT   ) |
+                        ((texture ? 1 : 0) << OFFSET_TEXTURE) |
+                        ((rtt     ? 1 : 0) << OFFSET_RTT    ) |
+                        ((xform   ? 1 : 0) << OFFSET_XFORM  ) |
+                        ((isoblit ? 1 : 0) << OFFSET_ISOBLIT));
+    }
+
+    /**
+     * Enqueues a BLIT operation with the given parameters.  Note that the
+     * RenderQueue lock must be held before calling this method.
+     */
+    private static void enqueueBlit(RenderQueue rq,
+                                    SurfaceData src, SurfaceData dst,
+                                    int packedParams,
+                                    int sx1, int sy1,
+                                    int sx2, int sy2,
+                                    double dx1, double dy1,
+                                    double dx2, double dy2)
+    {
+        // assert rq.lock.isHeldByCurrentThread();
+        RenderBuffer buf = rq.getBuffer();
+        rq.ensureCapacityAndAlignment(72, 24);
+        buf.putInt(BLIT);
+        buf.putInt(packedParams);
+        buf.putInt(sx1).putInt(sy1);
+        buf.putInt(sx2).putInt(sy2);
+        buf.putDouble(dx1).putDouble(dy1);
+        buf.putDouble(dx2).putDouble(dy2);
+        buf.putLong(src.getNativeOps());
+        buf.putLong(dst.getNativeOps());
+    }
+
+    static void Blit(SurfaceData srcData, SurfaceData dstData,
+                     Composite comp, Region clip,
+                     AffineTransform xform, int hint,
+                     int sx1, int sy1,
+                     int sx2, int sy2,
+                     double dx1, double dy1,
+                     double dx2, double dy2,
+                     int srctype, boolean texture)
+    {
+        int ctxflags = 0;
+        if (srcData.getTransparency() == Transparency.OPAQUE) {
+            ctxflags |= MTLContext.SRC_IS_OPAQUE;
+        }
+
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            // make sure the RenderQueue keeps a hard reference to the
+            // source (sysmem) SurfaceData to prevent it from being
+            // disposed while the operation is processed on the QFT
+            rq.addReference(srcData);
+
+            MTLSurfaceData oglDst = (MTLSurfaceData)dstData;
+            if (texture) {
+                // make sure we have a current context before uploading
+                // the sysmem data to the texture object
+                MTLGraphicsConfig gc = oglDst.getMTLGraphicsConfig();
+                MTLContext.setScratchSurface(gc);
+            } else {
+                MTLContext.validateContext(oglDst, oglDst,
+                        clip, comp, xform, null, null,
+                        ctxflags);
+            }
+
+            int packedParams = createPackedParams(false, texture,
+                    false, xform != null,
+                    hint, srctype);
+            enqueueBlit(rq, srcData, dstData,
+                    packedParams,
+                    sx1, sy1, sx2, sy2,
+                    dx1, dy1, dx2, dy2);
+
+            // always flush immediately, since we (currently) have no means
+            // of tracking changes to the system memory surface
+            rq.flushNow();
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    /**
+     * Note: The srcImg and biop parameters are only used when invoked
+     * from the MTLBufImgOps.renderImageWithOp() method; in all other cases,
+     * this method can be called with null values for those two parameters,
+     * and they will be effectively ignored.
+     */
+    static void IsoBlit(SurfaceData srcData, SurfaceData dstData,
+                        BufferedImage srcImg, BufferedImageOp biop,
+                        Composite comp, Region clip,
+                        AffineTransform xform, int hint,
+                        int sx1, int sy1,
+                        int sx2, int sy2,
+                        double dx1, double dy1,
+                        double dx2, double dy2,
+                        boolean texture)
+    {
+        int ctxflags = 0;
+        if (srcData.getTransparency() == Transparency.OPAQUE) {
+            ctxflags |= MTLContext.SRC_IS_OPAQUE;
+        }
+
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            MTLSurfaceData oglSrc = (MTLSurfaceData)srcData;
+            MTLSurfaceData oglDst = (MTLSurfaceData)dstData;
+            int srctype = oglSrc.getType();
+            boolean rtt;
+            MTLSurfaceData srcCtxData;
+            if (srctype == MTLSurfaceData.TEXTURE) {
+                // the source is a regular texture object; we substitute
+                // the destination surface for the purposes of making a
+                // context current
+                rtt = false;
+                srcCtxData = oglDst;
+            } else {
+                // the source is a pbuffer, backbuffer, or render-to-texture
+                // surface; we set rtt to true to differentiate this kind
+                // of surface from a regular texture object
+                rtt = true;
+                if (srctype == AccelSurface.RT_TEXTURE) {
+                    srcCtxData = oglDst;
+                } else {
+                    srcCtxData = oglSrc;
+                }
+            }
+
+            MTLContext.validateContext(srcCtxData, oglDst,
+                    clip, comp, xform, null, null,
+                    ctxflags);
+
+            if (biop != null) {
+                MTLBufImgOps.enableBufImgOp(rq, oglSrc, srcImg, biop);
+            }
+
+            int packedParams = createPackedParams(true, texture,
+                    rtt, xform != null,
+                    hint, 0 /*unused*/);
+            enqueueBlit(rq, srcData, dstData,
+                    packedParams,
+                    sx1, sy1, sx2, sy2,
+                    dx1, dy1, dx2, dy2);
+
+            if (biop != null) {
+                MTLBufImgOps.disableBufImgOp(rq, biop);
+            }
+
+            if (rtt && oglDst.isOnScreen()) {
+                // we only have to flush immediately when copying from a
+                // (non-texture) surface to the screen; otherwise Swing apps
+                // might appear unresponsive until the auto-flush completes
+                rq.flushNow();
+            }
+        } finally {
+            rq.unlock();
+        }
+    }
+}
+
+class MTLSurfaceToSurfaceBlit extends Blit {
+
+    MTLSurfaceToSurfaceBlit() {
+        super(MTLSurfaceData.MTLSurface,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Blit(SurfaceData src, SurfaceData dst,
+                     Composite comp, Region clip,
+                     int sx, int sy, int dx, int dy, int w, int h)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                false);
+    }
+}
+
+class MTLSurfaceToSurfaceScale extends ScaledBlit {
+
+    MTLSurfaceToSurfaceScale() {
+        super(MTLSurfaceData.MTLSurface,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Scale(SurfaceData src, SurfaceData dst,
+                      Composite comp, Region clip,
+                      int sx1, int sy1,
+                      int sx2, int sy2,
+                      double dx1, double dy1,
+                      double dx2, double dy2)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx1, sy1, sx2, sy2,
+                dx1, dy1, dx2, dy2,
+                false);
+    }
+}
+
+class MTLSurfaceToSurfaceTransform extends TransformBlit {
+
+    MTLSurfaceToSurfaceTransform() {
+        super(MTLSurfaceData.MTLSurface,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Transform(SurfaceData src, SurfaceData dst,
+                          Composite comp, Region clip,
+                          AffineTransform at, int hint,
+                          int sx, int sy, int dx, int dy,
+                          int w, int h)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, at, hint,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                false);
+    }
+}
+
+class MTLRTTSurfaceToSurfaceBlit extends Blit {
+
+    MTLRTTSurfaceToSurfaceBlit() {
+        super(MTLSurfaceData.MTLSurfaceRTT,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Blit(SurfaceData src, SurfaceData dst,
+                     Composite comp, Region clip,
+                     int sx, int sy, int dx, int dy, int w, int h)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                true);
+    }
+}
+
+class MTLRTTSurfaceToSurfaceScale extends ScaledBlit {
+
+    MTLRTTSurfaceToSurfaceScale() {
+        super(MTLSurfaceData.MTLSurfaceRTT,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Scale(SurfaceData src, SurfaceData dst,
+                      Composite comp, Region clip,
+                      int sx1, int sy1,
+                      int sx2, int sy2,
+                      double dx1, double dy1,
+                      double dx2, double dy2)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx1, sy1, sx2, sy2,
+                dx1, dy1, dx2, dy2,
+                true);
+    }
+}
+
+class MTLRTTSurfaceToSurfaceTransform extends TransformBlit {
+
+    MTLRTTSurfaceToSurfaceTransform() {
+        super(MTLSurfaceData.MTLSurfaceRTT,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Transform(SurfaceData src, SurfaceData dst,
+                          Composite comp, Region clip,
+                          AffineTransform at, int hint,
+                          int sx, int sy, int dx, int dy, int w, int h)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, at, hint,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                true);
+    }
+}
+
+final class MTLSurfaceToSwBlit extends Blit {
+
+    private final int typeval;
+    private WeakReference<SurfaceData> srcTmp;
+
+    // destination will actually be ArgbPre or Argb
+    MTLSurfaceToSwBlit(final SurfaceType dstType, final int typeval) {
+        super(MTLSurfaceData.MTLSurface,
+                CompositeType.SrcNoEa,
+                dstType);
+        this.typeval = typeval;
+    }
+
+    private synchronized void complexClipBlit(SurfaceData src, SurfaceData dst,
+                                              Composite comp, Region clip,
+                                              int sx, int sy, int dx, int dy,
+                                              int w, int h) {
+        SurfaceData cachedSrc = null;
+        if (srcTmp != null) {
+            // use cached intermediate surface, if available
+            cachedSrc = srcTmp.get();
+        }
+
+        // We can convert argb_pre data from MTL surface in two places:
+        // - During MTL surface -> SW blit
+        // - During SW -> SW blit
+        // The first one is faster when we use opaque MTL surface, because in
+        // this case we simply skip conversion and use color components as is.
+        // Because of this we align intermediate buffer type with type of
+        // destination not source.
+        final int type = typeval == MTLSurfaceData.PF_INT_ARGB_PRE ?
+                BufferedImage.TYPE_INT_ARGB_PRE :
+                BufferedImage.TYPE_INT_ARGB;
+
+        src = convertFrom(this, src, sx, sy, w, h, cachedSrc, type);
+
+        // copy intermediate SW to destination SW using complex clip
+        final Blit performop = Blit.getFromCache(src.getSurfaceType(),
+                CompositeType.SrcNoEa,
+                dst.getSurfaceType());
+        performop.Blit(src, dst, comp, clip, 0, 0, dx, dy, w, h);
+
+        if (src != cachedSrc) {
+            // cache the intermediate surface
+            srcTmp = new WeakReference<>(src);
+        }
+    }
+
+    public void Blit(SurfaceData src, SurfaceData dst,
+                     Composite comp, Region clip,
+                     int sx, int sy, int dx, int dy,
+                     int w, int h)
+    {
+        if (clip != null) {
+            clip = clip.getIntersectionXYWH(dx, dy, w, h);
+            // At the end this method will flush the RenderQueue, we should exit
+            // from it as soon as possible.
+            if (clip.isEmpty()) {
+                return;
+            }
+            sx += clip.getLoX() - dx;
+            sy += clip.getLoY() - dy;
+            dx = clip.getLoX();
+            dy = clip.getLoY();
+            w = clip.getWidth();
+            h = clip.getHeight();
+
+            if (!clip.isRectangular()) {
+                complexClipBlit(src, dst, comp, clip, sx, sy, dx, dy, w, h);
+                return;
+            }
+        }
+
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            // make sure the RenderQueue keeps a hard reference to the
+            // destination (sysmem) SurfaceData to prevent it from being
+            // disposed while the operation is processed on the QFT
+            rq.addReference(dst);
+
+            RenderBuffer buf = rq.getBuffer();
+            MTLContext.validateContext((MTLSurfaceData)src);
+
+            rq.ensureCapacityAndAlignment(48, 32);
+            buf.putInt(SURFACE_TO_SW_BLIT);
+            buf.putInt(sx).putInt(sy);
+            buf.putInt(dx).putInt(dy);
+            buf.putInt(w).putInt(h);
+            buf.putInt(typeval);
+            buf.putLong(src.getNativeOps());
+            buf.putLong(dst.getNativeOps());
+
+            // always flush immediately
+            rq.flushNow();
+        } finally {
+            rq.unlock();
+        }
+    }
+}
+
+class MTLSwToSurfaceBlit extends Blit {
+
+    private int typeval;
+
+    MTLSwToSurfaceBlit(SurfaceType srcType, int typeval) {
+        super(srcType,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+        this.typeval = typeval;
+    }
+
+    public void Blit(SurfaceData src, SurfaceData dst,
+                     Composite comp, Region clip,
+                     int sx, int sy, int dx, int dy, int w, int h)
+    {
+        MTLBlitLoops.Blit(src, dst,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                typeval, false);
+    }
+}
+
+class MTLSwToSurfaceScale extends ScaledBlit {
+
+    private int typeval;
+
+    MTLSwToSurfaceScale(SurfaceType srcType, int typeval) {
+        super(srcType,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+        this.typeval = typeval;
+    }
+
+    public void Scale(SurfaceData src, SurfaceData dst,
+                      Composite comp, Region clip,
+                      int sx1, int sy1,
+                      int sx2, int sy2,
+                      double dx1, double dy1,
+                      double dx2, double dy2)
+    {
+        MTLBlitLoops.Blit(src, dst,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx1, sy1, sx2, sy2,
+                dx1, dy1, dx2, dy2,
+                typeval, false);
+    }
+}
+
+class MTLSwToSurfaceTransform extends TransformBlit {
+
+    private int typeval;
+
+    MTLSwToSurfaceTransform(SurfaceType srcType, int typeval) {
+        super(srcType,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+        this.typeval = typeval;
+    }
+
+    public void Transform(SurfaceData src, SurfaceData dst,
+                          Composite comp, Region clip,
+                          AffineTransform at, int hint,
+                          int sx, int sy, int dx, int dy, int w, int h)
+    {
+        MTLBlitLoops.Blit(src, dst,
+                comp, clip, at, hint,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                typeval, false);
+    }
+}
+
+class MTLSwToTextureBlit extends Blit {
+
+    private int typeval;
+
+    MTLSwToTextureBlit(SurfaceType srcType, int typeval) {
+        super(srcType,
+                CompositeType.SrcNoEa,
+                MTLSurfaceData.MTLTexture);
+        this.typeval = typeval;
+    }
+
+    public void Blit(SurfaceData src, SurfaceData dst,
+                     Composite comp, Region clip,
+                     int sx, int sy, int dx, int dy, int w, int h)
+    {
+        MTLBlitLoops.Blit(src, dst,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                typeval, true);
+    }
+}
+
+class MTLTextureToSurfaceBlit extends Blit {
+
+    MTLTextureToSurfaceBlit() {
+        super(MTLSurfaceData.MTLTexture,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Blit(SurfaceData src, SurfaceData dst,
+                     Composite comp, Region clip,
+                     int sx, int sy, int dx, int dy, int w, int h)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                true);
+    }
+}
+
+class MTLTextureToSurfaceScale extends ScaledBlit {
+
+    MTLTextureToSurfaceScale() {
+        super(MTLSurfaceData.MTLTexture,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Scale(SurfaceData src, SurfaceData dst,
+                      Composite comp, Region clip,
+                      int sx1, int sy1,
+                      int sx2, int sy2,
+                      double dx1, double dy1,
+                      double dx2, double dy2)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, null,
+                AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
+                sx1, sy1, sx2, sy2,
+                dx1, dy1, dx2, dy2,
+                true);
+    }
+}
+
+class MTLTextureToSurfaceTransform extends TransformBlit {
+
+    MTLTextureToSurfaceTransform() {
+        super(MTLSurfaceData.MTLTexture,
+                CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+    }
+
+    public void Transform(SurfaceData src, SurfaceData dst,
+                          Composite comp, Region clip,
+                          AffineTransform at, int hint,
+                          int sx, int sy, int dx, int dy,
+                          int w, int h)
+    {
+        MTLBlitLoops.IsoBlit(src, dst,
+                null, null,
+                comp, clip, at, hint,
+                sx, sy, sx+w, sy+h,
+                dx, dy, dx+w, dy+h,
+                true);
+    }
+}
+
+/**
+ * This general Blit implementation converts any source surface to an
+ * intermediate IntArgbPre surface, and then uses the more specific
+ * IntArgbPre->MTLSurface/Texture loop to get the intermediate
+ * (premultiplied) surface down to OpenGL using simple blit.
+ */
+class MTLGeneralBlit extends Blit {
+
+    private final Blit performop;
+    private WeakReference<SurfaceData> srcTmp;
+
+    MTLGeneralBlit(SurfaceType dstType,
+                   CompositeType compType,
+                   Blit performop)
+    {
+        super(SurfaceType.Any, compType, dstType);
+        this.performop = performop;
+    }
+
+    public synchronized void Blit(SurfaceData src, SurfaceData dst,
+                                  Composite comp, Region clip,
+                                  int sx, int sy, int dx, int dy,
+                                  int w, int h)
+    {
+        Blit convertsrc = Blit.getFromCache(src.getSurfaceType(),
+                CompositeType.SrcNoEa,
+                SurfaceType.IntArgbPre);
+
+        SurfaceData cachedSrc = null;
+        if (srcTmp != null) {
+            // use cached intermediate surface, if available
+            cachedSrc = srcTmp.get();
+        }
+
+        // convert source to IntArgbPre
+        src = convertFrom(convertsrc, src, sx, sy, w, h,
+                cachedSrc, BufferedImage.TYPE_INT_ARGB_PRE);
+
+        // copy IntArgbPre intermediate surface to OpenGL surface
+        performop.Blit(src, dst, comp, clip,
+                0, 0, dx, dy, w, h);
+
+        if (src != cachedSrc) {
+            // cache the intermediate surface
+            srcTmp = new WeakReference<>(src);
+        }
+    }
+}
+
+/**
+ * This general TransformedBlit implementation converts any source surface to an
+ * intermediate IntArgbPre surface, and then uses the more specific
+ * IntArgbPre->MTLSurface/Texture loop to get the intermediate
+ * (premultiplied) surface down to OpenGL using simple transformBlit.
+ */
+final class MTLGeneralTransformedBlit extends TransformBlit {
+
+    private final TransformBlit performop;
+    private WeakReference<SurfaceData> srcTmp;
+
+    MTLGeneralTransformedBlit(final TransformBlit performop) {
+        super(SurfaceType.Any, CompositeType.AnyAlpha,
+                MTLSurfaceData.MTLSurface);
+        this.performop = performop;
+    }
+
+    @Override
+    public synchronized void Transform(SurfaceData src, SurfaceData dst,
+                                       Composite comp, Region clip,
+                                       AffineTransform at, int hint, int srcx,
+                                       int srcy, int dstx, int dsty, int width,
+                                       int height){
+        Blit convertsrc = Blit.getFromCache(src.getSurfaceType(),
+                CompositeType.SrcNoEa,
+                SurfaceType.IntArgbPre);
+        // use cached intermediate surface, if available
+        final SurfaceData cachedSrc = srcTmp != null ? srcTmp.get() : null;
+        // convert source to IntArgbPre
+        src = convertFrom(convertsrc, src, srcx, srcy, width, height, cachedSrc,
+                BufferedImage.TYPE_INT_ARGB_PRE);
+
+        // transform IntArgbPre intermediate surface to OpenGL surface
+        performop.Transform(src, dst, comp, clip, at, hint, 0, 0, dstx, dsty,
+                width, height);
+
+        if (src != cachedSrc) {
+            // cache the intermediate surface
+            srcTmp = new WeakReference<>(src);
+        }
+    }
+}
+
+/**
+ * This general MTLAnyCompositeBlit implementation can convert any source/target
+ * surface to an intermediate surface using convertsrc/convertdst loops, applies
+ * necessary composite operation, and then uses convertresult loop to get the
+ * intermediate surface down to OpenGL.
+ */
+final class MTLAnyCompositeBlit extends Blit {
+
+    private WeakReference<SurfaceData> dstTmp;
+    private WeakReference<SurfaceData> srcTmp;
+    private final Blit convertsrc;
+    private final Blit convertdst;
+    private final Blit convertresult;
+
+    MTLAnyCompositeBlit(SurfaceType srctype, Blit convertsrc, Blit convertdst,
+                        Blit convertresult) {
+        super(srctype, CompositeType.Any, MTLSurfaceData.MTLSurface);
+        this.convertsrc = convertsrc;
+        this.convertdst = convertdst;
+        this.convertresult = convertresult;
+    }
+
+    public synchronized void Blit(SurfaceData src, SurfaceData dst,
+                                  Composite comp, Region clip,
+                                  int sx, int sy, int dx, int dy,
+                                  int w, int h)
+    {
+        if (convertsrc != null) {
+            SurfaceData cachedSrc = null;
+            if (srcTmp != null) {
+                // use cached intermediate surface, if available
+                cachedSrc = srcTmp.get();
+            }
+            // convert source to IntArgbPre
+            src = convertFrom(convertsrc, src, sx, sy, w, h, cachedSrc,
+                    BufferedImage.TYPE_INT_ARGB_PRE);
+            if (src != cachedSrc) {
+                // cache the intermediate surface
+                srcTmp = new WeakReference<>(src);
+            }
+        }
+
+        SurfaceData cachedDst = null;
+
+        if (dstTmp != null) {
+            // use cached intermediate surface, if available
+            cachedDst = dstTmp.get();
+        }
+
+        // convert destination to IntArgbPre
+        SurfaceData dstBuffer = convertFrom(convertdst, dst, dx, dy, w, h,
+                cachedDst, BufferedImage.TYPE_INT_ARGB_PRE);
+        Region bufferClip =
+                clip == null ? null : clip.getTranslatedRegion(-dx, -dy);
+
+        Blit performop = Blit.getFromCache(src.getSurfaceType(),
+                CompositeType.Any, dstBuffer.getSurfaceType());
+        performop.Blit(src, dstBuffer, comp, bufferClip, sx, sy, 0, 0, w, h);
+
+        if (dstBuffer != cachedDst) {
+            // cache the intermediate surface
+            dstTmp = new WeakReference<>(dstBuffer);
+        }
+        // now blit the buffer back to the destination
+        convertresult.Blit(dstBuffer, dst, AlphaComposite.Src, clip, 0, 0, dx,
+                dy, w, h);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLBufImgOps.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.loops.CompositeType;
+import sun.java2d.pipe.BufferedBufImgOps;
+
+import java.awt.image.*;
+
+import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER;
+
+class MTLBufImgOps extends BufferedBufImgOps {
+
+    /**
+     * This method is called from MTLDrawImage.transformImage() only.  It
+     * validates the provided BufferedImageOp to determine whether the op
+     * is one that can be accelerated by the MTL pipeline.  If the operation
+     * cannot be completed for any reason, this method returns false;
+     * otherwise, the given BufferedImage is rendered to the destination
+     * using the provided BufferedImageOp and this method returns true.
+     */
+    static boolean renderImageWithOp(SunGraphics2D sg, BufferedImage img,
+                                     BufferedImageOp biop, int x, int y)
+    {
+        // Validate the provided BufferedImage (make sure it is one that
+        // is supported, and that its properties are acceleratable)
+        if (biop instanceof ConvolveOp) {
+            if (!isConvolveOpValid((ConvolveOp)biop)) {
+                return false;
+            }
+        } else if (biop instanceof RescaleOp) {
+            if (!isRescaleOpValid((RescaleOp)biop, img)) {
+                return false;
+            }
+        } else if (biop instanceof LookupOp) {
+            if (!isLookupOpValid((LookupOp)biop, img)) {
+                return false;
+            }
+        } else {
+            // No acceleration for other BufferedImageOps (yet)
+            return false;
+        }
+
+        SurfaceData dstData = sg.surfaceData;
+        if (!(dstData instanceof MTLSurfaceData) ||
+                (sg.interpolationType == AffineTransformOp.TYPE_BICUBIC) ||
+                (sg.compositeState > SunGraphics2D.COMP_ALPHA))
+        {
+            return false;
+        }
+
+        SurfaceData srcData =
+                dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
+                        CompositeType.SrcOver, null);
+        if (!(srcData instanceof MTLSurfaceData)) {
+            // REMIND: this hack tries to ensure that we have a cached texture
+            srcData =
+                    dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
+                            CompositeType.SrcOver, null);
+            if (!(srcData instanceof MTLSurfaceData)) {
+                return false;
+            }
+        }
+
+        // Verify that the source surface is actually a texture and
+        // that the operation is supported
+        MTLSurfaceData mtlSrc = (MTLSurfaceData)srcData;
+        MTLGraphicsConfig gc = mtlSrc.getMTLGraphicsConfig();
+        if (mtlSrc.getType() != MTLSurfaceData.TEXTURE ||
+                !gc.isCapPresent(CAPS_EXT_BIOP_SHADER))
+        {
+            return false;
+        }
+
+        int sw = img.getWidth();
+        int sh = img.getHeight();
+        MTLBlitLoops.IsoBlit(srcData, dstData,
+                img, biop,
+                sg.composite, sg.getCompClip(),
+                sg.transform, sg.interpolationType,
+                0, 0, sw, sh,
+                x, y, x+sw, y+sh,
+                true);
+
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLContext.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.java2d.pipe.BufferedContext;
+import sun.java2d.pipe.RenderBuffer;
+import sun.java2d.pipe.RenderQueue;
+import sun.java2d.pipe.hw.ContextCapabilities;
+
+import java.lang.annotation.Native;
+
+import static sun.java2d.pipe.BufferedOpCodes.*;
+
+/**
+ * Note that the RenderQueue lock must be acquired before calling any of
+ * the methods in this class.
+ */
+public class MTLContext extends BufferedContext {
+
+    private final MTLGraphicsConfig config;
+
+    public MTLContext(RenderQueue rq, MTLGraphicsConfig config) {
+        super(rq);
+        this.config = config;
+    }
+
+    /**
+     * Convenience method that delegates to setScratchSurface() below.
+     */
+    static void setScratchSurface(MTLGraphicsConfig gc) {
+        setScratchSurface(gc.getNativeConfigInfo());
+    }
+
+    /**
+     * Makes the given GraphicsConfig's context current to its associated
+     * "scratch surface".  Each GraphicsConfig maintains a native context
+     * (MTLDevice) as well as a native pbuffer
+     * known as the "scratch surface".  By making the context current to the
+     * scratch surface, we are assured that we have a current context for
+     * the relevant GraphicsConfig, and can therefore perform operations
+     * depending on the capabilities of that GraphicsConfig.
+     * This method should be used for operations with an MTL texture
+     * as the destination surface (e.g. a sw->texture blit loop), or in those
+     * situations where we may not otherwise have a current context (e.g.
+     * when disposing a texture-based surface).
+     */
+    public static void setScratchSurface(long pConfigInfo) {
+        // assert MTLRenderQueue.getInstance().lock.isHeldByCurrentThread();
+
+        // invalidate the current context
+        currentContext = null;
+
+        // set the scratch context
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        RenderBuffer buf = rq.getBuffer();
+        rq.ensureCapacityAndAlignment(12, 4);
+        buf.putInt(SET_SCRATCH_SURFACE);
+        buf.putLong(pConfigInfo);
+    }
+
+    /**
+     * Invalidates the currentContext field to ensure that we properly
+     * revalidate the MTLContext (make it current, etc.) next time through
+     * the validate() method.  This is typically invoked from methods
+     * that affect the current context state (e.g. disposing a context or
+     * surface).
+     */
+    public static void invalidateCurrentContext() {
+        // assert MTLRenderQueue.getInstance().lock.isHeldByCurrentThread();
+
+        // invalidate the current Java-level context so that we
+        // revalidate everything the next time around
+        if (currentContext != null) {
+            currentContext.invalidateContext();
+            currentContext = null;
+        }
+
+        // invalidate the context reference at the native level, and
+        // then flush the queue so that we have no pending operations
+        // dependent on the current context
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.ensureCapacity(4);
+        rq.getBuffer().putInt(INVALIDATE_CONTEXT);
+        rq.flushNow();
+    }
+
+    public RenderQueue getRenderQueue() {
+        return MTLRenderQueue.getInstance();
+    }
+
+    /**
+     * Returns a string representing adapter id (vendor, renderer, version).
+     * Must be called on the rendering thread.
+     *
+     * @return an id string for the adapter
+     */
+    public static final native String getMTLIdString();
+
+    @Override
+    public void saveState() {
+        // assert rq.lock.isHeldByCurrentThread();
+
+        // reset all attributes of this and current contexts
+        invalidateContext();
+        invalidateCurrentContext();
+
+        setScratchSurface(config);
+
+        // save the state on the native level
+        rq.ensureCapacity(4);
+        buf.putInt(SAVE_STATE);
+        rq.flushNow();
+    }
+
+    @Override
+    public void restoreState() {
+        // assert rq.lock.isHeldByCurrentThread();
+
+        // reset all attributes of this and current contexts
+        invalidateContext();
+        invalidateCurrentContext();
+
+        setScratchSurface(config);
+
+        // restore the state on the native level
+        rq.ensureCapacity(4);
+        buf.putInt(RESTORE_STATE);
+        rq.flushNow();
+    }
+
+    public static class MTLContextCaps extends ContextCapabilities {
+        /**
+         * This cap will only be set if the fbobject system property has been
+         * enabled and we are able to create an FBO with depth buffer.
+         */
+        @Native
+        public static final int CAPS_EXT_FBOBJECT     =
+                (CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE);
+        /** Indicates that the context is doublebuffered. */
+        @Native
+        public static final int CAPS_DOUBLEBUFFERED   = (FIRST_PRIVATE_CAP << 0);
+        /**
+         * This cap will only be set if the lcdshader system property has been
+         * enabled and the hardware supports the minimum number of texture units
+         */
+        @Native
+        static final int CAPS_EXT_LCD_SHADER   = (FIRST_PRIVATE_CAP << 1);
+        /**
+         * This cap will only be set if the biopshader system property has been
+         * enabled and the hardware meets our minimum requirements.
+         */
+        @Native
+        static final int CAPS_EXT_BIOP_SHADER  = (FIRST_PRIVATE_CAP << 2);
+        /**
+         * This cap will only be set if the gradshader system property has been
+         * enabled and the hardware meets our minimum requirements.
+         */
+        @Native
+        static final int CAPS_EXT_GRAD_SHADER  = (FIRST_PRIVATE_CAP << 3);
+        /** Indicates the presence of the GL_ARB_texture_rectangle extension. */
+        @Native
+        static final int CAPS_EXT_TEXRECT      = (FIRST_PRIVATE_CAP << 4);
+        /** Indicates the presence of the GL_NV_texture_barrier extension. */
+        @Native
+        static final int CAPS_EXT_TEXBARRIER = (FIRST_PRIVATE_CAP << 5);
+
+
+        public MTLContextCaps(int caps, String adapterId) {
+            super(caps, adapterId);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(super.toString());
+            if ((caps & CAPS_EXT_FBOBJECT) != 0) {
+                sb.append("CAPS_EXT_FBOBJECT|");
+            }
+            if ((caps & CAPS_DOUBLEBUFFERED) != 0) {
+                sb.append("CAPS_DOUBLEBUFFERED|");
+            }
+            if ((caps & CAPS_EXT_LCD_SHADER) != 0) {
+                sb.append("CAPS_EXT_LCD_SHADER|");
+            }
+            if ((caps & CAPS_EXT_BIOP_SHADER) != 0) {
+                sb.append("CAPS_BIOP_SHADER|");
+            }
+            if ((caps & CAPS_EXT_GRAD_SHADER) != 0) {
+                sb.append("CAPS_EXT_GRAD_SHADER|");
+            }
+            if ((caps & CAPS_EXT_TEXRECT) != 0) {
+                sb.append("CAPS_EXT_TEXRECT|");
+            }
+            if ((caps & CAPS_EXT_TEXBARRIER) != 0) {
+                sb.append("CAPS_EXT_TEXBARRIER|");
+            }
+            return sb.toString();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLDrawImage.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.loops.SurfaceType;
+import sun.java2d.loops.TransformBlit;
+import sun.java2d.pipe.DrawImage;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+
+public class MTLDrawImage extends DrawImage {
+
+    @Override
+    protected void renderImageXform(SunGraphics2D sg, Image img,
+                                    AffineTransform tx, int interpType,
+                                    int sx1, int sy1, int sx2, int sy2,
+                                    Color bgColor)
+    {
+        // punt to the MediaLib-based transformImage() in the superclass if:
+        //     - bicubic interpolation is specified
+        //     - a background color is specified and will be used
+        //     - the source surface is neither a texture nor render-to-texture
+        //       surface, and a non-default interpolation hint is specified
+        //       (we can only control the filtering for texture->surface
+        //       copies)
+        //         REMIND: we should tweak the sw->texture->surface
+        //         transform case to handle filtering appropriately
+        //         (see 4841762)...
+        //     - an appropriate TransformBlit primitive could not be found
+        if (interpType != AffineTransformOp.TYPE_BICUBIC) {
+            SurfaceData dstData = sg.surfaceData;
+            SurfaceData srcData =
+                    dstData.getSourceSurfaceData(img,
+                            SunGraphics2D.TRANSFORM_GENERIC,
+                            sg.imageComp,
+                            bgColor);
+
+            if (srcData != null &&
+                    !isBgOperation(srcData, bgColor) &&
+                    (srcData.getSurfaceType() == MTLSurfaceData.MTLTexture ||
+                            srcData.getSurfaceType() == MTLSurfaceData.MTLSurfaceRTT ||
+                            interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR))
+            {
+                SurfaceType srcType = srcData.getSurfaceType();
+                SurfaceType dstType = dstData.getSurfaceType();
+                TransformBlit blit = TransformBlit.getFromCache(srcType,
+                        sg.imageComp,
+                        dstType);
+
+                if (blit != null) {
+                    blit.Transform(srcData, dstData,
+                            sg.composite, sg.getCompClip(),
+                            tx, interpType,
+                            sx1, sy1, 0, 0, sx2-sx1, sy2-sy1);
+                    return;
+                }
+            }
+        }
+
+        super.renderImageXform(sg, img, tx, interpType,
+                sx1, sy1, sx2, sy2, bgColor);
+    }
+
+    @Override
+    public void transformImage(SunGraphics2D sg, BufferedImage img,
+                               BufferedImageOp op, int x, int y)
+    {
+        if (op != null) {
+            if (op instanceof AffineTransformOp) {
+                AffineTransformOp atop = (AffineTransformOp) op;
+                transformImage(sg, img, x, y,
+                        atop.getTransform(),
+                        atop.getInterpolationType());
+                return;
+            } else {
+                if (MTLBufImgOps.renderImageWithOp(sg, img, op, x, y)) {
+                    return;
+                }
+            }
+            img = op.filter(img, null);
+        }
+        copyImage(sg, img, x, y, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.awt.CGraphicsConfig;
+import sun.awt.CGraphicsDevice;
+import sun.awt.image.OffScreenImage;
+import sun.awt.image.SunVolatileImage;
+import sun.awt.image.SurfaceManager;
+import sun.java2d.Disposer;
+import sun.java2d.DisposerRecord;
+import sun.java2d.Surface;
+import sun.java2d.SurfaceData;
+import sun.java2d.pipe.hw.AccelGraphicsConfig;
+import sun.java2d.pipe.hw.AccelSurface;
+import sun.java2d.pipe.hw.AccelTypedVolatileImage;
+import sun.java2d.pipe.hw.ContextCapabilities;
+import sun.lwawt.LWComponentPeer;
+import sun.lwawt.macosx.CFRetainedResource;
+import sun.lwawt.macosx.CPlatformView;
+
+import java.awt.*;
+import java.awt.color.ColorSpace;
+import java.awt.image.*;
+import java.io.File;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+
+import static sun.java2d.opengl.OGLSurfaceData.TEXTURE;
+import static sun.java2d.pipe.hw.AccelSurface.RT_TEXTURE;
+import static sun.java2d.pipe.hw.ContextCapabilities.*;
+
+public final class MTLGraphicsConfig extends CGraphicsConfig
+        implements AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig
+{
+    //private static final int kOpenGLSwapInterval =
+    // RuntimeOptions.getCurrentOptions().OpenGLSwapInterval;
+    private static final int kOpenGLSwapInterval = 0; // TODO
+    private static boolean mtlAvailable;
+    private static ImageCapabilities imageCaps = new MTLImageCaps();
+
+    private static final String mtlShadersLib = AccessController.doPrivileged(
+            (PrivilegedAction<String>) () ->
+                    System.getProperty("java.home", "") + File.separator +
+                            "lib" + File.separator + "shaders.metallib");
+
+
+    private int pixfmt;
+    private BufferCapabilities bufferCaps;
+    private long pConfigInfo;
+    private ContextCapabilities mtlCaps;
+    private MTLContext context;
+    private final Object disposerReferent = new Object();
+    private final int maxTextureSize;
+
+    private static native boolean initMTL();
+    private static native long getMTLConfigInfo(int displayID, String mtlShadersLib);
+
+    /**
+     * Returns GL_MAX_TEXTURE_SIZE from the shared opengl context. Must be
+     * called under OGLRQ lock, because this method change current context.
+     *
+     * @return GL_MAX_TEXTURE_SIZE
+     */
+    private static native int nativeGetMaxTextureSize();
+
+    private static final HashMap<Long, Integer> pGCRefCounts = new HashMap<>();
+
+    static {
+        mtlAvailable = initMTL();
+    }
+
+    private MTLGraphicsConfig(CGraphicsDevice device, int pixfmt,
+                              long configInfo, int maxTextureSize,
+                              ContextCapabilities mtlCaps) {
+        super(device);
+
+        this.pixfmt = pixfmt;
+        this.pConfigInfo = configInfo;
+        this.mtlCaps = mtlCaps;
+        this.maxTextureSize = maxTextureSize;
+        context = new MTLContext(MTLRenderQueue.getInstance(), this);
+        refPConfigInfo(pConfigInfo);
+        // add a record to the Disposer so that we destroy the native
+        // MTLGraphicsConfigInfo data when this object goes away
+        Disposer.addRecord(disposerReferent,
+                new MTLGCDisposerRecord(pConfigInfo));
+    }
+
+    @Override
+    public Object getProxyKey() {
+        return this;
+    }
+
+    public SurfaceData createManagedSurface(int w, int h, int transparency) {
+        return MTLSurfaceData.createData(this, w, h,
+                getColorModel(transparency),
+                null,
+                MTLSurfaceData.TEXTURE);
+    }
+
+    public static MTLGraphicsConfig getConfig(CGraphicsDevice device,
+                                              int displayID, int pixfmt)
+    {
+        if (!mtlAvailable) {
+            return null;
+        }
+
+        long cfginfo = 0;
+        int textureSize = 0;
+        final String[] ids = new String[1];
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            // getCGLConfigInfo() creates and destroys temporary
+            // surfaces/contexts, so we should first invalidate the current
+            // Java-level context and flush the queue...
+            MTLContext.invalidateCurrentContext();
+            cfginfo = getMTLConfigInfo(displayID, mtlShadersLib);
+            if (cfginfo != 0L) {
+                textureSize = nativeGetMaxTextureSize();
+                // 7160609: GL still fails to create a square texture of this
+                // size. Half should be safe enough.
+                // Explicitly not support a texture more than 2^14, see 8010999.
+                textureSize = textureSize <= 16384 ? textureSize / 2 : 8192;
+                MTLContext.setScratchSurface(cfginfo);
+                rq.flushAndInvokeNow(() -> {
+                    ids[0] = MTLContext.getMTLIdString();
+                });
+            }
+        } finally {
+            rq.unlock();
+        }
+        if (cfginfo == 0) {
+            return null;
+        }
+
+        ContextCapabilities caps = new MTLContext.MTLContextCaps(
+                CAPS_PS30 | CAPS_PS20 | CAPS_RT_PLAIN_ALPHA |
+                        CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE |
+                        CAPS_MULTITEXTURE | CAPS_TEXNONPOW2 | CAPS_TEXNONSQUARE,
+                ids[0]);
+        return new MTLGraphicsConfig(device, pixfmt, cfginfo, textureSize, caps);
+    }
+
+    static void refPConfigInfo(long pConfigInfo) {
+        synchronized (pGCRefCounts) {
+            Integer count = pGCRefCounts.get(pConfigInfo);
+            if (count == null) {
+                count = 1;
+            }
+            else {
+                count++;
+            }
+            pGCRefCounts.put(pConfigInfo, count);
+        }
+    }
+
+    static void deRefPConfigInfo(long pConfigInfo) {
+        synchronized (pGCRefCounts) {
+            Integer count = pGCRefCounts.get(pConfigInfo);
+            if (count != null) {
+                count--;
+                pGCRefCounts.put(pConfigInfo, count);
+                if (count == 0) {
+                    MTLRenderQueue.disposeGraphicsConfig(pConfigInfo);
+                    pGCRefCounts.remove(pConfigInfo);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns true if the provided capability bit is present for this config.
+     * See MTLContext.java for a list of supported capabilities.
+     */
+    public boolean isCapPresent(int cap) {
+        return ((mtlCaps.getCaps() & cap) != 0);
+    }
+
+    public long getNativeConfigInfo() {
+        return pConfigInfo;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see sun.java2d.pipe.hw.BufferedContextProvider#getContext
+     */
+    @Override
+    public MTLContext getContext() {
+        return context;
+    }
+
+    @Override
+    public BufferedImage createCompatibleImage(int width, int height) {
+        ColorModel model = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
+        WritableRaster
+                raster = model.createCompatibleWritableRaster(width, height);
+        return new BufferedImage(model, raster, model.isAlphaPremultiplied(),
+                null);
+    }
+
+    @Override
+    public ColorModel getColorModel(int transparency) {
+        switch (transparency) {
+            case Transparency.OPAQUE:
+                // REMIND: once the ColorModel spec is changed, this should be
+                //         an opaque premultiplied DCM...
+                return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
+            case Transparency.BITMASK:
+                return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
+            case Transparency.TRANSLUCENT:
+                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+                return new DirectColorModel(cs, 32,
+                        0xff0000, 0xff00, 0xff, 0xff000000,
+                        true, DataBuffer.TYPE_INT);
+            default:
+                return null;
+        }
+    }
+
+    public boolean isDoubleBuffered() {
+        return true;
+    }
+
+    private static class MTLGCDisposerRecord implements DisposerRecord {
+        private long pCfgInfo;
+        public MTLGCDisposerRecord(long pCfgInfo) {
+            this.pCfgInfo = pCfgInfo;
+        }
+        public void dispose() {
+            if (pCfgInfo != 0) {
+                deRefPConfigInfo(pCfgInfo);
+                pCfgInfo = 0;
+            }
+        }
+    }
+
+    // TODO: CGraphicsConfig doesn't implement displayChanged() yet
+    //@Override
+    public synchronized void displayChanged() {
+        //super.displayChanged();
+
+        // the context could hold a reference to a MTLSurfaceData, which in
+        // turn has a reference back to this MTLGraphicsConfig, so in order
+        // for this instance to be disposed we need to break the connection
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            MTLContext.invalidateCurrentContext();
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return ("MTLGraphicsConfig[" + getDevice().getIDstring() +
+                ",pixfmt="+pixfmt+"]");
+    }
+
+    @Override
+    public SurfaceData createSurfaceData(CPlatformView pView) {
+        return MTLSurfaceData.createData(pView);
+    }
+
+    @Override
+    public SurfaceData createSurfaceData(CFRetainedResource layer) {
+        return MTLSurfaceData.createData((MTLLayer) layer);
+    }
+
+    @Override
+    public Image createAcceleratedImage(Component target,
+                                        int width, int height)
+    {
+        ColorModel model = getColorModel(Transparency.OPAQUE);
+        WritableRaster wr = model.createCompatibleWritableRaster(width, height);
+        return new OffScreenImage(target, model, wr,
+                model.isAlphaPremultiplied());
+    }
+
+    @Override
+    public void assertOperationSupported(final int numBuffers,
+                                         final BufferCapabilities caps)
+            throws AWTException {
+        // Assume this method is never called with numBuffers != 2, as 0 is
+        // unsupported, and 1 corresponds to a SingleBufferStrategy which
+        // doesn't depend on the peer. Screen is considered as a separate
+        // "buffer".
+        if (numBuffers != 2) {
+            throw new AWTException("Only double buffering is supported");
+        }
+        final BufferCapabilities configCaps = getBufferCapabilities();
+        if (!configCaps.isPageFlipping()) {
+            throw new AWTException("Page flipping is not supported");
+        }
+        if (caps.getFlipContents() == BufferCapabilities.FlipContents.PRIOR) {
+            throw new AWTException("FlipContents.PRIOR is not supported");
+        }
+    }
+
+    @Override
+    public Image createBackBuffer(final LWComponentPeer<?, ?> peer) {
+        final Rectangle r = peer.getBounds();
+        // It is possible for the component to have size 0x0, adjust it to
+        // be at least 1x1 to avoid IAE
+        final int w = Math.max(1, r.width);
+        final int h = Math.max(1, r.height);
+        final int transparency = peer.isTranslucent() ? Transparency.TRANSLUCENT
+                : Transparency.OPAQUE;
+        return new SunVolatileImage(this, w, h, transparency, null);
+    }
+
+    @Override
+    public void destroyBackBuffer(final Image backBuffer) {
+        if (backBuffer != null) {
+            backBuffer.flush();
+        }
+    }
+
+    @Override
+    public void flip(final LWComponentPeer<?, ?> peer, final Image backBuffer,
+                     final int x1, final int y1, final int x2, final int y2,
+                     final BufferCapabilities.FlipContents flipAction) {
+        final Graphics g = peer.getGraphics();
+        try {
+            g.drawImage(backBuffer, x1, y1, x2, y2, x1, y1, x2, y2, null);
+        } finally {
+            g.dispose();
+        }
+        if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) {
+            final Graphics2D bg = (Graphics2D) backBuffer.getGraphics();
+            try {
+                bg.setBackground(peer.getBackground());
+                bg.clearRect(0, 0, backBuffer.getWidth(null),
+                        backBuffer.getHeight(null));
+            } finally {
+                bg.dispose();
+            }
+        }
+    }
+
+    private static class MTLBufferCaps extends BufferCapabilities {
+        public MTLBufferCaps(boolean dblBuf) {
+            super(imageCaps, imageCaps,
+                    dblBuf ? FlipContents.UNDEFINED : null);
+        }
+    }
+
+    @Override
+    public BufferCapabilities getBufferCapabilities() {
+        if (bufferCaps == null) {
+            bufferCaps = new MTLBufferCaps(isDoubleBuffered());
+        }
+        return bufferCaps;
+    }
+
+    private static class MTLImageCaps extends ImageCapabilities {
+        private MTLImageCaps() {
+            super(true);
+        }
+        public boolean isTrueVolatile() {
+            return true;
+        }
+    }
+
+    @Override
+    public ImageCapabilities getImageCapabilities() {
+        return imageCaps;
+    }
+
+    @Override
+    public VolatileImage createCompatibleVolatileImage(int width, int height,
+                                                       int transparency,
+                                                       int type) {
+        if (type != RT_TEXTURE && type != TEXTURE) {
+            return null;
+        }
+
+        SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,
+                transparency, type);
+        Surface sd = vi.getDestSurface();
+        if (!(sd instanceof AccelSurface) ||
+                ((AccelSurface)sd).getType() != type)
+        {
+            vi.flush();
+            vi = null;
+        }
+
+        return vi;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see sun.java2d.pipe.hw.AccelGraphicsConfig#getContextCapabilities
+     */
+    @Override
+    public ContextCapabilities getContextCapabilities() {
+        return mtlCaps;
+    }
+
+    @Override
+    public int getMaxTextureWidth() {
+        return Math.max(maxTextureSize / getDevice().getScaleFactor(),
+                getBounds().width);
+    }
+
+    @Override
+    public int getMaxTextureHeight() {
+        return Math.max(maxTextureSize / getDevice().getScaleFactor(),
+                getBounds().height);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLLayer.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.java2d.NullSurfaceData;
+import sun.java2d.SurfaceData;
+import sun.lwawt.LWWindowPeer;
+import sun.lwawt.macosx.CFRetainedResource;
+
+import java.awt.*;
+
+public class MTLLayer extends CFRetainedResource {
+
+    private native long nativeCreateLayer();
+    private static native void nativeSetScale(long layerPtr, double scale);
+    private static native void validate(long layerPtr, MTLSurfaceData cglsd);
+
+    private LWWindowPeer peer;
+    private int scale = 1;
+
+    private SurfaceData surfaceData; // represents intermediate buffer (texture)
+
+    public MTLLayer(LWWindowPeer peer) {
+        super(0, true);
+
+        setPtr(nativeCreateLayer());
+        this.peer = peer;
+    }
+
+    public long getPointer() {
+        return ptr;
+    }
+
+    public Rectangle getBounds() {
+        return peer.getBounds();
+    }
+
+    public GraphicsConfiguration getGraphicsConfiguration() {
+        return peer.getGraphicsConfiguration();
+    }
+
+    public boolean isOpaque() {
+        return !peer.isTranslucent();
+    }
+
+    public int getTransparency() {
+        return isOpaque() ? Transparency.OPAQUE : Transparency.TRANSLUCENT;
+    }
+
+    public Object getDestination() {
+        return peer.getTarget();
+    }
+
+    public SurfaceData replaceSurfaceData() {
+        if (getBounds().isEmpty()) {
+            surfaceData = NullSurfaceData.theInstance;
+            return surfaceData;
+        }
+
+        // the layer redirects all painting to the buffer's graphics
+        // and blits the buffer to the layer surface (in drawInCGLContext callback)
+        MTLGraphicsConfig gc = (MTLGraphicsConfig)getGraphicsConfiguration();
+        surfaceData = gc.createSurfaceData(this);
+        setScale(gc.getDevice().getScaleFactor());
+        // the layer holds a reference to the buffer, which in
+        // turn has a reference back to this layer
+        if (surfaceData instanceof MTLSurfaceData) {
+            validate((MTLSurfaceData)surfaceData);
+        }
+
+        return surfaceData;
+    }
+
+    public SurfaceData getSurfaceData() {
+        return surfaceData;
+    }
+
+    public void validate(final MTLSurfaceData cglsd) {
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            execute(ptr -> validate(ptr, cglsd));
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    @Override
+    public void dispose() {
+        // break the connection between the layer and the buffer
+        validate(null);
+        super.dispose();
+    }
+
+    private void setScale(final int _scale) {
+        if (scale != _scale) {
+            scale = _scale;
+            execute(ptr -> nativeSetScale(ptr, scale));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLMaskBlit.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.java2d.SurfaceData;
+import sun.java2d.loops.CompositeType;
+import sun.java2d.loops.GraphicsPrimitive;
+import sun.java2d.loops.GraphicsPrimitiveMgr;
+import sun.java2d.loops.SurfaceType;
+import sun.java2d.pipe.BufferedMaskBlit;
+import sun.java2d.pipe.Region;
+
+import java.awt.*;
+
+import static sun.java2d.loops.CompositeType.SrcNoEa;
+import static sun.java2d.loops.CompositeType.SrcOver;
+import static sun.java2d.loops.SurfaceType.*;
+
+class MTLMaskBlit extends BufferedMaskBlit {
+
+    static void register() {
+        GraphicsPrimitive[] primitives = {
+                new MTLMaskBlit(IntArgb,    SrcOver),
+                new MTLMaskBlit(IntArgbPre, SrcOver),
+                new MTLMaskBlit(IntRgb,     SrcOver),
+                new MTLMaskBlit(IntRgb,     SrcNoEa),
+                new MTLMaskBlit(IntBgr,     SrcOver),
+                new MTLMaskBlit(IntBgr,     SrcNoEa),
+        };
+        GraphicsPrimitiveMgr.register(primitives);
+    }
+
+    private MTLMaskBlit(SurfaceType srcType,
+                        CompositeType compType)
+    {
+        super(MTLRenderQueue.getInstance(),
+                srcType, compType, MTLSurfaceData.MTLSurface);
+    }
+
+    @Override
+    protected void validateContext(SurfaceData dstData,
+                                   Composite comp, Region clip)
+    {
+        MTLSurfaceData oglDst = (MTLSurfaceData)dstData;
+        MTLContext.validateContext(oglDst, oglDst,
+                clip, comp, null, null, null,
+                MTLContext.NO_CONTEXT_FLAGS);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLMaskFill.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.java2d.metal;
+
+import sun.java2d.InvalidPipeException;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.loops.CompositeType;
+import sun.java2d.loops.GraphicsPrimitive;
+import sun.java2d.loops.GraphicsPrimitiveMgr;
+import sun.java2d.loops.SurfaceType;
+import sun.java2d.pipe.BufferedMaskFill;
+
+import java.awt.*;
+
+import static sun.java2d.loops.CompositeType.SrcNoEa;
+import static sun.java2d.loops.CompositeType.SrcOver;
+import static sun.java2d.loops.SurfaceType.*;
+
+class MTLMaskFill extends BufferedMaskFill {
+
+    static void register() {
+        GraphicsPrimitive[] primitives = {
+                new MTLMaskFill(AnyColor,                  SrcOver),
+                new MTLMaskFill(OpaqueColor,               SrcNoEa),
+                new MTLMaskFill(GradientPaint,             SrcOver),
+                new MTLMaskFill(OpaqueGradientPaint,       SrcNoEa),
+                new MTLMaskFill(LinearGradientPaint,       SrcOver),
+                new MTLMaskFill(OpaqueLinearGradientPaint, SrcNoEa),
+                new MTLMaskFill(RadialGradientPaint,       SrcOver),
+                new MTLMaskFill(OpaqueRadialGradientPaint, SrcNoEa),
+                new MTLMaskFill(TexturePaint,              SrcOver),
+                new MTLMaskFill(OpaqueTexturePaint,        SrcNoEa),
+        };
+        GraphicsPrimitiveMgr.register(primitives);
+    }
+
+    protected MTLMaskFill(SurfaceType srcType, CompositeType compType) {
+        super(MTLRenderQueue.getInstance(),
+                srcType, compType, MTLSurfaceData.MTLSurface);
+    }
+
+    @Override
+    protected native void maskFill(int x, int y, int w, int h,
+                                   int maskoff, int maskscan, int masklen,
+                                   byte[] mask);
+
+    @Override
+    protected void validateContext(SunGraphics2D sg2d,
+                                   Composite comp, int ctxflags)
+    {
+        MTLSurfaceData dstData;
+        try {
+            dstData = (MTLSurfaceData) sg2d.surfaceData;
+        } catch (ClassCastException e) {
+            throw new InvalidPipeException("wrong surface data type: " +
+                    sg2d.surfaceData);
+        }
+
+        MTLContext.validateContext(dstData, dstData,
+                sg2d.getCompClip(), comp,
+                null, sg2d.paint, sg2d, ctxflags);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLPaints.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.java2d.metal;
+
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.loops.CompositeType;
+
+import java.awt.*;
+import java.awt.MultipleGradientPaint.ColorSpaceType;
+import java.awt.MultipleGradientPaint.CycleMethod;
+import java.awt.image.BufferedImage;
+import java.util.HashMap;
+import java.util.Map;
+
+import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_GRAD_SHADER;
+import static sun.java2d.pipe.BufferedPaints.MULTI_MAX_FRACTIONS;
+
+abstract class MTLPaints {
+
+    /**
+     * Holds all registered implementations, using the corresponding
+     * SunGraphics2D.PAINT_* constant as the hash key.
+     */
+    private static Map<Integer, MTLPaints> impls =
+            new HashMap<Integer, MTLPaints>(4, 1.0f);
+
+    static {
+        impls.put(SunGraphics2D.PAINT_GRADIENT, new Gradient());
+        impls.put(SunGraphics2D.PAINT_LIN_GRADIENT, new LinearGradient());
+        impls.put(SunGraphics2D.PAINT_RAD_GRADIENT, new RadialGradient());
+        impls.put(SunGraphics2D.PAINT_TEXTURE, new Texture());
+    }
+
+    /**
+     * Attempts to locate an implementation corresponding to the paint state
+     * of the provided SunGraphics2D object.  If no implementation can be
+     * found, or if the paint cannot be accelerated under the conditions
+     * of the SunGraphics2D, this method returns false; otherwise, returns
+     * true.
+     */
+    static boolean isValid(SunGraphics2D sg2d) {
+        MTLPaints impl = impls.get(sg2d.paintState);
+        return (impl != null && impl.isPaintValid(sg2d));
+    }
+
+    /**
+     * Returns true if this implementation is able to accelerate the
+     * Paint object associated with, and under the conditions of, the
+     * provided SunGraphics2D instance; otherwise returns false.
+     */
+    abstract boolean isPaintValid(SunGraphics2D sg2d);
+
+    /************************* GradientPaint support ****************************/
+
+    private static class Gradient extends MTLPaints {
+        private Gradient() {}
+
+        /**
+         * There are no restrictions for accelerating GradientPaint, so
+         * this method always returns true.
+         */
+        @Override
+        boolean isPaintValid(SunGraphics2D sg2d) {
+            return true;
+        }
+    }
+
+    /************************** TexturePaint support ****************************/
+
+    private static class Texture extends MTLPaints {
+        private Texture() {}
+
+        /**
+         * Returns true if the given TexturePaint instance can be used by the
+         * accelerated MTLPaints.Texture implementation.  A TexturePaint is
+         * considered valid if the following conditions are met:
+         *   - the texture image dimensions are power-of-two (or the
+         *     GL_ARB_texture_non_power_of_two extension is present)
+         *   - the texture image can be (or is already) cached in an OpenGL
+         *     texture object
+         */
+        @Override
+        boolean isPaintValid(SunGraphics2D sg2d) {
+            TexturePaint paint = (TexturePaint)sg2d.paint;
+            MTLSurfaceData dstData = (MTLSurfaceData)sg2d.surfaceData;
+            BufferedImage bi = paint.getImage();
+
+            // see if texture-non-pow2 extension is available
+            if (!dstData.isTexNonPow2Available()) {
+                int imgw = bi.getWidth();
+                int imgh = bi.getHeight();
+
+                // verify that the texture image dimensions are pow2
+                if ((imgw & (imgw - 1)) != 0 || (imgh & (imgh - 1)) != 0) {
+                    return false;
+                }
+            }
+
+            SurfaceData srcData =
+                    dstData.getSourceSurfaceData(bi,
+                            SunGraphics2D.TRANSFORM_ISIDENT,
+                            CompositeType.SrcOver, null);
+            if (!(srcData instanceof MTLSurfaceData)) {
+                // REMIND: this is a hack that attempts to cache the system
+                //         memory image from the TexturePaint instance into an
+                //         OpenGL texture...
+                srcData =
+                        dstData.getSourceSurfaceData(bi,
+                                SunGraphics2D.TRANSFORM_ISIDENT,
+                                CompositeType.SrcOver, null);
+                if (!(srcData instanceof MTLSurfaceData)) {
+                    return false;
+                }
+            }
+
+            // verify that the source surface is actually a texture
+            MTLSurfaceData oglData = (MTLSurfaceData)srcData;
+            if (oglData.getType() != MTLSurfaceData.TEXTURE) {
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    /****************** Shared MultipleGradientPaint support ********************/
+
+    private abstract static class MultiGradient extends MTLPaints {
+        protected MultiGradient() {}
+
+        /**
+         * Returns true if the given MultipleGradientPaint instance can be
+         * used by the accelerated MTLPaints.MultiGradient implementation.
+         * A MultipleGradientPaint is considered valid if the following
+         * conditions are met:
+         *   - the number of gradient "stops" is <= MAX_FRACTIONS
+         *   - the destination has support for fragment shaders
+         */
+        @Override
+        boolean isPaintValid(SunGraphics2D sg2d) {
+            MultipleGradientPaint paint = (MultipleGradientPaint)sg2d.paint;
+            // REMIND: ugh, this creates garbage; would be nicer if
+            // we had a MultipleGradientPaint.getNumStops() method...
+            if (paint.getFractions().length > MULTI_MAX_FRACTIONS) {
+                return false;
+            }
+
+            MTLSurfaceData dstData = (MTLSurfaceData)sg2d.surfaceData;
+            MTLGraphicsConfig gc = dstData.getMTLGraphicsConfig();
+            if (!gc.isCapPresent(CAPS_EXT_GRAD_SHADER)) {
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    /********************** LinearGradientPaint support *************************/
+
+    private static class LinearGradient extends MultiGradient {
+        private LinearGradient() {}
+
+        @Override
+        boolean isPaintValid(SunGraphics2D sg2d) {
+            LinearGradientPaint paint = (LinearGradientPaint)sg2d.paint;
+
+            if (paint.getFractions().length == 2 &&
+                    paint.getCycleMethod() != CycleMethod.REPEAT &&
+                    paint.getColorSpace() != ColorSpaceType.LINEAR_RGB)
+            {
+                // we can delegate to the optimized two-color gradient
+                // codepath, which does not require fragment shader support
+                return true;
+            }
+
+            return super.isPaintValid(sg2d);
+        }
+    }
+
+    /********************** RadialGradientPaint support *************************/
+
+    private static class RadialGradient extends MultiGradient {
+        private RadialGradient() {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderQueue.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.awt.util.ThreadGroupUtils;
+import sun.java2d.pipe.RenderBuffer;
+import sun.java2d.pipe.RenderQueue;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_CONFIG;
+import static sun.java2d.pipe.BufferedOpCodes.SYNC;
+
+/**
+ * OGL-specific implementation of RenderQueue.  This class provides a
+ * single (daemon) thread that is responsible for periodically flushing
+ * the queue, thus ensuring that only one thread communicates with the native
+ * OpenGL libraries for the entire process.
+ */
+public class MTLRenderQueue extends RenderQueue {
+
+    private static MTLRenderQueue theInstance;
+    private final QueueFlusher flusher;
+
+    private MTLRenderQueue() {
+        /*
+         * The thread must be a member of a thread group
+         * which will not get GCed before VM exit.
+         */
+        flusher = AccessController.doPrivileged((PrivilegedAction<QueueFlusher>) QueueFlusher::new);
+    }
+
+    /**
+     * Returns the single MTLRenderQueue instance.  If it has not yet been
+     * initialized, this method will first construct the single instance
+     * before returning it.
+     */
+    public static synchronized MTLRenderQueue getInstance() {
+        if (theInstance == null) {
+            theInstance = new MTLRenderQueue();
+        }
+        return theInstance;
+    }
+
+    /**
+     * Flushes the single MTLRenderQueue instance synchronously.  If an
+     * MTLRenderQueue has not yet been instantiated, this method is a no-op.
+     * This method is useful in the case of Toolkit.sync(), in which we want
+     * to flush the OGL pipeline, but only if the OGL pipeline is currently
+     * enabled.  Since this class has few external dependencies, callers need
+     * not be concerned that calling this method will trigger initialization
+     * of the OGL pipeline and related classes.
+     */
+    public static void sync() {
+        if (theInstance != null) {
+            theInstance.lock();
+            try {
+                theInstance.ensureCapacity(4);
+                theInstance.getBuffer().putInt(SYNC);
+                theInstance.flushNow();
+            } finally {
+                theInstance.unlock();
+            }
+        }
+    }
+
+    /**
+     * Disposes the native memory associated with the given native
+     * graphics config info pointer on the single queue flushing thread.
+     */
+    public static void disposeGraphicsConfig(long pConfigInfo) {
+        MTLRenderQueue rq = getInstance();
+        rq.lock();
+        try {
+            // make sure we make the context associated with the given
+            // GraphicsConfig current before disposing the native resources
+            MTLContext.setScratchSurface(pConfigInfo);
+
+            RenderBuffer buf = rq.getBuffer();
+            rq.ensureCapacityAndAlignment(12, 4);
+            buf.putInt(DISPOSE_CONFIG);
+            buf.putLong(pConfigInfo);
+
+            // this call is expected to complete synchronously, so flush now
+            rq.flushNow();
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    /**
+     * Returns true if the current thread is the OGL QueueFlusher thread.
+     */
+    public static boolean isQueueFlusherThread() {
+        return (Thread.currentThread() == getInstance().flusher.thread);
+    }
+
+
+    @Override
+    public void flushNow() {
+        // assert lock.isHeldByCurrentThread();
+        try {
+            flusher.flushNow();
+        } catch (Exception e) {
+            System.err.println("exception in flushNow:");
+            e.printStackTrace();
+        }
+    }
+
+    public void flushAndInvokeNow(Runnable r) {
+        // assert lock.isHeldByCurrentThread();
+        try {
+            flusher.flushAndInvokeNow(r);
+        } catch (Exception e) {
+            System.err.println("exception in flushAndInvokeNow:");
+            e.printStackTrace();
+        }
+    }
+
+    private native void flushBuffer(long buf, int limit);
+
+    private void flushBuffer() {
+        // assert lock.isHeldByCurrentThread();
+        int limit = buf.position();
+        if (limit > 0) {
+            // process the queue
+            flushBuffer(buf.getAddress(), limit);
+        }
+        // reset the buffer position
+        buf.clear();
+        // clear the set of references, since we no longer need them
+        refSet.clear();
+    }
+
+    private class QueueFlusher implements Runnable {
+        private boolean needsFlush;
+        private Runnable task;
+        private Error error;
+        private final Thread thread;
+
+        public QueueFlusher() {
+            String name = "Java2D Queue Flusher";
+            thread = new Thread(ThreadGroupUtils.getRootThreadGroup(),
+                    this, name, 0, false);
+            thread.setDaemon(true);
+            thread.setPriority(Thread.MAX_PRIORITY);
+            thread.start();
+        }
+
+        public synchronized void flushNow() {
+            // wake up the flusher
+            needsFlush = true;
+            notify();
+
+            // wait for flush to complete
+            while (needsFlush) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+
+            // re-throw any error that may have occurred during the flush
+            if (error != null) {
+                throw error;
+            }
+        }
+
+        public synchronized void flushAndInvokeNow(Runnable task) {
+            this.task = task;
+            flushNow();
+        }
+
+        public synchronized void run() {
+            boolean timedOut = false;
+            while (true) {
+                while (!needsFlush) {
+                    try {
+                        timedOut = false;
+                        /*
+                         * Wait until we're woken up with a flushNow() call,
+                         * or the timeout period elapses (so that we can
+                         * flush the queue periodically).
+                         */
+                        wait(100);
+                        /*
+                         * We will automatically flush the queue if the
+                         * following conditions apply:
+                         *   - the wait() timed out
+                         *   - we can lock the queue (without blocking)
+                         *   - there is something in the queue to flush
+                         * Otherwise, just continue (we'll flush eventually).
+                         */
+                        if (!needsFlush && (timedOut = tryLock())) {
+                            if (buf.position() > 0) {
+                                needsFlush = true;
+                            } else {
+                                unlock();
+                            }
+                        }
+                    } catch (InterruptedException e) {
+                    }
+                }
+                try {
+                    // reset the throwable state
+                    error = null;
+                    // flush the buffer now
+                    flushBuffer();
+                    // if there's a task, invoke that now as well
+                    if (task != null) {
+                        task.run();
+                    }
+                } catch (Error e) {
+                    error = e;
+                } catch (Exception x) {
+                    System.err.println("exception in QueueFlusher:");
+                    x.printStackTrace();
+                } finally {
+                    if (timedOut) {
+                        unlock();
+                    }
+                    task = null;
+                    // allow the waiting thread to continue
+                    needsFlush = false;
+                    notify();
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderer.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.java2d.metal;
+
+import sun.java2d.InvalidPipeException;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.loops.GraphicsPrimitive;
+import sun.java2d.pipe.BufferedRenderPipe;
+import sun.java2d.pipe.ParallelogramPipe;
+import sun.java2d.pipe.RenderQueue;
+import sun.java2d.pipe.SpanIterator;
+
+import java.awt.*;
+import java.awt.geom.Path2D;
+
+import static sun.java2d.pipe.BufferedOpCodes.COPY_AREA;
+
+class MTLRenderer extends BufferedRenderPipe {
+
+    MTLRenderer(RenderQueue rq) {
+        super(rq);
+    }
+
+    @Override
+    protected void validateContext(SunGraphics2D sg2d) {
+        int ctxflags =
+                sg2d.paint.getTransparency() == Transparency.OPAQUE ?
+                        MTLContext.SRC_IS_OPAQUE : MTLContext.NO_CONTEXT_FLAGS;
+        MTLSurfaceData dstData;
+        try {
+            dstData = (MTLSurfaceData)sg2d.surfaceData;
+        } catch (ClassCastException e) {
+            throw new InvalidPipeException("wrong surface data type: " + sg2d.surfaceData);
+        }
+        MTLContext.validateContext(dstData, dstData,
+                sg2d.getCompClip(), sg2d.composite,
+                null, sg2d.paint, sg2d, ctxflags);
+    }
+
+    @Override
+    protected void validateContextAA(SunGraphics2D sg2d) {
+        int ctxflags = MTLContext.NO_CONTEXT_FLAGS;
+        MTLSurfaceData dstData;
+        try {
+            dstData = (MTLSurfaceData)sg2d.surfaceData;
+        } catch (ClassCastException e) {
+            throw new InvalidPipeException("wrong surface data type: " + sg2d.surfaceData);
+        }
+        MTLContext.validateContext(dstData, dstData,
+                sg2d.getCompClip(), sg2d.composite,
+                null, sg2d.paint, sg2d, ctxflags);
+    }
+
+    void copyArea(SunGraphics2D sg2d,
+                  int x, int y, int w, int h, int dx, int dy)
+    {
+        rq.lock();
+        try {
+            int ctxflags =
+                    sg2d.surfaceData.getTransparency() == Transparency.OPAQUE ?
+                            MTLContext.SRC_IS_OPAQUE : MTLContext.NO_CONTEXT_FLAGS;
+            MTLSurfaceData dstData;
+            try {
+                dstData = (MTLSurfaceData)sg2d.surfaceData;
+            } catch (ClassCastException e) {
+                throw new InvalidPipeException("wrong surface data type: " + sg2d.surfaceData);
+            }
+            MTLContext.validateContext(dstData, dstData,
+                    sg2d.getCompClip(), sg2d.composite,
+                    null, null, null, ctxflags);
+
+            rq.ensureCapacity(28);
+            buf.putInt(COPY_AREA);
+            buf.putInt(x).putInt(y).putInt(w).putInt(h);
+            buf.putInt(dx).putInt(dy);
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    @Override
+    protected native void drawPoly(int[] xPoints, int[] yPoints,
+                                   int nPoints, boolean isClosed,
+                                   int transX, int transY);
+
+    MTLRenderer traceWrap() {
+        return new Tracer(this);
+    }
+
+    private class Tracer extends MTLRenderer {
+        private MTLRenderer mtlr;
+        Tracer(MTLRenderer mtlr) {
+            super(mtlr.rq);
+            this.mtlr = mtlr;
+        }
+        public ParallelogramPipe getAAParallelogramPipe() {
+            final ParallelogramPipe realpipe = mtlr.getAAParallelogramPipe();
+            return new ParallelogramPipe() {
+                public void fillParallelogram(SunGraphics2D sg2d,
+                                              double ux1, double uy1,
+                                              double ux2, double uy2,
+                                              double x, double y,
+                                              double dx1, double dy1,
+                                              double dx2, double dy2)
+                {
+                    GraphicsPrimitive.tracePrimitive("MTLFillAAParallelogram");
+                    realpipe.fillParallelogram(sg2d,
+                            ux1, uy1, ux2, uy2,
+                            x, y, dx1, dy1, dx2, dy2);
+                }
+                public void drawParallelogram(SunGraphics2D sg2d,
+                                              double ux1, double uy1,
+                                              double ux2, double uy2,
+                                              double x, double y,
+                                              double dx1, double dy1,
+                                              double dx2, double dy2,
+                                              double lw1, double lw2)
+                {
+                    GraphicsPrimitive.tracePrimitive("MTLDrawAAParallelogram");
+                    realpipe.drawParallelogram(sg2d,
+                            ux1, uy1, ux2, uy2,
+                            x, y, dx1, dy1, dx2, dy2,
+                            lw1, lw2);
+                }
+            };
+        }
+        protected void validateContext(SunGraphics2D sg2d) {
+            mtlr.validateContext(sg2d);
+        }
+        public void drawLine(SunGraphics2D sg2d,
+                             int x1, int y1, int x2, int y2)
+        {
+            GraphicsPrimitive.tracePrimitive("MTLDrawLine");
+            mtlr.drawLine(sg2d, x1, y1, x2, y2);
+        }
+        public void drawRect(SunGraphics2D sg2d, int x, int y, int w, int h) {
+            GraphicsPrimitive.tracePrimitive("MTLDrawRect");
+            mtlr.drawRect(sg2d, x, y, w, h);
+        }
+        protected void drawPoly(SunGraphics2D sg2d,
+                                int[] xPoints, int[] yPoints,
+                                int nPoints, boolean isClosed)
+        {
+            GraphicsPrimitive.tracePrimitive("MTLDrawPoly");
+            mtlr.drawPoly(sg2d, xPoints, yPoints, nPoints, isClosed);
+        }
+        public void fillRect(SunGraphics2D sg2d, int x, int y, int w, int h) {
+            GraphicsPrimitive.tracePrimitive("MTLFillRect");
+            mtlr.fillRect(sg2d, x, y, w, h);
+        }
+        protected void drawPath(SunGraphics2D sg2d,
+                                Path2D.Float p2df, int transx, int transy)
+        {
+            GraphicsPrimitive.tracePrimitive("MTLDrawPath");
+            mtlr.drawPath(sg2d, p2df, transx, transy);
+        }
+        protected void fillPath(SunGraphics2D sg2d,
+                                Path2D.Float p2df, int transx, int transy)
+        {
+            GraphicsPrimitive.tracePrimitive("MTLFillPath");
+            mtlr.fillPath(sg2d, p2df, transx, transy);
+        }
+        protected void fillSpans(SunGraphics2D sg2d, SpanIterator si,
+                                 int transx, int transy)
+        {
+            GraphicsPrimitive.tracePrimitive("MTLFillSpans");
+            mtlr.fillSpans(sg2d, si, transx, transy);
+        }
+        public void fillParallelogram(SunGraphics2D sg2d,
+                                      double ux1, double uy1,
+                                      double ux2, double uy2,
+                                      double x, double y,
+                                      double dx1, double dy1,
+                                      double dx2, double dy2)
+        {
+            GraphicsPrimitive.tracePrimitive("MTLFillParallelogram");
+            mtlr.fillParallelogram(sg2d,
+                    ux1, uy1, ux2, uy2,
+                    x, y, dx1, dy1, dx2, dy2);
+        }
+        public void drawParallelogram(SunGraphics2D sg2d,
+                                      double ux1, double uy1,
+                                      double ux2, double uy2,
+                                      double x, double y,
+                                      double dx1, double dy1,
+                                      double dx2, double dy2,
+                                      double lw1, double lw2)
+        {
+            GraphicsPrimitive.tracePrimitive("MTLDrawParallelogram");
+            mtlr.drawParallelogram(sg2d,
+                    ux1, uy1, ux2, uy2,
+                    x, y, dx1, dy1, dx2, dy2, lw1, lw2);
+        }
+        public void copyArea(SunGraphics2D sg2d,
+                             int x, int y, int w, int h, int dx, int dy)
+        {
+            GraphicsPrimitive.tracePrimitive("MTLCopyArea");
+            mtlr.copyArea(sg2d, x, y, w, h, dx, dy);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,885 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.awt.SunHints;
+import sun.awt.image.PixelConverter;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.SurfaceDataProxy;
+import sun.java2d.loops.CompositeType;
+import sun.java2d.loops.GraphicsPrimitive;
+import sun.java2d.loops.MaskFill;
+import sun.java2d.loops.SurfaceType;
+import sun.java2d.pipe.ParallelogramPipe;
+import sun.java2d.pipe.PixelToParallelogramConverter;
+import sun.java2d.pipe.RenderBuffer;
+import sun.java2d.pipe.TextPipe;
+import sun.java2d.pipe.hw.AccelSurface;
+import sun.lwawt.macosx.CPlatformView;
+
+import java.awt.*;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+
+import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_LCD_SHADER;
+import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_TEXRECT;
+import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
+import static sun.java2d.pipe.BufferedOpCodes.SWAP_BUFFERS;
+import static sun.java2d.pipe.hw.ContextCapabilities.*;
+
+public abstract class MTLSurfaceData extends SurfaceData
+        implements AccelSurface {
+
+    /**
+     * Pixel formats
+     */
+    public static final int PF_INT_ARGB        = 0;
+    public static final int PF_INT_ARGB_PRE    = 1;
+    public static final int PF_INT_RGB         = 2;
+    public static final int PF_INT_RGBX        = 3;
+    public static final int PF_INT_BGR         = 4;
+    public static final int PF_INT_BGRX        = 5;
+    public static final int PF_USHORT_565_RGB  = 6;
+    public static final int PF_USHORT_555_RGB  = 7;
+    public static final int PF_USHORT_555_RGBX = 8;
+    public static final int PF_BYTE_GRAY       = 9;
+    public static final int PF_USHORT_GRAY     = 10;
+    public static final int PF_3BYTE_BGR       = 11;
+    /**
+     * SurfaceTypes
+     */
+
+    private static final String DESC_MTL_SURFACE = "MTL Surface";
+    private static final String DESC_MTL_SURFACE_RTT =
+            "MTL Surface (render-to-texture)";
+    private static final String DESC_MTL_TEXTURE = "MTL Texture";
+
+
+    static final SurfaceType MTLSurface =
+            SurfaceType.Any.deriveSubType(DESC_MTL_SURFACE,
+                    PixelConverter.ArgbPre.instance);
+    static final SurfaceType MTLSurfaceRTT =
+            MTLSurface.deriveSubType(DESC_MTL_SURFACE_RTT);
+    static final SurfaceType MTLTexture =
+            SurfaceType.Any.deriveSubType(DESC_MTL_TEXTURE);
+
+    protected static MTLRenderer mtlRenderPipe;
+    protected static PixelToParallelogramConverter mtlTxRenderPipe;
+    protected static ParallelogramPipe mtlAAPgramPipe;
+    protected static MTLTextRenderer mtlTextPipe;
+    protected static MTLDrawImage mtlImagePipe;
+    /** This will be true if the fbobject system property has been enabled. */
+    private static boolean isFBObjectEnabled;
+    /** This will be true if the lcdshader system property has been enabled.*/
+    private static boolean isLCDShaderEnabled;
+    /** This will be true if the biopshader system property has been enabled.*/
+    private static boolean isBIOpShaderEnabled;
+    /** This will be true if the gradshader system property has been enabled.*/
+    private static boolean isGradShaderEnabled;
+
+    static {
+        if (!GraphicsEnvironment.isHeadless()) {
+            // fbobject currently enabled by default; use "false" to disable
+            String fbo = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                            "java2d.metal.fbobject"));
+            isFBObjectEnabled = !"false".equals(fbo);
+
+            // lcdshader currently enabled by default; use "false" to disable
+            String lcd = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                            "java2d.metal.lcdshader"));
+            isLCDShaderEnabled = !"false".equals(lcd);
+
+            // biopshader currently enabled by default; use "false" to disable
+            String biop = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                            "java2d.metal.biopshader"));
+            isBIOpShaderEnabled = !"false".equals(biop);
+
+            // gradshader currently enabled by default; use "false" to disable
+            String grad = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                            "java2d.metal.gradshader"));
+            isGradShaderEnabled = !"false".equals(grad);
+
+            MTLRenderQueue rq = MTLRenderQueue.getInstance();
+            mtlImagePipe = new MTLDrawImage();
+            mtlTextPipe = new MTLTextRenderer(rq);
+            mtlRenderPipe = new MTLRenderer(rq);
+            if (GraphicsPrimitive.tracingEnabled()) {
+                mtlTextPipe = mtlTextPipe.traceWrap();
+                //The wrapped mtlRenderPipe will wrap the AA pipe as well...
+                //mtlAAPgramPipe = mtlRenderPipe.traceWrap();
+            }
+            mtlAAPgramPipe = mtlRenderPipe.getAAParallelogramPipe();
+            mtlTxRenderPipe =
+                    new PixelToParallelogramConverter(mtlRenderPipe,
+                            mtlRenderPipe,
+                            1.0, 0.25, true);
+
+            MTLBlitLoops.register();
+            MTLMaskFill.register();
+            MTLMaskBlit.register();
+        }
+    }
+
+    protected final int scale;
+    protected final int width;
+    protected final int height;
+    protected CPlatformView pView;
+    protected int type;
+    private MTLGraphicsConfig graphicsConfig;
+    // these fields are set from the native code when the surface is
+    // initialized
+    private int nativeWidth;
+    private int nativeHeight;
+
+    /**
+     * Returns the appropriate SurfaceType corresponding to the given OpenGL
+     * surface type constant (e.g. TEXTURE -> MTLTexture).
+     */
+    private static SurfaceType getCustomSurfaceType(int oglType) {
+        switch (oglType) {
+            case TEXTURE:
+                return MTLTexture;
+            case RT_TEXTURE:
+                return MTLSurfaceRTT;
+            default:
+                return MTLSurface;
+        }
+    }
+
+    static void swapBuffers(long window) {
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            RenderBuffer buf = rq.getBuffer();
+            rq.ensureCapacityAndAlignment(12, 4);
+            buf.putInt(SWAP_BUFFERS);
+            buf.putLong(window);
+            rq.flushNow();
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    native void validate(int xoff, int yoff, int width, int height, boolean isOpaque);
+
+    private native void initOps(long pConfigInfo, long pPeerData, long layerPtr,
+                                int xoff, int yoff, boolean isOpaque);
+
+    protected MTLSurfaceData(MTLGraphicsConfig gc, ColorModel cm, int type,
+                             int width, int height) {
+        super(getCustomSurfaceType(type), cm);
+        this.graphicsConfig = gc;
+        this.type = type;
+        setBlitProxyKey(gc.getProxyKey());
+
+        // TEXTURE shouldn't be scaled, it is used for managed BufferedImages.
+        scale = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor();
+        this.width = width * scale;
+        this.height = height * scale;
+    }
+
+    protected MTLSurfaceData(CPlatformView pView, MTLGraphicsConfig gc,
+                             ColorModel cm, int type, int width, int height)
+    {
+        this(gc, cm, type, width, height);
+        this.pView = pView;
+        this.graphicsConfig = gc;
+
+        long pConfigInfo = gc.getNativeConfigInfo();
+        long pPeerData = 0L;
+        boolean isOpaque = true;
+        if (pView != null) {
+            pPeerData = pView.getAWTView();
+            isOpaque = pView.isOpaque();
+        }
+        MTLGraphicsConfig.refPConfigInfo(pConfigInfo);
+        initOps(pConfigInfo, pPeerData, 0, 0, 0, isOpaque);
+    }
+
+    protected MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
+                             ColorModel cm, int type, int width, int height)
+    {
+        this(gc, cm, type, width, height);
+        this.graphicsConfig = gc;
+
+        long pConfigInfo = gc.getNativeConfigInfo();
+        long layerPtr = 0L;
+        boolean isOpaque = true;
+        if (layer != null) {
+            layerPtr = layer.getPointer();
+            isOpaque = layer.isOpaque();
+        }
+        MTLGraphicsConfig.refPConfigInfo(pConfigInfo);
+        initOps(pConfigInfo, 0, layerPtr, 0, 0, isOpaque);
+    }
+
+    @Override //SurfaceData
+    public GraphicsConfiguration getDeviceConfiguration() {
+        return graphicsConfig;
+    }
+
+    /**
+     * Creates a SurfaceData object representing the primary (front) buffer of
+     * an on-screen Window.
+     */
+    public static MTLWindowSurfaceData createData(CPlatformView pView) {
+        MTLGraphicsConfig gc = getGC(pView);
+        return new MTLWindowSurfaceData(pView, gc);
+    }
+
+    /**
+     * Creates a SurfaceData object representing the intermediate buffer
+     * between the Java2D flusher thread and the AppKit thread.
+     */
+    public static MTLLayerSurfaceData createData(MTLLayer layer) {
+        MTLGraphicsConfig gc = getGC(layer);
+        Rectangle r = layer.getBounds();
+        return new MTLLayerSurfaceData(layer, gc, r.width, r.height);
+    }
+
+    /**
+     * Creates a SurfaceData object representing the back buffer of a
+     * double-buffered on-screen Window.
+     */
+    public static MTLOffScreenSurfaceData createData(CPlatformView pView,
+                                                     Image image, int type) {
+        MTLGraphicsConfig gc = getGC(pView);
+        Rectangle r = pView.getBounds();
+        if (type == FLIP_BACKBUFFER) {
+            return new MTLOffScreenSurfaceData(pView, gc, r.width, r.height,
+                    image, gc.getColorModel(), FLIP_BACKBUFFER);
+        } else {
+            return new MTLVSyncOffScreenSurfaceData(pView, gc, r.width,
+                    r.height, image, gc.getColorModel(), type);
+        }
+    }
+
+    /**
+     * Creates a SurfaceData object representing an off-screen buffer (either a
+     * FBO or Texture).
+     */
+    public static MTLOffScreenSurfaceData createData(MTLGraphicsConfig gc,
+                                                     int width, int height, ColorModel cm, Image image, int type) {
+        return new MTLOffScreenSurfaceData(null, gc, width, height, image, cm,
+                type);
+    }
+
+    public static MTLGraphicsConfig getGC(CPlatformView pView) {
+        if (pView != null) {
+            return (MTLGraphicsConfig)pView.getGraphicsConfiguration();
+        } else {
+            // REMIND: this should rarely (never?) happen, but what if
+            // default config is not CGL?
+            GraphicsEnvironment env = GraphicsEnvironment
+                    .getLocalGraphicsEnvironment();
+            GraphicsDevice gd = env.getDefaultScreenDevice();
+            return (MTLGraphicsConfig) gd.getDefaultConfiguration();
+        }
+    }
+
+    public static MTLGraphicsConfig getGC(MTLLayer layer) {
+        return (MTLGraphicsConfig)layer.getGraphicsConfiguration();
+    }
+
+    public void validate() {
+        // Overridden in MTLWindowSurfaceData below
+    }
+
+    @Override
+    public double getDefaultScaleX() {
+        return scale;
+    }
+
+    @Override
+    public double getDefaultScaleY() {
+        return scale;
+    }
+
+    protected native void clearWindow();
+
+    protected native boolean initTexture(long pData,
+                                         boolean isOpaque, boolean texNonPow2,
+                                         boolean texRect,
+                                         int width, int height);
+
+    protected native boolean initRTexture(long pData,
+                                          boolean isOpaque, boolean texNonPow2,
+                                          boolean texRect,
+                                          int width, int height);
+
+    protected native boolean initFlipBackbuffer(long pData);
+
+    @Override
+    public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
+        return MTLSurfaceDataProxy.createProxy(srcData, graphicsConfig);
+    }
+
+    /**
+     * Note: This should only be called from the QFT under the AWT lock.
+     * This method is kept separate from the initSurface() method below just
+     * to keep the code a bit cleaner.
+     */
+    private void initSurfaceNow(int width, int height) {
+        boolean isOpaque = (getTransparency() == Transparency.OPAQUE);
+        boolean success = false;
+
+        switch (type) {
+            case TEXTURE:
+                success = initTexture(getNativeOps(),
+                        isOpaque, isTexNonPow2Available(),
+                        isTexRectAvailable(),
+                        width, height);
+                break;
+
+            case RT_TEXTURE:
+                success = initRTexture(getNativeOps(),
+                        isOpaque, isTexNonPow2Available(),
+                        isTexRectAvailable(),
+                        width, height);
+                break;
+
+            case FLIP_BACKBUFFER:
+                success = initFlipBackbuffer(getNativeOps());
+                break;
+
+            default:
+                break;
+        }
+
+        if (!success) {
+            throw new OutOfMemoryError("can't create offscreen surface");
+        }
+    }
+
+    /**
+     * Initializes the appropriate OpenGL offscreen surface based on the value
+     * of the type parameter.  If the surface creation fails for any reason,
+     * an OutOfMemoryError will be thrown.
+     */
+    protected void initSurface(final int width, final int height) {
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            switch (type) {
+                case TEXTURE:
+                case RT_TEXTURE:
+                    // need to make sure the context is current before
+                    // creating the texture or fbobject
+                    MTLContext.setScratchSurface(graphicsConfig);
+                    break;
+                default:
+                    break;
+            }
+            rq.flushAndInvokeNow(new Runnable() {
+                public void run() {
+                    initSurfaceNow(width, height);
+                }
+            });
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    /**
+     * Returns the MTLContext for the GraphicsConfig associated with this
+     * surface.
+     */
+    public final MTLContext getContext() {
+        return graphicsConfig.getContext();
+    }
+
+    /**
+     * Returns the MTLGraphicsConfig associated with this surface.
+     */
+    final MTLGraphicsConfig getMTLGraphicsConfig() {
+        return graphicsConfig;
+    }
+
+    /**
+     * Returns one of the surface type constants defined above.
+     */
+    public final int getType() {
+        return type;
+    }
+
+    /**
+     * For now, we can only render LCD text if:
+     *   - the fragment shader extension is available, and
+     *   - the source color is opaque, and
+     *   - blending is SrcOverNoEa or disabled
+     *   - and the destination is opaque
+     *
+     * Eventually, we could enhance the native OGL text rendering code
+     * and remove the above restrictions, but that would require significantly
+     * more code just to support a few uncommon cases.
+     */
+    public boolean canRenderLCDText(SunGraphics2D sg2d) {
+        return
+                graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) &&
+                        sg2d.surfaceData.getTransparency() == Transparency.OPAQUE &&
+                        sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR &&
+                        (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY ||
+                                (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite)));
+    }
+
+    private boolean canHandleComposite(Composite c) {
+        if (c instanceof AlphaComposite) {
+            AlphaComposite ac = (AlphaComposite)c;
+
+            return ac.getRule() == AlphaComposite.SRC_OVER && ac.getAlpha() >= 1f;
+        }
+        return false;
+    }
+
+    public void validatePipe(SunGraphics2D sg2d) {
+        TextPipe textpipe;
+        boolean validated = false;
+
+        // MTLTextRenderer handles both AA and non-AA text, but
+        // only works with the following modes:
+        // (Note: For LCD text we only enter this code path if
+        // canRenderLCDText() has already validated that the mode is
+        // CompositeType.SrcNoEa (opaque color), which will be subsumed
+        // by the CompositeType.SrcNoEa (any color) test below.)
+
+        if (/* CompositeType.SrcNoEa (any color) */
+                (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&
+                        sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR)         ||
+
+                        /* CompositeType.SrcOver (any color) */
+                        (sg2d.compositeState == SunGraphics2D.COMP_ALPHA   &&
+                                sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
+                                (((AlphaComposite)sg2d.composite).getRule() ==
+                                        AlphaComposite.SRC_OVER))                                 ||
+
+                        /* CompositeType.Xor (any color) */
+                        (sg2d.compositeState == SunGraphics2D.COMP_XOR &&
+                                sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR))
+        {
+            textpipe = mtlTextPipe;
+        } else {
+            // do this to initialize textpipe correctly; we will attempt
+            // to override the non-text pipes below
+            super.validatePipe(sg2d);
+            textpipe = sg2d.textpipe;
+            validated = true;
+        }
+
+        PixelToParallelogramConverter txPipe = null;
+        MTLRenderer nonTxPipe = null;
+
+        if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
+            if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
+                if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) {
+                    txPipe = mtlTxRenderPipe;
+                    nonTxPipe = mtlRenderPipe;
+                }
+            } else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {
+                if (MTLPaints.isValid(sg2d)) {
+                    txPipe = mtlTxRenderPipe;
+                    nonTxPipe = mtlRenderPipe;
+                }
+                // custom paints handled by super.validatePipe() below
+            }
+        } else {
+            if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
+                if (graphicsConfig.isCapPresent(CAPS_PS30) &&
+                        (sg2d.imageComp == CompositeType.SrcOverNoEa ||
+                                sg2d.imageComp == CompositeType.SrcOver))
+                {
+                    if (!validated) {
+                        super.validatePipe(sg2d);
+                        validated = true;
+                    }
+                    PixelToParallelogramConverter aaConverter =
+                            new PixelToParallelogramConverter(sg2d.shapepipe,
+                                    mtlAAPgramPipe,
+                                    1.0/8.0, 0.499,
+                                    false);
+                    sg2d.drawpipe = aaConverter;
+                    sg2d.fillpipe = aaConverter;
+                    sg2d.shapepipe = aaConverter;
+                } else if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {
+                    // install the solid pipes when AA and XOR are both enabled
+                    txPipe = mtlTxRenderPipe;
+                    nonTxPipe = mtlRenderPipe;
+                }
+            }
+            // other cases handled by super.validatePipe() below
+        }
+
+        if (txPipe != null) {
+            if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
+                sg2d.drawpipe = txPipe;
+                sg2d.fillpipe = txPipe;
+            } else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {
+                sg2d.drawpipe = txPipe;
+                sg2d.fillpipe = nonTxPipe;
+            } else {
+                sg2d.drawpipe = nonTxPipe;
+                sg2d.fillpipe = nonTxPipe;
+            }
+            // Note that we use the transforming pipe here because it
+            // will examine the shape and possibly perform an optimized
+            // operation if it can be simplified.  The simplifications
+            // will be valid for all STROKE and TRANSFORM types.
+            sg2d.shapepipe = txPipe;
+        } else {
+            if (!validated) {
+                super.validatePipe(sg2d);
+            }
+        }
+
+        // install the text pipe based on our earlier decision
+        sg2d.textpipe = textpipe;
+
+        // always override the image pipe with the specialized OGL pipe
+        sg2d.imagepipe = mtlImagePipe;
+    }
+
+    @Override
+    protected MaskFill getMaskFill(SunGraphics2D sg2d) {
+        if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) {
+            /*
+             * We can only accelerate non-Color MaskFill operations if
+             * all of the following conditions hold true:
+             *   - there is an implementation for the given paintState
+             *   - the current Paint can be accelerated for this destination
+             *   - multitexturing is available (since we need to modulate
+             *     the alpha mask texture with the paint texture)
+             *
+             * In all other cases, we return null, in which case the
+             * validation code will choose a more general software-based loop.
+             */
+            if (!MTLPaints.isValid(sg2d) ||
+                    !graphicsConfig.isCapPresent(CAPS_MULTITEXTURE))
+            {
+                return null;
+            }
+        }
+        return super.getMaskFill(sg2d);
+    }
+
+    public void flush() {
+        invalidate();
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            // make sure we have a current context before
+            // disposing the native resources (e.g. texture object)
+            MTLContext.setScratchSurface(graphicsConfig);
+
+            RenderBuffer buf = rq.getBuffer();
+            rq.ensureCapacityAndAlignment(12, 4);
+            buf.putInt(FLUSH_SURFACE);
+            buf.putLong(getNativeOps());
+
+            // this call is expected to complete synchronously, so flush now
+            rq.flushNow();
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    /**
+     * Returns true if OpenGL textures can have non-power-of-two dimensions
+     * when using the basic GL_TEXTURE_2D target.
+     */
+    boolean isTexNonPow2Available() {
+        return graphicsConfig.isCapPresent(CAPS_TEXNONPOW2);
+    }
+
+    /**
+     * Returns true if OpenGL textures can have non-power-of-two dimensions
+     * when using the GL_TEXTURE_RECTANGLE_ARB target (only available when the
+     * GL_ARB_texture_rectangle extension is present).
+     */
+    boolean isTexRectAvailable() {
+        return graphicsConfig.isCapPresent(CAPS_EXT_TEXRECT);
+    }
+
+    /**
+     * Returns true if the surface is an on-screen window surface or
+     * a FBO texture attached to an on-screen CALayer.
+     *
+     * Needed by Mac OS X port.
+     */
+    public boolean isOnScreen() {
+        return getType() == WINDOW;
+    }
+
+    private native int getTextureTarget(long pData);
+
+    private native int getTextureID(long pData);
+
+    /**
+     * If this surface is backed by a texture object, returns the target
+     * for that texture (either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB).
+     * Otherwise, this method will return zero.
+     */
+    public final int getTextureTarget() {
+        return getTextureTarget(getNativeOps());
+    }
+
+    /**
+     * If this surface is backed by a texture object, returns the texture ID
+     * for that texture.
+     * Otherwise, this method will return zero.
+     */
+    public final int getTextureID() {
+        return getTextureID(getNativeOps());
+    }
+
+    /**
+     * Returns native resource of specified {@code resType} associated with
+     * this surface.
+     *
+     * Specifically, for {@code MTLSurfaceData} this method returns the
+     * the following:
+     * <pre>
+     * TEXTURE              - texture id
+     * </pre>
+     *
+     * Note: the resource returned by this method is only valid on the rendering
+     * thread.
+     *
+     * @return native resource of specified type or 0L if
+     * such resource doesn't exist or can not be retrieved.
+     * @see AccelSurface#getNativeResource
+     */
+    public long getNativeResource(int resType) {
+        if (resType == TEXTURE) {
+            return getTextureID();
+        }
+        return 0L;
+    }
+
+    public Raster getRaster(int x, int y, int w, int h) {
+        throw new InternalError("not implemented yet");
+    }
+
+    @Override
+    public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,
+                            int dx, int dy) {
+        if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) {
+            return false;
+        }
+        mtlRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy);
+        return true;
+    }
+
+    public Rectangle getNativeBounds() {
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            return new Rectangle(nativeWidth, nativeHeight);
+        } finally {
+            rq.unlock();
+        }
+    }
+
+    public static class MTLWindowSurfaceData extends MTLSurfaceData {
+
+        public MTLWindowSurfaceData(CPlatformView pView,
+                                    MTLGraphicsConfig gc) {
+            super(pView, gc, gc.getColorModel(), WINDOW, 0, 0);
+        }
+
+        @Override
+        public SurfaceData getReplacement() {
+            return pView.getSurfaceData();
+        }
+
+        @Override
+        public Rectangle getBounds() {
+            Rectangle r = pView.getBounds();
+            return new Rectangle(0, 0, r.width, r.height);
+        }
+
+        /**
+         * Returns destination Component associated with this SurfaceData.
+         */
+        @Override
+        public Object getDestination() {
+            return pView.getDestination();
+        }
+
+        public void validate() {
+            MTLRenderQueue rq = MTLRenderQueue.getInstance();
+            rq.lock();
+            try {
+                rq.flushAndInvokeNow(() -> {
+                    Rectangle peerBounds = pView.getBounds();
+                    validate(0, 0, peerBounds.width, peerBounds.height, pView.isOpaque());
+                });
+            } finally {
+                rq.unlock();
+            }
+        }
+
+        @Override
+        public void invalidate() {
+            super.invalidate();
+            clearWindow();
+        }
+    }
+
+    /**
+     * A surface which implements an intermediate buffer between
+     * the Java2D flusher thread and the AppKit thread.
+     *
+     * This surface serves as a buffer attached to a MTLLayer and
+     * the layer redirects all painting to the buffer's graphics.
+     */
+    public static class MTLLayerSurfaceData extends MTLSurfaceData {
+
+        private MTLLayer layer;
+
+        public MTLLayerSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
+                                   int width, int height) {
+            super(layer, gc, gc.getColorModel(), RT_TEXTURE, width, height);
+            this.layer = layer;
+            initSurface(this.width, this.height);
+        }
+
+        @Override
+        public SurfaceData getReplacement() {
+            return layer.getSurfaceData();
+        }
+
+        @Override
+        public boolean isOnScreen() {
+            return true;
+        }
+
+        @Override
+        public Rectangle getBounds() {
+            return new Rectangle(width, height);
+        }
+
+        @Override
+        public Object getDestination() {
+            return layer.getDestination();
+        }
+
+        @Override
+        public int getTransparency() {
+            return layer.getTransparency();
+        }
+
+        @Override
+        public void invalidate() {
+            super.invalidate();
+            clearWindow();
+        }
+    }
+
+    /**
+     * A surface which implements a v-synced flip back-buffer with COPIED
+     * FlipContents.
+     *
+     * This surface serves as a back-buffer to the outside world, while it is
+     * actually an offscreen surface. When the BufferStrategy this surface
+     * belongs to is showed, it is first copied to the real private
+     * FLIP_BACKBUFFER, which is then flipped.
+     */
+    public static class MTLVSyncOffScreenSurfaceData extends
+            MTLOffScreenSurfaceData {
+        private MTLOffScreenSurfaceData flipSurface;
+
+        public MTLVSyncOffScreenSurfaceData(CPlatformView pView,
+                                            MTLGraphicsConfig gc, int width, int height, Image image,
+                                            ColorModel cm, int type) {
+            super(pView, gc, width, height, image, cm, type);
+            flipSurface = MTLSurfaceData.createData(pView, image,
+                    FLIP_BACKBUFFER);
+        }
+
+        public SurfaceData getFlipSurface() {
+            return flipSurface;
+        }
+
+        @Override
+        public void flush() {
+            flipSurface.flush();
+            super.flush();
+        }
+    }
+
+    public static class MTLOffScreenSurfaceData extends MTLSurfaceData {
+        private Image offscreenImage;
+
+        public MTLOffScreenSurfaceData(CPlatformView pView,
+                                       MTLGraphicsConfig gc, int width, int height, Image image,
+                                       ColorModel cm, int type) {
+            super(pView, gc, cm, type, width, height);
+            offscreenImage = image;
+            initSurface(this.width, this.height);
+        }
+
+        @Override
+        public SurfaceData getReplacement() {
+            return restoreContents(offscreenImage);
+        }
+
+        @Override
+        public Rectangle getBounds() {
+            if (type == FLIP_BACKBUFFER) {
+                Rectangle r = pView.getBounds();
+                return new Rectangle(0, 0, r.width, r.height);
+            } else {
+                return new Rectangle(width, height);
+            }
+        }
+
+        /**
+         * Returns destination Image associated with this SurfaceData.
+         */
+        @Override
+        public Object getDestination() {
+            return offscreenImage;
+        }
+    }
+
+
+    // additional cleanup
+    private static native void destroyCGLContext(long ctx);
+
+    public static void destroyOGLContext(long ctx) {
+        if (ctx != 0L) {
+            destroyCGLContext(ctx);
+        }
+    }
+
+    public static void dispose(long pData, long pConfigInfo) {
+        MTLGraphicsConfig.deRefPConfigInfo(pConfigInfo);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceDataProxy.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.java2d.SurfaceData;
+import sun.java2d.SurfaceDataProxy;
+import sun.java2d.loops.CompositeType;
+
+import java.awt.*;
+
+/**
+ * The proxy class contains the logic for when to replace a
+ * SurfaceData with a cached OGL Texture and the code to create
+ * the accelerated surfaces.
+ */
+public class MTLSurfaceDataProxy extends SurfaceDataProxy {
+    public static SurfaceDataProxy createProxy(SurfaceData srcData,
+                                               MTLGraphicsConfig dstConfig)
+    {
+        if (srcData instanceof MTLSurfaceData) {
+            // srcData must be a VolatileImage which either matches
+            // our pixel format or not - either way we do not cache it...
+            return UNCACHED;
+        }
+
+        return new MTLSurfaceDataProxy(dstConfig, srcData.getTransparency());
+    }
+
+    MTLGraphicsConfig oglgc;
+    int transparency;
+
+    public MTLSurfaceDataProxy(MTLGraphicsConfig oglgc, int transparency) {
+        this.oglgc = oglgc;
+        this.transparency = transparency;
+    }
+
+    @Override
+    public SurfaceData validateSurfaceData(SurfaceData srcData,
+                                           SurfaceData cachedData,
+                                           int w, int h)
+    {
+        if (cachedData == null) {
+            try {
+                cachedData = oglgc.createManagedSurface(w, h, transparency);
+            } catch (OutOfMemoryError er) {
+                return null;
+            }
+        }
+        return cachedData;
+    }
+
+    @Override
+    public boolean isSupportedOperation(SurfaceData srcData,
+                                        int txtype,
+                                        CompositeType comp,
+                                        Color bgColor)
+    {
+        return comp.isDerivedFrom(CompositeType.AnyAlpha) &&
+                (bgColor == null || transparency == Transparency.OPAQUE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLTextRenderer.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011, 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.font.GlyphList;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.loops.GraphicsPrimitive;
+import sun.java2d.pipe.BufferedTextPipe;
+import sun.java2d.pipe.RenderQueue;
+
+import java.awt.*;
+
+class MTLTextRenderer extends BufferedTextPipe {
+
+    MTLTextRenderer(RenderQueue rq) {
+        super(rq);
+    }
+
+    @Override
+    protected native void drawGlyphList(int numGlyphs, boolean usePositions,
+                                        boolean subPixPos, boolean rgbOrder,
+                                        int lcdContrast,
+                                        float glOrigX, float glOrigY,
+                                        long[] images, float[] positions);
+
+    @Override
+    protected void validateContext(SunGraphics2D sg2d, Composite comp) {
+        // assert rq.lock.isHeldByCurrentThread();
+        MTLSurfaceData oglDst = (MTLSurfaceData)sg2d.surfaceData;
+        MTLContext.validateContext(oglDst, oglDst,
+                sg2d.getCompClip(), comp,
+                null, sg2d.paint, sg2d,
+                MTLContext.NO_CONTEXT_FLAGS);
+    }
+
+    MTLTextRenderer traceWrap() {
+        return new Tracer(this);
+    }
+
+    private static class Tracer extends MTLTextRenderer {
+        Tracer(MTLTextRenderer mtltr) {
+            super(mtltr.rq);
+        }
+        protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
+            GraphicsPrimitive.tracePrimitive("MTLDrawGlyphs");
+            super.drawGlyphList(sg2d, gl);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLUtilities.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2011, 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.pipe.Region;
+
+import java.awt.*;
+
+/**
+ * This class contains a number of static utility methods that may be
+ * called (via reflection) by a third-party library in order
+ * to interoperate with the metal-based Java 2D pipeline.
+ *
+ */
+class MTLUtilities {
+
+    /**
+     * These OGL-specific surface type constants are the same as those
+     * defined in the MTLSurfaceData class and are duplicated here so that
+     * clients of this API can access them more easily via reflection.
+     */
+    public static final int UNDEFINED       = MTLSurfaceData.UNDEFINED;
+    public static final int WINDOW          = MTLSurfaceData.WINDOW;
+    public static final int TEXTURE         = MTLSurfaceData.TEXTURE;
+    public static final int FLIP_BACKBUFFER = MTLSurfaceData.FLIP_BACKBUFFER;
+    public static final int RT_TEXTURE      = MTLSurfaceData.RT_TEXTURE;
+
+    private MTLUtilities() {
+    }
+
+    /**
+     * Returns true if the current thread is the OGL QueueFlusher thread.
+     */
+    public static boolean isQueueFlusherThread() {
+        return MTLRenderQueue.isQueueFlusherThread();
+    }
+
+    /**
+     * Invokes the given Runnable on the MTL QueueFlusher thread with the
+     * MTL context corresponding to the given Graphics object made
+     * current.  It is legal for MTL code executed in the given
+     * Runnable to change the current MTL context; it will be reset
+     * once the Runnable completes.  No guarantees are made as to the
+     * state of the MTL context of the Graphics object; for
+     *
+     * In order to avoid deadlock, it is important that the given Runnable
+     * does not attempt to acquire the AWT lock, as that will be handled
+     * automatically as part of the {@code rq.flushAndInvokeNow()} step.
+     *
+     * @param g the Graphics object for the corresponding destination surface;
+     * if null, the step making a context current to the destination surface
+     * will be skipped
+     * @param r the action to be performed on the QFT; cannot be null
+     * @return true if the operation completed successfully, or false if
+     * there was any problem making a context current to the surface
+     * associated with the given Graphics object
+     */
+    public static boolean invokeWithMTLContextCurrent(Graphics g, Runnable r) {
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            if (g != null) {
+                if (!(g instanceof SunGraphics2D)) {
+                    return false;
+                }
+                SurfaceData sData = ((SunGraphics2D)g).surfaceData;
+                if (!(sData instanceof MTLSurfaceData)) {
+                    return false;
+                }
+
+                // make a context current to the destination surface
+                MTLContext.validateContext((MTLSurfaceData)sData);
+            }
+
+            // invoke the given runnable on the QFT
+            rq.flushAndInvokeNow(r);
+
+            // invalidate the current context so that the next time we render
+            // with Java 2D, the context state will be completely revalidated
+            MTLContext.invalidateCurrentContext();
+        } finally {
+            rq.unlock();
+        }
+
+        return true;
+    }
+
+    /**
+     * Invokes the given Runnable on the MTL QueueFlusher thread with the
+     * "shared" MTL context (corresponding to the given
+     * GraphicsConfiguration object) made current.  This method is typically
+     * used when the Runnable needs a current context to complete its
+     * operation, but does not require that the context be made current to
+     * a particular surface.  For example, an application may call this
+     * method so that the given Runnable can query the OpenGL capabilities
+     * of the given GraphicsConfiguration, without making a context current
+     * to a dummy surface (or similar hacky techniques).
+     *
+     * In order to avoid deadlock, it is important that the given Runnable
+     * does not attempt to acquire the AWT lock, as that will be handled
+     * automatically as part of the {@code rq.flushAndInvokeNow()} step.
+     *
+     * @param config the GraphicsConfiguration object whose "shared"
+     * context will be made current during this operation; if this value is
+     * null or if MTL is not enabled for the GraphicsConfiguration, this
+     * method will return false
+     * @param r the action to be performed on the QFT; cannot be null
+     * @return true if the operation completed successfully, or false if
+     * there was any problem making the shared context current
+     */
+    public static boolean
+    invokeWithMTLSharedContextCurrent(GraphicsConfiguration config,
+                                      Runnable r)
+    {
+        if (!(config instanceof MTLGraphicsConfig)) {
+            return false;
+        }
+
+        MTLRenderQueue rq = MTLRenderQueue.getInstance();
+        rq.lock();
+        try {
+            // make the "shared" context current for the given GraphicsConfig
+            MTLContext.setScratchSurface((MTLGraphicsConfig)config);
+
+            // invoke the given runnable on the QFT
+            rq.flushAndInvokeNow(r);
+
+            // invalidate the current context so that the next time we render
+            // with Java 2D, the context state will be completely revalidated
+            MTLContext.invalidateCurrentContext();
+        } finally {
+            rq.unlock();
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the Rectangle describing the MTL viewport on the
+     * Java 2D surface associated with the given Graphics object and
+     * component width and height. When a third-party library is
+     * performing MTL rendering directly into the visible region of
+     * the associated surface, this viewport helps the application
+     * position the MTL output correctly on that surface.
+     *
+     * Note that the x/y values in the returned Rectangle object represent
+     * the lower-left corner of the viewport region, relative to the
+     * lower-left corner of the given surface.
+     *
+     * @param g the Graphics object for the corresponding destination surface;
+     * cannot be null
+     * @param componentWidth width of the component to be painted
+     * @param componentHeight height of the component to be painted
+     * @return a Rectangle describing the MTL viewport for the given
+     * destination surface and component dimensions, or null if the given
+     * Graphics object is invalid
+     */
+    public static Rectangle getMTLViewport(Graphics g,
+                                           int componentWidth,
+                                           int componentHeight)
+    {
+        if (!(g instanceof SunGraphics2D)) {
+            return null;
+        }
+
+        SunGraphics2D sg2d = (SunGraphics2D)g;
+        SurfaceData sData = sg2d.surfaceData;
+
+        // this is the upper-left origin of the region to be painted,
+        // relative to the upper-left origin of the surface
+        // (in Java2D coordinates)
+        int x0 = sg2d.transX;
+        int y0 = sg2d.transY;
+
+        // this is the lower-left origin of the region to be painted,
+        // relative to the lower-left origin of the surface
+        // (in OpenGL coordinates)
+        Rectangle surfaceBounds = sData.getBounds();
+        int x1 = x0;
+        int y1 = surfaceBounds.height - (y0 + componentHeight);
+
+        return new Rectangle(x1, y1, componentWidth, componentHeight);
+    }
+
+    /**
+     * Returns the Rectangle describing the MTL scissor box on the
+     * Java 2D surface associated with the given Graphics object.  When a
+     * third-party library is performing MTL rendering directly
+     * into the visible region of the associated surface, this scissor box
+     * must be set to avoid drawing over existing rendering results.
+     *
+     * Note that the x/y values in the returned Rectangle object represent
+     * the lower-left corner of the scissor region, relative to the
+     * lower-left corner of the given surface.
+     *
+     * @param g the Graphics object for the corresponding destination surface;
+     * cannot be null
+     * @return a Rectangle describing the MTL scissor box for the given
+     * Graphics object and corresponding destination surface, or null if the
+     * given Graphics object is invalid or the clip region is non-rectangular
+     */
+    public static Rectangle getOGLScissorBox(Graphics g) {
+        if (!(g instanceof SunGraphics2D)) {
+            return null;
+        }
+
+        SunGraphics2D sg2d = (SunGraphics2D)g;
+        SurfaceData sData = sg2d.surfaceData;
+        Region r = sg2d.getCompClip();
+        if (!r.isRectangular()) {
+            // caller probably doesn't know how to handle shape clip
+            // appropriately, so just return null (Swing currently never
+            // sets a shape clip, but that could change in the future)
+            return null;
+        }
+
+        // this is the upper-left origin of the scissor box relative to the
+        // upper-left origin of the surface (in Java 2D coordinates)
+        int x0 = r.getLoX();
+        int y0 = r.getLoY();
+
+        // this is the width and height of the scissor region
+        int w = r.getWidth();
+        int h = r.getHeight();
+
+        // this is the lower-left origin of the scissor box relative to the
+        // lower-left origin of the surface (in OpenGL coordinates)
+        Rectangle surfaceBounds = sData.getBounds();
+        int x1 = x0;
+        int y1 = surfaceBounds.height - (y0 + h);
+
+        return new Rectangle(x1, y1, w, h);
+    }
+
+    /**
+     * Returns an Object identifier for the Java 2D surface associated with
+     * the given Graphics object.  This identifier may be used to determine
+     * whether the surface has changed since the last invocation of this
+     * operation, and thereby whether the MTL state corresponding to the
+     * old surface must be destroyed and recreated.
+     *
+     * @param g the Graphics object for the corresponding destination surface;
+     * cannot be null
+     * @return an identifier for the surface associated with the given
+     * Graphics object, or null if the given Graphics object is invalid
+     */
+    public static Object getMTLSurfaceIdentifier(Graphics g) {
+        if (!(g instanceof SunGraphics2D)) {
+            return null;
+        }
+        return ((SunGraphics2D)g).surfaceData;
+    }
+
+    /**
+     * Returns one of the MTL-specific surface type constants (defined in
+     * this class), which describes the surface associated with the given
+     * Graphics object.
+     *
+     * @param g the Graphics object for the corresponding destination surface;
+     * cannot be null
+     * @return a constant that describes the surface associated with the
+     * given Graphics object; if the given Graphics object is invalid (i.e.
+     * is not associated with an OpenGL surface) this method will return
+     * {@code MTLUtilities.UNDEFINED}
+     */
+    public static int getMTLSurfaceType(Graphics g) {
+        if (!(g instanceof SunGraphics2D)) {
+            return UNDEFINED;
+        }
+        SurfaceData sData = ((SunGraphics2D)g).surfaceData;
+        if (!(sData instanceof MTLSurfaceData)) {
+            return UNDEFINED;
+        }
+        return ((MTLSurfaceData)sData).getType();
+    }
+
+    /**
+     * Returns the MTL texture target constant (either GL_TEXTURE_2D
+     * or GL_TEXTURE_RECTANGLE_ARB) for the surface associated with the
+     * given Graphics object.  This method is only useful for those surface
+     * types that are backed by an MTL texture, namely {@code TEXTURE},
+     * {@code RT_TEXTURE}, and (on Windows only) {@code PBUFFER}.
+     *
+     * @param g the Graphics object for the corresponding destination surface;
+     * cannot be null
+     * @return the texture target constant for the surface associated with the
+     * given Graphics object; if the given Graphics object is invalid (i.e.
+     * is not associated with an MTL surface), or the associated surface
+     * is not backed by an OpenGL texture, this method will return zero.
+     */
+    public static int getMTLTextureType(Graphics g) {
+        if (!(g instanceof SunGraphics2D)) {
+            return 0;
+        }
+        SurfaceData sData = ((SunGraphics2D)g).surfaceData;
+        if (!(sData instanceof MTLSurfaceData)) {
+            return 0;
+        }
+        return ((MTLSurfaceData)sData).getTextureTarget();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLVolatileSurfaceManager.java	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.awt.AWTAccessor;
+import sun.awt.AWTAccessor.ComponentAccessor;
+import sun.awt.image.SunVolatileImage;
+import sun.awt.image.VolatileSurfaceManager;
+import sun.java2d.BackBufferCapsProvider;
+import sun.java2d.SurfaceData;
+import sun.java2d.opengl.OGLSurfaceData;
+import sun.java2d.pipe.hw.ExtendedBufferCapabilities;
+
+import java.awt.*;
+import java.awt.image.ColorModel;
+import java.awt.peer.ComponentPeer;
+
+import static java.awt.BufferCapabilities.FlipContents.COPIED;
+//import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_EXT_FBOBJECT;
+import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.VSYNC_ON;
+
+public class MTLVolatileSurfaceManager extends VolatileSurfaceManager {
+
+    private final boolean accelerationEnabled;
+
+    public MTLVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
+        super(vImg, context);
+
+        /*
+         * We will attempt to accelerate this image only under the
+         * following conditions:
+         *   - the image is not bitmask AND the GraphicsConfig supports the FBO
+         *     extension
+         */
+        int transparency = vImg.getTransparency();
+        MTLGraphicsConfig gc = (MTLGraphicsConfig) vImg.getGraphicsConfig();
+        accelerationEnabled = true;
+                //gc.isCapPresent(CAPS_EXT_FBOBJECT)
+                //&& transparency != Transparency.BITMASK;
+    }
+
+    protected boolean isAccelerationEnabled() {
+        return accelerationEnabled;
+    }
+
+    /**
+     * Create a FBO-based SurfaceData object (or init the backbuffer
+     * of an existing window if this is a double buffered GraphicsConfig)
+     */
+    protected SurfaceData initAcceleratedSurface() {
+        SurfaceData sData = null;
+        Component comp = vImg.getComponent();
+        final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
+        final ComponentPeer peer = (comp != null) ? acc.getPeer(comp) : null;
+
+        try {
+            boolean createVSynced = false;
+            boolean forceback = false;
+            if (context instanceof Boolean) {
+                forceback = ((Boolean)context).booleanValue();
+                if (forceback && peer instanceof BackBufferCapsProvider) {
+                    BackBufferCapsProvider provider =
+                        (BackBufferCapsProvider)peer;
+                    BufferCapabilities caps = provider.getBackBufferCaps();
+                    if (caps instanceof ExtendedBufferCapabilities) {
+                        ExtendedBufferCapabilities ebc =
+                            (ExtendedBufferCapabilities)caps;
+                        if (ebc.getVSync() == VSYNC_ON &&
+                            ebc.getFlipContents() == COPIED)
+                        {
+                            createVSynced = true;
+                            forceback = false;
+                        }
+                    }
+                }
+            }
+
+            if (forceback) {
+                // peer must be non-null in this case
+                // TODO: modify parameter to delegate
+                //                sData = MTLSurfaceData.createData(peer, vImg, FLIP_BACKBUFFER);
+            } else {
+                MTLGraphicsConfig gc =
+                    (MTLGraphicsConfig)vImg.getGraphicsConfig();
+                ColorModel cm = gc.getColorModel(vImg.getTransparency());
+                int type = vImg.getForcedAccelSurfaceType();
+                // if acceleration type is forced (type != UNDEFINED) then
+                // use the forced type, otherwise choose RT_TEXTURE
+                if (type == OGLSurfaceData.UNDEFINED) {
+                    type = OGLSurfaceData.FBOBJECT;
+                }
+                if (createVSynced) {
+                    // TODO: modify parameter to delegate
+//                  sData = MTLSurfaceData.createData(peer, vImg, type);
+                } else {
+                    sData = MTLSurfaceData.createData(gc,
+                                                      vImg.getWidth(),
+                                                      vImg.getHeight(),
+                                                      cm, vImg, type);
+                }
+            }
+        } catch (NullPointerException ex) {
+            sData = null;
+        } catch (OutOfMemoryError er) {
+            sData = null;
+        }
+
+        return sData;
+    }
+
+    @Override
+    protected boolean isConfigValid(GraphicsConfiguration gc) {
+        return ((gc == null) || (gc == vImg.getGraphicsConfig()));
+    }
+
+    @Override
+    public void initContents() {
+        if (vImg.getForcedAccelSurfaceType() != OGLSurfaceData.TEXTURE) {
+            super.initContents();
+        }
+    }
+}
+
--- a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java	Thu Aug 22 17:57:55 2019 +0530
@@ -55,6 +55,7 @@
 import sun.java2d.pipe.hw.AccelTypedVolatileImage;
 import sun.java2d.pipe.hw.ContextCapabilities;
 import sun.lwawt.LWComponentPeer;
+import sun.lwawt.macosx.CFRetainedResource;
 import sun.lwawt.macosx.CPlatformView;
 
 import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_DOUBLEBUFFERED;
@@ -63,7 +64,7 @@
 import static sun.java2d.opengl.OGLSurfaceData.TEXTURE;
 
 public final class CGLGraphicsConfig extends CGraphicsConfig
-    implements OGLGraphicsConfig
+        implements OGLGraphicsConfig
 {
     //private static final int kOpenGLSwapInterval =
     // RuntimeOptions.getCurrentOptions().OpenGLSwapInterval;
@@ -110,7 +111,7 @@
         // add a record to the Disposer so that we destroy the native
         // CGLGraphicsConfigInfo data when this object goes away
         Disposer.addRecord(disposerReferent,
-                           new CGLGCDisposerRecord(pConfigInfo));
+                new CGLGCDisposerRecord(pConfigInfo));
     }
 
     @Override
@@ -121,9 +122,9 @@
     @Override
     public SurfaceData createManagedSurface(int w, int h, int transparency) {
         return CGLSurfaceData.createData(this, w, h,
-                                         getColorModel(transparency),
-                                         null,
-                                         OGLSurfaceData.TEXTURE);
+                getColorModel(transparency),
+                null,
+                OGLSurfaceData.TEXTURE);
     }
 
     public static CGLGraphicsConfig getConfig(CGraphicsDevice device,
@@ -194,27 +195,27 @@
     public BufferedImage createCompatibleImage(int width, int height) {
         ColorModel model = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
         WritableRaster
-            raster = model.createCompatibleWritableRaster(width, height);
+                raster = model.createCompatibleWritableRaster(width, height);
         return new BufferedImage(model, raster, model.isAlphaPremultiplied(),
-                                 null);
+                null);
     }
 
     @Override
     public ColorModel getColorModel(int transparency) {
         switch (transparency) {
-        case Transparency.OPAQUE:
-            // REMIND: once the ColorModel spec is changed, this should be
-            //         an opaque premultiplied DCM...
-            return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
-        case Transparency.BITMASK:
-            return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
-        case Transparency.TRANSLUCENT:
-            ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
-            return new DirectColorModel(cs, 32,
-                                        0xff0000, 0xff00, 0xff, 0xff000000,
-                                        true, DataBuffer.TYPE_INT);
-        default:
-            return null;
+            case Transparency.OPAQUE:
+                // REMIND: once the ColorModel spec is changed, this should be
+                //         an opaque premultiplied DCM...
+                return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
+            case Transparency.BITMASK:
+                return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
+            case Transparency.TRANSLUCENT:
+                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+                return new DirectColorModel(cs, 32,
+                        0xff0000, 0xff00, 0xff, 0xff000000,
+                        true, DataBuffer.TYPE_INT);
+            default:
+                return null;
         }
     }
 
@@ -264,8 +265,8 @@
     }
 
     @Override
-    public SurfaceData createSurfaceData(CGLLayer layer) {
-        return CGLSurfaceData.createData(layer);
+    public SurfaceData createSurfaceData(CFRetainedResource layer) {
+        return CGLSurfaceData.createData((CGLLayer) layer);
     }
 
     @Override
@@ -275,7 +276,7 @@
         ColorModel model = getColorModel(Transparency.OPAQUE);
         WritableRaster wr = model.createCompatibleWritableRaster(width, height);
         return new OffScreenImage(target, model, wr,
-                                  model.isAlphaPremultiplied());
+                model.isAlphaPremultiplied());
     }
 
     @Override
@@ -306,7 +307,7 @@
         final int w = Math.max(1, r.width);
         final int h = Math.max(1, r.height);
         final int transparency = peer.isTranslucent() ? Transparency.TRANSLUCENT
-                                                      : Transparency.OPAQUE;
+                : Transparency.OPAQUE;
         return new SunVolatileImage(this, w, h, transparency, null);
     }
 
@@ -332,7 +333,7 @@
             try {
                 bg.setBackground(peer.getBackground());
                 bg.clearRect(0, 0, backBuffer.getWidth(null),
-                             backBuffer.getHeight(null));
+                        backBuffer.getHeight(null));
             } finally {
                 bg.dispose();
             }
@@ -342,7 +343,7 @@
     private static class CGLBufferCaps extends BufferCapabilities {
         public CGLBufferCaps(boolean dblBuf) {
             super(imageCaps, imageCaps,
-                  dblBuf ? FlipContents.UNDEFINED : null);
+                    dblBuf ? FlipContents.UNDEFINED : null);
         }
     }
 
@@ -378,10 +379,10 @@
             return null;
         }
         SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,
-                                                          transparency, type);
+                transparency, type);
         Surface sd = vi.getDestSurface();
         if (!(sd instanceof AccelSurface) ||
-            ((AccelSurface)sd).getType() != type)
+                ((AccelSurface)sd).getType() != type)
         {
             vi.flush();
             vi = null;
@@ -398,12 +399,12 @@
     @Override
     public int getMaxTextureWidth() {
         return Math.max(maxTextureSize / getDevice().getScaleFactor(),
-                        getBounds().width);
+                getBounds().width);
     }
 
     @Override
     public int getMaxTextureHeight() {
         return Math.max(maxTextureSize / getDevice().getScaleFactor(),
-                        getBounds().height);
+                getBounds().height);
     }
 }
--- a/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java	Thu Aug 22 17:57:55 2019 +0530
@@ -77,8 +77,11 @@
 import sun.awt.image.SunVolatileImage;
 import sun.awt.image.ToolkitImage;
 import sun.java2d.SunGraphics2D;
+import sun.java2d.macos.MacOSFlags;
+import sun.java2d.metal.MTLRenderQueue;
 import sun.java2d.opengl.OGLRenderQueue;
 import sun.java2d.pipe.Region;
+import sun.java2d.pipe.RenderQueue;
 import sun.util.logging.PlatformLogger;
 
 public abstract class LWComponentPeer<T extends Component, D extends JComponent>
@@ -1434,7 +1437,8 @@
     }
 
     protected static final void flushOnscreenGraphics(){
-        final OGLRenderQueue rq = OGLRenderQueue.getInstance();
+        RenderQueue rq = MacOSFlags.isMetalEnabled() ?
+                MTLRenderQueue.getInstance() : OGLRenderQueue.getInstance();
         rq.lock();
         try {
             rq.flushNow();
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java	Thu Aug 22 17:57:55 2019 +0530
@@ -33,6 +33,9 @@
 
 import sun.awt.CGraphicsConfig;
 import sun.awt.CGraphicsEnvironment;
+import sun.java2d.macos.MacOSFlags;
+import sun.java2d.metal.MTLLayer;
+import sun.java2d.metal.MTLSurfaceData;
 import sun.lwawt.LWWindowPeer;
 
 import sun.java2d.SurfaceData;
@@ -48,7 +51,7 @@
 
     private LWWindowPeer peer;
     private SurfaceData surfaceData;
-    private CGLLayer windowLayer;
+    private CFRetainedResource windowLayer;
     private CPlatformResponder responder;
 
     public CPlatformView() {
@@ -59,7 +62,7 @@
         initializeBase(peer, responder);
 
         if (!LWCToolkit.getSunAwtDisableCALayers()) {
-            this.windowLayer = createCGLayer();
+            this.windowLayer = MacOSFlags.isMetalEnabled()? createMTLLayer() : createCGLayer();
         }
         setPtr(nativeCreateView(0, 0, 0, 0, getWindowLayerPtr()));
     }
@@ -68,6 +71,11 @@
         return new CGLLayer(peer);
     }
 
+    public MTLLayer createMTLLayer() {
+        return new MTLLayer(peer);
+    }
+
+
     protected void initializeBase(LWWindowPeer peer, CPlatformResponder responder) {
         this.peer = peer;
         this.responder = responder;
@@ -107,7 +115,10 @@
     // ----------------------------------------------------------------------
     public SurfaceData replaceSurfaceData() {
         if (!LWCToolkit.getSunAwtDisableCALayers()) {
-            surfaceData = windowLayer.replaceSurfaceData();
+            surfaceData = (MacOSFlags.isMetalEnabled()) ?
+                    ((MTLLayer)windowLayer).replaceSurfaceData() :
+                    ((CGLLayer)windowLayer).replaceSurfaceData()
+            ;
         } else {
             if (surfaceData == null) {
                 CGraphicsConfig graphicsConfig = (CGraphicsConfig)getGraphicsConfiguration();
@@ -121,7 +132,11 @@
 
     private void validateSurface() {
         if (surfaceData != null) {
-            ((CGLSurfaceData)surfaceData).validate();
+            if (MacOSFlags.isMetalEnabled()) {
+                ((MTLSurfaceData) surfaceData).validate();
+            } else {
+                ((CGLSurfaceData) surfaceData).validate();
+            }
         }
     }
 
@@ -143,7 +158,9 @@
 
     public long getWindowLayerPtr() {
         if (!LWCToolkit.getSunAwtDisableCALayers()) {
-            return windowLayer.getPointer();
+            return MacOSFlags.isMetalEnabled() ?
+                    ((MTLLayer)windowLayer).getPointer() :
+                    ((CGLLayer)windowLayer).getPointer();
         } else {
             return 0;
         }
@@ -211,18 +228,18 @@
 
         if (event.getType() == CocoaConstants.NSScrollWheel) {
             responder.handleScrollEvent(x, y, absX, absY, event.getModifierFlags(),
-                                        event.getScrollDeltaX(), event.getScrollDeltaY(),
-                                        event.getScrollPhase());
+                    event.getScrollDeltaX(), event.getScrollDeltaY(),
+                    event.getScrollPhase());
         } else {
             responder.handleMouseEvent(event.getType(), event.getModifierFlags(), event.getButtonNumber(),
-                                       event.getClickCount(), x, y,
-                                       absX, absY);
+                    event.getClickCount(), x, y,
+                    absX, absY);
         }
     }
 
     private void deliverKeyEvent(NSEvent event) {
         responder.handleKeyEvent(event.getType(), event.getModifierFlags(), event.getCharacters(),
-                                 event.getCharactersIgnoringModifiers(), event.getKeyCode(), true, false);
+                event.getCharactersIgnoringModifiers(), event.getKeyCode(), true, false);
     }
 
     /**
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Thu Aug 22 17:57:55 2019 +0530
@@ -62,6 +62,7 @@
 import sun.awt.AWTAccessor.ComponentAccessor;
 import sun.awt.AWTAccessor.WindowAccessor;
 import sun.java2d.SurfaceData;
+import sun.java2d.metal.MTLSurfaceData;
 import sun.java2d.opengl.CGLSurfaceData;
 import sun.lwawt.LWLightweightFramePeer;
 import sun.lwawt.LWToolkit;
@@ -78,7 +79,7 @@
     private static native void nativeSetNSWindowBounds(long nsWindowPtr, double x, double y, double w, double h);
     private static native void nativeSetNSWindowLocationByPlatform(long nsWindowPtr);
     private static native void nativeSetNSWindowStandardFrame(long nsWindowPtr,
-            double x, double y, double w, double h);
+                                                              double x, double y, double w, double h);
     private static native void nativeSetNSWindowMinMax(long nsWindowPtr, double minW, double minH, double maxW, double maxH);
     private static native void nativePushNSWindowToBack(long nsWindowPtr);
     private static native void nativePushNSWindowToFront(long nsWindowPtr);
@@ -153,7 +154,7 @@
     static final int FULL_WINDOW_CONTENT = 1 << 14;
 
     static final int _STYLE_PROP_BITMASK = DECORATED | TEXTURED | UNIFIED | UTILITY | HUD | SHEET | CLOSEABLE
-                                             | MINIMIZABLE | RESIZABLE | FULL_WINDOW_CONTENT;
+            | MINIMIZABLE | RESIZABLE | FULL_WINDOW_CONTENT;
 
     // corresponds to method-based properties
     static final int HAS_SHADOW = 1 << 10;
@@ -167,8 +168,8 @@
     static final int TRANSPARENT_TITLE_BAR = 1 << 18;
 
     static final int _METHOD_PROP_BITMASK = RESIZABLE | HAS_SHADOW | ZOOMABLE | ALWAYS_ON_TOP | HIDES_ON_DEACTIVATE
-                                              | DRAGGABLE_BACKGROUND | DOCUMENT_MODIFIED | FULLSCREENABLE
-                                              | TRANSPARENT_TITLE_BAR;
+            | DRAGGABLE_BACKGROUND | DOCUMENT_MODIFIED | FULLSCREENABLE
+            | TRANSPARENT_TITLE_BAR;
 
     // corresponds to callback-based properties
     static final int SHOULD_BECOME_KEY = 1 << 12;
@@ -188,68 +189,68 @@
 
     @SuppressWarnings({"unchecked", "rawtypes"})
     static ClientPropertyApplicator<JRootPane, CPlatformWindow> CLIENT_PROPERTY_APPLICATOR = new ClientPropertyApplicator<JRootPane, CPlatformWindow>(new Property[] {
-        new Property<CPlatformWindow>(WINDOW_DOCUMENT_MODIFIED) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            c.setStyleBits(DOCUMENT_MODIFIED, value == null ? false : Boolean.parseBoolean(value.toString()));
-        }},
-        new Property<CPlatformWindow>(WINDOW_BRUSH_METAL_LOOK) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            c.setStyleBits(TEXTURED, Boolean.parseBoolean(value.toString()));
-        }},
-        new Property<CPlatformWindow>(WINDOW_ALPHA) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            c.target.setOpacity(value == null ? 1.0f : Float.parseFloat(value.toString()));
-        }},
-        new Property<CPlatformWindow>(WINDOW_SHADOW) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            c.setStyleBits(HAS_SHADOW, value == null ? true : Boolean.parseBoolean(value.toString()));
-        }},
-        new Property<CPlatformWindow>(WINDOW_MINIMIZABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            c.setStyleBits(MINIMIZABLE, Boolean.parseBoolean(value.toString()));
-        }},
-        new Property<CPlatformWindow>(WINDOW_CLOSEABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            c.setStyleBits(CLOSEABLE, Boolean.parseBoolean(value.toString()));
-        }},
-        new Property<CPlatformWindow>(WINDOW_ZOOMABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            boolean zoomable = Boolean.parseBoolean(value.toString());
-            if (c.target instanceof RootPaneContainer
-                    && c.getPeer().getPeerType() == PeerType.FRAME) {
-                if (c.isInFullScreen && !zoomable) {
-                    c.toggleFullScreen();
+            new Property<CPlatformWindow>(WINDOW_DOCUMENT_MODIFIED) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                c.setStyleBits(DOCUMENT_MODIFIED, value == null ? false : Boolean.parseBoolean(value.toString()));
+            }},
+            new Property<CPlatformWindow>(WINDOW_BRUSH_METAL_LOOK) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                c.setStyleBits(TEXTURED, Boolean.parseBoolean(value.toString()));
+            }},
+            new Property<CPlatformWindow>(WINDOW_ALPHA) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                c.target.setOpacity(value == null ? 1.0f : Float.parseFloat(value.toString()));
+            }},
+            new Property<CPlatformWindow>(WINDOW_SHADOW) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                c.setStyleBits(HAS_SHADOW, value == null ? true : Boolean.parseBoolean(value.toString()));
+            }},
+            new Property<CPlatformWindow>(WINDOW_MINIMIZABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                c.setStyleBits(MINIMIZABLE, Boolean.parseBoolean(value.toString()));
+            }},
+            new Property<CPlatformWindow>(WINDOW_CLOSEABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                c.setStyleBits(CLOSEABLE, Boolean.parseBoolean(value.toString()));
+            }},
+            new Property<CPlatformWindow>(WINDOW_ZOOMABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                boolean zoomable = Boolean.parseBoolean(value.toString());
+                if (c.target instanceof RootPaneContainer
+                        && c.getPeer().getPeerType() == PeerType.FRAME) {
+                    if (c.isInFullScreen && !zoomable) {
+                        c.toggleFullScreen();
+                    }
+                }
+                c.setStyleBits(ZOOMABLE, zoomable);
+            }},
+            new Property<CPlatformWindow>(WINDOW_FULLSCREENABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                boolean fullscrenable = Boolean.parseBoolean(value.toString());
+                if (c.target instanceof RootPaneContainer
+                        && c.getPeer().getPeerType() == PeerType.FRAME) {
+                    if (c.isInFullScreen && !fullscrenable) {
+                        c.toggleFullScreen();
+                    }
+                }
+                c.setStyleBits(FULLSCREENABLE, fullscrenable);
+            }},
+            new Property<CPlatformWindow>(WINDOW_SHADOW_REVALIDATE_NOW) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                c.execute(ptr -> nativeRevalidateNSWindowShadow(ptr));
+            }},
+            new Property<CPlatformWindow>(WINDOW_DOCUMENT_FILE) { public void applyProperty(final CPlatformWindow c, final Object value) {
+                if (value == null || !(value instanceof java.io.File)) {
+                    c.execute(ptr->nativeSetNSWindowRepresentedFilename(ptr, null));
+                    return;
+                }
+
+                final String filename = ((java.io.File)value).getAbsolutePath();
+                c.execute(ptr->nativeSetNSWindowRepresentedFilename(ptr, filename));
+            }},
+            new Property<CPlatformWindow>(WINDOW_FULL_CONTENT) {
+                public void applyProperty(final CPlatformWindow c, final Object value) {
+                    boolean isFullWindowContent = Boolean.parseBoolean(value.toString());
+                    c.setStyleBits(FULL_WINDOW_CONTENT, isFullWindowContent);
+                }
+            },
+            new Property<CPlatformWindow>(WINDOW_TRANSPARENT_TITLE_BAR) {
+                public void applyProperty(final CPlatformWindow c, final Object value) {
+                    boolean isTransparentTitleBar = Boolean.parseBoolean(value.toString());
+                    c.setStyleBits(TRANSPARENT_TITLE_BAR, isTransparentTitleBar);
                 }
             }
-            c.setStyleBits(ZOOMABLE, zoomable);
-        }},
-        new Property<CPlatformWindow>(WINDOW_FULLSCREENABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            boolean fullscrenable = Boolean.parseBoolean(value.toString());
-            if (c.target instanceof RootPaneContainer
-                    && c.getPeer().getPeerType() == PeerType.FRAME) {
-                if (c.isInFullScreen && !fullscrenable) {
-                    c.toggleFullScreen();
-                }
-            }
-            c.setStyleBits(FULLSCREENABLE, fullscrenable);
-        }},
-        new Property<CPlatformWindow>(WINDOW_SHADOW_REVALIDATE_NOW) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            c.execute(ptr -> nativeRevalidateNSWindowShadow(ptr));
-        }},
-        new Property<CPlatformWindow>(WINDOW_DOCUMENT_FILE) { public void applyProperty(final CPlatformWindow c, final Object value) {
-            if (value == null || !(value instanceof java.io.File)) {
-                c.execute(ptr->nativeSetNSWindowRepresentedFilename(ptr, null));
-                return;
-            }
-
-            final String filename = ((java.io.File)value).getAbsolutePath();
-            c.execute(ptr->nativeSetNSWindowRepresentedFilename(ptr, filename));
-        }},
-        new Property<CPlatformWindow>(WINDOW_FULL_CONTENT) {
-            public void applyProperty(final CPlatformWindow c, final Object value) {
-                boolean isFullWindowContent = Boolean.parseBoolean(value.toString());
-                c.setStyleBits(FULL_WINDOW_CONTENT, isFullWindowContent);
-            }
-        },
-        new Property<CPlatformWindow>(WINDOW_TRANSPARENT_TITLE_BAR) {
-            public void applyProperty(final CPlatformWindow c, final Object value) {
-                boolean isTransparentTitleBar = Boolean.parseBoolean(value.toString());
-                c.setStyleBits(TRANSPARENT_TITLE_BAR, isTransparentTitleBar);
-            }
-        }
     }) {
         @SuppressWarnings("deprecation")
         public CPlatformWindow convertJComponentToTarget(final JRootPane p) {
@@ -332,16 +333,16 @@
             if (owner != null) {
                 hasOwnerPtr = 0L != owner.executeGet(ownerPtr -> {
                     ref.set(nativeCreateNSWindow(viewPtr, ownerPtr, styleBits,
-                                                    bounds.x, bounds.y,
-                                                    bounds.width, bounds.height));
+                            bounds.x, bounds.y,
+                            bounds.width, bounds.height));
                     return 1;
                 });
             }
 
             if (!hasOwnerPtr) {
                 ref.set(nativeCreateNSWindow(viewPtr, 0,
-                                             styleBits, bounds.x, bounds.y,
-                                             bounds.width, bounds.height));
+                        styleBits, bounds.x, bounds.y,
+                        bounds.width, bounds.height));
             }
         });
         setPtr(ref.get());
@@ -652,7 +653,7 @@
             if (visible) {
                 contentView.execute(viewPtr -> {
                     execute(ptr -> CWrapper.NSWindow.makeFirstResponder(ptr,
-                                                                        viewPtr));
+                            viewPtr));
                 });
 
                 boolean isPopup = (target.getType() == Window.Type.POPUP);
@@ -698,8 +699,8 @@
             bw.execute(blockerPtr -> {
                 execute(ptr -> {
                     CWrapper.NSWindow.orderWindow(ptr,
-                                                  CWrapper.NSWindow.NSWindowBelow,
-                                                  blockerPtr);
+                            CWrapper.NSWindow.NSWindowBelow,
+                            blockerPtr);
                 });
             });
         }
@@ -711,7 +712,7 @@
             Frame or Dialog is resizable.
             **/
             final boolean resizable = (target instanceof Frame) ? ((Frame)target).isResizable() :
-            ((target instanceof Dialog) ? ((Dialog)target).isResizable() : false);
+                    ((target instanceof Dialog) ? ((Dialog)target).isResizable() : false);
             if (resizable) {
                 setCanFullscreen(true);
             }
@@ -861,7 +862,7 @@
     public boolean rejectFocusRequest(FocusEvent.Cause cause) {
         // Cross-app activation requests are not allowed.
         if (cause != FocusEvent.Cause.MOUSE_EVENT &&
-            !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive())
+                !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive())
         {
             focusLogger.fine("the app is inactive, so the request is rejected");
             return true;
@@ -1056,6 +1057,8 @@
         SurfaceData surfaceData = getSurfaceData();
         if (surfaceData instanceof CGLSurfaceData) {
             ((CGLSurfaceData)surfaceData).validate();
+        } else if (surfaceData instanceof MTLSurfaceData) {
+            ((MTLSurfaceData)surfaceData).validate();
         }
     }
 
@@ -1102,7 +1105,7 @@
     }
 
     protected void deliverMoveResizeEvent(int x, int y, int width, int height,
-                                        boolean byUser) {
+                                          boolean byUser) {
         AtomicBoolean ref = new AtomicBoolean();
         execute(ptr -> {
             ref.set(CWrapper.NSWindow.isZoomed(ptr));
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java	Thu Aug 22 17:57:55 2019 +0530
@@ -29,6 +29,7 @@
 import sun.awt.IconInfo;
 import sun.java2d.SunGraphics2D;
 import sun.java2d.SurfaceData;
+import sun.java2d.metal.MTLLayer;
 import sun.java2d.opengl.CGLLayer;
 import sun.lwawt.LWWindowPeer;
 import sun.lwawt.PlatformEventNotifier;
@@ -222,8 +223,8 @@
                     owner.execute(ownerPtr -> {
                         execute(ptr -> {
                             CWrapper.NSWindow.orderWindow(ptr,
-                                                          CWrapper.NSWindow.NSWindowAbove,
-                                                          ownerPtr);
+                                    CWrapper.NSWindow.NSWindowAbove,
+                                    ownerPtr);
                         });
                     });
 
@@ -300,6 +301,23 @@
                     }
                 };
             }
+            public MTLLayer createMTLLayer() {
+                return new MTLLayer(null) {
+                    public Rectangle getBounds() {
+                        return CWarningWindow.this.getBounds();
+                    }
+
+                    public GraphicsConfiguration getGraphicsConfiguration() {
+                        LWWindowPeer peer = ownerPeer.get();
+                        return peer.getGraphicsConfiguration();
+                    }
+
+                    public boolean isOpaque() {
+                        return false;
+                    }
+                };
+            }
+
         };
     }
 
@@ -349,7 +367,7 @@
                 currentSize = newSize;
                 IconInfo ico = getSecurityIconInfo(currentSize, 0);
                 AWTAccessor.getWindowAccessor().setSecurityWarningSize(
-                    ownerWindow, ico.getWidth(), ico.getHeight());
+                        ownerWindow, ico.getWidth(), ico.getHeight());
             }
         }
     }
@@ -361,7 +379,7 @@
         }
 
         return new SunGraphics2D(sd, SystemColor.windowText, SystemColor.window,
-                                 ownerWindow.getFont());
+                ownerWindow.getFont());
     }
 
 
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Thu Aug 22 17:57:55 2019 +0530
@@ -109,6 +109,8 @@
 import sun.awt.SunToolkit;
 import sun.awt.datatransfer.DataTransferer;
 import sun.awt.util.ThreadGroupUtils;
+import sun.java2d.macos.MacOSFlags;
+import sun.java2d.metal.MTLRenderQueue;
 import sun.java2d.opengl.OGLRenderQueue;
 import sun.lwawt.LWComponentPeer;
 import sun.lwawt.LWCursorManager;
@@ -148,21 +150,21 @@
 
         ResourceBundle platformResources = java.security.AccessController.doPrivileged(
                 new java.security.PrivilegedAction<ResourceBundle>() {
-            @Override
-            public ResourceBundle run() {
-                ResourceBundle platformResources = null;
-                try {
-                    platformResources = ResourceBundle.getBundle("sun.awt.resources.awtosx");
-                } catch (MissingResourceException e) {
-                    // No resource file; defaults will be used.
-                }
+                    @Override
+                    public ResourceBundle run() {
+                        ResourceBundle platformResources = null;
+                        try {
+                            platformResources = ResourceBundle.getBundle("sun.awt.resources.awtosx");
+                        } catch (MissingResourceException e) {
+                            // No resource file; defaults will be used.
+                        }
 
-                System.loadLibrary("awt");
-                System.loadLibrary("fontmanager");
+                        System.loadLibrary("awt");
+                        System.loadLibrary("fontmanager");
 
-                return platformResources;
-            }
-        });
+                        return platformResources;
+                    }
+                });
 
         if (!GraphicsEnvironment.isHeadless() &&
             !PlatformGraphicsInfo.isInAquaSession())
@@ -210,9 +212,9 @@
     public static final int INACTIVE_SELECTION_BACKGROUND_COLOR = 1;
     public static final int INACTIVE_SELECTION_FOREGROUND_COLOR = 2;
     private static int[] appleColors = {
-        0xFF808080, // keyboardFocusColor = Color.gray;
-        0xFFC0C0C0, // secondarySelectedControlColor
-        0xFF303030, // controlDarkShadowColor
+            0xFF808080, // keyboardFocusColor = Color.gray;
+            0xFFC0C0C0, // secondarySelectedControlColor
+            0xFF303030, // controlDarkShadowColor
     };
 
     private native void loadNativeColors(final int[] systemColors, final int[] appleColors);
@@ -485,7 +487,11 @@
     @Override
     public void sync() {
         // flush the OGL pipeline (this is a no-op if OGL is not enabled)
-        OGLRenderQueue.sync();
+        if (MacOSFlags.isMetalEnabled()) {
+            MTLRenderQueue.sync();
+        } else {
+            OGLRenderQueue.sync();
+        }
         // setNeedsDisplay() selector was sent to the appropriate CALayer so now
         // we have to flush the native selectors queue.
         flushNativeSelectors();
@@ -635,7 +641,7 @@
         final boolean[] ret = new boolean[1];
 
         try {  invokeAndWait(new Runnable() { @Override
-                                              public void run() { synchronized(ret) {
+        public void run() { synchronized(ret) {
             ret[0] = a.equals(b);
         }}}, c); } catch (Exception e) { e.printStackTrace(); }
 
@@ -856,7 +862,7 @@
     public static synchronized boolean getSunAwtDisableCALayers() {
         if (sunAwtDisableCALayers == null) {
             sunAwtDisableCALayers = AccessController.doPrivileged(
-                new GetBooleanAction("sun.awt.disableCALayers"));
+                    new GetBooleanAction("sun.awt.disableCALayers"));
         }
         return sunAwtDisableCALayers;
     }
@@ -915,9 +921,9 @@
     @Override
     public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
         return (exclusionType == null) ||
-            (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
-            (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
-            (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
+                (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
+                (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
+                (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
     }
 
     @Override
@@ -925,10 +931,10 @@
         //TODO: FileDialog blocks excluded windows...
         //TODO: Test: 2 file dialogs, separate AppContexts: a) Dialog 1 blocked, shouldn't be. Frame 4 blocked (shouldn't be).
         return (modalityType == null) ||
-            (modalityType == Dialog.ModalityType.MODELESS) ||
-            (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
-            (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
-            (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
+                (modalityType == Dialog.ModalityType.MODELESS) ||
+                (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
+                (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
+                (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
     }
 
     @Override
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTSurfaceLayers.m	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTSurfaceLayers.m	Thu Aug 22 17:57:55 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -92,7 +92,7 @@
 
 /*
  * Class:     sun_lwawt_macosx_CPlatformComponent
- * Method:    nativeCreateLayer
+ * Method:    nativeCreateComponent
  * Signature: ()J
  */
 JNIEXPORT jlong JNICALL
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m	Thu Aug 22 17:57:55 2019 +0530
@@ -37,6 +37,8 @@
 #import <Carbon/Carbon.h>
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
 
+jboolean metalEnabled = JNI_FALSE;
+
 @interface AWTView()
 @property (retain) CDropTarget *_dropTarget;
 @property (retain) CDragSource *_dragSource;
@@ -52,6 +54,8 @@
 //#define IM_DEBUG TRUE
 //#define EXTRA_DEBUG
 
+#define METAL_DEBUG
+
 static BOOL shouldUsePressAndHold() {
     static int shouldUsePressAndHold = -1;
     if (shouldUsePressAndHold != -1) return shouldUsePressAndHold;
@@ -66,6 +70,7 @@
 @synthesize cglLayer;
 @synthesize mouseIsOver;
 
+
 // Note: Must be called on main (AppKit) thread only
 - (id) initWithRect: (NSRect) rect
        platformView: (jobject) cPlatformView
@@ -1477,3 +1482,19 @@
 
     return underMouse;
 }
+
+jboolean GetStaticBoolean(JNIEnv *env, jclass fClass, const char *fieldName)
+{
+    jfieldID fieldID = (*env)->GetStaticFieldID(env, fClass, fieldName, "Z");
+    return (*env)->GetStaticBooleanField(env, fClass, fieldID);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_java2d_macos_MacOSFlags_initNativeFlags(JNIEnv *env,
+                                                     jclass flagsClass)
+{
+  metalEnabled = GetStaticBoolean(env, flagsClass, "metalEnabled");
+#ifdef METAL_DEBUG
+  fprintf(stderr, "metalEnabled=%d\n", metalEnabled);
+#endif
+}
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Mon Aug 19 19:58:50 2019 +0200
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Thu Aug 22 17:57:55 2019 +0530
@@ -1171,6 +1171,8 @@
 JNF_COCOA_EXIT(env);
 }
 
+extern jboolean metalEnabled;
+
 /*
  * Class:     sun_lwawt_macosx_CPlatformWindow
  * Method:    nativeGetNSWindowInsets
@@ -1197,6 +1199,10 @@
     jint left = (jint)(contentRect.origin.x - frame.origin.x);
     jint bottom = (jint)(contentRect.origin.y - frame.origin.y);
     jint right = (jint)(frame.size.width - (contentRect.size.width + left));
+    if (metalEnabled == JNI_TRUE) {
+        bottom -= top;
+        top = 0;
+    }
 
     static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets");
     static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/common.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <simd/SIMD.h>
+
+#define PGRAM_VERTEX_COUNT 6
+#define QUAD_VERTEX_COUNT 4
+
+enum VertexAttributes {
+    VertexAttributePosition = 0,
+    VertexAttributeTexPos = 1
+};
+
+enum BufferIndex  {
+    MeshVertexBuffer = 0,
+    FrameUniformBuffer = 1,
+    MatrixBuffer = 2
+};
+
+struct FrameUniforms {
+    vector_float4 color;
+};
+
+struct TransformMatrix {
+    matrix_float4x4 transformMatrix;
+};
+
+struct GradFrameUniforms {
+    vector_float3 params;
+    vector_float4 color1;
+    vector_float4 color2;
+};
+
+struct Vertex {
+    float position[3];
+};
+
+struct TxtVertex {
+    float position[3];
+    float txtpos[2];
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/shaders.metal	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <simd/simd.h>
+#include <metal_stdlib>
+#include "common.h"
+
+using namespace metal;
+
+struct VertexInput {
+    float3 position [[attribute(VertexAttributePosition)]];
+};
+
+struct TxtVertexInput {
+    float3 position [[attribute(VertexAttributePosition)]];
+    float2 texCoords [[attribute(VertexAttributeTexPos)]];
+};
+
+struct ColShaderInOut {
+    float4 position [[position]];
+    half4  color;
+};
+
+struct TxtShaderInOut {
+    float4 position [[position]];
+    float2 texCoords;
+};
+
+struct GradShaderInOut {
+    float4 position [[position]];
+};
+
+vertex ColShaderInOut vert_col(VertexInput in [[stage_in]],
+       constant FrameUniforms& uniforms [[buffer(FrameUniformBuffer)]],
+       constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
+    ColShaderInOut out;
+    float4 pos4 = float4(in.position, 1.0);
+    out.position = transform.transformMatrix*pos4;
+    out.color = half4(uniforms.color.r, uniforms.color.g, uniforms.color.b, uniforms.color.a);
+    return out;
+}
+
+vertex GradShaderInOut vert_grad(VertexInput in [[stage_in]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
+    GradShaderInOut out;
+    float4 pos4 = float4(in.position, 1.0);
+    out.position = transform.transformMatrix*pos4;
+    return out;
+}
+
+vertex TxtShaderInOut vert_txt(TxtVertexInput in [[stage_in]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
+    TxtShaderInOut out;
+    float4 pos4 = float4(in.position, 1.0);
+    out.position = transform.transformMatrix*pos4;
+    out.texCoords = in.texCoords;
+    return out;
+}
+
+fragment half4 frag_col(ColShaderInOut in [[stage_in]]) {
+    return in.color;
+}
+
+fragment half4 frag_txt(
+        TxtShaderInOut vert [[stage_in]],
+        texture2d<float, access::sample> renderTexture [[texture(0)]]
+        )
+{
+    constexpr sampler textureSampler (mag_filter::linear,
+                                  min_filter::linear);
+    float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords);
+    return half4(pixelColor.r, pixelColor.g, pixelColor.b , pixelColor.a);
+}
+
+fragment half4 frag_grad(GradShaderInOut in [[stage_in]],
+                         constant GradFrameUniforms& uniforms [[buffer(0)]]) {
+    float3 v = float3(in.position.x, in.position.y, 1);
+    float  a = (dot(v,uniforms.params)-0.25)*2.0;
+    float4 c = mix(uniforms.color1, uniforms.color2, a);
+    return half4(c);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLBlitLoops_h_Included
+#define MTLBlitLoops_h_Included
+
+#include "sun_java2d_metal_MTLBlitLoops.h"
+#include "MTLSurfaceDataBase.h"
+#include "MTLContext.h"
+
+#define OFFSET_SRCTYPE sun_java2d_metal_MTLBlitLoops_OFFSET_SRCTYPE
+#define OFFSET_HINT    sun_java2d_metal_MTLBlitLoops_OFFSET_HINT
+#define OFFSET_TEXTURE sun_java2d_metal_MTLBlitLoops_OFFSET_TEXTURE
+#define OFFSET_RTT     sun_java2d_metal_MTLBlitLoops_OFFSET_RTT
+#define OFFSET_XFORM   sun_java2d_metal_MTLBlitLoops_OFFSET_XFORM
+#define OFFSET_ISOBLIT sun_java2d_metal_MTLBlitLoops_OFFSET_ISOBLIT
+
+void MTLBlitLoops_IsoBlit(JNIEnv *env,
+                          MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
+                          jboolean xform, jint hint,
+                          jboolean texture, jboolean rtt,
+                          jint sx1, jint sy1,
+                          jint sx2, jint sy2,
+                          jdouble dx1, jdouble dy1,
+                          jdouble dx2, jdouble dy2);
+
+void MTLBlitLoops_Blit(JNIEnv *env,
+                       MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
+                       jboolean xform, jint hint,
+                       jint srctype, jboolean texture,
+                       jint sx1, jint sy1,
+                       jint sx2, jint sy2,
+                       jdouble dx1, jdouble dy1,
+                       jdouble dx2, jdouble dy2);
+
+void MTLBlitLoops_SurfaceToSwBlit(JNIEnv *env, MTLContext *mtlc,
+                                  jlong pSrcOps, jlong pDstOps, jint dsttype,
+                                  jint srcx, jint srcy,
+                                  jint dstx, jint dsty,
+                                  jint width, jint height);
+
+void MTLBlitLoops_CopyArea(JNIEnv *env,
+                           MTLContext *mtlc, BMTLSDOps *dstOps,
+                           jint x, jint y,
+                           jint width, jint height,
+                           jint dx, jint dy);
+
+void MTLBlitTex2Tex(MTLContext *mtlc, id<MTLTexture> src, id<MTLTexture> dest);
+
+#endif /* MTLBlitLoops_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef HEADLESS
+
+#include <jni.h>
+#include <jlong.h>
+
+#include "SurfaceData.h"
+#include "MTLBlitLoops.h"
+#include "MTLRenderQueue.h"
+#include "MTLSurfaceData.h"
+#include "MTLUtils.h"
+#include "GraphicsPrimitiveMgr.h"
+
+#include <stdlib.h> // malloc
+#include <string.h> // memcpy
+#include "IntArgbPre.h"
+
+extern MTLPixelFormat PixelFormats[];
+extern void J2dTraceImpl(int level, jboolean cr, const char *string, ...);
+
+void fillTxQuad(
+        struct TxtVertex * txQuadVerts,
+        jint sx1, jint sy1, jint sx2, jint sy2, jint sw, jint sh,
+        jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2, jdouble dw, jdouble dh
+) {
+    const float nsx1 = sx1/(float)sw;
+    const float nsy1 = sy1/(float)sh;
+    const float nsx2 = sx2/(float)sw;
+    const float nsy2 = sy2/(float)sh;
+
+    txQuadVerts[0].position[0] = dx1;
+    txQuadVerts[0].position[1] = dy1;
+    txQuadVerts[0].position[2] = 0;
+    txQuadVerts[0].txtpos[0]   = nsx1;
+    txQuadVerts[0].txtpos[1]   = nsy1;
+
+    txQuadVerts[1].position[0] = dx2;
+    txQuadVerts[1].position[1] = dy1;
+    txQuadVerts[1].position[2] = 0;
+    txQuadVerts[1].txtpos[0]   = nsx2;
+    txQuadVerts[1].txtpos[1]   = nsy1;
+
+    txQuadVerts[2].position[0] = dx2;
+    txQuadVerts[2].position[1] = dy2;
+    txQuadVerts[2].position[2] = 0;
+    txQuadVerts[2].txtpos[0]   = nsx2;
+    txQuadVerts[2].txtpos[1]   = nsy2;
+
+    txQuadVerts[3].position[0] = dx2;
+    txQuadVerts[3].position[1] = dy2;
+    txQuadVerts[3].position[2] = 0;
+    txQuadVerts[3].txtpos[0]   = nsx2;
+    txQuadVerts[3].txtpos[1]   = nsy2;
+
+    txQuadVerts[4].position[0] = dx1;
+    txQuadVerts[4].position[1] = dy2;
+    txQuadVerts[4].position[2] = 0;
+    txQuadVerts[4].txtpos[0]   = nsx1;
+    txQuadVerts[4].txtpos[1]   = nsy2;
+
+    txQuadVerts[5].position[0] = dx1;
+    txQuadVerts[5].position[1] = dy1;
+    txQuadVerts[5].position[2] = 0;
+    txQuadVerts[5].txtpos[0]   = nsx1;
+    txQuadVerts[5].txtpos[1]   = nsy1;
+}
+
+/**
+ * Inner loop used for copying a source MTL "Surface" (window, pbuffer,
+ * etc.) to a destination OpenGL "Surface".  Note that the same surface can
+ * be used as both the source and destination, as is the case in a copyArea()
+ * operation.  This method is invoked from MTLBlitLoops_IsoBlit() as well as
+ * MTLBlitLoops_CopyArea().
+ *
+ * The standard glCopyPixels() mechanism is used to copy the source region
+ * into the destination region.  If the regions have different dimensions,
+ * the source will be scaled into the destination as appropriate (only
+ * nearest neighbor filtering will be applied for simple scale operations).
+ */
+static void
+MTLBlitSurfaceToSurface(MTLContext *mtlc, BMTLSDOps *srcOps, BMTLSDOps *dstOps,
+                        jint sx1, jint sy1, jint sx2, jint sy2,
+                        jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitSurfaceToSurface -- :TODO");
+}
+
+static void drawTex2Tex(MTLContext *mtlc,
+                        id<MTLTexture> src, id<MTLTexture> dst,
+                        jboolean rtt, jint hint,
+                        jint sx1, jint sy1, jint sx2, jint sy2,
+                        jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+    if (mtlc == NULL || src == nil || dst == nil)
+        return;
+
+//    J2dTraceLn2(J2D_TRACE_VERBOSE, "_drawTex2Tex: src tex=%p, dst tex=%p", src, dst);
+//    J2dTraceLn4(J2D_TRACE_VERBOSE, "  sw=%d sh=%d dw=%d dh=%d", src.width, src.height, dst.width, dst.height);
+//    J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx1=%d sy1=%d sx2=%d sy2=%d", sx1, sy1, sx2, sy2);
+//    J2dTraceLn4(J2D_TRACE_VERBOSE, "  dx1=%f dy1=%f dx2=%f dy2=%f", dx1, dy1, dx2, dy2);
+
+    id<MTLRenderCommandEncoder> encoder = [mtlc createSamplingEncoderForDest:dst];
+
+
+    const jboolean normalize = !mtlc.useTransform;
+    struct TxtVertex quadTxVerticesBuffer[6];
+    fillTxQuad(quadTxVerticesBuffer, sx1, sy1, sx2, sy2, src.width, src.height, dx1, dy1, dx2, dy2, dst.width, dst.height);
+
+    [encoder setVertexBytes:quadTxVerticesBuffer length:sizeof(quadTxVerticesBuffer) atIndex:MeshVertexBuffer];
+    [encoder setFragmentTexture:src atIndex: 0];
+    [encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
+    [encoder endEncoding];
+}
+
+/**
+ * Inner loop used for copying a source MTL "Texture" to a destination
+ * MTL "Surface".  This method is invoked from MTLBlitLoops_IsoBlit().
+ *
+ * This method will copy, scale, or transform the source texture into the
+ * destination depending on the transform state, as established in
+ * and MTLContext_SetTransform().  If the source texture is
+ * transformed in any way when rendered into the destination, the filtering
+ * method applied is determined by the hint parameter (can be GL_NEAREST or
+ * GL_LINEAR).
+ */
+static void
+MTLBlitTextureToSurface(MTLContext *mtlc,
+                        BMTLSDOps *srcOps, BMTLSDOps *dstOps,
+                        jboolean rtt, jint hint,
+                        jint sx1, jint sy1, jint sx2, jint sy2,
+                        jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+    id<MTLTexture> srcTex = srcOps->pTexture;
+
+#ifdef DEBUG
+    J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_IsoBlit [via sampling]: bsrc=%p [tex=%p], bdst=%p [tex=%p] | s (%dx%d) -> d (%dx%d) | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", srcOps, srcOps->pTexture, dstOps, dstOps->pTexture, srcTex.width, srcTex.height, dstOps->width, dstOps->height, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
+#endif //DEBUG
+
+    drawTex2Tex(mtlc, srcOps->pTexture, dstOps->pTexture, rtt, hint, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
+}
+
+/**
+ * Inner loop used for copying a source system memory ("Sw") surface to a
+ * destination MTL "Surface".  This method is invoked from
+ * MTLBlitLoops_Blit().
+ *
+ * The standard glDrawPixels() mechanism is used to copy the source region
+ * into the destination region.  If the regions have different
+ * dimensions, the source will be scaled into the destination
+ * as appropriate (only nearest neighbor filtering will be applied for simple
+ * scale operations).
+ */
+
+static void
+MTLBlitSwToSurfaceViaTexture(MTLContext *ctx, SurfaceDataRasInfo *srcInfo, BMTLSDOps * bmtlsdOps,
+                   MTPixelFormat *pf,
+                   jint sx1, jint sy1, jint sx2, jint sy2,
+                   jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+    if (bmtlsdOps == NULL || bmtlsdOps->pTexture == NULL) {
+        J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitSwToSurfaceViaTexture: dest is null");
+        return;
+    }
+
+    const int sw = sx2 - sx1;
+    const int sh = sy2 - sy1;
+    id<MTLTexture> dest = bmtlsdOps->pTexture;
+
+#ifdef DEBUG
+    J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_Blit [via pooled texture]: bdst=%p [tex=%p], sw=%d, sh=%d | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", bmtlsdOps, dest, sw, sh, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
+#endif //DEBUG
+
+    id<MTLTexture> texBuff = [ctx.texturePool getTexture:sw height:sh format:MTLPixelFormatBGRA8Unorm];
+    if (texBuff == nil) {
+        J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitSwToSurfaceViaTexture: can't obtain temporary texture object from pool");
+        return;
+    }
+    MTLRegion region = MTLRegionMake2D(0, 0, sw, sh);
+    [texBuff replaceRegion:region mipmapLevel:0 withBytes:srcInfo->rasBase bytesPerRow:srcInfo->scanStride]; // texBuff is locked for current frame
+
+    drawTex2Tex(ctx, texBuff, dest, 0, 0, 0, 0, sw, sh, dx1, dy1, dx2, dy2);
+}
+
+/**
+ * Inner loop used for copying a source system memory ("Sw") surface or
+ * MTL "Surface" to a destination OpenGL "Surface", using an MTL texture
+ * tile as an intermediate surface.  This method is invoked from
+ * MTLBlitLoops_Blit() for "Sw" surfaces and MTLBlitLoops_IsoBlit() for
+ * "Surface" surfaces.
+ *
+ * This method is used to transform the source surface into the destination.
+ * Pixel rectangles cannot be arbitrarily transformed (without the
+ * GL_EXT_pixel_transform extension, which is not supported on most modern
+ * hardware).  However, texture mapped quads do respect the GL_MODELVIEW
+ * transform matrix, so we use textures here to perform the transform
+ * operation.  This method uses a tile-based approach in which a small
+ * subregion of the source surface is copied into a cached texture tile.  The
+ * texture tile is then mapped into the appropriate location in the
+ * destination surface.
+ *
+ * REMIND: this only works well using GL_NEAREST for the filtering mode
+ *         (GL_LINEAR causes visible stitching problems between tiles,
+ *         but this can be fixed by making use of texture borders)
+ */
+static void
+MTLBlitToSurfaceViaTexture(MTLContext *mtlc, SurfaceDataRasInfo *srcInfo,
+                           MTPixelFormat *pf, MTLSDOps *srcOps,
+                           jboolean swsurface, jint hint,
+                           jint sx1, jint sy1, jint sx2, jint sy2,
+                           jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitToSurfaceViaTexture -- :TODO");
+}
+
+/**
+ * Inner loop used for copying a source system memory ("Sw") surface to a
+ * destination OpenGL "Texture".  This method is invoked from
+ * MTLBlitLoops_Blit().
+ *
+ * The source surface is effectively loaded into the MTL texture object,
+ * which must have already been initialized by MTLSD_initTexture().  Note
+ * that this method is only capable of copying the source surface into the
+ * destination surface (i.e. no scaling or general transform is allowed).
+ * This restriction should not be an issue as this method is only used
+ * currently to cache a static system memory image into an MTL texture in
+ * a hidden-acceleration situation.
+ */
+static void
+MTLBlitSwToTexture(SurfaceDataRasInfo *srcInfo, MTPixelFormat *pf,
+                   MTLSDOps *dstOps,
+                   jint dx1, jint dy1, jint dx2, jint dy2)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitSwToTexture -- :TODO");
+}
+
+/**
+ * General blit method for copying a native MTL surface (of type "Surface"
+ * or "Texture") to another MTL "Surface".  If texture is JNI_TRUE, this
+ * method will invoke the Texture->Surface inner loop; otherwise, one of the
+ * Surface->Surface inner loops will be invoked, depending on the transform
+ * state.
+ *
+ * REMIND: we can trick these blit methods into doing XOR simply by passing
+ *         in the (pixel ^ xorpixel) as the pixel value and preceding the
+ *         blit with a fillrect...
+ */
+void
+MTLBlitLoops_IsoBlit(JNIEnv *env,
+                     MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
+                     jboolean xform, jint hint,
+                     jboolean texture, jboolean rtt,
+                     jint sx1, jint sy1, jint sx2, jint sy2,
+                     jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+    BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrcOps);
+    BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDstOps);
+
+    RETURN_IF_NULL(srcOps);
+    RETURN_IF_NULL(dstOps);
+
+    id<MTLTexture> srcTex = srcOps->pTexture;
+    id<MTLTexture> dstTex = dstOps->pTexture;
+    if (mtlc == NULL || srcTex == nil || srcTex == nil) {
+        J2dTraceLn2(J2D_TRACE_ERROR, "MTLBlitLoops_IsoBlit: surface is null (stex=%p, dtex=%p)", srcTex, dstTex);
+        return;
+    }
+
+    const jint sw    = sx2 - sx1;
+    const jint sh    = sy2 - sy1;
+    const jdouble dw = dx2 - dx1;
+    const jdouble dh = dy2 - dy1;
+
+    if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {
+        J2dTraceLn4(J2D_TRACE_WARNING, "MTLBlitLoops_IsoBlit: invalid dimensions: sw=%d, sh%d, dw=%d, dh=%d", sw, sh, dw, dh);
+        return;
+    }
+
+    SurfaceDataRasInfo srcInfo;
+    srcInfo.bounds.x1 = sx1;
+    srcInfo.bounds.y1 = sy1;
+    srcInfo.bounds.x2 = sx2;
+    srcInfo.bounds.y2 = sy2;
+    SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds, 0, 0, srcOps->width, srcOps->height);
+
+    if (srcInfo.bounds.x2 <= srcInfo.bounds.x1 || srcInfo.bounds.y2 <= srcInfo.bounds.y1) {
+        J2dTraceLn(J2D_TRACE_VERBOSE, "MTLBlitLoops_IsoBlit: source rectangle doesn't intersect with source surface bounds");
+        J2dTraceLn6(J2D_TRACE_VERBOSE, "  sx1=%d sy1=%d sx2=%d sy2=%d sw=%d sh=%d", sx1, sy1, sx2, sy2, srcOps->width, srcOps->height);
+        J2dTraceLn4(J2D_TRACE_VERBOSE, "  dx1=%f dy1=%f dx2=%f dy2=%f", dx1, dy1, dx2, dy2);
+        return;
+    }
+
+    if (srcInfo.bounds.x1 != sx1) {
+        dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
+        sx1 = srcInfo.bounds.x1;
+    }
+    if (srcInfo.bounds.y1 != sy1) {
+        dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
+        sy1 = srcInfo.bounds.y1;
+    }
+    if (srcInfo.bounds.x2 != sx2) {
+        dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
+        sx2 = srcInfo.bounds.x2;
+    }
+    if (srcInfo.bounds.y2 != sy2) {
+        dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
+        sy2 = srcInfo.bounds.y2;
+    }
+
+    const jboolean useBlitEncoder =
+            mtlc.isBlendingDisabled
+            && fabs(dx2 - dx1 - sx2 + sx1) < 0.001f && fabs(dy2 - dy1 - sy2 + sy1) < 0.001f // dimensions are equal (TODO: check that dx1,dy1 is integer)
+            && !mtlc.useTransform; // TODO: check whether transform is simple translate (and use blitEncoder in this case)
+    if (useBlitEncoder) {
+#ifdef DEBUG
+        J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_IsoBlit [via blitEncoder]: bdst=%p [tex=%p] %dx%d | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", dstOps, dstTex, dstTex.width, dstTex.height, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
+#endif //DEBUG
+        id <MTLBlitCommandEncoder> blitEncoder = [mtlc createBlitEncoder];
+        [blitEncoder copyFromTexture:srcTex sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(sx1, sy1, 0) sourceSize:MTLSizeMake(mtlc.clipRect.width, mtlc.clipRect.height, 1) toTexture:dstTex destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(dx1, dy1, 0)];
+        [blitEncoder endEncoding];
+    } else {
+        // TODO: support other flags
+        MTLBlitTextureToSurface(mtlc, srcOps, dstOps, rtt, hint, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
+    }
+}
+
+/**
+ * General blit method for copying a system memory ("Sw") surface to a native
+ * MTL surface (of type "Surface" or "Texture").  If texture is JNI_TRUE,
+ * this method will invoke the Sw->Texture inner loop; otherwise, one of the
+ * Sw->Surface inner loops will be invoked, depending on the transform state.
+ */
+void
+MTLBlitLoops_Blit(JNIEnv *env,
+                  MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
+                  jboolean xform, jint hint,
+                  jint srctype, jboolean texture,
+                  jint sx1, jint sy1, jint sx2, jint sy2,
+                  jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+    RETURN_IF_NULL(jlong_to_ptr(pSrcOps));
+    RETURN_IF_NULL(jlong_to_ptr(pDstOps));
+
+    SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
+    BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDstOps);
+    SurfaceDataRasInfo srcInfo;
+    MTLPixelFormat pf = MTLPixelFormatBGRA8Unorm;//PixelFormats[srctype];
+
+    if (dstOps == NULL || dstOps->pTexture == NULL) {
+        J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: dest is null");
+        return;
+    }
+    id<MTLTexture> dest = dstOps->pTexture;
+    if (dx1 < 0) {
+        sx1 += dx1;
+        dx1 = 0;
+    }
+    if (dx2 > dest.width) {
+        sx2 -= dx2 - dest.width;
+        dx2 = dest.width;
+    }
+    if (dy1 < 0) {
+        sy1 += dy1;
+        dy1 = 0;
+    }
+    if (dy2 > dest.height) {
+        sy2 -= dy2 - dest.height;
+        dy2 = dest.height;
+    }
+    jint sw    = sx2 - sx1;
+    jint sh    = sy2 - sy1;
+    jdouble dw = dx2 - dx1;
+    jdouble dh = dy2 - dy1;
+
+    if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0 || srctype < 0) {
+        J2dTraceLn(J2D_TRACE_WARNING, "MTLBlitLoops_Blit: invalid dimensions or srctype");
+        return;
+    }
+
+    srcInfo.bounds.x1 = sx1;
+    srcInfo.bounds.y1 = sy1;
+    srcInfo.bounds.x2 = sx2;
+    srcInfo.bounds.y2 = sy2;
+
+    if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
+        J2dTraceLn(J2D_TRACE_WARNING, "MTLBlitLoops_Blit: could not acquire lock");
+        return;
+    }
+
+    J2dTraceLn5(J2D_TRACE_VERBOSE, "MTLBlitLoops_Blit:  pf=%d texture=%d srctype=%d xform=%d hint=%d", pf, texture, srctype, xform, hint);
+
+    if (srcInfo.bounds.x2 > srcInfo.bounds.x1 && srcInfo.bounds.y2 > srcInfo.bounds.y1) {
+        srcOps->GetRasInfo(env, srcOps, &srcInfo);
+        if (srcInfo.rasBase) {
+            if (srcInfo.bounds.x1 != sx1) {
+                dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
+                sx1 = srcInfo.bounds.x1;
+            }
+            if (srcInfo.bounds.y1 != sy1) {
+                dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
+                sy1 = srcInfo.bounds.y1;
+            }
+            if (srcInfo.bounds.x2 != sx2) {
+                dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
+                sx2 = srcInfo.bounds.x2;
+            }
+            if (srcInfo.bounds.y2 != sy2) {
+                dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
+                sy2 = srcInfo.bounds.y2;
+            }
+
+            // NOTE: if (texture) => dest coordinates will always be integers since we only ever do a straight copy from sw to texture.
+            const jboolean useReplaceRegion = texture ||
+                    (mtlc.isBlendingDisabled
+                    && fabs(dx2 - dx1 - sx2 + sx1) < 0.001f && fabs(dy2 - dy1 - sy2 + sy1) < 0.001f // dimensions are equal (TODO: check that dx1,dy1 is integer)
+                    && !mtlc.useTransform); // TODO: check whether transform is simple translate (and use replaceRegion in this case)
+            if (useReplaceRegion) {
+                MTLRegion region = MTLRegionMake2D(dx1, dy1, dx2 - dx1, dy2 - dy1);
+#ifdef DEBUG
+                J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_Blit [replaceRegion]: bdst=%p [tex=%p] %dx%d | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", dstOps, dest, dest.width, dest.height, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
+#endif //DEBUG
+                [dest replaceRegion:region mipmapLevel:0 withBytes:srcInfo.rasBase bytesPerRow:srcInfo.scanStride]; // executed at CPU (sync), TODO: lock dest for current frame
+            } else {
+                MTLBlitSwToSurfaceViaTexture(mtlc, &srcInfo, dstOps, &pf, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
+            }
+        }
+        SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
+    }
+    SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
+}
+
+/**
+ * Specialized blit method for copying a native MTL "Surface" (pbuffer,
+ * window, etc.) to a system memory ("Sw") surface.
+ */
+void
+MTLBlitLoops_SurfaceToSwBlit(JNIEnv *env, MTLContext *mtlc,
+                             jlong pSrcOps, jlong pDstOps, jint dsttype,
+                             jint srcx, jint srcy, jint dstx, jint dsty,
+                             jint width, jint height)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_SurfaceToSwBlit -- :TODO");
+}
+
+void
+MTLBlitLoops_CopyArea(JNIEnv *env,
+                      MTLContext *mtlc, BMTLSDOps *dstOps,
+                      jint x, jint y, jint width, jint height,
+                      jint dx, jint dy)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_CopyArea -- :TODO");
+}
+
+#endif /* !HEADLESS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBufImgOps.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLBufImgOps_h_Included
+#define MTLBufImgOps_h_Included
+
+#include "MTLContext.h"
+
+void MTLBufImgOps_EnableConvolveOp(MTLContext *mtlc, jlong pSrcOps,
+                                   jboolean edgeZeroFill,
+                                   jint kernelWidth, jint KernelHeight,
+                                   unsigned char *kernelVals);
+void MTLBufImgOps_DisableConvolveOp(MTLContext *mtlc);
+void MTLBufImgOps_EnableRescaleOp(MTLContext *mtlc, jlong pSrcOps,
+                                  jboolean nonPremult,
+                                  unsigned char *scaleFactors,
+                                  unsigned char *offsets);
+void MTLBufImgOps_DisableRescaleOp(MTLContext *mtlc);
+void MTLBufImgOps_EnableLookupOp(MTLContext *mtlc, jlong pSrcOps,
+                                 jboolean nonPremult, jboolean shortData,
+                                 jint numBands, jint bandLength, jint offset,
+                                 void *tableValues);
+void MTLBufImgOps_DisableLookupOp(MTLContext *mtlc);
+
+#endif /* MTLBufImgOps_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBufImgOps.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef HEADLESS
+
+#include <jlong.h>
+
+#include "MTLBufImgOps.h"
+#include "MTLContext.h"
+#include "MTLRenderQueue.h"
+#include "MTLSurfaceDataBase.h"
+#include "GraphicsPrimitiveMgr.h"
+
+/** Evaluates to true if the given bit is set on the local flags variable. */
+#define IS_SET(flagbit) \
+    (((flags) & (flagbit)) != 0)
+
+/**************************** ConvolveOp support ****************************/
+
+/**
+ * The ConvolveOp shader is fairly straightforward.  For each texel in
+ * the source texture, the shader samples the MxN texels in the surrounding
+ * area, multiplies each by its corresponding kernel value, and then sums
+ * them all together to produce a single color result.  Finally, the
+ * resulting value is multiplied by the current OpenGL color, which contains
+ * the extra alpha value.
+ *
+ * Note that this shader source code includes some "holes" marked by "%s".
+ * This allows us to build different shader programs (e.g. one for
+ * 3x3, one for 5x5, and so on) simply by filling in these "holes" with
+ * a call to sprintf().  See the MTLBufImgOps_CreateConvolveProgram() method
+ * for more details.
+ *
+ * REMIND: Currently this shader (and the supporting code in the
+ *         EnableConvolveOp() method) only supports 3x3 and 5x5 filters.
+ *         Early shader-level hardware did not support non-constant sized
+ *         arrays but modern hardware should support them (although I
+ *         don't know of any simple way to find out, other than to compile
+ *         the shader at runtime and see if the drivers complain).
+ */
+static const char *convolveShaderSource =
+    // maximum size supported by this shader
+    "const int MAX_KERNEL_SIZE = %s;"
+    // image to be convolved
+    "uniform sampler%s baseImage;"
+    // image edge limits:
+    //   imgEdge.xy = imgMin.xy (anything < will be treated as edge case)
+    //   imgEdge.zw = imgMax.xy (anything > will be treated as edge case)
+    "uniform vec4 imgEdge;"
+    // value for each location in the convolution kernel:
+    //   kernelVals[i].x = offsetX[i]
+    //   kernelVals[i].y = offsetY[i]
+    //   kernelVals[i].z = kernel[i]
+    "uniform vec3 kernelVals[MAX_KERNEL_SIZE];"
+    ""
+    "void main(void)"
+    "{"
+    "    int i;"
+    "    vec4 sum;"
+    ""
+    "    if (any(lessThan(gl_TexCoord[0].st, imgEdge.xy)) ||"
+    "        any(greaterThan(gl_TexCoord[0].st, imgEdge.zw)))"
+    "    {"
+             // (placeholder for edge condition code)
+    "        %s"
+    "    } else {"
+    "        sum = vec4(0.0);"
+    "        for (i = 0; i < MAX_KERNEL_SIZE; i++) {"
+    "            sum +="
+    "                kernelVals[i].z *"
+    "                texture%s(baseImage,"
+    "                          gl_TexCoord[0].st + kernelVals[i].xy);"
+    "        }"
+    "    }"
+    ""
+         // modulate with gl_Color in order to apply extra alpha
+    "    gl_FragColor = sum * gl_Color;"
+    "}";
+
+/**
+ * Flags that can be bitwise-or'ed together to control how the shader
+ * source code is generated.
+ */
+#define CONVOLVE_RECT            (1 << 0)
+#define CONVOLVE_EDGE_ZERO_FILL  (1 << 1)
+#define CONVOLVE_5X5             (1 << 2)
+
+/**
+ * The handles to the ConvolveOp fragment program objects.  The index to
+ * the array should be a bitwise-or'ing of the CONVOLVE_* flags defined
+ * above.  Note that most applications will likely need to initialize one
+ * or two of these elements, so the array is usually sparsely populated.
+ */
+static GLhandleARB convolvePrograms[8];
+
+/**
+ * The maximum kernel size supported by the ConvolveOp shader.
+ */
+#define MAX_KERNEL_SIZE 25
+
+/**
+ * Compiles and links the ConvolveOp shader program.  If successful, this
+ * function returns a handle to the newly created shader program; otherwise
+ * returns 0.
+ */
+static GLhandleARB
+MTLBufImgOps_CreateConvolveProgram(jint flags)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_CreateConvolveProgram -- :TODO");
+
+    return NULL;
+}
+
+void
+MTLBufImgOps_EnableConvolveOp(MTLContext *mtlc, jlong pSrcOps,
+                              jboolean edgeZeroFill,
+                              jint kernelWidth, jint kernelHeight,
+                              unsigned char *kernel)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_EnableConvolveOp -- :TODO");
+
+}
+
+void
+MTLBufImgOps_DisableConvolveOp(MTLContext *mtlc)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_DisableConvolveOp -- :TODO");
+}
+
+/**************************** RescaleOp support *****************************/
+
+/**
+ * The RescaleOp shader is one of the simplest possible.  Each fragment
+ * from the source image is multiplied by the user's scale factor and added
+ * to the user's offset value (these are component-wise operations).
+ * Finally, the resulting value is multiplied by the current OpenGL color,
+ * which contains the extra alpha value.
+ *
+ * The RescaleOp spec says that the operation is performed regardless of
+ * whether the source data is premultiplied or non-premultiplied.  This is
+ * a problem for the OpenGL pipeline in that a non-premultiplied
+ * BufferedImage will have already been converted into premultiplied
+ * when uploaded to an OpenGL texture.  Therefore, we have a special mode
+ * called RESCALE_NON_PREMULT (used only for source images that were
+ * originally non-premultiplied) that un-premultiplies the source color
+ * prior to the rescale operation, then re-premultiplies the resulting
+ * color before returning from the fragment shader.
+ *
+ * Note that this shader source code includes some "holes" marked by "%s".
+ * This allows us to build different shader programs (e.g. one for
+ * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on)
+ * simply by filling in these "holes" with a call to sprintf().  See the
+ * MTLBufImgOps_CreateRescaleProgram() method for more details.
+ */
+static const char *rescaleShaderSource =
+    // image to be rescaled
+    "uniform sampler%s baseImage;"
+    // vector containing scale factors
+    "uniform vec4 scaleFactors;"
+    // vector containing offsets
+    "uniform vec4 offsets;"
+    ""
+    "void main(void)"
+    "{"
+    "    vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);"
+         // (placeholder for un-premult code)
+    "    %s"
+         // rescale source value
+    "    vec4 result = (srcColor * scaleFactors) + offsets;"
+         // (placeholder for re-premult code)
+    "    %s"
+         // modulate with gl_Color in order to apply extra alpha
+    "    gl_FragColor = result * gl_Color;"
+    "}";
+
+/**
+ * Flags that can be bitwise-or'ed together to control how the shader
+ * source code is generated.
+ */
+#define RESCALE_RECT        (1 << 0)
+#define RESCALE_NON_PREMULT (1 << 1)
+
+/**
+ * The handles to the RescaleOp fragment program objects.  The index to
+ * the array should be a bitwise-or'ing of the RESCALE_* flags defined
+ * above.  Note that most applications will likely need to initialize one
+ * or two of these elements, so the array is usually sparsely populated.
+ */
+static GLhandleARB rescalePrograms[4];
+
+/**
+ * Compiles and links the RescaleOp shader program.  If successful, this
+ * function returns a handle to the newly created shader program; otherwise
+ * returns 0.
+ */
+static GLhandleARB
+MTLBufImgOps_CreateRescaleProgram(jint flags)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_CreateRescaleProgram -- :TODO");
+
+    return NULL;
+}
+
+void
+MTLBufImgOps_EnableRescaleOp(MTLContext *mtlc, jlong pSrcOps,
+                             jboolean nonPremult,
+                             unsigned char *scaleFactors,
+                             unsigned char *offsets)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_EnableRescaleOp -- :TODO");
+}
+
+void
+MTLBufImgOps_DisableRescaleOp(MTLContext *mtlc)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_DisableRescaleOp -- :TODO");
+    RETURN_IF_NULL(mtlc);
+}
+
+/**************************** LookupOp support ******************************/
+
+/**
+ * The LookupOp shader takes a fragment color (from the source texture) as
+ * input, subtracts the optional user offset value, and then uses the
+ * resulting value to index into the lookup table texture to provide
+ * a new color result.  Finally, the resulting value is multiplied by
+ * the current OpenGL color, which contains the extra alpha value.
+ *
+ * The lookup step requires 3 texture accesses (or 4, when alpha is included),
+ * which is somewhat unfortunate because it's not ideal from a performance
+ * standpoint, but that sort of thing is getting faster with newer hardware.
+ * In the 3-band case, we could consider using a three-dimensional texture
+ * and performing the lookup with a single texture access step.  We already
+ * use this approach in the LCD text shader, and it works well, but for the
+ * purposes of this LookupOp shader, it's probably overkill.  Also, there's
+ * a difference in that the LCD text shader only needs to populate the 3D LUT
+ * once, but here we would need to populate it on every invocation, which
+ * would likely be a waste of VRAM and CPU/GPU cycles.
+ *
+ * The LUT texture is currently hardcoded as 4 rows/bands, each containing
+ * 256 elements.  This means that we currently only support user-provided
+ * tables with no more than 256 elements in each band (this is checked at
+ * at the Java level).  If the user provides a table with less than 256
+ * elements per band, our shader will still work fine, but if elements are
+ * accessed with an index >= the size of the LUT, then the shader will simply
+ * produce undefined values.  Typically the user would provide an offset
+ * value that would prevent this from happening, but it's worth pointing out
+ * this fact because the software LookupOp implementation would usually
+ * throw an ArrayIndexOutOfBoundsException in this scenario (although it is
+ * not something demanded by the spec).
+ *
+ * The LookupOp spec says that the operation is performed regardless of
+ * whether the source data is premultiplied or non-premultiplied.  This is
+ * a problem for the OpenGL pipeline in that a non-premultiplied
+ * BufferedImage will have already been converted into premultiplied
+ * when uploaded to an OpenGL texture.  Therefore, we have a special mode
+ * called LOOKUP_NON_PREMULT (used only for source images that were
+ * originally non-premultiplied) that un-premultiplies the source color
+ * prior to the lookup operation, then re-premultiplies the resulting
+ * color before returning from the fragment shader.
+ *
+ * Note that this shader source code includes some "holes" marked by "%s".
+ * This allows us to build different shader programs (e.g. one for
+ * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on)
+ * simply by filling in these "holes" with a call to sprintf().  See the
+ * MTLBufImgOps_CreateLookupProgram() method for more details.
+ */
+static const char *lookupShaderSource =
+    // source image (bound to texture unit 0)
+    "uniform sampler%s baseImage;"
+    // lookup table (bound to texture unit 1)
+    "uniform sampler2D lookupTable;"
+    // offset subtracted from source index prior to lookup step
+    "uniform vec4 offset;"
+    ""
+    "void main(void)"
+    "{"
+    "    vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);"
+         // (placeholder for un-premult code)
+    "    %s"
+         // subtract offset from original index
+    "    vec4 srcIndex = srcColor - offset;"
+         // use source value as input to lookup table (note that
+         // "v" texcoords are hardcoded to hit texel centers of
+         // each row/band in texture)
+    "    vec4 result;"
+    "    result.r = texture2D(lookupTable, vec2(srcIndex.r, 0.125)).r;"
+    "    result.g = texture2D(lookupTable, vec2(srcIndex.g, 0.375)).r;"
+    "    result.b = texture2D(lookupTable, vec2(srcIndex.b, 0.625)).r;"
+         // (placeholder for alpha store code)
+    "    %s"
+         // (placeholder for re-premult code)
+    "    %s"
+         // modulate with gl_Color in order to apply extra alpha
+    "    gl_FragColor = result * gl_Color;"
+    "}";
+
+/**
+ * Flags that can be bitwise-or'ed together to control how the shader
+ * source code is generated.
+ */
+#define LOOKUP_RECT          (1 << 0)
+#define LOOKUP_USE_SRC_ALPHA (1 << 1)
+#define LOOKUP_NON_PREMULT   (1 << 2)
+
+/**
+ * The handles to the LookupOp fragment program objects.  The index to
+ * the array should be a bitwise-or'ing of the LOOKUP_* flags defined
+ * above.  Note that most applications will likely need to initialize one
+ * or two of these elements, so the array is usually sparsely populated.
+ */
+static GLhandleARB lookupPrograms[8];
+
+/**
+ * The handle to the lookup table texture object used by the shader.
+ */
+static GLuint lutTextureID = 0;
+
+/**
+ * Compiles and links the LookupOp shader program.  If successful, this
+ * function returns a handle to the newly created shader program; otherwise
+ * returns 0.
+ */
+static GLhandleARB
+MTLBufImgOps_CreateLookupProgram(jint flags)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_CreateLookupProgram -- :TODO");
+    return NULL;
+}
+
+void
+MTLBufImgOps_EnableLookupOp(MTLContext *mtlc, jlong pSrcOps,
+                            jboolean nonPremult, jboolean shortData,
+                            jint numBands, jint bandLength, jint offset,
+                            void *tableValues)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_EnableLookupOp -- :TODO");
+}
+
+void
+MTLBufImgOps_DisableLookupOp(MTLContext *mtlc)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_DisableLookupOp -- :TODO");
+}
+
+#endif /* !HEADLESS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLContext.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLContext_h_Included
+#define MTLContext_h_Included
+
+#include <simd/simd.h>
+
+#include "sun_java2d_pipe_BufferedContext.h"
+#include "sun_java2d_metal_MTLContext.h"
+#include "sun_java2d_metal_MTLContext_MTLContextCaps.h"
+
+#import <Metal/Metal.h>
+#include "j2d_md.h"
+#include "MTLSurfaceDataBase.h"
+#include "MTLTexturePool.h"
+#include "MTLPipelineStatesStorage.h"
+
+/**
+ * The MTLBlendRule structure encapsulates the two enumerated values that
+ * comprise a given Porter-Duff blending (compositing) rule.  For example,
+ * the "SrcOver" rule can be represented by:
+ *     rule.src = GL_ONE;
+ *     rule.dst = GL_ONE_MINUS_SRC_ALPHA;
+ *
+ *     GLenum src;
+ * The constant representing the source factor in this Porter-Duff rule.
+ *
+ *     GLenum dst;
+ * The constant representing the destination factor in this Porter-Duff rule.
+ */
+typedef struct {
+    jint src;
+    jint dst;
+} MTLBlendRule;
+
+/**
+ * The MTLContext class contains cached state relevant to the native
+ * MTL context stored within the native ctxInfo field.  Each Java-level
+ * MTLContext object is associated with a native-level MTLContext class.
+ * */
+@interface MTLContext : NSObject
+
+@property jint          compState;
+@property jfloat        extraAlpha;
+@property jint          alphaCompositeRule;
+@property jint          xorPixel;
+@property jint          pixel;
+
+@property jdouble       p0;
+@property jdouble       p1;
+@property jdouble       p3;
+@property jboolean      cyclic;
+@property jint          pixel1;
+@property jint          pixel2;
+
+@property jubyte        r;
+@property jubyte        g;
+@property jubyte        b;
+@property jubyte        a;
+@property jint          paintState;
+@property jboolean      useMask;
+@property jboolean      useTransform;
+@property simd_float4x4 transform4x4;
+@property jint          blitTextureID;
+@property jint          textureFunction;
+@property jboolean      vertexCacheEnabled;
+
+@property (readonly, strong)   id<MTLDevice>   device;
+@property (strong) id<MTLLibrary>              library;
+@property (strong) id<MTLRenderPipelineState>  pipelineState;
+@property (strong) id<MTLCommandQueue>         commandQueue;
+@property (readonly,strong) id<MTLCommandBuffer>        commandBuffer;
+@property (strong) id<MTLBuffer>               vertexBuffer;
+@property jint                        color;
+@property MTLScissorRect              clipRect;
+@property jboolean                    useClip;
+@property (strong)MTLPipelineStatesStorage*   pipelineStateStorage;
+@property (strong)MTLTexturePool*             texturePool;
+
+- (void)releaseCommandBuffer;
+/**
+ * Fetches the MTLContext associated with the given destination surface,
+ * makes the context current for those surfaces, updates the destination
+ * viewport, and then returns a pointer to the MTLContext.
+ */
++ (MTLContext*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(jlong)pDst;
+
+- (id)initWithDevice:(id<MTLDevice>)d shadersLib:(NSString*)shadersLib;
+
+/**
+ * Resets the current clip state (disables both scissor and depth tests).
+ */
+- (void)resetClip;
+
+/**
+ * Sets the Metal scissor bounds to the provided rectangular clip bounds.
+ */
+- (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2;
+
+/**
+ * Sets up a complex (shape) clip using the OpenGL depth buffer.  This
+ * method prepares the depth buffer so that the clip Region spans can
+ * be "rendered" into it.  The depth buffer is first cleared, then the
+ * depth func is setup so that when we render the clip spans,
+ * nothing is rendered into the color buffer, but for each pixel that would
+ * be rendered, a non-zero value is placed into that location in the depth
+ * buffer.  With depth test enabled, pixels will only be rendered into the
+ * color buffer if the corresponding value at that (x,y) location in the
+ * depth buffer differs from the incoming depth value.
+ */
+- (void)beginShapeClip;
+
+/**
+ * Finishes setting up the shape clip by resetting the depth func
+ * so that future rendering operations will once again be written into the
+ * color buffer (while respecting the clip set up in the depth buffer).
+ */
+- (void)endShapeClip;
+
+/**
+ * Initializes the OpenGL state responsible for applying extra alpha.  This
+ * step is only necessary for any operation that uses glDrawPixels() or
+ * glCopyPixels() with a non-1.0f extra alpha value.  Since the source is
+ * always premultiplied, we apply the extra alpha value to both alpha and
+ * color components using GL_*_SCALE.
+ */
+- (void)setExtraAlpha:(jfloat)ea;
+
+/**
+ * Resets all OpenGL compositing state (disables blending and logic
+ * operations).
+ */
+- (void)resetComposite;
+
+/**
+ * Initializes the OpenGL blending state.  XOR mode is disabled and the
+ * appropriate blend functions are setup based on the AlphaComposite rule
+ * constant.
+ */
+- (void)setAlphaCompositeRule:(jint)rule extraAlpha:(jfloat)extraAlpha
+                        flags:(jint)flags;
+
+/**
+ * Initializes the OpenGL logic op state to XOR mode.  Blending is disabled
+ * before enabling logic op mode.  The XOR pixel value will be applied
+ * later in the MTLContext_SetColor() method.
+ */
+- (void)setXorComposite:(jint)xorPixel;
+- (jboolean)isBlendingDisabled;
+
+/**
+ * Resets the OpenGL transform state back to the identity matrix.
+ */
+- (void)resetTransform;
+
+/**
+ * Initializes the OpenGL transform state by setting the modelview transform
+ * using the given matrix parameters.
+ *
+ * REMIND: it may be worthwhile to add serial id to AffineTransform, so we
+ *         could do a quick check to see if the xform has changed since
+ *         last time... a simple object compare won't suffice...
+ */
+- (void)setTransformM00:(jdouble) m00 M10:(jdouble) m10
+                    M01:(jdouble) m01 M11:(jdouble) m11
+                    M02:(jdouble) m02 M12:(jdouble) m12;
+
+/**
+ * Initializes a small texture tile for use with tiled blit operations (see
+ * MTLBlitLoops.c and MTLMaskBlit.c for usage examples).  The texture ID for
+ * the tile is stored in the given MTLContext.  The tile is initially filled
+ * with garbage values, but the tile is updated as needed (via
+ * glTexSubImage2D()) with real RGBA values used in tiled blit situations.
+ * The internal format for the texture is GL_RGBA8, which should be sufficient
+ * for storing system memory surfaces of any known format (see PixelFormats
+ * for a list of compatible surface formats).
+ */
+- (jboolean)initBlitTileTexture;
+
+
+/**
+ * Creates a 2D texture of the given format and dimensions and returns the
+ * texture object identifier.  This method is typically used to create a
+ * temporary texture for intermediate work, such as in the
+ * MTLContext_InitBlitTileTexture() method below.
+ */
+- (jint)createBlitTextureFormat:(jint)internalFormat pixelFormat:(jint)pixelFormat
+                          width:(jint)width height:(jint)height;
+
+- (void)destroyContextResources;
+
+- (void)setColorR:(int)r G:(int)g B:(int)b A:(int)a;
+- (void)setColorInt:(int)pixel;
+
+- (id<MTLRenderCommandEncoder>)createSamplingEncoderForDest:(id<MTLTexture>)dest clearRed:(int)clearRed;
+- (id<MTLRenderCommandEncoder>)createSamplingEncoderForDest:(id<MTLTexture>)dest;
+- (id<MTLBlitCommandEncoder>)createBlitEncoder;
+// NOTE: debug parameners will be removed soon
+- (id<MTLRenderCommandEncoder>)createRenderEncoderForDest:(id<MTLTexture>)dest clearRed:(int) clearRed/*debug param*/;
+- (id<MTLRenderCommandEncoder>)createRenderEncoderForDest:(id<MTLTexture>)dest;
+- (void)setGradientPaintUseMask:(jboolean)useMask cyclic:(jboolean)cyclic p0:(jdouble) p0 p1:(jdouble) p1 p3:(jdouble)p3
+                         pixel1:(jint)pixel1 pixel2:(jint) pixel2;
+- (void) setEncoderTransform:(id<MTLRenderCommandEncoder>) encoder dest:(id<MTLTexture>) dest;
+- (void)dealloc;
+@end
+
+/**
+ * See BufferedContext.java for more on these flags...
+ */
+#define MTLC_NO_CONTEXT_FLAGS \
+    sun_java2d_pipe_BufferedContext_NO_CONTEXT_FLAGS
+#define MTLC_SRC_IS_OPAQUE    \
+    sun_java2d_pipe_BufferedContext_SRC_IS_OPAQUE
+#define MTLC_USE_MASK         \
+    sun_java2d_pipe_BufferedContext_USE_MASK
+
+#endif /* MTLContext_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLContext.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef HEADLESS
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "sun_java2d_SunGraphics2D.h"
+
+#include "jlong.h"
+#include "jni_util.h"
+#import "MTLContext.h"
+#include "MTLRenderQueue.h"
+#include "MTLSurfaceDataBase.h"
+#include "GraphicsPrimitiveMgr.h"
+#include "Region.h"
+#include "common.h"
+
+#include "jvm.h"
+
+extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
+extern MTLContext *MTLSD_MakeMTLContextCurrent(JNIEnv *env,
+                                               MTLSDOps *srcOps,
+                                               MTLSDOps *dstOps);
+
+#define RGBA_TO_V4(c)              \
+{                                  \
+    (((c) >> 16) & (0xFF))/255.0f, \
+    (((c) >> 8) & 0xFF)/255.0f,    \
+    ((c) & 0xFF)/255.0f,           \
+    (((c) >> 24) & 0xFF)/255.0f    \
+}
+
+/**
+ * This table contains the standard blending rules (or Porter-Duff compositing
+ * factors) used in glBlendFunc(), indexed by the rule constants from the
+ * AlphaComposite class.
+ */
+MTLBlendRule MTStdBlendRules[] = {
+};
+
+static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
+        {{-1.0, 1.0, 0.0}, {0.0, 0.0}},
+        {{1.0, 1.0, 0.0}, {1.0, 0.0}},
+        {{1.0, -1.0, 0.0}, {1.0, 1.0}},
+        {{1.0, -1.0, 0.0}, {1.0, 1.0}},
+        {{-1.0, -1.0, 0.0}, {0.0, 1.0}},
+        {{-1.0, 1.0, 0.0}, {0.0, 0.0}}
+};
+
+
+static void _traceMatrix(simd_float4x4 * mtx) {
+    for (int row = 0; row < 4; ++row) {
+        J2dTraceLn4(J2D_TRACE_VERBOSE, "  [%lf %lf %lf %lf]",
+                    mtx->columns[0][row], mtx->columns[1][row], mtx->columns[2][row], mtx->columns[3][row]);
+    }
+}
+
+MTLRenderPassDescriptor* createRenderPassDesc(id<MTLTexture> dest) {
+    MTLRenderPassDescriptor * result = [MTLRenderPassDescriptor renderPassDescriptor];
+    if (result == nil)
+        return nil;
+
+    if (dest == nil) {
+        J2dTraceLn(J2D_TRACE_ERROR, "_createRenderPassDesc: destination texture is null");
+        return nil;
+    }
+
+    MTLRenderPassColorAttachmentDescriptor * ca = result.colorAttachments[0];
+    ca.texture = dest;
+    ca.loadAction = MTLLoadActionLoad;
+    ca.clearColor = MTLClearColorMake(0.0f, 0.9f, 0.0f, 1.0f);
+    ca.storeAction = MTLStoreActionStore;
+    return result;
+}
+
+@implementation MTLContext {
+    id<MTLCommandBuffer> _commandBuffer;
+}
+
+@synthesize compState, extraAlpha, alphaCompositeRule, xorPixel, pixel, p0,
+            p1, p3, cyclic, pixel1, pixel2, r, g, b, a, paintState, useMask,
+            useTransform, transform4x4, blitTextureID, textureFunction,
+            vertexCacheEnabled, device, library, pipelineState, pipelineStateStorage,
+            commandQueue, vertexBuffer,
+            color, clipRect, useClip, texturePool;
+
+
+ - (id<MTLCommandBuffer>) commandBuffer {
+    if (_commandBuffer == nil) {
+        // NOTE: Command queues are thread-safe and allow multiple outstanding command buffers to be encoded simultaneously.
+        _commandBuffer = [[self.commandQueue commandBuffer] retain];// released in [layer blitTexture]
+    }
+    return _commandBuffer;
+}
+
+- (void)releaseCommandBuffer {
+    [_commandBuffer release];
+    _commandBuffer = nil;
+}
+
++ (MTLContext*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(jlong)pDst {
+    BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrc);
+    BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDst);
+    MTLContext *mtlc = NULL;
+
+    if (srcOps == NULL || dstOps == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_SetSurfaces: ops are null");
+        return NULL;
+    }
+
+    J2dTraceLn6(J2D_TRACE_VERBOSE, "MTLContext_SetSurfaces: bsrc=%p (tex=%p type=%d), bdst=%p (tex=%p type=%d)", srcOps, srcOps->pTexture, srcOps->drawableType, dstOps, dstOps->pTexture, dstOps->drawableType);
+
+    if (dstOps->drawableType == MTLSD_TEXTURE) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+                      "MTLContext_SetSurfaces: texture cannot be used as destination");
+        return NULL;
+    }
+
+    if (dstOps->drawableType == MTLSD_UNDEFINED) {
+        // initialize the surface as an OGLSD_WINDOW
+        if (!MTLSD_InitMTLWindow(env, dstOps)) {
+            J2dRlsTraceLn(J2D_TRACE_ERROR,
+                          "MTLContext_SetSurfaces: could not init OGL window");
+            return NULL;
+        }
+    }
+
+    // make the context current
+    MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
+    mtlc = dstCGLOps->configInfo->context;
+
+    if (mtlc == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+                      "MTLContext_SetSurfaces: could not make context current");
+        return NULL;
+    }
+
+    // perform additional one-time initialization, if necessary
+    if (dstOps->needsInit) {
+        if (dstOps->isOpaque) {
+            // in this case we are treating the destination as opaque, but
+            // to do so, first we need to ensure that the alpha channel
+            // is filled with fully opaque values (see 6319663)
+            //MTLContext_InitAlphaChannel();
+        }
+        dstOps->needsInit = JNI_FALSE;
+    }
+
+    return mtlc;
+}
+
+- (id)initWithDevice:(id<MTLDevice>)d shadersLib:(NSString*)shadersLib {
+    self = [super init];
+    if (self) {
+        // Initialization code here.
+        device = d;
+
+        texturePool = [[MTLTexturePool alloc] initWithDevice:device];
+        pipelineStateStorage = [[MTLPipelineStatesStorage alloc] initWithDevice:device shaderLibPath:shadersLib];
+
+        vertexBuffer = [device newBufferWithBytes:verts
+                                           length:sizeof(verts)
+                                          options:MTLResourceCPUCacheModeDefaultCache];
+
+        NSError *error = nil;
+
+        library = [device newLibraryWithFile:shadersLib error:&error];
+        if (!library) {
+            NSLog(@"Failed to load library. error %@", error);
+            exit(0);
+        }
+
+        _commandBuffer = nil;
+
+        // Create command queue
+        commandQueue = [device newCommandQueue];
+    }
+    return self;
+}
+
+- (void)resetClip {
+    //TODO
+    J2dTraceLn(J2D_TRACE_INFO, "MTLContext.resetClip");
+    useClip = JNI_FALSE;
+}
+
+- (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2 {
+    //TODO
+    jint width = x2 - x1;
+    jint height = y2 - y1;
+
+    J2dTraceLn4(J2D_TRACE_INFO, "MTLContext.setClipRect: x=%d y=%d w=%d h=%d", x1, y1, width, height);
+
+    clipRect.x = x1;
+    clipRect.y = y1;
+    clipRect.width = width;
+    clipRect.height = height;
+    useClip = JNI_TRUE;
+}
+
+- (void)beginShapeClip {
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLContext.beginShapeClip -- :TODO");
+}
+
+- (void)endShapeClip {
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLContext.endShapeClip  -- :TODO");
+}
+
+- (void)resetComposite {
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLContext_ResetComposite  -- :TODO");
+}
+
+- (void)setAlphaCompositeRule:(jint)rule extraAlpha:(jfloat)_extraAlpha
+                        flags:(jint)flags {
+    J2dTraceLn3(J2D_TRACE_INFO, "MTLContext_SetAlphaComposite: rule=%d, extraAlpha=%1.2f, flags=%d", rule, extraAlpha, flags);
+
+    extraAlpha = _extraAlpha;
+    alphaCompositeRule = rule;
+}
+
+
+- (void)setXorComposite:(jint)xp {
+    //TODO
+    J2dTraceLn1(J2D_TRACE_ERROR,
+                "MTLContext.setXorComposite: xorPixel=%08x -- :TODO", xp);
+}
+
+- (jboolean)isBlendingDisabled {
+    // TODO: hold case mtlc->alphaCompositeRule == RULE_SrcOver && sun_java2d_pipe_BufferedContext_SRC_IS_OPAQUE
+    return alphaCompositeRule == RULE_Src && (extraAlpha - 1.0f < 0.001f);
+}
+
+
+- (void)resetTransform {
+    J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetTransform");
+    useTransform = JNI_FALSE;
+}
+
+- (void)setTransformM00:(jdouble) m00 M10:(jdouble) m10
+                    M01:(jdouble) m01 M11:(jdouble) m11
+                    M02:(jdouble) m02 M12:(jdouble) m12 {
+
+
+    J2dTraceLn(J2D_TRACE_INFO, "MTLContext_SetTransform");
+
+    memset(&(transform4x4), 0, sizeof(transform4x4));
+    transform4x4.columns[0][0] = m00;
+    transform4x4.columns[0][1] = m10;
+    transform4x4.columns[1][0] = m01;
+    transform4x4.columns[1][1] = m11;
+    transform4x4.columns[3][0] = m02;
+    transform4x4.columns[3][1] = m12;
+    transform4x4.columns[3][3] = 1.0;
+    transform4x4.columns[4][4] = 1.0;
+    useTransform = JNI_TRUE;
+}
+
+- (jboolean)initBlitTileTexture {
+    //TODO
+    J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitBlitTileTexture -- :TODO");
+
+    return JNI_TRUE;
+}
+
+- (jint)createBlitTextureFormat:(jint)internalFormat pixelFormat:(jint)pixelFormat
+                          width:(jint)width height:(jint)height {
+    J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitBlitTileTexture -- :TODO");
+
+    //TODO
+    return 0;
+}
+
+
+- (void)setColorR:(int)_r G:(int)_g B:(int)_b A:(int)_a {
+    color = 0;
+    color |= (_r & (0xFF)) << 16;
+    color |= (_g & (0xFF)) << 8;
+    color |= _b & (0xFF);
+    color |= (_a & (0xFF)) << 24;
+    J2dTraceLn4(J2D_TRACE_INFO, "MTLContext.setColor (%d, %d, %d) %d", r,g,b,a);
+}
+
+- (void)setColorInt:(int)_pixel {
+    color = _pixel;
+    J2dTraceLn5(J2D_TRACE_INFO, "MTLContext.setColorInt: pixel=%08x [r=%d g=%d b=%d a=%d]", pixel, (pixel >> 16) & (0xFF), (pixel >> 8) & 0xFF, (pixel) & 0xFF, (pixel >> 24) & 0xFF);
+}
+
+- (id<MTLRenderCommandEncoder>) createEncoderForDest:(id<MTLTexture>) dest {
+    id<MTLCommandBuffer> cb = self.commandBuffer;
+    if (cb == nil)
+        return nil;
+
+    MTLRenderPassDescriptor * rpd = createRenderPassDesc(dest);
+    if (rpd == nil)
+        return nil;
+
+    // J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext: created render encoder to draw on tex=%p", dest);
+    return [cb renderCommandEncoderWithDescriptor:rpd];
+}
+
+- (void) setEncoderTransform:(id<MTLRenderCommandEncoder>) encoder dest:(id<MTLTexture>) dest {
+    simd_float4x4 normalize;
+    memset(&normalize, 0, sizeof(normalize));
+    normalize.columns[0][0] = 2/(double)dest.width;
+    normalize.columns[1][1] = -2/(double)dest.height;
+    normalize.columns[3][0] = -1.f;
+    normalize.columns[3][1] = 1.f;
+    normalize.columns[3][3] = 1.0;
+    normalize.columns[4][4] = 1.0;
+
+    if (useTransform) {
+        simd_float4x4 vertexMatrix = simd_mul(normalize, transform4x4);
+        [encoder setVertexBytes:&(vertexMatrix) length:sizeof(vertexMatrix) atIndex:MatrixBuffer];
+    } else {
+        [encoder setVertexBytes:&(normalize) length:sizeof(normalize) atIndex:MatrixBuffer];
+    }
+}
+
+- (id<MTLRenderCommandEncoder>) createRenderEncoderForDest:(id<MTLTexture>) dest {
+    id <MTLRenderCommandEncoder> mtlEncoder = [self createEncoderForDest: dest];
+    if (useClip)
+        [mtlEncoder setScissorRect:clipRect];
+
+    if (compState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
+        // set pipeline state
+        [mtlEncoder setRenderPipelineState:[self.pipelineStateStorage getRenderPipelineState:NO]];
+        struct FrameUniforms uf = {RGBA_TO_V4(color)};
+        [mtlEncoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
+    } else if (compState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
+        // set viewport and pipeline state
+        //[mtlEncoder setRenderPipelineState:gradPipelineState];
+        [mtlEncoder setRenderPipelineState:[self.pipelineStateStorage getRenderPipelineState:YES]];
+
+        struct GradFrameUniforms uf = {
+                {p0, p1, p3},
+                RGBA_TO_V4(pixel1),
+                RGBA_TO_V4(pixel2)};
+
+        [mtlEncoder setFragmentBytes: &uf length:sizeof(uf) atIndex:0];
+    }
+    [self setEncoderTransform:mtlEncoder dest:dest];
+    return mtlEncoder;
+}
+
+- (id<MTLRenderCommandEncoder>)createSamplingEncoderForDest:(id<MTLTexture>)dest {
+    id <MTLRenderCommandEncoder> mtlEncoder = [self createRenderEncoderForDest:dest];
+    [mtlEncoder setRenderPipelineState:[pipelineStateStorage getTexturePipelineState:NO compositeRule:alphaCompositeRule]];
+    [self setEncoderTransform:mtlEncoder dest:dest];
+    return mtlEncoder;
+}
+
+- (id<MTLBlitCommandEncoder>)createBlitEncoder {
+    return _commandBuffer == nil ? nil : [_commandBuffer blitCommandEncoder];
+}
+
+- (void)dealloc {
+    J2dTraceLn(J2D_TRACE_INFO, "MTLContext.dealloc");
+
+    self.texturePool = nil;
+    self.library = nil;
+    self.vertexBuffer = nil;
+    self.commandQueue = nil;
+    self.pipelineState = nil;
+    self.pipelineStateStorage = nil;
+    [super dealloc];
+}
+
+- (void)setGradientPaintUseMask:(jboolean)_useMask cyclic:(jboolean)_cyclic p0:(jdouble) _p0 p1:(jdouble)_p1
+                             p3:(jdouble)_p3 pixel1:(jint)_pixel1 pixel2:(jint)_pixel2 {
+
+    //TODO Resolve gradient distribution problem
+    //TODO Implement useMask
+    //TODO Implement cyclic
+    //fprintf(stderr,
+    //        "MTLPaints_SetGradientPaint useMask=%d cyclic=%d "
+    //        "p0=%f p1=%f p3=%f pix1=%d pix2=%d\n", useMask, cyclic,
+    //        p0, p1, p3, pixel1, pixel2);
+
+    compState = sun_java2d_SunGraphics2D_PAINT_GRADIENT;
+    useMask = _useMask;
+    pixel1 = _pixel1;
+    pixel2 = _pixel2;
+    p0 = _p0;
+    p1 = _p1;
+    p3 = _p3;
+    cyclic = _cyclic;
+ }
+
+@end
+
+/*
+ * Class:     sun_java2d_metal_MTLContext
+ * Method:    getMTLIdString
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_sun_java2d_metal_MTLContext_getMTLIdString
+  (JNIEnv *env, jclass mtlcc)
+{
+    char *vendor, *renderer, *version;
+    char *pAdapterId;
+    jobject ret = NULL;
+    int len;
+
+    return NULL;
+}
+
+
+
+#endif /* !HEADLESS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLFuncs.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLFuncs_h_Included
+#define MTLFuncs_h_Included
+
+#ifdef MACOSX
+#include <dlfcn.h>
+#endif
+#include "jni.h"
+#include "Trace.h"
+
+jboolean MTLFuncs_OpenLibrary();
+void     MTLFuncs_CloseLibrary();
+jboolean MTLFuncs_InitPlatformFuncs();
+jboolean MTLFuncs_InitBaseFuncs();
+jboolean MTLFuncs_InitExtFuncs();
+
+#endif /* MTLFuncs_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLFuncs.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef HEADLESS
+
+#include "MTLFuncs.h"
+
+
+jboolean
+MTLFuncs_OpenLibrary()
+{
+    //TODO
+
+    J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_OpenLibrary");
+
+
+    return JNI_TRUE;
+}
+
+void
+MTLFuncs_CloseLibrary()
+{
+    //TODO
+    J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_CloseLibrary");
+
+}
+
+jboolean
+MTLFuncs_InitPlatformFuncs()
+{
+    //TODO
+    J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitPlatformFuncs");
+
+    return JNI_TRUE;
+}
+
+jboolean
+MTLFuncs_InitBaseFuncs()
+{
+    //TODO
+    J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitBaseFuncs");
+
+
+    return JNI_TRUE;
+}
+
+jboolean
+MTLFuncs_InitExtFuncs()
+{
+    //TODO
+    J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitExtFuncs");
+
+    return JNI_TRUE;
+}
+
+#endif /* !HEADLESS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGraphicsConfig.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLGraphicsConfig_h_Included
+#define MTLGraphicsConfig_h_Included
+
+#import "jni.h"
+#import "MTLSurfaceDataBase.h"
+#import "MTLContext.h"
+#import <Cocoa/Cocoa.h>
+#import <Metal/Metal.h>
+
+
+@interface MTLGraphicsConfigUtil : NSObject {}
++ (void) _getMTLConfigInfo: (NSMutableArray *)argValue;
+@end
+
+// REMIND: Using an NSOpenGLPixelBuffer as the scratch surface has been
+// problematic thus far (seeing garbage and flickering when switching
+// between an NSView and the scratch surface), so the following enables
+// an alternate codepath that uses a hidden NSWindow/NSView as the scratch
+// surface, for the purposes of making a context current in certain
+// situations.  It appears that calling [NSOpenGLContext setView] too
+// frequently contributes to the bad behavior, so we should try to avoid
+// switching to the scratch surface whenever possible.
+
+/* Do we need this if we are using all off-screen drawing ? */
+#define USE_NSVIEW_FOR_SCRATCH 1
+
+/* Uncomment to have an additional CAOGLLayer instance tied to
+ * each instance, which can be used to test remoting the layer
+ * to an out of process window. The additional layer is needed
+ * because a layer can only be attached to one context (view/window).
+ * This is only for testing purposes and can be removed if/when no
+ * longer needed.
+ */
+
+
+/**
+ * The MTLGraphicsConfigInfo structure contains information specific to a
+ * given CGLGraphicsConfig (pixel format).
+ *
+ *     jint screen;
+ * The screen and PixelFormat for the associated CGLGraphicsConfig.
+ *
+ *     NSOpenGLPixelFormat *pixfmt;
+ * The pixel format of the native NSOpenGL context.
+ *
+ *     MTLContext *context;
+ * The context associated with this CGLGraphicsConfig.
+ */
+typedef struct _MTLGraphicsConfigInfo {
+    jint                screen;
+    NSOpenGLPixelFormat *pixfmt;
+    MTLContext          *context;
+} MTLGraphicsConfigInfo;
+
+#endif /* MTLGraphicsConfig_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGraphicsConfig.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "sun_java2d_metal_MTLGraphicsConfig.h"
+
+#import "MTLGraphicsConfig.h"
+#import "MTLSurfaceData.h"
+#import "ThreadUtilities.h"
+#import "awt.h"
+
+#import <stdlib.h>
+#import <string.h>
+#import <ApplicationServices/ApplicationServices.h>
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+#pragma mark -
+#pragma mark "--- Mac OS X specific methods for GL pipeline ---"
+
+/**
+ * Disposes all memory and resources associated with the given
+ * CGLGraphicsConfigInfo (including its native MTLContext data).
+ */
+void
+MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo)
+{
+    J2dTraceLn(J2D_TRACE_INFO, "MTLGC_DestroyMTLGraphicsConfig");
+
+    MTLGraphicsConfigInfo *mtlinfo =
+        (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
+    if (mtlinfo == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+                      "MTLGC_DestroyMTLGraphicsConfig: info is null");
+        return;
+    }
+
+    MTLContext *mtlc = (MTLContext*)mtlinfo->context;
+    if (mtlc != NULL) {
+        [mtlinfo->context release];
+        mtlinfo->context = nil;
+    }
+    free(mtlinfo);
+}
+
+#pragma mark -
+#pragma mark "--- MTLGraphicsConfig methods ---"
+
+
+/**
+ * Attempts to initialize CGL and the core OpenGL library.
+ */
+JNIEXPORT jboolean JNICALL
+Java_sun_java2d_metal_MTLGraphicsConfig_initMTL
+    (JNIEnv *env, jclass cglgc)
+{
+    J2dRlsTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_initMTL");
+
+    if (!MTLFuncs_OpenLibrary()) {
+        return JNI_FALSE;
+    }
+
+    if (!MTLFuncs_InitPlatformFuncs() ||
+        !MTLFuncs_InitBaseFuncs() ||
+        !MTLFuncs_InitExtFuncs())
+    {
+        MTLFuncs_CloseLibrary();
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+
+/**
+ * Determines whether the CGL pipeline can be used for a given GraphicsConfig
+ * provided its screen number and visual ID.  If the minimum requirements are
+ * met, the native CGLGraphicsConfigInfo structure is initialized for this
+ * GraphicsConfig with the necessary information (pixel format, etc.)
+ * and a pointer to this structure is returned as a jlong.  If
+ * initialization fails at any point, zero is returned, indicating that CGL
+ * cannot be used for this GraphicsConfig (we should fallback on an existing
+ * 2D pipeline).
+ */
+JNIEXPORT jlong JNICALL
+Java_sun_java2d_metal_MTLGraphicsConfig_getMTLConfigInfo
+    (JNIEnv *env, jclass cglgc, jint displayID, jstring mtlShadersLib)
+{
+  jlong ret = 0L;
+  JNF_COCOA_ENTER(env);
+  NSMutableArray * retArray = [NSMutableArray arrayWithCapacity:3];
+  [retArray addObject: [NSNumber numberWithInt: (int)displayID]];
+  [retArray addObject: [NSString stringWithUTF8String: JNU_GetStringPlatformChars(env, mtlShadersLib, 0)]];
+  if ([NSThread isMainThread]) {
+      [MTLGraphicsConfigUtil _getMTLConfigInfo: retArray];
+  } else {
+      [MTLGraphicsConfigUtil performSelectorOnMainThread: @selector(_getMTLConfigInfo:) withObject: retArray waitUntilDone: YES];
+  }
+  NSNumber * num = (NSNumber *)[retArray objectAtIndex: 0];
+  ret = (jlong)[num longValue];
+  JNF_COCOA_EXIT(env);
+  return ret;
+}
+
+
+
+
+@implementation MTLGraphicsConfigUtil
++ (void) _getMTLConfigInfo: (NSMutableArray *)argValue {
+    AWT_ASSERT_APPKIT_THREAD;
+
+    jint displayID = (jint)[(NSNumber *)[argValue objectAtIndex: 0] intValue];
+    NSString *mtlShadersLib = (NSString *)[argValue objectAtIndex: 1];
+    JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
+    [argValue removeAllObjects];
+
+    J2dRlsTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_getMTLConfigInfo");
+
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+
+    NSRect contentRect = NSMakeRect(0, 0, 64, 64);
+    NSWindow *window =
+        [[NSWindow alloc]
+            initWithContentRect: contentRect
+            styleMask: NSBorderlessWindowMask
+            backing: NSBackingStoreBuffered
+            defer: false];
+    if (window == nil) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: NSWindow is NULL");
+        [argValue addObject: [NSNumber numberWithLong: 0L]];
+        return;
+    }
+
+    NSView *scratchSurface =
+        [[NSView alloc]
+            initWithFrame: contentRect];
+    if (scratchSurface == nil) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: NSView is NULL");
+        [argValue addObject: [NSNumber numberWithLong: 0L]];
+        return;
+    }
+    [window setContentView: scratchSurface];
+
+    MTLContext *mtlc = [[MTLContext alloc] initWithDevice:CGDirectDisplayCopyCurrentMetalDevice(displayID)
+                        shadersLib:mtlShadersLib];
+    if (mtlc == 0L) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGC_InitMTLContext: could not allocate memory for mtlc");
+        [argValue addObject: [NSNumber numberWithLong: 0L]];
+        return;
+    }
+
+
+    // create the MTLGraphicsConfigInfo record for this config
+    MTLGraphicsConfigInfo *mtlinfo = (MTLGraphicsConfigInfo *)malloc(sizeof(MTLGraphicsConfigInfo));
+    if (mtlinfo == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: could not allocate memory for mtlinfo");
+        free(mtlc);
+        [argValue addObject: [NSNumber numberWithLong: 0L]];
+        return;
+    }
+    memset(mtlinfo, 0, sizeof(MTLGraphicsConfigInfo));
+    mtlinfo->screen = displayID;
+    mtlinfo->context = mtlc;
+
+    [argValue addObject: [NSNumber numberWithLong:ptr_to_jlong(mtlinfo)]];
+    [pool drain];
+}
+@end //GraphicsConfigUtil
+
+
+JNIEXPORT jint JNICALL
+Java_sun_java2d_metal_MTLGraphicsConfig_nativeGetMaxTextureSize
+    (JNIEnv *env, jclass mtlgc)
+{
+    J2dTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_nativeGetMaxTextureSize");
+
+    __block int max = 0;
+
+//    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
+//    }];
+
+    return (jint)max;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLLayer_h_Included
+#define MTLLayer_h_Included
+#import <Metal/Metal.h>
+#import <QuartzCore/CAMetalLayer.h>
+#import "common.h"
+
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+@interface MTLLayer : CAMetalLayer
+{
+@private
+    JNFWeakJObjectWrapper *javaLayer;
+
+    // intermediate buffer, used the RQ lock to synchronize
+    MTLContext* ctx;
+    float bufferWidth;
+    float bufferHeight;
+    id<MTLTexture> buffer;
+}
+
+@property (nonatomic, retain) JNFWeakJObjectWrapper *javaLayer;
+@property (readwrite, assign) MTLContext* ctx;
+@property (readwrite, assign) float bufferWidth;
+@property (readwrite, assign) float bufferHeight;
+@property (readwrite, assign) id<MTLTexture> buffer;
+
+- (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer;
+
+- (void) blitTexture:(id<MTLCommandBuffer>)commandBuf;
+- (void) fillParallelogramCtxX:(jfloat)x
+                             Y:(jfloat)y
+                           DX1:(jfloat)dx1
+                           DY1:(jfloat)dy1
+                           DX2:(jfloat)dx2
+                           DY2:(jfloat)dy2;
+@end
+
+#endif /* CGLLayer_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "MTLGraphicsConfig.h"
+#import "MTLLayer.h"
+#import "ThreadUtilities.h"
+#import "LWCToolkit.h"
+#import "MTLSurfaceData.h"
+
+#import "MTLBlitLoops.h"
+
+@implementation MTLLayer
+
+
+@synthesize javaLayer;
+@synthesize ctx;
+@synthesize bufferWidth;
+@synthesize bufferHeight;
+@synthesize buffer;
+
+- (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer
+{
+    AWT_ASSERT_APPKIT_THREAD;
+    // Initialize ourselves
+    self = [super init];
+    if (self == nil) return self;
+
+    self.javaLayer = layer;
+
+    self.contentsGravity = kCAGravityTopLeft;
+
+    //Disable CALayer's default animation
+    NSMutableDictionary * actions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
+                                    [NSNull null], @"anchorPoint",
+                                    [NSNull null], @"bounds",
+                                    [NSNull null], @"contents",
+                                    [NSNull null], @"contentsScale",
+                                    [NSNull null], @"onOrderIn",
+                                    [NSNull null], @"onOrderOut",
+                                    [NSNull null], @"position",
+                                    [NSNull null], @"sublayers",
+                                    nil];
+    self.actions = actions;
+    [actions release];
+
+
+    return self;
+}
+
+- (void) blitTexture:(id<MTLCommandBuffer>)commandBuf {
+    if (self.ctx == NULL || self.javaLayer == NULL || self.buffer == nil || ctx.device == nil) {
+        J2dTraceLn4(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: uninitialized (mtlc=%p, javaLayer=%p, buffer=%p, devide=%p)", self.ctx, self.javaLayer, self.buffer, ctx.device);
+        return;
+    }
+
+    if (commandBuf == nil) {
+        J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: nothing to do (commandBuf is null)");
+        return;
+    }
+
+    @autoreleasepool {
+        self.device = ctx.device;
+        self.pixelFormat = MTLPixelFormatBGRA8Unorm;
+        self.framebufferOnly = NO;
+
+        self.drawableSize =
+            CGSizeMake(self.buffer.width,
+                       self.buffer.height);
+
+        id<CAMetalDrawable> mtlDrawable = [self nextDrawable];
+        if (mtlDrawable == nil) {
+            return;
+        }
+        J2dTraceLn6(J2D_TRACE_INFO, "MTLLayer.blitTexture: src tex=%p (w=%d, h=%d), dst tex=%p (w=%d, h=%d)", self.buffer, self.buffer.width, self.buffer.height, mtlDrawable.texture, mtlDrawable.texture.width, mtlDrawable.texture.height);
+        id <MTLBlitCommandEncoder> blitEncoder = [commandBuf blitCommandEncoder];
+        [blitEncoder
+                copyFromTexture:self.buffer sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(self.buffer.width, self.buffer.height, 1)
+                toTexture:mtlDrawable.texture destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)];
+        [blitEncoder endEncoding];
+
+        [commandBuf presentDrawable:mtlDrawable];
+
+        [commandBuf addCompletedHandler:^(id <MTLCommandBuffer> cmdBuff) {
+                [cmdBuff release];
+                [ctx.texturePool markAllTexturesFree];
+        }];
+
+        [commandBuf commit];
+    }
+}
+
+- (void) dealloc {
+    self.javaLayer = nil;
+    [super dealloc];
+}
+
+@end
+
+/*
+ * Class:     sun_java2d_metal_CGLLayer
+ * Method:    nativeCreateLayer
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL
+Java_sun_java2d_metal_MTLLayer_nativeCreateLayer
+(JNIEnv *env, jobject obj)
+{
+    __block MTLLayer *layer = nil;
+
+JNF_COCOA_ENTER(env);
+
+    JNFWeakJObjectWrapper *javaLayer = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
+
+    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
+            AWT_ASSERT_APPKIT_THREAD;
+
+            layer = [[MTLLayer alloc] initWithJavaLayer: javaLayer];
+    }];
+
+JNF_COCOA_EXIT(env);
+
+    return ptr_to_jlong(layer);
+}
+
+// Must be called under the RQ lock.
+JNIEXPORT void JNICALL
+Java_sun_java2d_metal_MTLLayer_validate
+(JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData)
+{
+    MTLLayer *layer = OBJC(layerPtr);
+
+    if (surfaceData != NULL) {
+        BMTLSDOps *bmtlsdo = (BMTLSDOps*) SurfaceData_GetOps(env, surfaceData);
+        layer.bufferWidth = bmtlsdo->width;
+        layer.bufferHeight = bmtlsdo->width;
+        layer.buffer = bmtlsdo->pTexture;
+        layer.ctx = ((MTLSDOps *)bmtlsdo->privOps)->configInfo->context;
+        layer.device = layer.ctx.device;
+    } else {
+        layer.ctx = NULL;
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_java2d_metal_MTLLayer_nativeSetScale
+(JNIEnv *env, jclass cls, jlong layerPtr, jdouble scale)
+{
+    JNF_COCOA_ENTER(env);
+    MTLLayer *layer = jlong_to_ptr(layerPtr);
+    // We always call all setXX methods asynchronously, exception is only in
+    // this method where we need to change native texture size and layer's scale
+    // in one call on appkit, otherwise we'll get window's contents blinking,
+    // during screen-2-screen moving.
+    [ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){
+        layer.contentsScale = scale;
+    }];
+    JNF_COCOA_EXIT(env);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLMaskBlit.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLMaskBlit_h_Included
+#define MTLMaskBlit_h_Included
+
+#include "MTLContext.h"
+
+void MTLMaskBlit_MaskBlit(JNIEnv *env, MTLContext *mtlc, BMTLSDOps * dstOps,
+                          jint dstx, jint dsty,
+                          jint width, jint height,
+                          void *pPixels);
+
+#endif /* MTLMaskBlit_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLMaskBlit.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef HEADLESS
+
+#include <stdlib.h>
+#include <jlong.h>
+
+#include "MTLMaskBlit.h"
+#include "MTLRenderQueue.h"
+#include "MTLSurfaceDataBase.h"
+
+/**
+ * REMIND: This method assumes that the dimensions of the incoming pixel
+ *         array are less than or equal to the cached blit texture tile;
+ *         these are rather fragile assumptions, and should be cleaned up...
+ */
+void
+MTLMaskBlit_MaskBlit(JNIEnv *env, MTLContext *mtlc, BMTLSDOps * dstOps,
+                     jint dstx, jint dsty,
+                     jint width, jint height,
+                     void *pPixels)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLMaskBlit_MaskBlit -- :TODO");
+
+    if (width <= 0 || height <= 0) {
+        J2dTraceLn(J2D_TRACE_WARNING,
+                   "MTLMaskBlit_MaskBlit: invalid dimensions");
+        return;
+    }
+}
+
+#endif /* !HEADLESS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLMaskFill.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLMaskFill_h_Included
+#define MTLMaskFill_h_Included
+
+#include "MTLContext.h"
+
+void MTLMaskFill_MaskFill(MTLContext *mtlc, BMTLSDOps * dstOps,
+                          jint x, jint y, jint w, jint h,
+                          jint maskoff, jint maskscan, jint masklen,
+                          unsigned char *pMask);
+
+#endif /* MTLMaskFill_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLMaskFill.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef HEADLESS
+
+#include "sun_java2d_metal_MTLMaskFill.h"
+
+#include "MTLMaskFill.h"
+#include "MTLRenderQueue.h"
+#include "MTLVertexCache.h"
+
+/**
+ * This implementation first copies the alpha tile into a texture and then
+ * maps that texture to the destination surface.  This approach appears to
+ * offer the best performance despite being a two-step process.
+ *
+ * When the source paint is a Color, we can simply use the GL_MODULATE
+ * function to multiply the current color (already premultiplied with the
+ * extra alpha value from the AlphaComposite) with the alpha value from
+ * the mask texture tile.  In picture form, this process looks like:
+ *
+ *                        A     R    G     B
+ *     primary color      Pa    Pr   Pg    Pb    (modulated with...)
+ *     texture unit 0     Ca    Ca   Ca    Ca
+ *     ---------------------------------------
+ *     resulting color    Ra    Rr   Rg    Rb
+ *
+ * where:
+ *     Px = current color (already premultiplied by extra alpha)
+ *     Cx = coverage value from mask tile
+ *     Rx = resulting color/alpha component
+ *
+ * When the source paint is not a Color, it means that we are rendering with
+ * a complex paint (e.g. GradientPaint, TexturePaint).  In this case, we
+ * rely on the GL_ARB_multitexture extension to effectively multiply the
+ * paint fragments (autogenerated on texture unit 1, see the
+ * MTLPaints_Set{Gradient,Texture,etc}Paint() methods for more details)
+ * with the coverage values from the mask texture tile (provided on texture
+ * unit 0), all of which is multiplied with the current color value (which
+ * contains the extra alpha value).  In picture form:
+ *
+ *                        A     R    G     B
+ *     primary color      Ea    Ea   Ea    Ea    (modulated with...)
+ *     texture unit 0     Ca    Ca   Ca    Ca    (modulated with...)
+ *     texture unit 1     Pa    Pr   Pg    Pb
+ *     ---------------------------------------
+ *     resulting color    Ra    Rr   Rg    Rb
+ *
+ * where:
+ *     Ea = extra alpha
+ *     Cx = coverage value from mask tile
+ *     Px = gradient/texture paint color (generated for each fragment)
+ *     Rx = resulting color/alpha component
+ *
+ * Here are some descriptions of the many variables used in this method:
+ *   x,y     - upper left corner of the tile destination
+ *   w,h     - width/height of the mask tile
+ *   x0      - placekeeper for the original destination x location
+ *   tw,th   - width/height of the actual texture tile in pixels
+ *   sx1,sy1 - upper left corner of the mask tile source region
+ *   sx2,sy2 - lower left corner of the mask tile source region
+ *   sx,sy   - "current" upper left corner of the mask tile region of interest
+ */
+void
+MTLMaskFill_MaskFill(MTLContext *mtlc, BMTLSDOps * dstOps,
+                     jint x, jint y, jint w, jint h,
+                     jint maskoff, jint maskscan, jint masklen,
+                     unsigned char *pMask)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLMaskFill_MaskFill -- :TODO");
+}
+
+JNIEXPORT void JNICALL
+Java_sun_java2d_metal_MTLMaskFill_maskFill
+    (JNIEnv *env, jobject self,
+     jint x, jint y, jint w, jint h,
+     jint maskoff, jint maskscan, jint masklen,
+     jbyteArray maskArray)
+{
+    MTLContext *mtlc = MTLRenderQueue_GetCurrentContext();
+    unsigned char *mask;
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLMaskFill_maskFill -- :TODO");
+}
+
+#endif /* !HEADLESS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ */
+
+#ifndef MTLPaints_h_Included
+#define MTLPaints_h_Included
+
+#include "MTLContext.h"
+
+void MTLPaints_ResetPaint(MTLContext *mtlc);
+
+void MTLPaints_SetColor(MTLContext *mtlc, jint pixel);
+
+
+void MTLPaints_SetLinearGradientPaint(MTLContext *mtlc, BMTLSDOps *dstOps,
+                                      jboolean useMask, jboolean linear,
+                                      jint cycleMethod, jint numStops,
+                                      jfloat p0, jfloat p1, jfloat p3,
+                                      void *fractions, void *pixels);
+
+void MTLPaints_SetRadialGradientPaint(MTLContext *mtlc, BMTLSDOps *dstOps,
+                                      jboolean useMask, jboolean linear,
+                                      jint cycleMethod, jint numStops,
+                                      jfloat m00, jfloat m01, jfloat m02,
+                                      jfloat m10, jfloat m11, jfloat m12,
+                                      jfloat focusX,
+                                      void *fractions, void *pixels);
+
+void MTLPaints_SetTexturePaint(MTLContext *mtlc,
+                               jboolean useMask,
+                               jlong pSrcOps, jboolean filter,
+                               jdouble xp0, jdouble xp1, jdouble xp3,
+                               jdouble yp0, jdouble yp1, jdouble yp3);
+
+#endif /* MTLPaints_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef HEADLESS
+
+#include <jlong.h>
+#include <string.h>
+
+#include "sun_java2d_SunGraphics2D.h"
+#include "sun_java2d_pipe_BufferedPaints.h"
+
+#include "MTLPaints.h"
+#include "MTLContext.h"
+#include "MTLRenderQueue.h"
+#include "MTLSurfaceData.h"
+
+void
+MTLPaints_ResetPaint(MTLContext *mtlc)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLPaints_ResetPaint -- :TODO");
+}
+
+void
+MTLPaints_SetColor(MTLContext *mtlc, jint pixel)
+{
+    mtlc.compState = sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR;
+    //TODO
+    [mtlc setColorInt:pixel];
+}
+
+/************************* GradientPaint support ****************************/
+
+static GLuint gradientTexID = 0;
+
+static void
+MTLPaints_InitGradientTexture()
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_InitGradientTexture -- :TODO");
+}
+
+
+/************************** TexturePaint support ****************************/
+
+void
+MTLPaints_SetTexturePaint(MTLContext *mtlc,
+                          jboolean useMask,
+                          jlong pSrcOps, jboolean filter,
+                          jdouble xp0, jdouble xp1, jdouble xp3,
+                          jdouble yp0, jdouble yp1, jdouble yp3)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLPaints_SetTexturePaint -- :TODO");
+}
+
+/****************** Shared MultipleGradientPaint support ********************/
+
+/**
+ * These constants are identical to those defined in the
+ * MultipleGradientPaint.CycleMethod enum; they are copied here for
+ * convenience (ideally we would pull them directly from the Java level,
+ * but that entails more hassle than it is worth).
+ */
+#define CYCLE_NONE    0
+#define CYCLE_REFLECT 1
+#define CYCLE_REPEAT  2
+
+/**
+ * The following constants are flags that can be bitwise-or'ed together
+ * to control how the MultipleGradientPaint shader source code is generated:
+ *
+ *   MULTI_CYCLE_METHOD
+ *     Placeholder for the CycleMethod enum constant.
+ *
+ *   MULTI_LARGE
+ *     If set, use the (slower) shader that supports a larger number of
+ *     gradient colors; otherwise, use the optimized codepath.  See
+ *     the MAX_FRACTIONS_SMALL/LARGE constants below for more details.
+ *
+ *   MULTI_USE_MASK
+ *     If set, apply the alpha mask value from texture unit 0 to the
+ *     final color result (only used in the MaskFill case).
+ *
+ *   MULTI_LINEAR_RGB
+ *     If set, convert the linear RGB result back into the sRGB color space.
+ */
+#define MULTI_CYCLE_METHOD (3 << 0)
+#define MULTI_LARGE        (1 << 2)
+#define MULTI_USE_MASK     (1 << 3)
+#define MULTI_LINEAR_RGB   (1 << 4)
+
+/**
+ * This value determines the size of the array of programs for each
+ * MultipleGradientPaint type.  This value reflects the maximum value that
+ * can be represented by performing a bitwise-or of all the MULTI_*
+ * constants defined above.
+ */
+#define MAX_PROGRAMS 32
+
+/** Evaluates to true if the given bit is set on the local flags variable. */
+#define IS_SET(flagbit) \
+    (((flags) & (flagbit)) != 0)
+
+/** Composes the given parameters as flags into the given flags variable.*/
+#define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \
+    do {                                                   \
+        flags |= ((cycleMethod) & MULTI_CYCLE_METHOD);     \
+        if (large)   flags |= MULTI_LARGE;                 \
+        if (useMask) flags |= MULTI_USE_MASK;              \
+        if (linear)  flags |= MULTI_LINEAR_RGB;            \
+    } while (0)
+
+/** Extracts the CycleMethod enum value from the given flags variable. */
+#define EXTRACT_CYCLE_METHOD(flags) \
+    ((flags) & MULTI_CYCLE_METHOD)
+
+/**
+ * The maximum number of gradient "stops" supported by the fragment shader
+ * and related code.  When the MULTI_LARGE flag is set, we will use
+ * MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL.  By having
+ * two separate values, we can have one highly optimized shader (SMALL) that
+ * supports only a few fractions/colors, and then another, less optimal
+ * shader that supports more stops.
+ */
+#define MAX_FRACTIONS sun_java2d_pipe_BufferedPaints_MULTI_MAX_FRACTIONS
+#define MAX_FRACTIONS_LARGE MAX_FRACTIONS
+#define MAX_FRACTIONS_SMALL 4
+
+/**
+ * The maximum number of gradient colors supported by all of the gradient
+ * fragment shaders.  Note that this value must be a power of two, as it
+ * determines the size of the 1D texture created below.  It also must be
+ * greater than or equal to MAX_FRACTIONS (there is no strict requirement
+ * that the two values be equal).
+ */
+#define MAX_COLORS 16
+
+/**
+ * The handle to the gradient color table texture object used by the shaders.
+ */
+static jint multiGradientTexID = 0;
+
+/**
+ * This is essentially a template of the shader source code that can be used
+ * for either LinearGradientPaint or RadialGradientPaint.  It includes the
+ * structure and some variables that are common to each; the remaining
+ * code snippets (for CycleMethod, ColorSpaceType, and mask modulation)
+ * are filled in prior to compiling the shader at runtime depending on the
+ * paint parameters.  See MTLPaints_CreateMultiGradProgram() for more details.
+ */
+static const char *multiGradientShaderSource =
+    // gradient texture size (in texels)
+    "const int TEXTURE_SIZE = %d;"
+    // maximum number of fractions/colors supported by this shader
+    "const int MAX_FRACTIONS = %d;"
+    // size of a single texel
+    "const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));"
+    // size of half of a single texel
+    "const float HALF_TEXEL = (FULL_TEXEL / 2.0);"
+    // texture containing the gradient colors
+    "uniform sampler1D colors;"
+    // array of gradient stops/fractions
+    "uniform float fractions[MAX_FRACTIONS];"
+    // array of scale factors (one for each interval)
+    "uniform float scaleFactors[MAX_FRACTIONS-1];"
+    // (placeholder for mask variable)
+    "%s"
+    // (placeholder for Linear/RadialGP-specific variables)
+    "%s"
+    ""
+    "void main(void)"
+    "{"
+    "    float dist;"
+         // (placeholder for Linear/RadialGradientPaint-specific code)
+    "    %s"
+    ""
+    "    float tc;"
+         // (placeholder for CycleMethod-specific code)
+    "    %s"
+    ""
+         // calculate interpolated color
+    "    vec4 result = texture1D(colors, tc);"
+    ""
+         // (placeholder for ColorSpace conversion code)
+    "    %s"
+    ""
+         // (placeholder for mask modulation code)
+    "    %s"
+    ""
+         // modulate with gl_Color in order to apply extra alpha
+    "    gl_FragColor = result * gl_Color;"
+    "}";
+
+/**
+ * This code takes a "dist" value as input (as calculated earlier by the
+ * LGP/RGP-specific code) in the range [0,1] and produces a texture
+ * coordinate value "tc" that represents the position of the chosen color
+ * in the one-dimensional gradient texture (also in the range [0,1]).
+ *
+ * One naive way to implement this would be to iterate through the fractions
+ * to figure out in which interval "dist" falls, and then compute the
+ * relative distance between the two nearest stops.  This approach would
+ * require an "if" check on every iteration, and it is best to avoid
+ * conditionals in fragment shaders for performance reasons.  Also, one might
+ * be tempted to use a break statement to jump out of the loop once the
+ * interval was found, but break statements (and non-constant loop bounds)
+ * are not natively available on most graphics hardware today, so that is
+ * a non-starter.
+ *
+ * The more optimal approach used here avoids these issues entirely by using
+ * an accumulation function that is equivalent to the process described above.
+ * The scaleFactors array is pre-initialized at enable time as follows:
+ *     scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]);
+ *
+ * For each iteration, we subtract fractions[i] from dist and then multiply
+ * that value by scaleFactors[i].  If we are within the target interval,
+ * this value will be a fraction in the range [0,1] indicating the relative
+ * distance between fraction[i] and fraction[i+1].  If we are below the
+ * target interval, this value will be negative, so we clamp it to zero
+ * to avoid accumulating any value.  If we are above the target interval,
+ * the value will be greater than one, so we clamp it to one.  Upon exiting
+ * the loop, we will have accumulated zero or more 1.0's and a single
+ * fractional value.  This accumulated value tells us the position of the
+ * fragment color in the one-dimensional gradient texture, i.e., the
+ * texcoord called "tc".
+ */
+static const char *texCoordCalcCode =
+    "int i;"
+    "float relFraction = 0.0;"
+    "for (i = 0; i < MAX_FRACTIONS-1; i++) {"
+    "    relFraction +="
+    "        clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);"
+    "}"
+    // we offset by half a texel so that we find the linearly interpolated
+    // color between the two texel centers of interest
+    "tc = HALF_TEXEL + (FULL_TEXEL * relFraction);";
+
+/** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */
+static const char *noCycleCode =
+    "if (dist <= 0.0) {"
+    "    tc = 0.0;"
+    "} else if (dist >= 1.0) {"
+    "    tc = 1.0;"
+    "} else {"
+         // (placeholder for texcoord calculation)
+    "    %s"
+    "}";
+
+/** Code for REFLECT that gets plugged into the CycleMethod placeholder. */
+static const char *reflectCode =
+    "dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);"
+    // (placeholder for texcoord calculation)
+    "%s";
+
+/** Code for REPEAT that gets plugged into the CycleMethod placeholder. */
+static const char *repeatCode =
+    "dist = fract(dist);"
+    // (placeholder for texcoord calculation)
+    "%s";
+
+static void
+MTLPaints_InitMultiGradientTexture()
+{
+    J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_InitMultiGradientTexture -- :TODO");
+}
+
+/**
+ * Compiles and links the MultipleGradientPaint shader program.  If
+ * successful, this function returns a handle to the newly created
+ * shader program; otherwise returns 0.
+ */
+static GLhandleARB
+MTLPaints_CreateMultiGradProgram(jint flags,
+                                 char *paintVars, char *distCode)
+{
+
+    //TODO
+    J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_CreateMultiGradProgram -- :TODO");
+
+    return NULL;
+}
+
+/**
+ * Called from the MTLPaints_SetLinear/RadialGradientPaint() methods
+ * in order to setup the fraction/color values that are common to both.
+ */
+static void
+MTLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram,
+                                jint numStops,
+                                void *pFractions, void *pPixels)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_SetMultiGradientPaint -- :TODO");
+
+}
+
+/********************** LinearGradientPaint support *************************/
+
+/**
+ * The handles to the LinearGradientPaint fragment program objects.  The
+ * index to the array should be a bitwise-or'ing of the MULTI_* flags defined
+ * above.  Note that most applications will likely need to initialize one
+ * or two of these elements, so the array is usually sparsely populated.
+ */
+static GLhandleARB linearGradPrograms[MAX_PROGRAMS];
+
+/**
+ * Compiles and links the LinearGradientPaint shader program.  If successful,
+ * this function returns a handle to the newly created shader program;
+ * otherwise returns 0.
+ */
+static GLhandleARB
+MTLPaints_CreateLinearGradProgram(jint flags)
+{
+    char *paintVars;
+    char *distCode;
+
+    J2dTraceLn1(J2D_TRACE_INFO,
+                "MTLPaints_CreateLinearGradProgram",
+                flags);
+
+    /*
+     * To simplify the code and to make it easier to upload a number of
+     * uniform values at once, we pack a bunch of scalar (float) values
+     * into vec3 values below.  Here's how the values are related:
+     *
+     *   params.x = p0
+     *   params.y = p1
+     *   params.z = p3
+     *
+     *   yoff = dstOps->yOffset + dstOps->height
+     */
+    paintVars =
+        "uniform vec3 params;"
+        "uniform float yoff;";
+    distCode =
+        // note that gl_FragCoord is in window space relative to the
+        // lower-left corner, so we have to flip the y-coordinate here
+        "vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);"
+        "dist = dot(params, fragCoord);";
+
+    return MTLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
+}
+
+void
+MTLPaints_SetLinearGradientPaint(MTLContext *mtlc, BMTLSDOps *dstOps,
+                                 jboolean useMask, jboolean linear,
+                                 jint cycleMethod, jint numStops,
+                                 jfloat p0, jfloat p1, jfloat p3,
+                                 void *fractions, void *pixels)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLPaints_SetLinearGradientPaint -- :TODO");
+
+}
+
+/********************** RadialGradientPaint support *************************/
+
+/**
+ * The handles to the RadialGradientPaint fragment program objects.  The
+ * index to the array should be a bitwise-or'ing of the MULTI_* flags defined
+ * above.  Note that most applications will likely need to initialize one
+ * or two of these elements, so the array is usually sparsely populated.
+ */
+static GLhandleARB radialGradPrograms[MAX_PROGRAMS];
+
+/**
+ * Compiles and links the RadialGradientPaint shader program.  If successful,
+ * this function returns a handle to the newly created shader program;
+ * otherwise returns 0.
+ */
+static GLhandleARB
+MTLPaints_CreateRadialGradProgram(jint flags)
+{
+    char *paintVars;
+    char *distCode;
+
+    J2dTraceLn1(J2D_TRACE_INFO,
+                "MTLPaints_CreateRadialGradProgram",
+                flags);
+
+    /*
+     * To simplify the code and to make it easier to upload a number of
+     * uniform values at once, we pack a bunch of scalar (float) values
+     * into vec3 and vec4 values below.  Here's how the values are related:
+     *
+     *   m0.x = m00
+     *   m0.y = m01
+     *   m0.z = m02
+     *
+     *   m1.x = m10
+     *   m1.y = m11
+     *   m1.z = m12
+     *
+     *   precalc.x = focusX
+     *   precalc.y = yoff = dstOps->yOffset + dstOps->height
+     *   precalc.z = 1.0 - (focusX * focusX)
+     *   precalc.w = 1.0 / precalc.z
+     */
+    paintVars =
+        "uniform vec3 m0;"
+        "uniform vec3 m1;"
+        "uniform vec4 precalc;";
+
+    /*
+     * The following code is derived from Daniel Rice's whitepaper on
+     * radial gradient performance (attached to the bug report for 6521533).
+     * Refer to that document as well as the setup code in the Java-level
+     * BufferedPaints.setRadialGradientPaint() method for more details.
+     */
+    distCode =
+        // note that gl_FragCoord is in window space relative to the
+        // lower-left corner, so we have to flip the y-coordinate here
+        "vec3 fragCoord ="
+        "    vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);"
+        "float x = dot(fragCoord, m0);"
+        "float y = dot(fragCoord, m1);"
+        "float xfx = x - precalc.x;"
+        "dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;";
+
+    return MTLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
+}
+
+void
+MTLPaints_SetRadialGradientPaint(MTLContext *mtlc, BMTLSDOps *dstOps,
+                                 jboolean useMask, jboolean linear,
+                                 jint cycleMethod, jint numStops,
+                                 jfloat m00, jfloat m01, jfloat m02,
+                                 jfloat m10, jfloat m11, jfloat m12,
+                                 jfloat focusX,
+                                 void *fractions, void *pixels)
+{
+    //TODO
+    J2dTraceLn(J2D_TRACE_ERROR, "MTLPaints_SetRadialGradientPaint -- :TODO");
+
+}
+
+#endif /* !HEADLESS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,31 @@
+#ifndef MTLPipelineStatesStorage_h_Included
+#define MTLPipelineStatesStorage_h_Included
+
+#import <Metal/Metal.h>
+
+@interface MTLPipelineStatesStorage : NSObject {
+@private
+
+id<MTLDevice>       device;
+id<MTLLibrary>      library;
+NSMutableDictionary<NSString*, id<MTLFunction>> * shaders;
+NSMutableDictionary<NSString*, id<MTLRenderPipelineState>> * states;
+MTLRenderPipelineDescriptor * templateRenderPipelineDesc;
+MTLRenderPipelineDescriptor * templateTexturePipelineDesc;
+}
+
+@property (readwrite, assign) id<MTLDevice> device;
+@property (readwrite, retain) id<MTLLibrary> library;
+@property (readwrite, retain) NSMutableDictionary<NSString*, id<MTLFunction>> * shaders;
+@property (readwrite, retain) NSMutableDictionary<NSString*, id<MTLRenderPipelineState>> * states;
+@property (readwrite, retain) MTLRenderPipelineDescriptor * templateRenderPipelineDesc;
+@property (readwrite, retain) MTLRenderPipelineDescriptor * templateTexturePipelineDesc;
+
+- (id) initWithDevice:(id<MTLDevice>)device shaderLibPath:(NSString *)shadersLib;
+- (id<MTLRenderPipelineState>) getRenderPipelineState:(bool)isGradient;
+- (id<MTLRenderPipelineState>) getTexturePipelineState:(bool)isSourcePremultiplied compositeRule:(int)compositeRule;
+- (id<MTLFunction>) getShader:(NSString *)name;
+@end
+
+
+#endif // MTLPipelineStatesStorage_h_Included
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,147 @@
+#import "MTLPipelineStatesStorage.h"
+#import "Trace.h"
+
+#include "GraphicsPrimitiveMgr.h"
+#import "common.h"
+
+@implementation MTLPipelineStatesStorage
+
+@synthesize device;
+@synthesize library;
+@synthesize shaders;
+@synthesize states;
+@synthesize templateRenderPipelineDesc;
+@synthesize templateTexturePipelineDesc;
+
+- (id) initWithDevice:(id<MTLDevice>)dev shaderLibPath:(NSString *)shadersLib {
+    self = [super init];
+    if (self == nil) return self;
+
+    self.device = dev;
+
+    NSError *error = nil;
+    self.library = [dev newLibraryWithFile:shadersLib error:&error];
+    if (!self.library) {
+        NSLog(@"Failed to load library. error %@", error);
+        exit(0);
+    }
+    self.shaders = [NSMutableDictionary dictionaryWithCapacity:10];
+    self.states = [NSMutableDictionary dictionaryWithCapacity:10];
+
+    { // init template descriptors
+        MTLVertexDescriptor *vertDesc = [[MTLVertexDescriptor new] autorelease];
+        vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat3;
+        vertDesc.attributes[VertexAttributePosition].offset = 0;
+        vertDesc.attributes[VertexAttributePosition].bufferIndex = MeshVertexBuffer;
+        vertDesc.layouts[MeshVertexBuffer].stride = sizeof(struct Vertex);
+        vertDesc.layouts[MeshVertexBuffer].stepRate = 1;
+        vertDesc.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
+
+        self.templateRenderPipelineDesc = [[MTLRenderPipelineDescriptor new] autorelease];
+        self.templateRenderPipelineDesc.sampleCount = 1;
+        self.templateRenderPipelineDesc.vertexDescriptor = vertDesc;
+        self.templateRenderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
+        self.templateRenderPipelineDesc.label = @"template_render";
+
+        self.templateTexturePipelineDesc = [[self.templateRenderPipelineDesc copy] autorelease];
+        self.templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].format = MTLVertexFormatFloat2;
+        self.templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].offset = 3*sizeof(float);
+        self.templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].bufferIndex = MeshVertexBuffer;
+        self.templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stride = sizeof(struct TxtVertex);
+        self.templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stepRate = 1;
+        self.templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
+        self.templateTexturePipelineDesc.label = @"template_texture";
+    }
+
+    { // pre-create main states
+        [self getRenderPipelineState:YES];
+        [self getRenderPipelineState:NO];
+        [self getTexturePipelineState:NO compositeRule:RULE_Src];
+        [self getTexturePipelineState:NO compositeRule:RULE_SrcOver];
+    }
+
+    return self;
+}
+
+- (id<MTLRenderPipelineState>) getRenderPipelineState:(bool)isGradient {
+    NSString * uid = [NSString stringWithFormat:@"render_grad[%d]", isGradient];
+
+    id<MTLRenderPipelineState> result = [self.states valueForKey:uid];
+    if (result == nil) {
+        id<MTLFunction> vertexShader   = isGradient ? [self getShader:@"vert_grad"] : [self getShader:@"vert_col"];
+        id<MTLFunction> fragmentShader = isGradient ? [self getShader:@"frag_grad"] : [self getShader:@"frag_col"];
+        MTLRenderPipelineDescriptor *pipelineDesc = [[self.templateRenderPipelineDesc copy] autorelease];
+        pipelineDesc.vertexFunction = vertexShader;
+        pipelineDesc.fragmentFunction = fragmentShader;
+        pipelineDesc.label = uid;
+
+        NSError *error = nil;
+        result = [self.device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
+        if (result == nil) {
+            NSLog(@"Failed to create render pipeline state '%@', error %@", uid, error);
+            exit(0);
+        }
+
+        [self.states setValue:result forKey:uid];
+    }
+
+    return result;
+};
+
+- (id<MTLRenderPipelineState>) getTexturePipelineState:(bool)isSourcePremultiplied compositeRule:(int)compositeRule {
+    NSString * uid = [NSString stringWithFormat:@"texture_compositeRule[%d]", compositeRule];
+
+    id<MTLRenderPipelineState> result = [self.states valueForKey:uid];
+    if (result == nil) {
+        id<MTLFunction> vertexShader   = [self getShader:@"vert_txt"];
+        id<MTLFunction> fragmentShader = [self getShader:@"frag_txt"];
+        MTLRenderPipelineDescriptor *pipelineDesc = [[self.templateTexturePipelineDesc copy] autorelease];
+        pipelineDesc.vertexFunction = vertexShader;
+        pipelineDesc.fragmentFunction = fragmentShader;
+
+        if (compositeRule != RULE_Src) {
+            pipelineDesc.colorAttachments[0].blendingEnabled = YES;
+
+            if (!isSourcePremultiplied)
+                pipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
+
+            //RGB = Source.rgb * SBF + Dest.rgb * DBF
+            //A = Source.a * SBF + Dest.a * DBF
+            //
+            //default SRC:
+            //DBF=0
+            //SBF=1
+            if (compositeRule == RULE_SrcOver) {
+                // SRC_OVER (Porter-Duff Source Over Destination rule):
+                // Ar = As + Ad*(1-As)
+                // Cr = Cs + Cd*(1-As)
+                pipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
+                pipelineDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
+            } else {
+                J2dTrace1(J2D_TRACE_ERROR, "Unimplemented composite rule %d (will be used Src)", compositeRule);
+                pipelineDesc.colorAttachments[0].blendingEnabled = NO;
+            }
+        }
+
+        NSError *error = nil;
+        result = [self.device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
+        if (result == nil) {
+            NSLog(@"Failed to create texture pipeline state '%@', error %@", uid, error);
+            exit(0);
+        }
+
+        [self.states setValue:result forKey:uid];
+    }
+
+    return result;
+}
+
+- (id<MTLFunction>) getShader:(NSString *)name {
+    id<MTLFunction> result = [self.shaders valueForKey:name];
+    if (result == nil) {
+        result = [[self.library newFunctionWithName:name] autorelease];
+        [self.shaders setValue:result forKey:name];
+    }
+    return result;
+}
+@end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.h	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef MTLRenderQueue_h_Included
+#define MTLRenderQueue_h_Included
+
+#include "MTLContext.h"
+#include "MTLSurfaceData.h"
+#include "MTLVertexCache.h"
+
+/*
+ * The following macros are used to pick values (of the specified type) off
+ * the queue.
+ */
+#define NEXT_VAL(buf, type) (((type *)((buf) += sizeof(type)))[-1])
+#define NEXT_BYTE(buf)      NEXT_VAL(buf, unsigned char)
+#define NEXT_INT(buf)       NEXT_VAL(buf, jint)
+#define NEXT_FLOAT(buf)     NEXT_VAL(buf, jfloat)
+#define NEXT_BOOLEAN(buf)   (jboolean)NEXT_INT(buf)
+#define NEXT_LONG(buf)      NEXT_VAL(buf, jlong)
+#define NEXT_DOUBLE(buf)    NEXT_VAL(buf, jdouble)
+
+/*
+ * Increments a pointer (buf) by the given number of bytes.
+ */
+#define SKIP_BYTES(buf, numbytes) buf += (numbytes)
+
+/*
+ * Extracts a value at the given offset from the provided packed value.
+ */
+#define EXTRACT_VAL(packedval, offset, mask) \
+    (((packedval) >> (offset)) & (mask))
+#define EXTRACT_BYTE(packedval, offset) \
+    (unsigned char)EXTRACT_VAL(packedval, offset, 0xff)
+#define EXTRACT_BOOLEAN(packedval, offset) \
+    (jboolean)EXTRACT_VAL(packedval, offset, 0x1)
+
+/*
+ * Parameter used by the RESET_PREVIOUS_OP() convenience macro, which
+ * indicates that any "open" state (such as an unmatched glBegin() or
+ * glEnable(GL_TEXTURE_2D)) should be completed before the following operation
+ * is performed.  SET_SURFACES is an example of an operation that needs to
+ * call RESET_PREVIOUS_OP() before completing the surface change operation.
+ */
+#define MTL_STATE_RESET  -1
+
+/*
+ * Parameter passed to the CHECK_PREVIOUS_OP() macro to indicate that the
+ * following operation represents a "simple" state change.  A simple state
+ * change is one that is allowed to occur within a series of texturing
+ * operations; in other words, this type of state change can occur without
+ * first calling glDisable(GL_TEXTURE_2D).  An example of such an operation
+ * is SET_RECT_CLIP.
+ */
+#define MTL_STATE_CHANGE -2
+
+/*
+ * Parameter passed to the CHECK_PREVIOUS_OP() macro to indicate that the
+ * following operation represents an operation that uses an alpha mask,
+ * such as MTLMaskFill and MTLTR_DrawGrayscaleGlyphNoCache().
+ */
+#define MTL_STATE_MASK_OP -3
+
+/*
+ * Parameter passed to the CHECK_PREVIOUS_OP() macro to indicate that the
+ * following operation represents an operation that uses the glyph cache,
+ * such as MTLTR_DrawGrayscaleGlyphViaCache().
+ */
+#define MTL_STATE_GLYPH_OP -4
+
+/*
+ * Parameter passed to the CHECK_PREVIOUS_OP() macro to indicate that the
+ * following operation represents an operation that renders a
+ * parallelogram via a fragment program (see MTLRenderer).
+ */
+#define MTL_STATE_PGRAM_OP -5
+
+/*
+ * Initializes the "previous operation" state to its default value.
+ */
+#define INIT_PREVIOUS_OP() previousOp = MTL_STATE_RESET
+
+/*
+ * These macros now simply delegate to the CheckPreviousOp() method.
+ */
+#define CHECK_PREVIOUS_OP(op) MTLRenderQueue_CheckPreviousOp(op)
+#define RESET_PREVIOUS_OP() CHECK_PREVIOUS_OP(MTL_STATE_RESET)
+
+/*
+ * The following macros allow the caller to return (or continue) if the
+ * provided value is NULL.  (The strange else clause is included below to
+ * allow for a trailing ';' after RETURN/CONTINUE_IF_NULL() invocations.)
+ */
+#define ACT_IF_NULL(ACTION, value)         \
+    if ((value) == NULL) {                 \
+        J2dTraceLn1(J2D_TRACE_ERROR,       \
+                    "%s is null", #value); \
+        ACTION;                            \
+    } else do { } while (0)
+#define RETURN_IF_NULL(value)   ACT_IF_NULL(return, value)
+#define CONTINUE_IF_NULL(value) ACT_IF_NULL(continue, value)
+
+/*
+ * Exports.
+ */
+extern jint previousOp;
+
+MTLContext *MTLRenderQueue_GetCurrentContext();
+BMTLSDOps *MTLRenderQueue_GetCurrentDestination();
+void MTLRenderQueue_CheckPreviousOp(jint op);
+
+#endif /* MTLRenderQueue_h_Included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m	Thu Aug 22 17:57:55 2019 +0530
@@ -0,0 +1,1143 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef HEADLESS
+
+#include <stdlib.h>
+
+#include "sun_java2d_pipe_BufferedOpCodes.h"
+
+#include "jlong.h"
+#include "MTLBlitLoops.h"
+#include "MTLBufImgOps.h"
+#include "MTLMaskBlit.h"
+#include "MTLMaskFill.h"
+#include "MTLPaints.h"
+#include "MTLRenderQueue.h"
+#include "MTLRenderer.h"
+#include "MTLTextRenderer.h"
+
+/**
+ * Used to track whether we are in a series of a simple primitive operations
+ * or texturing operations.  This variable should be controlled only via
+ * the INIT/CHECK/RESET_PREVIOUS_OP() macros.  See the
+ * MTLRenderQueue_CheckPreviousOp() method below for more information.
+ */
+jint previousOp;
+
+/**
+ * References to the "current" context and destination surface.
+ */
+static MTLContext *mtlc = NULL;
+static BMTLSDOps *dstOps = NULL;
+
+/**
+ * The following methods are implemented in the windowing system (i.e. GLX
+ * and WGL) source files.
+ */
+extern void MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo);
+extern void MTLSD_SwapBuffers(JNIEnv *env, jlong window);
+
+/**
+ * Helper methods to manage modified layers
+ */
+static MTLLayer ** g_modifiedLayers = NULL;
+static int g_modifiedLayersCount = 0;
+static int g_modifiedLayersAllocatedCount = 0;
+
+static void markLayerModified(MTLLayer * modifiedLayer) {
+    if (modifiedLayer == NULL)
+        return;
+    if (g_modifiedLayers == NULL) {
+        g_modifiedLayersAllocatedCount = 3;
+        g_modifiedLayers = malloc(g_modifiedLayersAllocatedCount * sizeof(MTLLayer *));
+    }
+    for (int c = 0; c < g_modifiedLayersCount; ++c) {
+        if (g_modifiedLayers[c] == modifiedLayer)
+            return;
+    }
+    ++g_modifiedLayersCount;
+    if (g_modifiedLayersCount > g_modifiedLayersAllocatedCount) {
+        g_modifiedLayersAllocatedCount = g_modifiedLayersCount;
+        g_modifiedLayers = realloc(g_modifiedLayers, g_modifiedLayersAllocatedCount * sizeof(MTLLayer *));
+    }
+    g_modifiedLayers[g_modifiedLayersCount - 1] = modifiedLayer;
+}
+
+static void scheduleBlitAllModifiedLayers() {
+    for (int c = 0; c < g_modifiedLayersCount; ++c) {
+        MTLLayer * layer = g_modifiedLayers[c];
+        MTLContext * ctx = layer.ctx;
+        if (layer == NULL || ctx == NULL)
+            continue;
+        id<MTLCommandBuffer> bufferToCommit = ctx.commandBuffer;
+        [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
+            [layer blitTexture:bufferToCommit];
+        }];
+
+        [ctx releaseCommandBuffer];
+    }
+    g_modifiedLayersCount = 0;
+}
+
+static void onSurfaceModified(BMTLSDOps *bmtldst) {
+    if (bmtldst != NULL && bmtldst->privOps != NULL && ((MTLSDOps *)bmtldst->privOps)->layer != NULL)
+        markLayerModified(((MTLSDOps *) bmtldst->privOps)->layer);
+}
+
+static const jint g_drawOpcodes[] = {
+        sun_java2d_pipe_BufferedOpCodes_DRAW_LINE,
+        sun_java2d_pipe_BufferedOpCodes_DRAW_RECT,
+        sun_java2d_pipe_BufferedOpCodes_DRAW_POLY,
+        sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL,
+        sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES,
+        sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM,
+        sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM,
+
+        sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST,
+
+        sun_java2d_pipe_BufferedOpCodes_FILL_RECT,
+        sun_java2d_pipe_BufferedOpCodes_FILL_SPANS,
+        sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM,
+        sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM,
+
+        sun_java2d_pipe_BufferedOpCodes_COPY_AREA,
+        sun_java2d_pipe_BufferedOpCodes_MASK_FILL,
+        sun_java2d_pipe_BufferedOpCodes_MASK_BLIT,
+        sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS
+};
+
+static jboolean isDrawOpcode(jint opcode) {
+    for (int c = 0; c < sizeof(g_drawOpcodes)/sizeof(g_drawOpcodes[0]); ++c) {
+        if (opcode == g_drawOpcodes[c])
+            return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
+// TODO : Debug logic added for opcode verification,
+// should be removed later.
+static char *getOpcodeString(jint opcode) {
+    static char opName[30];
+    switch (opcode) {
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE:
+            {
+                strcpy(opName, "DRAW_LINE");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT:
+            {
+                strcpy(opName, "DRAW_RECT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY:
+            {
+                strcpy(opName, "DRAW_POLY");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL:
+            {
+                strcpy(opName, "DRAW_PIXEL");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES:
+            {
+                strcpy(opName, "DRAW_SCANLINES");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM:
+            {
+                strcpy(opName, "DRAW_PARALLELOGRAM");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
+            {
+                strcpy(opName, "DRAW_AAPARALLELOGRAM");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_FILL_RECT:
+            {
+                strcpy(opName, "FILL_RECT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
+            {
+                strcpy(opName, "FILL_SPANS");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM:
+            {
+                strcpy(opName, "FILL_PARALLELOGRAM");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
+            {
+                strcpy(opName, "FILL_AAPARALLELOGRAM");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST:
+            {
+                strcpy(opName, "DRAW_GLYPH_LIST");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_COPY_AREA:
+            {
+                strcpy(opName, "COPY_AREA");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_BLIT:
+            {
+                strcpy(opName, "BLIT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT:
+            {
+                strcpy(opName, "SURFACE_TO_SW_BLIT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
+            {
+                strcpy(opName, "MASK_FILL");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT:
+            {
+
+                strcpy(opName, "MASK_BLIT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_RECT_CLIP:
+            {
+                strcpy(opName, "SET_RECT_CLIP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP:
+            {
+                strcpy(opName, "BEGIN_SHAPE_CLIP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS:
+            {
+                strcpy(opName, "SET_SHAPE_CLIP_SPANS");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP:
+            {
+                strcpy(opName, "END_SHAPE_CLIP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP:
+            {
+                strcpy(opName, "RESET_CLIP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE:
+            {
+                strcpy(opName, "SET_ALPHA_COMPOSITE");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
+            {
+                strcpy(opName, "SET_XOR_COMPOSITE");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
+            {
+                strcpy(opName, "RESET_COMPOSITE");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM:
+            {
+                strcpy(opName, "SET_TRANSFORM");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM:
+            {
+                strcpy(opName, "RESET_TRANSFORM");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES:
+            {
+
+                strcpy(opName, "SET_SURFACES");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
+            {
+                strcpy(opName, "SET_SCRATCH_SURFACE");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
+            {
+                strcpy(opName, "FLUSH_SURFACE");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE:
+            {
+                strcpy(opName, "DISPOSE_SURFACE");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG:
+            {
+                strcpy(opName, "DISPOSE_CONFIG");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
+            {
+                strcpy(opName, "INVALIDATE_CONTEXT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SAVE_STATE:
+            {
+                strcpy(opName, "SAVE_STATE");
+
+            }
+            break;
+
+        case sun_java2d_pipe_BufferedOpCodes_RESTORE_STATE:
+            {
+                strcpy(opName, "RESTORE_STATE");
+
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SYNC:
+            {
+                strcpy(opName, "SYNC");
+
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SWAP_BUFFERS:
+            {
+                strcpy(opName, "SWAP_BUFFERS");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_NOOP:
+            strcpy(opName, "NOOP");
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_RESET_PAINT:
+            {
+                strcpy(opName, "RESET_PAINT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
+            {
+                strcpy(opName, "SET_COLOR");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
+            {
+                strcpy(opName, "SET_GRADIENT_PAINT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT:
+            {
+                strcpy(opName, "SET_LINEAR_GRADIENT_PAINT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_RADIAL_GRADIENT_PAINT:
+            {
+                strcpy(opName, "SET_RADIAL_GRADIENT_PAINT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_SET_TEXTURE_PAINT:
+            {
+                strcpy(opName, "SET_TEXTURE_PAINT");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_ENABLE_CONVOLVE_OP:
+            {
+                strcpy(opName, "ENABLE_CONVOLVE_OP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP:
+            {
+                strcpy(opName, "DISABLE_CONVOLVE_OP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_ENABLE_RESCALE_OP:
+            {
+                strcpy(opName, "ENABLE_RESCALE_OP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP:
+            {
+                 strcpy(opName, "DISABLE_RESCALE_OP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_ENABLE_LOOKUP_OP:
+            {
+                strcpy(opName, "ENABLE_LOOKUP_OP");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP:
+            {
+                strcpy(opName, "DISABLE_LOOKUP_OP");
+            }
+            break;
+        default:
+            strcpy(opName, "UNKNOWN");
+            break;
+        }
+    return opName;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
+    (JNIEnv *env, jobject mtlrq,
+     jlong buf, jint limit)
+{
+    jboolean sync = JNI_FALSE;
+    unsigned char *b, *end;
+
+    J2dTraceLn1(J2D_TRACE_INFO,
+                "MTLRenderQueue_flushBuffer: limit=%d", limit);
+
+    b = (unsigned char *)jlong_to_ptr(buf);
+    if (b == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+            "MTLRenderQueue_flushBuffer: cannot get direct buffer address");
+        return;
+    }
+
+    INIT_PREVIOUS_OP();
+    end = b + limit;
+
+    jboolean DEBUG_LOG = JNI_FALSE;
+    while (b < end) {
+        jint opcode = NEXT_INT(b);
+
+        if (DEBUG_LOG) {
+            J2dTraceLn2(J2D_TRACE_ERROR,
+                    "MTLRenderQueue_flushBuffer: opcode_name = %s, rem=%d",
+                    getOpcodeString(opcode), (end-b));
+        } else {
+            J2dTraceLn2(J2D_TRACE_VERBOSE,
+                    "MTLRenderQueue_flushBuffer: opcode=%d, rem=%d",
+                    opcode, (end-b));
+        }
+
+        if (opcode != sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST &&
+            opcode != sun_java2d_pipe_BufferedOpCodes_NOOP)
+        {
+            //MTLTR_DisableGlyphModeState();
+        }
+
+        switch (opcode) {
+
+        // draw ops
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE:
+            {
+                J2dTraceLn(J2D_TRACE_VERBOSE, "sun_java2d_pipe_BufferedOpCodes_DRAW_LINE");
+                jint x1 = NEXT_INT(b);
+                jint y1 = NEXT_INT(b);
+                jint x2 = NEXT_INT(b);
+                jint y2 = NEXT_INT(b);
+                MTLRenderer_DrawLine(mtlc, dstOps, x1, y1, x2, y2);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT:
+            {
+                jint x = NEXT_INT(b);
+                jint y = NEXT_INT(b);
+                jint w = NEXT_INT(b);
+                jint h = NEXT_INT(b);
+                MTLRenderer_DrawRect(mtlc, dstOps, x, y, w, h);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY:
+            {
+                jint nPoints      = NEXT_INT(b);
+                jboolean isClosed = NEXT_BOOLEAN(b);
+                jint transX       = NEXT_INT(b);
+                jint transY       = NEXT_INT(b);
+                jint *xPoints = (jint *)b;
+                jint *yPoints = ((jint *)b) + nPoints;
+                MTLRenderer_DrawPoly(mtlc, dstOps, nPoints, isClosed, transX, transY, xPoints, yPoints);
+                SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL:
+            {
+                jint x = NEXT_INT(b);
+                jint y = NEXT_INT(b);
+                CONTINUE_IF_NULL(mtlc);
+                //TODO
+                J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderQueue_DRAW_PIXEL -- :TODO");
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES:
+            {
+                jint count = NEXT_INT(b);
+                MTLRenderer_DrawScanlines(mtlc, dstOps, count, (jint *)b);
+
+                SKIP_BYTES(b, count * BYTES_PER_SCANLINE);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM:
+            {
+                jfloat x11 = NEXT_FLOAT(b);
+                jfloat y11 = NEXT_FLOAT(b);
+                jfloat dx21 = NEXT_FLOAT(b);
+                jfloat dy21 = NEXT_FLOAT(b);
+                jfloat dx12 = NEXT_FLOAT(b);
+                jfloat dy12 = NEXT_FLOAT(b);
+                jfloat lwr21 = NEXT_FLOAT(b);
+                jfloat lwr12 = NEXT_FLOAT(b);
+
+                MTLRenderer_DrawParallelogram(mtlc, dstOps,
+                                              x11, y11,
+                                              dx21, dy21,
+                                              dx12, dy12,
+                                              lwr21, lwr12);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
+            {
+                jfloat x11 = NEXT_FLOAT(b);
+                jfloat y11 = NEXT_FLOAT(b);
+                jfloat dx21 = NEXT_FLOAT(b);
+                jfloat dy21 = NEXT_FLOAT(b);
+                jfloat dx12 = NEXT_FLOAT(b);
+                jfloat dy12 = NEXT_FLOAT(b);
+                jfloat lwr21 = NEXT_FLOAT(b);
+                jfloat lwr12 = NEXT_FLOAT(b);
+
+                MTLRenderer_DrawAAParallelogram(mtlc, dstOps,
+                                                x11, y11,
+                                                dx21, dy21,
+                                                dx12, dy12,
+                                                lwr21, lwr12);
+            }
+            break;
+
+        // fill ops
+        case sun_java2d_pipe_BufferedOpCodes_FILL_RECT:
+            {
+                jint x = NEXT_INT(b);
+                jint y = NEXT_INT(b);
+                jint w = NEXT_INT(b);
+                jint h = NEXT_INT(b);
+                MTLRenderer_FillRect(mtlc, dstOps, x, y, w, h);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
+            {
+                jint count = NEXT_INT(b);
+                MTLRenderer_FillSpans(mtlc, dstOps, count, (jint *)b);
+                SKIP_BYTES(b, count * BYTES_PER_SPAN);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM:
+            {
+                jfloat x11 = NEXT_FLOAT(b);
+                jfloat y11 = NEXT_FLOAT(b);
+                jfloat dx21 = NEXT_FLOAT(b);
+                jfloat dy21 = NEXT_FLOAT(b);
+                jfloat dx12 = NEXT_FLOAT(b);
+                jfloat dy12 = NEXT_FLOAT(b);
+                MTLRenderer_FillParallelogram(mtlc, dstOps,
+                                              x11, y11,
+                                              dx21, dy21,
+                                              dx12, dy12);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
+            {
+                jfloat x11 = NEXT_FLOAT(b);
+                jfloat y11 = NEXT_FLOAT(b);
+                jfloat dx21 = NEXT_FLOAT(b);
+                jfloat dy21 = NEXT_FLOAT(b);
+                jfloat dx12 = NEXT_FLOAT(b);
+                jfloat dy12 = NEXT_FLOAT(b);
+                MTLRenderer_FillAAParallelogram(mtlc, dstOps,
+                                                x11, y11,
+                                                dx21, dy21,
+                                                dx12, dy12);
+            }
+            break;
+
+        // text-related ops
+        case sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST:
+            {
+                jint numGlyphs        = NEXT_INT(b);
+                jint packedParams     = NEXT_INT(b);
+                jfloat glyphListOrigX = NEXT_FLOAT(b);
+                jfloat glyphListOrigY = NEXT_FLOAT(b);
+                jboolean usePositions = EXTRACT_BOOLEAN(packedParams,
+                                                        OFFSET_POSITIONS);
+                jboolean subPixPos    = EXTRACT_BOOLEAN(packedParams,
+                                                        OFFSET_SUBPIXPOS);
+                jboolean rgbOrder     = EXTRACT_BOOLEAN(packedParams,
+                                                        OFFSET_RGBORDER);
+                jint lcdContrast      = EXTRACT_BYTE(packedParams,
+                                                     OFFSET_CONTRAST);
+                unsigned char *images = b;
+                unsigned char *positions;
+                jint bytesPerGlyph;
+                if (usePositions) {
+                    positions = (b + numGlyphs * BYTES_PER_GLYPH_IMAGE);
+                    bytesPerGlyph = BYTES_PER_POSITIONED_GLYPH;
+                } else {
+                    positions = NULL;
+                    bytesPerGlyph = BYTES_PER_GLYPH_IMAGE;
+                }
+                MTLTR_DrawGlyphList(env, mtlc, dstOps,
+                                    numGlyphs, usePositions,
+                                    subPixPos, rgbOrder, lcdContrast,
+                                    glyphListOrigX, glyphListOrigY,
+                                    images, positions);
+                SKIP_BYTES(b, numGlyphs * bytesPerGlyph);
+            }
+            break;
+
+        // copy-related ops
+        case sun_java2d_pipe_BufferedOpCodes_COPY_AREA:
+            {
+                jint x  = NEXT_INT(b);
+                jint y  = NEXT_INT(b);
+                jint w  = NEXT_INT(b);
+                jint h  = NEXT_INT(b);
+                jint dx = NEXT_INT(b);
+                jint dy = NEXT_INT(b);
+                MTLBlitLoops_CopyArea(env, mtlc, dstOps,
+                                      x, y, w, h, dx, dy);
+            }
+            break;
+        case sun_java2d_pipe_BufferedOpCodes_BLIT:
+            {
+
+                jint packedParams = NEXT_INT(b);
+                jint sx1          = NEXT_INT(b);
+                jint sy1          = NEXT_INT(b);
+                jint sx2          = NEXT_INT(b);
+                jint sy2          = NEXT_INT(b);
+                jdouble dx1       = NEXT_DOUBLE(b);
+