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             J2dRlsTraceLn(J2D_TRACE_ERROR, 
 187                           "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL");
 188             J2dRlsTraceLn1(J2D_TRACE_INFO, "glMask %0x\n",glMask);
 189             NSOpenGLPixelFormatAttribute attrs1[] = {
 190               NSOpenGLPFAAllowOfflineRenderers,
 191               NSOpenGLPFAClosestPolicy,
 192               NSOpenGLPFAWindow,
 193               NSOpenGLPFAPixelBuffer,
 194               NSOpenGLPFADoubleBuffer,
 195               NSOpenGLPFAColorSize, 32,
 196               NSOpenGLPFAAlphaSize, 8,
 197               NSOpenGLPFADepthSize, 16,
 198               0
 199             };
 200             sharedPixelFormat =
 201                [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs1];
 202             if (sharedPixelFormat == nil) {
 203                 J2dRlsTraceLn(J2D_TRACE_ERROR, 
 204                               "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL ");
 205                 
 206                [argValue addObject: [NSNumber numberWithLong: 0L]];
 207                return;
 208             }
 209         }
 210 
 211         sharedContext =
 212             [[NSOpenGLContext alloc]
 213                 initWithFormat:sharedPixelFormat
 214                 shareContext: NULL];
 215         if (sharedContext == nil) {
 216             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLContext is NULL");
 217             [argValue addObject: [NSNumber numberWithLong: 0L]];
 218             return;
 219         }
 220     }
 221 
 222 #if USE_NSVIEW_FOR_SCRATCH
 223     NSRect contentRect = NSMakeRect(0, 0, 64, 64);
 224     NSWindow *window =
 225         [[NSWindow alloc]
 226             initWithContentRect: contentRect
 227             styleMask: NSBorderlessWindowMask
 228             backing: NSBackingStoreBuffered
 229             defer: false];
 230     if (window == nil) {
 231         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSWindow is NULL");
 232         [argValue addObject: [NSNumber numberWithLong: 0L]];
 233         return;
 234     }
 235 
 236     NSView *scratchSurface =
 237         [[NSView alloc]
 238             initWithFrame: contentRect];
 239     if (scratchSurface == nil) {
 240         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSView is NULL");
 241         [argValue addObject: [NSNumber numberWithLong: 0L]];
 242         return;
 243     }
 244     [window setContentView: scratchSurface];
 245 #else
 246     NSOpenGLPixelBuffer *scratchSurface =
 247         [[NSOpenGLPixelBuffer alloc]
 248             initWithTextureTarget:GL_TEXTURE_2D
 249             textureInternalFormat:GL_RGB
 250             textureMaxMipMapLevel:0
 251             pixelsWide:64
 252             pixelsHigh:64];
 253 #endif
 254 
 255     NSOpenGLContext *context =
 256         [[NSOpenGLContext alloc]
 257             initWithFormat: sharedPixelFormat
 258             shareContext: sharedContext];
 259     if (context == nil) {
 260         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSOpenGLContext is NULL");
 261         [argValue addObject: [NSNumber numberWithLong: 0L]];
 262         return;
 263     }
 264 
 265     GLint contextVirtualScreen = [context currentVirtualScreen];
 266 #if USE_NSVIEW_FOR_SCRATCH
 267     [context setView: scratchSurface];
 268 #else
 269     [context
 270         setPixelBuffer: scratchSurface
 271         cubeMapFace:0
 272         mipMapLevel:0
 273         currentVirtualScreen: contextVirtualScreen];
 274 #endif
 275     [context makeCurrentContext];
 276 
 277     // get version and extension strings
 278     const unsigned char *versionstr = j2d_glGetString(GL_VERSION);
 279     if (!OGLContext_IsVersionSupported(versionstr)) {
 280         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL 1.2 is required");
 281         [NSOpenGLContext clearCurrentContext];
 282         [argValue addObject: [NSNumber numberWithLong: 0L]];
 283         return;
 284     }
 285     J2dRlsTraceLn1(J2D_TRACE_INFO, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL version=%s", versionstr);
 286 
 287     jint caps = CAPS_EMPTY;
 288     OGLContext_GetExtensionInfo(env, &caps);
 289 
 290     GLint value = 0;
 291     [sharedPixelFormat
 292         getValues: &value
 293         forAttribute: NSOpenGLPFADoubleBuffer
 294         forVirtualScreen: contextVirtualScreen];
 295     if (value != 0) {
 296         caps |= CAPS_DOUBLEBUFFERED;
 297     }
 298 
 299     J2dRlsTraceLn1(J2D_TRACE_INFO,
 300                    "CGLGraphicsConfig_getCGLConfigInfo: db=%d",
 301                    (caps & CAPS_DOUBLEBUFFERED) != 0);
 302 
 303     // remove before shipping (?)
 304 #if 1
 305     [sharedPixelFormat
 306         getValues: &value
 307         forAttribute: NSOpenGLPFAAccelerated
 308         forVirtualScreen: contextVirtualScreen];
 309     if (value == 0) {
 310         [sharedPixelFormat
 311             getValues: &value
 312             forAttribute: NSOpenGLPFARendererID
 313             forVirtualScreen: contextVirtualScreen];
 314         fprintf(stderr, "WARNING: GL pipe is running in software mode (Renderer ID=0x%x)\n", (int)value);
 315     }
 316 #endif
 317 
 318     // 0: the buffers are swapped with no regard to the vertical refresh rate
 319     // 1: the buffers are swapped only during the vertical retrace
 320     GLint params = swapInterval;
 321     [context setValues: &params forParameter: NSOpenGLCPSwapInterval];
 322 
 323     CGLCtxInfo *ctxinfo = (CGLCtxInfo *)malloc(sizeof(CGLCtxInfo));
 324     if (ctxinfo == NULL) {
 325         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for ctxinfo");
 326         [NSOpenGLContext clearCurrentContext];
 327         [argValue addObject: [NSNumber numberWithLong: 0L]];
 328         return;
 329     }
 330     memset(ctxinfo, 0, sizeof(CGLCtxInfo));
 331     ctxinfo->context = context;
 332     ctxinfo->scratchSurface = scratchSurface;
 333 
 334     OGLContext *oglc = (OGLContext *)malloc(sizeof(OGLContext));
 335     if (oglc == 0L) {
 336         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for oglc");
 337         [NSOpenGLContext clearCurrentContext];
 338         free(ctxinfo);
 339         [argValue addObject: [NSNumber numberWithLong: 0L]];
 340         return;
 341     }
 342     memset(oglc, 0, sizeof(OGLContext));
 343     oglc->ctxInfo = ctxinfo;
 344     oglc->caps = caps;
 345 
 346     // create the CGLGraphicsConfigInfo record for this config
 347     CGLGraphicsConfigInfo *cglinfo = (CGLGraphicsConfigInfo *)malloc(sizeof(CGLGraphicsConfigInfo));
 348     if (cglinfo == NULL) {
 349         J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: could not allocate memory for cglinfo");
 350         [NSOpenGLContext clearCurrentContext];
 351         free(oglc);
 352         free(ctxinfo);
 353         [argValue addObject: [NSNumber numberWithLong: 0L]];
 354         return;
 355     }
 356     memset(cglinfo, 0, sizeof(CGLGraphicsConfigInfo));
 357     cglinfo->screen = displayID;
 358     cglinfo->pixfmt = sharedPixelFormat;
 359     cglinfo->context = oglc;
 360 
 361     [NSOpenGLContext clearCurrentContext];
 362     [argValue addObject: [NSNumber numberWithLong:ptr_to_jlong(cglinfo)]];
 363     [pool drain];
 364 }
 365 @end //GraphicsConfigUtil
 366 
 367 JNIEXPORT jint JNICALL
 368 Java_sun_java2d_opengl_CGLGraphicsConfig_getOGLCapabilities
 369     (JNIEnv *env, jclass cglgc, jlong configInfo)
 370 {
 371     J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getOGLCapabilities");
 372 
 373     CGLGraphicsConfigInfo *cglinfo =
 374         (CGLGraphicsConfigInfo *)jlong_to_ptr(configInfo);
 375     if ((cglinfo == NULL) || (cglinfo->context == NULL)) {
 376         return CAPS_EMPTY;
 377     } else {
 378         return cglinfo->context->caps;
 379     }
 380 }
 381 
 382 JNIEXPORT jint JNICALL
 383 Java_sun_java2d_opengl_CGLGraphicsConfig_nativeGetMaxTextureSize
 384     (JNIEnv *env, jclass cglgc)
 385 {
 386     J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_nativeGetMaxTextureSize");
 387 
 388     __block int max = 0;
 389 
 390     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 391         [sharedContext makeCurrentContext];
 392         j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
 393         [NSOpenGLContext clearCurrentContext];
 394     }];
 395 
 396     return (jint)max;
 397 }