a3d66da4810a12e189f263f3e5eecd44459f76b4
[mesa.git] / progs / xdemos / pbutil.c
1
2 /*
3 * OpenGL pbuffers utility functions.
4 *
5 * Brian Paul
6 * Original code: April 1997
7 * Updated on 5 October 2002
8 * Updated again on 3 January 2005 to use GLX 1.3 functions in preference
9 * to the GLX_SGIX_fbconfig/pbuffer extensions.
10 */
11
12
13 #include <stdio.h>
14 #include <string.h>
15 #include "pbutil.h"
16
17
18 /**
19 * 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.
23 * 1 = pixel buffers are available via GLX 1.3.
24 * 2 = pixel buffers are available via GLX_SGIX_fbconfig/pbuffer.
25 */
26 int
27 QueryPbuffers(Display *dpy, int screen)
28 {
29 #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 */
41 }
42 #endif
43
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;
59 }
60
61
62
63 FBCONFIG *
64 ChooseFBConfig(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 }
79
80
81 FBCONFIG *
82 GetAllFBConfigs(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
104
105 XVisualInfo *
106 GetVisualFromFBConfig(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 */
127 static int
128 GetFBConfigAttrib(Display *dpy,
129 #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 {
137 int value;
138
139 #if defined(GLX_VERSION_1_3)
140 int glxVersionMajor, glxVersionMinor;
141 if (glXQueryVersion(dpy, &glxVersionMajor, &glxVersionMinor)
142 && glxVersionMajor * 100 + glxVersionMinor >= 103) {
143 /* 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)
153 if (glXGetFBConfigAttribSGIX(dpy, config, attrib, &value) != 0) {
154 value = 0;
155 }
156 return value;
157 #endif
158
159 return 0;
160 }
161
162
163
164 /**
165 * Print parameters for a GLXFBConfig to stdout.
166 * Input: dpy - the X display
167 * screen - the X screen number
168 * fbConfig - the fbconfig handle
169 * horizFormat - if true, print in horizontal format
170 */
171 void
172 PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat)
173 {
174 PBUFFER pBuffer;
175 int width=2, height=2;
176 int bufferSize, level, doubleBuffer, stereo, auxBuffers;
177 int redSize, greenSize, blueSize, alphaSize;
178 int depthSize, stencilSize;
179 int accumRedSize, accumBlueSize, accumGreenSize, accumAlphaSize;
180 int sampleBuffers, samples;
181 int drawableType, renderType, xRenderable, xVisual, id;
182 int maxWidth, maxHeight, maxPixels;
183 int optWidth, optHeight;
184 int floatComponents;
185
186 /* do queries using the GLX 1.3 tokens (same as the SGIX tokens) */
187 bufferSize = GetFBConfigAttrib(dpy, config, GLX_BUFFER_SIZE);
188 level = GetFBConfigAttrib(dpy, config, GLX_LEVEL);
189 doubleBuffer = GetFBConfigAttrib(dpy, config, GLX_DOUBLEBUFFER);
190 stereo = GetFBConfigAttrib(dpy, config, GLX_STEREO);
191 auxBuffers = GetFBConfigAttrib(dpy, config, GLX_AUX_BUFFERS);
192 redSize = GetFBConfigAttrib(dpy, config, GLX_RED_SIZE);
193 greenSize = GetFBConfigAttrib(dpy, config, GLX_GREEN_SIZE);
194 blueSize = GetFBConfigAttrib(dpy, config, GLX_BLUE_SIZE);
195 alphaSize = GetFBConfigAttrib(dpy, config, GLX_ALPHA_SIZE);
196 depthSize = GetFBConfigAttrib(dpy, config, GLX_DEPTH_SIZE);
197 stencilSize = GetFBConfigAttrib(dpy, config, GLX_STENCIL_SIZE);
198 accumRedSize = GetFBConfigAttrib(dpy, config, GLX_ACCUM_RED_SIZE);
199 accumGreenSize = GetFBConfigAttrib(dpy, config, GLX_ACCUM_GREEN_SIZE);
200 accumBlueSize = GetFBConfigAttrib(dpy, config, GLX_ACCUM_BLUE_SIZE);
201 accumAlphaSize = GetFBConfigAttrib(dpy, config, GLX_ACCUM_ALPHA_SIZE);
202 sampleBuffers = GetFBConfigAttrib(dpy, config, GLX_SAMPLE_BUFFERS);
203 samples = GetFBConfigAttrib(dpy, config, GLX_SAMPLES);
204 drawableType = GetFBConfigAttrib(dpy, config, GLX_DRAWABLE_TYPE);
205 renderType = GetFBConfigAttrib(dpy, config, GLX_RENDER_TYPE);
206 xRenderable = GetFBConfigAttrib(dpy, config, GLX_X_RENDERABLE);
207 xVisual = GetFBConfigAttrib(dpy, config, GLX_X_VISUAL_TYPE);
208 if (!xRenderable || !(drawableType & GLX_WINDOW_BIT_SGIX))
209 xVisual = -1;
210
211 id = GetFBConfigAttrib(dpy, config, GLX_FBCONFIG_ID);
212 maxWidth = GetFBConfigAttrib(dpy, config, GLX_MAX_PBUFFER_WIDTH);
213 maxHeight = GetFBConfigAttrib(dpy, config, GLX_MAX_PBUFFER_HEIGHT);
214 maxPixels = GetFBConfigAttrib(dpy, config, GLX_MAX_PBUFFER_PIXELS);
215 #if defined(GLX_SGIX_pbuffer)
216 optWidth = GetFBConfigAttrib(dpy, config, GLX_OPTIMAL_PBUFFER_WIDTH_SGIX);
217 optHeight = GetFBConfigAttrib(dpy, config, GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX);
218 #else
219 optWidth = optHeight = 0;
220 #endif
221 #if defined(GLX_NV_float_buffer)
222 floatComponents = GetFBConfigAttrib(dpy, config, GLX_FLOAT_COMPONENTS_NV);
223 #endif
224
225 /* See if we can create a pbuffer with this config */
226 pBuffer = CreatePbuffer(dpy, screen, config, width, height, False, False);
227
228 if (horizFormat) {
229 printf("0x%03x ", id);
230 if (xVisual==GLX_STATIC_GRAY) printf("StaticGray ");
231 else if (xVisual==GLX_GRAY_SCALE) printf("GrayScale ");
232 else if (xVisual==GLX_STATIC_COLOR) printf("StaticColor ");
233 else if (xVisual==GLX_PSEUDO_COLOR) printf("PseudoColor ");
234 else if (xVisual==GLX_TRUE_COLOR) printf("TrueColor ");
235 else if (xVisual==GLX_DIRECT_COLOR) printf("DirectColor ");
236 else printf(" -none- ");
237 printf(" %3d %3d %s %s %s %2s ", bufferSize, level,
238 (renderType & GLX_RGBA_BIT_SGIX) ? "y" : "n",
239 (renderType & GLX_COLOR_INDEX_BIT_SGIX) ? "y" : "n",
240 doubleBuffer ? "y" : "n",
241 stereo ? "y" : "n");
242 printf("%2d %2d %2d %2d ", redSize, greenSize, blueSize, alphaSize);
243 printf("%2d %2d ", depthSize, stencilSize);
244 printf("%2d %2d %2d %2d", accumRedSize, accumGreenSize, accumBlueSize,
245 accumAlphaSize);
246 printf(" %2d %2d", sampleBuffers, samples);
247 printf(" %s %c", pBuffer ? "y" : "n",
248 "ny"[floatComponents]);
249 printf("\n");
250 }
251 else {
252 printf("Id 0x%x\n", id);
253 printf(" Buffer Size: %d\n", bufferSize);
254 printf(" Level: %d\n", level);
255 printf(" Double Buffer: %s\n", doubleBuffer ? "yes" : "no");
256 printf(" Stereo: %s\n", stereo ? "yes" : "no");
257 printf(" Aux Buffers: %d\n", auxBuffers);
258 printf(" Red Size: %d\n", redSize);
259 printf(" Green Size: %d\n", greenSize);
260 printf(" Blue Size: %d\n", blueSize);
261 printf(" Alpha Size: %d\n", alphaSize);
262 printf(" Depth Size: %d\n", depthSize);
263 printf(" Stencil Size: %d\n", stencilSize);
264 printf(" Accum Red Size: %d\n", accumRedSize);
265 printf(" Accum Green Size: %d\n", accumGreenSize);
266 printf(" Accum Blue Size: %d\n", accumBlueSize);
267 printf(" Accum Alpha Size: %d\n", accumAlphaSize);
268 printf(" Sample Buffers: %d\n", sampleBuffers);
269 printf(" Samples/Pixel: %d\n", samples);
270 printf(" Drawable Types: ");
271 if (drawableType & GLX_WINDOW_BIT) printf("Window ");
272 if (drawableType & GLX_PIXMAP_BIT) printf("Pixmap ");
273 if (drawableType & GLX_PBUFFER_BIT) printf("PBuffer");
274 printf("\n");
275 printf(" Render Types: ");
276 if (renderType & GLX_RGBA_BIT_SGIX) printf("RGBA ");
277 if (renderType & GLX_COLOR_INDEX_BIT_SGIX) printf("CI ");
278 printf("\n");
279 printf(" X Renderable: %s\n", xRenderable ? "yes" : "no");
280
281 printf(" Pbuffer: %s\n", pBuffer ? "yes" : "no");
282 printf(" Max Pbuffer width: %d\n", maxWidth);
283 printf(" Max Pbuffer height: %d\n", maxHeight);
284 printf(" Max Pbuffer pixels: %d\n", maxPixels);
285 printf(" Optimum Pbuffer width: %d\n", optWidth);
286 printf(" Optimum Pbuffer height: %d\n", optHeight);
287
288 printf(" Float Components: %s\n", floatComponents ? "yes" : "no");
289 }
290
291 if (pBuffer) {
292 DestroyPbuffer(dpy, screen, pBuffer);
293 }
294 }
295
296
297
298 /* This is only used by CreatePbuffer() */
299 static int XErrorFlag = 0;
300 static int HandleXError(Display *dpy, XErrorEvent *event)
301 {
302 XErrorFlag = 1;
303 return 0;
304 }
305
306
307 /**
308 * Create a Pbuffer. Use an X error handler to deal with potential
309 * BadAlloc errors.
310 *
311 * Input: dpy - the X display
312 * fbConfig - an FBConfig as returned by glXChooseFBConfigSGIX().
313 * width, height - size of pixel buffer to request, in pixels.
314 * pbAttribs - list of optional pixel buffer attributes
315 * Return: a Pbuffer or None.
316 */
317 PBUFFER
318 CreatePbuffer(Display *dpy, int screen, FBCONFIG config,
319 int width, int height, Bool largest, Bool preserve)
320 {
321 int (*oldHandler)(Display *, XErrorEvent *);
322 PBUFFER pBuffer = None;
323 int pbSupport = QueryPbuffers(dpy, screen);
324
325 /* Catch X protocol errors with our own error handler */
326 oldHandler = XSetErrorHandler(HandleXError);
327 XErrorFlag = 0;
328
329 #if defined(GLX_VERSION_1_3)
330 if (pbSupport == 1) {
331 /* GLX 1.3 */
332 int attribs[100], i = 0;
333 attribs[i++] = GLX_PBUFFER_WIDTH;
334 attribs[i++] = width;
335 attribs[i++] = GLX_PBUFFER_HEIGHT;
336 attribs[i++] = height;
337 attribs[i++] = GLX_PRESERVED_CONTENTS;
338 attribs[i++] = preserve;
339 attribs[i++] = GLX_LARGEST_PBUFFER;
340 attribs[i++] = largest;
341 attribs[i++] = 0;
342 pBuffer = glXCreatePbuffer(dpy, config, attribs);
343 }
344 else
345 #endif
346 #if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
347 if (pbSupport == 2) {
348 int attribs[100], i = 0;
349 attribs[i++] = GLX_PRESERVED_CONTENTS;
350 attribs[i++] = preserve;
351 attribs[i++] = GLX_LARGEST_PBUFFER;
352 attribs[i++] = largest;
353 attribs[i++] = 0;
354 pBuffer = glXCreateGLXPbufferSGIX(dpy, config, width, height, attribs);
355 }
356 else
357 #endif
358 {
359 pBuffer = None;
360 }
361
362 /* Restore original X error handler */
363 (void) XSetErrorHandler(oldHandler);
364
365 /* Return pbuffer (may be None) */
366 if (!XErrorFlag && pBuffer != None) {
367 /*printf("config %d worked!\n", i);*/
368 return pBuffer;
369 }
370 else {
371 return None;
372 }
373 }
374
375
376 void
377 DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer)
378 {
379 int pbSupport = QueryPbuffers(dpy, screen);
380 #if defined(GLX_VERSION_1_3)
381 if (pbSupport == 1) {
382 glXDestroyPbuffer(dpy, pbuffer);
383 return;
384 }
385 #endif
386 #if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
387 if (pbSupport == 2) {
388 glXDestroyGLXPbufferSGIX(dpy, pbuffer);
389 return;
390 }
391 #endif
392 }