1 /* 2 * Copyright (c) 2011, 2015, 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 346 J2dRlsTraceLn1(J2D_TRACE_INFO, 347 "CGLGraphicsConfig_getCGLConfigInfo: db=%d", 348 (caps & CAPS_DOUBLEBUFFERED) != 0); 349 350 // remove before shipping (?) 351 #if 1 352 [sharedPixelFormat 353 getValues: &value 354 forAttribute: NSOpenGLPFAAccelerated 355 forVirtualScreen: contextVirtualScreen]; 356 if (value == 0) { 357 [sharedPixelFormat 358 getValues: &value 359 forAttribute: NSOpenGLPFARendererID 360 forVirtualScreen: contextVirtualScreen]; 361 fprintf(stderr, "WARNING: GL pipe is running in software mode (Renderer ID=0x%x)\n", (int)value); 362 } 363 #endif 364 365 // 0: the buffers are swapped with no regard to the vertical refresh rate 366 // 1: the buffers are swapped only during the vertical retrace 367 GLint params = swapInterval; 368 [context setValues: ¶ms forParameter: NSOpenGLCPSwapInterval]; 369 370 CGLCtxInfo *ctxinfo = (CGLCtxInfo *)malloc(sizeof(CGLCtxInfo)); 371 if (ctxinfo == NULL) { 372 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for ctxinfo"); 373 [NSOpenGLContext clearCurrentContext]; 374 [argValue addObject: [NSNumber numberWithLong: 0L]]; 375 return; 376 } 377 memset(ctxinfo, 0, sizeof(CGLCtxInfo)); 378 ctxinfo->context = context; 379 ctxinfo->scratchSurface = scratchSurface; 380 381 OGLContext *oglc = (OGLContext *)malloc(sizeof(OGLContext)); 382 if (oglc == 0L) { 383 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for oglc"); 384 [NSOpenGLContext clearCurrentContext]; 385 free(ctxinfo); 386 [argValue addObject: [NSNumber numberWithLong: 0L]]; 387 return; 388 } 389 memset(oglc, 0, sizeof(OGLContext)); 390 oglc->ctxInfo = ctxinfo; 391 oglc->caps = caps; 392 393 // create the CGLGraphicsConfigInfo record for this config 394 CGLGraphicsConfigInfo *cglinfo = (CGLGraphicsConfigInfo *)malloc(sizeof(CGLGraphicsConfigInfo)); 395 if (cglinfo == NULL) { 396 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: could not allocate memory for cglinfo"); 397 [NSOpenGLContext clearCurrentContext]; 398 free(oglc); 399 free(ctxinfo); 400 [argValue addObject: [NSNumber numberWithLong: 0L]]; 401 return; 402 } 403 memset(cglinfo, 0, sizeof(CGLGraphicsConfigInfo)); 404 cglinfo->screen = displayID; 405 cglinfo->pixfmt = sharedPixelFormat; 406 cglinfo->context = oglc; 407 408 [NSOpenGLContext clearCurrentContext]; 409 [argValue addObject: [NSNumber numberWithLong:ptr_to_jlong(cglinfo)]]; 410 [pool drain]; 411 } 412 @end //GraphicsConfigUtil 413 414 JNIEXPORT jint JNICALL 415 Java_sun_java2d_opengl_CGLGraphicsConfig_getOGLCapabilities 416 (JNIEnv *env, jclass cglgc, jlong configInfo) 417 { 418 J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getOGLCapabilities"); 419 420 CGLGraphicsConfigInfo *cglinfo = 421 (CGLGraphicsConfigInfo *)jlong_to_ptr(configInfo); 422 if ((cglinfo == NULL) || (cglinfo->context == NULL)) { 423 return CAPS_EMPTY; 424 } else { 425 return cglinfo->context->caps; 426 } 427 } 428 429 JNIEXPORT jint JNICALL 430 Java_sun_java2d_opengl_CGLGraphicsConfig_nativeGetMaxTextureSize 431 (JNIEnv *env, jclass cglgc) 432 { 433 J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_nativeGetMaxTextureSize"); 434 435 __block int max = 0; 436 437 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 438 [sharedContext makeCurrentContext]; 439 j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max); 440 [NSOpenGLContext clearCurrentContext]; 441 }]; 442 443 return (jint)max; 444 }