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