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 #include <string.h>
  30 
  31 #include "sun_java2d_SunGraphics2D.h"
  32 
  33 #include "jlong.h"
  34 #include "jni_util.h"
  35 #import "MTLContext.h"
  36 #include "MTLRenderQueue.h"
  37 #include "MTLSurfaceDataBase.h"
  38 #include "GraphicsPrimitiveMgr.h"
  39 #include "Region.h"
  40 #include "common.h"
  41 
  42 #include "jvm.h"
  43 
  44 extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
  45 extern MTLContext *MTLSD_MakeMTLContextCurrent(JNIEnv *env,
  46                                                MTLSDOps *srcOps,
  47                                                MTLSDOps *dstOps);
  48 
  49 #define RGBA_TO_V4(c)              \
  50 {                                  \
  51     (((c) >> 16) & (0xFF))/255.0f, \
  52     (((c) >> 8) & 0xFF)/255.0f,    \
  53     ((c) & 0xFF)/255.0f,           \
  54     (((c) >> 24) & 0xFF)/255.0f    \
  55 }
  56 
  57 /**
  58  * This table contains the standard blending rules (or Porter-Duff compositing
  59  * factors) used in glBlendFunc(), indexed by the rule constants from the
  60  * AlphaComposite class.
  61  */
  62 MTLBlendRule MTStdBlendRules[] = {
  63 };
  64 
  65 static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
  66         {{-1.0, 1.0, 0.0}, {0.0, 0.0}},
  67         {{1.0, 1.0, 0.0}, {1.0, 0.0}},
  68         {{1.0, -1.0, 0.0}, {1.0, 1.0}},
  69         {{1.0, -1.0, 0.0}, {1.0, 1.0}},
  70         {{-1.0, -1.0, 0.0}, {0.0, 1.0}},
  71         {{-1.0, 1.0, 0.0}, {0.0, 0.0}}
  72 };
  73 
  74 
  75 static void _traceMatrix(simd_float4x4 * mtx) {
  76     for (int row = 0; row < 4; ++row) {
  77         J2dTraceLn4(J2D_TRACE_VERBOSE, "  [%lf %lf %lf %lf]",
  78                     mtx->columns[0][row], mtx->columns[1][row], mtx->columns[2][row], mtx->columns[3][row]);
  79     }
  80 }
  81 
  82 MTLRenderPassDescriptor* createRenderPassDesc(id<MTLTexture> dest) {
  83     MTLRenderPassDescriptor * result = [MTLRenderPassDescriptor renderPassDescriptor];
  84     if (result == nil)
  85         return nil;
  86 
  87     if (dest == nil) {
  88         J2dTraceLn(J2D_TRACE_ERROR, "_createRenderPassDesc: destination texture is null");
  89         return nil;
  90     }
  91 
  92     MTLRenderPassColorAttachmentDescriptor * ca = result.colorAttachments[0];
  93     ca.texture = dest;
  94     ca.loadAction = MTLLoadActionLoad;
  95     ca.clearColor = MTLClearColorMake(0.0f, 0.9f, 0.0f, 1.0f);
  96     ca.storeAction = MTLStoreActionStore;
  97     return result;
  98 }
  99 
 100 @implementation MTLContext {
 101     id<MTLCommandBuffer> _commandBuffer;
 102 }
 103 
 104 @synthesize compState, extraAlpha, alphaCompositeRule, xorPixel, pixel, p0,
 105             p1, p3, cyclic, pixel1, pixel2, r, g, b, a, paintState, useMask,
 106             useTransform, transform4x4, blitTextureID, textureFunction,
 107             vertexCacheEnabled, device, library, pipelineState, pipelineStateStorage,
 108             commandQueue, vertexBuffer,
 109             color, clipRect, useClip, texturePool;
 110 
 111 
 112  - (id<MTLCommandBuffer>) commandBuffer {
 113     if (_commandBuffer == nil) {
 114         // NOTE: Command queues are thread-safe and allow multiple outstanding command buffers to be encoded simultaneously.
 115         _commandBuffer = [[self.commandQueue commandBuffer] retain];// released in [layer blitTexture]
 116     }
 117     return _commandBuffer;
 118 }
 119 
 120 - (void)releaseCommandBuffer {
 121     [_commandBuffer release];
 122     _commandBuffer = nil;
 123 }
 124 
 125 + (MTLContext*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(jlong)pDst {
 126     BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrc);
 127     BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDst);
 128     MTLContext *mtlc = NULL;
 129 
 130     if (srcOps == NULL || dstOps == NULL) {
 131         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_SetSurfaces: ops are null");
 132         return NULL;
 133     }
 134 
 135     J2dTraceLn6(J2D_TRACE_VERBOSE, "MTLContext_SetSurfaces: bsrc=%p (tex=%p type=%d), bdst=%p (tex=%p type=%d)", srcOps, srcOps->pTexture, srcOps->drawableType, dstOps, dstOps->pTexture, dstOps->drawableType);
 136 
 137     if (dstOps->drawableType == MTLSD_TEXTURE) {
 138         J2dRlsTraceLn(J2D_TRACE_ERROR,
 139                       "MTLContext_SetSurfaces: texture cannot be used as destination");
 140         return NULL;
 141     }
 142 
 143     if (dstOps->drawableType == MTLSD_UNDEFINED) {
 144         // initialize the surface as an OGLSD_WINDOW
 145         if (!MTLSD_InitMTLWindow(env, dstOps)) {
 146             J2dRlsTraceLn(J2D_TRACE_ERROR,
 147                           "MTLContext_SetSurfaces: could not init OGL window");
 148             return NULL;
 149         }
 150     }
 151 
 152     // make the context current
 153     MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
 154     mtlc = dstCGLOps->configInfo->context;
 155 
 156     if (mtlc == NULL) {
 157         J2dRlsTraceLn(J2D_TRACE_ERROR,
 158                       "MTLContext_SetSurfaces: could not make context current");
 159         return NULL;
 160     }
 161 
 162     // perform additional one-time initialization, if necessary
 163     if (dstOps->needsInit) {
 164         if (dstOps->isOpaque) {
 165             // in this case we are treating the destination as opaque, but
 166             // to do so, first we need to ensure that the alpha channel
 167             // is filled with fully opaque values (see 6319663)
 168             //MTLContext_InitAlphaChannel();
 169         }
 170         dstOps->needsInit = JNI_FALSE;
 171     }
 172 
 173     return mtlc;
 174 }
 175 
 176 - (id)initWithDevice:(id<MTLDevice>)d shadersLib:(NSString*)shadersLib {
 177     self = [super init];
 178     if (self) {
 179         // Initialization code here.
 180         device = d;
 181 
 182         texturePool = [[MTLTexturePool alloc] initWithDevice:device];
 183         pipelineStateStorage = [[MTLPipelineStatesStorage alloc] initWithDevice:device shaderLibPath:shadersLib];
 184 
 185         vertexBuffer = [device newBufferWithBytes:verts
 186                                            length:sizeof(verts)
 187                                           options:MTLResourceCPUCacheModeDefaultCache];
 188 
 189         NSError *error = nil;
 190 
 191         library = [device newLibraryWithFile:shadersLib error:&error];
 192         if (!library) {
 193             NSLog(@"Failed to load library. error %@", error);
 194             exit(0);
 195         }
 196 
 197         _commandBuffer = nil;
 198 
 199         // Create command queue
 200         commandQueue = [device newCommandQueue];
 201     }
 202     return self;
 203 }
 204 
 205 - (void)resetClip {
 206     //TODO
 207     J2dTraceNotImplPrimitive("MTLContext.resetClip");
 208     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.resetClip");
 209     useClip = JNI_FALSE;
 210 }
 211 
 212 - (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2 {
 213     //TODO
 214     J2dTraceNotImplPrimitive("MTLContext.setClipRectX1:Y1:X2:Y2");
 215     jint width = x2 - x1;
 216     jint height = y2 - y1;
 217 
 218     J2dTraceLn4(J2D_TRACE_INFO, "MTLContext.setClipRect: x=%d y=%d w=%d h=%d", x1, y1, width, height);
 219 
 220     clipRect.x = x1;
 221     clipRect.y = y1;
 222     clipRect.width = width;
 223     clipRect.height = height;
 224     useClip = JNI_TRUE;
 225 }
 226 
 227 - (void)beginShapeClip {
 228     //TODO
 229     J2dTraceNotImplPrimitive("MTLContext.beginShapeClip");
 230     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.beginShapeClip");
 231 }
 232 
 233 - (void)endShapeClip {
 234     //TODO
 235     J2dTraceNotImplPrimitive("MTLContext.endShapeClip");
 236     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.endShapeClip");
 237 }
 238 
 239 - (void)resetComposite {
 240     //TODO
 241     J2dTraceNotImplPrimitive("MTLContext_ResetComposite");
 242     J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetComposite");
 243 }
 244 
 245 - (void)setAlphaCompositeRule:(jint)rule extraAlpha:(jfloat)_extraAlpha
 246                         flags:(jint)flags {
 247     J2dTracePrimitive("MTLContext_SetAlphaComposite");
 248     J2dTraceLn3(J2D_TRACE_INFO, "MTLContext_SetAlphaComposite: rule=%d, extraAlpha=%1.2f, flags=%d", rule, extraAlpha, flags);
 249 
 250     extraAlpha = _extraAlpha;
 251     alphaCompositeRule = rule;
 252 }
 253 
 254 
 255 - (void)setXorComposite:(jint)xp {
 256     //TODO
 257     J2dTraceNotImplPrimitive("MTLContext.setXorComposite");
 258     J2dTraceLn1(J2D_TRACE_INFO,
 259                 "MTLContext.setXorComposite: xorPixel=%08x", xp);
 260 }
 261 
 262 - (jboolean)isBlendingDisabled {
 263     // TODO: hold case mtlc->alphaCompositeRule == RULE_SrcOver && sun_java2d_pipe_BufferedContext_SRC_IS_OPAQUE
 264     return alphaCompositeRule == RULE_Src && (extraAlpha - 1.0f < 0.001f);
 265 }
 266 
 267 
 268 - (void)resetTransform {
 269     J2dTracePrimitive("MTLContext_ResetTransform");
 270     J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetTransform");
 271     useTransform = JNI_FALSE;
 272 }
 273 
 274 - (void)setTransformM00:(jdouble) m00 M10:(jdouble) m10
 275                     M01:(jdouble) m01 M11:(jdouble) m11
 276                     M02:(jdouble) m02 M12:(jdouble) m12 {
 277 
 278 
 279     J2dTraceLn(J2D_TRACE_INFO, "MTLContext_SetTransform");
 280 
 281     J2dTracePrimitive("MTLContext_SetTransform");
 282 
 283     memset(&(transform4x4), 0, sizeof(transform4x4));
 284     transform4x4.columns[0][0] = m00;
 285     transform4x4.columns[0][1] = m10;
 286     transform4x4.columns[1][0] = m01;
 287     transform4x4.columns[1][1] = m11;
 288     transform4x4.columns[3][0] = m02;
 289     transform4x4.columns[3][1] = m12;
 290     transform4x4.columns[3][3] = 1.0;
 291     transform4x4.columns[4][4] = 1.0;
 292     useTransform = JNI_TRUE;
 293 }
 294 
 295 - (jboolean)initBlitTileTexture {
 296     //TODO
 297     J2dTraceNotImplPrimitive("MTLContext_InitBlitTileTexture");
 298     J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitBlitTileTexture");
 299 
 300     return JNI_TRUE;
 301 }
 302 
 303 - (jint)createBlitTextureFormat:(jint)internalFormat pixelFormat:(jint)pixelFormat
 304                           width:(jint)width height:(jint)height {
 305     //TODO
 306     J2dTraceNotImplPrimitive("MTLContext_CreateBlitTexture");
 307     return 0;
 308 }
 309 
 310 
 311 - (void)setColorR:(int)_r G:(int)_g B:(int)_b A:(int)_a {
 312     color = 0;
 313     color |= (_r & (0xFF)) << 16;
 314     color |= (_g & (0xFF)) << 8;
 315     color |= _b & (0xFF);
 316     color |= (_a & (0xFF)) << 24;
 317     J2dTraceLn4(J2D_TRACE_INFO, "MTLContext.setColor (%d, %d, %d) %d", r,g,b,a);
 318 }
 319 
 320 - (void)setColorInt:(int)_pixel {
 321     color = _pixel;
 322     J2dTraceLn5(J2D_TRACE_INFO, "MTLContext.setColorInt: pixel=%08x [r=%d g=%d b=%d a=%d]", pixel, (pixel >> 16) & (0xFF), (pixel >> 8) & 0xFF, (pixel) & 0xFF, (pixel >> 24) & 0xFF);
 323 }
 324 
 325 - (id<MTLRenderCommandEncoder>) createEncoderForDest:(id<MTLTexture>) dest {
 326     id<MTLCommandBuffer> cb = self.commandBuffer;
 327     if (cb == nil)
 328         return nil;
 329 
 330     MTLRenderPassDescriptor * rpd = createRenderPassDesc(dest);
 331     if (rpd == nil)
 332         return nil;
 333 
 334     // J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext: created render encoder to draw on tex=%p", dest);
 335     return [cb renderCommandEncoderWithDescriptor:rpd];
 336 }
 337 
 338 - (void) setEncoderTransform:(id<MTLRenderCommandEncoder>) encoder dest:(id<MTLTexture>) dest {
 339     simd_float4x4 normalize;
 340     memset(&normalize, 0, sizeof(normalize));
 341     normalize.columns[0][0] = 2/(double)dest.width;
 342     normalize.columns[1][1] = -2/(double)dest.height;
 343     normalize.columns[3][0] = -1.f;
 344     normalize.columns[3][1] = 1.f;
 345     normalize.columns[3][3] = 1.0;
 346     normalize.columns[4][4] = 1.0;
 347 
 348     if (useTransform) {
 349         simd_float4x4 vertexMatrix = simd_mul(normalize, transform4x4);
 350         [encoder setVertexBytes:&(vertexMatrix) length:sizeof(vertexMatrix) atIndex:MatrixBuffer];
 351     } else {
 352         [encoder setVertexBytes:&(normalize) length:sizeof(normalize) atIndex:MatrixBuffer];
 353     }
 354 }
 355 
 356 - (id<MTLRenderCommandEncoder>) createRenderEncoderForDest:(id<MTLTexture>) dest {
 357     id <MTLRenderCommandEncoder> mtlEncoder = [self createEncoderForDest: dest];
 358     if (useClip)
 359         [mtlEncoder setScissorRect:clipRect];
 360 
 361     if (compState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
 362         // set pipeline state
 363         [mtlEncoder setRenderPipelineState:[self.pipelineStateStorage getRenderPipelineState:NO]];
 364         struct FrameUniforms uf = {RGBA_TO_V4(color)};
 365         [mtlEncoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
 366     } else if (compState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
 367         // set viewport and pipeline state
 368         //[mtlEncoder setRenderPipelineState:gradPipelineState];
 369         [mtlEncoder setRenderPipelineState:[self.pipelineStateStorage getRenderPipelineState:YES]];
 370 
 371         struct GradFrameUniforms uf = {
 372                 {p0, p1, p3},
 373                 RGBA_TO_V4(pixel1),
 374                 RGBA_TO_V4(pixel2)};
 375 
 376         [mtlEncoder setFragmentBytes: &uf length:sizeof(uf) atIndex:0];
 377     }
 378     [self setEncoderTransform:mtlEncoder dest:dest];
 379     return mtlEncoder;
 380 }
 381 
 382 - (id<MTLRenderCommandEncoder>)createSamplingEncoderForDest:(id<MTLTexture>)dest {
 383     id <MTLRenderCommandEncoder> mtlEncoder = [self createRenderEncoderForDest:dest];
 384     [mtlEncoder setRenderPipelineState:[pipelineStateStorage getTexturePipelineState:NO compositeRule:alphaCompositeRule]];
 385     [self setEncoderTransform:mtlEncoder dest:dest];
 386     return mtlEncoder;
 387 }
 388 
 389 - (id<MTLBlitCommandEncoder>)createBlitEncoder {
 390     return _commandBuffer == nil ? nil : [_commandBuffer blitCommandEncoder];
 391 }
 392 
 393 - (void)dealloc {
 394     J2dTracePrimitive("MTLContext.dealloc");
 395     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.dealloc");
 396 
 397     self.texturePool = nil;
 398     self.library = nil;
 399     self.vertexBuffer = nil;
 400     self.commandQueue = nil;
 401     self.pipelineState = nil;
 402     self.pipelineStateStorage = nil;
 403     [super dealloc];
 404 }
 405 
 406 - (void)setGradientPaintUseMask:(jboolean)_useMask cyclic:(jboolean)_cyclic p0:(jdouble) _p0 p1:(jdouble)_p1
 407                              p3:(jdouble)_p3 pixel1:(jint)_pixel1 pixel2:(jint)_pixel2 {
 408 
 409     //TODO Resolve gradient distribution problem
 410     //TODO Implement useMask
 411     //TODO Implement cyclic
 412     //fprintf(stderr,
 413     //        "MTLPaints_SetGradientPaint useMask=%d cyclic=%d "
 414     //        "p0=%f p1=%f p3=%f pix1=%d pix2=%d\n", useMask, cyclic,
 415     //        p0, p1, p3, pixel1, pixel2);
 416     J2dTraceNotImplPrimitive("MTLContext.setGradientPaint");
 417 
 418     compState = sun_java2d_SunGraphics2D_PAINT_GRADIENT;
 419     useMask = _useMask;
 420     pixel1 = _pixel1;
 421     pixel2 = _pixel2;
 422     p0 = _p0;
 423     p1 = _p1;
 424     p3 = _p3;
 425     cyclic = _cyclic;
 426  }
 427 
 428 @end
 429 
 430 /*
 431  * Class:     sun_java2d_metal_MTLContext
 432  * Method:    getMTLIdString
 433  * Signature: ()Ljava/lang/String;
 434  */
 435 JNIEXPORT jstring JNICALL Java_sun_java2d_metal_MTLContext_getMTLIdString
 436   (JNIEnv *env, jclass mtlcc)
 437 {
 438     char *vendor, *renderer, *version;
 439     char *pAdapterId;
 440     jobject ret = NULL;
 441     int len;
 442 
 443     return NULL;
 444 }
 445 
 446 
 447 
 448 #endif /* !HEADLESS */