VirtualBox

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

Last change on this file since 44768 was 44768, checked in by vboxsync, 12 years ago

burn fix

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