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