1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.java2d.metal;
  27 
  28 import sun.java2d.SurfaceData;
  29 import sun.java2d.loops.*;
  30 import sun.java2d.pipe.Region;
  31 import sun.java2d.pipe.RenderBuffer;
  32 import sun.java2d.pipe.RenderQueue;
  33 
  34 import java.awt.*;
  35 import java.awt.geom.AffineTransform;
  36 import java.awt.image.AffineTransformOp;
  37 import java.awt.image.BufferedImage;
  38 import java.awt.image.BufferedImageOp;
  39 import java.lang.annotation.Native;
  40 import java.lang.ref.WeakReference;
  41 
  42 import static sun.java2d.pipe.BufferedOpCodes.BLIT;
  43 import static sun.java2d.pipe.BufferedOpCodes.SURFACE_TO_SW_BLIT;
  44 
  45 final class MTLBlitLoops {
  46 
  47     static void register() {
  48         Blit blitIntArgbPreToSurface =
  49             new MTLSwToSurfaceBlit(SurfaceType.IntArgbPre,
  50                                    MTLSurfaceDataBase.PF_INT_ARGB_PRE);
  51         Blit blitIntArgbPreToTexture =
  52             new MTLSwToTextureBlit(SurfaceType.IntArgbPre,
  53                                    MTLSurfaceDataBase.PF_INT_ARGB_PRE);
  54         TransformBlit transformBlitIntArgbPreToSurface =
  55             new MTLSwToSurfaceTransform(SurfaceType.IntArgbPre,
  56                                         MTLSurfaceDataBase.PF_INT_ARGB_PRE);
  57         MTLSurfaceToSwBlit blitSurfaceToIntArgbPre =
  58             new MTLSurfaceToSwBlit(SurfaceType.IntArgbPre,
  59                                    MTLSurfaceDataBase.PF_INT_ARGB_PRE);
  60 
  61         GraphicsPrimitive[] primitives = {
  62             // surface->surface ops
  63             new MTLSurfaceToSurfaceBlit(),
  64             new MTLSurfaceToSurfaceScale(),
  65             new MTLSurfaceToSurfaceTransform(),
  66 
  67             // render-to-texture surface->surface ops
  68             new MTLRTTSurfaceToSurfaceBlit(),
  69             new MTLRTTSurfaceToSurfaceScale(),
  70             new MTLRTTSurfaceToSurfaceTransform(),
  71 
  72             // surface->sw ops
  73             new MTLSurfaceToSwBlit(SurfaceType.IntArgb,
  74                                    MTLSurfaceDataBase.PF_INT_ARGB),
  75             blitSurfaceToIntArgbPre,
  76 
  77             // sw->surface ops
  78             blitIntArgbPreToSurface,
  79             new MTLSwToSurfaceBlit(SurfaceType.IntRgb,
  80                                    MTLSurfaceDataBase.PF_INT_RGB),
  81             new MTLSwToSurfaceBlit(SurfaceType.IntRgbx,
  82                                    MTLSurfaceDataBase.PF_INT_RGBX),
  83             new MTLSwToSurfaceBlit(SurfaceType.IntBgr,
  84                                    MTLSurfaceDataBase.PF_INT_BGR),
  85             new MTLSwToSurfaceBlit(SurfaceType.IntBgrx,
  86                                    MTLSurfaceDataBase.PF_INT_BGRX),
  87             new MTLSwToSurfaceBlit(SurfaceType.ThreeByteBgr,
  88                                    MTLSurfaceDataBase.PF_3BYTE_BGR),
  89             new MTLSwToSurfaceBlit(SurfaceType.Ushort565Rgb,
  90                                    MTLSurfaceDataBase.PF_USHORT_565_RGB),
  91             new MTLSwToSurfaceBlit(SurfaceType.Ushort555Rgb,
  92                                    MTLSurfaceDataBase.PF_USHORT_555_RGB),
  93             new MTLSwToSurfaceBlit(SurfaceType.Ushort555Rgbx,
  94                                    MTLSurfaceDataBase.PF_USHORT_555_RGBX),
  95             new MTLSwToSurfaceBlit(SurfaceType.ByteGray,
  96                                    MTLSurfaceDataBase.PF_BYTE_GRAY),
  97             new MTLSwToSurfaceBlit(SurfaceType.UshortGray,
  98                                    MTLSurfaceDataBase.PF_USHORT_GRAY),
  99             new MTLGeneralBlit(MTLSurfaceDataBase.MTLSurface,
 100                                CompositeType.AnyAlpha,
 101                                blitIntArgbPreToSurface),
 102 
 103             new MTLAnyCompositeBlit(MTLSurfaceDataBase.MTLSurface,
 104                                     blitSurfaceToIntArgbPre,
 105                                     blitSurfaceToIntArgbPre,
 106                                     blitIntArgbPreToSurface),
 107             new MTLAnyCompositeBlit(SurfaceType.Any,
 108                                     null,
 109                                     blitSurfaceToIntArgbPre,
 110                                     blitIntArgbPreToSurface),
 111 
 112             new MTLSwToSurfaceScale(SurfaceType.IntRgb,
 113                                     MTLSurfaceDataBase.PF_INT_RGB),
 114             new MTLSwToSurfaceScale(SurfaceType.IntRgbx,
 115                                     MTLSurfaceDataBase.PF_INT_RGBX),
 116             new MTLSwToSurfaceScale(SurfaceType.IntBgr,
 117                                     MTLSurfaceDataBase.PF_INT_BGR),
 118             new MTLSwToSurfaceScale(SurfaceType.IntBgrx,
 119                                     MTLSurfaceDataBase.PF_INT_BGRX),
 120             new MTLSwToSurfaceScale(SurfaceType.ThreeByteBgr,
 121                                     MTLSurfaceDataBase.PF_3BYTE_BGR),
 122             new MTLSwToSurfaceScale(SurfaceType.Ushort565Rgb,
 123                                     MTLSurfaceDataBase.PF_USHORT_565_RGB),
 124             new MTLSwToSurfaceScale(SurfaceType.Ushort555Rgb,
 125                                     MTLSurfaceDataBase.PF_USHORT_555_RGB),
 126             new MTLSwToSurfaceScale(SurfaceType.Ushort555Rgbx,
 127                                     MTLSurfaceDataBase.PF_USHORT_555_RGBX),
 128             new MTLSwToSurfaceScale(SurfaceType.ByteGray,
 129                                     MTLSurfaceDataBase.PF_BYTE_GRAY),
 130             new MTLSwToSurfaceScale(SurfaceType.UshortGray,
 131                                     MTLSurfaceDataBase.PF_USHORT_GRAY),
 132             new MTLSwToSurfaceScale(SurfaceType.IntArgbPre,
 133                                     MTLSurfaceDataBase.PF_INT_ARGB_PRE),
 134 
 135             new MTLSwToSurfaceTransform(SurfaceType.IntRgb,
 136                                         MTLSurfaceDataBase.PF_INT_RGB),
 137             new MTLSwToSurfaceTransform(SurfaceType.IntRgbx,
 138                                         MTLSurfaceDataBase.PF_INT_RGBX),
 139             new MTLSwToSurfaceTransform(SurfaceType.IntBgr,
 140                                         MTLSurfaceDataBase.PF_INT_BGR),
 141             new MTLSwToSurfaceTransform(SurfaceType.IntBgrx,
 142                                         MTLSurfaceDataBase.PF_INT_BGRX),
 143             new MTLSwToSurfaceTransform(SurfaceType.ThreeByteBgr,
 144                                         MTLSurfaceDataBase.PF_3BYTE_BGR),
 145             new MTLSwToSurfaceTransform(SurfaceType.Ushort565Rgb,
 146                                         MTLSurfaceDataBase.PF_USHORT_565_RGB),
 147             new MTLSwToSurfaceTransform(SurfaceType.Ushort555Rgb,
 148                                         MTLSurfaceDataBase.PF_USHORT_555_RGB),
 149             new MTLSwToSurfaceTransform(SurfaceType.Ushort555Rgbx,
 150                                         MTLSurfaceDataBase.PF_USHORT_555_RGBX),
 151             new MTLSwToSurfaceTransform(SurfaceType.ByteGray,
 152                                         MTLSurfaceDataBase.PF_BYTE_GRAY),
 153             new MTLSwToSurfaceTransform(SurfaceType.UshortGray,
 154                                         MTLSurfaceDataBase.PF_USHORT_GRAY),
 155             transformBlitIntArgbPreToSurface,
 156 
 157             new MTLGeneralTransformedBlit(transformBlitIntArgbPreToSurface),
 158 
 159             // texture->surface ops
 160             new MTLTextureToSurfaceBlit(),
 161             new MTLTextureToSurfaceScale(),
 162             new MTLTextureToSurfaceTransform(),
 163 
 164             // sw->texture ops
 165             blitIntArgbPreToTexture,
 166             new MTLSwToTextureBlit(SurfaceType.IntRgb,
 167                                    MTLSurfaceDataBase.PF_INT_RGB),
 168             new MTLSwToTextureBlit(SurfaceType.IntRgbx,
 169                                    MTLSurfaceDataBase.PF_INT_RGBX),
 170             new MTLSwToTextureBlit(SurfaceType.IntBgr,
 171                                    MTLSurfaceDataBase.PF_INT_BGR),
 172             new MTLSwToTextureBlit(SurfaceType.IntBgrx,
 173                                    MTLSurfaceDataBase.PF_INT_BGRX),
 174             new MTLSwToTextureBlit(SurfaceType.ThreeByteBgr,
 175                                    MTLSurfaceDataBase.PF_3BYTE_BGR),
 176             new MTLSwToTextureBlit(SurfaceType.Ushort565Rgb,
 177                                    MTLSurfaceDataBase.PF_USHORT_565_RGB),
 178             new MTLSwToTextureBlit(SurfaceType.Ushort555Rgb,
 179                                    MTLSurfaceDataBase.PF_USHORT_555_RGB),
 180             new MTLSwToTextureBlit(SurfaceType.Ushort555Rgbx,
 181                                    MTLSurfaceDataBase.PF_USHORT_555_RGBX),
 182             new MTLSwToTextureBlit(SurfaceType.ByteGray,
 183                                    MTLSurfaceDataBase.PF_BYTE_GRAY),
 184             new MTLSwToTextureBlit(SurfaceType.UshortGray,
 185                                    MTLSurfaceDataBase.PF_USHORT_GRAY),
 186             new MTLGeneralBlit(MTLSurfaceDataBase.MTLTexture,
 187                                CompositeType.SrcNoEa,
 188                                blitIntArgbPreToTexture),
 189         };
 190         GraphicsPrimitiveMgr.register(primitives);
 191     }
 192 
 193     /**
 194      * The following offsets are used to pack the parameters in
 195      * createPackedParams().  (They are also used at the native level when
 196      * unpacking the params.)
 197      */
 198     @Native private static final int OFFSET_SRCTYPE = 16;
 199     @Native private static final int OFFSET_HINT    =  8;
 200     @Native private static final int OFFSET_TEXTURE =  3;
 201     @Native private static final int OFFSET_RTT     =  2;
 202     @Native private static final int OFFSET_XFORM   =  1;
 203     @Native private static final int OFFSET_ISOBLIT =  0;
 204 
 205     /**
 206      * Packs the given parameters into a single int value in order to save
 207      * space on the rendering queue.
 208      */
 209     private static int createPackedParams(boolean isoblit, boolean texture,
 210                                           boolean rtt, boolean xform,
 211                                           int hint, int srctype)
 212     {
 213         return
 214             ((srctype           << OFFSET_SRCTYPE) |
 215              (hint              << OFFSET_HINT   ) |
 216              ((texture ? 1 : 0) << OFFSET_TEXTURE) |
 217              ((rtt     ? 1 : 0) << OFFSET_RTT    ) |
 218              ((xform   ? 1 : 0) << OFFSET_XFORM  ) |
 219              ((isoblit ? 1 : 0) << OFFSET_ISOBLIT));
 220     }
 221 
 222     /**
 223      * Enqueues a BLIT operation with the given parameters.  Note that the
 224      * RenderQueue lock must be held before calling this method.
 225      */
 226     private static void enqueueBlit(RenderQueue rq,
 227                                     SurfaceData src, SurfaceData dst,
 228                                     int packedParams,
 229                                     int sx1, int sy1,
 230                                     int sx2, int sy2,
 231                                     double dx1, double dy1,
 232                                     double dx2, double dy2)
 233     {
 234         // assert rq.lock.isHeldByCurrentThread();
 235         RenderBuffer buf = rq.getBuffer();
 236         rq.ensureCapacityAndAlignment(72, 24);
 237         buf.putInt(BLIT);
 238         buf.putInt(packedParams);
 239         buf.putInt(sx1).putInt(sy1);
 240         buf.putInt(sx2).putInt(sy2);
 241         buf.putDouble(dx1).putDouble(dy1);
 242         buf.putDouble(dx2).putDouble(dy2);
 243         buf.putLong(src.getNativeOps());
 244         buf.putLong(dst.getNativeOps());
 245     }
 246 
 247     static void Blit(SurfaceData srcData, SurfaceData dstData,
 248                      Composite comp, Region clip,
 249                      AffineTransform xform, int hint,
 250                      int sx1, int sy1,
 251                      int sx2, int sy2,
 252                      double dx1, double dy1,
 253                      double dx2, double dy2,
 254                      int srctype, boolean texture)
 255     {
 256         int ctxflags = 0;
 257         if (srcData.getTransparency() == Transparency.OPAQUE) {
 258             ctxflags |= MTLContext.SRC_IS_OPAQUE;
 259         }
 260 
 261         MTLRenderQueue rq = MTLRenderQueue.getInstance();
 262         rq.lock();
 263         try {
 264             // make sure the RenderQueue keeps a hard reference to the
 265             // source (sysmem) SurfaceData to prevent it from being
 266             // disposed while the operation is processed on the QFT
 267             rq.addReference(srcData);
 268 
 269             MTLSurfaceDataBase oglDst = (MTLSurfaceDataBase)dstData;
 270             if (texture) {
 271                 // make sure we have a current context before uploading
 272                 // the sysmem data to the texture object
 273                 MTLGraphicsConfigBase gc = oglDst.getMTLGraphicsConfig();
 274                 MTLContext.setScratchSurface(gc);
 275             } else {
 276                 MTLContext.validateContext(oglDst, oglDst,
 277                                            clip, comp, xform, null, null,
 278                                            ctxflags);
 279             }
 280 
 281             int packedParams = createPackedParams(false, texture,
 282                                                   false, xform != null,
 283                                                   hint, srctype);
 284             enqueueBlit(rq, srcData, dstData,
 285                         packedParams,
 286                         sx1, sy1, sx2, sy2,
 287                         dx1, dy1, dx2, dy2);
 288 
 289             // always flush immediately, since we (currently) have no means
 290             // of tracking changes to the system memory surface
 291             rq.flushNow();
 292         } finally {
 293             rq.unlock();
 294         }
 295     }
 296 
 297     /**
 298      * Note: The srcImg and biop parameters are only used when invoked
 299      * from the MTLBufImgOps.renderImageWithOp() method; in all other cases,
 300      * this method can be called with null values for those two parameters,
 301      * and they will be effectively ignored.
 302      */
 303     static void IsoBlit(SurfaceData srcData, SurfaceData dstData,
 304                         BufferedImage srcImg, BufferedImageOp biop,
 305                         Composite comp, Region clip,
 306                         AffineTransform xform, int hint,
 307                         int sx1, int sy1,
 308                         int sx2, int sy2,
 309                         double dx1, double dy1,
 310                         double dx2, double dy2,
 311                         boolean texture)
 312     {
 313         int ctxflags = 0;
 314         if (srcData.getTransparency() == Transparency.OPAQUE) {
 315             ctxflags |= MTLContext.SRC_IS_OPAQUE;
 316         }
 317 
 318         MTLRenderQueue rq = MTLRenderQueue.getInstance();
 319         rq.lock();
 320         try {
 321             MTLSurfaceDataBase oglSrc = (MTLSurfaceDataBase)srcData;
 322             MTLSurfaceDataBase oglDst = (MTLSurfaceDataBase)dstData;
 323             int srctype = oglSrc.getType();
 324             boolean rtt;
 325             MTLSurfaceDataBase srcCtxData;
 326             if (srctype == MTLSurfaceDataBase.TEXTURE) {
 327                 // the source is a regular texture object; we substitute
 328                 // the destination surface for the purposes of making a
 329                 // context current
 330                 rtt = false;
 331                 srcCtxData = oglDst;
 332             } else {
 333                 // the source is a pbuffer, backbuffer, or render-to-texture
 334                 // surface; we set rtt to true to differentiate this kind
 335                 // of surface from a regular texture object
 336                 rtt = true;
 337                 if (srctype == MTLSurfaceDataBase.FBOBJECT) {
 338                     srcCtxData = oglDst;
 339                 } else {
 340                     srcCtxData = oglSrc;
 341                 }
 342             }
 343 
 344             MTLContext.validateContext(srcCtxData, oglDst,
 345                                        clip, comp, xform, null, null,
 346                                        ctxflags);
 347 
 348             if (biop != null) {
 349                 MTLBufImgOps.enableBufImgOp(rq, oglSrc, srcImg, biop);
 350             }
 351 
 352             int packedParams = createPackedParams(true, texture,
 353                                                   rtt, xform != null,
 354                                                   hint, 0 /*unused*/);
 355             enqueueBlit(rq, srcData, dstData,
 356                         packedParams,
 357                         sx1, sy1, sx2, sy2,
 358                         dx1, dy1, dx2, dy2);
 359 
 360             if (biop != null) {
 361                 MTLBufImgOps.disableBufImgOp(rq, biop);
 362             }
 363 
 364             if (rtt && oglDst.isOnScreen()) {
 365                 // we only have to flush immediately when copying from a
 366                 // (non-texture) surface to the screen; otherwise Swing apps
 367                 // might appear unresponsive until the auto-flush completes
 368                 rq.flushNow();
 369             }
 370         } finally {
 371             rq.unlock();
 372         }
 373     }
 374 }
 375 
 376 class MTLSurfaceToSurfaceBlit extends Blit {
 377 
 378     MTLSurfaceToSurfaceBlit() {
 379         super(MTLSurfaceDataBase.MTLSurface,
 380               CompositeType.AnyAlpha,
 381               MTLSurfaceDataBase.MTLSurface);
 382     }
 383 
 384     public void Blit(SurfaceData src, SurfaceData dst,
 385                      Composite comp, Region clip,
 386                      int sx, int sy, int dx, int dy, int w, int h)
 387     {
 388         MTLBlitLoops.IsoBlit(src, dst,
 389                              null, null,
 390                              comp, clip, null,
 391                              AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 392                              sx, sy, sx+w, sy+h,
 393                              dx, dy, dx+w, dy+h,
 394                              false);
 395     }
 396 }
 397 
 398 class MTLSurfaceToSurfaceScale extends ScaledBlit {
 399 
 400     MTLSurfaceToSurfaceScale() {
 401         super(MTLSurfaceDataBase.MTLSurface,
 402               CompositeType.AnyAlpha,
 403               MTLSurfaceDataBase.MTLSurface);
 404     }
 405 
 406     public void Scale(SurfaceData src, SurfaceData dst,
 407                       Composite comp, Region clip,
 408                       int sx1, int sy1,
 409                       int sx2, int sy2,
 410                       double dx1, double dy1,
 411                       double dx2, double dy2)
 412     {
 413         MTLBlitLoops.IsoBlit(src, dst,
 414                              null, null,
 415                              comp, clip, null,
 416                              AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 417                              sx1, sy1, sx2, sy2,
 418                              dx1, dy1, dx2, dy2,
 419                              false);
 420     }
 421 }
 422 
 423 class MTLSurfaceToSurfaceTransform extends TransformBlit {
 424 
 425     MTLSurfaceToSurfaceTransform() {
 426         super(MTLSurfaceDataBase.MTLSurface,
 427               CompositeType.AnyAlpha,
 428               MTLSurfaceDataBase.MTLSurface);
 429     }
 430 
 431     public void Transform(SurfaceData src, SurfaceData dst,
 432                           Composite comp, Region clip,
 433                           AffineTransform at, int hint,
 434                           int sx, int sy, int dx, int dy,
 435                           int w, int h)
 436     {
 437         MTLBlitLoops.IsoBlit(src, dst,
 438                              null, null,
 439                              comp, clip, at, hint,
 440                              sx, sy, sx+w, sy+h,
 441                              dx, dy, dx+w, dy+h,
 442                              false);
 443     }
 444 }
 445 
 446 class MTLRTTSurfaceToSurfaceBlit extends Blit {
 447 
 448     MTLRTTSurfaceToSurfaceBlit() {
 449         super(MTLSurfaceDataBase.MTLSurfaceRTT,
 450               CompositeType.AnyAlpha,
 451               MTLSurfaceDataBase.MTLSurface);
 452     }
 453 
 454     public void Blit(SurfaceData src, SurfaceData dst,
 455                      Composite comp, Region clip,
 456                      int sx, int sy, int dx, int dy, int w, int h)
 457     {
 458         MTLBlitLoops.IsoBlit(src, dst,
 459                              null, null,
 460                              comp, clip, null,
 461                              AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 462                              sx, sy, sx+w, sy+h,
 463                              dx, dy, dx+w, dy+h,
 464                              true);
 465     }
 466 }
 467 
 468 class MTLRTTSurfaceToSurfaceScale extends ScaledBlit {
 469 
 470     MTLRTTSurfaceToSurfaceScale() {
 471         super(MTLSurfaceDataBase.MTLSurfaceRTT,
 472               CompositeType.AnyAlpha,
 473               MTLSurfaceDataBase.MTLSurface);
 474     }
 475 
 476     public void Scale(SurfaceData src, SurfaceData dst,
 477                       Composite comp, Region clip,
 478                       int sx1, int sy1,
 479                       int sx2, int sy2,
 480                       double dx1, double dy1,
 481                       double dx2, double dy2)
 482     {
 483         MTLBlitLoops.IsoBlit(src, dst,
 484                              null, null,
 485                              comp, clip, null,
 486                              AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 487                              sx1, sy1, sx2, sy2,
 488                              dx1, dy1, dx2, dy2,
 489                              true);
 490     }
 491 }
 492 
 493 class MTLRTTSurfaceToSurfaceTransform extends TransformBlit {
 494 
 495     MTLRTTSurfaceToSurfaceTransform() {
 496         super(MTLSurfaceDataBase.MTLSurfaceRTT,
 497               CompositeType.AnyAlpha,
 498               MTLSurfaceDataBase.MTLSurface);
 499     }
 500 
 501     public void Transform(SurfaceData src, SurfaceData dst,
 502                           Composite comp, Region clip,
 503                           AffineTransform at, int hint,
 504                           int sx, int sy, int dx, int dy, int w, int h)
 505     {
 506         MTLBlitLoops.IsoBlit(src, dst,
 507                              null, null,
 508                              comp, clip, at, hint,
 509                              sx, sy, sx+w, sy+h,
 510                              dx, dy, dx+w, dy+h,
 511                              true);
 512     }
 513 }
 514 
 515 final class MTLSurfaceToSwBlit extends Blit {
 516 
 517     private final int typeval;
 518     private WeakReference<SurfaceData> srcTmp;
 519 
 520     // destination will actually be ArgbPre or Argb
 521     MTLSurfaceToSwBlit(final SurfaceType dstType, final int typeval) {
 522         super(MTLSurfaceDataBase.MTLSurface,
 523               CompositeType.SrcNoEa,
 524               dstType);
 525         this.typeval = typeval;
 526     }
 527 
 528     private synchronized void complexClipBlit(SurfaceData src, SurfaceData dst,
 529                                               Composite comp, Region clip,
 530                                               int sx, int sy, int dx, int dy,
 531                                               int w, int h) {
 532         SurfaceData cachedSrc = null;
 533         if (srcTmp != null) {
 534             // use cached intermediate surface, if available
 535             cachedSrc = srcTmp.get();
 536         }
 537 
 538         // We can convert argb_pre data from MTL surface in two places:
 539         // - During MTL surface -> SW blit
 540         // - During SW -> SW blit
 541         // The first one is faster when we use opaque MTL surface, because in
 542         // this case we simply skip conversion and use color components as is.
 543         // Because of this we align intermediate buffer type with type of
 544         // destination not source.
 545         final int type = typeval == MTLSurfaceDataBase.PF_INT_ARGB_PRE ?
 546                          BufferedImage.TYPE_INT_ARGB_PRE :
 547                          BufferedImage.TYPE_INT_ARGB;
 548 
 549         src = convertFrom(this, src, sx, sy, w, h, cachedSrc, type);
 550 
 551         // copy intermediate SW to destination SW using complex clip
 552         final Blit performop = Blit.getFromCache(src.getSurfaceType(),
 553                                                  CompositeType.SrcNoEa,
 554                                                  dst.getSurfaceType());
 555         performop.Blit(src, dst, comp, clip, 0, 0, dx, dy, w, h);
 556 
 557         if (src != cachedSrc) {
 558             // cache the intermediate surface
 559             srcTmp = new WeakReference<>(src);
 560         }
 561     }
 562 
 563     public void Blit(SurfaceData src, SurfaceData dst,
 564                      Composite comp, Region clip,
 565                      int sx, int sy, int dx, int dy,
 566                      int w, int h)
 567     {
 568         if (clip != null) {
 569             clip = clip.getIntersectionXYWH(dx, dy, w, h);
 570             // At the end this method will flush the RenderQueue, we should exit
 571             // from it as soon as possible.
 572             if (clip.isEmpty()) {
 573                 return;
 574             }
 575             sx += clip.getLoX() - dx;
 576             sy += clip.getLoY() - dy;
 577             dx = clip.getLoX();
 578             dy = clip.getLoY();
 579             w = clip.getWidth();
 580             h = clip.getHeight();
 581 
 582             if (!clip.isRectangular()) {
 583                 complexClipBlit(src, dst, comp, clip, sx, sy, dx, dy, w, h);
 584                 return;
 585             }
 586         }
 587 
 588         MTLRenderQueue rq = MTLRenderQueue.getInstance();
 589         rq.lock();
 590         try {
 591             // make sure the RenderQueue keeps a hard reference to the
 592             // destination (sysmem) SurfaceData to prevent it from being
 593             // disposed while the operation is processed on the QFT
 594             rq.addReference(dst);
 595 
 596             RenderBuffer buf = rq.getBuffer();
 597             MTLContext.validateContext((MTLSurfaceDataBase)src);
 598 
 599             rq.ensureCapacityAndAlignment(48, 32);
 600             buf.putInt(SURFACE_TO_SW_BLIT);
 601             buf.putInt(sx).putInt(sy);
 602             buf.putInt(dx).putInt(dy);
 603             buf.putInt(w).putInt(h);
 604             buf.putInt(typeval);
 605             buf.putLong(src.getNativeOps());
 606             buf.putLong(dst.getNativeOps());
 607 
 608             // always flush immediately
 609             rq.flushNow();
 610         } finally {
 611             rq.unlock();
 612         }
 613     }
 614 }
 615 
 616 class MTLSwToSurfaceBlit extends Blit {
 617 
 618     private int typeval;
 619 
 620     MTLSwToSurfaceBlit(SurfaceType srcType, int typeval) {
 621         super(srcType,
 622               CompositeType.AnyAlpha,
 623               MTLSurfaceDataBase.MTLSurface);
 624         this.typeval = typeval;
 625     }
 626 
 627     public void Blit(SurfaceData src, SurfaceData dst,
 628                      Composite comp, Region clip,
 629                      int sx, int sy, int dx, int dy, int w, int h)
 630     {
 631         MTLBlitLoops.Blit(src, dst,
 632                           comp, clip, null,
 633                           AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 634                           sx, sy, sx+w, sy+h,
 635                           dx, dy, dx+w, dy+h,
 636                           typeval, false);
 637     }
 638 }
 639 
 640 class MTLSwToSurfaceScale extends ScaledBlit {
 641 
 642     private int typeval;
 643 
 644     MTLSwToSurfaceScale(SurfaceType srcType, int typeval) {
 645         super(srcType,
 646               CompositeType.AnyAlpha,
 647               MTLSurfaceDataBase.MTLSurface);
 648         this.typeval = typeval;
 649     }
 650 
 651     public void Scale(SurfaceData src, SurfaceData dst,
 652                       Composite comp, Region clip,
 653                       int sx1, int sy1,
 654                       int sx2, int sy2,
 655                       double dx1, double dy1,
 656                       double dx2, double dy2)
 657     {
 658         MTLBlitLoops.Blit(src, dst,
 659                           comp, clip, null,
 660                           AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 661                           sx1, sy1, sx2, sy2,
 662                           dx1, dy1, dx2, dy2,
 663                           typeval, false);
 664     }
 665 }
 666 
 667 class MTLSwToSurfaceTransform extends TransformBlit {
 668 
 669     private int typeval;
 670 
 671     MTLSwToSurfaceTransform(SurfaceType srcType, int typeval) {
 672         super(srcType,
 673               CompositeType.AnyAlpha,
 674               MTLSurfaceDataBase.MTLSurface);
 675         this.typeval = typeval;
 676     }
 677 
 678     public void Transform(SurfaceData src, SurfaceData dst,
 679                           Composite comp, Region clip,
 680                           AffineTransform at, int hint,
 681                           int sx, int sy, int dx, int dy, int w, int h)
 682     {
 683         MTLBlitLoops.Blit(src, dst,
 684                           comp, clip, at, hint,
 685                           sx, sy, sx+w, sy+h,
 686                           dx, dy, dx+w, dy+h,
 687                           typeval, false);
 688     }
 689 }
 690 
 691 class MTLSwToTextureBlit extends Blit {
 692 
 693     private int typeval;
 694 
 695     MTLSwToTextureBlit(SurfaceType srcType, int typeval) {
 696         super(srcType,
 697               CompositeType.SrcNoEa,
 698               MTLSurfaceDataBase.MTLTexture);
 699         this.typeval = typeval;
 700     }
 701 
 702     public void Blit(SurfaceData src, SurfaceData dst,
 703                      Composite comp, Region clip,
 704                      int sx, int sy, int dx, int dy, int w, int h)
 705     {
 706         MTLBlitLoops.Blit(src, dst,
 707                           comp, clip, null,
 708                           AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 709                           sx, sy, sx+w, sy+h,
 710                           dx, dy, dx+w, dy+h,
 711                           typeval, true);
 712     }
 713 }
 714 
 715 class MTLTextureToSurfaceBlit extends Blit {
 716 
 717     MTLTextureToSurfaceBlit() {
 718         super(MTLSurfaceDataBase.MTLTexture,
 719               CompositeType.AnyAlpha,
 720               MTLSurfaceDataBase.MTLSurface);
 721     }
 722 
 723     public void Blit(SurfaceData src, SurfaceData dst,
 724                      Composite comp, Region clip,
 725                      int sx, int sy, int dx, int dy, int w, int h)
 726     {
 727         MTLBlitLoops.IsoBlit(src, dst,
 728                              null, null,
 729                              comp, clip, null,
 730                              AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 731                              sx, sy, sx+w, sy+h,
 732                              dx, dy, dx+w, dy+h,
 733                              true);
 734     }
 735 }
 736 
 737 class MTLTextureToSurfaceScale extends ScaledBlit {
 738 
 739     MTLTextureToSurfaceScale() {
 740         super(MTLSurfaceDataBase.MTLTexture,
 741               CompositeType.AnyAlpha,
 742               MTLSurfaceDataBase.MTLSurface);
 743     }
 744 
 745     public void Scale(SurfaceData src, SurfaceData dst,
 746                       Composite comp, Region clip,
 747                       int sx1, int sy1,
 748                       int sx2, int sy2,
 749                       double dx1, double dy1,
 750                       double dx2, double dy2)
 751     {
 752         MTLBlitLoops.IsoBlit(src, dst,
 753                              null, null,
 754                              comp, clip, null,
 755                              AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
 756                              sx1, sy1, sx2, sy2,
 757                              dx1, dy1, dx2, dy2,
 758                              true);
 759     }
 760 }
 761 
 762 class MTLTextureToSurfaceTransform extends TransformBlit {
 763 
 764     MTLTextureToSurfaceTransform() {
 765         super(MTLSurfaceDataBase.MTLTexture,
 766               CompositeType.AnyAlpha,
 767               MTLSurfaceDataBase.MTLSurface);
 768     }
 769 
 770     public void Transform(SurfaceData src, SurfaceData dst,
 771                           Composite comp, Region clip,
 772                           AffineTransform at, int hint,
 773                           int sx, int sy, int dx, int dy,
 774                           int w, int h)
 775     {
 776         MTLBlitLoops.IsoBlit(src, dst,
 777                              null, null,
 778                              comp, clip, at, hint,
 779                              sx, sy, sx+w, sy+h,
 780                              dx, dy, dx+w, dy+h,
 781                              true);
 782     }
 783 }
 784 
 785 /**
 786  * This general Blit implementation converts any source surface to an
 787  * intermediate IntArgbPre surface, and then uses the more specific
 788  * IntArgbPre->MTLSurface/Texture loop to get the intermediate
 789  * (premultiplied) surface down to OpenGL using simple blit.
 790  */
 791 class MTLGeneralBlit extends Blit {
 792 
 793     private final Blit performop;
 794     private WeakReference<SurfaceData> srcTmp;
 795 
 796     MTLGeneralBlit(SurfaceType dstType,
 797                    CompositeType compType,
 798                    Blit performop)
 799     {
 800         super(SurfaceType.Any, compType, dstType);
 801         this.performop = performop;
 802     }
 803 
 804     public synchronized void Blit(SurfaceData src, SurfaceData dst,
 805                                   Composite comp, Region clip,
 806                                   int sx, int sy, int dx, int dy,
 807                                   int w, int h)
 808     {
 809         Blit convertsrc = Blit.getFromCache(src.getSurfaceType(),
 810                                             CompositeType.SrcNoEa,
 811                                             SurfaceType.IntArgbPre);
 812 
 813         SurfaceData cachedSrc = null;
 814         if (srcTmp != null) {
 815             // use cached intermediate surface, if available
 816             cachedSrc = srcTmp.get();
 817         }
 818 
 819         // convert source to IntArgbPre
 820         src = convertFrom(convertsrc, src, sx, sy, w, h,
 821                           cachedSrc, BufferedImage.TYPE_INT_ARGB_PRE);
 822 
 823         // copy IntArgbPre intermediate surface to OpenGL surface
 824         performop.Blit(src, dst, comp, clip,
 825                        0, 0, dx, dy, w, h);
 826 
 827         if (src != cachedSrc) {
 828             // cache the intermediate surface
 829             srcTmp = new WeakReference<>(src);
 830         }
 831     }
 832 }
 833 
 834 /**
 835  * This general TransformedBlit implementation converts any source surface to an
 836  * intermediate IntArgbPre surface, and then uses the more specific
 837  * IntArgbPre->MTLSurface/Texture loop to get the intermediate
 838  * (premultiplied) surface down to OpenGL using simple transformBlit.
 839  */
 840 final class MTLGeneralTransformedBlit extends TransformBlit {
 841 
 842     private final TransformBlit performop;
 843     private WeakReference<SurfaceData> srcTmp;
 844 
 845     MTLGeneralTransformedBlit(final TransformBlit performop) {
 846         super(SurfaceType.Any, CompositeType.AnyAlpha,
 847               MTLSurfaceDataBase.MTLSurface);
 848         this.performop = performop;
 849     }
 850 
 851     @Override
 852     public synchronized void Transform(SurfaceData src, SurfaceData dst,
 853                                        Composite comp, Region clip,
 854                                        AffineTransform at, int hint, int srcx,
 855                                        int srcy, int dstx, int dsty, int width,
 856                                        int height){
 857         Blit convertsrc = Blit.getFromCache(src.getSurfaceType(),
 858                                             CompositeType.SrcNoEa,
 859                                             SurfaceType.IntArgbPre);
 860         // use cached intermediate surface, if available
 861         final SurfaceData cachedSrc = srcTmp != null ? srcTmp.get() : null;
 862         // convert source to IntArgbPre
 863         src = convertFrom(convertsrc, src, srcx, srcy, width, height, cachedSrc,
 864                           BufferedImage.TYPE_INT_ARGB_PRE);
 865 
 866         // transform IntArgbPre intermediate surface to OpenGL surface
 867         performop.Transform(src, dst, comp, clip, at, hint, 0, 0, dstx, dsty,
 868                             width, height);
 869 
 870         if (src != cachedSrc) {
 871             // cache the intermediate surface
 872             srcTmp = new WeakReference<>(src);
 873         }
 874     }
 875 }
 876 
 877 /**
 878  * This general MTLAnyCompositeBlit implementation can convert any source/target
 879  * surface to an intermediate surface using convertsrc/convertdst loops, applies
 880  * necessary composite operation, and then uses convertresult loop to get the
 881  * intermediate surface down to OpenGL.
 882  */
 883 final class MTLAnyCompositeBlit extends Blit {
 884 
 885     private WeakReference<SurfaceData> dstTmp;
 886     private WeakReference<SurfaceData> srcTmp;
 887     private final Blit convertsrc;
 888     private final Blit convertdst;
 889     private final Blit convertresult;
 890 
 891     MTLAnyCompositeBlit(SurfaceType srctype, Blit convertsrc, Blit convertdst,
 892                         Blit convertresult) {
 893         super(srctype, CompositeType.Any, MTLSurfaceDataBase.MTLSurface);
 894         this.convertsrc = convertsrc;
 895         this.convertdst = convertdst;
 896         this.convertresult = convertresult;
 897     }
 898 
 899     public synchronized void Blit(SurfaceData src, SurfaceData dst,
 900                                   Composite comp, Region clip,
 901                                   int sx, int sy, int dx, int dy,
 902                                   int w, int h)
 903     {
 904         if (convertsrc != null) {
 905             SurfaceData cachedSrc = null;
 906             if (srcTmp != null) {
 907                 // use cached intermediate surface, if available
 908                 cachedSrc = srcTmp.get();
 909             }
 910             // convert source to IntArgbPre
 911             src = convertFrom(convertsrc, src, sx, sy, w, h, cachedSrc,
 912                               BufferedImage.TYPE_INT_ARGB_PRE);
 913             if (src != cachedSrc) {
 914                 // cache the intermediate surface
 915                 srcTmp = new WeakReference<>(src);
 916             }
 917         }
 918 
 919         SurfaceData cachedDst = null;
 920 
 921         if (dstTmp != null) {
 922             // use cached intermediate surface, if available
 923             cachedDst = dstTmp.get();
 924         }
 925 
 926         // convert destination to IntArgbPre
 927         SurfaceData dstBuffer = convertFrom(convertdst, dst, dx, dy, w, h,
 928                           cachedDst, BufferedImage.TYPE_INT_ARGB_PRE);
 929         Region bufferClip =
 930                 clip == null ? null : clip.getTranslatedRegion(-dx, -dy);
 931 
 932         Blit performop = Blit.getFromCache(src.getSurfaceType(),
 933                 CompositeType.Any, dstBuffer.getSurfaceType());
 934         performop.Blit(src, dstBuffer, comp, bufferClip, sx, sy, 0, 0, w, h);
 935 
 936         if (dstBuffer != cachedDst) {
 937             // cache the intermediate surface
 938             dstTmp = new WeakReference<>(dstBuffer);
 939         }
 940         // now blit the buffer back to the destination
 941         convertresult.Blit(dstBuffer, dst, AlphaComposite.Src, clip, 0, 0, dx,
 942                            dy, w, h);
 943     }
 944 }