1 /* 2 * Copyright 1994-1997 Mark Kilgard, All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Mark Kilgard 7 */ 8 9 10 #include <stdlib.h> 11 12 13 #if !defined(_WIN32) && !(defined(__BEOS__) || defined(__HAIKU__)) 14 #include <GL/glx.h> 15 #endif 16 17 #ifdef __sgi 18 #include <dlfcn.h> 19 #endif 20 21 #include "glutint.h" 22 23 /* Grumble. The IRIX 6.3 and early IRIX 6.4 OpenGL headers 24 support the video resize extension, but failed to define 25 GLX_SGIX_video_resize. */ 26 #ifdef GLX_SYNC_FRAME_SGIX 27 #define GLX_SGIX_video_resize 1 28 #endif 29 30 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_video_resize) 31 static int canVideoResize = -1; 32 static int videoResizeChannel; 33 #else 34 static int canVideoResize = 0; 35 #endif 36 static int videoResizeInUse = 0; 37 static int dx = -1, dy = -1, dw = -1, dh = -1; 38 39 /* XXX Note that IRIX 6.2, 6.3, and some 6.4 versions have a 40 bug where programs seg-fault when they attempt video 41 resizing from an indirect OpenGL context (either local or 42 over a network). */ 43 44 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_video_resize) 45 46 static volatile int errorCaught; 47 48 /* ARGSUSED */ 49 static 50 catchXSGIvcErrors(Display * dpy, XErrorEvent * event) 51 { 52 errorCaught = 1; 53 return 0; 54 } 55 #endif 56 57 /* CENTRY */ 58 int APIENTRY 59 glutVideoResizeGet(GLenum param) 60 { 61 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_video_resize) 62 if (canVideoResize < 0) { 63 canVideoResize = __glutIsSupportedByGLX("GLX_SGIX_video_resize"); 64 if (canVideoResize) { 65 #if __sgi 66 /* This is a hack because IRIX 6.2, 6.3, and some 6.4 67 versions were released with GLX_SGIX_video_resize 68 being advertised by the X server though the video 69 resize extension is not actually supported. We try to 70 determine if the libGL.so we are using actually has a 71 video resize entrypoint before we try to use the 72 feature. */ 73 void (*func) (void); 74 void *glxDso = dlopen("libGL.so", RTLD_LAZY); 75 76 func = (void (*)(void)) dlsym(glxDso, "glXQueryChannelDeltasSGIX"); 77 if (!func) { 78 canVideoResize = 0; 79 } else 80 #endif 81 { 82 char *channelString; 83 int (*handler) (Display *, XErrorEvent *); 84 85 channelString = getenv("GLUT_VIDEO_RESIZE_CHANNEL"); 86 videoResizeChannel = channelString ? atoi(channelString) : 0; 87 88 /* Work around another annoying problem with SGI's 89 GLX_SGIX_video_resize implementation. Early IRIX 90 6.4 OpenGL's advertise the extension and have the 91 video resize API, but an XSGIvc X protocol errors 92 result trying to use the API. Set up an error 93 handler to intercept what would otherwise be a fatal 94 error. If an error was recieved, do not report that 95 video resize is possible. */ 96 handler = XSetErrorHandler(catchXSGIvcErrors); 97 98 errorCaught = 0; 99 100 glXQueryChannelDeltasSGIX(__glutDisplay, __glutScreen, 101 videoResizeChannel, &dx, &dy, &dw, &dh); 102 103 /* glXQueryChannelDeltasSGIX is an inherent X server 104 round-trip so we know we will have gotten either the 105 correct reply or and error by this time. */ 106 XSetErrorHandler(handler); 107 108 /* Still yet another work around. In IRIX 6.4 betas, 109 glXQueryChannelDeltasSGIX will return as if it 110 succeeded, but the values are filled with junk. 111 Watch to make sure the delta variables really make 112 sense. */ 113 if (errorCaught || 114 dx < 0 || dy < 0 || dw < 0 || dh < 0 || 115 dx > 2048 || dy > 2048 || dw > 2048 || dh > 2048) { 116 canVideoResize = 0; 117 } 118 } 119 } 120 } 121 #endif /* GLX_SGIX_video_resize */ 122 123 switch (param) { 124 case GLUT_VIDEO_RESIZE_POSSIBLE: 125 return canVideoResize; 126 case GLUT_VIDEO_RESIZE_IN_USE: 127 return videoResizeInUse; 128 case GLUT_VIDEO_RESIZE_X_DELTA: 129 return dx; 130 case GLUT_VIDEO_RESIZE_Y_DELTA: 131 return dy; 132 case GLUT_VIDEO_RESIZE_WIDTH_DELTA: 133 return dw; 134 case GLUT_VIDEO_RESIZE_HEIGHT_DELTA: 135 return dh; 136 case GLUT_VIDEO_RESIZE_X: 137 case GLUT_VIDEO_RESIZE_Y: 138 case GLUT_VIDEO_RESIZE_WIDTH: 139 case GLUT_VIDEO_RESIZE_HEIGHT: 140 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_video_resize) 141 if (videoResizeInUse) { 142 int x, y, width, height; 143 144 glXQueryChannelRectSGIX(__glutDisplay, __glutScreen, 145 videoResizeChannel, &x, &y, &width, &height); 146 switch (param) { 147 case GLUT_VIDEO_RESIZE_X: 148 return x; 149 case GLUT_VIDEO_RESIZE_Y: 150 return y; 151 case GLUT_VIDEO_RESIZE_WIDTH: 152 return width; 153 case GLUT_VIDEO_RESIZE_HEIGHT: 154 return height; 155 } 156 } 157 #endif 158 return -1; 159 default: 160 __glutWarning("invalid glutVideoResizeGet parameter: %d", param); 161 return -1; 162 } 163 } 164 165 void APIENTRY 166 glutSetupVideoResizing(void) 167 { 168 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_video_resize) 169 if (glutVideoResizeGet(GLUT_VIDEO_RESIZE_POSSIBLE)) { 170 glXBindChannelToWindowSGIX(__glutDisplay, __glutScreen, 171 videoResizeChannel, __glutCurrentWindow->win); 172 videoResizeInUse = 1; 173 } else 174 #endif 175 __glutFatalError("glutEstablishVideoResizing: video resizing not possible.\n"); 176 } 177 178 void APIENTRY 179 glutStopVideoResizing(void) 180 { 181 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_video_resize) 182 if (glutVideoResizeGet(GLUT_VIDEO_RESIZE_POSSIBLE)) { 183 if (videoResizeInUse) { 184 glXBindChannelToWindowSGIX(__glutDisplay, __glutScreen, 185 videoResizeChannel, None); 186 videoResizeInUse = 0; 187 } 188 } 189 #endif 190 } 191 192 /* ARGSUSED */ 193 void APIENTRY 194 glutVideoResize(int x, int y, int width, int height) 195 { 196 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_video_resize) 197 if (videoResizeInUse) { 198 #ifdef GLX_SYNC_SWAP_SGIX 199 /* glXChannelRectSyncSGIX introduced in a patch to IRIX 200 6.2; the original unpatched IRIX 6.2 behavior is always 201 GLX_SYNC_SWAP_SGIX. */ 202 glXChannelRectSyncSGIX(__glutDisplay, __glutScreen, 203 videoResizeChannel, GLX_SYNC_SWAP_SGIX); 204 #endif 205 glXChannelRectSGIX(__glutDisplay, __glutScreen, 206 videoResizeChannel, x, y, width, height); 207 } 208 #endif 209 } 210 211 /* ARGSUSED */ 212 void APIENTRY 213 glutVideoPan(int x, int y, int width, int height) 214 { 215 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_video_resize) 216 if (videoResizeInUse) { 217 #ifdef GLX_SYNC_FRAME_SGIX 218 /* glXChannelRectSyncSGIX introduced in a patch to IRIX 219 6.2; the original unpatched IRIX 6.2 behavior is always 220 GLX_SYNC_SWAP_SGIX. We just ignore that we cannot 221 accomplish GLX_SYNC_FRAME_SGIX on IRIX unpatched 6.2; 222 this means you'd need a glutSwapBuffers to actually 223 realize the video resize. */ 224 glXChannelRectSyncSGIX(__glutDisplay, __glutScreen, 225 videoResizeChannel, GLX_SYNC_FRAME_SGIX); 226 #endif 227 glXChannelRectSGIX(__glutDisplay, __glutScreen, 228 videoResizeChannel, x, y, width, height); 229 } 230 #endif 231 } 232 233 /* ENDCENTRY */ 234