xref: /haiku/src/libs/glut/glut_vidresize.c (revision 98057dd02a2411868fd4c35f7a48d20acfd92c23)
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