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