/* * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #ifndef HEADLESS #include #include "sun_java2d_pipe_BufferedOpCodes.h" #include "jlong.h" #include "MTLBlitLoops.h" #include "MTLBufImgOps.h" #include "MTLMaskBlit.h" #include "MTLMaskFill.h" #include "MTLPaints.h" #include "MTLRenderQueue.h" #include "MTLRenderer.h" #include "MTLTextRenderer.h" /** * Used to track whether we are in a series of a simple primitive operations * or texturing operations. This variable should be controlled only via * the INIT/CHECK/RESET_PREVIOUS_OP() macros. See the * MTLRenderQueue_CheckPreviousOp() method below for more information. */ jint previousOp; /** * References to the "current" context and destination surface. */ static MTLContext *mtlc = NULL; static BMTLSDOps *dstOps = NULL; /** * The following methods are implemented in the windowing system (i.e. GLX * and WGL) source files. */ extern void MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo); extern void MTLSD_SwapBuffers(JNIEnv *env, jlong window); /** * Helper methods to manage modified layers */ static MTLLayer ** g_modifiedLayers = NULL; static int g_modifiedLayersCount = 0; static int g_modifiedLayersAllocatedCount = 0; static void markLayerModified(MTLLayer * modifiedLayer) { if (modifiedLayer == NULL) return; if (g_modifiedLayers == NULL) { g_modifiedLayersAllocatedCount = 3; g_modifiedLayers = malloc(g_modifiedLayersAllocatedCount * sizeof(MTLLayer *)); } for (int c = 0; c < g_modifiedLayersCount; ++c) { if (g_modifiedLayers[c] == modifiedLayer) return; } ++g_modifiedLayersCount; if (g_modifiedLayersCount > g_modifiedLayersAllocatedCount) { g_modifiedLayersAllocatedCount = g_modifiedLayersCount; g_modifiedLayers = realloc(g_modifiedLayers, g_modifiedLayersAllocatedCount * sizeof(MTLLayer *)); } g_modifiedLayers[g_modifiedLayersCount - 1] = modifiedLayer; } static void scheduleBlitAllModifiedLayers() { for (int c = 0; c < g_modifiedLayersCount; ++c) { MTLLayer * layer = g_modifiedLayers[c]; MTLContext * ctx = layer.ctx; if (layer == NULL || ctx == NULL) continue; id bufferToCommit = ctx.commandBuffer; [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ [layer blitTexture:bufferToCommit]; }]; [ctx releaseCommandBuffer]; } g_modifiedLayersCount = 0; } static void onSurfaceModified(BMTLSDOps *bmtldst) { if (bmtldst != NULL && bmtldst->privOps != NULL && ((MTLSDOps *)bmtldst->privOps)->layer != NULL) markLayerModified(((MTLSDOps *) bmtldst->privOps)->layer); } static const jint g_drawOpcodes[] = { sun_java2d_pipe_BufferedOpCodes_DRAW_LINE, sun_java2d_pipe_BufferedOpCodes_DRAW_RECT, sun_java2d_pipe_BufferedOpCodes_DRAW_POLY, sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL, sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES, sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM, sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM, sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST, sun_java2d_pipe_BufferedOpCodes_FILL_RECT, sun_java2d_pipe_BufferedOpCodes_FILL_SPANS, sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM, sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM, sun_java2d_pipe_BufferedOpCodes_COPY_AREA, sun_java2d_pipe_BufferedOpCodes_MASK_FILL, sun_java2d_pipe_BufferedOpCodes_MASK_BLIT, sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS }; static jboolean isDrawOpcode(jint opcode) { for (int c = 0; c < sizeof(g_drawOpcodes)/sizeof(g_drawOpcodes[0]); ++c) { if (opcode == g_drawOpcodes[c]) return JNI_TRUE; } return JNI_FALSE; } JNIEXPORT void JNICALL Java_sun_java2d_metal_MTLRenderQueue_flushBuffer (JNIEnv *env, jobject mtlrq, jlong buf, jint limit) { jboolean sync = JNI_FALSE; unsigned char *b, *end; J2dTraceLn1(J2D_TRACE_INFO, "MTLRenderQueue_flushBuffer: limit=%d", limit); b = (unsigned char *)jlong_to_ptr(buf); if (b == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderQueue_flushBuffer: cannot get direct buffer address"); return; } INIT_PREVIOUS_OP(); end = b + limit; while (b < end) { jint opcode = NEXT_INT(b); J2dTraceLn2(J2D_TRACE_VERBOSE, "MTLRenderQueue_flushBuffer: opcode=%d, rem=%d", opcode, (end-b)); if (opcode != sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST && opcode != sun_java2d_pipe_BufferedOpCodes_NOOP) { //MTLTR_DisableGlyphModeState(); } switch (opcode) { // draw ops case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE: { J2dTraceLn(J2D_TRACE_VERBOSE, "sun_java2d_pipe_BufferedOpCodes_DRAW_LINE"); jint x1 = NEXT_INT(b); jint y1 = NEXT_INT(b); jint x2 = NEXT_INT(b); jint y2 = NEXT_INT(b); MTLRenderer_DrawLine(mtlc, dstOps, x1, y1, x2, y2); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); MTLRenderer_DrawRect(mtlc, dstOps, x, y, w, h); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY: { jint nPoints = NEXT_INT(b); jboolean isClosed = NEXT_BOOLEAN(b); jint transX = NEXT_INT(b); jint transY = NEXT_INT(b); jint *xPoints = (jint *)b; jint *yPoints = ((jint *)b) + nPoints; MTLRenderer_DrawPoly(mtlc, dstOps, nPoints, isClosed, transX, transY, xPoints, yPoints); SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); CONTINUE_IF_NULL(mtlc); //TODO J2dTraceNotImplPrimitive("MTLRenderQueue_DRAW_PIXEL"); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES: { jint count = NEXT_INT(b); MTLRenderer_DrawScanlines(mtlc, dstOps, count, (jint *)b); SKIP_BYTES(b, count * BYTES_PER_SCANLINE); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM: { jfloat x11 = NEXT_FLOAT(b); jfloat y11 = NEXT_FLOAT(b); jfloat dx21 = NEXT_FLOAT(b); jfloat dy21 = NEXT_FLOAT(b); jfloat dx12 = NEXT_FLOAT(b); jfloat dy12 = NEXT_FLOAT(b); jfloat lwr21 = NEXT_FLOAT(b); jfloat lwr12 = NEXT_FLOAT(b); MTLRenderer_DrawParallelogram(mtlc, dstOps, x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM: { jfloat x11 = NEXT_FLOAT(b); jfloat y11 = NEXT_FLOAT(b); jfloat dx21 = NEXT_FLOAT(b); jfloat dy21 = NEXT_FLOAT(b); jfloat dx12 = NEXT_FLOAT(b); jfloat dy12 = NEXT_FLOAT(b); jfloat lwr21 = NEXT_FLOAT(b); jfloat lwr12 = NEXT_FLOAT(b); MTLRenderer_DrawAAParallelogram(mtlc, dstOps, x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12); } break; // fill ops case sun_java2d_pipe_BufferedOpCodes_FILL_RECT: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); MTLRenderer_FillRect(mtlc, dstOps, x, y, w, h); } break; case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS: { jint count = NEXT_INT(b); MTLRenderer_FillSpans(mtlc, dstOps, count, (jint *)b); SKIP_BYTES(b, count * BYTES_PER_SPAN); } break; case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM: { jfloat x11 = NEXT_FLOAT(b); jfloat y11 = NEXT_FLOAT(b); jfloat dx21 = NEXT_FLOAT(b); jfloat dy21 = NEXT_FLOAT(b); jfloat dx12 = NEXT_FLOAT(b); jfloat dy12 = NEXT_FLOAT(b); MTLRenderer_FillParallelogram(mtlc, dstOps, x11, y11, dx21, dy21, dx12, dy12); } break; case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM: { jfloat x11 = NEXT_FLOAT(b); jfloat y11 = NEXT_FLOAT(b); jfloat dx21 = NEXT_FLOAT(b); jfloat dy21 = NEXT_FLOAT(b); jfloat dx12 = NEXT_FLOAT(b); jfloat dy12 = NEXT_FLOAT(b); MTLRenderer_FillAAParallelogram(mtlc, dstOps, x11, y11, dx21, dy21, dx12, dy12); } break; // text-related ops case sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST: { jint numGlyphs = NEXT_INT(b); jint packedParams = NEXT_INT(b); jfloat glyphListOrigX = NEXT_FLOAT(b); jfloat glyphListOrigY = NEXT_FLOAT(b); jboolean usePositions = EXTRACT_BOOLEAN(packedParams, OFFSET_POSITIONS); jboolean subPixPos = EXTRACT_BOOLEAN(packedParams, OFFSET_SUBPIXPOS); jboolean rgbOrder = EXTRACT_BOOLEAN(packedParams, OFFSET_RGBORDER); jint lcdContrast = EXTRACT_BYTE(packedParams, OFFSET_CONTRAST); unsigned char *images = b; unsigned char *positions; jint bytesPerGlyph; if (usePositions) { positions = (b + numGlyphs * BYTES_PER_GLYPH_IMAGE); bytesPerGlyph = BYTES_PER_POSITIONED_GLYPH; } else { positions = NULL; bytesPerGlyph = BYTES_PER_GLYPH_IMAGE; } MTLTR_DrawGlyphList(env, mtlc, dstOps, numGlyphs, usePositions, subPixPos, rgbOrder, lcdContrast, glyphListOrigX, glyphListOrigY, images, positions); SKIP_BYTES(b, numGlyphs * bytesPerGlyph); } break; // copy-related ops case sun_java2d_pipe_BufferedOpCodes_COPY_AREA: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); jint dx = NEXT_INT(b); jint dy = NEXT_INT(b); MTLBlitLoops_CopyArea(env, mtlc, dstOps, x, y, w, h, dx, dy); } break; case sun_java2d_pipe_BufferedOpCodes_BLIT: { J2dTracePrimitive("MTLRenderQueue_BLIT"); jint packedParams = NEXT_INT(b); jint sx1 = NEXT_INT(b); jint sy1 = NEXT_INT(b); jint sx2 = NEXT_INT(b); jint sy2 = NEXT_INT(b); jdouble dx1 = NEXT_DOUBLE(b); jdouble dy1 = NEXT_DOUBLE(b); jdouble dx2 = NEXT_DOUBLE(b); jdouble dy2 = NEXT_DOUBLE(b); jlong pSrc = NEXT_LONG(b); jlong pDst = NEXT_LONG(b); jint hint = EXTRACT_BYTE(packedParams, OFFSET_HINT); jboolean texture = EXTRACT_BOOLEAN(packedParams, OFFSET_TEXTURE); jboolean rtt = EXTRACT_BOOLEAN(packedParams, OFFSET_RTT); jboolean xform = EXTRACT_BOOLEAN(packedParams, OFFSET_XFORM); jboolean isoblit = EXTRACT_BOOLEAN(packedParams, OFFSET_ISOBLIT); if (isoblit) { MTLBlitLoops_IsoBlit(env, mtlc, pSrc, pDst, xform, hint, texture, rtt, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); } else { jint srctype = EXTRACT_BYTE(packedParams, OFFSET_SRCTYPE); MTLBlitLoops_Blit(env, mtlc, pSrc, pDst, xform, hint, srctype, texture, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); } onSurfaceModified(jlong_to_ptr(pDst)); } break; case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT: { J2dTracePrimitive("MTLRenderQueue_SURFACE_TO_SW_BLIT"); jint sx = NEXT_INT(b); jint sy = NEXT_INT(b); jint dx = NEXT_INT(b); jint dy = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); jint dsttype = NEXT_INT(b); jlong pSrc = NEXT_LONG(b); jlong pDst = NEXT_LONG(b); MTLBlitLoops_SurfaceToSwBlit(env, mtlc, pSrc, pDst, dsttype, sx, sy, dx, dy, w, h); } break; case sun_java2d_pipe_BufferedOpCodes_MASK_FILL: { J2dTracePrimitive("MTLRenderQueue_MASK_FILL"); jint x = NEXT_INT(b); jint y = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); jint maskoff = NEXT_INT(b); jint maskscan = NEXT_INT(b); jint masklen = NEXT_INT(b); unsigned char *pMask = (masklen > 0) ? b : NULL; MTLMaskFill_MaskFill(mtlc, dstOps, x, y, w, h, maskoff, maskscan, masklen, pMask); SKIP_BYTES(b, masklen); } break; case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT: { J2dTracePrimitive("MTLRenderQueue_MASK_BLIT"); jint dstx = NEXT_INT(b); jint dsty = NEXT_INT(b); jint width = NEXT_INT(b); jint height = NEXT_INT(b); jint masklen = width * height * sizeof(jint); MTLMaskBlit_MaskBlit(env, mtlc, dstOps, dstx, dsty, width, height, b); SKIP_BYTES(b, masklen); } break; // state-related ops case sun_java2d_pipe_BufferedOpCodes_SET_RECT_CLIP: { jint x1 = NEXT_INT(b); jint y1 = NEXT_INT(b); jint x2 = NEXT_INT(b); jint y2 = NEXT_INT(b); [mtlc setClipRectX1:x1 Y1:y1 X2:x2 Y2:y2]; } break; case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP: { [mtlc beginShapeClip]; } break; case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS: { jint count = NEXT_INT(b); MTLRenderer_FillSpans(mtlc, dstOps, count, (jint *)b); SKIP_BYTES(b, count * BYTES_PER_SPAN); } break; case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP: { //TODO [mtlc endShapeClipDstOps:dstOps]; } break; case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP: { [mtlc resetClip]; } break; case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE: { jint rule = NEXT_INT(b); jfloat extraAlpha = NEXT_FLOAT(b); jint flags = NEXT_INT(b); [mtlc setAlphaCompositeRule:rule extraAlpha:extraAlpha flags:flags]; } break; case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE: { jint xorPixel = NEXT_INT(b); [mtlc setXorComposite:xorPixel]; } break; case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE: { [mtlc resetComposite]; } break; case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM: { jdouble m00 = NEXT_DOUBLE(b); jdouble m10 = NEXT_DOUBLE(b); jdouble m01 = NEXT_DOUBLE(b); jdouble m11 = NEXT_DOUBLE(b); jdouble m02 = NEXT_DOUBLE(b); jdouble m12 = NEXT_DOUBLE(b); [mtlc setTransformM00:m00 M10:m10 M01:m01 M11:m11 M02:m02 M12:m12]; } break; case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM: { [mtlc resetTransform]; } break; // context-related ops case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES: { J2dTracePrimitive("MTLRenderQueue_SET_SURFACES"); jlong pSrc = NEXT_LONG(b); jlong pDst = NEXT_LONG(b); if (mtlc != NULL) { RESET_PREVIOUS_OP(); } dstOps = (BMTLSDOps *)jlong_to_ptr(pDst); [MTLContext setSurfacesEnv:env src:pSrc dst:pDst]; } break; case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE: { J2dTracePrimitive("MTLRenderQueue_SET_SCRATCH_SURFACE"); jlong pConfigInfo = NEXT_LONG(b); MTLGraphicsConfigInfo *mtlInfo = (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); if (mtlInfo == NULL) { J2dTraceImplPrimitive( "MTLRenderQueue_SET_SCRATCH_SURFACE", "ERROR: mtl config info is null"); } else { MTLContext *newMtlc = mtlInfo->context; if (newMtlc == NULL) { J2dTraceImplPrimitive( "MTLRenderQueue_SET_SCRATCH_SURFACE", "ERROR: mtl context is null"); } else { mtlc = newMtlc; dstOps = NULL; } } } break; case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE: { J2dTracePrimitive("MTLRenderQueue_FLUSH_SURFACE"); jlong pData = NEXT_LONG(b); BMTLSDOps *mtlsdo = (BMTLSDOps *)jlong_to_ptr(pData); if (mtlsdo != NULL) { CONTINUE_IF_NULL(mtlc); RESET_PREVIOUS_OP(); MTLSD_Delete(env, mtlsdo); } } break; case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE: { J2dTracePrimitive("MTLRenderQueue_DISPOSE_SURFACE"); jlong pData = NEXT_LONG(b); BMTLSDOps *mtlsdo = (BMTLSDOps *)jlong_to_ptr(pData); if (mtlsdo != NULL) { CONTINUE_IF_NULL(mtlc); RESET_PREVIOUS_OP(); MTLSD_Delete(env, mtlsdo); if (mtlsdo->privOps != NULL) { free(mtlsdo->privOps); } } } break; case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG: { J2dTracePrimitive("MTLRenderQueue_DISPOSE_CONFIG"); jlong pConfigInfo = NEXT_LONG(b); CONTINUE_IF_NULL(mtlc); RESET_PREVIOUS_OP(); [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ MTLGC_DestroyMTLGraphicsConfig(pConfigInfo); }]; // the previous method will call glX/wglMakeCurrent(None), // so we should nullify the current mtlc and dstOps to avoid // calling glFlush() (or similar) while no context is current mtlc = NULL; // dstOps = NULL; } break; case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT: { //TODO J2dTraceNotImplPrimitive("MTLRenderQueue_INVALIDATE_CONTEXT"); // flush just in case there are any pending operations in // the hardware pipe if (mtlc != NULL) { RESET_PREVIOUS_OP(); } // invalidate the references to the current context and // destination surface that are maintained at the native level mtlc = NULL; // dstOps = NULL; } break; case sun_java2d_pipe_BufferedOpCodes_SAVE_STATE: { //TODO J2dTraceNotImplPrimitive("MTLRenderQueue_INVALIDATE_CONTEXT"); } break; case sun_java2d_pipe_BufferedOpCodes_RESTORE_STATE: { //TODO J2dTraceNotImplPrimitive("MTLRenderQueue_RESTORE_STATE"); } break; case sun_java2d_pipe_BufferedOpCodes_SYNC: { sync = JNI_TRUE; } break; // multibuffering ops case sun_java2d_pipe_BufferedOpCodes_SWAP_BUFFERS: { jlong window = NEXT_LONG(b); if (mtlc != NULL) { RESET_PREVIOUS_OP(); } MTLSD_SwapBuffers(env, window); } break; // special no-op (mainly used for achieving 8-byte alignment) case sun_java2d_pipe_BufferedOpCodes_NOOP: break; // paint-related ops case sun_java2d_pipe_BufferedOpCodes_RESET_PAINT: { MTLPaints_ResetPaint(mtlc); } break; case sun_java2d_pipe_BufferedOpCodes_SET_COLOR: { jint pixel = NEXT_INT(b); if (dstOps != NULL) { MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps; dstCGLOps->configInfo->context.color = pixel; } MTLPaints_SetColor(mtlc, pixel); } break; case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT: { J2dTraceNotImplPrimitive("MTLRenderQueue_SET_GRADIENT_PAINT"); jboolean useMask= NEXT_BOOLEAN(b); jboolean cyclic = NEXT_BOOLEAN(b); jdouble p0 = NEXT_DOUBLE(b); jdouble p1 = NEXT_DOUBLE(b); jdouble p3 = NEXT_DOUBLE(b); jint pixel1 = NEXT_INT(b); jint pixel2 = NEXT_INT(b); if (dstOps != NULL) { MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps; [dstCGLOps->configInfo->context setGradientPaintUseMask:useMask cyclic:cyclic p0:p0 p1:p1 p3:p3 pixel1:pixel1 pixel2:pixel2]; } } break; case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT: { jboolean useMask = NEXT_BOOLEAN(b); jboolean linear = NEXT_BOOLEAN(b); jint cycleMethod = NEXT_INT(b); jint numStops = NEXT_INT(b); jfloat p0 = NEXT_FLOAT(b); jfloat p1 = NEXT_FLOAT(b); jfloat p3 = NEXT_FLOAT(b); void *fractions, *pixels; fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat)); pixels = b; SKIP_BYTES(b, numStops * sizeof(jint)); MTLPaints_SetLinearGradientPaint(mtlc, dstOps, useMask, linear, cycleMethod, numStops, p0, p1, p3, fractions, pixels); } break; case sun_java2d_pipe_BufferedOpCodes_SET_RADIAL_GRADIENT_PAINT: { jboolean useMask = NEXT_BOOLEAN(b); jboolean linear = NEXT_BOOLEAN(b); jint numStops = NEXT_INT(b); jint cycleMethod = NEXT_INT(b); jfloat m00 = NEXT_FLOAT(b); jfloat m01 = NEXT_FLOAT(b); jfloat m02 = NEXT_FLOAT(b); jfloat m10 = NEXT_FLOAT(b); jfloat m11 = NEXT_FLOAT(b); jfloat m12 = NEXT_FLOAT(b); jfloat focusX = NEXT_FLOAT(b); void *fractions, *pixels; fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat)); pixels = b; SKIP_BYTES(b, numStops * sizeof(jint)); MTLPaints_SetRadialGradientPaint(mtlc, dstOps, useMask, linear, cycleMethod, numStops, m00, m01, m02, m10, m11, m12, focusX, fractions, pixels); } break; case sun_java2d_pipe_BufferedOpCodes_SET_TEXTURE_PAINT: { jboolean useMask= NEXT_BOOLEAN(b); jboolean filter = NEXT_BOOLEAN(b); jlong pSrc = NEXT_LONG(b); jdouble xp0 = NEXT_DOUBLE(b); jdouble xp1 = NEXT_DOUBLE(b); jdouble xp3 = NEXT_DOUBLE(b); jdouble yp0 = NEXT_DOUBLE(b); jdouble yp1 = NEXT_DOUBLE(b); jdouble yp3 = NEXT_DOUBLE(b); MTLPaints_SetTexturePaint(mtlc, useMask, pSrc, filter, xp0, xp1, xp3, yp0, yp1, yp3); } break; // BufferedImageOp-related ops case sun_java2d_pipe_BufferedOpCodes_ENABLE_CONVOLVE_OP: { jlong pSrc = NEXT_LONG(b); jboolean edgeZero = NEXT_BOOLEAN(b); jint kernelWidth = NEXT_INT(b); jint kernelHeight = NEXT_INT(b); MTLBufImgOps_EnableConvolveOp(mtlc, pSrc, edgeZero, kernelWidth, kernelHeight, b); SKIP_BYTES(b, kernelWidth * kernelHeight * sizeof(jfloat)); } break; case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP: { MTLBufImgOps_DisableConvolveOp(mtlc); } break; case sun_java2d_pipe_BufferedOpCodes_ENABLE_RESCALE_OP: { jlong pSrc = NEXT_LONG(b); jboolean nonPremult = NEXT_BOOLEAN(b); jint numFactors = 4; unsigned char *scaleFactors = b; unsigned char *offsets = (b + numFactors * sizeof(jfloat)); MTLBufImgOps_EnableRescaleOp(mtlc, pSrc, nonPremult, scaleFactors, offsets); SKIP_BYTES(b, numFactors * sizeof(jfloat) * 2); } break; case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP: { MTLBufImgOps_DisableRescaleOp(mtlc); } break; case sun_java2d_pipe_BufferedOpCodes_ENABLE_LOOKUP_OP: { jlong pSrc = NEXT_LONG(b); jboolean nonPremult = NEXT_BOOLEAN(b); jboolean shortData = NEXT_BOOLEAN(b); jint numBands = NEXT_INT(b); jint bandLength = NEXT_INT(b); jint offset = NEXT_INT(b); jint bytesPerElem = shortData ? sizeof(jshort):sizeof(jbyte); void *tableValues = b; MTLBufImgOps_EnableLookupOp(mtlc, pSrc, nonPremult, shortData, numBands, bandLength, offset, tableValues); SKIP_BYTES(b, numBands * bandLength * bytesPerElem); } break; case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP: { MTLBufImgOps_DisableLookupOp(mtlc); } break; default: J2dRlsTraceLn1(J2D_TRACE_ERROR, "MTLRenderQueue_flushBuffer: invalid opcode=%d", opcode); if (mtlc != NULL) { RESET_PREVIOUS_OP(); } return; } if (isDrawOpcode(opcode)) // performed rendering operation on dstOps onSurfaceModified(dstOps); } MTLTR_DisableGlyphModeState(); scheduleBlitAllModifiedLayers(); } /** * Returns a pointer to the "current" context, as set by the last SET_SURFACES * or SET_SCRATCH_SURFACE operation. */ MTLContext * MTLRenderQueue_GetCurrentContext() { return mtlc; } /** * Returns a pointer to the "current" destination surface, as set by the last * SET_SURFACES operation. */ BMTLSDOps * MTLRenderQueue_GetCurrentDestination() { return dstOps; } /** * Used to track whether we are within a series of simple primitive operations * or texturing operations. The op parameter determines the nature of the * operation that is to follow. Valid values for this op parameter are: */ void MTLRenderQueue_CheckPreviousOp(jint op) { //TODO J2dTraceNotImplPrimitive("MTLRenderQueue_CheckPreviousOp"); previousOp = op; } #endif /* !HEADLESS */