1 /*
   2  * Copyright (c) 2011, 2020, 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 /**
  38  * Disposes all memory and resources associated with the given
  39  * CGLGraphicsConfigInfo (including its native OGLContext data).
  40  */
  41 void
  42 OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo)
  43 {
  44     J2dTraceLn(J2D_TRACE_INFO, "OGLGC_DestroyOGLGraphicsConfig");
  45 
  46     CGLGraphicsConfigInfo *cglinfo =
  47         (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
  48     if (cglinfo == NULL) {
  49         J2dRlsTraceLn(J2D_TRACE_ERROR,
  50                       "OGLGC_DestroyOGLGraphicsConfig: info is null");
  51         return;
  52     }
  53 
  54     OGLContext *oglc = (OGLContext*)cglinfo->context;
  55     if (oglc != NULL) {
  56         OGLContext_DestroyContextResources(oglc);
  57 
  58         CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;
  59         if (ctxinfo != NULL) {
  60             NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  61             [NSOpenGLContext clearCurrentContext];
  62             [ctxinfo->context clearDrawable];
  63             [ctxinfo->context release];
  64             if (ctxinfo->scratchSurface != 0) {
  65                 [ctxinfo->scratchSurface release];
  66             }
  67             [pool drain];
  68             free(ctxinfo);
  69             oglc->ctxInfo = NULL;
  70         }
  71         cglinfo->context = NULL;
  72     }
  73 
  74     free(cglinfo);
  75 }
  76 
  77 /**
  78  * This is a globally shared context used when creating textures.  When any
  79  * new contexts are created, they specify this context as the "share list"
  80  * context, which means any texture objects created when this shared context
  81  * is current will be available to any other context in any other thread.
  82  */
  83 NSOpenGLContext *sharedContext = NULL;
  84 NSOpenGLPixelFormat *sharedPixelFormat = NULL;
  85 
  86 /**
  87  * Attempts to initialize CGL and the core OpenGL library.
  88  */
  89 JNIEXPORT jboolean JNICALL
  90 Java_sun_java2d_opengl_CGLGraphicsConfig_initCGL
  91     (JNIEnv *env, jclass cglgc)
  92 {
  93     J2dRlsTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_initCGL");
  94 
  95     if (!OGLFuncs_OpenLibrary()) {
  96         return JNI_FALSE;
  97     }
  98 
  99     if (!OGLFuncs_InitPlatformFuncs() ||
 100         !OGLFuncs_InitBaseFuncs() ||
 101         !OGLFuncs_InitExtFuncs())
 102     {
 103         OGLFuncs_CloseLibrary();
 104         return JNI_FALSE;
 105     }
 106     return JNI_TRUE;
 107 }
 108 
 109 /**
 110  * Determines whether the CGL pipeline can be used for a given GraphicsConfig.
 111  * If the minimum requirements are met, the native CGLGraphicsConfigInfo
 112  * structure is initialized for this GraphicsConfig with the necessary
 113  * information and a pointer to this structure is returned as a jlong. If
 114  * initialization fails at any point, zero is returned, indicating that CGL
 115  * cannot be used for this GraphicsConfig (we should fallback on an existing 2D
 116  * pipeline).
 117  */
 118 JNIEXPORT jlong JNICALL
 119 Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo
 120     (JNIEnv *env, jclass cglgc)
 121 {
 122     __block jlong ret = 0L;
 123     JNF_COCOA_ENTER(env);
 124     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 125         JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 126 
 127         J2dRlsTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getCGLConfigInfo");
 128 
 129         NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
 130 
 131         if (sharedContext == NULL) {
 132 
 133             NSOpenGLPixelFormatAttribute attrs[] = {
 134                 NSOpenGLPFAAllowOfflineRenderers,
 135                 NSOpenGLPFAClosestPolicy,
 136                 NSOpenGLPFAWindow,
 137                 NSOpenGLPFAPixelBuffer,
 138                 NSOpenGLPFADoubleBuffer,
 139                 NSOpenGLPFAColorSize, 32,
 140                 NSOpenGLPFAAlphaSize, 8,
 141                 NSOpenGLPFADepthSize, 16,
 142                 0
 143             };
 144 
 145             sharedPixelFormat =
 146                 [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
 147             if (sharedPixelFormat == nil) {
 148                 J2dRlsTraceLn(J2D_TRACE_ERROR,
 149                               "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL");
 150                return;
 151             }
 152 
 153             sharedContext =
 154                 [[NSOpenGLContext alloc]
 155                     initWithFormat:sharedPixelFormat
 156                     shareContext: NULL];
 157             if (sharedContext == nil) {
 158                 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLContext is NULL");
 159                 return;
 160             }
 161         }
 162 
 163 #if USE_NSVIEW_FOR_SCRATCH
 164         NSRect contentRect = NSMakeRect(0, 0, 64, 64);
 165         NSWindow *window =
 166             [[NSWindow alloc]
 167                 initWithContentRect: contentRect
 168                 styleMask: NSBorderlessWindowMask
 169                 backing: NSBackingStoreBuffered
 170                 defer: false];
 171         if (window == nil) {
 172             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSWindow is NULL");
 173             return;
 174         }
 175 
 176         NSView *scratchSurface =
 177             [[NSView alloc]
 178                 initWithFrame: contentRect];
 179         if (scratchSurface == nil) {
 180             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSView is NULL");
 181             return;
 182         }
 183         [window setContentView: scratchSurface];
 184 #else
 185         NSOpenGLPixelBuffer *scratchSurface =
 186             [[NSOpenGLPixelBuffer alloc]
 187                 initWithTextureTarget:GL_TEXTURE_2D
 188                 textureInternalFormat:GL_RGB
 189                 textureMaxMipMapLevel:0
 190                 pixelsWide:64
 191                 pixelsHigh:64];
 192 #endif
 193 
 194         NSOpenGLContext *context =
 195             [[NSOpenGLContext alloc]
 196                 initWithFormat: sharedPixelFormat
 197                 shareContext: sharedContext];
 198         if (context == nil) {
 199             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSOpenGLContext is NULL");
 200             return;
 201         }
 202 
 203         GLint contextVirtualScreen = [context currentVirtualScreen];
 204 #if USE_NSVIEW_FOR_SCRATCH
 205         [context setView: scratchSurface];
 206 #else
 207         [context
 208             setPixelBuffer: scratchSurface
 209             cubeMapFace:0
 210             mipMapLevel:0
 211             currentVirtualScreen: contextVirtualScreen];
 212 #endif
 213         [context makeCurrentContext];
 214 
 215         // get version and extension strings
 216         const unsigned char *versionstr = j2d_glGetString(GL_VERSION);
 217         if (!OGLContext_IsVersionSupported(versionstr)) {
 218             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL 1.2 is required");
 219             [NSOpenGLContext clearCurrentContext];
 220             return;
 221         }
 222         J2dRlsTraceLn1(J2D_TRACE_INFO, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL version=%s", versionstr);
 223 
 224         jint caps = CAPS_EMPTY;
 225         OGLContext_GetExtensionInfo(env, &caps);
 226 
 227         GLint value = 0;
 228         [sharedPixelFormat
 229             getValues: &value
 230             forAttribute: NSOpenGLPFADoubleBuffer
 231             forVirtualScreen: contextVirtualScreen];
 232         if (value != 0) {
 233             caps |= CAPS_DOUBLEBUFFERED;
 234         }
 235 
 236         J2dRlsTraceLn1(J2D_TRACE_INFO,
 237                        "CGLGraphicsConfig_getCGLConfigInfo: db=%d",
 238                        (caps & CAPS_DOUBLEBUFFERED) != 0);
 239 
 240         // remove before shipping (?)
 241 #if 1
 242         [sharedPixelFormat
 243             getValues: &value
 244             forAttribute: NSOpenGLPFAAccelerated
 245             forVirtualScreen: contextVirtualScreen];
 246         if (value == 0) {
 247             [sharedPixelFormat
 248                 getValues: &value
 249                 forAttribute: NSOpenGLPFARendererID
 250                 forVirtualScreen: contextVirtualScreen];
 251             fprintf(stderr, "WARNING: GL pipe is running in software mode (Renderer ID=0x%x)\n", (int)value);
 252         }
 253 #endif
 254         CGLCtxInfo *ctxinfo = (CGLCtxInfo *)malloc(sizeof(CGLCtxInfo));
 255         if (ctxinfo == NULL) {
 256             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for ctxinfo");
 257             [NSOpenGLContext clearCurrentContext];
 258             return;
 259         }
 260         memset(ctxinfo, 0, sizeof(CGLCtxInfo));
 261         ctxinfo->context = context;
 262         ctxinfo->scratchSurface = scratchSurface;
 263 
 264         OGLContext *oglc = (OGLContext *)malloc(sizeof(OGLContext));
 265         if (oglc == 0L) {
 266             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for oglc");
 267             [NSOpenGLContext clearCurrentContext];
 268             free(ctxinfo);
 269             return;
 270         }
 271         memset(oglc, 0, sizeof(OGLContext));
 272         oglc->ctxInfo = ctxinfo;
 273         oglc->caps = caps;
 274 
 275         // create the CGLGraphicsConfigInfo record for this config
 276         CGLGraphicsConfigInfo *cglinfo = (CGLGraphicsConfigInfo *)malloc(sizeof(CGLGraphicsConfigInfo));
 277         if (cglinfo == NULL) {
 278             J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: could not allocate memory for cglinfo");
 279             [NSOpenGLContext clearCurrentContext];
 280             free(oglc);
 281             free(ctxinfo);
 282             return;
 283         }
 284         memset(cglinfo, 0, sizeof(CGLGraphicsConfigInfo));
 285         cglinfo->context = oglc;
 286 
 287         [NSOpenGLContext clearCurrentContext];
 288         ret = ptr_to_jlong(cglinfo);
 289         [pool drain];
 290     }];
 291     JNF_COCOA_EXIT(env);
 292     return ret;
 293 }
 294 
 295 JNIEXPORT jint JNICALL
 296 Java_sun_java2d_opengl_CGLGraphicsConfig_getOGLCapabilities
 297     (JNIEnv *env, jclass cglgc, jlong configInfo)
 298 {
 299     J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getOGLCapabilities");
 300 
 301     CGLGraphicsConfigInfo *cglinfo =
 302         (CGLGraphicsConfigInfo *)jlong_to_ptr(configInfo);
 303     if ((cglinfo == NULL) || (cglinfo->context == NULL)) {
 304         return CAPS_EMPTY;
 305     } else {
 306         return cglinfo->context->caps;
 307     }
 308 }
 309 
 310 JNIEXPORT jint JNICALL
 311 Java_sun_java2d_opengl_CGLGraphicsConfig_nativeGetMaxTextureSize
 312     (JNIEnv *env, jclass cglgc)
 313 {
 314     J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_nativeGetMaxTextureSize");
 315 
 316     __block int max = 0;
 317 
 318     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 319         [sharedContext makeCurrentContext];
 320         j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
 321         [NSOpenGLContext clearCurrentContext];
 322     }];
 323 
 324     return (jint)max;
 325 }