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__)
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)
28static int canVideoResize = -1;
29static int videoResizeChannel;
30#else
31static int canVideoResize = 0;
32#endif
33static int videoResizeInUse = 0;
34static 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
43static volatile int errorCaught;
44
45/* ARGSUSED */
46static
47catchXSGIvcErrors(Display * dpy, XErrorEvent * event)
48{
49  errorCaught = 1;
50  return 0;
51}
52#endif
53
54/* CENTRY */
55int APIENTRY
56glutVideoResizeGet(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
162void APIENTRY
163glutSetupVideoResizing(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
175void APIENTRY
176glutStopVideoResizing(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 */
190void APIENTRY
191glutVideoResize(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 */
209void APIENTRY
210glutVideoPan(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