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 #import "MTLGraphicsConfig.h"
  27 #import "MTLLayer.h"
  28 #import "ThreadUtilities.h"
  29 #import "LWCToolkit.h"
  30 #import "MTLSurfaceData.h"
  31 
  32 #import "MTLBlitLoops.h"
  33 
  34 @implementation MTLLayer
  35 
  36 
  37 @synthesize javaLayer;
  38 @synthesize ctx;
  39 @synthesize bufferWidth;
  40 @synthesize bufferHeight;
  41 @synthesize buffer;
  42 
  43 - (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer
  44 {
  45     AWT_ASSERT_APPKIT_THREAD;
  46     // Initialize ourselves
  47     self = [super init];
  48     if (self == nil) return self;
  49 
  50     self.javaLayer = layer;
  51 
  52     self.contentsGravity = kCAGravityTopLeft;
  53 
  54     //Disable CALayer's default animation
  55     NSMutableDictionary * actions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  56                                     [NSNull null], @"anchorPoint",
  57                                     [NSNull null], @"bounds",
  58                                     [NSNull null], @"contents",
  59                                     [NSNull null], @"contentsScale",
  60                                     [NSNull null], @"onOrderIn",
  61                                     [NSNull null], @"onOrderOut",
  62                                     [NSNull null], @"position",
  63                                     [NSNull null], @"sublayers",
  64                                     nil];
  65     self.actions = actions;
  66     [actions release];
  67 
  68 
  69     return self;
  70 }
  71 
  72 - (void) blitTexture:(id<MTLCommandBuffer>)commandBuf {
  73     if (self.ctx == NULL || self.javaLayer == NULL || self.buffer == nil || ctx.device == nil) {
  74         J2dTraceLn4(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: uninitialized (mtlc=%p, javaLayer=%p, buffer=%p, devide=%p)", self.ctx, self.javaLayer, self.buffer, ctx->mtlDevice);
  75         return;
  76     }
  77 
  78     if (commandBuf == nil) {
  79         J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: nothing to do (commandBuf is null)");
  80         return;
  81     }
  82 
  83     @autoreleasepool {
  84         self.device = ctx.device;
  85         self.pixelFormat = MTLPixelFormatBGRA8Unorm;
  86         self.framebufferOnly = NO;
  87 
  88         self.drawableSize =
  89             CGSizeMake(self.buffer.width,
  90                        self.buffer.height);
  91 
  92         id<CAMetalDrawable> mtlDrawable = [self nextDrawable];
  93         if (mtlDrawable == nil) {
  94             return;
  95         }
  96         J2dTraceLn6(J2D_TRACE_INFO, "MTLLayer.blitTexture: src tex=%p (w=%d, h=%d), dst tex=%p (w=%d, h=%d)", self.buffer, self.buffer.width, self.buffer.height, mtlDrawable.texture, mtlDrawable.texture.width, mtlDrawable.texture.height);
  97         id <MTLBlitCommandEncoder> blitEncoder = [commandBuf blitCommandEncoder];
  98         [blitEncoder
  99                 copyFromTexture:self.buffer sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(self.buffer.width, self.buffer.height, 1)
 100                 toTexture:mtlDrawable.texture destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)];
 101         [blitEncoder endEncoding];
 102 
 103         [commandBuf presentDrawable:mtlDrawable];
 104 
 105         [commandBuf addCompletedHandler:^(id <MTLCommandBuffer> cmdBuff) {
 106                 [cmdBuff release];
 107                 [ctx.texturePool markAllTexturesFree];
 108         }];
 109 
 110         [commandBuf commit];
 111     }
 112 }
 113 
 114 - (void) dealloc {
 115     self.javaLayer = nil;
 116     [super dealloc];
 117 }
 118 
 119 @end
 120 
 121 /*
 122  * Class:     sun_java2d_metal_CGLLayer
 123  * Method:    nativeCreateLayer
 124  * Signature: ()J
 125  */
 126 JNIEXPORT jlong JNICALL
 127 Java_sun_java2d_metal_MTLLayer_nativeCreateLayer
 128 (JNIEnv *env, jobject obj)
 129 {
 130     __block MTLLayer *layer = nil;
 131 
 132 JNF_COCOA_ENTER(env);
 133 
 134     JNFWeakJObjectWrapper *javaLayer = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
 135 
 136     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 137             AWT_ASSERT_APPKIT_THREAD;
 138         
 139             layer = [[MTLLayer alloc] initWithJavaLayer: javaLayer];
 140     }];
 141     
 142 JNF_COCOA_EXIT(env);
 143 
 144     return ptr_to_jlong(layer);
 145 }
 146 
 147 // Must be called under the RQ lock.
 148 JNIEXPORT void JNICALL
 149 Java_sun_java2d_metal_MTLLayer_validate
 150 (JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData)
 151 {
 152     MTLLayer *layer = OBJC(layerPtr);
 153 
 154     if (surfaceData != NULL) {
 155         BMTLSDOps *bmtlsdo = (BMTLSDOps*) SurfaceData_GetOps(env, surfaceData);
 156         layer.bufferWidth = bmtlsdo->width;
 157         layer.bufferHeight = bmtlsdo->width;
 158         layer.buffer = bmtlsdo->pTexture;
 159         layer.ctx = ((MTLSDOps *)bmtlsdo->privOps)->configInfo->context;
 160         layer.device = layer.ctx.device;
 161     } else {
 162         layer.ctx = NULL;
 163     }
 164 }
 165 
 166 JNIEXPORT void JNICALL
 167 Java_sun_java2d_metal_MTLLayer_nativeSetScale
 168 (JNIEnv *env, jclass cls, jlong layerPtr, jdouble scale)
 169 {
 170     JNF_COCOA_ENTER(env);
 171     MTLLayer *layer = jlong_to_ptr(layerPtr);
 172     // We always call all setXX methods asynchronously, exception is only in 
 173     // this method where we need to change native texture size and layer's scale
 174     // in one call on appkit, otherwise we'll get window's contents blinking, 
 175     // during screen-2-screen moving.
 176     [ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){
 177         layer.contentsScale = scale;
 178     }];
 179     JNF_COCOA_EXIT(env);
 180 }