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 #ifndef HEADLESS
  27 
  28 #include <stdlib.h>
  29 
  30 #include "sun_java2d_pipe_BufferedOpCodes.h"
  31 
  32 #include "jlong.h"
  33 #include "MTLBlitLoops.h"
  34 #include "MTLBufImgOps.h"
  35 #include "MTLMaskBlit.h"
  36 #include "MTLMaskFill.h"
  37 #include "MTLPaints.h"
  38 #include "MTLRenderQueue.h"
  39 #include "MTLRenderer.h"
  40 #include "MTLTextRenderer.h"
  41 
  42 /**
  43  * Used to track whether we are in a series of a simple primitive operations
  44  * or texturing operations.  This variable should be controlled only via
  45  * the INIT/CHECK/RESET_PREVIOUS_OP() macros.  See the
  46  * MTLRenderQueue_CheckPreviousOp() method below for more information.
  47  */
  48 jint previousOp;
  49 
  50 /**
  51  * References to the "current" context and destination surface.
  52  */
  53 static MTLContext *mtlc = NULL;
  54 static BMTLSDOps *dstOps = NULL;
  55 
  56 /**
  57  * The following methods are implemented in the windowing system (i.e. GLX
  58  * and WGL) source files.
  59  */
  60 extern void MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo);
  61 extern void MTLSD_SwapBuffers(JNIEnv *env, jlong window);
  62 
  63 /**
  64  * Helper methods to manage modified layers
  65  */
  66 static MTLLayer ** g_modifiedLayers = NULL;
  67 static int g_modifiedLayersCount = 0;
  68 static int g_modifiedLayersAllocatedCount = 0;
  69 
  70 static void markLayerModified(MTLLayer * modifiedLayer) {
  71     if (modifiedLayer == NULL)
  72         return;
  73     if (g_modifiedLayers == NULL) {
  74         g_modifiedLayersAllocatedCount = 3;
  75         g_modifiedLayers = malloc(g_modifiedLayersAllocatedCount * sizeof(MTLLayer *));
  76     }
  77     for (int c = 0; c < g_modifiedLayersCount; ++c) {
  78         if (g_modifiedLayers[c] == modifiedLayer)
  79             return;
  80     }
  81     ++g_modifiedLayersCount;
  82     if (g_modifiedLayersCount > g_modifiedLayersAllocatedCount) {
  83         g_modifiedLayersAllocatedCount = g_modifiedLayersCount;
  84         g_modifiedLayers = realloc(g_modifiedLayers, g_modifiedLayersAllocatedCount * sizeof(MTLLayer *));
  85     }
  86     g_modifiedLayers[g_modifiedLayersCount - 1] = modifiedLayer;
  87 }
  88 
  89 static void scheduleBlitAllModifiedLayers() {
  90     for (int c = 0; c < g_modifiedLayersCount; ++c) {
  91         MTLLayer * layer = g_modifiedLayers[c];
  92         MTLContext * ctx = layer.ctx;
  93         if (layer == NULL || ctx == NULL)
  94             continue;
  95         id<MTLCommandBuffer> bufferToCommit = ctx.commandBuffer;
  96         [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
  97             [layer blitTexture:bufferToCommit];
  98         }];
  99 
 100         [ctx releaseCommandBuffer];
 101     }
 102     g_modifiedLayersCount = 0;
 103 }
 104 
 105 static void onSurfaceModified(BMTLSDOps *bmtldst) {
 106     if (bmtldst != NULL && bmtldst->privOps != NULL && ((MTLSDOps *)bmtldst->privOps)->layer != NULL)
 107         markLayerModified(((MTLSDOps *) bmtldst->privOps)->layer);
 108 }
 109 
 110 static const jint g_drawOpcodes[] = {
 111         sun_java2d_pipe_BufferedOpCodes_DRAW_LINE,
 112         sun_java2d_pipe_BufferedOpCodes_DRAW_RECT,
 113         sun_java2d_pipe_BufferedOpCodes_DRAW_POLY,
 114         sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL,
 115         sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES,
 116         sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM,
 117         sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM,
 118 
 119         sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST,
 120 
 121         sun_java2d_pipe_BufferedOpCodes_FILL_RECT,
 122         sun_java2d_pipe_BufferedOpCodes_FILL_SPANS,
 123         sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM,
 124         sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM,
 125 
 126         sun_java2d_pipe_BufferedOpCodes_COPY_AREA,
 127         sun_java2d_pipe_BufferedOpCodes_MASK_FILL,
 128         sun_java2d_pipe_BufferedOpCodes_MASK_BLIT,
 129         sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS
 130 };
 131 
 132 static jboolean isDrawOpcode(jint opcode) {
 133     for (int c = 0; c < sizeof(g_drawOpcodes)/sizeof(g_drawOpcodes[0]); ++c) {
 134         if (opcode == g_drawOpcodes[c])
 135             return JNI_TRUE;
 136     }
 137     return JNI_FALSE;
 138 }
 139 
 140 JNIEXPORT void JNICALL
 141 Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
 142     (JNIEnv *env, jobject mtlrq,
 143      jlong buf, jint limit)
 144 {
 145     jboolean sync = JNI_FALSE;
 146     unsigned char *b, *end;
 147 
 148     J2dTraceLn1(J2D_TRACE_INFO,
 149                 "MTLRenderQueue_flushBuffer: limit=%d", limit);
 150 
 151     b = (unsigned char *)jlong_to_ptr(buf);
 152     if (b == NULL) {
 153         J2dRlsTraceLn(J2D_TRACE_ERROR,
 154             "MTLRenderQueue_flushBuffer: cannot get direct buffer address");
 155         return;
 156     }
 157 
 158     INIT_PREVIOUS_OP();
 159     end = b + limit;
 160 
 161     while (b < end) {
 162         jint opcode = NEXT_INT(b);
 163 
 164         J2dTraceLn2(J2D_TRACE_VERBOSE,
 165                     "MTLRenderQueue_flushBuffer: opcode=%d, rem=%d",
 166                     opcode, (end-b));
 167 
 168         if (opcode != sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST &&
 169             opcode != sun_java2d_pipe_BufferedOpCodes_NOOP)
 170         {
 171             //MTLTR_DisableGlyphModeState();
 172         }
 173 
 174         switch (opcode) {
 175 
 176         // draw ops
 177         case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE:
 178             {
 179                 J2dTraceLn(J2D_TRACE_VERBOSE, "sun_java2d_pipe_BufferedOpCodes_DRAW_LINE");
 180                 jint x1 = NEXT_INT(b);
 181                 jint y1 = NEXT_INT(b);
 182                 jint x2 = NEXT_INT(b);
 183                 jint y2 = NEXT_INT(b);
 184                 MTLRenderer_DrawLine(mtlc, dstOps, x1, y1, x2, y2);
 185             }
 186             break;
 187         case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT:
 188             {
 189                 jint x = NEXT_INT(b);
 190                 jint y = NEXT_INT(b);
 191                 jint w = NEXT_INT(b);
 192                 jint h = NEXT_INT(b);
 193                 MTLRenderer_DrawRect(mtlc, dstOps, x, y, w, h);
 194             }
 195             break;
 196         case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY:
 197             {
 198                 jint nPoints      = NEXT_INT(b);
 199                 jboolean isClosed = NEXT_BOOLEAN(b);
 200                 jint transX       = NEXT_INT(b);
 201                 jint transY       = NEXT_INT(b);
 202                 jint *xPoints = (jint *)b;
 203                 jint *yPoints = ((jint *)b) + nPoints;
 204                 MTLRenderer_DrawPoly(mtlc, dstOps, nPoints, isClosed, transX, transY, xPoints, yPoints);
 205                 SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT);
 206             }
 207             break;
 208         case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL:
 209             {
 210                 jint x = NEXT_INT(b);
 211                 jint y = NEXT_INT(b);
 212                 CONTINUE_IF_NULL(mtlc);
 213                 //TODO
 214                 J2dTraceNotImplPrimitive("MTLRenderQueue_DRAW_PIXEL");
 215             }
 216             break;
 217         case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES:
 218             {
 219                 jint count = NEXT_INT(b);
 220                 MTLRenderer_DrawScanlines(mtlc, dstOps, count, (jint *)b);
 221 
 222                 SKIP_BYTES(b, count * BYTES_PER_SCANLINE);
 223             }
 224             break;
 225         case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM:
 226             {
 227                 jfloat x11 = NEXT_FLOAT(b);
 228                 jfloat y11 = NEXT_FLOAT(b);
 229                 jfloat dx21 = NEXT_FLOAT(b);
 230                 jfloat dy21 = NEXT_FLOAT(b);
 231                 jfloat dx12 = NEXT_FLOAT(b);
 232                 jfloat dy12 = NEXT_FLOAT(b);
 233                 jfloat lwr21 = NEXT_FLOAT(b);
 234                 jfloat lwr12 = NEXT_FLOAT(b);
 235 
 236                 MTLRenderer_DrawParallelogram(mtlc, dstOps,
 237                                               x11, y11,
 238                                               dx21, dy21,
 239                                               dx12, dy12,
 240                                               lwr21, lwr12);
 241             }
 242             break;
 243         case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
 244             {
 245                 jfloat x11 = NEXT_FLOAT(b);
 246                 jfloat y11 = NEXT_FLOAT(b);
 247                 jfloat dx21 = NEXT_FLOAT(b);
 248                 jfloat dy21 = NEXT_FLOAT(b);
 249                 jfloat dx12 = NEXT_FLOAT(b);
 250                 jfloat dy12 = NEXT_FLOAT(b);
 251                 jfloat lwr21 = NEXT_FLOAT(b);
 252                 jfloat lwr12 = NEXT_FLOAT(b);
 253 
 254                 MTLRenderer_DrawAAParallelogram(mtlc, dstOps,
 255                                                 x11, y11,
 256                                                 dx21, dy21,
 257                                                 dx12, dy12,
 258                                                 lwr21, lwr12);
 259             }
 260             break;
 261 
 262         // fill ops
 263         case sun_java2d_pipe_BufferedOpCodes_FILL_RECT:
 264             {
 265                 jint x = NEXT_INT(b);
 266                 jint y = NEXT_INT(b);
 267                 jint w = NEXT_INT(b);
 268                 jint h = NEXT_INT(b);
 269                 MTLRenderer_FillRect(mtlc, dstOps, x, y, w, h);
 270             }
 271             break;
 272         case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
 273             {
 274                 jint count = NEXT_INT(b);
 275                 MTLRenderer_FillSpans(mtlc, dstOps, count, (jint *)b);
 276                 SKIP_BYTES(b, count * BYTES_PER_SPAN);
 277             }
 278             break;
 279         case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM:
 280             {
 281                 jfloat x11 = NEXT_FLOAT(b);
 282                 jfloat y11 = NEXT_FLOAT(b);
 283                 jfloat dx21 = NEXT_FLOAT(b);
 284                 jfloat dy21 = NEXT_FLOAT(b);
 285                 jfloat dx12 = NEXT_FLOAT(b);
 286                 jfloat dy12 = NEXT_FLOAT(b);
 287                 MTLRenderer_FillParallelogram(mtlc, dstOps,
 288                                               x11, y11,
 289                                               dx21, dy21,
 290                                               dx12, dy12);
 291             }
 292             break;
 293         case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
 294             {
 295                 jfloat x11 = NEXT_FLOAT(b);
 296                 jfloat y11 = NEXT_FLOAT(b);
 297                 jfloat dx21 = NEXT_FLOAT(b);
 298                 jfloat dy21 = NEXT_FLOAT(b);
 299                 jfloat dx12 = NEXT_FLOAT(b);
 300                 jfloat dy12 = NEXT_FLOAT(b);
 301                 MTLRenderer_FillAAParallelogram(mtlc, dstOps,
 302                                                 x11, y11,
 303                                                 dx21, dy21,
 304                                                 dx12, dy12);
 305             }
 306             break;
 307 
 308         // text-related ops
 309         case sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST:
 310             {
 311                 jint numGlyphs        = NEXT_INT(b);
 312                 jint packedParams     = NEXT_INT(b);
 313                 jfloat glyphListOrigX = NEXT_FLOAT(b);
 314                 jfloat glyphListOrigY = NEXT_FLOAT(b);
 315                 jboolean usePositions = EXTRACT_BOOLEAN(packedParams,
 316                                                         OFFSET_POSITIONS);
 317                 jboolean subPixPos    = EXTRACT_BOOLEAN(packedParams,
 318                                                         OFFSET_SUBPIXPOS);
 319                 jboolean rgbOrder     = EXTRACT_BOOLEAN(packedParams,
 320                                                         OFFSET_RGBORDER);
 321                 jint lcdContrast      = EXTRACT_BYTE(packedParams,
 322                                                      OFFSET_CONTRAST);
 323                 unsigned char *images = b;
 324                 unsigned char *positions;
 325                 jint bytesPerGlyph;
 326                 if (usePositions) {
 327                     positions = (b + numGlyphs * BYTES_PER_GLYPH_IMAGE);
 328                     bytesPerGlyph = BYTES_PER_POSITIONED_GLYPH;
 329                 } else {
 330                     positions = NULL;
 331                     bytesPerGlyph = BYTES_PER_GLYPH_IMAGE;
 332                 }
 333                 MTLTR_DrawGlyphList(env, mtlc, dstOps,
 334                                     numGlyphs, usePositions,
 335                                     subPixPos, rgbOrder, lcdContrast,
 336                                     glyphListOrigX, glyphListOrigY,
 337                                     images, positions);
 338                 SKIP_BYTES(b, numGlyphs * bytesPerGlyph);
 339             }
 340             break;
 341 
 342         // copy-related ops
 343         case sun_java2d_pipe_BufferedOpCodes_COPY_AREA:
 344             {
 345                 jint x  = NEXT_INT(b);
 346                 jint y  = NEXT_INT(b);
 347                 jint w  = NEXT_INT(b);
 348                 jint h  = NEXT_INT(b);
 349                 jint dx = NEXT_INT(b);
 350                 jint dy = NEXT_INT(b);
 351                 MTLBlitLoops_CopyArea(env, mtlc, dstOps,
 352                                       x, y, w, h, dx, dy);
 353             }
 354             break;
 355         case sun_java2d_pipe_BufferedOpCodes_BLIT:
 356             {
 357                 J2dTracePrimitive("MTLRenderQueue_BLIT");
 358 
 359                 jint packedParams = NEXT_INT(b);
 360                 jint sx1          = NEXT_INT(b);
 361                 jint sy1          = NEXT_INT(b);
 362                 jint sx2          = NEXT_INT(b);
 363                 jint sy2          = NEXT_INT(b);
 364                 jdouble dx1       = NEXT_DOUBLE(b);
 365                 jdouble dy1       = NEXT_DOUBLE(b);
 366                 jdouble dx2       = NEXT_DOUBLE(b);
 367                 jdouble dy2       = NEXT_DOUBLE(b);
 368                 jlong pSrc        = NEXT_LONG(b);
 369                 jlong pDst        = NEXT_LONG(b);
 370                 jint hint         = EXTRACT_BYTE(packedParams, OFFSET_HINT);
 371                 jboolean texture  = EXTRACT_BOOLEAN(packedParams,
 372                                                     OFFSET_TEXTURE);
 373                 jboolean rtt      = EXTRACT_BOOLEAN(packedParams,
 374                                                     OFFSET_RTT);
 375                 jboolean xform    = EXTRACT_BOOLEAN(packedParams,
 376                                                     OFFSET_XFORM);
 377                 jboolean isoblit  = EXTRACT_BOOLEAN(packedParams,
 378                                                     OFFSET_ISOBLIT);
 379                 if (isoblit) {
 380                     MTLBlitLoops_IsoBlit(env, mtlc, pSrc, pDst,
 381                                          xform, hint, texture, rtt,
 382                                          sx1, sy1, sx2, sy2,
 383                                          dx1, dy1, dx2, dy2);
 384                 } else {
 385                     jint srctype = EXTRACT_BYTE(packedParams, OFFSET_SRCTYPE);
 386                     MTLBlitLoops_Blit(env, mtlc, pSrc, pDst,
 387                                       xform, hint, srctype, texture,
 388                                       sx1, sy1, sx2, sy2,
 389                                       dx1, dy1, dx2, dy2);
 390                 }
 391                 onSurfaceModified(jlong_to_ptr(pDst));
 392             }
 393             break;
 394         case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT:
 395             {
 396                 J2dTracePrimitive("MTLRenderQueue_SURFACE_TO_SW_BLIT");
 397 
 398                 jint sx      = NEXT_INT(b);
 399                 jint sy      = NEXT_INT(b);
 400                 jint dx      = NEXT_INT(b);
 401                 jint dy      = NEXT_INT(b);
 402                 jint w       = NEXT_INT(b);
 403                 jint h       = NEXT_INT(b);
 404                 jint dsttype = NEXT_INT(b);
 405                 jlong pSrc   = NEXT_LONG(b);
 406                 jlong pDst   = NEXT_LONG(b);
 407                 MTLBlitLoops_SurfaceToSwBlit(env, mtlc,
 408                                              pSrc, pDst, dsttype,
 409                                              sx, sy, dx, dy, w, h);
 410             }
 411             break;
 412         case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
 413             {
 414                 J2dTracePrimitive("MTLRenderQueue_MASK_FILL");
 415 
 416                 jint x        = NEXT_INT(b);
 417                 jint y        = NEXT_INT(b);
 418                 jint w        = NEXT_INT(b);
 419                 jint h        = NEXT_INT(b);
 420                 jint maskoff  = NEXT_INT(b);
 421                 jint maskscan = NEXT_INT(b);
 422                 jint masklen  = NEXT_INT(b);
 423                 unsigned char *pMask = (masklen > 0) ? b : NULL;
 424                 MTLMaskFill_MaskFill(mtlc, dstOps, x, y, w, h,
 425                                      maskoff, maskscan, masklen, pMask);
 426                 SKIP_BYTES(b, masklen);
 427             }
 428             break;
 429         case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT:
 430             {
 431                 J2dTracePrimitive("MTLRenderQueue_MASK_BLIT");
 432 
 433                 jint dstx     = NEXT_INT(b);
 434                 jint dsty     = NEXT_INT(b);
 435                 jint width    = NEXT_INT(b);
 436                 jint height   = NEXT_INT(b);
 437                 jint masklen  = width * height * sizeof(jint);
 438                 MTLMaskBlit_MaskBlit(env, mtlc, dstOps,
 439                                      dstx, dsty, width, height, b);
 440                 SKIP_BYTES(b, masklen);
 441             }
 442             break;
 443 
 444         // state-related ops
 445         case sun_java2d_pipe_BufferedOpCodes_SET_RECT_CLIP:
 446             {
 447                 jint x1 = NEXT_INT(b);
 448                 jint y1 = NEXT_INT(b);
 449                 jint x2 = NEXT_INT(b);
 450                 jint y2 = NEXT_INT(b);
 451                 [mtlc setClipRectX1:x1 Y1:y1 X2:x2 Y2:y2];
 452             }
 453             break;
 454         case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP:
 455             {
 456                 [mtlc beginShapeClip];
 457             }
 458             break;
 459         case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS:
 460             {
 461                 jint count = NEXT_INT(b);
 462                 MTLRenderer_FillSpans(mtlc, dstOps, count, (jint *)b);
 463                 SKIP_BYTES(b, count * BYTES_PER_SPAN);
 464             }
 465             break;
 466         case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP:
 467             {
 468                 //TODO
 469                 [mtlc endShapeClipDstOps:dstOps];
 470             }
 471             break;
 472         case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP:
 473             {
 474                 [mtlc resetClip];
 475             }
 476             break;
 477         case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE:
 478             {
 479                 jint rule         = NEXT_INT(b);
 480                 jfloat extraAlpha = NEXT_FLOAT(b);
 481                 jint flags        = NEXT_INT(b);
 482                 [mtlc setAlphaCompositeRule:rule extraAlpha:extraAlpha flags:flags];
 483             }
 484             break;
 485         case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
 486             {
 487                 jint xorPixel = NEXT_INT(b);
 488                 [mtlc setXorComposite:xorPixel];
 489             }
 490             break;
 491         case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
 492             {
 493                 [mtlc resetComposite];
 494             }
 495             break;
 496         case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM:
 497             {
 498                 jdouble m00 = NEXT_DOUBLE(b);
 499                 jdouble m10 = NEXT_DOUBLE(b);
 500                 jdouble m01 = NEXT_DOUBLE(b);
 501                 jdouble m11 = NEXT_DOUBLE(b);
 502                 jdouble m02 = NEXT_DOUBLE(b);
 503                 jdouble m12 = NEXT_DOUBLE(b);
 504                 [mtlc setTransformM00:m00 M10:m10 M01:m01 M11:m11 M02:m02 M12:m12];
 505             }
 506             break;
 507         case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM:
 508             {
 509                 [mtlc resetTransform];
 510             }
 511             break;
 512 
 513         // context-related ops
 514         case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES:
 515             {
 516                 J2dTracePrimitive("MTLRenderQueue_SET_SURFACES");
 517 
 518                 jlong pSrc = NEXT_LONG(b);
 519                 jlong pDst = NEXT_LONG(b);
 520                 if (mtlc != NULL) {
 521                     RESET_PREVIOUS_OP();
 522                 }
 523 
 524                 dstOps = (BMTLSDOps *)jlong_to_ptr(pDst);
 525                 [MTLContext setSurfacesEnv:env src:pSrc dst:pDst];
 526             }
 527             break;
 528         case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
 529             {
 530                 J2dTracePrimitive("MTLRenderQueue_SET_SCRATCH_SURFACE");
 531                 jlong pConfigInfo = NEXT_LONG(b);
 532                 MTLGraphicsConfigInfo *mtlInfo =
 533                         (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
 534 
 535                 if (mtlInfo == NULL) {
 536                     J2dTraceImplPrimitive(
 537                             "MTLRenderQueue_SET_SCRATCH_SURFACE",
 538                             "ERROR: mtl config info is null");
 539                 } else {
 540                     MTLContext *newMtlc = mtlInfo->context;
 541                     if (newMtlc == NULL) {
 542                         J2dTraceImplPrimitive(
 543                                 "MTLRenderQueue_SET_SCRATCH_SURFACE",
 544                                 "ERROR: mtl context is null");
 545                     } else {
 546                         mtlc = newMtlc;
 547                         dstOps = NULL;
 548                     }
 549                 }
 550             }
 551             break;
 552         case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
 553             {
 554                 J2dTracePrimitive("MTLRenderQueue_FLUSH_SURFACE");
 555                 jlong pData = NEXT_LONG(b);
 556                 BMTLSDOps *mtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
 557                 if (mtlsdo != NULL) {
 558                     CONTINUE_IF_NULL(mtlc);
 559                     RESET_PREVIOUS_OP();
 560                     MTLSD_Delete(env, mtlsdo);
 561                 }
 562             }
 563             break;
 564         case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE:
 565             {
 566                 J2dTracePrimitive("MTLRenderQueue_DISPOSE_SURFACE");
 567                 jlong pData = NEXT_LONG(b);
 568                 BMTLSDOps *mtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
 569                 if (mtlsdo != NULL) {
 570                     CONTINUE_IF_NULL(mtlc);
 571                     RESET_PREVIOUS_OP();
 572                     MTLSD_Delete(env, mtlsdo);
 573                     if (mtlsdo->privOps != NULL) {
 574                         free(mtlsdo->privOps);
 575                     }
 576                 }
 577             }
 578             break;
 579         case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG:
 580             {
 581                 J2dTracePrimitive("MTLRenderQueue_DISPOSE_CONFIG");
 582                 jlong pConfigInfo = NEXT_LONG(b);
 583                 CONTINUE_IF_NULL(mtlc);
 584                 RESET_PREVIOUS_OP();
 585                 [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 586                     MTLGC_DestroyMTLGraphicsConfig(pConfigInfo);
 587                 }];
 588 
 589 
 590                 // the previous method will call glX/wglMakeCurrent(None),
 591                 // so we should nullify the current mtlc and dstOps to avoid
 592                 // calling glFlush() (or similar) while no context is current
 593                 mtlc = NULL;
 594              //   dstOps = NULL;
 595             }
 596             break;
 597         case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
 598             {
 599                 //TODO
 600                 J2dTraceNotImplPrimitive("MTLRenderQueue_INVALIDATE_CONTEXT");
 601                 // flush just in case there are any pending operations in
 602                 // the hardware pipe
 603                 if (mtlc != NULL) {
 604                     RESET_PREVIOUS_OP();
 605                 }
 606                 // invalidate the references to the current context and
 607                 // destination surface that are maintained at the native level
 608                 mtlc = NULL;
 609             //    dstOps = NULL;
 610             }
 611             break;
 612         case sun_java2d_pipe_BufferedOpCodes_SAVE_STATE:
 613             {
 614                 //TODO
 615                 J2dTraceNotImplPrimitive("MTLRenderQueue_INVALIDATE_CONTEXT");
 616             }
 617             break;
 618 
 619         case sun_java2d_pipe_BufferedOpCodes_RESTORE_STATE:
 620             {
 621                 //TODO
 622                 J2dTraceNotImplPrimitive("MTLRenderQueue_RESTORE_STATE");
 623 
 624             }
 625             break;
 626         case sun_java2d_pipe_BufferedOpCodes_SYNC:
 627             {
 628                 sync = JNI_TRUE;
 629             }
 630             break;
 631 
 632         // multibuffering ops
 633         case sun_java2d_pipe_BufferedOpCodes_SWAP_BUFFERS:
 634             {
 635                 jlong window = NEXT_LONG(b);
 636                 if (mtlc != NULL) {
 637                     RESET_PREVIOUS_OP();
 638                 }
 639                 MTLSD_SwapBuffers(env, window);
 640             }
 641             break;
 642 
 643         // special no-op (mainly used for achieving 8-byte alignment)
 644         case sun_java2d_pipe_BufferedOpCodes_NOOP:
 645             break;
 646 
 647         // paint-related ops
 648         case sun_java2d_pipe_BufferedOpCodes_RESET_PAINT:
 649             {
 650                 MTLPaints_ResetPaint(mtlc);
 651             }
 652             break;
 653         case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
 654             {
 655                 jint pixel = NEXT_INT(b);
 656 
 657                 if (dstOps != NULL) {
 658                     MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
 659                     dstCGLOps->configInfo->context.color = pixel;
 660                 }
 661                 MTLPaints_SetColor(mtlc, pixel);
 662             }
 663             break;
 664         case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
 665             {
 666                 J2dTraceNotImplPrimitive("MTLRenderQueue_SET_GRADIENT_PAINT");
 667                 jboolean useMask= NEXT_BOOLEAN(b);
 668                 jboolean cyclic = NEXT_BOOLEAN(b);
 669                 jdouble p0      = NEXT_DOUBLE(b);
 670                 jdouble p1      = NEXT_DOUBLE(b);
 671                 jdouble p3      = NEXT_DOUBLE(b);
 672                 jint pixel1     = NEXT_INT(b);
 673                 jint pixel2     = NEXT_INT(b);
 674                 if (dstOps != NULL) {
 675                     MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
 676                     [dstCGLOps->configInfo->context setGradientPaintUseMask:useMask cyclic:cyclic
 677                                                                          p0:p0 p1:p1 p3:p3
 678                                                                      pixel1:pixel1 pixel2:pixel2];
 679 
 680                 }
 681             }
 682             break;
 683         case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT:
 684             {
 685                 jboolean useMask = NEXT_BOOLEAN(b);
 686                 jboolean linear  = NEXT_BOOLEAN(b);
 687                 jint cycleMethod = NEXT_INT(b);
 688                 jint numStops    = NEXT_INT(b);
 689                 jfloat p0        = NEXT_FLOAT(b);
 690                 jfloat p1        = NEXT_FLOAT(b);
 691                 jfloat p3        = NEXT_FLOAT(b);
 692                 void *fractions, *pixels;
 693                 fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat));
 694                 pixels    = b; SKIP_BYTES(b, numStops * sizeof(jint));
 695                 MTLPaints_SetLinearGradientPaint(mtlc, dstOps,
 696                                                  useMask, linear,
 697                                                  cycleMethod, numStops,
 698                                                  p0, p1, p3,
 699                                                  fractions, pixels);
 700             }
 701             break;
 702         case sun_java2d_pipe_BufferedOpCodes_SET_RADIAL_GRADIENT_PAINT:
 703             {
 704                 jboolean useMask = NEXT_BOOLEAN(b);
 705                 jboolean linear  = NEXT_BOOLEAN(b);
 706                 jint numStops    = NEXT_INT(b);
 707                 jint cycleMethod = NEXT_INT(b);
 708                 jfloat m00       = NEXT_FLOAT(b);
 709                 jfloat m01       = NEXT_FLOAT(b);
 710                 jfloat m02       = NEXT_FLOAT(b);
 711                 jfloat m10       = NEXT_FLOAT(b);
 712                 jfloat m11       = NEXT_FLOAT(b);
 713                 jfloat m12       = NEXT_FLOAT(b);
 714                 jfloat focusX    = NEXT_FLOAT(b);
 715                 void *fractions, *pixels;
 716                 fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat));
 717                 pixels    = b; SKIP_BYTES(b, numStops * sizeof(jint));
 718                 MTLPaints_SetRadialGradientPaint(mtlc, dstOps,
 719                                                  useMask, linear,
 720                                                  cycleMethod, numStops,
 721                                                  m00, m01, m02,
 722                                                  m10, m11, m12,
 723                                                  focusX,
 724                                                  fractions, pixels);
 725             }
 726             break;
 727         case sun_java2d_pipe_BufferedOpCodes_SET_TEXTURE_PAINT:
 728             {
 729                 jboolean useMask= NEXT_BOOLEAN(b);
 730                 jboolean filter = NEXT_BOOLEAN(b);
 731                 jlong pSrc      = NEXT_LONG(b);
 732                 jdouble xp0     = NEXT_DOUBLE(b);
 733                 jdouble xp1     = NEXT_DOUBLE(b);
 734                 jdouble xp3     = NEXT_DOUBLE(b);
 735                 jdouble yp0     = NEXT_DOUBLE(b);
 736                 jdouble yp1     = NEXT_DOUBLE(b);
 737                 jdouble yp3     = NEXT_DOUBLE(b);
 738                 MTLPaints_SetTexturePaint(mtlc, useMask, pSrc, filter,
 739                                           xp0, xp1, xp3,
 740                                           yp0, yp1, yp3);
 741             }
 742             break;
 743 
 744         // BufferedImageOp-related ops
 745         case sun_java2d_pipe_BufferedOpCodes_ENABLE_CONVOLVE_OP:
 746             {
 747                 jlong pSrc        = NEXT_LONG(b);
 748                 jboolean edgeZero = NEXT_BOOLEAN(b);
 749                 jint kernelWidth  = NEXT_INT(b);
 750                 jint kernelHeight = NEXT_INT(b);
 751                 MTLBufImgOps_EnableConvolveOp(mtlc, pSrc, edgeZero,
 752                                               kernelWidth, kernelHeight, b);
 753                 SKIP_BYTES(b, kernelWidth * kernelHeight * sizeof(jfloat));
 754             }
 755             break;
 756         case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP:
 757             {
 758                 MTLBufImgOps_DisableConvolveOp(mtlc);
 759             }
 760             break;
 761         case sun_java2d_pipe_BufferedOpCodes_ENABLE_RESCALE_OP:
 762             {
 763                 jlong pSrc          = NEXT_LONG(b);
 764                 jboolean nonPremult = NEXT_BOOLEAN(b);
 765                 jint numFactors     = 4;
 766                 unsigned char *scaleFactors = b;
 767                 unsigned char *offsets = (b + numFactors * sizeof(jfloat));
 768                 MTLBufImgOps_EnableRescaleOp(mtlc, pSrc, nonPremult,
 769                                              scaleFactors, offsets);
 770                 SKIP_BYTES(b, numFactors * sizeof(jfloat) * 2);
 771             }
 772             break;
 773         case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP:
 774             {
 775                 MTLBufImgOps_DisableRescaleOp(mtlc);
 776             }
 777             break;
 778         case sun_java2d_pipe_BufferedOpCodes_ENABLE_LOOKUP_OP:
 779             {
 780                 jlong pSrc          = NEXT_LONG(b);
 781                 jboolean nonPremult = NEXT_BOOLEAN(b);
 782                 jboolean shortData  = NEXT_BOOLEAN(b);
 783                 jint numBands       = NEXT_INT(b);
 784                 jint bandLength     = NEXT_INT(b);
 785                 jint offset         = NEXT_INT(b);
 786                 jint bytesPerElem = shortData ? sizeof(jshort):sizeof(jbyte);
 787                 void *tableValues = b;
 788                 MTLBufImgOps_EnableLookupOp(mtlc, pSrc, nonPremult, shortData,
 789                                             numBands, bandLength, offset,
 790                                             tableValues);
 791                 SKIP_BYTES(b, numBands * bandLength * bytesPerElem);
 792             }
 793             break;
 794         case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP:
 795             {
 796                 MTLBufImgOps_DisableLookupOp(mtlc);
 797             }
 798             break;
 799 
 800         default:
 801             J2dRlsTraceLn1(J2D_TRACE_ERROR,
 802                 "MTLRenderQueue_flushBuffer: invalid opcode=%d", opcode);
 803             if (mtlc != NULL) {
 804                 RESET_PREVIOUS_OP();
 805             }
 806             return;
 807         }
 808 
 809         if (isDrawOpcode(opcode)) // performed rendering operation on dstOps
 810             onSurfaceModified(dstOps);
 811     }
 812 
 813     MTLTR_DisableGlyphModeState();
 814     scheduleBlitAllModifiedLayers();
 815 }
 816 
 817 /**
 818  * Returns a pointer to the "current" context, as set by the last SET_SURFACES
 819  * or SET_SCRATCH_SURFACE operation.
 820  */
 821 MTLContext *
 822 MTLRenderQueue_GetCurrentContext()
 823 {
 824     return mtlc;
 825 }
 826 
 827 /**
 828  * Returns a pointer to the "current" destination surface, as set by the last
 829  * SET_SURFACES operation.
 830  */
 831 BMTLSDOps *
 832 MTLRenderQueue_GetCurrentDestination()
 833 {
 834     return dstOps;
 835 }
 836 
 837 /**
 838  * Used to track whether we are within a series of simple primitive operations
 839  * or texturing operations.  The op parameter determines the nature of the
 840  * operation that is to follow.  Valid values for this op parameter are:
 841  */
 842 void
 843 MTLRenderQueue_CheckPreviousOp(jint op)
 844 {
 845     //TODO
 846     J2dTraceNotImplPrimitive("MTLRenderQueue_CheckPreviousOp");
 847     previousOp = op;
 848 }
 849 
 850 #endif /* !HEADLESS */