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 "sun_java2d_metal_MetalGraphicsConfig.h"
  27 
  28 #import "MetalGraphicsConfig.h"
  29 //#import "CGLSurfaceData.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 Metal pipeline ---"
  39 
  40 /**
  41  * Disposes all memory and resources associated with the given
  42  * CGLGraphicsConfigInfo (including its native OGLContext data).
  43  */
  44 /*void
  45 OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo)
  46 {
  47     J2dTraceLn(J2D_TRACE_INFO, "OGLGC_DestroyOGLGraphicsConfig");
  48 
  49     CGLGraphicsConfigInfo *cglinfo =
  50         (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
  51     if (cglinfo == NULL) {
  52         J2dRlsTraceLn(J2D_TRACE_ERROR,
  53                       "OGLGC_DestroyOGLGraphicsConfig: info is null");
  54         return;
  55     }
  56 
  57     OGLContext *oglc = (OGLContext*)cglinfo->context;
  58     if (oglc != NULL) {
  59         OGLContext_DestroyContextResources(oglc);
  60 
  61         CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;
  62         if (ctxinfo != NULL) {
  63             NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  64             [NSOpenGLContext clearCurrentContext];
  65             [ctxinfo->context clearDrawable];
  66             [ctxinfo->context release];
  67             if (ctxinfo->scratchSurface != 0) {
  68                 [ctxinfo->scratchSurface release];
  69             }
  70             [pool drain];
  71             free(ctxinfo);
  72             oglc->ctxInfo = NULL;
  73         }
  74         cglinfo->context = NULL;
  75     }
  76 
  77     free(cglinfo);
  78 }*/
  79 
  80 #pragma mark -
  81 #pragma mark "--- MetalGraphicsConfig methods ---"
  82 
  83 /*#ifdef REMOTELAYER
  84 mach_port_t JRSRemotePort;
  85 int remoteSocketFD = -1;
  86 
  87 static void *JRSRemoteThreadFn(void *data) {
  88     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  89 
  90     // Negotiate a unix domain socket to communicate the
  91     // out of band data: to read the mach port server name, and
  92     // subsequently write out the layer ID.
  93     static char* sock_path = "/tmp/JRSRemoteDemoSocket";
  94     struct sockaddr_un address;
  95     int  socket_fd, nbytes;
  96     int BUFLEN = 256;
  97     char buffer[BUFLEN];
  98 
  99     remoteSocketFD = socket(PF_LOCAL, SOCK_STREAM, 0);
 100     if (remoteSocketFD < 0) {
 101         NSLog(@"socket() failed");
 102         return NULL;
 103     }
 104     memset(&address, 0, sizeof(struct sockaddr_un));
 105     address.sun_family = AF_UNIX;
 106     memcpy(address.sun_path, sock_path, strlen(sock_path)+1);
 107     int tries=0, status=-1;
 108     while (status !=0 && tries<600) {
 109         status = connect(remoteSocketFD, (struct sockaddr *) &address,
 110                          sizeof(struct sockaddr_un));
 111         if (status != 0) {
 112             tries++;
 113             NSLog(@"connection attempt %d failed.", tries);
 114             usleep(5000000);
 115         }
 116     }
 117     if (status != 0) {
 118         NSLog(@"failed to connect");
 119         return NULL;
 120     }
 121     nbytes = read(remoteSocketFD, buffer, BUFLEN);
 122     NSString* serverString = [[NSString alloc] initWithUTF8String:buffer];
 123     CFRetain(serverString);
 124     NSLog(@"Read server name %@", serverString);
 125     JRSRemotePort = [JRSRenderServer recieveRenderServer:serverString];
 126     NSLog(@"Read server port %d", JRSRemotePort);
 127 
 128     [pool drain];
 129     return NULL;
 130 }
 131 
 132 void sendLayerID(int layerID) {
 133     if (JRSRemotePort == 0 || remoteSocketFD < 0) {
 134         NSLog(@"No connection to send ID");
 135         return;
 136     }
 137     int BUFLEN = 256;
 138     char buffer[BUFLEN];
 139     snprintf(buffer, BUFLEN, "%d", layerID);
 140     write(remoteSocketFD, buffer, BUFLEN);
 141 }
 142 #endif*/  /* REMOTELAYER */
 143 
 144 /**
 145  * This is a globally shared context used when creating textures.  When any
 146  * new contexts are created, they specify this context as the "share list"
 147  * context, which means any texture objects created when this shared context
 148  * is current will be available to any other context in any other thread.
 149  */
 150 //NSOpenGLContext *sharedContext = NULL;
 151 //NSOpenGLPixelFormat *sharedPixelFormat = NULL;
 152 
 153 /**
 154  * Attempts to initialize CGL and the core OpenGL library.
 155  */
 156 /*JNIEXPORT jboolean JNICALL
 157 Java_sun_java2d_opengl_CGLGraphicsConfig_initCGL
 158     (JNIEnv *env, jclass cglgc)
 159 {
 160     J2dRlsTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_initCGL");
 161 
 162     if (!OGLFuncs_OpenLibrary()) {
 163         return JNI_FALSE;
 164     }
 165 
 166     if (!OGLFuncs_InitPlatformFuncs() ||
 167         !OGLFuncs_InitBaseFuncs() ||
 168         !OGLFuncs_InitExtFuncs())
 169     {
 170         OGLFuncs_CloseLibrary();
 171         return JNI_FALSE;
 172     }
 173 #ifdef REMOTELAYER
 174     pthread_t jrsRemoteThread;
 175     pthread_create(&jrsRemoteThread, NULL, JRSRemoteThreadFn, NULL);
 176 #endif
 177     return JNI_TRUE;
 178 }*/
 179 
 180 
 181 /**
 182  * Determines whether the CGL pipeline can be used for a given GraphicsConfig
 183  * provided its screen number and visual ID.  If the minimum requirements are
 184  * met, the native CGLGraphicsConfigInfo structure is initialized for this
 185  * GraphicsConfig with the necessary information (pixel format, etc.)
 186  * and a pointer to this structure is returned as a jlong.  If
 187  * initialization fails at any point, zero is returned, indicating that CGL
 188  * cannot be used for this GraphicsConfig (we should fallback on an existing
 189  * 2D pipeline).
 190  */
 191 JNIEXPORT jlong JNICALL
 192 Java_sun_java2d_metal_MetalGraphicsConfig_getMetalConfigInfo
 193     (JNIEnv *env, jclass metalgc,
 194      jint displayID, jint pixfmt)
 195 {
 196     //fprintf(stdout, "Jay : MetalGraphicsConfig_getMetalConfigInfo\n");fflush(stdout);
 197   jlong ret = 0L;
 198   JNF_COCOA_ENTER(env);
 199   NSMutableArray * retArray = [NSMutableArray arrayWithCapacity:2];
 200   [retArray addObject: [NSNumber numberWithInt: (int)displayID]];
 201   [retArray addObject: [NSNumber numberWithInt: (int)pixfmt]];
 202   //if ([NSThread isMainThread]) {
 203       //[GraphicsConfigUtil _getCGLConfigInfo: retArray];
 204   //} else {
 205       [MetalGraphicsConfigUtil performSelectorOnMainThread: @selector(_getMetalConfigInfo:) withObject: retArray waitUntilDone: YES];
 206   //}
 207   NSNumber * num = (NSNumber *)[retArray objectAtIndex: 0];
 208   ret = (jlong)[num longValue];
 209   JNF_COCOA_EXIT(env);
 210   return ret;
 211 }
 212 
 213 @implementation MetalGraphicsConfigUtil
 214 + (void) _getMetalConfigInfo: (NSMutableArray *)argValue {
 215     AWT_ASSERT_APPKIT_THREAD;
 216 
 217     //fprintf(stdout, "Jay : MetalGraphicsConfig_MetalGraphicsConfigUtil\n");fflush(stdout);
 218     jint displayID = (jint)[(NSNumber *)[argValue objectAtIndex: 0] intValue];
 219     jint pixfmt = (jint)[(NSNumber *)[argValue objectAtIndex: 1] intValue];
 220     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 221     [argValue removeAllObjects];
 222 
 223     //J2dRlsTraceLn(J2D_TRACE_INFO, "MetalGraphicsConfig_getMetalConfigInfo");
 224 
 225     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
 226 
 227     /*CGOpenGLDisplayMask glMask = (CGOpenGLDisplayMask)pixfmt;
 228     if (sharedContext == NULL) {
 229         if (glMask == 0) {
 230             glMask = CGDisplayIDToOpenGLDisplayMask(displayID);
 231         }
 232 
 233         NSOpenGLPixelFormatAttribute attrs[] = {
 234             NSOpenGLPFAAllowOfflineRenderers,
 235             NSOpenGLPFAClosestPolicy,
 236             NSOpenGLPFAWindow,
 237             NSOpenGLPFAPixelBuffer,
 238             NSOpenGLPFADoubleBuffer,
 239             NSOpenGLPFAColorSize, 32,
 240             NSOpenGLPFAAlphaSize, 8,
 241             NSOpenGLPFADepthSize, 16,
 242             NSOpenGLPFAScreenMask, glMask,
 243             0
 244         };
 245 
 246         sharedPixelFormat =
 247             [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
 248         if (sharedPixelFormat == nil) {
 249             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL");
 250             [argValue addObject: [NSNumber numberWithLong: 0L]];
 251             return;
 252         }
 253 
 254         sharedContext =
 255             [[NSOpenGLContext alloc]
 256                 initWithFormat:sharedPixelFormat
 257                 shareContext: NULL];
 258         if (sharedContext == nil) {
 259             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLContext is NULL");
 260             [argValue addObject: [NSNumber numberWithLong: 0L]];
 261             return;
 262         }
 263     }*/
 264     id<MTLDevice> device = MTLCreateSystemDefaultDevice();
 265     
 266     id<MTLCommandQueue> commandQueue = [device newCommandQueue];
 267     
 268     // Jay : Looks like no need to create MetaLayer here and we were creating
 269     // scratch surface only to make OGL context current. So no need to create any layer for
 270     // Metal. Just create device and commandQueue for Metal.
 271     //defaultLibrary = [device newDefaultLibrary];
 272     /*CAMetalLayer *metalLayer = [CAMetalLayer layer];
 273     metalLayer.device = device;
 274     metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;*/
 275     
 276 #if USE_NSVIEW_FOR_SCRATCH
 277     /*NSRect contentRect = NSMakeRect(0, 0, 64, 64);
 278     NSWindow *window =
 279         [[NSWindow alloc]
 280             initWithContentRect: contentRect
 281             styleMask: NSBorderlessWindowMask
 282             backing: NSBackingStoreBuffered
 283             defer: false];
 284     if (window == nil) {
 285         J2dRlsTraceLn(J2D_TRACE_ERROR, "MetalGraphicsConfig_getMetalConfigInfo: NSWindow is NULL");
 286         [argValue addObject: [NSNumber numberWithLong: 0L]];
 287         return;
 288     }
 289 
 290     NSView *scratchSurface =
 291         [[NSView alloc]
 292             initWithFrame: contentRect];
 293     if (scratchSurface == nil) {
 294         J2dRlsTraceLn(J2D_TRACE_ERROR, "MetalGraphicsConfig_getMetalConfigInfo: NSView is NULL");
 295         [argValue addObject: [NSNumber numberWithLong: 0L]];
 296         return;
 297     }
 298     [window setContentView: scratchSurface];*/
 299 #else
 300     /*NSOpenGLPixelBuffer *scratchSurface =
 301         [[NSOpenGLPixelBuffer alloc]
 302             initWithTextureTarget:GL_TEXTURE_2D
 303             textureInternalFormat:GL_RGB
 304             textureMaxMipMapLevel:0
 305             pixelsWide:64
 306             pixelsHigh:64];*/
 307 #endif
 308 
 309     /*NSOpenGLContext *context =
 310         [[NSOpenGLContext alloc]
 311             initWithFormat: sharedPixelFormat
 312             shareContext: sharedContext];
 313     if (context == nil) {
 314         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSOpenGLContext is NULL");
 315         [argValue addObject: [NSNumber numberWithLong: 0L]];
 316         return;
 317     }
 318 
 319     GLint contextVirtualScreen = [context currentVirtualScreen];*/
 320 #if USE_NSVIEW_FOR_SCRATCH
 321     //[context setView: scratchSurface];
 322     // Jay : no need of scratch layer for metal
 323     //metalLayer.frame = scratchSurface.layer.frame;
 324     //[scratchSurface.layer addSublayer: metalLayer];
 325 #else
 326     /*[context
 327         setPixelBuffer: scratchSurface
 328         cubeMapFace:0
 329         mipMapLevel:0
 330         currentVirtualScreen: contextVirtualScreen];*/
 331 #endif
 332     /*[context makeCurrentContext];
 333 
 334     // get version and extension strings
 335     const unsigned char *versionstr = j2d_glGetString(GL_VERSION);
 336     if (!OGLContext_IsVersionSupported(versionstr)) {
 337         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL 1.2 is required");
 338         [NSOpenGLContext clearCurrentContext];
 339         [argValue addObject: [NSNumber numberWithLong: 0L]];
 340         return;
 341     }
 342     J2dRlsTraceLn1(J2D_TRACE_INFO, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL version=%s", versionstr);
 343 
 344     jint caps = CAPS_EMPTY;
 345     OGLContext_GetExtensionInfo(env, &caps);
 346 
 347     GLint value = 0;
 348     [sharedPixelFormat
 349         getValues: &value
 350         forAttribute: NSOpenGLPFADoubleBuffer
 351         forVirtualScreen: contextVirtualScreen];
 352     if (value != 0) {
 353         caps |= CAPS_DOUBLEBUFFERED;
 354     }
 355 
 356     J2dRlsTraceLn1(J2D_TRACE_INFO,
 357                    "CGLGraphicsConfig_getCGLConfigInfo: db=%d",
 358                    (caps & CAPS_DOUBLEBUFFERED) != 0);*/
 359 
 360     // remove before shipping (?)
 361 #if 1
 362     /*[sharedPixelFormat
 363         getValues: &value
 364         forAttribute: NSOpenGLPFAAccelerated
 365         forVirtualScreen: contextVirtualScreen];
 366     if (value == 0) {
 367         [sharedPixelFormat
 368             getValues: &value
 369             forAttribute: NSOpenGLPFARendererID
 370             forVirtualScreen: contextVirtualScreen];
 371         fprintf(stderr, "WARNING: GL pipe is running in software mode (Renderer ID=0x%x)\n", (int)value);
 372     }*/
 373 #endif
 374 
 375     // 0: the buffers are swapped with no regard to the vertical refresh rate
 376     // 1: the buffers are swapped only during the vertical retrace
 377     /*GLint params = swapInterval;
 378     [context setValues: &params forParameter: NSOpenGLCPSwapInterval];
 379 
 380     CGLCtxInfo *ctxinfo = (CGLCtxInfo *)malloc(sizeof(CGLCtxInfo));
 381     if (ctxinfo == NULL) {
 382         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for ctxinfo");
 383         [NSOpenGLContext clearCurrentContext];
 384         [argValue addObject: [NSNumber numberWithLong: 0L]];
 385         return;
 386     }
 387     memset(ctxinfo, 0, sizeof(CGLCtxInfo));
 388     ctxinfo->context = context;
 389     ctxinfo->scratchSurface = scratchSurface;
 390 
 391     OGLContext *oglc = (OGLContext *)malloc(sizeof(OGLContext));
 392     if (oglc == 0L) {
 393         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for oglc");
 394         [NSOpenGLContext clearCurrentContext];
 395         free(ctxinfo);
 396         [argValue addObject: [NSNumber numberWithLong: 0L]];
 397         return;
 398     }
 399     memset(oglc, 0, sizeof(OGLContext));
 400     oglc->ctxInfo = ctxinfo;
 401     oglc->caps = caps;*/
 402 
 403     // create the CGLGraphicsConfigInfo record for this config
 404     MetalGraphicsConfigInfo *metalinfo = (MetalGraphicsConfigInfo *)malloc(sizeof(MetalGraphicsConfigInfo));
 405     if (metalinfo == NULL) {
 406         //J2dRlsTraceLn(J2D_TRACE_ERROR, "MetalGraphicsConfig_getMetalConfigInfo: could not allocate memory for cglinfo");
 407         //[NSOpenGLContext clearCurrentContext];
 408         //free(oglc);
 409         //free(ctxinfo);
 410         //[argValue addObject: [NSNumber numberWithLong: 0L]];
 411         return;
 412     }
 413     memset(metalinfo, 0, sizeof(MetalGraphicsConfigInfo));
 414     metalinfo->screen = displayID;
 415     metalinfo->device = device;
 416     metalinfo->commandQueue = commandQueue;
 417 
 418     //[NSOpenGLContext clearCurrentContext];
 419     [argValue addObject: [NSNumber numberWithLong:ptr_to_jlong(metalinfo)]];
 420     [pool drain];
 421 }
 422 @end //GraphicsConfigUtil
 423 
 424 /*JNIEXPORT jint JNICALL
 425 Java_sun_java2d_opengl_CGLGraphicsConfig_getOGLCapabilities
 426     (JNIEnv *env, jclass cglgc, jlong configInfo)
 427 {
 428     J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getOGLCapabilities");
 429 
 430     CGLGraphicsConfigInfo *cglinfo =
 431         (CGLGraphicsConfigInfo *)jlong_to_ptr(configInfo);
 432     if ((cglinfo == NULL) || (cglinfo->context == NULL)) {
 433         return CAPS_EMPTY;
 434     } else {
 435         return cglinfo->context->caps;
 436     }
 437 }
 438 
 439 JNIEXPORT jint JNICALL
 440 Java_sun_java2d_opengl_CGLGraphicsConfig_nativeGetMaxTextureSize
 441     (JNIEnv *env, jclass cglgc)
 442 {
 443     J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_nativeGetMaxTextureSize");
 444 
 445     __block int max = 0;
 446 
 447     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 448         [sharedContext makeCurrentContext];
 449         j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
 450         [NSOpenGLContext clearCurrentContext];
 451     }];
 452 
 453     return (jint)max;
 454 }*/