VirtualBox

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

Last change on this file since 78425 was 78341, checked in by vboxsync, 6 years ago

Config.kmk,Additions/common/crOpenGL,VBox/GuestHost/OpenGL,HostServices/SharedOpenGL: Remove CHROMIUM_THREADSAFE define and apply the current default

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