/** * Initializes a new OGLContext, which includes the native GLXContext handle * and some other important information such as the associated GLXFBConfig. * If sharedctx is non-null, its texture objects will be shared with the newly * created GLXContext. If useDisposer is JNI_TRUE, a new DisposerTarget * (with the current Java-level thread object as the referent) will be * created and enqueued in the Disposer, so that this OGLContext will be * disposed of properly when its associated thread exits. Contexts that are * intended to remain for the lifetime of the app (such as the sharedContext) * should specify JNI_FALSE for useDisposer. */ OGLContext * GLXGC_InitOGLContext(JNIEnv *env, GLXGraphicsConfigInfo *glxinfo, GLXContext sharedctx, jboolean useDisposer) { OGLContext *oglc; GLXCtxInfo *ctxinfo; GLXFBConfig fbconfig; GLXContext context; static jboolean firstTime = JNI_TRUE; J2dTraceLn(J2D_TRACE_INFO, "in GLXGC_InitOGLContext"); oglc = (OGLContext *)malloc(sizeof(OGLContext)); if (oglc == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "could not allocate memory for oglc"); return NULL; } memset(oglc, 0, sizeof(OGLContext)); ctxinfo = (GLXCtxInfo *)malloc(sizeof(GLXCtxInfo)); if (ctxinfo == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "could not allocate memory for ctxinfo"); free(oglc); return NULL; } fbconfig = GLXGC_InitFBConfig(env, glxinfo->screen, glxinfo->visual); if (fbconfig == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not create new GLX fbconfig"); free(oglc); free(ctxinfo); return NULL; } // REMIND: we cannot rely on direct contexts when rendering to pixmaps context = j2d_glXCreateNewContext(awt_display, fbconfig, GLX_RGBA_TYPE, sharedctx, GL_TRUE); if (context == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not create new GLX context"); free(oglc); free(ctxinfo); return NULL; } ctxinfo->fbconfig = fbconfig; ctxinfo->context = context; oglc->ctxInfo = ctxinfo; oglc->extInfo = &glxinfo->extInfo; // initialize this value to 1.0f as it is sometimes used when uploading // textures (see OGLBlitLoops_Blit()), and in the case of the shared // context, we skip the InitComposite() step that would otherwise // initialize the oglc->extraAlpha value... oglc->extraAlpha = 1.0f; /** * REMIND: The following is a total hack. The first time we enter * this method, we must be on the main thread attempting to initialize * the default GraphicsConfig. Each time we enter this method, we would * like to upcall to the static EventQueue.isDispatchThread() method. * But the first time we call that static method, we may end up implicitly * loading MToolkit, which will also attempt to call getDefaultConfig(). * But since we still haven't fully initialized the default config, we * re-enter the getDefaultConfig() method (in the same thread), and then * come down through this same method. JNI doesn't seem to like this * situation, and we end up with a seg fault. This may be a JNI bug, * but for now we'll work around it, by avoiding the upcall the first * time around. After that, we should be able to make this upcall without * the nasty side effects. */ if (firstTime) { oglc->onJED = JNI_FALSE; firstTime = JNI_FALSE; } else { oglc->onJED = JNU_CallStaticMethodByName(env, NULL, "java/awt/EventQueue", "isDispatchThread", "()Z").z; } if (useDisposer) { // initialize a new Disposer target (when the Java-level thread object // is about to go away, Disposer will invoke our native dispose // method, which destroys this OGLContext and its associated entries) jobject thread = awtJNI_GetCurrentThread(env); if (thread == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "could not fetch current thread"); free(oglc); free(ctxinfo); return NULL; } Disposer_AddRecord(env, thread, GLXGC_DisposeOGLContext, ptr_to_jlong(oglc)); } return oglc; }
/** * Determines whether the GLX pipeline can be used for a given GraphicsConfig * provided its screen number and visual ID. If the minimum requirements are * met, the native GLXGraphicsConfigInfo structure is initialized for this * GraphicsConfig with the necessary information (pthread key, GLXFBConfig, * etc.) and a pointer to this structure is returned as a jlong. If * initialization fails at any point, zero is returned, indicating that GLX * cannot be used for this GraphicsConfig (we should fallback on the existing * X11 pipeline). */ static jlong GLXGC_GetGLXConfigInfo(JNIEnv *env, jint screennum, jint visnum) { GLXFBConfig fbconfig; GLXContext context; GLXPbuffer glxpbuffer; int pbattrlist[] = {GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, GLX_PRESERVED_CONTENTS, GL_FALSE, 0}; GLXGraphicsConfigInfo *glxinfo; int db; const unsigned char *versionstr; J2dTraceLn(J2D_TRACE_INFO, "in GLXGC_GetGLXConfigInfo"); fbconfig = GLXGC_InitFBConfig(env, screennum, visnum); if (fbconfig == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not create fbconfig"); return 0; } glxinfo = (GLXGraphicsConfigInfo *)malloc(sizeof(GLXGraphicsConfigInfo)); if (glxinfo == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "could not allocate memory for glxinfo"); return 0; } // create a temporary context, used for querying OpenGL version and // extensions context = j2d_glXCreateNewContext(awt_display, fbconfig, GLX_RGBA_TYPE, NULL, GL_TRUE); if (context == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not create temp GLX context"); free(glxinfo); return 0; } // this is pretty sketchy, but it seems to be the easiest way to create // some form of GLXDrawable using only the display and a GLXFBConfig // (in order to make the context current for checking the version, // extensions, etc)... glxpbuffer = j2d_glXCreatePbuffer(awt_display, fbconfig, pbattrlist); if (glxpbuffer == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not create scratch pbuffer"); j2d_glXDestroyContext(awt_display, context); free(glxinfo); return 0; } // the temporary context must be made current before we can query the // version and extension strings j2d_glXMakeContextCurrent(awt_display, glxpbuffer, glxpbuffer, context); versionstr = j2d_glGetString(GL_VERSION); OGLContext_GetExtensionInfo(&glxinfo->extInfo); // destroy the temporary resources j2d_glXMakeContextCurrent(awt_display, None, None, NULL); j2d_glXDestroyPbuffer(awt_display, glxpbuffer); j2d_glXDestroyContext(awt_display, context); // invalidate the current context OGLContext_InvalidateCurrentContext(env); J2dTraceLn(J2D_TRACE_VERBOSE, "finished with temporary pbuffer/context"); J2dTraceLn1(J2D_TRACE_INFO, "OpenGL version: %s", versionstr); if (!OGLContext_IsVersionSupported(versionstr)) { J2dTraceLn(J2D_TRACE_ERROR, "invalid OpenGL version; 1.2 is required"); free(glxinfo); return 0; } J2dTraceLn(J2D_TRACE_VERBOSE, "successfully finished checking dependencies"); j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_DOUBLEBUFFER, &db); glxinfo->screen = screennum; glxinfo->visual = visnum; glxinfo->fbconfig = fbconfig; glxinfo->isDoubleBuffered = db; // create the single shared context (if it hasn't been created already) if (sharedContext == NULL) { if (GLXGC_InitSharedContext(env, glxinfo) == SD_FAILURE) { J2dTraceLn(J2D_TRACE_ERROR, "could not init shared context"); free(glxinfo); return 0; } } return ptr_to_jlong(glxinfo); }
/** * Determines whether the GLX pipeline can be used for a given GraphicsConfig * provided its screen number and visual ID. If the minimum requirements are * met, the native GLXGraphicsConfigInfo structure is initialized for this * GraphicsConfig with the necessary information (GLXFBConfig, etc.) * and a pointer to this structure is returned as a jlong. If * initialization fails at any point, zero is returned, indicating that GLX * cannot be used for this GraphicsConfig (we should fallback on the existing * X11 pipeline). */ JNIEXPORT jlong JNICALL Java_sun_java2d_opengl_GLXGraphicsConfig_getGLXConfigInfo(JNIEnv *env, jclass glxgc, jint screennum, jint visnum) { #ifndef HEADLESS OGLContext *oglc; GLXFBConfig fbconfig; GLXContext context; GLXPbuffer scratch; GLXGraphicsConfigInfo *glxinfo; jint caps = CAPS_EMPTY; int db, alpha; const unsigned char *versionstr; J2dRlsTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getGLXConfigInfo"); if (usingXinerama) { // when Xinerama is enabled, the screen ID needs to be 0 screennum = 0; } fbconfig = GLXGC_InitFBConfig(env, screennum, (VisualID)visnum); if (fbconfig == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "GLXGraphicsConfig_getGLXConfigInfo: could not create fbconfig"); return 0L; } if (sharedContext == 0) { // create the one shared context sharedContext = j2d_glXCreateNewContext(awt_display, fbconfig, GLX_RGBA_TYPE, 0, GL_TRUE); if (sharedContext == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "GLXGraphicsConfig_getGLXConfigInfo: could not create shared context"); return 0L; } } // create the GLXContext for this GLXGraphicsConfig context = j2d_glXCreateNewContext(awt_display, fbconfig, GLX_RGBA_TYPE, sharedContext, GL_TRUE); if (context == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "GLXGraphicsConfig_getGLXConfigInfo: could not create GLX context"); return 0L; } // this is pretty sketchy, but it seems to be the easiest way to create // some form of GLXDrawable using only the display and a GLXFBConfig // (in order to make the context current for checking the version, // extensions, etc)... scratch = GLXGC_InitScratchPbuffer(fbconfig); if (scratch == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "GLXGraphicsConfig_getGLXConfigInfo: could not create scratch pbuffer"); j2d_glXDestroyContext(awt_display, context); return 0L; } // the context must be made current before we can query the // version and extension strings j2d_glXMakeContextCurrent(awt_display, scratch, scratch, context); #ifdef __sparc /* * 6438225: The software rasterizer used by Sun's OpenGL libraries * for certain boards has quality issues, and besides, performance * of these boards is not high enough to justify the use of the * OpenGL-based Java 2D pipeline. If we detect one of the following * boards via the GL_RENDERER string, just give up: * - FFB[2[+]] ("Creator[3D]") * - PGX-series ("m64") * - AFB ("Elite3D") */ { const char *renderer = (const char *)j2d_glGetString(GL_RENDERER); J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "GLXGraphicsConfig_getGLXConfigInfo: detected renderer (%s)", (renderer == NULL) ? "null" : renderer); if (renderer == NULL || strncmp(renderer, "Creator", 7) == 0 || strncmp(renderer, "SUNWm64", 7) == 0 || strncmp(renderer, "Elite", 5) == 0) { J2dRlsTraceLn1(J2D_TRACE_ERROR, "GLXGraphicsConfig_getGLXConfigInfo: unsupported board (%s)", (renderer == NULL) ? "null" : renderer); j2d_glXMakeContextCurrent(awt_display, None, None, NULL); j2d_glXDestroyPbuffer(awt_display, scratch); j2d_glXDestroyContext(awt_display, context); return 0L; } } #endif /* __sparc */ versionstr = j2d_glGetString(GL_VERSION); OGLContext_GetExtensionInfo(env, &caps); // destroy the temporary resources j2d_glXMakeContextCurrent(awt_display, None, None, NULL); J2dRlsTraceLn1(J2D_TRACE_INFO, "GLXGraphicsConfig_getGLXConfigInfo: OpenGL version=%s", (versionstr == NULL) ? "null" : (char *)versionstr); if (!OGLContext_IsVersionSupported(versionstr)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "GLXGraphicsConfig_getGLXConfigInfo: OpenGL 1.2 is required"); j2d_glXDestroyPbuffer(awt_display, scratch); j2d_glXDestroyContext(awt_display, context); return 0L; } // get config-specific capabilities j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_DOUBLEBUFFER, &db); if (db) { caps |= CAPS_DOUBLEBUFFERED; } j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_ALPHA_SIZE, &alpha); if (alpha > 0) { caps |= CAPS_STORED_ALPHA; } // initialize the OGLContext, which wraps the GLXFBConfig and GLXContext oglc = GLXGC_InitOGLContext(fbconfig, context, scratch, caps); if (oglc == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "GLXGraphicsConfig_getGLXConfigInfo: could not create oglc"); j2d_glXDestroyPbuffer(awt_display, scratch); j2d_glXDestroyContext(awt_display, context); return 0L; } J2dTraceLn(J2D_TRACE_VERBOSE, "GLXGraphicsConfig_getGLXConfigInfo: finished checking dependencies"); // create the GLXGraphicsConfigInfo record for this config glxinfo = (GLXGraphicsConfigInfo *)malloc(sizeof(GLXGraphicsConfigInfo)); if (glxinfo == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "GLXGraphicsConfig_getGLXConfigInfo: could not allocate memory for glxinfo"); GLXGC_DestroyOGLContext(oglc); return 0L; } glxinfo->screen = screennum; glxinfo->visual = visnum; glxinfo->context = oglc; glxinfo->fbconfig = fbconfig; return ptr_to_jlong(glxinfo); #else return 0L; #endif /* !HEADLESS */ }