1 /*
   2  * Copyright (c) 2003, 2008, 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 #include <stdlib.h>
  27 #include <string.h>
  28 
  29 #include "sun_java2d_opengl_GLXGraphicsConfig.h"
  30 
  31 #include "jni.h"
  32 #include "jlong.h"
  33 #include "GLXGraphicsConfig.h"
  34 #include "GLXSurfaceData.h"
  35 #include "awt_GraphicsEnv.h"
  36 #include "awt_util.h"
  37 
  38 #ifndef HEADLESS
  39 
  40 extern Bool usingXinerama;
  41 
  42 /**
  43  * This is a globally shared context used when creating textures.  When any
  44  * new contexts are created, they specify this context as the "share list"
  45  * context, which means any texture objects created when this shared context
  46  * is current will be available to any other context.
  47  */
  48 static GLXContext sharedContext = 0;
  49 
  50 /**
  51  * Attempts to initialize GLX and the core OpenGL library.  For this method
  52  * to return JNI_TRUE, the following must be true:
  53  *     - libGL must be loaded successfully (via dlopen)
  54  *     - all function symbols from libGL must be available and loaded properly
  55  *     - the GLX extension must be available through X11
  56  *     - client GLX version must be >= 1.3
  57  * If any of these requirements are not met, this method will return
  58  * JNI_FALSE, indicating there is no hope of using GLX/OpenGL for any
  59  * GraphicsConfig in the environment.
  60  */
  61 static jboolean
  62 GLXGC_InitGLX()
  63 {
  64     int errorbase, eventbase;
  65     const char *version;
  66 
  67     J2dRlsTraceLn(J2D_TRACE_INFO, "GLXGC_InitGLX");
  68 
  69     if (!OGLFuncs_OpenLibrary()) {
  70         return JNI_FALSE;
  71     }
  72 
  73     if (!OGLFuncs_InitPlatformFuncs() ||
  74         !OGLFuncs_InitBaseFuncs() ||
  75         !OGLFuncs_InitExtFuncs())
  76     {
  77         OGLFuncs_CloseLibrary();
  78         return JNI_FALSE;
  79     }
  80 
  81     if (!j2d_glXQueryExtension(awt_display, &errorbase, &eventbase)) {
  82         J2dRlsTraceLn(J2D_TRACE_ERROR,
  83                       "GLXGC_InitGLX: GLX extension is not present");
  84         OGLFuncs_CloseLibrary();
  85         return JNI_FALSE;
  86     }
  87 
  88     version = j2d_glXGetClientString(awt_display, GLX_VERSION);
  89     if (version == NULL) {
  90         J2dRlsTraceLn(J2D_TRACE_ERROR,
  91                       "GLXGC_InitGLX: could not query GLX version");
  92         OGLFuncs_CloseLibrary();
  93         return JNI_FALSE;
  94     }
  95 
  96     // we now only verify that the client GLX version is >= 1.3 (if the
  97     // server does not support GLX 1.3, then we will find that out later
  98     // when we attempt to create a GLXFBConfig)
  99     J2dRlsTraceLn1(J2D_TRACE_INFO,
 100                    "GLXGC_InitGLX: client GLX version=%s", version);
 101     if (!((version[0] == '1' && version[2] >= '3') || (version[0] > '1'))) {
 102         J2dRlsTraceLn(J2D_TRACE_ERROR,
 103                       "GLXGC_InitGLX: invalid GLX version; 1.3 is required");
 104         OGLFuncs_CloseLibrary();
 105         return JNI_FALSE;
 106     }
 107 
 108     return JNI_TRUE;
 109 }
 110 
 111 /**
 112  * Returns JNI_TRUE if GLX is available for the current display.  Note that
 113  * this method will attempt to initialize GLX (and all the necessary function
 114  * symbols) if it has not been already.  The AWT_LOCK must be acquired before
 115  * calling this method.
 116  */
 117 jboolean
 118 GLXGC_IsGLXAvailable()
 119 {
 120     static jboolean glxAvailable = JNI_FALSE;
 121     static jboolean firstTime = JNI_TRUE;
 122 
 123     J2dTraceLn(J2D_TRACE_INFO, "GLXGC_IsGLXAvailable");
 124 
 125     if (firstTime) {
 126         glxAvailable = GLXGC_InitGLX();
 127         firstTime = JNI_FALSE;
 128     }
 129 
 130     return glxAvailable;
 131 }
 132 
 133 /**
 134  * Disposes all memory and resources allocated for the given OGLContext.
 135  */
 136 static void
 137 GLXGC_DestroyOGLContext(OGLContext *oglc)
 138 {
 139     GLXCtxInfo *ctxinfo;
 140 
 141     J2dTraceLn(J2D_TRACE_INFO, "GLXGC_DestroyOGLContext");
 142 
 143     if (oglc == NULL) {
 144         J2dRlsTraceLn(J2D_TRACE_ERROR,
 145                       "GLXGC_DestroyOGLContext: context is null");
 146         return;
 147     }
 148 
 149     // at this point, this context will be current to its scratch surface
 150     // so the following GL/GLX operations should be safe...
 151 
 152     OGLContext_DestroyContextResources(oglc);
 153 
 154     ctxinfo = (GLXCtxInfo *)oglc->ctxInfo;
 155     if (ctxinfo != NULL) {
 156         // release the current context before we continue
 157         j2d_glXMakeContextCurrent(awt_display, None, None, NULL);
 158 
 159         if (ctxinfo->context != 0) {
 160             j2d_glXDestroyContext(awt_display, ctxinfo->context);
 161         }
 162         if (ctxinfo->scratchSurface != 0) {
 163             j2d_glXDestroyPbuffer(awt_display, ctxinfo->scratchSurface);
 164         }
 165 
 166         free(ctxinfo);
 167     }
 168 
 169     free(oglc);
 170 }
 171 
 172 /**
 173  * Disposes all memory and resources associated with the given
 174  * GLXGraphicsConfigInfo (including its native OGLContext data).
 175  */
 176 void
 177 OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo)
 178 {
 179     GLXGraphicsConfigInfo *glxinfo =
 180         (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
 181 
 182     J2dTraceLn(J2D_TRACE_INFO, "OGLGC_DestroyOGLGraphicsConfig");
 183 
 184     if (glxinfo == NULL) {
 185         J2dRlsTraceLn(J2D_TRACE_ERROR,
 186                       "OGLGC_DestroyOGLGraphicsConfig: info is null");
 187         return;
 188     }
 189 
 190     if (glxinfo->context != NULL) {
 191         GLXGC_DestroyOGLContext(glxinfo->context);
 192     }
 193 
 194     free(glxinfo);
 195 }
 196 
 197 /**
 198  * Attempts to create a new GLXFBConfig for the requested screen and visual.
 199  * If visualid is 0, this method will iterate through all GLXFBConfigs (if
 200  * any) that match the requested attributes and will attempt to find an
 201  * fbconfig with a minimal combined depth+stencil buffer.  Note that we
 202  * currently only need depth capabilities (for shape clipping purposes), but
 203  * glXChooseFBConfig() will often return a list of fbconfigs with the largest
 204  * depth buffer (and stencil) sizes at the top of the list.  Therefore, we
 205  * scan through the whole list to find the most VRAM-efficient fbconfig.
 206  * If visualid is non-zero, the GLXFBConfig associated with the given visual
 207  * is chosen (assuming it meets the requested attributes).  If there are no
 208  * valid GLXFBConfigs available, this method returns 0.
 209  */
 210 static GLXFBConfig
 211 GLXGC_InitFBConfig(JNIEnv *env, jint screennum, VisualID visualid)
 212 {
 213     GLXFBConfig *fbconfigs;
 214     GLXFBConfig chosenConfig = 0;
 215     int nconfs, i;
 216     int attrlist[] = {GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT,
 217                       GLX_RENDER_TYPE, GLX_RGBA_BIT,
 218                       GLX_CONFIG_CAVEAT, GLX_NONE, // avoid "slow" configs
 219                       GLX_DEPTH_SIZE, 16, // anything >= 16 will work for us
 220                       0};
 221 
 222     // this is the initial minimum value for the combined depth+stencil size
 223     // (we initialize it to some absurdly high value; realistic values will
 224     // be much less than this number)
 225     int minDepthPlusStencil = 512;
 226 
 227     J2dRlsTraceLn2(J2D_TRACE_INFO, "GLXGC_InitFBConfig: scn=%d vis=0x%x",
 228                    screennum, visualid);
 229 
 230     // find all fbconfigs for this screen with the provided attributes
 231     fbconfigs = j2d_glXChooseFBConfig(awt_display, screennum,
 232                                       attrlist, &nconfs);
 233 
 234     if ((fbconfigs == NULL) || (nconfs <= 0)) {
 235         J2dRlsTraceLn(J2D_TRACE_ERROR,
 236             "GLXGC_InitFBConfig: could not find any valid fbconfigs");
 237         return 0;
 238     }
 239 
 240     J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  candidate fbconfigs:");
 241 
 242     // iterate through the list of fbconfigs, looking for the one that matches
 243     // the requested VisualID and supports RGBA rendering as well as the
 244     // creation of windows and pbuffers
 245     for (i = 0; i < nconfs; i++) {
 246         XVisualInfo *xvi;
 247         VisualID fbvisualid;
 248         GLXFBConfig fbc = fbconfigs[i];
 249 
 250         // get VisualID from GLXFBConfig
 251         xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);
 252         if (xvi == NULL) {
 253             continue;
 254         }
 255         fbvisualid = xvi->visualid;
 256         XFree(xvi);
 257 
 258         if (visualid == 0 || visualid == fbvisualid) {
 259             int dtype, rtype, depth, stencil, db, alpha, gamma;
 260 
 261             // get GLX-specific attributes from GLXFBConfig
 262             j2d_glXGetFBConfigAttrib(awt_display, fbc,
 263                                      GLX_DRAWABLE_TYPE, &dtype);
 264             j2d_glXGetFBConfigAttrib(awt_display, fbc,
 265                                      GLX_RENDER_TYPE, &rtype);
 266             j2d_glXGetFBConfigAttrib(awt_display, fbc,
 267                                      GLX_DEPTH_SIZE, &depth);
 268             j2d_glXGetFBConfigAttrib(awt_display, fbc,
 269                                      GLX_STENCIL_SIZE, &stencil);
 270 
 271             // these attributes don't affect our decision, but they are
 272             // interesting for trace logs, so we will query them anyway
 273             j2d_glXGetFBConfigAttrib(awt_display, fbc,
 274                                      GLX_DOUBLEBUFFER, &db);
 275             j2d_glXGetFBConfigAttrib(awt_display, fbc,
 276                                      GLX_ALPHA_SIZE, &alpha);
 277 
 278             J2dRlsTrace5(J2D_TRACE_VERBOSE,
 279                 "[V]     id=0x%x db=%d alpha=%d depth=%d stencil=%d valid=",
 280                          fbvisualid, db, alpha, depth, stencil);
 281 
 282 #ifdef __sparc
 283             /*
 284              * Sun's OpenGL implementation will always
 285              * return at least two GLXFBConfigs (visuals) from
 286              * glXChooseFBConfig().  The first will be a linear (gamma
 287              * corrected) visual; the second will have the same capabilities
 288              * as the first, except it will be a non-linear (non-gamma
 289              * corrected) visual, which is the one we want, otherwise
 290              * everything will look "washed out".  So we will reject any
 291              * visuals that have gamma values other than 1.0 (the value
 292              * returned by glXGetFBConfigAttrib() will be scaled
 293              * by 100, so 100 corresponds to a gamma value of 1.0, 220
 294              * corresponds to 2.2, and so on).
 295              */
 296             j2d_glXGetFBConfigAttrib(awt_display, fbc,
 297                                      GLX_GAMMA_VALUE_SUN, &gamma);
 298             if (gamma != 100) {
 299                 J2dRlsTrace(J2D_TRACE_VERBOSE, "false (linear visual)\n");
 300                 continue;
 301             }
 302 #endif /* __sparc */
 303 
 304             if ((dtype & GLX_WINDOW_BIT) &&
 305                 (dtype & GLX_PBUFFER_BIT) &&
 306                 (rtype & GLX_RGBA_BIT) &&
 307                 (depth >= 16))
 308             {
 309                 if (visualid == 0) {
 310                     // when visualid == 0, we loop through all configs
 311                     // looking for an fbconfig that has the smallest combined
 312                     // depth+stencil size (this keeps VRAM usage to a minimum)
 313                     if ((depth + stencil) < minDepthPlusStencil) {
 314                         J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
 315                         minDepthPlusStencil = depth + stencil;
 316                         chosenConfig = fbc;
 317                     } else {
 318                         J2dRlsTrace(J2D_TRACE_VERBOSE,
 319                                     "false (large depth)\n");
 320                     }
 321                     continue;
 322                 } else {
 323                     // in this case, visualid == fbvisualid, which means
 324                     // we've found a valid fbconfig corresponding to the
 325                     // requested VisualID, so break out of the loop
 326                     J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
 327                     chosenConfig = fbc;
 328                     break;
 329                 }
 330             } else {
 331                 J2dRlsTrace(J2D_TRACE_VERBOSE, "false (bad match)\n");
 332             }
 333         }
 334     }
 335 
 336     // free the list of fbconfigs
 337     XFree(fbconfigs);
 338 
 339     if (chosenConfig == 0) {
 340         J2dRlsTraceLn(J2D_TRACE_ERROR,
 341             "GLXGC_InitFBConfig: could not find an appropriate fbconfig");
 342         return 0;
 343     }
 344 
 345     return chosenConfig;
 346 }
 347 
 348 /**
 349  * Returns the X11 VisualID that corresponds to the best GLXFBConfig for the
 350  * given screen.  If no valid visual could be found, this method returns zero.
 351  * Note that this method will attempt to initialize GLX (and all the
 352  * necessary function symbols) if it has not been already.  The AWT_LOCK
 353  * must be acquired before calling this method.
 354  */
 355 VisualID
 356 GLXGC_FindBestVisual(JNIEnv *env, jint screen)
 357 {
 358     GLXFBConfig fbc;
 359     XVisualInfo *xvi;
 360     VisualID visualid;
 361 
 362     J2dRlsTraceLn1(J2D_TRACE_INFO, "GLXGC_FindBestVisual: scn=%d", screen);
 363 
 364     if (!GLXGC_IsGLXAvailable()) {
 365         J2dRlsTraceLn(J2D_TRACE_ERROR,
 366             "GLXGC_FindBestVisual: could not initialize GLX");
 367         return 0;
 368     }
 369 
 370     fbc = GLXGC_InitFBConfig(env, screen, 0);
 371     if (fbc == 0) {
 372         J2dRlsTraceLn(J2D_TRACE_ERROR,
 373             "GLXGC_FindBestVisual: could not find best visual");
 374         return 0;
 375     }
 376 
 377     xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);
 378     if (xvi == NULL) {
 379         J2dRlsTraceLn(J2D_TRACE_ERROR,
 380             "GLXGC_FindBestVisual: could not get visual for fbconfig");
 381         return 0;
 382     }
 383 
 384     visualid = xvi->visualid;
 385     XFree(xvi);
 386 
 387     J2dRlsTraceLn2(J2D_TRACE_INFO,
 388         "GLXGC_FindBestVisual: chose 0x%x as the best visual for screen %d",
 389                    visualid, screen);
 390 
 391     return visualid;
 392 }
 393 
 394 /**
 395  * Creates a scratch pbuffer, which can be used to make a context current
 396  * for extension queries, etc.
 397  */
 398 static GLXPbuffer
 399 GLXGC_InitScratchPbuffer(GLXFBConfig fbconfig)
 400 {
 401     int pbattrlist[] = {GLX_PBUFFER_WIDTH, 1,
 402                         GLX_PBUFFER_HEIGHT, 1,
 403                         GLX_PRESERVED_CONTENTS, GL_FALSE,
 404                         0};
 405 
 406     J2dTraceLn(J2D_TRACE_INFO, "GLXGC_InitScratchPbuffer");
 407 
 408     return j2d_glXCreatePbuffer(awt_display, fbconfig, pbattrlist);
 409 }
 410 
 411 /**
 412  * Initializes a new OGLContext, which includes the native GLXContext handle
 413  * and some other important information such as the associated GLXFBConfig.
 414  */
 415 static OGLContext *
 416 GLXGC_InitOGLContext(GLXFBConfig fbconfig, GLXContext context,
 417                      GLXPbuffer scratch, jint caps)
 418 {
 419     OGLContext *oglc;
 420     GLXCtxInfo *ctxinfo;
 421 
 422     J2dTraceLn(J2D_TRACE_INFO, "GLXGC_InitOGLContext");
 423 
 424     oglc = (OGLContext *)malloc(sizeof(OGLContext));
 425     if (oglc == NULL) {
 426         J2dRlsTraceLn(J2D_TRACE_ERROR,
 427             "GLXGC_InitOGLContext: could not allocate memory for oglc");
 428         return NULL;
 429     }
 430 
 431     memset(oglc, 0, sizeof(OGLContext));
 432 
 433     ctxinfo = (GLXCtxInfo *)malloc(sizeof(GLXCtxInfo));
 434     if (ctxinfo == NULL) {
 435         J2dRlsTraceLn(J2D_TRACE_ERROR,
 436             "GLXGC_InitOGLContext: could not allocate memory for ctxinfo");
 437         free(oglc);
 438         return NULL;
 439     }
 440 
 441     ctxinfo->fbconfig = fbconfig;
 442     ctxinfo->context = context;
 443     ctxinfo->scratchSurface = scratch;
 444     oglc->ctxInfo = ctxinfo;
 445     oglc->caps = caps;
 446 
 447     return oglc;
 448 }
 449 
 450 #endif /* !HEADLESS */
 451 
 452 /**
 453  * Determines whether the GLX pipeline can be used for a given GraphicsConfig
 454  * provided its screen number and visual ID.  If the minimum requirements are
 455  * met, the native GLXGraphicsConfigInfo structure is initialized for this
 456  * GraphicsConfig with the necessary information (GLXFBConfig, etc.)
 457  * and a pointer to this structure is returned as a jlong.  If
 458  * initialization fails at any point, zero is returned, indicating that GLX
 459  * cannot be used for this GraphicsConfig (we should fallback on the existing
 460  * X11 pipeline).
 461  */
 462 JNIEXPORT jlong JNICALL
 463 Java_sun_java2d_opengl_GLXGraphicsConfig_getGLXConfigInfo(JNIEnv *env,
 464                                                           jclass glxgc,
 465                                                           jint screennum,
 466                                                           jint visnum)
 467 {
 468 #ifndef HEADLESS
 469     OGLContext *oglc;
 470     GLXFBConfig fbconfig;
 471     GLXContext context;
 472     GLXPbuffer scratch;
 473     GLXGraphicsConfigInfo *glxinfo;
 474     jint caps = CAPS_EMPTY;
 475     int db, alpha;
 476     const unsigned char *versionstr;
 477 
 478     J2dRlsTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getGLXConfigInfo");
 479 
 480     if (usingXinerama) {
 481         // when Xinerama is enabled, the screen ID needs to be 0
 482         screennum = 0;
 483     }
 484 
 485     fbconfig = GLXGC_InitFBConfig(env, screennum, (VisualID)visnum);
 486     if (fbconfig == 0) {
 487         J2dRlsTraceLn(J2D_TRACE_ERROR,
 488             "GLXGraphicsConfig_getGLXConfigInfo: could not create fbconfig");
 489         return 0L;
 490     }
 491 
 492     if (sharedContext == 0) {
 493         // create the one shared context
 494         sharedContext = j2d_glXCreateNewContext(awt_display, fbconfig,
 495                                                 GLX_RGBA_TYPE, 0, GL_TRUE);
 496         if (sharedContext == 0) {
 497             J2dRlsTraceLn(J2D_TRACE_ERROR,
 498                 "GLXGraphicsConfig_getGLXConfigInfo: could not create shared context");
 499             return 0L;
 500         }
 501     }
 502 
 503     // create the GLXContext for this GLXGraphicsConfig
 504     context = j2d_glXCreateNewContext(awt_display, fbconfig,
 505                                       GLX_RGBA_TYPE, sharedContext,
 506                                       GL_TRUE);
 507     if (context == 0) {
 508         J2dRlsTraceLn(J2D_TRACE_ERROR,
 509             "GLXGraphicsConfig_getGLXConfigInfo: could not create GLX context");
 510         return 0L;
 511     }
 512 
 513     // this is pretty sketchy, but it seems to be the easiest way to create
 514     // some form of GLXDrawable using only the display and a GLXFBConfig
 515     // (in order to make the context current for checking the version,
 516     // extensions, etc)...
 517     scratch = GLXGC_InitScratchPbuffer(fbconfig);
 518     if (scratch == 0) {
 519         J2dRlsTraceLn(J2D_TRACE_ERROR,
 520             "GLXGraphicsConfig_getGLXConfigInfo: could not create scratch pbuffer");
 521         j2d_glXDestroyContext(awt_display, context);
 522         return 0L;
 523     }
 524 
 525     // the context must be made current before we can query the
 526     // version and extension strings
 527     j2d_glXMakeContextCurrent(awt_display, scratch, scratch, context);
 528 
 529 #ifdef __sparc
 530     /*
 531      * 6438225: The software rasterizer used by Sun's OpenGL libraries
 532      * for certain boards has quality issues, and besides, performance
 533      * of these boards is not high enough to justify the use of the
 534      * OpenGL-based Java 2D pipeline.  If we detect one of the following
 535      * boards via the GL_RENDERER string, just give up:
 536      *   - FFB[2[+]] ("Creator[3D]")
 537      *   - PGX-series ("m64")
 538      *   - AFB ("Elite3D")
 539      */
 540     {
 541         const char *renderer = (const char *)j2d_glGetString(GL_RENDERER);
 542 
 543         J2dRlsTraceLn1(J2D_TRACE_VERBOSE,
 544             "GLXGraphicsConfig_getGLXConfigInfo: detected renderer (%s)",
 545             (renderer == NULL) ? "null" : renderer);
 546 
 547         if (renderer == NULL ||
 548             strncmp(renderer, "Creator", 7) == 0 ||
 549             strncmp(renderer, "SUNWm64", 7) == 0 ||
 550             strncmp(renderer, "Elite", 5) == 0)
 551         {
 552             J2dRlsTraceLn1(J2D_TRACE_ERROR,
 553                 "GLXGraphicsConfig_getGLXConfigInfo: unsupported board (%s)",
 554                 (renderer == NULL) ? "null" : renderer);
 555             j2d_glXMakeContextCurrent(awt_display, None, None, NULL);
 556             j2d_glXDestroyPbuffer(awt_display, scratch);
 557             j2d_glXDestroyContext(awt_display, context);
 558             return 0L;
 559         }
 560     }
 561 #endif /* __sparc */
 562 
 563     versionstr = j2d_glGetString(GL_VERSION);
 564     OGLContext_GetExtensionInfo(env, &caps);
 565 
 566     // destroy the temporary resources
 567     j2d_glXMakeContextCurrent(awt_display, None, None, NULL);
 568 
 569     J2dRlsTraceLn1(J2D_TRACE_INFO,
 570         "GLXGraphicsConfig_getGLXConfigInfo: OpenGL version=%s",
 571                    (versionstr == NULL) ? "null" : (char *)versionstr);
 572 
 573     if (!OGLContext_IsVersionSupported(versionstr)) {
 574         J2dRlsTraceLn(J2D_TRACE_ERROR,
 575             "GLXGraphicsConfig_getGLXConfigInfo: OpenGL 1.2 is required");
 576         j2d_glXDestroyPbuffer(awt_display, scratch);
 577         j2d_glXDestroyContext(awt_display, context);
 578         return 0L;
 579     }
 580 
 581     // get config-specific capabilities
 582     j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_DOUBLEBUFFER, &db);
 583     if (db) {
 584         caps |= CAPS_DOUBLEBUFFERED;
 585     }
 586     j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_ALPHA_SIZE, &alpha);
 587     if (alpha > 0) {
 588         caps |= CAPS_STORED_ALPHA;
 589     }
 590 
 591     // initialize the OGLContext, which wraps the GLXFBConfig and GLXContext
 592     oglc = GLXGC_InitOGLContext(fbconfig, context, scratch, caps);
 593     if (oglc == NULL) {
 594         J2dRlsTraceLn(J2D_TRACE_ERROR,
 595             "GLXGraphicsConfig_getGLXConfigInfo: could not create oglc");
 596         j2d_glXDestroyPbuffer(awt_display, scratch);
 597         j2d_glXDestroyContext(awt_display, context);
 598         return 0L;
 599     }
 600 
 601     J2dTraceLn(J2D_TRACE_VERBOSE,
 602         "GLXGraphicsConfig_getGLXConfigInfo: finished checking dependencies");
 603 
 604     // create the GLXGraphicsConfigInfo record for this config
 605     glxinfo = (GLXGraphicsConfigInfo *)malloc(sizeof(GLXGraphicsConfigInfo));
 606     if (glxinfo == NULL) {
 607         J2dRlsTraceLn(J2D_TRACE_ERROR,
 608             "GLXGraphicsConfig_getGLXConfigInfo: could not allocate memory for glxinfo");
 609         GLXGC_DestroyOGLContext(oglc);
 610         return 0L;
 611     }
 612 
 613     glxinfo->screen = screennum;
 614     glxinfo->visual = visnum;
 615     glxinfo->context = oglc;
 616     glxinfo->fbconfig = fbconfig;
 617 
 618     return ptr_to_jlong(glxinfo);
 619 #else
 620     return 0L;
 621 #endif /* !HEADLESS */
 622 }
 623 
 624 JNIEXPORT void JNICALL
 625 Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig(JNIEnv *env,
 626                                                     jobject glxgc,
 627                                                     jlong aData,
 628                                                     jlong configInfo)
 629 {
 630 #ifndef HEADLESS
 631     GLXGraphicsConfigInfo *glxinfo;
 632     AwtGraphicsConfigDataPtr configData =
 633         (AwtGraphicsConfigDataPtr)jlong_to_ptr(aData);
 634 
 635     J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_initConfig");
 636 
 637     if (configData == NULL) {
 638         JNU_ThrowNullPointerException(env, "Native GraphicsConfig missing");
 639         return;
 640     }
 641 
 642     glxinfo = (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);
 643     if (glxinfo == NULL) {
 644         JNU_ThrowNullPointerException(env,
 645                                       "GLXGraphicsConfigInfo data missing");
 646         return;
 647     }
 648 
 649     configData->glxInfo = glxinfo;
 650 #endif /* !HEADLESS */
 651 }
 652 
 653 JNIEXPORT jint JNICALL
 654 Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities(JNIEnv *env,
 655                                                             jclass glxgc,
 656                                                             jlong configInfo)
 657 {
 658 #ifndef HEADLESS
 659     GLXGraphicsConfigInfo *glxinfo =
 660         (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);
 661 
 662     J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getOGLCapabilities");
 663 
 664     if (glxinfo == NULL || glxinfo->context == NULL) {
 665         return CAPS_EMPTY;
 666     }
 667 
 668     return glxinfo->context->caps;
 669 #else
 670     return CAPS_EMPTY;
 671 #endif /* !HEADLESS */
 672 }