VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c@ 20175

Last change on this file since 20175 was 16142, checked in by vboxsync, 16 years ago

crOpenGL: don't crash if there's no x display, (public 3089)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 51.9 KB
Line 
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 */
31typedef 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
46static Bool WindowExistsFlag;
47
48static int
49WindowExistsErrorHandler( Display *dpy, XErrorEvent *xerr )
50{
51 if (xerr->error_code == BadWindow)
52 {
53 WindowExistsFlag = GL_FALSE;
54 }
55 return 0;
56}
57
58static GLboolean
59WindowExists( 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
71static GLboolean
72renderDestroyWindow( 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 */
94void
95renderspu_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
113static Colormap
114GetLUTColormap( 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
164static Colormap
165GetShareableColormap( 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
212static int
213WaitForMapNotify( 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 */
223static int
224GetWindowVisualID( 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 */
237static int
238Attrib( 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 */
251static XVisualInfo *
252chooseVisualRetry( 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
281static GLXFBConfig
282chooseFBConfig( 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
405GLboolean
406renderspu_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 */
532static void
533JoinSwapGroup(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
591static GLboolean
592createWindow( 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
855static GLboolean
856createPBuffer( 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
895GLboolean
896renderspu_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
908GLboolean
909renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
910{
911 return renderspu_SystemCreateWindow(visual, showIt, window);
912}
913
914void
915renderspu_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
951GLboolean
952renderspu_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 */
1025struct 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
1037static struct saved_state SavedState;
1038
1039static void
1040get_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
1056static void
1057set_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 */
1093static void
1094renderspu_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
1130void
1131renderspu_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
1152static void
1153check_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
1172void
1173renderspu_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 */
1358void
1359renderspu_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
1454void
1455renderspu_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
1506void
1507renderspu_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
1528void
1529renderspu_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
1546void
1547renderspu_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. */
1599void
1600renderspu_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
1625static void
1626MarkWindow(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
1639void
1640renderspu_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}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette