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
40extern 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 */
48static 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 */
61static jboolean
62GLXGC_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 */
117jboolean
118GLXGC_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 */
136static void
137GLXGC_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 */
176void
177OGLGC_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 */
210static GLXFBConfig
211GLXGC_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 */
355VisualID
356GLXGC_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 */
398static GLXPbuffer
399GLXGC_InitScratchPbuffer(GLXFBConfig fbconfig)
400{
401    int pbattrlist[] = {GLX_PBUFFER_WIDTH, 4,
402                        GLX_PBUFFER_HEIGHT, 4,
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 */
415static OGLContext *
416GLXGC_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 */
462JNIEXPORT jlong JNICALL
463Java_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;
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
587    // initialize the OGLContext, which wraps the GLXFBConfig and GLXContext
588    oglc = GLXGC_InitOGLContext(fbconfig, context, scratch, caps);
589    if (oglc == NULL) {
590        J2dRlsTraceLn(J2D_TRACE_ERROR,
591            "GLXGraphicsConfig_getGLXConfigInfo: could not create oglc");
592        j2d_glXDestroyPbuffer(awt_display, scratch);
593        j2d_glXDestroyContext(awt_display, context);
594        return 0L;
595    }
596
597    J2dTraceLn(J2D_TRACE_VERBOSE,
598        "GLXGraphicsConfig_getGLXConfigInfo: finished checking dependencies");
599
600    // create the GLXGraphicsConfigInfo record for this config
601    glxinfo = (GLXGraphicsConfigInfo *)malloc(sizeof(GLXGraphicsConfigInfo));
602    if (glxinfo == NULL) {
603        J2dRlsTraceLn(J2D_TRACE_ERROR,
604            "GLXGraphicsConfig_getGLXConfigInfo: could not allocate memory for glxinfo");
605        GLXGC_DestroyOGLContext(oglc);
606        return 0L;
607    }
608
609    glxinfo->screen = screennum;
610    glxinfo->visual = visnum;
611    glxinfo->context = oglc;
612    glxinfo->fbconfig = fbconfig;
613
614    return ptr_to_jlong(glxinfo);
615#else
616    return 0L;
617#endif /* !HEADLESS */
618}
619
620JNIEXPORT void JNICALL
621Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig(JNIEnv *env,
622                                                    jobject glxgc,
623                                                    jlong aData,
624                                                    jlong configInfo)
625{
626#ifndef HEADLESS
627    GLXGraphicsConfigInfo *glxinfo;
628    AwtGraphicsConfigDataPtr configData =
629        (AwtGraphicsConfigDataPtr)jlong_to_ptr(aData);
630
631    J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_initConfig");
632
633    if (configData == NULL) {
634        JNU_ThrowNullPointerException(env, "Native GraphicsConfig missing");
635        return;
636    }
637
638    glxinfo = (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);
639    if (glxinfo == NULL) {
640        JNU_ThrowNullPointerException(env,
641                                      "GLXGraphicsConfigInfo data missing");
642        return;
643    }
644
645    configData->glxInfo = glxinfo;
646#endif /* !HEADLESS */
647}
648
649JNIEXPORT jint JNICALL
650Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities(JNIEnv *env,
651                                                            jclass glxgc,
652                                                            jlong configInfo)
653{
654#ifndef HEADLESS
655    GLXGraphicsConfigInfo *glxinfo =
656        (GLXGraphicsConfigInfo *)jlong_to_ptr(configInfo);
657
658    J2dTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getOGLCapabilities");
659
660    if (glxinfo == NULL || glxinfo->context == NULL) {
661        return CAPS_EMPTY;
662    }
663
664    return glxinfo->context->caps;
665#else
666    return CAPS_EMPTY;
667#endif /* !HEADLESS */
668}
669