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