| /* | |
| * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| #import "sun_java2d_opengl_CGLGraphicsConfig.h" | |
| #import "CGLGraphicsConfig.h" | |
| #import "CGLSurfaceData.h" | |
| #import "ThreadUtilities.h" | |
| #import "JNIUtilities.h" | |
| #import <stdlib.h> | |
| #import <string.h> | |
| #import <ApplicationServices/ApplicationServices.h> | |
| /** | |
| * Disposes all memory and resources associated with the given | |
| * CGLGraphicsConfigInfo (including its native OGLContext data). | |
| */ | |
| void | |
| OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo) | |
| { | |
| J2dTraceLn(J2D_TRACE_INFO, "OGLGC_DestroyOGLGraphicsConfig"); | |
| CGLGraphicsConfigInfo *cglinfo = | |
| (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); | |
| if (cglinfo == NULL) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, | |
| "OGLGC_DestroyOGLGraphicsConfig: info is null"); | |
| return; | |
| } | |
| OGLContext *oglc = (OGLContext*)cglinfo->context; | |
| if (oglc != NULL) { | |
| OGLContext_DestroyContextResources(oglc); | |
| CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; | |
| if (ctxinfo != NULL) { | |
| NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
| [NSOpenGLContext clearCurrentContext]; | |
| [ctxinfo->context clearDrawable]; | |
| [ctxinfo->context release]; | |
| if (ctxinfo->scratchSurface != 0) { | |
| [ctxinfo->scratchSurface release]; | |
| } | |
| [pool drain]; | |
| free(ctxinfo); | |
| oglc->ctxInfo = NULL; | |
| } | |
| cglinfo->context = NULL; | |
| } | |
| free(cglinfo); | |
| } | |
| /** | |
| * This is a globally shared context used when creating textures. When any | |
| * new contexts are created, they specify this context as the "share list" | |
| * context, which means any texture objects created when this shared context | |
| * is current will be available to any other context in any other thread. | |
| */ | |
| NSOpenGLContext *sharedContext = NULL; | |
| NSOpenGLPixelFormat *sharedPixelFormat = NULL; | |
| /** | |
| * Attempts to initialize CGL and the core OpenGL library. | |
| */ | |
| JNIEXPORT jboolean JNICALL | |
| Java_sun_java2d_opengl_CGLGraphicsConfig_initCGL | |
| (JNIEnv *env, jclass cglgc) | |
| { | |
| J2dRlsTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_initCGL"); | |
| if (!OGLFuncs_OpenLibrary()) { | |
| return JNI_FALSE; | |
| } | |
| if (!OGLFuncs_InitPlatformFuncs() || | |
| !OGLFuncs_InitBaseFuncs() || | |
| !OGLFuncs_InitExtFuncs()) | |
| { | |
| OGLFuncs_CloseLibrary(); | |
| return JNI_FALSE; | |
| } | |
| return JNI_TRUE; | |
| } | |
| /** | |
| * Determines whether the CGL pipeline can be used for a given GraphicsConfig. | |
| * If the minimum requirements are met, the native CGLGraphicsConfigInfo | |
| * structure is initialized for this GraphicsConfig with the necessary | |
| * information and a pointer to this structure is returned as a jlong. If | |
| * initialization fails at any point, zero is returned, indicating that CGL | |
| * cannot be used for this GraphicsConfig (we should fallback on an existing 2D | |
| * pipeline). | |
| */ | |
| JNIEXPORT jlong JNICALL | |
| Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo | |
| (JNIEnv *env, jclass cglgc) | |
| { | |
| __block jlong ret = 0L; | |
| JNI_COCOA_ENTER(env); | |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ | |
| JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; | |
| J2dRlsTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getCGLConfigInfo"); | |
| NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; | |
| if (sharedContext == NULL) { | |
| NSOpenGLPixelFormatAttribute attrs[] = { | |
| NSOpenGLPFAAllowOfflineRenderers, | |
| NSOpenGLPFAClosestPolicy, | |
| NSOpenGLPFAWindow, | |
| NSOpenGLPFAPixelBuffer, | |
| NSOpenGLPFADoubleBuffer, | |
| NSOpenGLPFAColorSize, 32, | |
| NSOpenGLPFAAlphaSize, 8, | |
| NSOpenGLPFADepthSize, 16, | |
| 0 | |
| }; | |
| sharedPixelFormat = | |
| [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; | |
| if (sharedPixelFormat == nil) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, | |
| "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL"); | |
| return; | |
| } | |
| sharedContext = | |
| [[NSOpenGLContext alloc] | |
| initWithFormat:sharedPixelFormat | |
| shareContext: NULL]; | |
| if (sharedContext == nil) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLContext is NULL"); | |
| return; | |
| } | |
| } | |
| #if USE_NSVIEW_FOR_SCRATCH | |
| NSRect contentRect = NSMakeRect(0, 0, 64, 64); | |
| NSWindow *window = | |
| [[NSWindow alloc] | |
| initWithContentRect: contentRect | |
| styleMask: NSWindowStyleMaskBorderless | |
| backing: NSBackingStoreBuffered | |
| defer: false]; | |
| if (window == nil) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSWindow is NULL"); | |
| return; | |
| } | |
| NSView *scratchSurface = | |
| [[NSView alloc] | |
| initWithFrame: contentRect]; | |
| if (scratchSurface == nil) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSView is NULL"); | |
| return; | |
| } | |
| [window setContentView: scratchSurface]; | |
| #else | |
| NSOpenGLPixelBuffer *scratchSurface = | |
| [[NSOpenGLPixelBuffer alloc] | |
| initWithTextureTarget:GL_TEXTURE_2D | |
| textureInternalFormat:GL_RGB | |
| textureMaxMipMapLevel:0 | |
| pixelsWide:64 | |
| pixelsHigh:64]; | |
| #endif | |
| NSOpenGLContext *context = | |
| [[NSOpenGLContext alloc] | |
| initWithFormat: sharedPixelFormat | |
| shareContext: sharedContext]; | |
| if (context == nil) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: NSOpenGLContext is NULL"); | |
| return; | |
| } | |
| GLint contextVirtualScreen = [context currentVirtualScreen]; | |
| #if USE_NSVIEW_FOR_SCRATCH | |
| [context setView: scratchSurface]; | |
| #else | |
| [context | |
| setPixelBuffer: scratchSurface | |
| cubeMapFace:0 | |
| mipMapLevel:0 | |
| currentVirtualScreen: contextVirtualScreen]; | |
| #endif | |
| [context makeCurrentContext]; | |
| // get version and extension strings | |
| const unsigned char *versionstr = j2d_glGetString(GL_VERSION); | |
| if (!OGLContext_IsVersionSupported(versionstr)) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL 1.2 is required"); | |
| [NSOpenGLContext clearCurrentContext]; | |
| return; | |
| } | |
| J2dRlsTraceLn1(J2D_TRACE_INFO, "CGLGraphicsConfig_getCGLConfigInfo: OpenGL version=%s", versionstr); | |
| jint caps = CAPS_EMPTY; | |
| OGLContext_GetExtensionInfo(env, &caps); | |
| GLint value = 0; | |
| [sharedPixelFormat | |
| getValues: &value | |
| forAttribute: NSOpenGLPFADoubleBuffer | |
| forVirtualScreen: contextVirtualScreen]; | |
| if (value != 0) { | |
| caps |= CAPS_DOUBLEBUFFERED; | |
| } | |
| J2dRlsTraceLn1(J2D_TRACE_INFO, | |
| "CGLGraphicsConfig_getCGLConfigInfo: db=%d", | |
| (caps & CAPS_DOUBLEBUFFERED) != 0); | |
| // remove before shipping (?) | |
| #if 1 | |
| [sharedPixelFormat | |
| getValues: &value | |
| forAttribute: NSOpenGLPFAAccelerated | |
| forVirtualScreen: contextVirtualScreen]; | |
| if (value == 0) { | |
| [sharedPixelFormat | |
| getValues: &value | |
| forAttribute: NSOpenGLPFARendererID | |
| forVirtualScreen: contextVirtualScreen]; | |
| fprintf(stderr, "WARNING: GL pipe is running in software mode (Renderer ID=0x%x)\n", (int)value); | |
| } | |
| #endif | |
| CGLCtxInfo *ctxinfo = (CGLCtxInfo *)malloc(sizeof(CGLCtxInfo)); | |
| if (ctxinfo == NULL) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for ctxinfo"); | |
| [NSOpenGLContext clearCurrentContext]; | |
| return; | |
| } | |
| memset(ctxinfo, 0, sizeof(CGLCtxInfo)); | |
| ctxinfo->context = context; | |
| ctxinfo->scratchSurface = scratchSurface; | |
| OGLContext *oglc = (OGLContext *)malloc(sizeof(OGLContext)); | |
| if (oglc == 0L) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGC_InitOGLContext: could not allocate memory for oglc"); | |
| [NSOpenGLContext clearCurrentContext]; | |
| free(ctxinfo); | |
| return; | |
| } | |
| memset(oglc, 0, sizeof(OGLContext)); | |
| oglc->ctxInfo = ctxinfo; | |
| oglc->caps = caps; | |
| // create the CGLGraphicsConfigInfo record for this config | |
| CGLGraphicsConfigInfo *cglinfo = (CGLGraphicsConfigInfo *)malloc(sizeof(CGLGraphicsConfigInfo)); | |
| if (cglinfo == NULL) { | |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: could not allocate memory for cglinfo"); | |
| [NSOpenGLContext clearCurrentContext]; | |
| free(oglc); | |
| free(ctxinfo); | |
| return; | |
| } | |
| memset(cglinfo, 0, sizeof(CGLGraphicsConfigInfo)); | |
| cglinfo->context = oglc; | |
| [NSOpenGLContext clearCurrentContext]; | |
| ret = ptr_to_jlong(cglinfo); | |
| [pool drain]; | |
| }]; | |
| JNI_COCOA_EXIT(env); | |
| return ret; | |
| } | |
| JNIEXPORT jint JNICALL | |
| Java_sun_java2d_opengl_CGLGraphicsConfig_getOGLCapabilities | |
| (JNIEnv *env, jclass cglgc, jlong configInfo) | |
| { | |
| J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getOGLCapabilities"); | |
| CGLGraphicsConfigInfo *cglinfo = | |
| (CGLGraphicsConfigInfo *)jlong_to_ptr(configInfo); | |
| if ((cglinfo == NULL) || (cglinfo->context == NULL)) { | |
| return CAPS_EMPTY; | |
| } else { | |
| return cglinfo->context->caps; | |
| } | |
| } | |
| JNIEXPORT jint JNICALL | |
| Java_sun_java2d_opengl_CGLGraphicsConfig_nativeGetMaxTextureSize | |
| (JNIEnv *env, jclass cglgc) | |
| { | |
| J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_nativeGetMaxTextureSize"); | |
| __block int max = 0; | |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ | |
| [sharedContext makeCurrentContext]; | |
| j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max); | |
| [NSOpenGLContext clearCurrentContext]; | |
| }]; | |
| return (jint)max; | |
| } |