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 
  33 @implementation MTLLayer
  34 
  35 
  36 @synthesize javaLayer;
  37 @synthesize ctx;
  38 @synthesize bufferWidth;
  39 @synthesize bufferHeight;
  40 
  41 - (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer
  42 {
  43     AWT_ASSERT_APPKIT_THREAD;
  44     // Initialize ourselves
  45     self = [super init];
  46     if (self == nil) return self;
  47 
  48     self.javaLayer = layer;
  49 
  50     self.contentsGravity = kCAGravityTopLeft;
  51 
  52     //Disable CALayer's default animation
  53     NSMutableDictionary * actions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  54                                     [NSNull null], @"anchorPoint",
  55                                     [NSNull null], @"bounds",
  56                                     [NSNull null], @"contents",
  57                                     [NSNull null], @"contentsScale",
  58                                     [NSNull null], @"onOrderIn",
  59                                     [NSNull null], @"onOrderOut",
  60                                     [NSNull null], @"position",
  61                                     [NSNull null], @"sublayers",
  62                                     nil];
  63     self.actions = actions;
  64     [actions release];
  65 
  66 
  67     return self;
  68 }
  69 
  70 - (void) blitTexture {
  71     if (self.ctx == NULL || self.javaLayer == NULL) {
  72         return;
  73     }
  74 
  75     @autoreleasepool {
  76         if (ctx->mtlCommandBuffer && ctx->mtlDevice) {
  77             self.device = ctx->mtlDevice;
  78             self.pixelFormat = MTLPixelFormatBGRA8Unorm;
  79             self.framebufferOnly = NO;
  80 
  81             self.drawableSize =
  82                 CGSizeMake(ctx->mtlFrameBuffer.width,
  83                            ctx->mtlFrameBuffer.height);
  84 
  85             id<CAMetalDrawable> mtlDrawable = [self nextDrawable];
  86             if (mtlDrawable == nil) {
  87                 [ctx->mtlCommandBuffer release];
  88                 ctx->mtlCommandBuffer = nil;
  89                 ctx->mtlEmptyCommandBuffer = YES;
  90                 if (ctx->mtlRenderPassDesc) {
  91                     [ctx->mtlRenderPassDesc release];
  92                     ctx->mtlRenderPassDesc = nil;
  93                 }
  94                 return;
  95             }
  96 
  97             if (!ctx->mtlRenderPassDesc) {
  98                 ctx->mtlRenderPassDesc = [[MTLRenderPassDescriptor renderPassDescriptor] retain];
  99             }
 100             MTLRenderPassColorAttachmentDescriptor *colorAttachment = ctx->mtlRenderPassDesc.colorAttachments[0];
 101 
 102             colorAttachment.texture = mtlDrawable.texture;
 103 
 104             colorAttachment.loadAction = MTLLoadActionLoad;
 105             colorAttachment.clearColor = MTLClearColorMake(0.0f, 0.0f, 0.0f, 1.0f);
 106 
 107             colorAttachment.storeAction = MTLStoreActionStore;
 108 
 109             id<MTLRenderCommandEncoder>  mtlEncoder =
 110                 [ctx->mtlCommandBuffer renderCommandEncoderWithDescriptor:ctx->mtlRenderPassDesc];
 111             MTLViewport vp = {0, 0, ctx->mtlFrameBuffer.width, ctx->mtlFrameBuffer.height, 0, 1};
 112 
 113             [mtlEncoder setViewport:vp];
 114             [mtlEncoder setRenderPipelineState:ctx->mtlBlitPipelineState];
 115             [mtlEncoder setFragmentTexture: ctx->mtlFrameBuffer atIndex: 0];
 116             [mtlEncoder setVertexBuffer:ctx->mtlVertexBuffer offset:0 atIndex:MeshVertexBuffer];
 117             [mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:PGRAM_VERTEX_COUNT];
 118             [mtlEncoder endEncoding];
 119 
 120 
 121             if (!ctx->mtlEmptyCommandBuffer) {
 122                 [ctx->mtlCommandBuffer presentDrawable:mtlDrawable];
 123                 [ctx->mtlCommandBuffer commit];
 124             }
 125 
 126             [ctx->mtlRenderPassDesc release];
 127             ctx->mtlRenderPassDesc = nil;
 128 
 129             [ctx->mtlCommandBuffer release];
 130             ctx->mtlCommandBuffer = nil;
 131             ctx->mtlEmptyCommandBuffer = YES;
 132         }
 133     }
 134 }
 135 
 136 - (void) dealloc {
 137     self.javaLayer = nil;
 138     [super dealloc];
 139 }
 140 
 141 @end
 142 
 143 /*
 144  * Class:     sun_java2d_metal_CGLLayer
 145  * Method:    nativeCreateLayer
 146  * Signature: ()J
 147  */
 148 JNIEXPORT jlong JNICALL
 149 Java_sun_java2d_metal_MTLLayer_nativeCreateLayer
 150 (JNIEnv *env, jobject obj)
 151 {
 152     __block MTLLayer *layer = nil;
 153 
 154 JNF_COCOA_ENTER(env);
 155 
 156     JNFWeakJObjectWrapper *javaLayer = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
 157 
 158     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 159             AWT_ASSERT_APPKIT_THREAD;
 160         
 161             layer = [[MTLLayer alloc] initWithJavaLayer: javaLayer];
 162     }];
 163     
 164 JNF_COCOA_EXIT(env);
 165 
 166     return ptr_to_jlong(layer);
 167 }
 168 
 169 // Must be called under the RQ lock.
 170 JNIEXPORT void JNICALL
 171 Java_sun_java2d_metal_MTLLayer_validate
 172 (JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData)
 173 {
 174     MTLLayer *layer = OBJC(layerPtr);
 175 
 176     if (surfaceData != NULL) {
 177         BMTLSDOps *bmtlsdo = (BMTLSDOps*) SurfaceData_GetOps(env, surfaceData);
 178         layer.bufferWidth = bmtlsdo->width;
 179         layer.bufferHeight = bmtlsdo->height;
 180         layer.ctx = ((MTLSDOps *)bmtlsdo->privOps)->configInfo->context;
 181         layer.device = layer.ctx->mtlDevice;
 182     } else {
 183         layer.ctx = NULL;
 184     }
 185 }
 186 
 187 // Must be called on the AppKit thread and under the RQ lock.
 188 JNIEXPORT void JNICALL
 189 Java_sun_java2d_metal_MTLLayer_blitTexture
 190 (JNIEnv *env, jclass cls, jlong layerPtr)
 191 {
 192     MTLLayer *layer = jlong_to_ptr(layerPtr);
 193     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 194         [layer blitTexture];
 195     }];
 196 }
 197 
 198 JNIEXPORT void JNICALL
 199 Java_sun_java2d_metal_MTLLayer_nativeSetScale
 200 (JNIEnv *env, jclass cls, jlong layerPtr, jdouble scale)
 201 {
 202     JNF_COCOA_ENTER(env);
 203     MTLLayer *layer = jlong_to_ptr(layerPtr);
 204     // We always call all setXX methods asynchronously, exception is only in 
 205     // this method where we need to change native texture size and layer's scale
 206     // in one call on appkit, otherwise we'll get window's contents blinking, 
 207     // during screen-2-screen moving.
 208     [ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){
 209         layer.contentsScale = scale;
 210     }];
 211     JNF_COCOA_EXIT(env);
 212 }