blob: c9df5b3a05bece7a5a4f1b8c1d0a2b69c288318e [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
12
13#include <stdio.h>
14#include <string.h>
15#include "pbutil.h"
16
17
Brian Paulf72e4422005-01-04 00:58:29 +000018/**
Brian Paul21666e32002-10-05 18:30:13 +000019 * Test if we pixel buffers are available for a particular X screen.
20 * Input: dpy - the X display
21 * screen - screen number
22 * Return: 0 = pixel buffers not available.
Brian Paulf72e4422005-01-04 00:58:29 +000023 * 1 = pixel buffers are available via GLX 1.3.
24 * 2 = pixel buffers are available via GLX_SGIX_fbconfig/pbuffer.
Brian Paul21666e32002-10-05 18:30:13 +000025 */
26int
27QueryPbuffers(Display *dpy, int screen)
28{
Brian Paulff53a4e2005-01-10 23:15:59 +000029 return 1;
Brian Paulf72e4422005-01-04 00:58:29 +000030#if defined(GLX_VERSION_1_3)
31 {
32 /* GLX 1.3 supports pbuffers */
33 int glxVersionMajor, glxVersionMinor;
34 if (!glXQueryVersion(dpy, &glxVersionMajor, &glxVersionMinor)) {
35 /* GLX not available! */
36 return 0;
37 }
38 if (glxVersionMajor * 100 + glxVersionMinor >= 103) {
39 return 1;
40 }
41 /* fall-through */
Brian Paul21666e32002-10-05 18:30:13 +000042 }
Brian Paul21666e32002-10-05 18:30:13 +000043#endif
Brian Paulf72e4422005-01-04 00:58:29 +000044
45#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
46 /* Try the SGIX extensions */
47 {
48 char *extensions;
49 extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS);
50 if (!extensions ||
51 !strstr(extensions,"GLX_SGIX_fbconfig") ||
52 !strstr(extensions,"GLX_SGIX_pbuffer")) {
53 return 0;
54 }
55 return 2;
56 }
57#endif
58
59 return 0;
Brian Paul21666e32002-10-05 18:30:13 +000060}
61
62
63
Brian Paulf72e4422005-01-04 00:58:29 +000064FBCONFIG *
65ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs)
66{
67 int pbSupport = QueryPbuffers(dpy, screen);
68#if defined(GLX_VERSION_1_3)
69 if (pbSupport == 1) {
70 return glXChooseFBConfig(dpy, screen, attribs, nConfigs);
71 }
72#endif
73#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
74 if (pbSupport == 2) {
75 return glXChooseFBConfigSGIX(dpy, screen, (int *) attribs, nConfigs);
76 }
77#endif
78 return NULL;
79}
Brian Paul21666e32002-10-05 18:30:13 +000080
81
Brian Paulba5ceda2005-01-07 01:17:42 +000082FBCONFIG *
83GetAllFBConfigs(Display *dpy, int screen, int *nConfigs)
84{
85 int pbSupport = QueryPbuffers(dpy, screen);
86#if defined(GLX_VERSION_1_3)
87 if (pbSupport == 1) {
88 return glXGetFBConfigs(dpy, screen, nConfigs);
89 }
90#endif
91#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
92 if (pbSupport == 2) {
93 /* this *seems* to work, but may not be perfect */
94 static int fbAttribs[] = {
95 GLX_RENDER_TYPE, 0,
96 GLX_DRAWABLE_TYPE, 0,
97 None
98 };
99 return glXChooseFBConfigSGIX(dpy, screen, fbAttribs, nConfigs);
100 }
101#endif
102 return NULL;
103}
104
Brian Paulf72e4422005-01-04 00:58:29 +0000105
106XVisualInfo *
107GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config)
108{
109 int pbSupport = QueryPbuffers(dpy, screen);
110#if defined(GLX_VERSION_1_3)
111 if (pbSupport == 1) {
112 return glXGetVisualFromFBConfig(dpy, config);
113 }
114#endif
115#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
116 if (pbSupport == 2) {
117 return glXGetVisualFromFBConfigSGIX(dpy, config);
118 }
119#endif
120 return NULL;
121}
122
123
124/**
125 * Either use glXGetFBConfigAttrib() or glXGetFBConfigAttribSGIX()
126 * to query an fbconfig attribute.
127 */
128static int
Brian Paulff53a4e2005-01-10 23:15:59 +0000129GetFBConfigAttrib(Display *dpy, int screen,
Brian Paulf72e4422005-01-04 00:58:29 +0000130#if defined(GLX_VERSION_1_3)
131 const GLXFBConfig config,
132#elif defined(GLX_SGIX_fbconfig)
133 const GLXFBConfigSGIX config,
134#endif
135 int attrib
136 )
137{
Brian Paulff53a4e2005-01-10 23:15:59 +0000138 int pbSupport = QueryPbuffers(dpy, screen);
139 int value = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000140
141#if defined(GLX_VERSION_1_3)
Brian Paulff53a4e2005-01-10 23:15:59 +0000142 if (pbSupport == 1) {
Brian Paulf72e4422005-01-04 00:58:29 +0000143 /* ok */
144 if (glXGetFBConfigAttrib(dpy, config, attrib, &value) != 0) {
145 value = 0;
146 }
147 return value;
148 }
149 /* fall-through */
150#endif
151
152#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000153 if (pbSupport == 2) {
154 if (glXGetFBConfigAttribSGIX(dpy, config, attrib, &value) != 0) {
155 value = 0;
156 }
157 return value;
Brian Paulf72e4422005-01-04 00:58:29 +0000158 }
Brian Paulf72e4422005-01-04 00:58:29 +0000159#endif
160
Brian Paulff53a4e2005-01-10 23:15:59 +0000161 return value;
Brian Paulf72e4422005-01-04 00:58:29 +0000162}
163
164
165
166/**
Brian Paul21666e32002-10-05 18:30:13 +0000167 * Print parameters for a GLXFBConfig to stdout.
168 * Input: dpy - the X display
Brian Paulf72e4422005-01-04 00:58:29 +0000169 * screen - the X screen number
Brian Paul21666e32002-10-05 18:30:13 +0000170 * fbConfig - the fbconfig handle
171 * horizFormat - if true, print in horizontal format
172 */
173void
Brian Paulf72e4422005-01-04 00:58:29 +0000174PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat)
Brian Paul21666e32002-10-05 18:30:13 +0000175{
Brian Paulf72e4422005-01-04 00:58:29 +0000176 PBUFFER pBuffer;
Brian Paul21666e32002-10-05 18:30:13 +0000177 int width=2, height=2;
178 int bufferSize, level, doubleBuffer, stereo, auxBuffers;
179 int redSize, greenSize, blueSize, alphaSize;
180 int depthSize, stencilSize;
181 int accumRedSize, accumBlueSize, accumGreenSize, accumAlphaSize;
182 int sampleBuffers, samples;
183 int drawableType, renderType, xRenderable, xVisual, id;
184 int maxWidth, maxHeight, maxPixels;
185 int optWidth, optHeight;
Brian Paulff53a4e2005-01-10 23:15:59 +0000186 int floatComponents = 0;
Brian Paul21666e32002-10-05 18:30:13 +0000187
Brian Paulf72e4422005-01-04 00:58:29 +0000188 /* do queries using the GLX 1.3 tokens (same as the SGIX tokens) */
Brian Paulff53a4e2005-01-10 23:15:59 +0000189 bufferSize = GetFBConfigAttrib(dpy, screen, config, GLX_BUFFER_SIZE);
190 level = GetFBConfigAttrib(dpy, screen, config, GLX_LEVEL);
191 doubleBuffer = GetFBConfigAttrib(dpy, screen, config, GLX_DOUBLEBUFFER);
192 stereo = GetFBConfigAttrib(dpy, screen, config, GLX_STEREO);
193 auxBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_AUX_BUFFERS);
194 redSize = GetFBConfigAttrib(dpy, screen, config, GLX_RED_SIZE);
195 greenSize = GetFBConfigAttrib(dpy, screen, config, GLX_GREEN_SIZE);
196 blueSize = GetFBConfigAttrib(dpy, screen, config, GLX_BLUE_SIZE);
197 alphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ALPHA_SIZE);
198 depthSize = GetFBConfigAttrib(dpy, screen, config, GLX_DEPTH_SIZE);
199 stencilSize = GetFBConfigAttrib(dpy, screen, config, GLX_STENCIL_SIZE);
200 accumRedSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_RED_SIZE);
201 accumGreenSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_GREEN_SIZE);
202 accumBlueSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_BLUE_SIZE);
203 accumAlphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_ALPHA_SIZE);
204 sampleBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLE_BUFFERS);
205 samples = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLES);
206 drawableType = GetFBConfigAttrib(dpy, screen, config, GLX_DRAWABLE_TYPE);
207 renderType = GetFBConfigAttrib(dpy, screen, config, GLX_RENDER_TYPE);
208 xRenderable = GetFBConfigAttrib(dpy, screen, config, GLX_X_RENDERABLE);
209 xVisual = GetFBConfigAttrib(dpy, screen, config, GLX_X_VISUAL_TYPE);
Brian Paul21666e32002-10-05 18:30:13 +0000210 if (!xRenderable || !(drawableType & GLX_WINDOW_BIT_SGIX))
211 xVisual = -1;
Brian Paul21666e32002-10-05 18:30:13 +0000212
Brian Paulff53a4e2005-01-10 23:15:59 +0000213 id = GetFBConfigAttrib(dpy, screen, config, GLX_FBCONFIG_ID);
214 maxWidth = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_WIDTH);
215 maxHeight = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_HEIGHT);
216 maxPixels = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_PIXELS);
Brian Paulf72e4422005-01-04 00:58:29 +0000217#if defined(GLX_SGIX_pbuffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000218 optWidth = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_WIDTH_SGIX);
219 optHeight = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX);
Brian Paulf72e4422005-01-04 00:58:29 +0000220#else
221 optWidth = optHeight = 0;
222#endif
223#if defined(GLX_NV_float_buffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000224 floatComponents = GetFBConfigAttrib(dpy, screen, config, GLX_FLOAT_COMPONENTS_NV);
Brian Paulf72e4422005-01-04 00:58:29 +0000225#endif
Brian Paul21666e32002-10-05 18:30:13 +0000226
Brian Paulf72e4422005-01-04 00:58:29 +0000227 /* See if we can create a pbuffer with this config */
228 pBuffer = CreatePbuffer(dpy, screen, config, width, height, False, False);
Brian Paul21666e32002-10-05 18:30:13 +0000229
230 if (horizFormat) {
Brian Paulff53a4e2005-01-10 23:15:59 +0000231 printf("0x%-9x ", id);
Brian Paul21666e32002-10-05 18:30:13 +0000232 if (xVisual==GLX_STATIC_GRAY) printf("StaticGray ");
233 else if (xVisual==GLX_GRAY_SCALE) printf("GrayScale ");
234 else if (xVisual==GLX_STATIC_COLOR) printf("StaticColor ");
235 else if (xVisual==GLX_PSEUDO_COLOR) printf("PseudoColor ");
236 else if (xVisual==GLX_TRUE_COLOR) printf("TrueColor ");
237 else if (xVisual==GLX_DIRECT_COLOR) printf("DirectColor ");
238 else printf(" -none- ");
239 printf(" %3d %3d %s %s %s %2s ", bufferSize, level,
Brian Paulff53a4e2005-01-10 23:15:59 +0000240 (renderType & GLX_RGBA_BIT_SGIX) ? "y" : ".",
241 (renderType & GLX_COLOR_INDEX_BIT_SGIX) ? "y" : ".",
242 doubleBuffer ? "y" : ".",
243 stereo ? "y" : ".");
Brian Paul21666e32002-10-05 18:30:13 +0000244 printf("%2d %2d %2d %2d ", redSize, greenSize, blueSize, alphaSize);
245 printf("%2d %2d ", depthSize, stencilSize);
246 printf("%2d %2d %2d %2d", accumRedSize, accumGreenSize, accumBlueSize,
247 accumAlphaSize);
248 printf(" %2d %2d", sampleBuffers, samples);
Brian Paulff53a4e2005-01-10 23:15:59 +0000249 printf(" %s %c", pBuffer ? "y" : ".",
250 ".y"[floatComponents]);
Brian Paul21666e32002-10-05 18:30:13 +0000251 printf("\n");
252 }
253 else {
254 printf("Id 0x%x\n", id);
255 printf(" Buffer Size: %d\n", bufferSize);
256 printf(" Level: %d\n", level);
257 printf(" Double Buffer: %s\n", doubleBuffer ? "yes" : "no");
258 printf(" Stereo: %s\n", stereo ? "yes" : "no");
259 printf(" Aux Buffers: %d\n", auxBuffers);
260 printf(" Red Size: %d\n", redSize);
261 printf(" Green Size: %d\n", greenSize);
262 printf(" Blue Size: %d\n", blueSize);
263 printf(" Alpha Size: %d\n", alphaSize);
264 printf(" Depth Size: %d\n", depthSize);
265 printf(" Stencil Size: %d\n", stencilSize);
266 printf(" Accum Red Size: %d\n", accumRedSize);
267 printf(" Accum Green Size: %d\n", accumGreenSize);
268 printf(" Accum Blue Size: %d\n", accumBlueSize);
269 printf(" Accum Alpha Size: %d\n", accumAlphaSize);
270 printf(" Sample Buffers: %d\n", sampleBuffers);
271 printf(" Samples/Pixel: %d\n", samples);
272 printf(" Drawable Types: ");
Brian Paulf72e4422005-01-04 00:58:29 +0000273 if (drawableType & GLX_WINDOW_BIT) printf("Window ");
274 if (drawableType & GLX_PIXMAP_BIT) printf("Pixmap ");
275 if (drawableType & GLX_PBUFFER_BIT) printf("PBuffer");
Brian Paul21666e32002-10-05 18:30:13 +0000276 printf("\n");
277 printf(" Render Types: ");
278 if (renderType & GLX_RGBA_BIT_SGIX) printf("RGBA ");
279 if (renderType & GLX_COLOR_INDEX_BIT_SGIX) printf("CI ");
280 printf("\n");
281 printf(" X Renderable: %s\n", xRenderable ? "yes" : "no");
Brian Paulf72e4422005-01-04 00:58:29 +0000282
Brian Paul21666e32002-10-05 18:30:13 +0000283 printf(" Pbuffer: %s\n", pBuffer ? "yes" : "no");
Brian Paulf72e4422005-01-04 00:58:29 +0000284 printf(" Max Pbuffer width: %d\n", maxWidth);
285 printf(" Max Pbuffer height: %d\n", maxHeight);
286 printf(" Max Pbuffer pixels: %d\n", maxPixels);
287 printf(" Optimum Pbuffer width: %d\n", optWidth);
288 printf(" Optimum Pbuffer height: %d\n", optHeight);
289
290 printf(" Float Components: %s\n", floatComponents ? "yes" : "no");
Brian Paul21666e32002-10-05 18:30:13 +0000291 }
292
293 if (pBuffer) {
Brian Paulf72e4422005-01-04 00:58:29 +0000294 DestroyPbuffer(dpy, screen, pBuffer);
Brian Paul21666e32002-10-05 18:30:13 +0000295 }
296}
297
298
299
300/* This is only used by CreatePbuffer() */
301static int XErrorFlag = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000302static int HandleXError(Display *dpy, XErrorEvent *event)
Brian Paul21666e32002-10-05 18:30:13 +0000303{
304 XErrorFlag = 1;
305 return 0;
306}
307
308
Brian Paulf72e4422005-01-04 00:58:29 +0000309/**
Brian Paul18a94902004-02-02 15:38:26 +0000310 * Create a Pbuffer. Use an X error handler to deal with potential
311 * BadAlloc errors.
Brian Paul21666e32002-10-05 18:30:13 +0000312 *
313 * Input: dpy - the X display
314 * fbConfig - an FBConfig as returned by glXChooseFBConfigSGIX().
315 * width, height - size of pixel buffer to request, in pixels.
Brian Paulf72e4422005-01-04 00:58:29 +0000316 * pbAttribs - list of optional pixel buffer attributes
317 * Return: a Pbuffer or None.
Brian Paul21666e32002-10-05 18:30:13 +0000318 */
Brian Paulf72e4422005-01-04 00:58:29 +0000319PBUFFER
320CreatePbuffer(Display *dpy, int screen, FBCONFIG config,
321 int width, int height, Bool largest, Bool preserve)
Brian Paul21666e32002-10-05 18:30:13 +0000322{
Brian Paulf72e4422005-01-04 00:58:29 +0000323 int (*oldHandler)(Display *, XErrorEvent *);
324 PBUFFER pBuffer = None;
325 int pbSupport = QueryPbuffers(dpy, screen);
Brian Paul21666e32002-10-05 18:30:13 +0000326
327 /* Catch X protocol errors with our own error handler */
Brian Paulf72e4422005-01-04 00:58:29 +0000328 oldHandler = XSetErrorHandler(HandleXError);
Brian Paul21666e32002-10-05 18:30:13 +0000329 XErrorFlag = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000330
331#if defined(GLX_VERSION_1_3)
332 if (pbSupport == 1) {
333 /* GLX 1.3 */
334 int attribs[100], i = 0;
335 attribs[i++] = GLX_PBUFFER_WIDTH;
336 attribs[i++] = width;
337 attribs[i++] = GLX_PBUFFER_HEIGHT;
338 attribs[i++] = height;
339 attribs[i++] = GLX_PRESERVED_CONTENTS;
340 attribs[i++] = preserve;
341 attribs[i++] = GLX_LARGEST_PBUFFER;
342 attribs[i++] = largest;
343 attribs[i++] = 0;
344 pBuffer = glXCreatePbuffer(dpy, config, attribs);
345 }
346 else
347#endif
348#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
349 if (pbSupport == 2) {
350 int attribs[100], i = 0;
351 attribs[i++] = GLX_PRESERVED_CONTENTS;
352 attribs[i++] = preserve;
353 attribs[i++] = GLX_LARGEST_PBUFFER;
354 attribs[i++] = largest;
355 attribs[i++] = 0;
356 pBuffer = glXCreateGLXPbufferSGIX(dpy, config, width, height, attribs);
357 }
358 else
359#endif
360 {
361 pBuffer = None;
362 }
Brian Paul21666e32002-10-05 18:30:13 +0000363
364 /* Restore original X error handler */
Brian Paulf72e4422005-01-04 00:58:29 +0000365 (void) XSetErrorHandler(oldHandler);
Brian Paul21666e32002-10-05 18:30:13 +0000366
367 /* Return pbuffer (may be None) */
Brian Paulf72e4422005-01-04 00:58:29 +0000368 if (!XErrorFlag && pBuffer != None) {
Brian Paul21666e32002-10-05 18:30:13 +0000369 /*printf("config %d worked!\n", i);*/
370 return pBuffer;
371 }
372 else {
373 return None;
374 }
375}
376
377
Brian Paulf72e4422005-01-04 00:58:29 +0000378void
379DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer)
380{
381 int pbSupport = QueryPbuffers(dpy, screen);
382#if defined(GLX_VERSION_1_3)
383 if (pbSupport == 1) {
384 glXDestroyPbuffer(dpy, pbuffer);
385 return;
386 }
387#endif
388#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
389 if (pbSupport == 2) {
390 glXDestroyGLXPbufferSGIX(dpy, pbuffer);
391 return;
392 }
393#endif
394}