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 | #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, 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 | */ |
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; |
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 | |
620 | JNIEXPORT void JNICALL |
621 | Java_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 | |
649 | JNIEXPORT jint JNICALL |
650 | Java_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 | |