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