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