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