Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/unix/native/common/java2d/opengl/GLXGraphicsConfig.c
41159 views
1
/*
2
* Copyright (c) 2003, 2020, 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
}
613
614