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 "sun_java2d_metal_MTLGraphicsConfig.h"
  27 
  28 #import "MTLGraphicsConfig.h"
  29 #import "MTLSurfaceData.h"
  30 #import "ThreadUtilities.h"
  31 
  32 #import <stdlib.h>
  33 #import <string.h>
  34 #import <ApplicationServices/ApplicationServices.h>
  35 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  36 
  37 #pragma mark -
  38 #pragma mark "--- Mac OS X specific methods for GL pipeline ---"
  39 
  40 /**
  41  * Disposes all memory and resources associated with the given
  42  * CGLGraphicsConfigInfo (including its native MTLContext data).
  43  */
  44 void
  45 MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo)
  46 {
  47     J2dTraceLn(J2D_TRACE_INFO, "MTLGC_DestroyMTLGraphicsConfig");
  48 
  49     MTLGraphicsConfigInfo *mtlinfo =
  50         (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
  51     if (mtlinfo == NULL) {
  52         J2dRlsTraceLn(J2D_TRACE_ERROR,
  53                       "MTLGC_DestroyMTLGraphicsConfig: info is null");
  54         return;
  55     }
  56 
  57     MTLContext *mtlc = (MTLContext*)mtlinfo->context;
  58     if (mtlc != NULL) {
  59         MTLContext_DestroyContextResources(mtlc);
  60         mtlinfo->context = NULL;
  61     }
  62     free(mtlinfo);
  63 }
  64 
  65 #pragma mark -
  66 #pragma mark "--- MTLGraphicsConfig methods ---"
  67 
  68 
  69 /**
  70  * Attempts to initialize CGL and the core OpenGL library.
  71  */
  72 JNIEXPORT jboolean JNICALL
  73 Java_sun_java2d_metal_MTLGraphicsConfig_initMTL
  74     (JNIEnv *env, jclass cglgc)
  75 {
  76     J2dRlsTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_initMTL");
  77 
  78     if (!MTLFuncs_OpenLibrary()) {
  79         return JNI_FALSE;
  80     }
  81 
  82     if (!MTLFuncs_InitPlatformFuncs() ||
  83         !MTLFuncs_InitBaseFuncs() ||
  84         !MTLFuncs_InitExtFuncs())
  85     {
  86         MTLFuncs_CloseLibrary();
  87         return JNI_FALSE;
  88     }
  89 
  90     return JNI_TRUE;
  91 }
  92 
  93 
  94 /**
  95  * Determines whether the CGL pipeline can be used for a given GraphicsConfig
  96  * provided its screen number and visual ID.  If the minimum requirements are
  97  * met, the native CGLGraphicsConfigInfo structure is initialized for this
  98  * GraphicsConfig with the necessary information (pixel format, etc.)
  99  * and a pointer to this structure is returned as a jlong.  If
 100  * initialization fails at any point, zero is returned, indicating that CGL
 101  * cannot be used for this GraphicsConfig (we should fallback on an existing
 102  * 2D pipeline).
 103  */
 104 JNIEXPORT jlong JNICALL
 105 Java_sun_java2d_metal_MTLGraphicsConfig_getMTLConfigInfo
 106     (JNIEnv *env, jclass cglgc, jint displayID, jstring mtlShadersLib)
 107 {
 108   jlong ret = 0L;
 109   JNF_COCOA_ENTER(env);
 110   NSMutableArray * retArray = [NSMutableArray arrayWithCapacity:3];
 111   [retArray addObject: [NSNumber numberWithInt: (int)displayID]];
 112   [retArray addObject: [NSString stringWithUTF8String: JNU_GetStringPlatformChars(env, mtlShadersLib, 0)]];
 113   if ([NSThread isMainThread]) {
 114       [MTLGraphicsConfigUtil _getMTLConfigInfo: retArray];
 115   } else {
 116       [MTLGraphicsConfigUtil performSelectorOnMainThread: @selector(_getMTLConfigInfo:) withObject: retArray waitUntilDone: YES];
 117   }
 118   NSNumber * num = (NSNumber *)[retArray objectAtIndex: 0];
 119   ret = (jlong)[num longValue];
 120   JNF_COCOA_EXIT(env);
 121   return ret;
 122 }
 123 
 124 
 125 static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
 126     {{-1.0, 1.0, 0.0}, {0.0, 0.0}},
 127     {{1.0, 1.0, 0.0}, {1.0, 0.0}},
 128     {{1.0, -1.0, 0.0}, {1.0, 1.0}},
 129     {{1.0, -1.0, 0.0}, {1.0, 1.0}},
 130     {{-1.0, -1.0, 0.0}, {0.0, 1.0}},
 131     {{-1.0, 1.0, 0.0}, {0.0, 0.0}}
 132 };
 133 
 134 
 135 @implementation MTLGraphicsConfigUtil
 136 + (void) _getMTLConfigInfo: (NSMutableArray *)argValue {
 137     AWT_ASSERT_APPKIT_THREAD;
 138 
 139     jint displayID = (jint)[(NSNumber *)[argValue objectAtIndex: 0] intValue];
 140     NSString *mtlShadersLib = (NSString *)[argValue objectAtIndex: 1];
 141     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 142     [argValue removeAllObjects];
 143 
 144     J2dRlsTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_getMTLConfigInfo");
 145 
 146     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
 147 
 148 
 149     NSRect contentRect = NSMakeRect(0, 0, 64, 64);
 150     NSWindow *window =
 151         [[NSWindow alloc]
 152             initWithContentRect: contentRect
 153             styleMask: NSBorderlessWindowMask
 154             backing: NSBackingStoreBuffered
 155             defer: false];
 156     if (window == nil) {
 157         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: NSWindow is NULL");
 158         [argValue addObject: [NSNumber numberWithLong: 0L]];
 159         return;
 160     }
 161 
 162     NSView *scratchSurface =
 163         [[NSView alloc]
 164             initWithFrame: contentRect];
 165     if (scratchSurface == nil) {
 166         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: NSView is NULL");
 167         [argValue addObject: [NSNumber numberWithLong: 0L]];
 168         return;
 169     }
 170     [window setContentView: scratchSurface];
 171 
 172     MTLContext *mtlc = (MTLContext *)malloc(sizeof(MTLContext));
 173     if (mtlc == 0L) {
 174         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGC_InitMTLContext: could not allocate memory for mtlc");
 175         [argValue addObject: [NSNumber numberWithLong: 0L]];
 176         return;
 177     }
 178     memset(mtlc, 0, sizeof(MTLContext));
 179 
 180 
 181     mtlc->mtlDevice = [CGDirectDisplayCopyCurrentMetalDevice(displayID) retain];
 182 
 183     mtlc->mtlVertexBuffer = [[mtlc->mtlDevice  newBufferWithBytes:verts
 184                                                            length:sizeof(verts)
 185                                                            options:MTLResourceCPUCacheModeDefaultCache] retain];
 186 
 187     NSError *error = nil;
 188 
 189     mtlc->mtlLibrary = [mtlc->mtlDevice newLibraryWithFile: mtlShadersLib error:&error];
 190     if (!mtlc->mtlLibrary) {
 191         NSLog(@"Failed to load library. error %@", error);
 192         exit(0);
 193     }
 194     id <MTLFunction> vertColFunc = [mtlc->mtlLibrary newFunctionWithName:@"vert_col"];
 195     id <MTLFunction> vertTxtFunc = [mtlc->mtlLibrary newFunctionWithName:@"vert_txt"];
 196     id <MTLFunction> fragColFunc = [mtlc->mtlLibrary newFunctionWithName:@"frag_col"];
 197     id <MTLFunction> fragTxtFunc = [mtlc->mtlLibrary newFunctionWithName:@"frag_txt"];
 198 
 199     // Create depth state.
 200     MTLDepthStencilDescriptor *depthDesc = [MTLDepthStencilDescriptor new];
 201     depthDesc.depthCompareFunction = MTLCompareFunctionLess;
 202     depthDesc.depthWriteEnabled = YES;
 203 
 204     MTLVertexDescriptor *vertDesc = [MTLVertexDescriptor new];
 205     vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat3;
 206     vertDesc.attributes[VertexAttributePosition].offset = 0;
 207     vertDesc.attributes[VertexAttributePosition].bufferIndex = MeshVertexBuffer;
 208     vertDesc.layouts[MeshVertexBuffer].stride = sizeof(struct Vertex);
 209     vertDesc.layouts[MeshVertexBuffer].stepRate = 1;
 210     vertDesc.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
 211 
 212     // Create pipeline state.
 213     MTLRenderPipelineDescriptor *pipelineDesc = [MTLRenderPipelineDescriptor new];
 214     pipelineDesc.sampleCount = 1;
 215     pipelineDesc.vertexFunction = vertColFunc;
 216     pipelineDesc.fragmentFunction = fragColFunc;
 217     pipelineDesc.vertexDescriptor = vertDesc;
 218     pipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
 219     mtlc->mtlPipelineState = [mtlc->mtlDevice newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
 220     if (!mtlc->mtlPipelineState) {
 221         NSLog(@"Failed to create pipeline state, error %@", error);
 222         exit(0);
 223     }
 224 
 225     vertDesc = [MTLVertexDescriptor new];
 226     vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat3;
 227     vertDesc.attributes[VertexAttributePosition].offset = 0;
 228     vertDesc.attributes[VertexAttributePosition].bufferIndex = MeshVertexBuffer;
 229     vertDesc.attributes[VertexAttributeTexPos].format = MTLVertexFormatFloat2;
 230     vertDesc.attributes[VertexAttributeTexPos].offset = 3*sizeof(float);
 231     vertDesc.attributes[VertexAttributeTexPos].bufferIndex = MeshVertexBuffer;
 232     vertDesc.layouts[MeshVertexBuffer].stride = sizeof(struct TxtVertex);
 233     vertDesc.layouts[MeshVertexBuffer].stepRate = 1;
 234     vertDesc.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
 235     // Create pipeline state.
 236     pipelineDesc = [MTLRenderPipelineDescriptor new];
 237     pipelineDesc.sampleCount = 1;
 238     pipelineDesc.vertexFunction = vertTxtFunc;
 239     pipelineDesc.fragmentFunction = fragTxtFunc;
 240     pipelineDesc.vertexDescriptor = vertDesc;
 241     pipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
 242     mtlc->mtlBlitPipelineState = [mtlc->mtlDevice newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
 243     if (!mtlc->mtlBlitPipelineState) {
 244         NSLog(@"Failed to create pipeline state, error %@", error);
 245         exit(0);
 246     }
 247 
 248     mtlc->mtlCommandBuffer = nil;
 249 
 250     // Create command queue
 251     mtlc->mtlCommandQueue = [mtlc->mtlDevice newCommandQueue];
 252     mtlc->mtlEmptyCommandBuffer = YES;
 253 
 254     // create the MTLGraphicsConfigInfo record for this config
 255     MTLGraphicsConfigInfo *mtlinfo = (MTLGraphicsConfigInfo *)malloc(sizeof(MTLGraphicsConfigInfo));
 256     if (mtlinfo == NULL) {
 257         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: could not allocate memory for mtlinfo");
 258         free(mtlc);
 259         [argValue addObject: [NSNumber numberWithLong: 0L]];
 260         return;
 261     }
 262     memset(mtlinfo, 0, sizeof(MTLGraphicsConfigInfo));
 263     mtlinfo->screen = displayID;
 264     mtlinfo->context = mtlc;
 265 
 266     [argValue addObject: [NSNumber numberWithLong:ptr_to_jlong(mtlinfo)]];
 267     [pool drain];
 268 }
 269 @end //GraphicsConfigUtil
 270 
 271 
 272 JNIEXPORT jint JNICALL
 273 Java_sun_java2d_metal_MTLGraphicsConfig_nativeGetMaxTextureSize
 274     (JNIEnv *env, jclass mtlgc)
 275 {
 276     J2dTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_nativeGetMaxTextureSize");
 277 
 278     __block int max = 0;
 279 
 280 //    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 281 //    }];
 282 
 283     return (jint)max;
 284 }