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 @synthesize mtlDrawable; 43 @synthesize blitCommandBuf; 44 @synthesize blitEncoder; 45 @synthesize topInset; 46 @synthesize leftInset; 47 48 - (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer 49 { 50 AWT_ASSERT_APPKIT_THREAD; 51 // Initialize ourselves 52 self = [super init]; 53 if (self == nil) return self; 54 55 self.javaLayer = layer; 56 57 self.contentsGravity = kCAGravityTopLeft; 58 59 //Disable CALayer's default animation 60 NSMutableDictionary * actions = [[NSMutableDictionary alloc] initWithObjectsAndKeys: 61 [NSNull null], @"anchorPoint", 62 [NSNull null], @"bounds", 63 [NSNull null], @"contents", 64 [NSNull null], @"contentsScale", 65 [NSNull null], @"onOrderIn", 66 [NSNull null], @"onOrderOut", 67 [NSNull null], @"position", 68 [NSNull null], @"sublayers", 69 nil]; 70 self.actions = actions; 71 [actions release]; 72 self.topInset = 0; 73 self.leftInset = 0; 74 self.framebufferOnly = NO; 75 return self; 76 } 77 78 - (void) blitTexture { 79 @autoreleasepool { 80 [self.blitEncoder 81 copyFromTexture:self.buffer sourceSlice:0 sourceLevel:0 82 sourceOrigin:MTLOriginMake((jint)(self.leftInset*self.contentsScale), (jint)(self.topInset*self.contentsScale), 0) 83 sourceSize:MTLSizeMake(self.buffer.width, self.buffer.height, 1) 84 toTexture:self.mtlDrawable.texture destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)]; 85 [self.blitEncoder endEncoding]; 86 87 [self.blitCommandBuf presentDrawable:self.mtlDrawable]; 88 89 [self.blitCommandBuf commit]; 90 } 91 } 92 93 - (void) dealloc { 94 self.javaLayer = nil; 95 [super dealloc]; 96 } 97 98 - (void) blitCallback { 99 100 JNIEnv *env = [ThreadUtilities getJNIEnv]; 101 static JNF_CLASS_CACHE(jc_JavaLayer, "sun/java2d/metal/MTLLayer"); 102 static JNF_MEMBER_CACHE(jm_drawInMTLContext, jc_JavaLayer, "drawInMTLContext", "()V"); 103 104 jobject javaLayerLocalRef = [self.javaLayer jObjectWithEnv:env]; 105 if ((*env)->IsSameObject(env, javaLayerLocalRef, NULL)) { 106 return; 107 } 108 109 JNFCallVoidMethod(env, javaLayerLocalRef, jm_drawInMTLContext); 110 (*env)->DeleteLocalRef(env, javaLayerLocalRef); 111 } 112 113 - (void) initBlit { 114 if (self.ctx == NULL || self.javaLayer == NULL || self.buffer == nil || self.ctx.device == nil) { 115 J2dTraceLn4(J2D_TRACE_VERBOSE, "MTLLayer.initBlit: uninitialized (mtlc=%p, javaLayer=%p, buffer=%p, devide=%p)", self.ctx, self.javaLayer, self.buffer, ctx.device); 116 return; 117 } 118 119 if ((self.buffer.width == 0) || (self.buffer.height == 0)) { 120 J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.initBlit: cannot create drawable of size 0"); 121 return; 122 } 123 self.blitCommandBuf = [self.ctx createBlitCommandBuffer]; 124 if (self.blitCommandBuf == nil) { 125 J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.initBlit: nothing to do (commandBuf is null)"); 126 return; 127 } 128 129 self.blitEncoder = [self.blitCommandBuf blitCommandEncoder]; 130 if (self.blitEncoder == nil) { 131 J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.initBlit: blitEncoder is null)"); 132 return; 133 } 134 135 self.mtlDrawable = [self nextDrawable]; 136 if (self.mtlDrawable == nil) { 137 J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.initBlit: nextDrawable is null)"); 138 return; 139 } 140 J2dTraceLn6(J2D_TRACE_VERBOSE, "MTLLayer.initBlit: src tex=%p (w=%d, h=%d), dst tex=%p (w=%d, h=%d)", self.buffer, self.buffer.width, self.buffer.height, self.mtlDrawable.texture, self.mtlDrawable.texture.width, self.mtlDrawable.texture.height); 141 } 142 143 - (void) display { 144 AWT_ASSERT_APPKIT_THREAD; 145 J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_display() called"); 146 [self initBlit]; 147 [self blitCallback]; 148 [super display]; 149 } 150 @end 151 152 /* 153 * Class: sun_java2d_metal_MTLLayer 154 * Method: nativeCreateLayer 155 * Signature: ()J 156 */ 157 JNIEXPORT jlong JNICALL 158 Java_sun_java2d_metal_MTLLayer_nativeCreateLayer 159 (JNIEnv *env, jobject obj) 160 { 161 __block MTLLayer *layer = nil; 162 163 JNF_COCOA_ENTER(env); 164 165 JNFWeakJObjectWrapper *javaLayer = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env]; 166 167 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 168 AWT_ASSERT_APPKIT_THREAD; 169 170 layer = [[MTLLayer alloc] initWithJavaLayer: javaLayer]; 171 }]; 172 173 JNF_COCOA_EXIT(env); 174 175 return ptr_to_jlong(layer); 176 } 177 178 // Must be called under the RQ lock. 179 JNIEXPORT void JNICALL 180 Java_sun_java2d_metal_MTLLayer_validate 181 (JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData) 182 { 183 MTLLayer *layer = OBJC(layerPtr); 184 185 if (surfaceData != NULL) { 186 BMTLSDOps *bmtlsdo = (BMTLSDOps*) SurfaceData_GetOps(env, surfaceData); 187 layer.bufferWidth = bmtlsdo->width; 188 layer.bufferHeight = bmtlsdo->width; 189 layer.buffer = bmtlsdo->pTexture; 190 layer.ctx = ((MTLSDOps *)bmtlsdo->privOps)->configInfo->context; 191 layer.device = layer.ctx.device; 192 layer.pixelFormat = MTLPixelFormatBGRA8Unorm; 193 layer.drawableSize = 194 CGSizeMake(layer.buffer.width, 195 layer.buffer.height); 196 } else { 197 layer.ctx = NULL; 198 } 199 } 200 201 JNIEXPORT void JNICALL 202 Java_sun_java2d_metal_MTLLayer_nativeSetScale 203 (JNIEnv *env, jclass cls, jlong layerPtr, jdouble scale) 204 { 205 JNF_COCOA_ENTER(env); 206 MTLLayer *layer = jlong_to_ptr(layerPtr); 207 // We always call all setXX methods asynchronously, exception is only in 208 // this method where we need to change native texture size and layer's scale 209 // in one call on appkit, otherwise we'll get window's contents blinking, 210 // during screen-2-screen moving. 211 [ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){ 212 layer.contentsScale = scale; 213 }]; 214 JNF_COCOA_EXIT(env); 215 } 216 217 JNIEXPORT void JNICALL 218 Java_sun_java2d_metal_MTLLayer_nativeSetInsets 219 (JNIEnv *env, jclass cls, jlong layerPtr, jint top, jint left) 220 { 221 MTLLayer *layer = jlong_to_ptr(layerPtr); 222 layer.topInset = top; 223 layer.leftInset = left; 224 } 225 226 JNIEXPORT void JNICALL 227 Java_sun_java2d_metal_MTLLayer_blitTexture 228 (JNIEnv *env, jclass cls, jlong layerPtr) 229 { 230 J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_blitTexture"); 231 MTLLayer *layer = jlong_to_ptr(layerPtr); 232 MTLContext * ctx = layer.ctx; 233 if (layer == NULL || ctx == NULL) { 234 J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_blit : Layer or Context is null"); 235 return; 236 } 237 238 [layer blitTexture]; 239 }