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#include <stdio.h> 13#include <string.h> 14#include "pbutil.h" 15 16 17/** 18 * 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 = fbconfigs not available. 22 * 1 = fbconfigs are available via GLX 1.3. 23 * 2 = fbconfigs and pbuffers are available via GLX_SGIX_fbconfig 24 */ 25int 26QueryFBConfig(Display *dpy, int screen) 27{ 28#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 */ 40 } 41#endif 42 43 /* Try the SGIX extensions */ 44 { 45 char *extensions; 46 extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS); 47 if (extensions && strstr(extensions,"GLX_SGIX_fbconfig")) { 48 return 2; 49 } 50 } 51 52 return 0; 53} 54 55/** 56 * Test if we pixel buffers are available for a particular X screen. 57 * Input: dpy - the X display 58 * screen - screen number 59 * Return: 0 = pixel buffers not available. 60 * 1 = pixel buffers are available via GLX 1.3. 61 * 2 = pixel buffers are available via GLX_SGIX_fbconfig/pbuffer. 62 */ 63int 64QueryPbuffers(Display *dpy, int screen) 65{ 66 int ret; 67 68 ret = QueryFBConfig(dpy, screen); 69 if (ret == 2) { 70 char *extensions; 71 extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS); 72 if (extensions && strstr(extensions, "GLX_SGIX_pbuffer")) 73 return 2; 74 else 75 return 0; 76 } 77 else 78 return ret; 79} 80 81FBCONFIG * 82ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs) 83{ 84 int fbcSupport = QueryPbuffers(dpy, screen); 85#if defined(GLX_VERSION_1_3) 86 if (fbcSupport == 1) { 87 return glXChooseFBConfig(dpy, screen, attribs, nConfigs); 88 } 89#endif 90#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) 91 if (fbcSupport == 2) { 92 return glXChooseFBConfigSGIX(dpy, screen, (int *) attribs, nConfigs); 93 } 94#endif 95 return NULL; 96} 97 98 99FBCONFIG * 100GetAllFBConfigs(Display *dpy, int screen, int *nConfigs) 101{ 102 int fbcSupport = QueryFBConfig(dpy, screen); 103#if defined(GLX_VERSION_1_3) 104 if (fbcSupport == 1) { 105 return glXGetFBConfigs(dpy, screen, nConfigs); 106 } 107#endif 108#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) 109 if (fbcSupport == 2) { 110 /* The GLX_SGIX_fbconfig extensions says to pass NULL to get list 111 * of all available configurations. 112 */ 113 return glXChooseFBConfigSGIX(dpy, screen, NULL, nConfigs); 114 } 115#endif 116 return NULL; 117} 118 119 120XVisualInfo * 121GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config) 122{ 123 int fbcSupport = QueryFBConfig(dpy, screen); 124#if defined(GLX_VERSION_1_3) 125 if (fbcSupport == 1) { 126 return glXGetVisualFromFBConfig(dpy, config); 127 } 128#endif 129#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) 130 if (fbcSupport == 2) { 131 return glXGetVisualFromFBConfigSGIX(dpy, config); 132 } 133#endif 134 return NULL; 135} 136 137 138/** 139 * Either use glXGetFBConfigAttrib() or glXGetFBConfigAttribSGIX() 140 * to query an fbconfig attribute. 141 */ 142static int 143GetFBConfigAttrib(Display *dpy, int screen, 144#if defined(GLX_VERSION_1_3) 145 const GLXFBConfig config, 146#elif defined(GLX_SGIX_fbconfig) 147 const GLXFBConfigSGIX config, 148#endif 149 int attrib 150 ) 151{ 152 int fbcSupport = QueryFBConfig(dpy, screen); 153 int value = 0; 154 155#if defined(GLX_VERSION_1_3) 156 if (fbcSupport == 1) { 157 /* ok */ 158 if (glXGetFBConfigAttrib(dpy, config, attrib, &value) != 0) { 159 value = 0; 160 } 161 return value; 162 } 163 /* fall-through */ 164#endif 165 166#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) 167 if (fbcSupport == 2) { 168 if (glXGetFBConfigAttribSGIX(dpy, config, attrib, &value) != 0) { 169 value = 0; 170 } 171 return value; 172 } 173#endif 174 175 return value; 176} 177 178 179 180/** 181 * Print parameters for a GLXFBConfig to stdout. 182 * Input: dpy - the X display 183 * screen - the X screen number 184 * fbConfig - the fbconfig handle 185 * horizFormat - if true, print in horizontal format 186 */ 187void 188PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat) 189{ 190 PBUFFER pBuffer; 191 int width=2, height=2; 192 int bufferSize, level, doubleBuffer, stereo, auxBuffers; 193 int redSize, greenSize, blueSize, alphaSize; 194 int depthSize, stencilSize; 195 int accumRedSize, accumBlueSize, accumGreenSize, accumAlphaSize; 196 int sampleBuffers, samples; 197 int drawableType, renderType, xRenderable, xVisual, id; 198 int maxWidth, maxHeight, maxPixels; 199 int optWidth, optHeight; 200 int floatComponents = 0; 201 202 /* do queries using the GLX 1.3 tokens (same as the SGIX tokens) */ 203 bufferSize = GetFBConfigAttrib(dpy, screen, config, GLX_BUFFER_SIZE); 204 level = GetFBConfigAttrib(dpy, screen, config, GLX_LEVEL); 205 doubleBuffer = GetFBConfigAttrib(dpy, screen, config, GLX_DOUBLEBUFFER); 206 stereo = GetFBConfigAttrib(dpy, screen, config, GLX_STEREO); 207 auxBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_AUX_BUFFERS); 208 redSize = GetFBConfigAttrib(dpy, screen, config, GLX_RED_SIZE); 209 greenSize = GetFBConfigAttrib(dpy, screen, config, GLX_GREEN_SIZE); 210 blueSize = GetFBConfigAttrib(dpy, screen, config, GLX_BLUE_SIZE); 211 alphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ALPHA_SIZE); 212 depthSize = GetFBConfigAttrib(dpy, screen, config, GLX_DEPTH_SIZE); 213 stencilSize = GetFBConfigAttrib(dpy, screen, config, GLX_STENCIL_SIZE); 214 accumRedSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_RED_SIZE); 215 accumGreenSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_GREEN_SIZE); 216 accumBlueSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_BLUE_SIZE); 217 accumAlphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_ALPHA_SIZE); 218 sampleBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLE_BUFFERS); 219 samples = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLES); 220 drawableType = GetFBConfigAttrib(dpy, screen, config, GLX_DRAWABLE_TYPE); 221 renderType = GetFBConfigAttrib(dpy, screen, config, GLX_RENDER_TYPE); 222 xRenderable = GetFBConfigAttrib(dpy, screen, config, GLX_X_RENDERABLE); 223 xVisual = GetFBConfigAttrib(dpy, screen, config, GLX_X_VISUAL_TYPE); 224 if (!xRenderable || !(drawableType & GLX_WINDOW_BIT_SGIX)) 225 xVisual = -1; 226 227 id = GetFBConfigAttrib(dpy, screen, config, GLX_FBCONFIG_ID); 228 maxWidth = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_WIDTH); 229 maxHeight = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_HEIGHT); 230 maxPixels = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_PIXELS); 231#if defined(GLX_SGIX_pbuffer) 232 optWidth = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_WIDTH_SGIX); 233 optHeight = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX); 234#else 235 optWidth = optHeight = 0; 236#endif 237#if defined(GLX_NV_float_buffer) 238 floatComponents = GetFBConfigAttrib(dpy, screen, config, GLX_FLOAT_COMPONENTS_NV); 239#endif 240 241 /* See if we can create a pbuffer with this config */ 242 pBuffer = CreatePbuffer(dpy, screen, config, width, height, False, False); 243 244 if (horizFormat) { 245 printf("0x%-9x ", id); 246 if (xVisual==GLX_STATIC_GRAY) printf("StaticGray "); 247 else if (xVisual==GLX_GRAY_SCALE) printf("GrayScale "); 248 else if (xVisual==GLX_STATIC_COLOR) printf("StaticColor "); 249 else if (xVisual==GLX_PSEUDO_COLOR) printf("PseudoColor "); 250 else if (xVisual==GLX_TRUE_COLOR) printf("TrueColor "); 251 else if (xVisual==GLX_DIRECT_COLOR) printf("DirectColor "); 252 else printf(" -none- "); 253 printf(" %3d %3d %s %s %s %2s ", bufferSize, level, 254 (renderType & GLX_RGBA_BIT_SGIX) ? "y" : ".", 255 (renderType & GLX_COLOR_INDEX_BIT_SGIX) ? "y" : ".", 256 doubleBuffer ? "y" : ".", 257 stereo ? "y" : "."); 258 printf("%2d %2d %2d %2d ", redSize, greenSize, blueSize, alphaSize); 259 printf("%2d %2d ", depthSize, stencilSize); 260 printf("%2d %2d %2d %2d", accumRedSize, accumGreenSize, accumBlueSize, 261 accumAlphaSize); 262 printf(" %2d %2d", sampleBuffers, samples); 263 printf(" %s %c", pBuffer ? "y" : ".", 264 ".y"[floatComponents]); 265 printf("\n"); 266 } 267 else { 268 printf("Id 0x%x\n", id); 269 printf(" Buffer Size: %d\n", bufferSize); 270 printf(" Level: %d\n", level); 271 printf(" Double Buffer: %s\n", doubleBuffer ? "yes" : "no"); 272 printf(" Stereo: %s\n", stereo ? "yes" : "no"); 273 printf(" Aux Buffers: %d\n", auxBuffers); 274 printf(" Red Size: %d\n", redSize); 275 printf(" Green Size: %d\n", greenSize); 276 printf(" Blue Size: %d\n", blueSize); 277 printf(" Alpha Size: %d\n", alphaSize); 278 printf(" Depth Size: %d\n", depthSize); 279 printf(" Stencil Size: %d\n", stencilSize); 280 printf(" Accum Red Size: %d\n", accumRedSize); 281 printf(" Accum Green Size: %d\n", accumGreenSize); 282 printf(" Accum Blue Size: %d\n", accumBlueSize); 283 printf(" Accum Alpha Size: %d\n", accumAlphaSize); 284 printf(" Sample Buffers: %d\n", sampleBuffers); 285 printf(" Samples/Pixel: %d\n", samples); 286 printf(" Drawable Types: "); 287 if (drawableType & GLX_WINDOW_BIT) printf("Window "); 288 if (drawableType & GLX_PIXMAP_BIT) printf("Pixmap "); 289 if (drawableType & GLX_PBUFFER_BIT) printf("PBuffer"); 290 printf("\n"); 291 printf(" Render Types: "); 292 if (renderType & GLX_RGBA_BIT_SGIX) printf("RGBA "); 293 if (renderType & GLX_COLOR_INDEX_BIT_SGIX) printf("CI "); 294 printf("\n"); 295 printf(" X Renderable: %s\n", xRenderable ? "yes" : "no"); 296 297 printf(" Pbuffer: %s\n", pBuffer ? "yes" : "no"); 298 printf(" Max Pbuffer width: %d\n", maxWidth); 299 printf(" Max Pbuffer height: %d\n", maxHeight); 300 printf(" Max Pbuffer pixels: %d\n", maxPixels); 301 printf(" Optimum Pbuffer width: %d\n", optWidth); 302 printf(" Optimum Pbuffer height: %d\n", optHeight); 303 304 printf(" Float Components: %s\n", floatComponents ? "yes" : "no"); 305 } 306 307 if (pBuffer) { 308 DestroyPbuffer(dpy, screen, pBuffer); 309 } 310} 311 312 313 314GLXContext 315CreateContext(Display *dpy, int screen, FBCONFIG config) 316{ 317 int fbcSupport = QueryFBConfig(dpy, screen); 318#if defined(GLX_VERSION_1_3) 319 if (fbcSupport == 1) { 320 /* GLX 1.3 */ 321 GLXContext c; 322 c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, True); 323 if (!c) { 324 /* try indirect */ 325 c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, False); 326 } 327 return c; 328 } 329#endif 330#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) 331 if (fbcSupport == 2) { 332 GLXContext c; 333 c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, True); 334 if (!c) { 335 c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, False); 336 } 337 return c; 338 } 339#endif 340 return 0; 341} 342 343 344void 345DestroyContext(Display *dpy, GLXContext ctx) 346{ 347 glXDestroyContext(dpy, ctx); 348} 349 350 351/* This is only used by CreatePbuffer() */ 352static int XErrorFlag = 0; 353static int HandleXError(Display *dpy, XErrorEvent *event) 354{ 355 XErrorFlag = 1; 356 return 0; 357} 358 359 360/** 361 * Create a Pbuffer. Use an X error handler to deal with potential 362 * BadAlloc errors. 363 * 364 * Input: dpy - the X display 365 * fbConfig - an FBConfig as returned by glXChooseFBConfigSGIX(). 366 * width, height - size of pixel buffer to request, in pixels. 367 * pbAttribs - list of optional pixel buffer attributes 368 * Return: a Pbuffer or None. 369 */ 370PBUFFER 371CreatePbuffer(Display *dpy, int screen, FBCONFIG config, 372 int width, int height, Bool largest, Bool preserve) 373{ 374 int (*oldHandler)(Display *, XErrorEvent *); 375 PBUFFER pBuffer = None; 376 int pbSupport = QueryPbuffers(dpy, screen); 377 378 /* Catch X protocol errors with our own error handler */ 379 oldHandler = XSetErrorHandler(HandleXError); 380 XErrorFlag = 0; 381 382#if defined(GLX_VERSION_1_3) 383 if (pbSupport == 1) { 384 /* GLX 1.3 */ 385 int attribs[100], i = 0; 386 attribs[i++] = GLX_PBUFFER_WIDTH; 387 attribs[i++] = width; 388 attribs[i++] = GLX_PBUFFER_HEIGHT; 389 attribs[i++] = height; 390 attribs[i++] = GLX_PRESERVED_CONTENTS; 391 attribs[i++] = preserve; 392 attribs[i++] = GLX_LARGEST_PBUFFER; 393 attribs[i++] = largest; 394 attribs[i++] = 0; 395 pBuffer = glXCreatePbuffer(dpy, config, attribs); 396 } 397 else 398#endif 399#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) 400 if (pbSupport == 2) { 401 int attribs[100], i = 0; 402 attribs[i++] = GLX_PRESERVED_CONTENTS; 403 attribs[i++] = preserve; 404 attribs[i++] = GLX_LARGEST_PBUFFER; 405 attribs[i++] = largest; 406 attribs[i++] = 0; 407 pBuffer = glXCreateGLXPbufferSGIX(dpy, config, width, height, attribs); 408 } 409 else 410#endif 411 { 412 pBuffer = None; 413 } 414 415 XSync(dpy, False); 416 /* Restore original X error handler */ 417 (void) XSetErrorHandler(oldHandler); 418 419 /* Return pbuffer (may be None) */ 420 if (!XErrorFlag && pBuffer != None) { 421 /*printf("config %d worked!\n", i);*/ 422 return pBuffer; 423 } 424 else { 425 return None; 426 } 427} 428 429 430void 431DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer) 432{ 433 int pbSupport = QueryPbuffers(dpy, screen); 434#if defined(GLX_VERSION_1_3) 435 if (pbSupport == 1) { 436 glXDestroyPbuffer(dpy, pbuffer); 437 return; 438 } 439#endif 440#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) 441 if (pbSupport == 2) { 442 glXDestroyGLXPbufferSGIX(dpy, pbuffer); 443 return; 444 } 445#endif 446} 447