jdk/src/solaris/native/sun/java2d/opengl/GLXGraphicsConfig.c
changeset 2 90ce3da70b43
child 887 0aab8d3fa11a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/java2d/opengl/GLXGraphicsConfig.c	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,672 @@
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "sun_java2d_opengl_GLXGraphicsConfig.h"
+
+#include "jni.h"
+#include "jlong.h"
+#include "GLXGraphicsConfig.h"
+#include "GLXSurfaceData.h"
+#include "awt_GraphicsEnv.h"
+#include "awt_util.h"
+
+#ifndef HEADLESS
+
+extern Bool usingXinerama;
+
+/**
+ * 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.
+ */
+static GLXContext sharedContext = 0;
+
+/**
+ * Attempts to initialize GLX and the core OpenGL library.  For this method
+ * to return JNI_TRUE, the following must be true:
+ *     - libGL must be loaded successfully (via dlopen)
+ *     - all function symbols from libGL must be available and loaded properly
+ *     - the GLX extension must be available through X11
+ *     - client GLX version must be >= 1.3
+ * If any of these requirements are not met, this method will return
+ * JNI_FALSE, indicating there is no hope of using GLX/OpenGL for any
+ * GraphicsConfig in the environment.
+ */
+static jboolean
+GLXGC_InitGLX()
+{
+    int errorbase, eventbase;
+    const char *version;
+
+    J2dRlsTraceLn(J2D_TRACE_INFO, "GLXGC_InitGLX");
+
+    if (!OGLFuncs_OpenLibrary()) {
+        return JNI_FALSE;
+    }
+
+    if (!OGLFuncs_InitPlatformFuncs() ||
+        !OGLFuncs_InitBaseFuncs() ||
+        !OGLFuncs_InitExtFuncs())
+    {
+        OGLFuncs_CloseLibrary();
+        return JNI_FALSE;
+    }
+
+    if (!j2d_glXQueryExtension(awt_display, &errorbase, &eventbase)) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+                      "GLXGC_InitGLX: GLX extension is not present");
+        OGLFuncs_CloseLibrary();
+        return JNI_FALSE;
+    }
+
+    version = j2d_glXGetClientString(awt_display, GLX_VERSION);
+    if (version == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+                      "GLXGC_InitGLX: could not query GLX version");
+        OGLFuncs_CloseLibrary();
+        return JNI_FALSE;
+    }
+
+    // we now only verify that the client GLX version is >= 1.3 (if the
+    // server does not support GLX 1.3, then we will find that out later
+    // when we attempt to create a GLXFBConfig)
+    J2dRlsTraceLn1(J2D_TRACE_INFO,
+                   "GLXGC_InitGLX: client GLX version=%s", version);
+    if (!((version[0] == '1' && version[2] >= '3') || (version[0] > '1'))) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+                      "GLXGC_InitGLX: invalid GLX version; 1.3 is required");
+        OGLFuncs_CloseLibrary();
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+/**
+ * Returns JNI_TRUE if GLX is available for the current display.  Note that
+ * this method will attempt to initialize GLX (and all the necessary function
+ * symbols) if it has not been already.  The AWT_LOCK must be acquired before
+ * calling this method.
+ */
+jboolean
+GLXGC_IsGLXAvailable()
+{
+    static jboolean glxAvailable = JNI_FALSE;
+    static jboolean firstTime = JNI_TRUE;
+
+    J2dTraceLn(J2D_TRACE_INFO, "GLXGC_IsGLXAvailable");
+
+    if (firstTime) {
+        glxAvailable = GLXGC_InitGLX();
+        firstTime = JNI_FALSE;
+    }
+
+    return glxAvailable;
+}
+
+/**
+ * Disposes all memory and resources allocated for the given OGLContext.
+ */
+static void
+GLXGC_DestroyOGLContext(OGLContext *oglc)
+{
+    GLXCtxInfo *ctxinfo;
+
+    J2dTraceLn(J2D_TRACE_INFO, "GLXGC_DestroyOGLContext");
+
+    if (oglc == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+                      "GLXGC_DestroyOGLContext: context is null");
+        return;
+    }
+
+    // at this point, this context will be current to its scratch surface
+    // so the following GL/GLX operations should be safe...
+
+    OGLContext_DestroyContextResources(oglc);
+
+    ctxinfo = (GLXCtxInfo *)oglc->ctxInfo;
+    if (ctxinfo != NULL) {
+        // release the current context before we continue
+        j2d_glXMakeContextCurrent(awt_display, None, None, NULL);
+
+        if (ctxinfo->context != 0) {
+            j2d_glXDestroyContext(awt_display, ctxinfo->context);
+        }
+        if (ctxinfo->scratchSurface != 0) {
+            j2d_glXDestroyPbuffer(awt_display, ctxinfo->scratchSurface);
+        }
+
+        free(ctxinfo);
+    }
+
+    free(oglc);
+}
+
+/**
+ * Disposes all memory and resources associated with the given
+ * GLXGraphicsConfigInfo (including its native OGLContext data).
+ */
+void
+OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo)
+{
+    GLXGraphicsConfigInfo *glxinfo =
+        (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
+
+    J2dTraceLn(J2D_TRACE_INFO, "OGLGC_DestroyOGLGraphicsConfig");
+
+    if (glxinfo == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+                      "OGLGC_DestroyOGLGraphicsConfig: info is null");
+        return;
+    }
+
+    if (glxinfo->context != NULL) {
+        GLXGC_DestroyOGLContext(glxinfo->context);
+    }
+
+    free(glxinfo);
+}
+
+/**
+ * Attempts to create a new GLXFBConfig for the requested screen and visual.
+ * If visualid is 0, this method will iterate through all GLXFBConfigs (if
+ * any) that match the requested attributes and will attempt to find an
+ * fbconfig with a minimal combined depth+stencil buffer.  Note that we
+ * currently only need depth capabilities (for shape clipping purposes), but
+ * glXChooseFBConfig() will often return a list of fbconfigs with the largest
+ * depth buffer (and stencil) sizes at the top of the list.  Therefore, we
+ * scan through the whole list to find the most VRAM-efficient fbconfig.
+ * If visualid is non-zero, the GLXFBConfig associated with the given visual
+ * is chosen (assuming it meets the requested attributes).  If there are no
+ * valid GLXFBConfigs available, this method returns 0.
+ */
+static GLXFBConfig
+GLXGC_InitFBConfig(JNIEnv *env, jint screennum, VisualID visualid)
+{
+    GLXFBConfig *fbconfigs;
+    GLXFBConfig chosenConfig = 0;
+    int nconfs, i;
+    int attrlist[] = {GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT,
+                      GLX_RENDER_TYPE, GLX_RGBA_BIT,
+                      GLX_CONFIG_CAVEAT, GLX_NONE, // avoid "slow" configs
+                      GLX_DEPTH_SIZE, 16, // anything >= 16 will work for us
+                      0};
+
+    // this is the initial minimum value for the combined depth+stencil size
+    // (we initialize it to some absurdly high value; realistic values will
+    // be much less than this number)
+    int minDepthPlusStencil = 512;
+
+    J2dRlsTraceLn2(J2D_TRACE_INFO, "GLXGC_InitFBConfig: scn=%d vis=0x%x",
+                   screennum, visualid);
+
+    // find all fbconfigs for this screen with the provided attributes
+    fbconfigs = j2d_glXChooseFBConfig(awt_display, screennum,
+                                      attrlist, &nconfs);
+
+    if ((fbconfigs == NULL) || (nconfs <= 0)) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+            "GLXGC_InitFBConfig: could not find any valid fbconfigs");
+        return 0;
+    }
+
+    J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  candidate fbconfigs:");
+
+    // iterate through the list of fbconfigs, looking for the one that matches
+    // the requested VisualID and supports RGBA rendering as well as the
+    // creation of windows and pbuffers
+    for (i = 0; i < nconfs; i++) {
+        XVisualInfo *xvi;
+        VisualID fbvisualid;
+        GLXFBConfig fbc = fbconfigs[i];
+
+        // get VisualID from GLXFBConfig
+        xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);
+        if (xvi == NULL) {
+            continue;
+        }
+        fbvisualid = xvi->visualid;
+        XFree(xvi);
+
+        if (visualid == 0 || visualid == fbvisualid) {
+            int dtype, rtype, depth, stencil, db, alpha, gamma;
+
+            // get GLX-specific attributes from GLXFBConfig
+            j2d_glXGetFBConfigAttrib(awt_display, fbc,
+                                     GLX_DRAWABLE_TYPE, &dtype);
+            j2d_glXGetFBConfigAttrib(awt_display, fbc,
+                                     GLX_RENDER_TYPE, &rtype);
+            j2d_glXGetFBConfigAttrib(awt_display, fbc,
+                                     GLX_DEPTH_SIZE, &depth);
+            j2d_glXGetFBConfigAttrib(awt_display, fbc,
+                                     GLX_STENCIL_SIZE, &stencil);
+
+            // these attributes don't affect our decision, but they are
+            // interesting for trace logs, so we will query them anyway
+            j2d_glXGetFBConfigAttrib(awt_display, fbc,
+                                     GLX_DOUBLEBUFFER, &db);
+            j2d_glXGetFBConfigAttrib(awt_display, fbc,
+                                     GLX_ALPHA_SIZE, &alpha);
+
+            J2dRlsTrace5(J2D_TRACE_VERBOSE,
+                "[V]     id=0x%x db=%d alpha=%d depth=%d stencil=%d valid=",
+                         fbvisualid, db, alpha, depth, stencil);
+
+#ifdef __sparc
+            /*
+             * Sun's OpenGL implementation will always
+             * return at least two GLXFBConfigs (visuals) from
+             * glXChooseFBConfig().  The first will be a linear (gamma
+             * corrected) visual; the second will have the same capabilities
+             * as the first, except it will be a non-linear (non-gamma
+             * corrected) visual, which is the one we want, otherwise
+             * everything will look "washed out".  So we will reject any
+             * visuals that have gamma values other than 1.0 (the value
+             * returned by glXGetFBConfigAttrib() will be scaled
+             * by 100, so 100 corresponds to a gamma value of 1.0, 220
+             * corresponds to 2.2, and so on).
+             */
+            j2d_glXGetFBConfigAttrib(awt_display, fbc,
+                                     GLX_GAMMA_VALUE_SUN, &gamma);
+            if (gamma != 100) {
+                J2dRlsTrace(J2D_TRACE_VERBOSE, "false (linear visual)\n");
+                continue;
+            }
+#endif /* __sparc */
+
+            if ((dtype & GLX_WINDOW_BIT) &&
+                (dtype & GLX_PBUFFER_BIT) &&
+                (rtype & GLX_RGBA_BIT) &&
+                (depth >= 16))
+            {
+                if (visualid == 0) {
+                    // when visualid == 0, we loop through all configs
+                    // looking for an fbconfig that has the smallest combined
+                    // depth+stencil size (this keeps VRAM usage to a minimum)
+                    if ((depth + stencil) < minDepthPlusStencil) {
+                        J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
+                        minDepthPlusStencil = depth + stencil;
+                        chosenConfig = fbc;
+                    } else {
+                        J2dRlsTrace(J2D_TRACE_VERBOSE,
+                                    "false (large depth)\n");
+                    }
+                    continue;
+                } else {
+                    // in this case, visualid == fbvisualid, which means
+                    // we've found a valid fbconfig corresponding to the
+                    // requested VisualID, so break out of the loop
+                    J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
+                    chosenConfig = fbc;
+                    break;
+                }
+            } else {
+                J2dRlsTrace(J2D_TRACE_VERBOSE, "false (bad match)\n");
+            }
+        }
+    }
+
+    // free the list of fbconfigs
+    XFree(fbconfigs);
+
+    if (chosenConfig == 0) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+            "GLXGC_InitFBConfig: could not find an appropriate fbconfig");
+        return 0;
+    }
+
+    return chosenConfig;
+}
+
+/**
+ * Returns the X11 VisualID that corresponds to the best GLXFBConfig for the
+ * given screen.  If no valid visual could be found, this method returns zero.
+ * Note that this method will attempt to initialize GLX (and all the
+ * necessary function symbols) if it has not been already.  The AWT_LOCK
+ * must be acquired before calling this method.
+ */
+VisualID
+GLXGC_FindBestVisual(JNIEnv *env, jint screen)
+{
+    GLXFBConfig fbc;
+    XVisualInfo *xvi;
+    VisualID visualid;
+
+    J2dRlsTraceLn1(J2D_TRACE_INFO, "GLXGC_FindBestVisual: scn=%d", screen);
+
+    if (!GLXGC_IsGLXAvailable()) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+            "GLXGC_FindBestVisual: could not initialize GLX");
+        return 0;
+    }
+
+    fbc = GLXGC_InitFBConfig(env, screen, 0);
+    if (fbc == 0) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+            "GLXGC_FindBestVisual: could not find best visual");
+        return 0;
+    }
+
+    xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);
+    if (xvi == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+            "GLXGC_FindBestVisual: could not get visual for fbconfig");
+        return 0;
+    }
+
+    visualid = xvi->visualid;
+    XFree(xvi);
+
+    J2dRlsTraceLn2(J2D_TRACE_INFO,
+        "GLXGC_FindBestVisual: chose 0x%x as the best visual for screen %d",
+                   visualid, screen);
+
+    return visualid;
+}
+
+/**
+ * Creates a scratch pbuffer, which can be used to make a context current
+ * for extension queries, etc.
+ */
+static GLXPbuffer
+GLXGC_InitScratchPbuffer(GLXFBConfig fbconfig)
+{
+    int pbattrlist[] = {GLX_PBUFFER_WIDTH, 1,
+                        GLX_PBUFFER_HEIGHT, 1,
+                        GLX_PRESERVED_CONTENTS, GL_FALSE,
+                        0};
+
+    J2dTraceLn(J2D_TRACE_INFO, "GLXGC_InitScratchPbuffer");
+
+    return j2d_glXCreatePbuffer(awt_display, fbconfig, pbattrlist);
+}
+
+/**
+ * Initializes a new OGLContext, which includes the native GLXContext handle
+ * and some other important information such as the associated GLXFBConfig.
+ */
+static OGLContext *
+GLXGC_InitOGLContext(GLXFBConfig fbconfig, GLXContext context,
+                     GLXPbuffer scratch, jint caps)
+{
+    OGLContext *oglc;
+    GLXCtxInfo *ctxinfo;
+
+    J2dTraceLn(J2D_TRACE_INFO, "GLXGC_InitOGLContext");
+
+    oglc = (OGLContext *)malloc(sizeof(OGLContext));
+    if (oglc == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+            "GLXGC_InitOGLContext: could not allocate memory for oglc");
+        return NULL;
+    }
+
+    memset(oglc, 0, sizeof(OGLContext));
+
+    ctxinfo = (GLXCtxInfo *)malloc(sizeof(GLXCtxInfo));
+    if (ctxinfo == NULL) {
+        J2dRlsTraceLn(J2D_TRACE_ERROR,
+            "GLXGC_InitOGLContext: could not allocate memory for ctxinfo");
+        free(oglc);
+        return NULL;
+    }
+
+    ctxinfo->fbconfig = fbconfig;
+    ctxinfo->context = context;
+    ctxinfo->scratchSurface = scratch;
+    oglc->ctxInfo = ctxinfo;
+    oglc->caps = caps;
+
+    return oglc;
+}
+
+#endif /* !HEADLESS */
+
+/**
+ * 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 = sun_java2d_opengl_OGLContext_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 |= sun_java2d_opengl_OGLContext_CAPS_DOUBLEBUFFERED;
+    }
+    j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_ALPHA_SIZE, &alpha);
+    if (alpha > 0) {
+        caps |= sun_java2d_opengl_OGLContext_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 */
+}
+
+JNIEXPORT void JNICALL
+Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig(JNIEnv *env,
+                                                    jobject glxgc,
+                                                    jlong aData,
+                                                    jlong configInfo)
+{
+#ifndef HEADLESS
+    GLXGraphicsConfigInfo *glxinfo;
+    AwtGraphicsConfigDataPtr configData =
+        (AwtGraphicsConfigDataPtr)jlong_to_ptr(aData);
+
+    J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_initConfig");
+
+    if (configData == NULL) {
+        JNU_ThrowNullPointerException(env, "Native GraphicsConfig missing");
+        return;
+    }
+
+    glxinfo = (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);
+    if (glxinfo == NULL) {
+        JNU_ThrowNullPointerException(env,
+                                      "GLXGraphicsConfigInfo data missing");
+        return;
+    }
+
+    configData->glxInfo = glxinfo;
+#endif /* !HEADLESS */
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities(JNIEnv *env,
+                                                            jclass glxgc,
+                                                            jlong configInfo)
+{
+#ifndef HEADLESS
+    GLXGraphicsConfigInfo *glxinfo =
+        (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);
+
+    J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getOGLCapabilities");
+
+    if (glxinfo == NULL || glxinfo->context == NULL) {
+        return sun_java2d_opengl_OGLContext_CAPS_EMPTY;
+    }
+
+    return glxinfo->context->caps;
+#else
+    return sun_java2d_opengl_OGLContext_CAPS_EMPTY;
+#endif /* !HEADLESS */
+}