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