1 | /* Copyright (c) 2001, Stanford University
|
---|
2 | * All rights reserved
|
---|
3 | *
|
---|
4 | * See the file LICENSE.txt for information on redistributing this software.
|
---|
5 | */
|
---|
6 | #if 00 /*TEMPORARY*/
|
---|
7 | #include <unistd.h>
|
---|
8 | #include "cr_rand.h"
|
---|
9 | #endif
|
---|
10 |
|
---|
11 | #include <GL/glx.h>
|
---|
12 | #include <X11/Xlib.h>
|
---|
13 | #include <X11/Xutil.h>
|
---|
14 | #include <X11/Xmu/StdCmap.h>
|
---|
15 | #include <X11/Xatom.h>
|
---|
16 | #include <X11/extensions/shape.h>
|
---|
17 | #include <sys/time.h>
|
---|
18 | #include <stdio.h>
|
---|
19 |
|
---|
20 | #include "cr_environment.h"
|
---|
21 | #include "cr_error.h"
|
---|
22 | #include "cr_string.h"
|
---|
23 | #include "cr_mem.h"
|
---|
24 | #include "cr_process.h"
|
---|
25 | #include "renderspu.h"
|
---|
26 |
|
---|
27 |
|
---|
28 | /*
|
---|
29 | * Stuff from MwmUtils.h
|
---|
30 | */
|
---|
31 | typedef struct
|
---|
32 | {
|
---|
33 | unsigned long flags;
|
---|
34 | unsigned long functions;
|
---|
35 | unsigned long decorations;
|
---|
36 | long inputMode;
|
---|
37 | unsigned long status;
|
---|
38 | } PropMotifWmHints;
|
---|
39 |
|
---|
40 | #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
|
---|
41 | #define MWM_HINTS_DECORATIONS (1L << 1)
|
---|
42 |
|
---|
43 |
|
---|
44 | #define WINDOW_NAME window->title
|
---|
45 |
|
---|
46 | static Bool WindowExistsFlag;
|
---|
47 |
|
---|
48 | static int
|
---|
49 | WindowExistsErrorHandler( Display *dpy, XErrorEvent *xerr )
|
---|
50 | {
|
---|
51 | if (xerr->error_code == BadWindow)
|
---|
52 | {
|
---|
53 | WindowExistsFlag = GL_FALSE;
|
---|
54 | }
|
---|
55 | return 0;
|
---|
56 | }
|
---|
57 |
|
---|
58 | static GLboolean
|
---|
59 | WindowExists( Display *dpy, Window w )
|
---|
60 | {
|
---|
61 | XWindowAttributes xwa;
|
---|
62 | int (*oldXErrorHandler)(Display *, XErrorEvent *);
|
---|
63 |
|
---|
64 | WindowExistsFlag = GL_TRUE;
|
---|
65 | oldXErrorHandler = XSetErrorHandler(WindowExistsErrorHandler);
|
---|
66 | XGetWindowAttributes(dpy, w, &xwa); /* dummy request */
|
---|
67 | XSetErrorHandler(oldXErrorHandler);
|
---|
68 | return WindowExistsFlag;
|
---|
69 | }
|
---|
70 |
|
---|
71 | static GLboolean
|
---|
72 | renderDestroyWindow( Display *dpy, Window w )
|
---|
73 | {
|
---|
74 | XWindowAttributes xwa;
|
---|
75 | int (*oldXErrorHandler)(Display *, XErrorEvent *);
|
---|
76 |
|
---|
77 | WindowExistsFlag = GL_TRUE;
|
---|
78 | oldXErrorHandler = XSetErrorHandler(WindowExistsErrorHandler);
|
---|
79 | XGetWindowAttributes(dpy, w, &xwa); /* dummy request */
|
---|
80 | if (xwa.map_state == IsViewable) {
|
---|
81 | XDestroyWindow (dpy, w); /* dummy request */
|
---|
82 | XSync (dpy,0);
|
---|
83 | }
|
---|
84 | XSetErrorHandler(oldXErrorHandler);
|
---|
85 | return WindowExistsFlag;
|
---|
86 | }
|
---|
87 |
|
---|
88 | /*
|
---|
89 | * Garbage collection function.
|
---|
90 | * Loop over all known windows and check if corresponding X window still
|
---|
91 | * exists. If it doesn't, destroy the render SPU window.
|
---|
92 | * XXX seems to blow up with threadtest.conf tests.
|
---|
93 | */
|
---|
94 | void
|
---|
95 | renderspu_GCWindow(void)
|
---|
96 | {
|
---|
97 | int i;
|
---|
98 | WindowInfo *window;
|
---|
99 |
|
---|
100 | for (i = 0; i < (int)render_spu.window_id - 1; i++) {
|
---|
101 | window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, i);
|
---|
102 | if (window->visual->dpy) {
|
---|
103 | if (!WindowExists (window->visual->dpy, window->appWindow) ) {
|
---|
104 | XSync(window->visual->dpy,0);
|
---|
105 | if(WindowExists(window->visual->dpy, window->window)) {
|
---|
106 | renderDestroyWindow(window->visual->dpy, window->window);
|
---|
107 | }
|
---|
108 | }
|
---|
109 | }
|
---|
110 | }
|
---|
111 | }
|
---|
112 |
|
---|
113 | static Colormap
|
---|
114 | GetLUTColormap( Display *dpy, XVisualInfo *vi )
|
---|
115 | {
|
---|
116 | int a;
|
---|
117 | XColor col;
|
---|
118 | Colormap cmap;
|
---|
119 |
|
---|
120 | #if defined(__cplusplus) || defined(c_plusplus)
|
---|
121 | int localclass = vi->c_class; /* C++ */
|
---|
122 | #else
|
---|
123 | int localclass = vi->class; /* C */
|
---|
124 | #endif
|
---|
125 |
|
---|
126 | if ( localclass != DirectColor )
|
---|
127 | {
|
---|
128 | crError( "No support for non-DirectColor visuals with LUTs" );
|
---|
129 | }
|
---|
130 |
|
---|
131 | cmap = XCreateColormap( dpy, RootWindow(dpy, vi->screen),
|
---|
132 | vi->visual, AllocAll );
|
---|
133 |
|
---|
134 | for (a=0; a<256; a++)
|
---|
135 | {
|
---|
136 | col.red = render_spu.lut8[0][a]<<8;
|
---|
137 | col.green = col.blue = 0;
|
---|
138 | col.pixel = a<<16;
|
---|
139 | col.flags = DoRed;
|
---|
140 | XStoreColor(dpy, cmap, &col);
|
---|
141 | }
|
---|
142 |
|
---|
143 | for (a=0; a<256; a++)
|
---|
144 | {
|
---|
145 | col.green = render_spu.lut8[1][a]<<8;
|
---|
146 | col.red = col.blue = 0;
|
---|
147 | col.pixel = a<<8;
|
---|
148 | col.flags = DoGreen;
|
---|
149 | XStoreColor(dpy, cmap, &col);
|
---|
150 | }
|
---|
151 |
|
---|
152 | for (a=0; a<256; a++)
|
---|
153 | {
|
---|
154 | col.blue = render_spu.lut8[2][a]<<8;
|
---|
155 | col.red = col.green= 0;
|
---|
156 | col.pixel = a;
|
---|
157 | col.flags = DoBlue;
|
---|
158 | XStoreColor(dpy, cmap, &col);
|
---|
159 | }
|
---|
160 |
|
---|
161 | return cmap;
|
---|
162 | }
|
---|
163 |
|
---|
164 | static Colormap
|
---|
165 | GetShareableColormap( Display *dpy, XVisualInfo *vi )
|
---|
166 | {
|
---|
167 | Status status;
|
---|
168 | XStandardColormap *standardCmaps;
|
---|
169 | Colormap cmap;
|
---|
170 | int i, numCmaps;
|
---|
171 |
|
---|
172 | #if defined(__cplusplus) || defined(c_plusplus)
|
---|
173 | int localclass = vi->c_class; /* C++ */
|
---|
174 | #else
|
---|
175 | int localclass = vi->class; /* C */
|
---|
176 | #endif
|
---|
177 |
|
---|
178 | if ( localclass != TrueColor )
|
---|
179 | {
|
---|
180 | crError( "No support for non-TrueColor visuals." );
|
---|
181 | }
|
---|
182 |
|
---|
183 | status = XmuLookupStandardColormap( dpy, vi->screen, vi->visualid,
|
---|
184 | vi->depth, XA_RGB_DEFAULT_MAP,
|
---|
185 | False, True );
|
---|
186 |
|
---|
187 | if ( status == 1 )
|
---|
188 | {
|
---|
189 | status = XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen),
|
---|
190 | &standardCmaps, &numCmaps,
|
---|
191 | XA_RGB_DEFAULT_MAP );
|
---|
192 | if ( status == 1 )
|
---|
193 | {
|
---|
194 | for (i = 0 ; i < numCmaps ; i++)
|
---|
195 | {
|
---|
196 | if (standardCmaps[i].visualid == vi->visualid)
|
---|
197 | {
|
---|
198 | cmap = standardCmaps[i].colormap;
|
---|
199 | XFree( standardCmaps);
|
---|
200 | return cmap;
|
---|
201 | }
|
---|
202 | }
|
---|
203 | }
|
---|
204 | }
|
---|
205 |
|
---|
206 | cmap = XCreateColormap( dpy, RootWindow(dpy, vi->screen),
|
---|
207 | vi->visual, AllocNone );
|
---|
208 | return cmap;
|
---|
209 | }
|
---|
210 |
|
---|
211 |
|
---|
212 | static int
|
---|
213 | WaitForMapNotify( Display *display, XEvent *event, char *arg )
|
---|
214 | {
|
---|
215 | (void)display;
|
---|
216 | return ( event->type == MapNotify && event->xmap.window == (Window)arg );
|
---|
217 | }
|
---|
218 |
|
---|
219 |
|
---|
220 | /**
|
---|
221 | * Return the X Visual ID of the given window
|
---|
222 | */
|
---|
223 | static int
|
---|
224 | GetWindowVisualID( Display *dpy, Window w )
|
---|
225 | {
|
---|
226 | XWindowAttributes attr;
|
---|
227 | int k = XGetWindowAttributes(dpy, w, &attr);
|
---|
228 | if (!k)
|
---|
229 | return -1;
|
---|
230 | return attr.visual->visualid;
|
---|
231 | }
|
---|
232 |
|
---|
233 |
|
---|
234 | /**
|
---|
235 | * Wrapper for glXGetConfig().
|
---|
236 | */
|
---|
237 | static int
|
---|
238 | Attrib( const VisualInfo *visual, int attrib )
|
---|
239 | {
|
---|
240 | int value = 0;
|
---|
241 | render_spu.ws.glXGetConfig( visual->dpy, visual->visual, attrib, &value );
|
---|
242 | return value;
|
---|
243 | }
|
---|
244 |
|
---|
245 |
|
---|
246 |
|
---|
247 | /**
|
---|
248 | * Find a visual with the specified attributes. If we fail, turn off an
|
---|
249 | * attribute (like multisample or stereo) and try again.
|
---|
250 | */
|
---|
251 | static XVisualInfo *
|
---|
252 | chooseVisualRetry( Display *dpy, int screen, GLbitfield visAttribs )
|
---|
253 | {
|
---|
254 | while (1) {
|
---|
255 | XVisualInfo *vis = crChooseVisual(&render_spu.ws, dpy, screen,
|
---|
256 | (GLboolean) render_spu.use_lut8,
|
---|
257 | visAttribs);
|
---|
258 | if (vis)
|
---|
259 | return vis;
|
---|
260 |
|
---|
261 | if (visAttribs & CR_MULTISAMPLE_BIT)
|
---|
262 | visAttribs &= ~CR_MULTISAMPLE_BIT;
|
---|
263 | else if (visAttribs & CR_OVERLAY_BIT)
|
---|
264 | visAttribs &= ~CR_OVERLAY_BIT;
|
---|
265 | else if (visAttribs & CR_STEREO_BIT)
|
---|
266 | visAttribs &= ~CR_STEREO_BIT;
|
---|
267 | else if (visAttribs & CR_ACCUM_BIT)
|
---|
268 | visAttribs &= ~CR_ACCUM_BIT;
|
---|
269 | else if (visAttribs & CR_ALPHA_BIT)
|
---|
270 | visAttribs &= ~CR_ALPHA_BIT;
|
---|
271 | else
|
---|
272 | return NULL;
|
---|
273 | }
|
---|
274 | }
|
---|
275 |
|
---|
276 |
|
---|
277 | /**
|
---|
278 | * Get an FBconfig for the specified attributes
|
---|
279 | */
|
---|
280 | #ifdef GLX_VERSION_1_3
|
---|
281 | static GLXFBConfig
|
---|
282 | chooseFBConfig( Display *dpy, int screen, GLbitfield visAttribs )
|
---|
283 | {
|
---|
284 | GLXFBConfig *fbconfig;
|
---|
285 | int attribs[1000], attrCount = 0, numConfigs;
|
---|
286 | int major, minor;
|
---|
287 |
|
---|
288 | CRASSERT(visAttribs & CR_PBUFFER_BIT);
|
---|
289 |
|
---|
290 | /* Make sure pbuffers are supported */
|
---|
291 | render_spu.ws.glXQueryVersion(dpy, &major, &minor);
|
---|
292 | if (major * 100 + minor < 103) {
|
---|
293 | crWarning("Render SPU: GLX %d.%d doesn't support pbuffers", major, minor);
|
---|
294 | return 0;
|
---|
295 | }
|
---|
296 |
|
---|
297 | attribs[attrCount++] = GLX_DRAWABLE_TYPE;
|
---|
298 | attribs[attrCount++] = GLX_PBUFFER_BIT;
|
---|
299 |
|
---|
300 | if (visAttribs & CR_RGB_BIT) {
|
---|
301 | attribs[attrCount++] = GLX_RENDER_TYPE;
|
---|
302 | attribs[attrCount++] = GLX_RGBA_BIT;
|
---|
303 | attribs[attrCount++] = GLX_RED_SIZE;
|
---|
304 | attribs[attrCount++] = 1;
|
---|
305 | attribs[attrCount++] = GLX_GREEN_SIZE;
|
---|
306 | attribs[attrCount++] = 1;
|
---|
307 | attribs[attrCount++] = GLX_BLUE_SIZE;
|
---|
308 | attribs[attrCount++] = 1;
|
---|
309 | if (visAttribs & CR_ALPHA_BIT) {
|
---|
310 | attribs[attrCount++] = GLX_ALPHA_SIZE;
|
---|
311 | attribs[attrCount++] = 1;
|
---|
312 | }
|
---|
313 | }
|
---|
314 |
|
---|
315 | if (visAttribs & CR_DEPTH_BIT) {
|
---|
316 | attribs[attrCount++] = GLX_DEPTH_SIZE;
|
---|
317 | attribs[attrCount++] = 1;
|
---|
318 | }
|
---|
319 |
|
---|
320 | if (visAttribs & CR_DOUBLE_BIT) {
|
---|
321 | attribs[attrCount++] = GLX_DOUBLEBUFFER;
|
---|
322 | attribs[attrCount++] = True;
|
---|
323 | }
|
---|
324 | else {
|
---|
325 | /* don't care */
|
---|
326 | }
|
---|
327 |
|
---|
328 | if (visAttribs & CR_STENCIL_BIT) {
|
---|
329 | attribs[attrCount++] = GLX_STENCIL_SIZE;
|
---|
330 | attribs[attrCount++] = 1;
|
---|
331 | }
|
---|
332 |
|
---|
333 | if (visAttribs & CR_ACCUM_BIT) {
|
---|
334 | attribs[attrCount++] = GLX_ACCUM_RED_SIZE;
|
---|
335 | attribs[attrCount++] = 1;
|
---|
336 | attribs[attrCount++] = GLX_ACCUM_GREEN_SIZE;
|
---|
337 | attribs[attrCount++] = 1;
|
---|
338 | attribs[attrCount++] = GLX_ACCUM_BLUE_SIZE;
|
---|
339 | attribs[attrCount++] = 1;
|
---|
340 | if (visAttribs & CR_ALPHA_BIT) {
|
---|
341 | attribs[attrCount++] = GLX_ACCUM_ALPHA_SIZE;
|
---|
342 | attribs[attrCount++] = 1;
|
---|
343 | }
|
---|
344 | }
|
---|
345 |
|
---|
346 | if (visAttribs & CR_MULTISAMPLE_BIT) {
|
---|
347 | attribs[attrCount++] = GLX_SAMPLE_BUFFERS_SGIS;
|
---|
348 | attribs[attrCount++] = 1;
|
---|
349 | attribs[attrCount++] = GLX_SAMPLES_SGIS;
|
---|
350 | attribs[attrCount++] = 4;
|
---|
351 | }
|
---|
352 |
|
---|
353 | if (visAttribs & CR_STEREO_BIT) {
|
---|
354 | attribs[attrCount++] = GLX_STEREO;
|
---|
355 | attribs[attrCount++] = 1;
|
---|
356 | }
|
---|
357 |
|
---|
358 | /* terminate */
|
---|
359 | attribs[attrCount++] = 0;
|
---|
360 |
|
---|
361 | fbconfig = render_spu.ws.glXChooseFBConfig(dpy, screen, attribs, &numConfigs);
|
---|
362 | if (!fbconfig || numConfigs == 0) {
|
---|
363 | /* no matches! */
|
---|
364 | return 0;
|
---|
365 | }
|
---|
366 | if (numConfigs == 1) {
|
---|
367 | /* one match */
|
---|
368 | return fbconfig[0];
|
---|
369 | }
|
---|
370 | else {
|
---|
371 | /* found several matches - try to find best one */
|
---|
372 | int i;
|
---|
373 |
|
---|
374 | crDebug("Render SPU: glXChooseFBConfig found %d matches for visBits 0x%x",
|
---|
375 | numConfigs, visAttribs);
|
---|
376 | /* Skip/omit configs that have unneeded Z buffer or unneeded double
|
---|
377 | * buffering. Possible add other tests in the future.
|
---|
378 | */
|
---|
379 | for (i = 0; i < numConfigs; i++) {
|
---|
380 | int zBits, db;
|
---|
381 | render_spu.ws.glXGetFBConfigAttrib(dpy, fbconfig[i],
|
---|
382 | GLX_DEPTH_SIZE, &zBits);
|
---|
383 | if ((visAttribs & CR_DEPTH_BIT) == 0 && zBits > 0) {
|
---|
384 | /* omit fbconfig with unneeded Z */
|
---|
385 | continue;
|
---|
386 | }
|
---|
387 | render_spu.ws.glXGetFBConfigAttrib(dpy, fbconfig[i],
|
---|
388 | GLX_DOUBLEBUFFER, &db);
|
---|
389 | if ((visAttribs & CR_DOUBLE_BIT) == 0 && db) {
|
---|
390 | /* omit fbconfig with uneeded DB */
|
---|
391 | continue;
|
---|
392 | }
|
---|
393 |
|
---|
394 | /* if we get here, use this config */
|
---|
395 | return fbconfig[i];
|
---|
396 | }
|
---|
397 |
|
---|
398 | /* if we get here, we didn't find a better fbconfig */
|
---|
399 | return fbconfig[0];
|
---|
400 | }
|
---|
401 | }
|
---|
402 | #endif /* GLX_VERSION_1_3 */
|
---|
403 |
|
---|
404 |
|
---|
405 | GLboolean
|
---|
406 | renderspu_SystemInitVisual( VisualInfo *visual )
|
---|
407 | {
|
---|
408 | const char *dpyName;
|
---|
409 | int screen;
|
---|
410 |
|
---|
411 | CRASSERT(visual);
|
---|
412 |
|
---|
413 | #ifdef USE_OSMESA
|
---|
414 | if (render_spu.use_osmesa) {
|
---|
415 | /* A dummy visual - being non null is enough. */
|
---|
416 | visual->visual =(XVisualInfo *) "os";
|
---|
417 | return GL_TRUE;
|
---|
418 | }
|
---|
419 | #endif
|
---|
420 |
|
---|
421 | if (render_spu.display_string[0])
|
---|
422 | dpyName = render_spu.display_string;
|
---|
423 | else if (visual->displayName[0])
|
---|
424 | dpyName = visual->displayName;
|
---|
425 | else
|
---|
426 | dpyName = NULL;
|
---|
427 |
|
---|
428 | if (!dpyName)
|
---|
429 | {
|
---|
430 | crWarning("Render SPU: no display, aborting");
|
---|
431 | return GL_FALSE;
|
---|
432 | }
|
---|
433 |
|
---|
434 | crDebug("Render SPU: Opening display %s", dpyName);
|
---|
435 |
|
---|
436 | if (dpyName &&
|
---|
437 | (crStrncmp(dpyName, "localhost:11", 12) == 0 ||
|
---|
438 | crStrncmp(dpyName, "localhost:12", 12) == 0 ||
|
---|
439 | crStrncmp(dpyName, "localhost:13", 12) == 0)) {
|
---|
440 | /* Issue both debug and warning messages to make sure the
|
---|
441 | * message gets noticed!
|
---|
442 | */
|
---|
443 | crDebug("Render SPU: display string looks like a proxy X server!");
|
---|
444 | crDebug("Render SPU: This is usually a problem!");
|
---|
445 | crWarning("Render SPU: display string looks like a proxy X server!");
|
---|
446 | crWarning("Render SPU: This is usually a problem!");
|
---|
447 | }
|
---|
448 |
|
---|
449 | visual->dpy = XOpenDisplay(dpyName);
|
---|
450 | if (!visual->dpy)
|
---|
451 | {
|
---|
452 | crWarning( "Couldn't open X display named '%s'", dpyName );
|
---|
453 | return GL_FALSE;
|
---|
454 | }
|
---|
455 |
|
---|
456 | if ( !render_spu.ws.glXQueryExtension( visual->dpy, NULL, NULL ) )
|
---|
457 | {
|
---|
458 | crWarning( "Render SPU: Display %s doesn't support GLX", visual->displayName );
|
---|
459 | return GL_FALSE;
|
---|
460 | }
|
---|
461 |
|
---|
462 | screen = DefaultScreen(visual->dpy);
|
---|
463 |
|
---|
464 | #ifdef GLX_VERSION_1_3
|
---|
465 | if (visual->visAttribs & CR_PBUFFER_BIT)
|
---|
466 | {
|
---|
467 | visual->fbconfig = chooseFBConfig(visual->dpy, screen, visual->visAttribs);
|
---|
468 | if (!visual->fbconfig) {
|
---|
469 | char s[1000];
|
---|
470 | renderspuMakeVisString( visual->visAttribs, s );
|
---|
471 | crWarning( "Render SPU: Display %s doesn't have the necessary fbconfig: %s",
|
---|
472 | dpyName, s );
|
---|
473 | XCloseDisplay(visual->dpy);
|
---|
474 | return GL_FALSE;
|
---|
475 | }
|
---|
476 | }
|
---|
477 | else
|
---|
478 | #endif /* GLX_VERSION_1_3 */
|
---|
479 | {
|
---|
480 | visual->visual = chooseVisualRetry(visual->dpy, screen, visual->visAttribs);
|
---|
481 | if (!visual->visual) {
|
---|
482 | char s[1000];
|
---|
483 | renderspuMakeVisString( visual->visAttribs, s );
|
---|
484 | crWarning("Render SPU: Display %s doesn't have the necessary visual: %s",
|
---|
485 | dpyName, s );
|
---|
486 | XCloseDisplay(visual->dpy);
|
---|
487 | return GL_FALSE;
|
---|
488 | }
|
---|
489 | }
|
---|
490 |
|
---|
491 | if ( render_spu.sync )
|
---|
492 | {
|
---|
493 | crDebug( "Render SPU: Turning on XSynchronize" );
|
---|
494 | XSynchronize( visual->dpy, True );
|
---|
495 | }
|
---|
496 |
|
---|
497 | if (visual->visual) {
|
---|
498 | crDebug( "Render SPU: Chose visual id=0x%x: RGBA=(%d,%d,%d,%d) Z=%d"
|
---|
499 | " stencil=%d double=%d stereo=%d accum=(%d,%d,%d,%d)",
|
---|
500 | (int) visual->visual->visualid,
|
---|
501 | Attrib( visual, GLX_RED_SIZE ),
|
---|
502 | Attrib( visual, GLX_GREEN_SIZE ),
|
---|
503 | Attrib( visual, GLX_BLUE_SIZE ),
|
---|
504 | Attrib( visual, GLX_ALPHA_SIZE ),
|
---|
505 | Attrib( visual, GLX_DEPTH_SIZE ),
|
---|
506 | Attrib( visual, GLX_STENCIL_SIZE ),
|
---|
507 | Attrib( visual, GLX_DOUBLEBUFFER ),
|
---|
508 | Attrib( visual, GLX_STEREO ),
|
---|
509 | Attrib( visual, GLX_ACCUM_RED_SIZE ),
|
---|
510 | Attrib( visual, GLX_ACCUM_GREEN_SIZE ),
|
---|
511 | Attrib( visual, GLX_ACCUM_BLUE_SIZE ),
|
---|
512 | Attrib( visual, GLX_ACCUM_ALPHA_SIZE )
|
---|
513 | );
|
---|
514 | }
|
---|
515 | else if (visual->fbconfig) {
|
---|
516 | int id;
|
---|
517 | render_spu.ws.glXGetFBConfigAttrib(visual->dpy, visual->fbconfig,
|
---|
518 | GLX_FBCONFIG_ID, &id);
|
---|
519 | crDebug("Render SPU: Chose FBConfig 0x%x, visBits=0x%x",
|
---|
520 | id, visual->visAttribs);
|
---|
521 | }
|
---|
522 |
|
---|
523 | return GL_TRUE;
|
---|
524 | }
|
---|
525 |
|
---|
526 |
|
---|
527 | /*
|
---|
528 | * Add a GLX window to a swap group for inter-machine SwapBuffer
|
---|
529 | * synchronization.
|
---|
530 | * Only supported on NVIDIA Quadro 3000G hardware.
|
---|
531 | */
|
---|
532 | static void
|
---|
533 | JoinSwapGroup(Display *dpy, int screen, Window window,
|
---|
534 | GLuint group, GLuint barrier)
|
---|
535 | {
|
---|
536 | GLuint maxGroups, maxBarriers;
|
---|
537 | const char *ext;
|
---|
538 | Bool b;
|
---|
539 |
|
---|
540 | /*
|
---|
541 | * XXX maybe query glXGetClientString() instead???
|
---|
542 | */
|
---|
543 | ext = render_spu.ws.glXQueryExtensionsString(dpy, screen);
|
---|
544 |
|
---|
545 | if (!crStrstr(ext, "GLX_NV_swap_group") ||
|
---|
546 | !render_spu.ws.glXQueryMaxSwapGroupsNV ||
|
---|
547 | !render_spu.ws.glXJoinSwapGroupNV ||
|
---|
548 | !render_spu.ws.glXBindSwapBarrierNV) {
|
---|
549 | crWarning("Render SPU: nv_swap_group is set but GLX_NV_swap_group is not supported on this system!");
|
---|
550 | return;
|
---|
551 | }
|
---|
552 |
|
---|
553 | b = render_spu.ws.glXQueryMaxSwapGroupsNV(dpy, screen,
|
---|
554 | &maxGroups, &maxBarriers);
|
---|
555 | if (!b)
|
---|
556 | crWarning("Render SPU: call to glXQueryMaxSwapGroupsNV() failed!");
|
---|
557 |
|
---|
558 | if (group >= maxGroups) {
|
---|
559 | crWarning("Render SPU: nv_swap_group too large (%d > %d)",
|
---|
560 | group, (int) maxGroups);
|
---|
561 | return;
|
---|
562 | }
|
---|
563 | crDebug("Render SPU: max swap groups = %d, max barriers = %d",
|
---|
564 | maxGroups, maxBarriers);
|
---|
565 |
|
---|
566 | /* add this window to the swap group */
|
---|
567 | b = render_spu.ws.glXJoinSwapGroupNV(dpy, window, group);
|
---|
568 | if (!b) {
|
---|
569 | crWarning("Render SPU: call to glXJoinSwapGroupNV() failed!");
|
---|
570 | return;
|
---|
571 | }
|
---|
572 | else {
|
---|
573 | crDebug("Render SPU: call to glXJoinSwapGroupNV() worked!");
|
---|
574 | }
|
---|
575 |
|
---|
576 | /* ... and bind window to barrier of same ID */
|
---|
577 | b = render_spu.ws.glXBindSwapBarrierNV(dpy, group, barrier);
|
---|
578 | if (!b) {
|
---|
579 | crWarning("Render SPU: call to glXBindSwapBarrierNV(group=%d barrier=%d) failed!", group, barrier);
|
---|
580 | return;
|
---|
581 | }
|
---|
582 | else {
|
---|
583 | crDebug("Render SPU: call to glXBindSwapBarrierNV(group=%d barrier=%d) worked!", group, barrier);
|
---|
584 | }
|
---|
585 |
|
---|
586 | crDebug("Render SPU: window has joined swap group %d", group);
|
---|
587 | }
|
---|
588 |
|
---|
589 |
|
---|
590 |
|
---|
591 | static GLboolean
|
---|
592 | createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
|
---|
593 | {
|
---|
594 | Display *dpy;
|
---|
595 | Colormap cmap;
|
---|
596 | XSetWindowAttributes swa;
|
---|
597 | XSizeHints hints = {0};
|
---|
598 | XEvent event;
|
---|
599 | XTextProperty text_prop;
|
---|
600 | XClassHint *class_hints = NULL;
|
---|
601 | Window parent;
|
---|
602 | char *name;
|
---|
603 | unsigned long flags;
|
---|
604 | unsigned int vncWin;
|
---|
605 |
|
---|
606 | CRASSERT(visual);
|
---|
607 | window->visual = visual;
|
---|
608 | window->nativeWindow = 0;
|
---|
609 |
|
---|
610 | #ifdef USE_OSMESA
|
---|
611 | if (render_spu.use_osmesa)
|
---|
612 | return GL_TRUE;
|
---|
613 | #endif
|
---|
614 |
|
---|
615 | dpy = visual->dpy;
|
---|
616 |
|
---|
617 | if ( render_spu.use_L2 )
|
---|
618 | {
|
---|
619 | crWarning( "Render SPU: Going fullscreen because we think we're using Lightning-2." );
|
---|
620 | render_spu.fullscreen = 1;
|
---|
621 | }
|
---|
622 |
|
---|
623 | /*
|
---|
624 | * Query screen size if we're going full-screen
|
---|
625 | */
|
---|
626 | if ( render_spu.fullscreen )
|
---|
627 | {
|
---|
628 | XWindowAttributes xwa;
|
---|
629 | Window root_window;
|
---|
630 |
|
---|
631 | /* disable the screensaver */
|
---|
632 | XSetScreenSaver( dpy, 0, 0, PreferBlanking, AllowExposures );
|
---|
633 | crDebug( "Render SPU: Just turned off the screensaver" );
|
---|
634 |
|
---|
635 | /* Figure out how big the screen is, and make the window that size */
|
---|
636 | root_window = DefaultRootWindow( dpy );
|
---|
637 | XGetWindowAttributes( dpy, root_window, &xwa );
|
---|
638 |
|
---|
639 | crDebug( "Render SPU: root window size: %d x %d", xwa.width, xwa.height );
|
---|
640 |
|
---|
641 | window->x = 0;
|
---|
642 | window->y = 0;
|
---|
643 | window->width = xwa.width;
|
---|
644 | window->height = xwa.height;
|
---|
645 | }
|
---|
646 |
|
---|
647 | /* i've changed default window size to be 0,0 but X doesn't like it */
|
---|
648 | /*CRASSERT(window->width >= 1);
|
---|
649 | CRASSERT(window->height >= 1);*/
|
---|
650 | if (window->width < 1) window->width = 1;
|
---|
651 | if (window->height < 1) window->height = 1;
|
---|
652 |
|
---|
653 | /*
|
---|
654 | * Get a colormap.
|
---|
655 | */
|
---|
656 | if (render_spu.use_lut8)
|
---|
657 | cmap = GetLUTColormap( dpy, visual->visual );
|
---|
658 | else
|
---|
659 | cmap = GetShareableColormap( dpy, visual->visual );
|
---|
660 | if ( !cmap ) {
|
---|
661 | crError( "Render SPU: Unable to get a colormap!" );
|
---|
662 | return GL_FALSE;
|
---|
663 | }
|
---|
664 |
|
---|
665 | /* destroy existing window if there is one */
|
---|
666 | if (window->window) {
|
---|
667 | XDestroyWindow(dpy, window->window);
|
---|
668 | }
|
---|
669 |
|
---|
670 | /*
|
---|
671 | * Create the window
|
---|
672 | *
|
---|
673 | * POSSIBLE OPTIMIZATION:
|
---|
674 | * If we're using the render_to_app_window or render_to_crut_window option
|
---|
675 | * (or DMX) we may never actually use this X window. So we could perhaps
|
---|
676 | * delay its creation until glXMakeCurrent is called. With NVIDIA's OpenGL
|
---|
677 | * driver, creating a lot of GLX windows can eat up a lot of VRAM and lead
|
---|
678 | * to slow, software-fallback rendering. Apps that use render_to_app_window,
|
---|
679 | * etc should set the default window size very small to avoid this.
|
---|
680 | * See dmx.conf for example.
|
---|
681 | */
|
---|
682 | swa.colormap = cmap;
|
---|
683 | swa.border_pixel = 0;
|
---|
684 | swa.event_mask = ExposureMask | StructureNotifyMask;
|
---|
685 | swa.override_redirect = 1;
|
---|
686 |
|
---|
687 | flags = CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
|
---|
688 |
|
---|
689 | /*
|
---|
690 | * We pass the VNC's desktop windowID via an environment variable.
|
---|
691 | * If we don't find one, we're not on a 3D-capable vncviewer, or
|
---|
692 | * if we do find one, then create the renderspu subwindow as a
|
---|
693 | * child of the vncviewer's desktop window.
|
---|
694 | *
|
---|
695 | * This is purely for the replicateSPU.
|
---|
696 | *
|
---|
697 | * NOTE: This is crufty, and will do for now. FIXME.
|
---|
698 | */
|
---|
699 | vncWin = crStrToInt( crGetenv("CRVNCWINDOW") );
|
---|
700 | if (vncWin)
|
---|
701 | parent = (Window) vncWin;
|
---|
702 | else
|
---|
703 | parent = RootWindow(dpy, visual->visual->screen);
|
---|
704 |
|
---|
705 | if (render_spu_parent_window_id>0)
|
---|
706 | {
|
---|
707 | crDebug("Render SPU: VBox parent window_id is: %x", render_spu_parent_window_id);
|
---|
708 | window->window = XCreateWindow(dpy, render_spu_parent_window_id,
|
---|
709 | window->x, window->y,
|
---|
710 | window->width, window->height,
|
---|
711 | 0, visual->visual->depth, InputOutput,
|
---|
712 | visual->visual->visual, flags, &swa);
|
---|
713 | }
|
---|
714 | else
|
---|
715 | {
|
---|
716 | /* This should happen only at the call from crVBoxServerInit. At this point we don't
|
---|
717 | * know render_spu_parent_window_id yet, nor we need it for default window which is hidden.
|
---|
718 | */
|
---|
719 |
|
---|
720 | crDebug("Render SPU: Creating global window, parent: %x", RootWindow(dpy, visual->visual->screen));
|
---|
721 | window->window = XCreateWindow(dpy, RootWindow(dpy, visual->visual->screen),
|
---|
722 | window->x, window->y,
|
---|
723 | window->width, window->height,
|
---|
724 | 0, visual->visual->depth, InputOutput,
|
---|
725 | visual->visual->visual, flags, &swa);
|
---|
726 | }
|
---|
727 |
|
---|
728 | if (!window->window) {
|
---|
729 | crWarning( "Render SPU: unable to create window" );
|
---|
730 | return GL_FALSE;
|
---|
731 | }
|
---|
732 |
|
---|
733 | crDebug( "Render SPU: Created window 0x%x on display %s, Xvisual 0x%x",
|
---|
734 | (int) window->window,
|
---|
735 | DisplayString(visual->dpy),
|
---|
736 | (int) visual->visual->visual->visualid /* yikes */
|
---|
737 | );
|
---|
738 |
|
---|
739 | if (render_spu.fullscreen || render_spu.borderless)
|
---|
740 | {
|
---|
741 | /* Disable border/decorations with an MWM property (observed by most
|
---|
742 | * modern window managers.
|
---|
743 | */
|
---|
744 | PropMotifWmHints motif_hints;
|
---|
745 | Atom prop, proptype;
|
---|
746 |
|
---|
747 | /* setup the property */
|
---|
748 | motif_hints.flags = MWM_HINTS_DECORATIONS;
|
---|
749 | motif_hints.decorations = 0; /* Turn off all decorations */
|
---|
750 |
|
---|
751 | /* get the atom for the property */
|
---|
752 | prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
|
---|
753 | if (prop) {
|
---|
754 | /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
|
---|
755 | proptype = prop;
|
---|
756 | XChangeProperty( dpy, window->window, /* display, window */
|
---|
757 | prop, proptype, /* property, type */
|
---|
758 | 32, /* format: 32-bit datums */
|
---|
759 | PropModeReplace, /* mode */
|
---|
760 | (unsigned char *) &motif_hints, /* data */
|
---|
761 | PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
|
---|
762 | );
|
---|
763 | }
|
---|
764 | }
|
---|
765 |
|
---|
766 | /* Make a clear cursor to get rid of the monitor cursor */
|
---|
767 | if ( render_spu.fullscreen )
|
---|
768 | {
|
---|
769 | Pixmap pixmap;
|
---|
770 | Cursor cursor;
|
---|
771 | XColor colour;
|
---|
772 | char clearByte = 0;
|
---|
773 |
|
---|
774 | /* AdB - Only bother to create a 1x1 cursor (byte) */
|
---|
775 | pixmap = XCreatePixmapFromBitmapData(dpy, window->window, &clearByte,
|
---|
776 | 1, 1, 1, 0, 1);
|
---|
777 | if(!pixmap){
|
---|
778 | crWarning("Unable to create clear cursor pixmap");
|
---|
779 | return GL_FALSE;
|
---|
780 | }
|
---|
781 |
|
---|
782 | cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &colour, &colour, 0, 0);
|
---|
783 | if(!cursor){
|
---|
784 | crWarning("Unable to create clear cursor from zero byte pixmap");
|
---|
785 | return GL_FALSE;
|
---|
786 | }
|
---|
787 | XDefineCursor(dpy, window->window, cursor);
|
---|
788 | XFreePixmap(dpy, pixmap);
|
---|
789 | }
|
---|
790 |
|
---|
791 | hints.x = window->x;
|
---|
792 | hints.y = window->y;
|
---|
793 | hints.width = window->width;
|
---|
794 | hints.height = window->height;
|
---|
795 | hints.min_width = hints.width;
|
---|
796 | hints.min_height = hints.height;
|
---|
797 | hints.max_width = hints.width;
|
---|
798 | hints.max_height = hints.height;
|
---|
799 | if (render_spu.resizable)
|
---|
800 | hints.flags = USPosition | USSize;
|
---|
801 | else
|
---|
802 | hints.flags = USPosition | USSize | PMinSize | PMaxSize;
|
---|
803 | XSetStandardProperties( dpy, window->window,
|
---|
804 | WINDOW_NAME, WINDOW_NAME,
|
---|
805 | None, NULL, 0, &hints );
|
---|
806 |
|
---|
807 | /* New item! This is needed so that the sgimouse server can find
|
---|
808 | * the crDebug window.
|
---|
809 | */
|
---|
810 | name = WINDOW_NAME;
|
---|
811 | XStringListToTextProperty( &name, 1, &text_prop );
|
---|
812 | XSetWMName( dpy, window->window, &text_prop );
|
---|
813 |
|
---|
814 | /* Set window name, resource class */
|
---|
815 | class_hints = XAllocClassHint( );
|
---|
816 | class_hints->res_name = crStrdup( "foo" );
|
---|
817 | class_hints->res_class = crStrdup( "Chromium" );
|
---|
818 | XSetClassHint( dpy, window->window, class_hints );
|
---|
819 | crFree( class_hints->res_name );
|
---|
820 | crFree( class_hints->res_class );
|
---|
821 | XFree( class_hints );
|
---|
822 |
|
---|
823 | if (showIt) {
|
---|
824 | XMapWindow( dpy, window->window );
|
---|
825 | XIfEvent( dpy, &event, WaitForMapNotify,
|
---|
826 | (char *) window->window );
|
---|
827 | }
|
---|
828 | window->visible = showIt;
|
---|
829 |
|
---|
830 | if ((window->visual->visAttribs & CR_DOUBLE_BIT) && render_spu.nvSwapGroup) {
|
---|
831 | /* NOTE:
|
---|
832 | * If this SPU creates N windows we don't want to gang the N windows
|
---|
833 | * together!
|
---|
834 | * By adding the window ID to the nvSwapGroup ID we can be sure each
|
---|
835 | * app window is in a separate swap group while all the back-end windows
|
---|
836 | * which form a mural are in the same swap group.
|
---|
837 | */
|
---|
838 | GLuint group = 0; /*render_spu.nvSwapGroup + window->id;*/
|
---|
839 | GLuint barrier = 0;
|
---|
840 | JoinSwapGroup(dpy, visual->visual->screen, window->window, group, barrier);
|
---|
841 | }
|
---|
842 |
|
---|
843 | /*
|
---|
844 | * End GLX code
|
---|
845 | */
|
---|
846 | crDebug( "Render SPU: actual window x, y, width, height: %d, %d, %d, %d",
|
---|
847 | window->x, window->y, window->width, window->height );
|
---|
848 |
|
---|
849 | XSync(dpy, 0);
|
---|
850 |
|
---|
851 | return GL_TRUE;
|
---|
852 | }
|
---|
853 |
|
---|
854 |
|
---|
855 | static GLboolean
|
---|
856 | createPBuffer( VisualInfo *visual, WindowInfo *window )
|
---|
857 | {
|
---|
858 | window->visual = visual;
|
---|
859 | window->x = 0;
|
---|
860 | window->y = 0;
|
---|
861 | window->nativeWindow = 0;
|
---|
862 |
|
---|
863 | CRASSERT(window->width > 0);
|
---|
864 | CRASSERT(window->height > 0);
|
---|
865 |
|
---|
866 | #ifdef GLX_VERSION_1_3
|
---|
867 | {
|
---|
868 | int attribs[100], i = 0, w, h;
|
---|
869 | CRASSERT(visual->fbconfig);
|
---|
870 | w = window->width;
|
---|
871 | h = window->height;
|
---|
872 | attribs[i++] = GLX_PRESERVED_CONTENTS;
|
---|
873 | attribs[i++] = True;
|
---|
874 | attribs[i++] = GLX_PBUFFER_WIDTH;
|
---|
875 | attribs[i++] = w;
|
---|
876 | attribs[i++] = GLX_PBUFFER_HEIGHT;
|
---|
877 | attribs[i++] = h;
|
---|
878 | attribs[i++] = 0; /* terminator */
|
---|
879 | window->window = render_spu.ws.glXCreatePbuffer(visual->dpy,
|
---|
880 | visual->fbconfig, attribs);
|
---|
881 | if (window->window) {
|
---|
882 | crDebug("Render SPU: Allocated %d x %d pbuffer", w, h);
|
---|
883 | return GL_TRUE;
|
---|
884 | }
|
---|
885 | else {
|
---|
886 | crWarning("Render SPU: Failed to allocate %d x %d pbuffer", w, h);
|
---|
887 | return GL_FALSE;
|
---|
888 | }
|
---|
889 | }
|
---|
890 | #endif /* GLX_VERSION_1_3 */
|
---|
891 | return GL_FALSE;
|
---|
892 | }
|
---|
893 |
|
---|
894 |
|
---|
895 | GLboolean
|
---|
896 | renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
|
---|
897 | {
|
---|
898 | if (visual->visAttribs & CR_PBUFFER_BIT) {
|
---|
899 | window->width = render_spu.defaultWidth;
|
---|
900 | window->height = render_spu.defaultHeight;
|
---|
901 | return createPBuffer(visual, window);
|
---|
902 | }
|
---|
903 | else {
|
---|
904 | return createWindow(visual, showIt, window);
|
---|
905 | }
|
---|
906 | }
|
---|
907 |
|
---|
908 | GLboolean
|
---|
909 | renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
|
---|
910 | {
|
---|
911 | return renderspu_SystemCreateWindow(visual, showIt, window);
|
---|
912 | }
|
---|
913 |
|
---|
914 | void
|
---|
915 | renderspu_SystemDestroyWindow( WindowInfo *window )
|
---|
916 | {
|
---|
917 | CRASSERT(window);
|
---|
918 | CRASSERT(window->visual);
|
---|
919 |
|
---|
920 | #ifdef USE_OSMESA
|
---|
921 | if (render_spu.use_osmesa)
|
---|
922 | {
|
---|
923 | crFree(window->buffer);
|
---|
924 | window->buffer = NULL;
|
---|
925 | }
|
---|
926 | else
|
---|
927 | #endif
|
---|
928 | {
|
---|
929 | if (window->visual->visAttribs & CR_PBUFFER_BIT) {
|
---|
930 | #ifdef GLX_VERSION_1_3
|
---|
931 | render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window);
|
---|
932 | #endif
|
---|
933 | }
|
---|
934 | else {
|
---|
935 | /* The value window->nativeWindow will only be non-NULL if the
|
---|
936 | * render_to_app_window option is set to true. In this case, we
|
---|
937 | * don't want to do anything, since we're not responsible for this
|
---|
938 | * window. I know...personal responsibility and all...
|
---|
939 | */
|
---|
940 | if (!window->nativeWindow) {
|
---|
941 | XDestroyWindow(window->visual->dpy, window->window);
|
---|
942 | XSync(window->visual->dpy, 0);
|
---|
943 | }
|
---|
944 | }
|
---|
945 | }
|
---|
946 | window->visual = NULL;
|
---|
947 | window->window = 0;
|
---|
948 | }
|
---|
949 |
|
---|
950 |
|
---|
951 | GLboolean
|
---|
952 | renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext )
|
---|
953 | {
|
---|
954 | Bool is_direct;
|
---|
955 | GLXContext sharedSystemContext = NULL;
|
---|
956 |
|
---|
957 | CRASSERT(visual);
|
---|
958 | CRASSERT(context);
|
---|
959 |
|
---|
960 | context->visual = visual;
|
---|
961 |
|
---|
962 | if (sharedContext != NULL) {
|
---|
963 | sharedSystemContext = sharedContext->context;
|
---|
964 | }
|
---|
965 |
|
---|
966 |
|
---|
967 |
|
---|
968 | #ifdef USE_OSMESA
|
---|
969 | if (render_spu.use_osmesa) {
|
---|
970 | context->context = (GLXContext) render_spu.OSMesaCreateContext(OSMESA_RGB, 0);
|
---|
971 | if (context->context)
|
---|
972 | return GL_TRUE;
|
---|
973 | else
|
---|
974 | return GL_FALSE;
|
---|
975 | }
|
---|
976 | #endif
|
---|
977 |
|
---|
978 | #ifdef GLX_VERSION_1_3
|
---|
979 | if (visual->visAttribs & CR_PBUFFER_BIT) {
|
---|
980 | context->context = render_spu.ws.glXCreateNewContext( visual->dpy,
|
---|
981 | visual->fbconfig,
|
---|
982 | GLX_RGBA_TYPE,
|
---|
983 | sharedSystemContext,
|
---|
984 | render_spu.try_direct);
|
---|
985 | }
|
---|
986 | else
|
---|
987 | #endif
|
---|
988 | {
|
---|
989 | context->context = render_spu.ws.glXCreateContext( visual->dpy,
|
---|
990 | visual->visual,
|
---|
991 | sharedSystemContext,
|
---|
992 | render_spu.try_direct);
|
---|
993 | }
|
---|
994 | if (!context->context) {
|
---|
995 | crError( "Render SPU: Couldn't create rendering context" );
|
---|
996 | return GL_FALSE;
|
---|
997 | }
|
---|
998 |
|
---|
999 | is_direct = render_spu.ws.glXIsDirect( visual->dpy, context->context );
|
---|
1000 | if (visual->visual)
|
---|
1001 | crDebug("Render SPU: Created %s context (%d) on display %s for visAttribs 0x%x",
|
---|
1002 | is_direct ? "DIRECT" : "INDIRECT",
|
---|
1003 | context->id,
|
---|
1004 | DisplayString(visual->dpy),
|
---|
1005 | visual->visAttribs);
|
---|
1006 |
|
---|
1007 | if ( render_spu.force_direct && !is_direct )
|
---|
1008 | {
|
---|
1009 | crError( "Render SPU: Direct rendering not possible." );
|
---|
1010 | return GL_FALSE;
|
---|
1011 | }
|
---|
1012 |
|
---|
1013 | return GL_TRUE;
|
---|
1014 | }
|
---|
1015 |
|
---|
1016 |
|
---|
1017 | #define USE_GLX_COPYCONTEXT 0
|
---|
1018 |
|
---|
1019 | #if !USE_GLX_COPYCONTEXT
|
---|
1020 |
|
---|
1021 | /**
|
---|
1022 | * Unfortunately, glXCopyContext() is broken sometimes (NVIDIA 76.76 driver).
|
---|
1023 | * This bit of code gets and sets GL state we need to copy between contexts.
|
---|
1024 | */
|
---|
1025 | struct saved_state
|
---|
1026 | {
|
---|
1027 | /* XXX depending on the app, more state may be needed here */
|
---|
1028 | GLboolean Lighting;
|
---|
1029 | GLboolean LightEnabled[8];
|
---|
1030 | GLfloat LightPos[8][4];
|
---|
1031 | GLfloat LightAmbient[8][4];
|
---|
1032 | GLfloat LightDiffuse[8][4];
|
---|
1033 | GLfloat LightSpecular[8][4];
|
---|
1034 | GLboolean DepthTest;
|
---|
1035 | };
|
---|
1036 |
|
---|
1037 | static struct saved_state SavedState;
|
---|
1038 |
|
---|
1039 | static void
|
---|
1040 | get_state(struct saved_state *s)
|
---|
1041 | {
|
---|
1042 | int i;
|
---|
1043 |
|
---|
1044 | s->Lighting = render_spu.self.IsEnabled(GL_LIGHTING);
|
---|
1045 | for (i = 0; i < 8; i++) {
|
---|
1046 | s->LightEnabled[i] = render_spu.self.IsEnabled(GL_LIGHT0 + i);
|
---|
1047 | render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_POSITION, s->LightPos[i]);
|
---|
1048 | render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_AMBIENT, s->LightAmbient[i]);
|
---|
1049 | render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, s->LightDiffuse[i]);
|
---|
1050 | render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_SPECULAR, s->LightSpecular[i]);
|
---|
1051 | }
|
---|
1052 |
|
---|
1053 | s->DepthTest = render_spu.self.IsEnabled(GL_DEPTH_TEST);
|
---|
1054 | }
|
---|
1055 |
|
---|
1056 | static void
|
---|
1057 | set_state(const struct saved_state *s)
|
---|
1058 | {
|
---|
1059 | int i;
|
---|
1060 |
|
---|
1061 | if (s->Lighting) {
|
---|
1062 | render_spu.self.Enable(GL_LIGHTING);
|
---|
1063 | }
|
---|
1064 | else {
|
---|
1065 | render_spu.self.Disable(GL_LIGHTING);
|
---|
1066 | }
|
---|
1067 |
|
---|
1068 | for (i = 0; i < 8; i++) {
|
---|
1069 | if (s->LightEnabled[i]) {
|
---|
1070 | render_spu.self.Enable(GL_LIGHT0 + i);
|
---|
1071 | }
|
---|
1072 | else {
|
---|
1073 | render_spu.self.Disable(GL_LIGHT0 + i);
|
---|
1074 | }
|
---|
1075 | render_spu.self.Lightfv(GL_LIGHT0 + i, GL_POSITION, s->LightPos[i]);
|
---|
1076 | render_spu.self.Lightfv(GL_LIGHT0 + i, GL_AMBIENT, s->LightAmbient[i]);
|
---|
1077 | render_spu.self.Lightfv(GL_LIGHT0 + i, GL_DIFFUSE, s->LightDiffuse[i]);
|
---|
1078 | render_spu.self.Lightfv(GL_LIGHT0 + i, GL_SPECULAR, s->LightSpecular[i]);
|
---|
1079 | }
|
---|
1080 |
|
---|
1081 | if (s->DepthTest)
|
---|
1082 | render_spu.self.Enable(GL_DEPTH_TEST);
|
---|
1083 | else
|
---|
1084 | render_spu.self.Disable(GL_DEPTH_TEST);
|
---|
1085 | }
|
---|
1086 |
|
---|
1087 | #endif /* !USE_GLX_COPYCONTEXT */
|
---|
1088 |
|
---|
1089 | /**
|
---|
1090 | * Recreate the GLX context for ContextInfo. The new context will use the
|
---|
1091 | * visual specified by newVisualID.
|
---|
1092 | */
|
---|
1093 | static void
|
---|
1094 | renderspu_RecreateContext( ContextInfo *context, int newVisualID )
|
---|
1095 | {
|
---|
1096 | XVisualInfo templateVis, *vis;
|
---|
1097 | long templateFlags;
|
---|
1098 | int screen = 0, count;
|
---|
1099 | GLXContext oldContext = context->context;
|
---|
1100 |
|
---|
1101 | templateFlags = VisualScreenMask | VisualIDMask;
|
---|
1102 | templateVis.screen = screen;
|
---|
1103 | templateVis.visualid = newVisualID;
|
---|
1104 | vis = XGetVisualInfo(context->visual->dpy, templateFlags, &templateVis, &count);
|
---|
1105 | CRASSERT(vis);
|
---|
1106 | if (!vis)
|
---|
1107 | return;
|
---|
1108 |
|
---|
1109 | /* create new context */
|
---|
1110 | crDebug("Render SPU: Creating new GLX context with visual 0x%x", newVisualID);
|
---|
1111 | context->context = render_spu.ws.glXCreateContext(context->visual->dpy,
|
---|
1112 | vis, NULL,
|
---|
1113 | render_spu.try_direct);
|
---|
1114 | CRASSERT(context->context);
|
---|
1115 |
|
---|
1116 | #if USE_GLX_COPYCONTEXT
|
---|
1117 | /* copy old context state to new context */
|
---|
1118 | render_spu.ws.glXCopyContext(context->visual->dpy,
|
---|
1119 | oldContext, context->context, ~0);
|
---|
1120 | crDebug("Render SPU: Done copying context state");
|
---|
1121 | #endif
|
---|
1122 |
|
---|
1123 | /* destroy old context */
|
---|
1124 | render_spu.ws.glXDestroyContext(context->visual->dpy, oldContext);
|
---|
1125 |
|
---|
1126 | context->visual->visual = vis;
|
---|
1127 | }
|
---|
1128 |
|
---|
1129 |
|
---|
1130 | void
|
---|
1131 | renderspu_SystemDestroyContext( ContextInfo *context )
|
---|
1132 | {
|
---|
1133 | #ifdef USE_OSMESA
|
---|
1134 | if (render_spu.use_osmesa)
|
---|
1135 | {
|
---|
1136 | render_spu.OSMesaDestroyContext( (OSMesaContext) context->context );
|
---|
1137 | }
|
---|
1138 | else
|
---|
1139 | #endif
|
---|
1140 | {
|
---|
1141 | #if 0
|
---|
1142 | /* XXX disable for now - causes segfaults w/ NVIDIA's driver */
|
---|
1143 | render_spu.ws.glXDestroyContext( context->visual->dpy, context->context );
|
---|
1144 | #endif
|
---|
1145 | }
|
---|
1146 | context->visual = NULL;
|
---|
1147 | context->context = 0;
|
---|
1148 | }
|
---|
1149 |
|
---|
1150 |
|
---|
1151 | #ifdef USE_OSMESA
|
---|
1152 | static void
|
---|
1153 | check_buffer_size( WindowInfo *window )
|
---|
1154 | {
|
---|
1155 | if (window->width != window->in_buffer_width
|
---|
1156 | || window->height != window->in_buffer_height
|
---|
1157 | || ! window->buffer) {
|
---|
1158 | crFree(window->buffer);
|
---|
1159 |
|
---|
1160 | window->buffer = crCalloc(window->width * window->height
|
---|
1161 | * 4 * sizeof (GLubyte));
|
---|
1162 |
|
---|
1163 | window->in_buffer_width = window->width;
|
---|
1164 | window->in_buffer_height = window->height;
|
---|
1165 |
|
---|
1166 | crDebug("Render SPU: dimensions changed to %d x %d", window->width, window->height);
|
---|
1167 | }
|
---|
1168 | }
|
---|
1169 | #endif
|
---|
1170 |
|
---|
1171 |
|
---|
1172 | void
|
---|
1173 | renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow,
|
---|
1174 | ContextInfo *context )
|
---|
1175 | {
|
---|
1176 | Bool b;
|
---|
1177 |
|
---|
1178 | CRASSERT(render_spu.ws.glXMakeCurrent);
|
---|
1179 | window->appWindow = nativeWindow;
|
---|
1180 |
|
---|
1181 | /*crDebug("%s nativeWindow=0x%x", __FUNCTION__, (int) nativeWindow);*/
|
---|
1182 |
|
---|
1183 | #ifdef USE_OSMESA
|
---|
1184 | if (render_spu.use_osmesa) {
|
---|
1185 | check_buffer_size(window);
|
---|
1186 | render_spu.OSMesaMakeCurrent( (OSMesaContext) context->context,
|
---|
1187 | window->buffer, GL_UNSIGNED_BYTE,
|
---|
1188 | window->width, window->height);
|
---|
1189 | return;
|
---|
1190 | }
|
---|
1191 | #endif
|
---|
1192 |
|
---|
1193 | if (window && context) {
|
---|
1194 | if (window->visual != context->visual) {
|
---|
1195 | crDebug("Render SPU: MakeCurrent visual mismatch (win(%d) bits:0x%x != ctx(%d) bits:0x%x); remaking window.",
|
---|
1196 | window->id, window->visual->visAttribs,
|
---|
1197 | context->id, context->visual->visAttribs);
|
---|
1198 | /*
|
---|
1199 | * XXX have to revisit this issue!!!
|
---|
1200 | *
|
---|
1201 | * But for now we destroy the current window
|
---|
1202 | * and re-create it with the context's visual abilities
|
---|
1203 | */
|
---|
1204 | #ifndef SOLARIS_9_X_BUG
|
---|
1205 | /*
|
---|
1206 | I'm having some really weird issues if I destroy this window
|
---|
1207 | when I'm using the version of sunX that comes with Solaris 9.
|
---|
1208 | Subsiquent glX calls return GLXBadCurrentWindow error.
|
---|
1209 |
|
---|
1210 | This is an issue even when running Linux version and using
|
---|
1211 | the Solaris 9 sunX as a display.
|
---|
1212 | -- jw
|
---|
1213 |
|
---|
1214 | jw: we might have to call glXMakeCurrent(dpy, 0, 0) to unbind
|
---|
1215 | the context from the window before destroying it. -Brian
|
---|
1216 | */
|
---|
1217 | render_spu.ws.glXMakeCurrent(window->visual->dpy, 0, 0);
|
---|
1218 | renderspu_SystemDestroyWindow( window );
|
---|
1219 | #endif
|
---|
1220 | renderspu_SystemCreateWindow( context->visual, window->visible, window );
|
---|
1221 | /*
|
---|
1222 | crError("In renderspu_SystemMakeCurrent() window and context"
|
---|
1223 | " weren't created with same visual!");
|
---|
1224 | */
|
---|
1225 | }
|
---|
1226 |
|
---|
1227 | CRASSERT(context->context);
|
---|
1228 |
|
---|
1229 | #if 0
|
---|
1230 | if (render_spu.render_to_crut_window) {
|
---|
1231 | if (render_spu.crut_drawable == 0) {
|
---|
1232 | /* We don't know the X drawable ID yet. Ask mothership for it. */
|
---|
1233 | char response[8096];
|
---|
1234 | CRConnection *conn = crMothershipConnect();
|
---|
1235 | if (!conn)
|
---|
1236 | {
|
---|
1237 | crError("Couldn't connect to the mothership to get CRUT drawable-- "
|
---|
1238 | "I have no idea what to do!");
|
---|
1239 | }
|
---|
1240 | crMothershipGetParam( conn, "crut_drawable", response );
|
---|
1241 | render_spu.crut_drawable = crStrToInt(response);
|
---|
1242 | crMothershipDisconnect(conn);
|
---|
1243 |
|
---|
1244 | crDebug("Render SPU: using CRUT drawable: 0x%x",
|
---|
1245 | render_spu.crut_drawable);
|
---|
1246 | if (!render_spu.crut_drawable) {
|
---|
1247 | crDebug("Render SPU: Crut drawable 0 is invalid");
|
---|
1248 | /* Continue with nativeWindow = 0; we'll render to the window that
|
---|
1249 | * we (the Render SPU) previously created.
|
---|
1250 | */
|
---|
1251 | }
|
---|
1252 | }
|
---|
1253 |
|
---|
1254 | nativeWindow = render_spu.crut_drawable;
|
---|
1255 | }
|
---|
1256 | #endif
|
---|
1257 |
|
---|
1258 | if ((render_spu.render_to_crut_window || render_spu.render_to_app_window)
|
---|
1259 | && nativeWindow)
|
---|
1260 | {
|
---|
1261 | /* We're about to bind the rendering context to a window that we
|
---|
1262 | * (the Render SPU) did not create. The window was created by the
|
---|
1263 | * application or the CRUT server.
|
---|
1264 | * Make sure the window ID is valid and that the window's X visual is
|
---|
1265 | * the same as the rendering context's.
|
---|
1266 | */
|
---|
1267 | if (WindowExists(window->visual->dpy, nativeWindow))
|
---|
1268 | {
|
---|
1269 | int vid = GetWindowVisualID(window->visual->dpy, nativeWindow);
|
---|
1270 | GLboolean recreated = GL_FALSE;
|
---|
1271 |
|
---|
1272 | /* check that the window's visual and context's visual match */
|
---|
1273 | if (vid != (int) context->visual->visual->visualid) {
|
---|
1274 | crWarning("Render SPU: Can't bind context %d to CRUT/native window "
|
---|
1275 | "0x%x because of different X visuals (0x%x != 0x%x)!",
|
---|
1276 | context->id, (int) nativeWindow,
|
---|
1277 | vid, (int) context->visual->visual->visualid);
|
---|
1278 | crWarning("Render SPU: Trying to recreate GLX context to match.");
|
---|
1279 | /* Try to recreate the GLX context so that it uses the same
|
---|
1280 | * GLX visual as the window.
|
---|
1281 | */
|
---|
1282 | #if !USE_GLX_COPYCONTEXT
|
---|
1283 | if (context->everCurrent) {
|
---|
1284 | get_state(&SavedState);
|
---|
1285 | }
|
---|
1286 | #endif
|
---|
1287 | renderspu_RecreateContext(context, vid);
|
---|
1288 | recreated = GL_TRUE;
|
---|
1289 | }
|
---|
1290 |
|
---|
1291 | /* OK, this should work */
|
---|
1292 | window->nativeWindow = (Window) nativeWindow;
|
---|
1293 | b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
|
---|
1294 | window->nativeWindow,
|
---|
1295 | context->context );
|
---|
1296 | CRASSERT(b);
|
---|
1297 | #if !USE_GLX_COPYCONTEXT
|
---|
1298 | if (recreated) {
|
---|
1299 | set_state(&SavedState);
|
---|
1300 | }
|
---|
1301 | #endif
|
---|
1302 | }
|
---|
1303 | else
|
---|
1304 | {
|
---|
1305 | crWarning("Render SPU: render_to_app/crut_window option is set but "
|
---|
1306 | "the window ID 0x%x is invalid on the display named %s",
|
---|
1307 | (unsigned int) nativeWindow,
|
---|
1308 | DisplayString(window->visual->dpy));
|
---|
1309 | CRASSERT(window->window);
|
---|
1310 | b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
|
---|
1311 | window->window, context->context );
|
---|
1312 | CRASSERT(b);
|
---|
1313 | }
|
---|
1314 | }
|
---|
1315 | else
|
---|
1316 | {
|
---|
1317 | /* This is the normal case - rendering to the render SPU's own window */
|
---|
1318 | CRASSERT(window->window);
|
---|
1319 | #if 0
|
---|
1320 | crDebug("calling glXMakecurrent(%p, 0x%x, 0x%x)",
|
---|
1321 | window->visual->dpy,
|
---|
1322 | (int) window->window, (int) context->context );
|
---|
1323 | #endif
|
---|
1324 | b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
|
---|
1325 | window->window, context->context );
|
---|
1326 | if (!b) {
|
---|
1327 | crWarning("glXMakeCurrent(%p, 0x%x, %p) failed! (winId %d, ctxId %d)",
|
---|
1328 | window->visual->dpy,
|
---|
1329 | (int) window->window, (void *) context->context,
|
---|
1330 | window->id, context->id );
|
---|
1331 | }
|
---|
1332 | /*CRASSERT(b);*/
|
---|
1333 | }
|
---|
1334 |
|
---|
1335 | /* XXX this is a total hack to work around an NVIDIA driver bug */
|
---|
1336 | #if 0
|
---|
1337 | if (render_spu.self.GetFloatv && context->haveWindowPosARB) {
|
---|
1338 | GLfloat f[4];
|
---|
1339 | render_spu.self.GetFloatv(GL_CURRENT_RASTER_POSITION, f);
|
---|
1340 | if (!window->everCurrent || f[1] < 0.0) {
|
---|
1341 | crDebug("Render SPU: Resetting raster pos");
|
---|
1342 | render_spu.self.WindowPos2iARB(0, 0);
|
---|
1343 | }
|
---|
1344 | }
|
---|
1345 | #endif
|
---|
1346 | }
|
---|
1347 |
|
---|
1348 | #if 0
|
---|
1349 | /* XXX disabled for now due to problem with threadtest.conf */
|
---|
1350 | renderspu_GCWindow();
|
---|
1351 | #endif
|
---|
1352 | }
|
---|
1353 |
|
---|
1354 |
|
---|
1355 | /**
|
---|
1356 | * Set window (or pbuffer) size.
|
---|
1357 | */
|
---|
1358 | void
|
---|
1359 | renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h )
|
---|
1360 | {
|
---|
1361 | #ifdef USE_OSMESA
|
---|
1362 | if (render_spu.use_osmesa) {
|
---|
1363 | window->width = w;
|
---|
1364 | window->height = h;
|
---|
1365 | check_buffer_size(window);
|
---|
1366 | return;
|
---|
1367 | }
|
---|
1368 | #endif
|
---|
1369 |
|
---|
1370 | CRASSERT(window);
|
---|
1371 | CRASSERT(window->visual);
|
---|
1372 | if (window->visual->visAttribs & CR_PBUFFER_BIT)
|
---|
1373 | {
|
---|
1374 | /* resizing a pbuffer */
|
---|
1375 | if (render_spu.pbufferWidth != 0 || render_spu.pbufferHeight != 0) {
|
---|
1376 | /* size limit check */
|
---|
1377 | if (w > render_spu.pbufferWidth || h > render_spu.pbufferHeight) {
|
---|
1378 | crWarning("Render SPU: Request for %d x %d pbuffer is larger than "
|
---|
1379 | "the configured size of %d x %d. ('pbuffer_size')",
|
---|
1380 | w, h, render_spu.pbufferWidth, render_spu.pbufferHeight);
|
---|
1381 | return;
|
---|
1382 | }
|
---|
1383 | /*
|
---|
1384 | * If the requested new pbuffer size is greater than 1/2 the size of
|
---|
1385 | * the max pbuffer, just use the max pbuffer size. This helps avoid
|
---|
1386 | * problems with VRAM memory fragmentation. If we run out of VRAM
|
---|
1387 | * for pbuffers, some drivers revert to software rendering. We want
|
---|
1388 | * to avoid that!
|
---|
1389 | */
|
---|
1390 | if (w * h >= render_spu.pbufferWidth * render_spu.pbufferHeight / 2) {
|
---|
1391 | /* increase the dimensions to the max pbuffer size now */
|
---|
1392 | w = render_spu.pbufferWidth;
|
---|
1393 | h = render_spu.pbufferHeight;
|
---|
1394 | }
|
---|
1395 | }
|
---|
1396 |
|
---|
1397 | if (window->width != w || window->height != h) {
|
---|
1398 | /* Only resize if the new dimensions really are different */
|
---|
1399 | #ifdef CHROMIUM_THREADSAFE
|
---|
1400 | ContextInfo *currentContext = (ContextInfo *) crGetTSD(&_RenderTSD);
|
---|
1401 | #else
|
---|
1402 | ContextInfo *currentContext = render_spu.currentContext;
|
---|
1403 | #endif
|
---|
1404 | /* Can't resize pbuffers, so destroy it and make a new one */
|
---|
1405 | render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window);
|
---|
1406 | window->width = w;
|
---|
1407 | window->height = h;
|
---|
1408 | crDebug("Render SPU: Creating new %d x %d PBuffer (id=%d)",
|
---|
1409 | w, h, window->id);
|
---|
1410 | if (!createPBuffer(window->visual, window)) {
|
---|
1411 | crWarning("Render SPU: Unable to create PBuffer (out of VRAM?)!");
|
---|
1412 | }
|
---|
1413 | else if (currentContext && currentContext->currentWindow == window) {
|
---|
1414 | /* Determine if we need to bind the current context to new pbuffer */
|
---|
1415 | render_spu.ws.glXMakeCurrent(window->visual->dpy,
|
---|
1416 | window->window,
|
---|
1417 | currentContext->context );
|
---|
1418 | }
|
---|
1419 | }
|
---|
1420 | }
|
---|
1421 | else {
|
---|
1422 | /* Resize ordinary X window */
|
---|
1423 | /*
|
---|
1424 | * This is ugly, but it seems to be the only thing that works.
|
---|
1425 | * Basically, XResizeWindow() doesn't seem to always take effect
|
---|
1426 | * immediately.
|
---|
1427 | * Even after an XSync(), the GetWindowAttributes() call will sometimes
|
---|
1428 | * return the old window size. So, we use a loop to repeat the window
|
---|
1429 | * resize until it seems to take effect.
|
---|
1430 | */
|
---|
1431 | int attempt;
|
---|
1432 | crDebug("Render SPU: XResizeWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, w, h);
|
---|
1433 | XResizeWindow(window->visual->dpy, window->window, w, h);
|
---|
1434 | XSync(window->visual->dpy, 0);
|
---|
1435 | #if 0
|
---|
1436 | for (attempt = 0; attempt < 3; attempt++) { /* try three times max */
|
---|
1437 | XWindowAttributes attribs;
|
---|
1438 | /* Now, query the window size */
|
---|
1439 | XGetWindowAttributes(window->visual->dpy, window->window, &attribs);
|
---|
1440 | if (attribs.width == w && attribs.height == h)
|
---|
1441 | break;
|
---|
1442 | /* sleep for a millisecond and try again */
|
---|
1443 | crMsleep(1);
|
---|
1444 | }
|
---|
1445 | #endif
|
---|
1446 | }
|
---|
1447 |
|
---|
1448 | /* finally, save the new size */
|
---|
1449 | window->width = w;
|
---|
1450 | window->height = h;
|
---|
1451 | }
|
---|
1452 |
|
---|
1453 |
|
---|
1454 | void
|
---|
1455 | renderspu_SystemGetWindowGeometry( WindowInfo *window,
|
---|
1456 | GLint *x, GLint *y, GLint *w, GLint *h )
|
---|
1457 | {
|
---|
1458 | #ifdef USE_OSMESA
|
---|
1459 | if (render_spu.use_osmesa) {
|
---|
1460 | *w = window->width;
|
---|
1461 | *h = window->height;
|
---|
1462 | return;
|
---|
1463 | }
|
---|
1464 | #endif
|
---|
1465 |
|
---|
1466 | CRASSERT(window);
|
---|
1467 | CRASSERT(window->visual);
|
---|
1468 | CRASSERT(window->window);
|
---|
1469 | if (window->visual->visAttribs & CR_PBUFFER_BIT)
|
---|
1470 | {
|
---|
1471 | *x = 0;
|
---|
1472 | *y = 0;
|
---|
1473 | *w = window->width;
|
---|
1474 | *h = window->height;
|
---|
1475 | }
|
---|
1476 | else
|
---|
1477 | {
|
---|
1478 | Window xw, child, root;
|
---|
1479 | unsigned int width, height, bw, d;
|
---|
1480 | int rx, ry;
|
---|
1481 |
|
---|
1482 | if ((render_spu.render_to_app_window || render_spu.render_to_crut_window)
|
---|
1483 | && window->nativeWindow) {
|
---|
1484 | xw = window->nativeWindow;
|
---|
1485 | }
|
---|
1486 | else {
|
---|
1487 | xw = window->window;
|
---|
1488 | }
|
---|
1489 |
|
---|
1490 | XGetGeometry(window->visual->dpy, xw, &root,
|
---|
1491 | x, y, &width, &height, &bw, &d);
|
---|
1492 |
|
---|
1493 | /* translate x/y to screen coords */
|
---|
1494 | if (!XTranslateCoordinates(window->visual->dpy, xw, root,
|
---|
1495 | 0, 0, &rx, &ry, &child)) {
|
---|
1496 | rx = ry = 0;
|
---|
1497 | }
|
---|
1498 | *x = rx;
|
---|
1499 | *y = ry;
|
---|
1500 | *w = (int) width;
|
---|
1501 | *h = (int) height;
|
---|
1502 | }
|
---|
1503 | }
|
---|
1504 |
|
---|
1505 |
|
---|
1506 | void
|
---|
1507 | renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h )
|
---|
1508 | {
|
---|
1509 | int scrn;
|
---|
1510 | #ifdef USE_OSMESA
|
---|
1511 | if (render_spu.use_osmesa) {
|
---|
1512 | *w = 2048;
|
---|
1513 | *h = 2048;
|
---|
1514 | return;
|
---|
1515 | }
|
---|
1516 | #endif
|
---|
1517 |
|
---|
1518 | CRASSERT(window);
|
---|
1519 | CRASSERT(window->visual);
|
---|
1520 | CRASSERT(window->window);
|
---|
1521 |
|
---|
1522 | scrn = DefaultScreen(window->visual->dpy);
|
---|
1523 | *w = DisplayWidth(window->visual->dpy, scrn);
|
---|
1524 | *h = DisplayHeight(window->visual->dpy, scrn);
|
---|
1525 | }
|
---|
1526 |
|
---|
1527 |
|
---|
1528 | void
|
---|
1529 | renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y )
|
---|
1530 | {
|
---|
1531 | #ifdef USE_OSMESA
|
---|
1532 | if (render_spu.use_osmesa)
|
---|
1533 | return;
|
---|
1534 | #endif
|
---|
1535 |
|
---|
1536 | CRASSERT(window);
|
---|
1537 | CRASSERT(window->visual);
|
---|
1538 | if ((window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
|
---|
1539 | {
|
---|
1540 | crDebug("Render SPU: XMoveWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, x, y);
|
---|
1541 | XMoveWindow(window->visual->dpy, window->window, x, y);
|
---|
1542 | XSync(window->visual->dpy, 0);
|
---|
1543 | }
|
---|
1544 | }
|
---|
1545 |
|
---|
1546 | void
|
---|
1547 | renderspu_SystemWindowVisibleRegion( WindowInfo *window, GLint cRects, GLint *pRects )
|
---|
1548 | {
|
---|
1549 | #ifdef USE_OSMESA
|
---|
1550 | if (render_spu.use_osmesa)
|
---|
1551 | return;
|
---|
1552 | #endif
|
---|
1553 |
|
---|
1554 | CRASSERT(window);
|
---|
1555 | CRASSERT(window->visual);
|
---|
1556 | if ((window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
|
---|
1557 | {
|
---|
1558 | int evb, erb, i;
|
---|
1559 | XRectangle *pXRects;
|
---|
1560 |
|
---|
1561 | if (!XShapeQueryExtension(window->visual->dpy, &evb, &erb))
|
---|
1562 | {
|
---|
1563 | crWarning("Render SPU: Display %s doesn't support SHAPE extension", window->visual->displayName);
|
---|
1564 | return;
|
---|
1565 | }
|
---|
1566 |
|
---|
1567 | if (cRects>0)
|
---|
1568 | {
|
---|
1569 | pXRects = (XRectangle *) crAlloc(cRects * sizeof(XRectangle));
|
---|
1570 |
|
---|
1571 | for (i=0; i<cRects; ++i)
|
---|
1572 | {
|
---|
1573 | pXRects[i].x = (short) pRects[4*i];
|
---|
1574 | pXRects[i].y = (short) pRects[4*i+1];
|
---|
1575 | pXRects[i].width = (unsigned short) (pRects[4*i+2]-pRects[4*i]);
|
---|
1576 | pXRects[i].height = (unsigned short) (pRects[4*i+3]-pRects[4*i+1]);
|
---|
1577 | }
|
---|
1578 | }
|
---|
1579 | else
|
---|
1580 | {
|
---|
1581 | pXRects = (XRectangle *) crAlloc(sizeof(XRectangle));
|
---|
1582 | pXRects[0].x = 0;
|
---|
1583 | pXRects[0].y = 0;
|
---|
1584 | pXRects[0].width = 0;
|
---|
1585 | pXRects[0].height = 0;
|
---|
1586 | cRects = 1;
|
---|
1587 | }
|
---|
1588 |
|
---|
1589 | crDebug("Render SPU: XShapeCombineRectangles (%x, %x, cRects=%i)", window->visual->dpy, window->window, cRects);
|
---|
1590 |
|
---|
1591 | XShapeCombineRectangles(window->visual->dpy, window->window, ShapeBounding, 0, 0,
|
---|
1592 | pXRects, cRects, ShapeSet, YXBanded);
|
---|
1593 | XSync(window->visual->dpy, 0);
|
---|
1594 | crFree(pXRects);
|
---|
1595 | }
|
---|
1596 | }
|
---|
1597 |
|
---|
1598 | /* Either show or hide the render SPU's window. */
|
---|
1599 | void
|
---|
1600 | renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt )
|
---|
1601 | {
|
---|
1602 | #ifdef USE_OSMESA
|
---|
1603 | if (render_spu.use_osmesa)
|
---|
1604 | return;
|
---|
1605 | #endif
|
---|
1606 |
|
---|
1607 | if (window->visual->dpy && window->window &&
|
---|
1608 | (window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
|
---|
1609 | {
|
---|
1610 | if (showIt)
|
---|
1611 | {
|
---|
1612 | XMapWindow( window->visual->dpy, window->window );
|
---|
1613 | XSync(window->visual->dpy, 0);
|
---|
1614 | }
|
---|
1615 | else
|
---|
1616 | {
|
---|
1617 | XUnmapWindow( window->visual->dpy, window->window );
|
---|
1618 | XSync(window->visual->dpy, 0);
|
---|
1619 | }
|
---|
1620 | window->visible = showIt;
|
---|
1621 | }
|
---|
1622 | }
|
---|
1623 |
|
---|
1624 |
|
---|
1625 | static void
|
---|
1626 | MarkWindow(WindowInfo *w)
|
---|
1627 | {
|
---|
1628 | static GC gc = 0; /* XXX per-window??? */
|
---|
1629 | if (!gc) {
|
---|
1630 | /* Create a GC for drawing invisible lines */
|
---|
1631 | XGCValues gcValues;
|
---|
1632 | gcValues.function = GXnoop;
|
---|
1633 | gc = XCreateGC(w->visual->dpy, w->nativeWindow, GCFunction, &gcValues);
|
---|
1634 | }
|
---|
1635 | XDrawLine(w->visual->dpy, w->nativeWindow, gc, 0, 0, w->width, w->height);
|
---|
1636 | }
|
---|
1637 |
|
---|
1638 |
|
---|
1639 | void
|
---|
1640 | renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags )
|
---|
1641 | {
|
---|
1642 | CRASSERT(w);
|
---|
1643 |
|
---|
1644 | #if 00 /*TEMPORARY - FOR TESTING SWAP LOCK*/
|
---|
1645 | if (1) {
|
---|
1646 | /* random delay */
|
---|
1647 | int k = crRandInt(1000 * 100, 750*1000);
|
---|
1648 | static int first = 1;
|
---|
1649 | if (first) {
|
---|
1650 | crRandAutoSeed();
|
---|
1651 | first = 0;
|
---|
1652 | }
|
---|
1653 | usleep(k);
|
---|
1654 | }
|
---|
1655 | #endif
|
---|
1656 |
|
---|
1657 | /* render_to_app_window:
|
---|
1658 | * w->nativeWindow will only be non-zero if the
|
---|
1659 | * render_spu.render_to_app_window option is true and
|
---|
1660 | * MakeCurrent() recorded the nativeWindow handle in the WindowInfo
|
---|
1661 | * structure.
|
---|
1662 | */
|
---|
1663 | if (w->nativeWindow) {
|
---|
1664 | render_spu.ws.glXSwapBuffers( w->visual->dpy, w->nativeWindow );
|
---|
1665 | #if 0
|
---|
1666 | MarkWindow(w);
|
---|
1667 | #else
|
---|
1668 | (void) MarkWindow;
|
---|
1669 | #endif
|
---|
1670 | }
|
---|
1671 | else {
|
---|
1672 | render_spu.ws.glXSwapBuffers( w->visual->dpy, w->window );
|
---|
1673 | }
|
---|
1674 | }
|
---|