1 /* 2 * Copyright (c) 2019, 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 "MetalGraphicsConfig.h" 27 #import "MetalLayer.h" 28 #import "shaders/MetalShaderTypes.h" 29 #import "ThreadUtilities.h" 30 #import "LWCToolkit.h" 31 #import "MetalSurfaceData.h" 32 #import "VertexDataManager.h" 33 34 35 //extern NSOpenGLPixelFormat *sharedPixelFormat; 36 //extern NSOpenGLContext *sharedContext; 37 38 @implementation MetalLayer 39 40 @synthesize javaLayer; 41 @synthesize mtlTexture; 42 //@synthesize target; 43 @synthesize textureWidth; 44 @synthesize textureHeight; 45 @synthesize mtlLibrary; 46 @synthesize mtlRenderPipelineDescriptor; 47 @synthesize renderPipelineState; 48 //@synthesize LineVertexBuffer; 49 //@synthesize QuadVertexBuffer; 50 #ifdef REMOTELAYER 51 //@synthesize parentLayer; 52 //@synthesize remoteLayer; 53 //@synthesize jrsRemoteLayer; 54 #endif 55 56 - (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer; 57 { 58 AWT_ASSERT_APPKIT_THREAD; 59 // Initialize ourselves 60 self = [super init]; 61 if (self == nil) return self; 62 63 self.javaLayer = layer; 64 65 // NOTE: async=YES means that the layer is re-cached periodically 66 //self.displaySyncEnabled = NO; 67 self.contentsGravity = kCAGravityTopLeft; 68 //Layer backed view 69 //self.needsDisplayOnBoundsChange = YES; 70 //self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; 71 72 //fprintf(stdout, "MetalLayer_initWithJavaLayer\n");fflush(stdout); 73 //Disable CALayer's default animation 74 NSMutableDictionary * actions = [[NSMutableDictionary alloc] initWithObjectsAndKeys: 75 [NSNull null], @"anchorPoint", 76 [NSNull null], @"bounds", 77 [NSNull null], @"contents", 78 [NSNull null], @"contentsScale", 79 [NSNull null], @"onOrderIn", 80 [NSNull null], @"onOrderOut", 81 [NSNull null], @"position", 82 [NSNull null], @"sublayers", 83 nil]; 84 self.actions = actions; 85 [actions release]; 86 87 //textureID = 0; // texture will be created by rendering pipe 88 mtlTexture = NULL; 89 //target = 0; 90 91 return self; 92 } 93 94 - (void) dealloc { 95 self.javaLayer = nil; 96 [super dealloc]; 97 98 VertexDataManager_freeAllPrimitives(); 99 } 100 101 /* 102 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { 103 return CGLRetainPixelFormat(sharedPixelFormat.CGLPixelFormatObj); 104 } 105 106 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { 107 CGLContextObj contextObj = NULL; 108 CGLCreateContext(pixelFormat, sharedContext.CGLContextObj, &contextObj); 109 return contextObj; 110 }*/ 111 112 // use texture (intermediate buffer) as src and blit it to the layer 113 /*- (void) blitTexture 114 { 115 if (textureID == 0) { 116 return; 117 } 118 119 glEnable(target); 120 glBindTexture(target, textureID); 121 122 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // srccopy 123 124 float swid = 1.0f, shgt = 1.0f; 125 if (target == GL_TEXTURE_RECTANGLE_ARB) { 126 swid = textureWidth; 127 shgt = textureHeight; 128 } 129 glBegin(GL_QUADS); 130 glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); 131 glTexCoord2f(swid, 0.0f); glVertex2f( 1.0f, -1.0f); 132 glTexCoord2f(swid, shgt); glVertex2f( 1.0f, 1.0f); 133 glTexCoord2f(0.0f, shgt); glVertex2f(-1.0f, 1.0f); 134 glEnd(); 135 136 glBindTexture(target, 0); 137 glDisable(target); 138 }*/ 139 140 /*-(BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp{ 141 return textureID == 0 ? NO : YES; 142 } 143 144 -(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp 145 { 146 AWT_ASSERT_APPKIT_THREAD; 147 148 JNIEnv *env = [ThreadUtilities getJNIEnv]; 149 static JNF_CLASS_CACHE(jc_JavaLayer, "sun/java2d/opengl/CGLLayer"); 150 static JNF_MEMBER_CACHE(jm_drawInCGLContext, jc_JavaLayer, "drawInCGLContext", "()V"); 151 152 jobject javaLayerLocalRef = [self.javaLayer jObjectWithEnv:env]; 153 if ((*env)->IsSameObject(env, javaLayerLocalRef, NULL)) { 154 return; 155 } 156 157 // Set the current context to the one given to us. 158 CGLSetCurrentContext(glContext); 159 160 // Should clear the whole CALayer, because it can be larger than our texture. 161 glClearColor(0.0, 0.0, 0.0, 0.0); 162 glClear(GL_COLOR_BUFFER_BIT); 163 164 glViewport(0, 0, textureWidth, textureHeight); 165 166 JNFCallVoidMethod(env, javaLayerLocalRef, jm_drawInCGLContext); 167 (*env)->DeleteLocalRef(env, javaLayerLocalRef); 168 169 // Call super to finalize the drawing. By default all it does is call glFlush(). 170 [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; 171 172 CGLSetCurrentContext(NULL); 173 }*/ 174 175 @end 176 177 178 179 static jlong cachedLayer = 0; 180 static float drawColor[4] = {0.0, 0.0, 0.0, 0.0}; 181 /* 182 * Class: sun_java2d_metal_MetalLayer 183 * Method: nativeCreateLayer 184 * Signature: ()J 185 */ 186 JNIEXPORT jlong JNICALL 187 Java_sun_java2d_metal_MetalLayer_nativeCreateLayer 188 (JNIEnv *env, jobject obj) 189 { 190 __block MetalLayer *layer = nil; 191 192 //fprintf(stdout, "MetalLayer_nativeCreateLayer\n");fflush(stdout); 193 JNF_COCOA_ENTER(env); 194 195 JNFWeakJObjectWrapper *javaLayer = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env]; 196 197 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 198 AWT_ASSERT_APPKIT_THREAD; 199 200 layer = [[MetalLayer alloc] initWithJavaLayer: javaLayer]; 201 202 //cachedLayer = ptr_to_jlong(layer); 203 }]; 204 205 JNF_COCOA_EXIT(env); 206 207 return ptr_to_jlong(layer); 208 } 209 210 211 212 JNIEXPORT jlong JNICALL 213 Java_sun_java2d_metal_MetalLayer_nativeInitLayer 214 (JNIEnv *env, jobject obj, jlong configInfo, jlong layer) 215 { 216 217 JNF_COCOA_ENTER(env); 218 MetalGraphicsConfigInfo *pInfo = 219 (MetalGraphicsConfigInfo *)jlong_to_ptr(configInfo); 220 if ((pInfo == NULL)) { 221 return -1; 222 } 223 224 MetalLayer *mtlLayer = jlong_to_ptr(layer); 225 226 mtlLayer.device = pInfo->device; 227 mtlLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; 228 229 //mtlLayer.commandQueue = pInfo->commandQueue; 230 231 // ------------------------------------------------------------------------------------------------ 232 // TODO : Currently we manually compile and copy the shader library to /tmp. 233 // Need to complete build changes - to build it and read from some other location within jdk 234 // ------------------------------------------------------------------------------------------------ 235 // Load shader library 236 /*NSError *error = nil; 237 mtlLayer.mtlLibrary = [mtlLayer.device newLibraryWithFile: @"/tmp/BaseShader.metallib" error:&error]; 238 if (!mtlLayer.mtlLibrary) { 239 NSLog(@"Failed to load library. error %@", error); 240 //exit(0); 241 }*/ 242 243 NSError* error = nil; 244 NSString* content = @"#include <metal_stdlib>\n" 245 "#include <simd/simd.h>\n" 246 "using namespace metal;\n" 247 "struct MetalVertex" 248 "{" 249 "vector_float4 position;" 250 "vector_float4 color;" 251 "};\n" 252 "struct VertexOut {" 253 "float4 color;" 254 "float4 pos [[position]];" 255 "};\n" 256 "vertex VertexOut vertexShader(device MetalVertex *vertices [[buffer(0)]]," 257 "constant unsigned int *viewportSize [[buffer(1)]]," 258 "uint vid [[vertex_id]]) {\n" 259 "VertexOut out;" 260 "out.pos = vertices[vid].position;" 261 "\n" 262 "float halfViewWidth = (float)(viewportSize[0] >> 1);" 263 "float halfViewHeight = (float)(viewportSize[1] >> 1);" 264 "\n" 265 "out.pos.x = (out.pos.x - halfViewWidth) / halfViewWidth;" 266 "out.pos.y = (halfViewHeight - out.pos.y) / halfViewHeight;" 267 "\n" 268 "out.color = vertices[vid].color;" 269 "\n" 270 "return out;" 271 "}\n" 272 "fragment float4 fragmentShader(MetalVertex in [[stage_in]]) {" 273 "return in.color;" 274 "}"; 275 276 mtlLayer.mtlLibrary = [mtlLayer.device newLibraryWithSource:content options:nil error:&error]; 277 if (!mtlLayer.mtlLibrary) { 278 NSLog(@"Failed to create shader library from source. error %@", error); 279 //exit(0); 280 } 281 282 //create a vertex and fragment objects 283 id<MTLFunction> vertexProgram = [mtlLayer.mtlLibrary newFunctionWithName:@"vertexShader"]; 284 id<MTLFunction> fragmentProgram = [mtlLayer.mtlLibrary newFunctionWithName:@"fragmentShader"]; 285 286 287 mtlLayer.mtlRenderPipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; 288 289 [mtlLayer.mtlRenderPipelineDescriptor setVertexFunction:vertexProgram]; 290 [mtlLayer.mtlRenderPipelineDescriptor setFragmentFunction:fragmentProgram]; 291 292 //specify the target-texture pixel format 293 mtlLayer.mtlRenderPipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm; 294 295 //create the Rendering Pipeline Object 296 mtlLayer.renderPipelineState = [mtlLayer.device newRenderPipelineStateWithDescriptor:mtlLayer.mtlRenderPipelineDescriptor error:nil]; 297 298 VertexDataManager_init(mtlLayer.device); 299 300 301 JNF_COCOA_EXIT(env); 302 303 return ptr_to_jlong(layer); 304 } 305 306 307 308 // Must be called under the RQ lock. 309 /*JNIEXPORT void JNICALL 310 Java_sun_java2d_metal_MetalLayer_nativeValidate 311 (JNIEnv *env, jclass cls, jlong layer, jlong view) 312 { 313 314 JNF_COCOA_ENTER(env); 315 316 MetalLayer *mtlLayer = jlong_to_ptr(layer); 317 NSView *nsView = jlong_to_ptr(view); 318 319 mtlLayer.frame = nsView.bounds; 320 [mtlLayer setDrawableSize: nsView.bounds.size]; 321 322 mtlLayer.textureWidth = nsView.bounds.size.width; 323 mtlLayer.textureHeight = nsView.bounds.size.height; 324 325 NSLog(@"Validate : Width : %f", nsView.bounds.size.width); 326 NSLog(@"Validate : Height : %f", nsView.bounds.size.height); 327 328 JNF_COCOA_EXIT(env); 329 }*/ 330 331 // Must be called under the RQ lock. 332 JNIEXPORT void JNICALL 333 Java_sun_java2d_metal_MetalLayer_validate 334 (JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData) 335 { 336 MetalLayer *layer = OBJC(layerPtr); 337 //fprintf(stdout, "MetalLayer_validate\n");fflush(stdout); 338 if (surfaceData != NULL) { 339 MetalSDOps *metalsdo = (MetalSDOps*) SurfaceData_GetOps(env, surfaceData); 340 // TODO : Check whether we have to use pointer or instance variable 341 //fprintf(stdout, "MetalLayer_validate replace mtlTexture\n");fflush(stdout); 342 layer.mtlTexture = metalsdo->mtlTexture; 343 //layer.target = GL_TEXTURE_2D; 344 layer.textureWidth = metalsdo->width; 345 layer.textureHeight = metalsdo->height; 346 347 VertexDataManager_reset(metalsdo->configInfo->device); 348 349 NSLog(@"Validate : Width : %f", layer.textureWidth); 350 NSLog(@"Validate : height : %f", layer.textureHeight); 351 352 } else { 353 //fprintf(stdout, "MetalLayer_validate Null SD \n");fflush(stdout); 354 //layer.textureID = 0; 355 } 356 } 357 358 359 360 /* 361 // Must be called on the AppKit thread and under the RQ lock. 362 JNIEXPORT void JNICALL 363 Java_sun_java2d_opengl_CGLLayer_blitTexture 364 (JNIEnv *env, jclass cls, jlong layerPtr) 365 { 366 CGLLayer *layer = jlong_to_ptr(layerPtr); 367 368 [layer blitTexture]; 369 }*/ 370 371 JNIEXPORT void JNICALL 372 Java_sun_java2d_metal_MetalLayer_nativeSetScale 373 (JNIEnv *env, jclass cls, jlong layerPtr, jdouble scale) 374 { 375 JNF_COCOA_ENTER(env); 376 MetalLayer *layer = jlong_to_ptr(layerPtr); 377 // We always call all setXX methods asynchronously, exception is only in 378 // this method where we need to change native texture size and layer's scale 379 // in one call on appkit, otherwise we'll get window's contents blinking, 380 // during screen-2-screen moving. 381 [ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){ 382 layer.contentsScale = scale; 383 }]; 384 JNF_COCOA_EXIT(env); 385 }