1 /* 2 * Copyright (c) 2011, 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_opengl_CGLGraphicsConfig.h" 27 28 #import "CGLGraphicsConfig.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 GL 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 "--- CGLGraphicsConfig methods ---" 82 83 /** 84 * This is a globally shared context used when creating textures. When any 85 * new contexts are created, they specify this context as the "share list" 86 * context, which means any texture objects created when this shared context 87 * is current will be available to any other context in any other thread. 88 */ 89 NSOpenGLContext *sharedContext = NULL; 90 NSOpenGLPixelFormat *sharedPixelFormat = NULL; 91 92 /** 93 * Attempts to initialize CGL and the core OpenGL library. 94 */ 95 JNIEXPORT jboolean JNICALL 96 Java_sun_java2d_opengl_CGLGraphicsConfig_initCGL 97 (JNIEnv *env, jclass cglgc) 98 { 99 J2dRlsTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_initCGL"); 100 101 if (!OGLFuncs_OpenLibrary()) { 102 return JNI_FALSE; 103 } 104 105 if (!OGLFuncs_InitPlatformFuncs() || 106 !OGLFuncs_InitBaseFuncs() || 107 !OGLFuncs_InitExtFuncs()) 108 { 109 OGLFuncs_CloseLibrary(); 110 return JNI_FALSE; 111 } 112 return JNI_TRUE; 113 } 114 115 116 /** 117 * Determines whether the CGL pipeline can be used for a given GraphicsConfig 118 * provided its screen number and visual ID. If the minimum requirements are 119 * met, the native CGLGraphicsConfigInfo structure is initialized for this 120 * GraphicsConfig with the necessary information (pixel format, etc.) 121 * and a pointer to this structure is returned as a jlong. If 122 * initialization fails at any point, zero is returned, indicating that CGL 123 * cannot be used for this GraphicsConfig (we should fallback on an existing 124 * 2D pipeline). 125 */ 126 JNIEXPORT jlong JNICALL 127 Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo 128 (JNIEnv *env, jclass cglgc, 129 jint displayID, jint pixfmt, jint swapInterval) 130 { 131 jlong ret = 0L; 132 JNF_COCOA_ENTER(env); 133 NSMutableArray * retArray = [NSMutableArray arrayWithCapacity:3]; 134 [retArray addObject: [NSNumber numberWithInt: (int)displayID]]; 135 [retArray addObject: [NSNumber numberWithInt: (int)pixfmt]]; 136 [retArray addObject: [NSNumber numberWithInt: (int)swapInterval]]; 137 if ([NSThread isMainThread]) { 138 [GraphicsConfigUtil _getCGLConfigInfo: retArray]; 139 } else { 140 [GraphicsConfigUtil performSelectorOnMainThread: @selector(_getCGLConfigInfo:) withObject: retArray waitUntilDone: YES]; 141 } 142 NSNumber * num = (NSNumber *)[retArray objectAtIndex: 0]; 143 ret = (jlong)[num longValue]; 144 JNF_COCOA_EXIT(env); 145 return ret; 146 } 147 148 149 150 @implementation GraphicsConfigUtil 151 + (void) _getCGLConfigInfo: (NSMutableArray *)argValue { 152 AWT_ASSERT_APPKIT_THREAD; 153 154 jint displayID = (jint)[(NSNumber *)[argValue objectAtIndex: 0] intValue]; 155 jint pixfmt = (jint)[(NSNumber *)[argValue objectAtIndex: 1] intValue]; 156 jint swapInterval = (jint)[(NSNumber *)[argValue objectAtIndex: 2] intValue]; 157 JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; 158 [argValue removeAllObjects]; 159 160 J2dRlsTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getCGLConfigInfo"); 161 162 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 163 164 CGOpenGLDisplayMask glMask = (CGOpenGLDisplayMask)pixfmt; 165 if (sharedContext == NULL) { 166 if (glMask == 0) { 167 glMask = CGDisplayIDToOpenGLDisplayMask(displayID); 168 } 169 170 NSOpenGLPixelFormatAttribute attrs[] = { 171 NSOpenGLPFAAllowOfflineRenderers, 172 NSOpenGLPFAClosestPolicy, 173 NSOpenGLPFAWindow, 174 NSOpenGLPFAPixelBuffer, 175 NSOpenGLPFADoubleBuffer, 176 NSOpenGLPFAColorSize, 32, 177 NSOpenGLPFAAlphaSize, 8, 178 NSOpenGLPFADepthSize, 16, 179 NSOpenGLPFAScreenMask, glMask, 180 0 181 }; 182 183 sharedPixelFormat = 184 [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; 185 if (sharedPixelFormat == nil) { 186 J2dRlsTraceLn1(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL glMask %0x\n",glMask); 187 NSOpenGLPixelFormatAttribute attrs1[] = { 188 NSOpenGLPFAAllowOfflineRenderers, 189 NSOpenGLPFAClosestPolicy, 190 NSOpenGLPFAWindow, 191 NSOpenGLPFAPixelBuffer, 192 NSOpenGLPFADoubleBuffer, 193 NSOpenGLPFAColorSize, 32, 194 NSOpenGLPFAAlphaSize, 8, 195 NSOpenGLPFADepthSize, 16, 196 0 197 }; 198 sharedPixelFormat = 199 [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs1]; 200 if (sharedPixelFormat == nil) { 201 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL "); 202 203 [argValue addObject: [NSNumber numberWithLong: 0L]]; 204 return; 205 } 206 } 207 208 sharedContext = 209 [[NSOpenGLContext alloc] 210 initWithFormat:sharedPixelFormat 211 shareContext: NULL]; 212 if (sharedContext == nil) { 213 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLContext is NULL"); 214 [argValue addObject: [NSNumber numberWithLong: 0L]]; 215 return; 216 } 217 } 218 219 #if USE_NSVIEW_FOR_SCRATCH 220 NSRect contentRect = NSMakeRect(0, 0, 64, 64); 221 NSWindow *window = 222 [[NSWindow alloc] 223 initWithContentRect: contentRect 224 styleMask: NSBorderlessWindowMask 225 backing: NSBackingStoreBuffered 226 defer: false]; 227 if (window == nil) { 228 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSWindow is NULL"); 229 [argValue addObject: [NSNumber numberWithLong: 0L]]; 230 return; 231 } 232 233 NSView *scratchSurface = 234 [[NSView alloc] 235 initWithFrame: contentRect]; 236 if (scratchSurface == nil) { 237 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSView is NULL"); 238 [argValue addObject: [NSNumber numberWithLong: 0L]]; 239 return; 240 } 241 [window setContentView: scratchSurface]; 242 #else 243 NSOpenGLPixelBuffer *scratchSurface = 244 [[NSOpenGLPixelBuffer alloc] 245 initWithTextureTarget:GL_TEXTURE_2D 246 textureInternalFormat:GL_RGB 247 textureMaxMipMapLevel:0 248 pixelsWide:64 249 pixelsHigh:64]; 250 #endif 251 252 NSOpenGLContext *context = 253 [[NSOpenGLContext alloc] 254 initWithFormat: sharedPixelFormat 255 shareContext: sharedContext]; 256 if (context == nil) { 257 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSOpenGLContext is NULL"); 258 [argValue addObject: [NSNumber numberWithLong: 0L]]; 259 return; 260 } 261 262 GLint contextVirtualScreen = [context currentVirtualScreen]; 263 #if USE_NSVIEW_FOR_SCRATCH 264 [context setView: scratchSurface]; 265 #else 266 [context 267 setPixelBuffer: scratchSurface 268 cubeMapFace:0 269 mipMapLevel:0 270 currentVirtualScreen: contextVirtualScreen]; 271 #endif 272 [context makeCurrentContext]; 273 274 // get version and extension strings 275 const unsigned char *versionstr = j2d_glGetString(GL_VERSION); 276 if (!OGLContext_IsVersionSupported(versionstr)) { 277 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL 1.2 is required"); 278 [NSOpenGLContext clearCurrentContext]; 279 [argValue addObject: [NSNumber numberWithLong: 0L]]; 280 return; 281 } 282 J2dRlsTraceLn1(J2D_TRACE_INFO, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL version=%s", versionstr); 283 284 jint caps = CAPS_EMPTY; 285 OGLContext_GetExtensionInfo(env, &caps); 286 287 GLint value = 0; 288 [sharedPixelFormat 289 getValues: &value 290 forAttribute: NSOpenGLPFADoubleBuffer 291 forVirtualScreen: contextVirtualScreen]; 292 if (value != 0) { 293 caps |= CAPS_DOUBLEBUFFERED; 294 } 295 296 J2dRlsTraceLn1(J2D_TRACE_INFO, 297 "CGLGraphicsConfig_getCGLConfigInfo: db=%d", 298 (caps & CAPS_DOUBLEBUFFERED) != 0); 299 300 // remove before shipping (?) 301 #if 1 302 [sharedPixelFormat 303 getValues: &value 304 forAttribute: NSOpenGLPFAAccelerated 305 forVirtualScreen: contextVirtualScreen]; 306 if (value == 0) { 307 [sharedPixelFormat 308 getValues: &value 309 forAttribute: NSOpenGLPFARendererID 310 forVirtualScreen: contextVirtualScreen]; 311 fprintf(stderr, "WARNING: GL pipe is running in software mode (Renderer ID=0x%x)\n", (int)value); 312 } 313 #endif 314 315 // 0: the buffers are swapped with no regard to the vertical refresh rate 316 // 1: the buffers are swapped only during the vertical retrace 317 GLint params = swapInterval; 318 [context setValues: ¶ms forParameter: NSOpenGLCPSwapInterval]; 319 320 CGLCtxInfo *ctxinfo = (CGLCtxInfo *)malloc(sizeof(CGLCtxInfo)); 321 if (ctxinfo == NULL) { 322 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for ctxinfo"); 323 [NSOpenGLContext clearCurrentContext]; 324 [argValue addObject: [NSNumber numberWithLong: 0L]]; 325 return; 326 } 327 memset(ctxinfo, 0, sizeof(CGLCtxInfo)); 328 ctxinfo->context = context; 329 ctxinfo->scratchSurface = scratchSurface; 330 331 OGLContext *oglc = (OGLContext *)malloc(sizeof(OGLContext)); 332 if (oglc == 0L) { 333 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for oglc"); 334 [NSOpenGLContext clearCurrentContext]; 335 free(ctxinfo); 336 [argValue addObject: [NSNumber numberWithLong: 0L]]; 337 return; 338 } 339 memset(oglc, 0, sizeof(OGLContext)); 340 oglc->ctxInfo = ctxinfo; 341 oglc->caps = caps; 342 343 // create the CGLGraphicsConfigInfo record for this config 344 CGLGraphicsConfigInfo *cglinfo = (CGLGraphicsConfigInfo *)malloc(sizeof(CGLGraphicsConfigInfo)); 345 if (cglinfo == NULL) { 346 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: could not allocate memory for cglinfo"); 347 [NSOpenGLContext clearCurrentContext]; 348 free(oglc); 349 free(ctxinfo); 350 [argValue addObject: [NSNumber numberWithLong: 0L]]; 351 return; 352 } 353 memset(cglinfo, 0, sizeof(CGLGraphicsConfigInfo)); 354 cglinfo->screen = displayID; 355 cglinfo->pixfmt = sharedPixelFormat; 356 cglinfo->context = oglc; 357 358 [NSOpenGLContext clearCurrentContext]; 359 [argValue addObject: [NSNumber numberWithLong:ptr_to_jlong(cglinfo)]]; 360 [pool drain]; 361 } 362 @end //GraphicsConfigUtil 363 364 JNIEXPORT jint JNICALL 365 Java_sun_java2d_opengl_CGLGraphicsConfig_getOGLCapabilities 366 (JNIEnv *env, jclass cglgc, jlong configInfo) 367 { 368 J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getOGLCapabilities"); 369 370 CGLGraphicsConfigInfo *cglinfo = 371 (CGLGraphicsConfigInfo *)jlong_to_ptr(configInfo); 372 if ((cglinfo == NULL) || (cglinfo->context == NULL)) { 373 return CAPS_EMPTY; 374 } else { 375 return cglinfo->context->caps; 376 } 377 } 378 379 JNIEXPORT jint JNICALL 380 Java_sun_java2d_opengl_CGLGraphicsConfig_nativeGetMaxTextureSize 381 (JNIEnv *env, jclass cglgc) 382 { 383 J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_nativeGetMaxTextureSize"); 384 385 __block int max = 0; 386 387 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 388 [sharedContext makeCurrentContext]; 389 j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max); 390 [NSOpenGLContext clearCurrentContext]; 391 }]; 392 393 return (jint)max; 394 }