blob: e82fc6ac59d85aad00c6762e0058e062dd818a94 [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 Paulf72e4422005-01-04 00:58:29 +000029#if defined(GLX_VERSION_1_3)
30 {
31 /* GLX 1.3 supports pbuffers */
32 int glxVersionMajor, glxVersionMinor;
33 if (!glXQueryVersion(dpy, &glxVersionMajor, &glxVersionMinor)) {
34 /* GLX not available! */
35 return 0;
36 }
37 if (glxVersionMajor * 100 + glxVersionMinor >= 103) {
38 return 1;
39 }
40 /* fall-through */
Brian Paul21666e32002-10-05 18:30:13 +000041 }
Brian Paul21666e32002-10-05 18:30:13 +000042#endif
Brian Paulf72e4422005-01-04 00:58:29 +000043
44#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
45 /* Try the SGIX extensions */
46 {
47 char *extensions;
48 extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS);
49 if (!extensions ||
50 !strstr(extensions,"GLX_SGIX_fbconfig") ||
51 !strstr(extensions,"GLX_SGIX_pbuffer")) {
52 return 0;
53 }
54 return 2;
55 }
56#endif
57
58 return 0;
Brian Paul21666e32002-10-05 18:30:13 +000059}
60
61
62
Brian Paulf72e4422005-01-04 00:58:29 +000063FBCONFIG *
64ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs)
65{
66 int pbSupport = QueryPbuffers(dpy, screen);
67#if defined(GLX_VERSION_1_3)
68 if (pbSupport == 1) {
69 return glXChooseFBConfig(dpy, screen, attribs, nConfigs);
70 }
71#endif
72#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
73 if (pbSupport == 2) {
74 return glXChooseFBConfigSGIX(dpy, screen, (int *) attribs, nConfigs);
75 }
76#endif
77 return NULL;
78}
Brian Paul21666e32002-10-05 18:30:13 +000079
80
Brian Paulba5ceda2005-01-07 01:17:42 +000081FBCONFIG *
82GetAllFBConfigs(Display *dpy, int screen, int *nConfigs)
83{
84 int pbSupport = QueryPbuffers(dpy, screen);
85#if defined(GLX_VERSION_1_3)
86 if (pbSupport == 1) {
87 return glXGetFBConfigs(dpy, screen, nConfigs);
88 }
89#endif
90#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
91 if (pbSupport == 2) {
92 /* this *seems* to work, but may not be perfect */
93 static int fbAttribs[] = {
94 GLX_RENDER_TYPE, 0,
95 GLX_DRAWABLE_TYPE, 0,
96 None
97 };
98 return glXChooseFBConfigSGIX(dpy, screen, fbAttribs, nConfigs);
99 }
100#endif
101 return NULL;
102}
103
Brian Paulf72e4422005-01-04 00:58:29 +0000104
105XVisualInfo *
106GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config)
107{
108 int pbSupport = QueryPbuffers(dpy, screen);
109#if defined(GLX_VERSION_1_3)
110 if (pbSupport == 1) {
111 return glXGetVisualFromFBConfig(dpy, config);
112 }
113#endif
114#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
115 if (pbSupport == 2) {
116 return glXGetVisualFromFBConfigSGIX(dpy, config);
117 }
118#endif
119 return NULL;
120}
121
122
123/**
124 * Either use glXGetFBConfigAttrib() or glXGetFBConfigAttribSGIX()
125 * to query an fbconfig attribute.
126 */
127static int
Brian Paulff53a4e2005-01-10 23:15:59 +0000128GetFBConfigAttrib(Display *dpy, int screen,
Brian Paulf72e4422005-01-04 00:58:29 +0000129#if defined(GLX_VERSION_1_3)
130 const GLXFBConfig config,
131#elif defined(GLX_SGIX_fbconfig)
132 const GLXFBConfigSGIX config,
133#endif
134 int attrib
135 )
136{
Brian Paulff53a4e2005-01-10 23:15:59 +0000137 int pbSupport = QueryPbuffers(dpy, screen);
138 int value = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000139
140#if defined(GLX_VERSION_1_3)
Brian Paulff53a4e2005-01-10 23:15:59 +0000141 if (pbSupport == 1) {
Brian Paulf72e4422005-01-04 00:58:29 +0000142 /* ok */
143 if (glXGetFBConfigAttrib(dpy, config, attrib, &value) != 0) {
144 value = 0;
145 }
146 return value;
147 }
148 /* fall-through */
149#endif
150
151#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000152 if (pbSupport == 2) {
153 if (glXGetFBConfigAttribSGIX(dpy, config, attrib, &value) != 0) {
154 value = 0;
155 }
156 return value;
Brian Paulf72e4422005-01-04 00:58:29 +0000157 }
Brian Paulf72e4422005-01-04 00:58:29 +0000158#endif
159
Brian Paulff53a4e2005-01-10 23:15:59 +0000160 return value;
Brian Paulf72e4422005-01-04 00:58:29 +0000161}
162
163
164
165/**
Brian Paul21666e32002-10-05 18:30:13 +0000166 * Print parameters for a GLXFBConfig to stdout.
167 * Input: dpy - the X display
Brian Paulf72e4422005-01-04 00:58:29 +0000168 * screen - the X screen number
Brian Paul21666e32002-10-05 18:30:13 +0000169 * fbConfig - the fbconfig handle
170 * horizFormat - if true, print in horizontal format
171 */
172void
Brian Paulf72e4422005-01-04 00:58:29 +0000173PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat)
Brian Paul21666e32002-10-05 18:30:13 +0000174{
Brian Paulf72e4422005-01-04 00:58:29 +0000175 PBUFFER pBuffer;
Brian Paul21666e32002-10-05 18:30:13 +0000176 int width=2, height=2;
177 int bufferSize, level, doubleBuffer, stereo, auxBuffers;
178 int redSize, greenSize, blueSize, alphaSize;
179 int depthSize, stencilSize;
180 int accumRedSize, accumBlueSize, accumGreenSize, accumAlphaSize;
181 int sampleBuffers, samples;
182 int drawableType, renderType, xRenderable, xVisual, id;
183 int maxWidth, maxHeight, maxPixels;
184 int optWidth, optHeight;
Brian Paulff53a4e2005-01-10 23:15:59 +0000185 int floatComponents = 0;
Brian Paul21666e32002-10-05 18:30:13 +0000186
Brian Paulf72e4422005-01-04 00:58:29 +0000187 /* do queries using the GLX 1.3 tokens (same as the SGIX tokens) */
Brian Paulff53a4e2005-01-10 23:15:59 +0000188 bufferSize = GetFBConfigAttrib(dpy, screen, config, GLX_BUFFER_SIZE);
189 level = GetFBConfigAttrib(dpy, screen, config, GLX_LEVEL);
190 doubleBuffer = GetFBConfigAttrib(dpy, screen, config, GLX_DOUBLEBUFFER);
191 stereo = GetFBConfigAttrib(dpy, screen, config, GLX_STEREO);
192 auxBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_AUX_BUFFERS);
193 redSize = GetFBConfigAttrib(dpy, screen, config, GLX_RED_SIZE);
194 greenSize = GetFBConfigAttrib(dpy, screen, config, GLX_GREEN_SIZE);
195 blueSize = GetFBConfigAttrib(dpy, screen, config, GLX_BLUE_SIZE);
196 alphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ALPHA_SIZE);
197 depthSize = GetFBConfigAttrib(dpy, screen, config, GLX_DEPTH_SIZE);
198 stencilSize = GetFBConfigAttrib(dpy, screen, config, GLX_STENCIL_SIZE);
199 accumRedSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_RED_SIZE);
200 accumGreenSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_GREEN_SIZE);
201 accumBlueSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_BLUE_SIZE);
202 accumAlphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_ALPHA_SIZE);
203 sampleBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLE_BUFFERS);
204 samples = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLES);
205 drawableType = GetFBConfigAttrib(dpy, screen, config, GLX_DRAWABLE_TYPE);
206 renderType = GetFBConfigAttrib(dpy, screen, config, GLX_RENDER_TYPE);
207 xRenderable = GetFBConfigAttrib(dpy, screen, config, GLX_X_RENDERABLE);
208 xVisual = GetFBConfigAttrib(dpy, screen, config, GLX_X_VISUAL_TYPE);
Brian Paul21666e32002-10-05 18:30:13 +0000209 if (!xRenderable || !(drawableType & GLX_WINDOW_BIT_SGIX))
210 xVisual = -1;
Brian Paul21666e32002-10-05 18:30:13 +0000211
Brian Paulff53a4e2005-01-10 23:15:59 +0000212 id = GetFBConfigAttrib(dpy, screen, config, GLX_FBCONFIG_ID);
213 maxWidth = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_WIDTH);
214 maxHeight = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_HEIGHT);
215 maxPixels = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_PIXELS);
Brian Paulf72e4422005-01-04 00:58:29 +0000216#if defined(GLX_SGIX_pbuffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000217 optWidth = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_WIDTH_SGIX);
218 optHeight = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX);
Brian Paulf72e4422005-01-04 00:58:29 +0000219#else
220 optWidth = optHeight = 0;
221#endif
222#if defined(GLX_NV_float_buffer)
Brian Paulff53a4e2005-01-10 23:15:59 +0000223 floatComponents = GetFBConfigAttrib(dpy, screen, config, GLX_FLOAT_COMPONENTS_NV);
Brian Paulf72e4422005-01-04 00:58:29 +0000224#endif
Brian Paul21666e32002-10-05 18:30:13 +0000225
Brian Paulf72e4422005-01-04 00:58:29 +0000226 /* See if we can create a pbuffer with this config */
227 pBuffer = CreatePbuffer(dpy, screen, config, width, height, False, False);
Brian Paul21666e32002-10-05 18:30:13 +0000228
229 if (horizFormat) {
Brian Paulff53a4e2005-01-10 23:15:59 +0000230 printf("0x%-9x ", id);
Brian Paul21666e32002-10-05 18:30:13 +0000231 if (xVisual==GLX_STATIC_GRAY) printf("StaticGray ");
232 else if (xVisual==GLX_GRAY_SCALE) printf("GrayScale ");
233 else if (xVisual==GLX_STATIC_COLOR) printf("StaticColor ");
234 else if (xVisual==GLX_PSEUDO_COLOR) printf("PseudoColor ");
235 else if (xVisual==GLX_TRUE_COLOR) printf("TrueColor ");
236 else if (xVisual==GLX_DIRECT_COLOR) printf("DirectColor ");
237 else printf(" -none- ");
238 printf(" %3d %3d %s %s %s %2s ", bufferSize, level,
Brian Paulff53a4e2005-01-10 23:15:59 +0000239 (renderType & GLX_RGBA_BIT_SGIX) ? "y" : ".",
240 (renderType & GLX_COLOR_INDEX_BIT_SGIX) ? "y" : ".",
241 doubleBuffer ? "y" : ".",
242 stereo ? "y" : ".");
Brian Paul21666e32002-10-05 18:30:13 +0000243 printf("%2d %2d %2d %2d ", redSize, greenSize, blueSize, alphaSize);
244 printf("%2d %2d ", depthSize, stencilSize);
245 printf("%2d %2d %2d %2d", accumRedSize, accumGreenSize, accumBlueSize,
246 accumAlphaSize);
247 printf(" %2d %2d", sampleBuffers, samples);
Brian Paulff53a4e2005-01-10 23:15:59 +0000248 printf(" %s %c", pBuffer ? "y" : ".",
249 ".y"[floatComponents]);
Brian Paul21666e32002-10-05 18:30:13 +0000250 printf("\n");
251 }
252 else {
253 printf("Id 0x%x\n", id);
254 printf(" Buffer Size: %d\n", bufferSize);
255 printf(" Level: %d\n", level);
256 printf(" Double Buffer: %s\n", doubleBuffer ? "yes" : "no");
257 printf(" Stereo: %s\n", stereo ? "yes" : "no");
258 printf(" Aux Buffers: %d\n", auxBuffers);
259 printf(" Red Size: %d\n", redSize);
260 printf(" Green Size: %d\n", greenSize);
261 printf(" Blue Size: %d\n", blueSize);
262 printf(" Alpha Size: %d\n", alphaSize);
263 printf(" Depth Size: %d\n", depthSize);
264 printf(" Stencil Size: %d\n", stencilSize);
265 printf(" Accum Red Size: %d\n", accumRedSize);
266 printf(" Accum Green Size: %d\n", accumGreenSize);
267 printf(" Accum Blue Size: %d\n", accumBlueSize);
268 printf(" Accum Alpha Size: %d\n", accumAlphaSize);
269 printf(" Sample Buffers: %d\n", sampleBuffers);
270 printf(" Samples/Pixel: %d\n", samples);
271 printf(" Drawable Types: ");
Brian Paulf72e4422005-01-04 00:58:29 +0000272 if (drawableType & GLX_WINDOW_BIT) printf("Window ");
273 if (drawableType & GLX_PIXMAP_BIT) printf("Pixmap ");
274 if (drawableType & GLX_PBUFFER_BIT) printf("PBuffer");
Brian Paul21666e32002-10-05 18:30:13 +0000275 printf("\n");
276 printf(" Render Types: ");
277 if (renderType & GLX_RGBA_BIT_SGIX) printf("RGBA ");
278 if (renderType & GLX_COLOR_INDEX_BIT_SGIX) printf("CI ");
279 printf("\n");
280 printf(" X Renderable: %s\n", xRenderable ? "yes" : "no");
Brian Paulf72e4422005-01-04 00:58:29 +0000281
Brian Paul21666e32002-10-05 18:30:13 +0000282 printf(" Pbuffer: %s\n", pBuffer ? "yes" : "no");
Brian Paulf72e4422005-01-04 00:58:29 +0000283 printf(" Max Pbuffer width: %d\n", maxWidth);
284 printf(" Max Pbuffer height: %d\n", maxHeight);
285 printf(" Max Pbuffer pixels: %d\n", maxPixels);
286 printf(" Optimum Pbuffer width: %d\n", optWidth);
287 printf(" Optimum Pbuffer height: %d\n", optHeight);
288
289 printf(" Float Components: %s\n", floatComponents ? "yes" : "no");
Brian Paul21666e32002-10-05 18:30:13 +0000290 }
291
292 if (pBuffer) {
Brian Paulf72e4422005-01-04 00:58:29 +0000293 DestroyPbuffer(dpy, screen, pBuffer);
Brian Paul21666e32002-10-05 18:30:13 +0000294 }
295}
296
297
298
299/* This is only used by CreatePbuffer() */
300static int XErrorFlag = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000301static int HandleXError(Display *dpy, XErrorEvent *event)
Brian Paul21666e32002-10-05 18:30:13 +0000302{
303 XErrorFlag = 1;
304 return 0;
305}
306
307
Brian Paulf72e4422005-01-04 00:58:29 +0000308/**
Brian Paul18a94902004-02-02 15:38:26 +0000309 * Create a Pbuffer. Use an X error handler to deal with potential
310 * BadAlloc errors.
Brian Paul21666e32002-10-05 18:30:13 +0000311 *
312 * Input: dpy - the X display
313 * fbConfig - an FBConfig as returned by glXChooseFBConfigSGIX().
314 * width, height - size of pixel buffer to request, in pixels.
Brian Paulf72e4422005-01-04 00:58:29 +0000315 * pbAttribs - list of optional pixel buffer attributes
316 * Return: a Pbuffer or None.
Brian Paul21666e32002-10-05 18:30:13 +0000317 */
Brian Paulf72e4422005-01-04 00:58:29 +0000318PBUFFER
319CreatePbuffer(Display *dpy, int screen, FBCONFIG config,
320 int width, int height, Bool largest, Bool preserve)
Brian Paul21666e32002-10-05 18:30:13 +0000321{
Brian Paulf72e4422005-01-04 00:58:29 +0000322 int (*oldHandler)(Display *, XErrorEvent *);
323 PBUFFER pBuffer = None;
324 int pbSupport = QueryPbuffers(dpy, screen);
Brian Paul21666e32002-10-05 18:30:13 +0000325
326 /* Catch X protocol errors with our own error handler */
Brian Paulf72e4422005-01-04 00:58:29 +0000327 oldHandler = XSetErrorHandler(HandleXError);
Brian Paul21666e32002-10-05 18:30:13 +0000328 XErrorFlag = 0;
Brian Paulf72e4422005-01-04 00:58:29 +0000329
330#if defined(GLX_VERSION_1_3)
331 if (pbSupport == 1) {
332 /* GLX 1.3 */
333 int attribs[100], i = 0;
334 attribs[i++] = GLX_PBUFFER_WIDTH;
335 attribs[i++] = width;
336 attribs[i++] = GLX_PBUFFER_HEIGHT;
337 attribs[i++] = height;
338 attribs[i++] = GLX_PRESERVED_CONTENTS;
339 attribs[i++] = preserve;
340 attribs[i++] = GLX_LARGEST_PBUFFER;
341 attribs[i++] = largest;
342 attribs[i++] = 0;
343 pBuffer = glXCreatePbuffer(dpy, config, attribs);
344 }
345 else
346#endif
347#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
348 if (pbSupport == 2) {
349 int attribs[100], i = 0;
350 attribs[i++] = GLX_PRESERVED_CONTENTS;
351 attribs[i++] = preserve;
352 attribs[i++] = GLX_LARGEST_PBUFFER;
353 attribs[i++] = largest;
354 attribs[i++] = 0;
355 pBuffer = glXCreateGLXPbufferSGIX(dpy, config, width, height, attribs);
356 }
357 else
358#endif
359 {
360 pBuffer = None;
361 }
Brian Paul21666e32002-10-05 18:30:13 +0000362
363 /* Restore original X error handler */
Brian Paulf72e4422005-01-04 00:58:29 +0000364 (void) XSetErrorHandler(oldHandler);
Brian Paul21666e32002-10-05 18:30:13 +0000365
366 /* Return pbuffer (may be None) */
Brian Paulf72e4422005-01-04 00:58:29 +0000367 if (!XErrorFlag && pBuffer != None) {
Brian Paul21666e32002-10-05 18:30:13 +0000368 /*printf("config %d worked!\n", i);*/
369 return pBuffer;
370 }
371 else {
372 return None;
373 }
374}
375
376
Brian Paulf72e4422005-01-04 00:58:29 +0000377void
378DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer)
379{
380 int pbSupport = QueryPbuffers(dpy, screen);
381#if defined(GLX_VERSION_1_3)
382 if (pbSupport == 1) {
383 glXDestroyPbuffer(dpy, pbuffer);
384 return;
385 }
386#endif
387#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
388 if (pbSupport == 2) {
389 glXDestroyGLXPbufferSGIX(dpy, pbuffer);
390 return;
391 }
392#endif
393}