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 | */
|
---|
24 | typedef 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 |
|
---|
39 | static Bool WindowExistsFlag;
|
---|
40 |
|
---|
41 | static int
|
---|
42 | WindowExistsErrorHandler( Display *dpy, XErrorEvent *xerr )
|
---|
43 | {
|
---|
44 | if (xerr->error_code == BadWindow)
|
---|
45 | {
|
---|
46 | WindowExistsFlag = GL_FALSE;
|
---|
47 | }
|
---|
48 | return 0;
|
---|
49 | }
|
---|
50 |
|
---|
51 | static GLboolean
|
---|
52 | WindowExists( 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 |
|
---|
64 | static Colormap
|
---|
65 | GetLUTColormap( 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 |
|
---|
115 | static Colormap
|
---|
116 | GetShareableColormap( 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 |
|
---|
163 | static int
|
---|
164 | WaitForMapNotify( 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 | */
|
---|
174 | static int
|
---|
175 | GetWindowVisualID( 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 | */
|
---|
188 | static int
|
---|
189 | Attrib( 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 | */
|
---|
202 | static XVisualInfo *
|
---|
203 | chooseVisualRetry( 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
|
---|
232 | static GLXFBConfig
|
---|
233 | chooseFBConfig( 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 |
|
---|
355 | static 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 |
|
---|
369 | static int renderspuWinCmdWinCreate(WindowInfo *pWindow)
|
---|
370 | {
|
---|
371 | return VERR_NOT_IMPLEMENTED;
|
---|
372 | }
|
---|
373 |
|
---|
374 | static int renderspuWinCmdWinDestroy(WindowInfo *pWindow)
|
---|
375 | {
|
---|
376 | return VERR_NOT_IMPLEMENTED;
|
---|
377 | }
|
---|
378 |
|
---|
379 | static 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 |
|
---|
433 | static 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 |
|
---|
444 | static 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 |
|
---|
484 | static 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 |
|
---|
550 | static 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 |
|
---|
587 | int 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 |
|
---|
650 | int 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 |
|
---|
664 | GLboolean
|
---|
665 | renderspu_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 | */
|
---|
778 | static void
|
---|
779 | JoinSwapGroup(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 |
|
---|
837 | static GLboolean
|
---|
838 | createWindow( 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 |
|
---|
1086 | static GLboolean
|
---|
1087 | createPBuffer( 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 |
|
---|
1126 | GLboolean
|
---|
1127 | renderspu_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 |
|
---|
1139 | GLboolean
|
---|
1140 | renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
|
---|
1141 | {
|
---|
1142 | return renderspu_SystemCreateWindow(visual, showIt, window);
|
---|
1143 | }
|
---|
1144 |
|
---|
1145 | void
|
---|
1146 | renderspu_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 |
|
---|
1177 | GLboolean
|
---|
1178 | renderspu_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 | */
|
---|
1239 | struct 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 |
|
---|
1251 | static struct saved_state SavedState;
|
---|
1252 |
|
---|
1253 | static void
|
---|
1254 | get_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 |
|
---|
1270 | static void
|
---|
1271 | set_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 | */
|
---|
1307 | static void
|
---|
1308 | renderspu_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 |
|
---|
1344 | void
|
---|
1345 | renderspu_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 |
|
---|
1356 | void
|
---|
1357 | renderspu_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 | */
|
---|
1542 | void
|
---|
1543 | renderspu_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 |
|
---|
1640 | void
|
---|
1641 | renderspu_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 |
|
---|
1684 | void
|
---|
1685 | renderspu_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 |
|
---|
1699 | void
|
---|
1700 | renderspu_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 |
|
---|
1712 | GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window)
|
---|
1713 | {
|
---|
1714 | return GL_FALSE;
|
---|
1715 | }
|
---|
1716 |
|
---|
1717 | void
|
---|
1718 | renderspu_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. */
|
---|
1765 | void
|
---|
1766 | renderspu_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 |
|
---|
1787 | void 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 |
|
---|
1832 | static void
|
---|
1833 | MarkWindow(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 |
|
---|
1846 | void
|
---|
1847 | renderspu_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 |
|
---|
1870 | void 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 |
|
---|
1881 | void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
|
---|
1882 | {
|
---|
1883 |
|
---|
1884 | }
|
---|
1885 |
|
---|
1886 | uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable)
|
---|
1887 | {
|
---|
1888 | return cFunctions;
|
---|
1889 | }
|
---|