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