blob: 6c340fd7f9e138a0cd0cf7ce4afc5d75ef2a167a [file] [log] [blame]
Brian Paul21666e32002-10-05 18:30:13 +00001
2/*
3 * OpenGL pbuffers utility functions.
4 *
5 * Brian Paul
Brian Paulf72e4422005-01-04 00:58:29 +00006 * Original code: April 1997
Brian Paul21666e32002-10-05 18:30:13 +00007 * Updated on 5 October 2002
Brian Paulf72e4422005-01-04 00:58:29 +00008 * Updated again on 3 January 2005 to use GLX 1.3 functions in preference
9 * to the GLX_SGIX_fbconfig/pbuffer extensions.
Brian Paul21666e32002-10-05 18:30:13 +000010 */
11
Brian Paul21666e32002-10-05 18:30:13 +000012#include <stdio.h>
13#include <string.h>
14#include "pbutil.h"
15
16
Brian Paulf72e4422005-01-04 00:58:29 +000017/**
Brian Paul21666e32002-10-05 18:30:13 +000018 * Test if we pixel buffers are available for a particular X screen.
19 * Input: dpy - the X display
20 * screen - screen number
21 * Return: 0 = pixel buffers not available.
Brian Paulf72e4422005-01-04 00:58:29 +000022 * 1 = pixel buffers are available via GLX 1.3.
23 * 2 = pixel buffers are available via GLX_SGIX_fbconfig/pbuffer.
Brian Paul21666e32002-10-05 18:30:13 +000024 */
25int
26QueryPbuffers(Display *dpy, int screen)
27{
Brian Paulf72e4422005-01-04 00:58:29 +000028#if defined(GLX_VERSION_1_3)
29 {
30 /* GLX 1.3 supports pbuffers */
31 int glxVersionMajor, glxVersionMinor;
32 if (!glXQueryVersion(dpy, &glxVersionMajor, &glxVersionMinor)) {
33 /* GLX not available! */
34 return 0;
35 }
36 if (glxVersionMajor * 100 + glxVersionMinor >= 103) {
37 return 1;
38 }
39 /* fall-through */
Brian Paul21666e32002-10-05 18:30:13 +000040 }
Brian Paul21666e32002-10-05 18:30:13 +000041#endif
Brian Paulf72e4422005-01-04 00:58:29 +000042
43#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
44 /* Try the SGIX extensions */
45 {
46 char *extensions;
47 extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS);
48 if (!extensions ||
49 !strstr(extensions,"GLX_SGIX_fbconfig") ||
50 !strstr(extensions,"GLX_SGIX_pbuffer")) {
51 return 0;
52 }
53 return 2;
54 }
55#endif
56
57 return 0;
Brian Paul21666e32002-10-05 18:30:13 +000058}
59
60
61
Brian Paulf72e4422005-01-04 00:58:29 +000062FBCONFIG *
63ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs)
64{
65 int pbSupport = QueryPbuffers(dpy, screen);
66#if defined(GLX_VERSION_1_3)
67 if (pbSupport == 1) {
68 return glXChooseFBConfig(dpy, screen, attribs, nConfigs);
69 }
70#endif
71#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
72 if (pbSupport == 2) {
73 return glXChooseFBConfigSGIX(dpy, screen, (int *) attribs, nConfigs);
74 }
75#endif
76 return NULL;
77}
Brian Paul21666e32002-10-05 18:30:13 +000078
79
Brian Paulba5ceda2005-01-07 01:17:42 +000080FBCONFIG *
81GetAllFBConfigs(Display *dpy, int screen, int *nConfigs)
82{
83 int pbSupport = QueryPbuffers(dpy, screen);
84#if defined(GLX_VERSION_1_3)
85 if (pbSupport == 1) {
86 return glXGetFBConfigs(dpy, screen, nConfigs);
87 }
88#endif
89#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
90 if (pbSupport == 2) {
Brian Paulc3984fc2005-04-06 22:40:39 +000091 /* The GLX_SGIX_fbconfig extensions says to pass NULL to get list
92 * of all available configurations.
93 */
94 return glXChooseFBConfigSGIX(dpy, screen, NULL, nConfigs);
Brian Paulba5ceda2005-01-07 01:17:42 +000095 }
96#endif
97 return NULL;
98}
99
Brian Paulf72e4422005-01-04 00:58:29 +0000100
101XVisualInfo *
102GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config)
103{
104 int pbSupport = QueryPbuffers(dpy, screen);
105#if defined(GLX_VERSION_1_3)
106 if (pbSupport == 1) {
107 return glXGetVisualFromFBConfig(dpy, config);
108 }
109#endif
110#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
111 if (pbSupport == 2) {
112 return glXGetVisualFromFBConfigSGIX(dpy, config);
113 }
114#endif
115 return NULL;
116}
117
118
119/**
120 * Either use glXGetFBConfigAttrib() or glXGetFBConfigAttribSGIX()
121 * to query an fbconfig attribute.
122 */
123static int
Brian Paulff53a4e2005-01-10 23:15:59 +0000124GetFBConfigAttrib(Display *dpy, int screen,
Brian Paulf72e4422005-01-04 00:58:29 +0000125#if defined(GLX_VERSION_1_3)
126 const GLXFBConfig config,
127#elif defined(GLX_SGIX_fbconfig)
128 const GLXFBConfigSGIX config,
129#endif
130 int attrib
131 )
132{
Brian Paulff53a4e2005-01-10 23:15:59 +0000133 int pbSupport = QueryPbuffers(dpy, screen);
134 int value = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000135
136#if defined(GLX_VERSION_1_3)
Brian Paulff53a4e2005-01-10 23:15:59 +0000137 if (pbSupport == 1) {
Brian Paulf72e4422005-01-04 00:58:29 +0000138 /* ok */
139 if (glXGetFBConfigAttrib(dpy, config, attrib, &value) != 0) {
140 value = 0;
141 }
142 return value;
143 }
144 /* fall-through */
145#endif
146
147#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000148 if (pbSupport == 2) {
149 if (glXGetFBConfigAttribSGIX(dpy, config, attrib, &value) != 0) {
150 value = 0;
151 }
152 return value;
Brian Paulf72e4422005-01-04 00:58:29 +0000153 }
Brian Paulf72e4422005-01-04 00:58:29 +0000154#endif
155
Brian Paulff53a4e2005-01-10 23:15:59 +0000156 return value;
Brian Paulf72e4422005-01-04 00:58:29 +0000157}
158
159
160
161/**
Brian Paul21666e32002-10-05 18:30:13 +0000162 * Print parameters for a GLXFBConfig to stdout.
163 * Input: dpy - the X display
Brian Paulf72e4422005-01-04 00:58:29 +0000164 * screen - the X screen number
Brian Paul21666e32002-10-05 18:30:13 +0000165 * fbConfig - the fbconfig handle
166 * horizFormat - if true, print in horizontal format
167 */
168void
Brian Paulf72e4422005-01-04 00:58:29 +0000169PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat)
Brian Paul21666e32002-10-05 18:30:13 +0000170{
Brian Paulf72e4422005-01-04 00:58:29 +0000171 PBUFFER pBuffer;
Brian Paul21666e32002-10-05 18:30:13 +0000172 int width=2, height=2;
173 int bufferSize, level, doubleBuffer, stereo, auxBuffers;
174 int redSize, greenSize, blueSize, alphaSize;
175 int depthSize, stencilSize;
176 int accumRedSize, accumBlueSize, accumGreenSize, accumAlphaSize;
177 int sampleBuffers, samples;
178 int drawableType, renderType, xRenderable, xVisual, id;
179 int maxWidth, maxHeight, maxPixels;
180 int optWidth, optHeight;
Brian Paulff53a4e2005-01-10 23:15:59 +0000181 int floatComponents = 0;
Brian Paul21666e32002-10-05 18:30:13 +0000182
Brian Paulf72e4422005-01-04 00:58:29 +0000183 /* do queries using the GLX 1.3 tokens (same as the SGIX tokens) */
Brian Paulff53a4e2005-01-10 23:15:59 +0000184 bufferSize = GetFBConfigAttrib(dpy, screen, config, GLX_BUFFER_SIZE);
185 level = GetFBConfigAttrib(dpy, screen, config, GLX_LEVEL);
186 doubleBuffer = GetFBConfigAttrib(dpy, screen, config, GLX_DOUBLEBUFFER);
187 stereo = GetFBConfigAttrib(dpy, screen, config, GLX_STEREO);
188 auxBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_AUX_BUFFERS);
189 redSize = GetFBConfigAttrib(dpy, screen, config, GLX_RED_SIZE);
190 greenSize = GetFBConfigAttrib(dpy, screen, config, GLX_GREEN_SIZE);
191 blueSize = GetFBConfigAttrib(dpy, screen, config, GLX_BLUE_SIZE);
192 alphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ALPHA_SIZE);
193 depthSize = GetFBConfigAttrib(dpy, screen, config, GLX_DEPTH_SIZE);
194 stencilSize = GetFBConfigAttrib(dpy, screen, config, GLX_STENCIL_SIZE);
195 accumRedSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_RED_SIZE);
196 accumGreenSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_GREEN_SIZE);
197 accumBlueSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_BLUE_SIZE);
198 accumAlphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_ALPHA_SIZE);
199 sampleBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLE_BUFFERS);
200 samples = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLES);
201 drawableType = GetFBConfigAttrib(dpy, screen, config, GLX_DRAWABLE_TYPE);
202 renderType = GetFBConfigAttrib(dpy, screen, config, GLX_RENDER_TYPE);
203 xRenderable = GetFBConfigAttrib(dpy, screen, config, GLX_X_RENDERABLE);
204 xVisual = GetFBConfigAttrib(dpy, screen, config, GLX_X_VISUAL_TYPE);
Brian Paul21666e32002-10-05 18:30:13 +0000205 if (!xRenderable || !(drawableType & GLX_WINDOW_BIT_SGIX))
206 xVisual = -1;
Brian Paul21666e32002-10-05 18:30:13 +0000207
Brian Paulff53a4e2005-01-10 23:15:59 +0000208 id = GetFBConfigAttrib(dpy, screen, config, GLX_FBCONFIG_ID);
209 maxWidth = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_WIDTH);
210 maxHeight = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_HEIGHT);
211 maxPixels = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_PIXELS);
Brian Paulf72e4422005-01-04 00:58:29 +0000212#if defined(GLX_SGIX_pbuffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000213 optWidth = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_WIDTH_SGIX);
214 optHeight = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX);
Brian Paulf72e4422005-01-04 00:58:29 +0000215#else
216 optWidth = optHeight = 0;
217#endif
218#if defined(GLX_NV_float_buffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000219 floatComponents = GetFBConfigAttrib(dpy, screen, config, GLX_FLOAT_COMPONENTS_NV);
Brian Paulf72e4422005-01-04 00:58:29 +0000220#endif
Brian Paul21666e32002-10-05 18:30:13 +0000221
Brian Paulf72e4422005-01-04 00:58:29 +0000222 /* See if we can create a pbuffer with this config */
223 pBuffer = CreatePbuffer(dpy, screen, config, width, height, False, False);
Brian Paul21666e32002-10-05 18:30:13 +0000224
225 if (horizFormat) {
Brian Paulff53a4e2005-01-10 23:15:59 +0000226 printf("0x%-9x ", id);
Brian Paul21666e32002-10-05 18:30:13 +0000227 if (xVisual==GLX_STATIC_GRAY) printf("StaticGray ");
228 else if (xVisual==GLX_GRAY_SCALE) printf("GrayScale ");
229 else if (xVisual==GLX_STATIC_COLOR) printf("StaticColor ");
230 else if (xVisual==GLX_PSEUDO_COLOR) printf("PseudoColor ");
231 else if (xVisual==GLX_TRUE_COLOR) printf("TrueColor ");
232 else if (xVisual==GLX_DIRECT_COLOR) printf("DirectColor ");
233 else printf(" -none- ");
234 printf(" %3d %3d %s %s %s %2s ", bufferSize, level,
Brian Paulff53a4e2005-01-10 23:15:59 +0000235 (renderType & GLX_RGBA_BIT_SGIX) ? "y" : ".",
236 (renderType & GLX_COLOR_INDEX_BIT_SGIX) ? "y" : ".",
237 doubleBuffer ? "y" : ".",
238 stereo ? "y" : ".");
Brian Paul21666e32002-10-05 18:30:13 +0000239 printf("%2d %2d %2d %2d ", redSize, greenSize, blueSize, alphaSize);
240 printf("%2d %2d ", depthSize, stencilSize);
241 printf("%2d %2d %2d %2d", accumRedSize, accumGreenSize, accumBlueSize,
242 accumAlphaSize);
243 printf(" %2d %2d", sampleBuffers, samples);
Brian Paulff53a4e2005-01-10 23:15:59 +0000244 printf(" %s %c", pBuffer ? "y" : ".",
245 ".y"[floatComponents]);
Brian Paul21666e32002-10-05 18:30:13 +0000246 printf("\n");
247 }
248 else {
249 printf("Id 0x%x\n", id);
250 printf(" Buffer Size: %d\n", bufferSize);
251 printf(" Level: %d\n", level);
252 printf(" Double Buffer: %s\n", doubleBuffer ? "yes" : "no");
253 printf(" Stereo: %s\n", stereo ? "yes" : "no");
254 printf(" Aux Buffers: %d\n", auxBuffers);
255 printf(" Red Size: %d\n", redSize);
256 printf(" Green Size: %d\n", greenSize);
257 printf(" Blue Size: %d\n", blueSize);
258 printf(" Alpha Size: %d\n", alphaSize);
259 printf(" Depth Size: %d\n", depthSize);
260 printf(" Stencil Size: %d\n", stencilSize);
261 printf(" Accum Red Size: %d\n", accumRedSize);
262 printf(" Accum Green Size: %d\n", accumGreenSize);
263 printf(" Accum Blue Size: %d\n", accumBlueSize);
264 printf(" Accum Alpha Size: %d\n", accumAlphaSize);
265 printf(" Sample Buffers: %d\n", sampleBuffers);
266 printf(" Samples/Pixel: %d\n", samples);
267 printf(" Drawable Types: ");
Brian Paulf72e4422005-01-04 00:58:29 +0000268 if (drawableType & GLX_WINDOW_BIT) printf("Window ");
269 if (drawableType & GLX_PIXMAP_BIT) printf("Pixmap ");
270 if (drawableType & GLX_PBUFFER_BIT) printf("PBuffer");
Brian Paul21666e32002-10-05 18:30:13 +0000271 printf("\n");
272 printf(" Render Types: ");
273 if (renderType & GLX_RGBA_BIT_SGIX) printf("RGBA ");
274 if (renderType & GLX_COLOR_INDEX_BIT_SGIX) printf("CI ");
275 printf("\n");
276 printf(" X Renderable: %s\n", xRenderable ? "yes" : "no");
Brian Paulf72e4422005-01-04 00:58:29 +0000277
Brian Paul21666e32002-10-05 18:30:13 +0000278 printf(" Pbuffer: %s\n", pBuffer ? "yes" : "no");
Brian Paulf72e4422005-01-04 00:58:29 +0000279 printf(" Max Pbuffer width: %d\n", maxWidth);
280 printf(" Max Pbuffer height: %d\n", maxHeight);
281 printf(" Max Pbuffer pixels: %d\n", maxPixels);
282 printf(" Optimum Pbuffer width: %d\n", optWidth);
283 printf(" Optimum Pbuffer height: %d\n", optHeight);
284
285 printf(" Float Components: %s\n", floatComponents ? "yes" : "no");
Brian Paul21666e32002-10-05 18:30:13 +0000286 }
287
288 if (pBuffer) {
Brian Paulf72e4422005-01-04 00:58:29 +0000289 DestroyPbuffer(dpy, screen, pBuffer);
Brian Paul21666e32002-10-05 18:30:13 +0000290 }
291}
292
293
294
Brian Paulc6178292005-04-06 22:41:46 +0000295GLXContext
296CreateContext(Display *dpy, int screen, FBCONFIG config)
297{
298 int pbSupport = QueryPbuffers(dpy, screen);
299#if defined(GLX_VERSION_1_3)
300 if (pbSupport == 1) {
301 /* GLX 1.3 */
302 GLXContext c;
303 c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, True);
304 if (!c) {
305 /* try indirect */
306 c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, False);
307 }
308 return c;
309 }
310#endif
311#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
312 if (pbSupport == 2) {
313 GLXContext c;
314 c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, True);
315 if (!c) {
316 c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, False);
317 }
318 return c;
319 }
320#endif
321 return 0;
322}
323
324
325void
326DestroyContext(Display *dpy, GLXContext ctx)
327{
328 glXDestroyContext(dpy, ctx);
329}
330
331
Brian Paul21666e32002-10-05 18:30:13 +0000332/* This is only used by CreatePbuffer() */
333static int XErrorFlag = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000334static int HandleXError(Display *dpy, XErrorEvent *event)
Brian Paul21666e32002-10-05 18:30:13 +0000335{
336 XErrorFlag = 1;
337 return 0;
338}
339
340
Brian Paulf72e4422005-01-04 00:58:29 +0000341/**
Brian Paul18a94902004-02-02 15:38:26 +0000342 * Create a Pbuffer. Use an X error handler to deal with potential
343 * BadAlloc errors.
Brian Paul21666e32002-10-05 18:30:13 +0000344 *
345 * Input: dpy - the X display
346 * fbConfig - an FBConfig as returned by glXChooseFBConfigSGIX().
347 * width, height - size of pixel buffer to request, in pixels.
Brian Paulf72e4422005-01-04 00:58:29 +0000348 * pbAttribs - list of optional pixel buffer attributes
349 * Return: a Pbuffer or None.
Brian Paul21666e32002-10-05 18:30:13 +0000350 */
Brian Paulf72e4422005-01-04 00:58:29 +0000351PBUFFER
352CreatePbuffer(Display *dpy, int screen, FBCONFIG config,
353 int width, int height, Bool largest, Bool preserve)
Brian Paul21666e32002-10-05 18:30:13 +0000354{
Brian Paulf72e4422005-01-04 00:58:29 +0000355 int (*oldHandler)(Display *, XErrorEvent *);
356 PBUFFER pBuffer = None;
357 int pbSupport = QueryPbuffers(dpy, screen);
Brian Paul21666e32002-10-05 18:30:13 +0000358
359 /* Catch X protocol errors with our own error handler */
Brian Paulf72e4422005-01-04 00:58:29 +0000360 oldHandler = XSetErrorHandler(HandleXError);
Brian Paul21666e32002-10-05 18:30:13 +0000361 XErrorFlag = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000362
363#if defined(GLX_VERSION_1_3)
364 if (pbSupport == 1) {
365 /* GLX 1.3 */
366 int attribs[100], i = 0;
367 attribs[i++] = GLX_PBUFFER_WIDTH;
368 attribs[i++] = width;
369 attribs[i++] = GLX_PBUFFER_HEIGHT;
370 attribs[i++] = height;
371 attribs[i++] = GLX_PRESERVED_CONTENTS;
372 attribs[i++] = preserve;
373 attribs[i++] = GLX_LARGEST_PBUFFER;
374 attribs[i++] = largest;
375 attribs[i++] = 0;
376 pBuffer = glXCreatePbuffer(dpy, config, attribs);
377 }
378 else
379#endif
380#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
381 if (pbSupport == 2) {
382 int attribs[100], i = 0;
383 attribs[i++] = GLX_PRESERVED_CONTENTS;
384 attribs[i++] = preserve;
385 attribs[i++] = GLX_LARGEST_PBUFFER;
386 attribs[i++] = largest;
387 attribs[i++] = 0;
388 pBuffer = glXCreateGLXPbufferSGIX(dpy, config, width, height, attribs);
389 }
390 else
391#endif
392 {
393 pBuffer = None;
394 }
Brian Paul21666e32002-10-05 18:30:13 +0000395
Kristian Høgsbergc095f7e2007-08-30 13:00:20 -0400396 XSync(dpy, False);
Brian Paul21666e32002-10-05 18:30:13 +0000397 /* Restore original X error handler */
Brian Paulf72e4422005-01-04 00:58:29 +0000398 (void) XSetErrorHandler(oldHandler);
Brian Paul21666e32002-10-05 18:30:13 +0000399
400 /* Return pbuffer (may be None) */
Brian Paulf72e4422005-01-04 00:58:29 +0000401 if (!XErrorFlag && pBuffer != None) {
Brian Paul21666e32002-10-05 18:30:13 +0000402 /*printf("config %d worked!\n", i);*/
403 return pBuffer;
404 }
405 else {
406 return None;
407 }
408}
409
410
Brian Paulf72e4422005-01-04 00:58:29 +0000411void
412DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer)
413{
414 int pbSupport = QueryPbuffers(dpy, screen);
415#if defined(GLX_VERSION_1_3)
416 if (pbSupport == 1) {
417 glXDestroyPbuffer(dpy, pbuffer);
418 return;
419 }
420#endif
421#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
422 if (pbSupport == 2) {
423 glXDestroyGLXPbufferSGIX(dpy, pbuffer);
424 return;
425 }
426#endif
427}