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