1 /*
   2  * Copyright (c) 2003, 2015, 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             if ((dtype & GLX_WINDOW_BIT) &&
 283                 (dtype & GLX_PBUFFER_BIT) &&
 284                 (rtype & GLX_RGBA_BIT) &&
 285                 (depth >= 16))
 286             {
 287                 if (visualid == 0) {
 288                     // when visualid == 0, we loop through all configs
 289                     // looking for an fbconfig that has the smallest combined
 290                     // depth+stencil size (this keeps VRAM usage to a minimum)
 291                     if ((depth + stencil) < minDepthPlusStencil) {
 292                         J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
 293                         minDepthPlusStencil = depth + stencil;
 294                         chosenConfig = fbc;
 295                     } else {
 296                         J2dRlsTrace(J2D_TRACE_VERBOSE,
 297                                     "false (large depth)\n");
 298                     }
 299                     continue;
 300                 } else {
 301                     // in this case, visualid == fbvisualid, which means
 302                     // we've found a valid fbconfig corresponding to the
 303                     // requested VisualID, so break out of the loop
 304                     J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
 305                     chosenConfig = fbc;
 306                     break;
 307                 }
 308             } else {
 309                 J2dRlsTrace(J2D_TRACE_VERBOSE, "false (bad match)\n");
 310             }
 311         }
 312     }
 313 
 314     // free the list of fbconfigs
 315     XFree(fbconfigs);
 316 
 317     if (chosenConfig == 0) {
 318         J2dRlsTraceLn(J2D_TRACE_ERROR,
 319             "GLXGC_InitFBConfig: could not find an appropriate fbconfig");
 320         return 0;
 321     }
 322 
 323     return chosenConfig;
 324 }
 325 
 326 /**
 327  * Returns the X11 VisualID that corresponds to the best GLXFBConfig for the
 328  * given screen.  If no valid visual could be found, this method returns zero.
 329  * Note that this method will attempt to initialize GLX (and all the
 330  * necessary function symbols) if it has not been already.  The AWT_LOCK
 331  * must be acquired before calling this method.
 332  */
 333 VisualID
 334 GLXGC_FindBestVisual(JNIEnv *env, jint screen)
 335 {
 336     GLXFBConfig fbc;
 337     XVisualInfo *xvi;
 338     VisualID visualid;
 339 
 340     J2dRlsTraceLn1(J2D_TRACE_INFO, "GLXGC_FindBestVisual: scn=%d", screen);
 341 
 342     if (!GLXGC_IsGLXAvailable()) {
 343         J2dRlsTraceLn(J2D_TRACE_ERROR,
 344             "GLXGC_FindBestVisual: could not initialize GLX");
 345         return 0;
 346     }
 347 
 348     fbc = GLXGC_InitFBConfig(env, screen, 0);
 349     if (fbc == 0) {
 350         J2dRlsTraceLn(J2D_TRACE_ERROR,
 351             "GLXGC_FindBestVisual: could not find best visual");
 352         return 0;
 353     }
 354 
 355     xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);
 356     if (xvi == NULL) {
 357         J2dRlsTraceLn(J2D_TRACE_ERROR,
 358             "GLXGC_FindBestVisual: could not get visual for fbconfig");
 359         return 0;
 360     }
 361 
 362     visualid = xvi->visualid;
 363     XFree(xvi);
 364 
 365     J2dRlsTraceLn2(J2D_TRACE_INFO,
 366         "GLXGC_FindBestVisual: chose 0x%x as the best visual for screen %d",
 367                    visualid, screen);
 368 
 369     return visualid;
 370 }
 371 
 372 /**
 373  * Creates a scratch pbuffer, which can be used to make a context current
 374  * for extension queries, etc.
 375  */
 376 static GLXPbuffer
 377 GLXGC_InitScratchPbuffer(GLXFBConfig fbconfig)
 378 {
 379     int pbattrlist[] = {GLX_PBUFFER_WIDTH, 4,
 380                         GLX_PBUFFER_HEIGHT, 4,
 381                         GLX_PRESERVED_CONTENTS, GL_FALSE,
 382                         0};
 383 
 384     J2dTraceLn(J2D_TRACE_INFO, "GLXGC_InitScratchPbuffer");
 385 
 386     return j2d_glXCreatePbuffer(awt_display, fbconfig, pbattrlist);
 387 }
 388 
 389 /**
 390  * Initializes a new OGLContext, which includes the native GLXContext handle
 391  * and some other important information such as the associated GLXFBConfig.
 392  */
 393 static OGLContext *
 394 GLXGC_InitOGLContext(GLXFBConfig fbconfig, GLXContext context,
 395                      GLXPbuffer scratch, jint caps)
 396 {
 397     OGLContext *oglc;
 398     GLXCtxInfo *ctxinfo;
 399 
 400     J2dTraceLn(J2D_TRACE_INFO, "GLXGC_InitOGLContext");
 401 
 402     oglc = (OGLContext *)malloc(sizeof(OGLContext));
 403     if (oglc == NULL) {
 404         J2dRlsTraceLn(J2D_TRACE_ERROR,
 405             "GLXGC_InitOGLContext: could not allocate memory for oglc");
 406         return NULL;
 407     }
 408 
 409     memset(oglc, 0, sizeof(OGLContext));
 410 
 411     ctxinfo = (GLXCtxInfo *)malloc(sizeof(GLXCtxInfo));
 412     if (ctxinfo == NULL) {
 413         J2dRlsTraceLn(J2D_TRACE_ERROR,
 414             "GLXGC_InitOGLContext: could not allocate memory for ctxinfo");
 415         free(oglc);
 416         return NULL;
 417     }
 418 
 419     ctxinfo->fbconfig = fbconfig;
 420     ctxinfo->context = context;
 421     ctxinfo->scratchSurface = scratch;
 422     oglc->ctxInfo = ctxinfo;
 423     oglc->caps = caps;
 424 
 425     return oglc;
 426 }
 427 
 428 #endif /* !HEADLESS */
 429 
 430 /**
 431  * Determines whether the GLX pipeline can be used for a given GraphicsConfig
 432  * provided its screen number and visual ID.  If the minimum requirements are
 433  * met, the native GLXGraphicsConfigInfo structure is initialized for this
 434  * GraphicsConfig with the necessary information (GLXFBConfig, etc.)
 435  * and a pointer to this structure is returned as a jlong.  If
 436  * initialization fails at any point, zero is returned, indicating that GLX
 437  * cannot be used for this GraphicsConfig (we should fallback on the existing
 438  * X11 pipeline).
 439  */
 440 JNIEXPORT jlong JNICALL
 441 Java_sun_java2d_opengl_GLXGraphicsConfig_getGLXConfigInfo(JNIEnv *env,
 442                                                           jclass glxgc,
 443                                                           jint screennum,
 444                                                           jint visnum)
 445 {
 446 #ifndef HEADLESS
 447     OGLContext *oglc;
 448     GLXFBConfig fbconfig;
 449     GLXContext context;
 450     GLXPbuffer scratch;
 451     GLXGraphicsConfigInfo *glxinfo;
 452     jint caps = CAPS_EMPTY;
 453     int db;
 454     const unsigned char *versionstr;
 455 
 456     J2dRlsTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getGLXConfigInfo");
 457 
 458     if (usingXinerama) {
 459         // when Xinerama is enabled, the screen ID needs to be 0
 460         screennum = 0;
 461     }
 462 
 463     fbconfig = GLXGC_InitFBConfig(env, screennum, (VisualID)visnum);
 464     if (fbconfig == 0) {
 465         J2dRlsTraceLn(J2D_TRACE_ERROR,
 466             "GLXGraphicsConfig_getGLXConfigInfo: could not create fbconfig");
 467         return 0L;
 468     }
 469 
 470     if (sharedContext == 0) {
 471         // create the one shared context
 472         sharedContext = j2d_glXCreateNewContext(awt_display, fbconfig,
 473                                                 GLX_RGBA_TYPE, 0, GL_TRUE);
 474         if (sharedContext == 0) {
 475             J2dRlsTraceLn(J2D_TRACE_ERROR,
 476                 "GLXGraphicsConfig_getGLXConfigInfo: could not create shared context");
 477             return 0L;
 478         }
 479     }
 480 
 481     // create the GLXContext for this GLXGraphicsConfig
 482     context = j2d_glXCreateNewContext(awt_display, fbconfig,
 483                                       GLX_RGBA_TYPE, sharedContext,
 484                                       GL_TRUE);
 485     if (context == 0) {
 486         J2dRlsTraceLn(J2D_TRACE_ERROR,
 487             "GLXGraphicsConfig_getGLXConfigInfo: could not create GLX context");
 488         return 0L;
 489     }
 490 
 491     // this is pretty sketchy, but it seems to be the easiest way to create
 492     // some form of GLXDrawable using only the display and a GLXFBConfig
 493     // (in order to make the context current for checking the version,
 494     // extensions, etc)...
 495     scratch = GLXGC_InitScratchPbuffer(fbconfig);
 496     if (scratch == 0) {
 497         J2dRlsTraceLn(J2D_TRACE_ERROR,
 498             "GLXGraphicsConfig_getGLXConfigInfo: could not create scratch pbuffer");
 499         j2d_glXDestroyContext(awt_display, context);
 500         return 0L;
 501     }
 502 
 503     // the context must be made current before we can query the
 504     // version and extension strings
 505     j2d_glXMakeContextCurrent(awt_display, scratch, scratch, context);
 506 
 507     versionstr = j2d_glGetString(GL_VERSION);
 508     OGLContext_GetExtensionInfo(env, &caps);
 509 
 510     // destroy the temporary resources
 511     j2d_glXMakeContextCurrent(awt_display, None, None, NULL);
 512 
 513     J2dRlsTraceLn1(J2D_TRACE_INFO,
 514         "GLXGraphicsConfig_getGLXConfigInfo: OpenGL version=%s",
 515                    (versionstr == NULL) ? "null" : (char *)versionstr);
 516 
 517     if (!OGLContext_IsVersionSupported(versionstr)) {
 518         J2dRlsTraceLn(J2D_TRACE_ERROR,
 519             "GLXGraphicsConfig_getGLXConfigInfo: OpenGL 1.2 is required");
 520         j2d_glXDestroyPbuffer(awt_display, scratch);
 521         j2d_glXDestroyContext(awt_display, context);
 522         return 0L;
 523     }
 524 
 525     // get config-specific capabilities
 526     j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_DOUBLEBUFFER, &db);
 527     if (db) {
 528         caps |= CAPS_DOUBLEBUFFERED;
 529     }
 530 
 531     // initialize the OGLContext, which wraps the GLXFBConfig and GLXContext
 532     oglc = GLXGC_InitOGLContext(fbconfig, context, scratch, caps);
 533     if (oglc == NULL) {
 534         J2dRlsTraceLn(J2D_TRACE_ERROR,
 535             "GLXGraphicsConfig_getGLXConfigInfo: could not create oglc");
 536         j2d_glXDestroyPbuffer(awt_display, scratch);
 537         j2d_glXDestroyContext(awt_display, context);
 538         return 0L;
 539     }
 540 
 541     J2dTraceLn(J2D_TRACE_VERBOSE,
 542         "GLXGraphicsConfig_getGLXConfigInfo: finished checking dependencies");
 543 
 544     // create the GLXGraphicsConfigInfo record for this config
 545     glxinfo = (GLXGraphicsConfigInfo *)malloc(sizeof(GLXGraphicsConfigInfo));
 546     if (glxinfo == NULL) {
 547         J2dRlsTraceLn(J2D_TRACE_ERROR,
 548             "GLXGraphicsConfig_getGLXConfigInfo: could not allocate memory for glxinfo");
 549         GLXGC_DestroyOGLContext(oglc);
 550         return 0L;
 551     }
 552 
 553     glxinfo->screen = screennum;
 554     glxinfo->visual = visnum;
 555     glxinfo->context = oglc;
 556     glxinfo->fbconfig = fbconfig;
 557 
 558     return ptr_to_jlong(glxinfo);
 559 #else
 560     return 0L;
 561 #endif /* !HEADLESS */
 562 }
 563 
 564 JNIEXPORT void JNICALL
 565 Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig(JNIEnv *env,
 566                                                     jobject glxgc,
 567                                                     jlong aData,
 568                                                     jlong configInfo)
 569 {
 570 #ifndef HEADLESS
 571     GLXGraphicsConfigInfo *glxinfo;
 572     AwtGraphicsConfigDataPtr configData =
 573         (AwtGraphicsConfigDataPtr)jlong_to_ptr(aData);
 574 
 575     J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_initConfig");
 576 
 577     if (configData == NULL) {
 578         JNU_ThrowNullPointerException(env, "Native GraphicsConfig missing");
 579         return;
 580     }
 581 
 582     glxinfo = (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);
 583     if (glxinfo == NULL) {
 584         JNU_ThrowNullPointerException(env,
 585                                       "GLXGraphicsConfigInfo data missing");
 586         return;
 587     }
 588 
 589     configData->glxInfo = glxinfo;
 590 #endif /* !HEADLESS */
 591 }
 592 
 593 JNIEXPORT jint JNICALL
 594 Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities(JNIEnv *env,
 595                                                             jclass glxgc,
 596                                                             jlong configInfo)
 597 {
 598 #ifndef HEADLESS
 599     GLXGraphicsConfigInfo *glxinfo =
 600         (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);
 601 
 602     J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getOGLCapabilities");
 603 
 604     if (glxinfo == NULL || glxinfo->context == NULL) {
 605         return CAPS_EMPTY;
 606     }
 607 
 608     return glxinfo->context->caps;
 609 #else
 610     return CAPS_EMPTY;
 611 #endif /* !HEADLESS */
 612 }