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