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