VirtualBox

source: vbox/trunk/src/VBox/Additions/common/crOpenGL/load.c@ 39012

Last change on this file since 39012 was 38864, checked in by vboxsync, 14 years ago

crOpenGL: fix compiz under ubuntu9.10

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 35.5 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "cr_spu.h"
8#include "cr_net.h"
9#include "cr_error.h"
10#include "cr_mem.h"
11#include "cr_string.h"
12#include "cr_net.h"
13#include "cr_environment.h"
14#include "cr_process.h"
15#include "cr_rand.h"
16#include "cr_netserver.h"
17#include "stub.h"
18#include <stdlib.h>
19#include <string.h>
20#include <signal.h>
21#include <iprt/initterm.h>
22#include <iprt/thread.h>
23#include <iprt/err.h>
24#include <iprt/asm.h>
25#ifndef WINDOWS
26# include <sys/types.h>
27# include <unistd.h>
28#endif
29#ifdef CHROMIUM_THREADSAFE
30#include "cr_threads.h"
31#endif
32
33#ifdef VBOX_WITH_WDDM
34#include <d3d9types.h>
35#include <D3dumddi.h>
36#include "../../WINNT/Graphics/Video/common/wddm/VBoxMPIf.h"
37#include "../../WINNT/Graphics/Video/disp/wddm/VBoxDispMp.h"
38#endif
39
40/**
41 * If you change this, see the comments in tilesortspu_context.c
42 */
43#define MAGIC_CONTEXT_BASE 500
44
45#define CONFIG_LOOKUP_FILE ".crconfigs"
46
47#ifdef WINDOWS
48#define PYTHON_EXE "python.exe"
49#else
50#define PYTHON_EXE "python"
51#endif
52
53#ifdef WINDOWS
54static char* gsViewportHackApps[] = {"googleearth.exe", NULL};
55#endif
56
57static int stub_initialized = 0;
58
59/* NOTE: 'SPUDispatchTable glim' is declared in NULLfuncs.py now */
60/* NOTE: 'SPUDispatchTable stubThreadsafeDispatch' is declared in tsfuncs.c */
61Stub stub;
62
63
64static void stubInitNativeDispatch( void )
65{
66#define MAX_FUNCS 1000
67 SPUNamedFunctionTable gl_funcs[MAX_FUNCS];
68 int numFuncs;
69
70 numFuncs = crLoadOpenGL( &stub.wsInterface, gl_funcs );
71
72 stub.haveNativeOpenGL = (numFuncs > 0);
73
74 /* XXX call this after context binding */
75 numFuncs += crLoadOpenGLExtensions( &stub.wsInterface, gl_funcs + numFuncs );
76
77 CRASSERT(numFuncs < MAX_FUNCS);
78
79 crSPUInitDispatchTable( &stub.nativeDispatch );
80 crSPUInitDispatch( &stub.nativeDispatch, gl_funcs );
81 crSPUInitDispatchNops( &stub.nativeDispatch );
82#undef MAX_FUNCS
83}
84
85
86/** Pointer to the SPU's real glClear and glViewport functions */
87static ClearFunc_t origClear;
88static ViewportFunc_t origViewport;
89static SwapBuffersFunc_t origSwapBuffers;
90static DrawBufferFunc_t origDrawBuffer;
91static ScissorFunc_t origScissor;
92
93static void stubCheckWindowState(WindowInfo *window, GLboolean bFlushOnChange)
94{
95 bool bForceUpdate = false;
96 bool bChanged = false;
97
98#ifdef WINDOWS
99 /* @todo install hook and track for WM_DISPLAYCHANGE */
100 {
101 DEVMODE devMode;
102
103 devMode.dmSize = sizeof(DEVMODE);
104 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode);
105
106 if (devMode.dmPelsWidth!=window->dmPelsWidth || devMode.dmPelsHeight!=window->dmPelsHeight)
107 {
108 crDebug("Resolution changed(%d,%d), forcing window Pos/Size update", devMode.dmPelsWidth, devMode.dmPelsHeight);
109 window->dmPelsWidth = devMode.dmPelsWidth;
110 window->dmPelsHeight = devMode.dmPelsHeight;
111 bForceUpdate = true;
112 }
113 }
114#endif
115
116 bChanged = stubUpdateWindowGeometry(window, bForceUpdate) || bForceUpdate;
117
118#if defined(GLX) || defined (WINDOWS)
119 if (stub.trackWindowVisibleRgn)
120 {
121 bChanged = stubUpdateWindowVisibileRegions(window) || bChanged;
122 }
123#endif
124
125 if (stub.trackWindowVisibility && window->type == CHROMIUM && window->drawable) {
126 const int mapped = stubIsWindowVisible(window);
127 if (mapped != window->mapped) {
128 crDebug("Dispatched: WindowShow(%i, %i)", window->spuWindow, mapped);
129 stub.spu->dispatch_table.WindowShow(window->spuWindow, mapped);
130 window->mapped = mapped;
131 bChanged = true;
132 }
133 }
134
135 if (bFlushOnChange && bChanged)
136 {
137 stub.spu->dispatch_table.Flush();
138 }
139}
140
141static bool stubSystemWindowExist(WindowInfo *pWindow)
142{
143#ifdef WINDOWS
144 if (pWindow->hWnd!=WindowFromDC(pWindow->drawable))
145 {
146 return false;
147 }
148#else
149 Window root;
150 int x, y;
151 unsigned int border, depth, w, h;
152 Display *dpy;
153
154 dpy = stubGetWindowDisplay(pWindow);
155
156 XLOCK(dpy);
157 if (!XGetGeometry(dpy, pWindow->drawable, &root, &x, &y, &w, &h, &border, &depth))
158 {
159 XUNLOCK(dpy);
160 return false;
161 }
162 XUNLOCK(dpy);
163#endif
164
165 return true;
166}
167
168static void stubCheckWindowsCB(unsigned long key, void *data1, void *data2)
169{
170 WindowInfo *pWindow = (WindowInfo *) data1;
171 ContextInfo *pCtx = (ContextInfo *) data2;
172
173 if (pWindow == pCtx->currentDrawable
174 || pWindow->type!=CHROMIUM
175 || pWindow->pOwner!=pCtx)
176 {
177 return;
178 }
179
180 if (!stubSystemWindowExist(pWindow))
181 {
182#ifdef WINDOWS
183 crWindowDestroy((GLint)pWindow->hWnd);
184#else
185 crWindowDestroy((GLint)pWindow->drawable);
186#endif
187 return;
188 }
189
190 stubCheckWindowState(pWindow, GL_FALSE);
191}
192
193static void stubCheckWindowsState(void)
194{
195 CRASSERT(stub.trackWindowSize || stub.trackWindowPos);
196
197 if (!stub.currentContext)
198 return;
199
200#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
201 if (stub.bRunningUnderWDDM)
202 return;
203#endif
204
205#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
206 crLockMutex(&stub.mutex);
207#endif
208
209 stubCheckWindowState(stub.currentContext->currentDrawable, GL_TRUE);
210 crHashtableWalk(stub.windowTable, stubCheckWindowsCB, stub.currentContext);
211
212#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
213 crUnlockMutex(&stub.mutex);
214#endif
215}
216
217
218/**
219 * Override the head SPU's glClear function.
220 * We're basically trapping this function so that we can poll the
221 * application window size at a regular interval.
222 */
223static void SPU_APIENTRY trapClear(GLbitfield mask)
224{
225 stubCheckWindowsState();
226 /* call the original SPU glClear function */
227 origClear(mask);
228}
229
230/**
231 * As above, but for glViewport. Most apps call glViewport before
232 * glClear when a window is resized.
233 */
234static void SPU_APIENTRY trapViewport(GLint x, GLint y, GLsizei w, GLsizei h)
235{
236 stubCheckWindowsState();
237 /* call the original SPU glViewport function */
238 if (!stub.viewportHack)
239 {
240 origViewport(x, y, w, h);
241 }
242 else
243 {
244 int winX, winY;
245 unsigned int winW, winH;
246 WindowInfo *pWindow;
247 pWindow = stub.currentContext->currentDrawable;
248 stubGetWindowGeometry(pWindow, &winX, &winY, &winW, &winH);
249 origViewport(0, 0, winW, winH);
250 }
251}
252
253static void SPU_APIENTRY trapSwapBuffers(GLint window, GLint flags)
254{
255 stubCheckWindowsState();
256 origSwapBuffers(window, flags);
257}
258
259static void SPU_APIENTRY trapDrawBuffer(GLenum buf)
260{
261 stubCheckWindowsState();
262 origDrawBuffer(buf);
263}
264
265static void SPU_APIENTRY trapScissor(GLint x, GLint y, GLsizei w, GLsizei h)
266{
267 int winX, winY;
268 unsigned int winW, winH;
269 WindowInfo *pWindow;
270 pWindow = stub.currentContext->currentDrawable;
271 stubGetWindowGeometry(pWindow, &winX, &winY, &winW, &winH);
272 origScissor(0, 0, winW, winH);
273}
274
275/**
276 * Use the GL function pointers in <spu> to initialize the static glim
277 * dispatch table.
278 */
279static void stubInitSPUDispatch(SPU *spu)
280{
281 crSPUInitDispatchTable( &stub.spuDispatch );
282 crSPUCopyDispatchTable( &stub.spuDispatch, &(spu->dispatch_table) );
283
284 if (stub.trackWindowSize || stub.trackWindowPos || stub.trackWindowVisibleRgn) {
285 /* patch-in special glClear/Viewport function to track window sizing */
286 origClear = stub.spuDispatch.Clear;
287 origViewport = stub.spuDispatch.Viewport;
288 origSwapBuffers = stub.spuDispatch.SwapBuffers;
289 origDrawBuffer = stub.spuDispatch.DrawBuffer;
290 origScissor = stub.spuDispatch.Scissor;
291 stub.spuDispatch.Clear = trapClear;
292 stub.spuDispatch.Viewport = trapViewport;
293
294 if (stub.viewportHack)
295 stub.spuDispatch.Scissor = trapScissor;
296 /*stub.spuDispatch.SwapBuffers = trapSwapBuffers;
297 stub.spuDispatch.DrawBuffer = trapDrawBuffer;*/
298 }
299
300 crSPUCopyDispatchTable( &glim, &stub.spuDispatch );
301}
302
303// Callback function, used to destroy all created contexts
304static void hsWalkStubDestroyContexts(unsigned long key, void *data1, void *data2)
305{
306 stubDestroyContext(key);
307}
308
309/**
310 * This is called when we exit.
311 * We call all the SPU's cleanup functions.
312 */
313static void stubSPUTearDown(void)
314{
315 crDebug("stubSPUTearDown");
316 if (!stub_initialized) return;
317
318 stub_initialized = 0;
319
320#ifdef WINDOWS
321# ifndef CR_NEWWINTRACK
322 stubUninstallWindowMessageHook();
323# endif
324#endif
325
326#ifdef CR_NEWWINTRACK
327 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
328#endif
329
330 //delete all created contexts
331 stubMakeCurrent( NULL, NULL);
332 crHashtableWalk(stub.contextTable, hsWalkStubDestroyContexts, NULL);
333
334 /* shutdown, now trap any calls to a NULL dispatcher */
335 crSPUCopyDispatchTable(&glim, &stubNULLDispatch);
336
337 crSPUUnloadChain(stub.spu);
338 stub.spu = NULL;
339
340#ifndef Linux
341 crUnloadOpenGL();
342#endif
343
344#ifndef WINDOWS
345 crNetTearDown();
346#endif
347
348#ifdef GLX
349 if (stub.xshmSI.shmid>=0)
350 {
351 shmctl(stub.xshmSI.shmid, IPC_RMID, 0);
352 shmdt(stub.xshmSI.shmaddr);
353 }
354 crFreeHashtable(stub.pGLXPixmapsHash, crFree);
355#endif
356
357 crFreeHashtable(stub.windowTable, crFree);
358 crFreeHashtable(stub.contextTable, NULL);
359
360 crMemset(&stub, 0, sizeof(stub));
361}
362
363static void stubSPUSafeTearDown(void)
364{
365#ifdef CHROMIUM_THREADSAFE
366 CRmutex *mutex;
367#endif
368
369 if (!stub_initialized) return;
370 stub_initialized = 0;
371
372#ifdef CHROMIUM_THREADSAFE
373 mutex = &stub.mutex;
374 crLockMutex(mutex);
375#endif
376 crDebug("stubSPUSafeTearDown");
377
378#ifdef WINDOWS
379# ifndef CR_NEWWINTRACK
380 stubUninstallWindowMessageHook();
381# endif
382#endif
383
384#if defined(CR_NEWWINTRACK)
385 crUnlockMutex(mutex);
386# if defined(WINDOWS)
387 if (RTThreadGetState(stub.hSyncThread)!=RTTHREADSTATE_TERMINATED)
388 {
389 HANDLE hNative;
390 DWORD ec=0;
391
392 hNative = OpenThread(SYNCHRONIZE|THREAD_QUERY_INFORMATION|THREAD_TERMINATE,
393 false, RTThreadGetNative(stub.hSyncThread));
394 if (!hNative)
395 {
396 crWarning("Failed to get handle for sync thread(%#x)", GetLastError());
397 }
398 else
399 {
400 crDebug("Got handle %p for thread %#x", hNative, RTThreadGetNative(stub.hSyncThread));
401 }
402
403 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
404
405 if (PostThreadMessage(RTThreadGetNative(stub.hSyncThread), WM_QUIT, 0, 0))
406 {
407 RTThreadWait(stub.hSyncThread, 1000, NULL);
408
409 /*Same issue as on linux, RTThreadWait exits before system thread is terminated, which leads
410 * to issues as our dll goes to be unloaded.
411 *@todo
412 *We usually call this function from DllMain which seems to be holding some lock and thus we have to
413 * kill thread via TerminateThread.
414 */
415 if (WaitForSingleObject(hNative, 100)==WAIT_TIMEOUT)
416 {
417 crDebug("Wait failed, terminating");
418 if (!TerminateThread(hNative, 1))
419 {
420 crDebug("TerminateThread failed");
421 }
422 }
423 if (GetExitCodeThread(hNative, &ec))
424 {
425 crDebug("Thread %p exited with ec=%i", hNative, ec);
426 }
427 else
428 {
429 crDebug("GetExitCodeThread failed(%#x)", GetLastError());
430 }
431 }
432 else
433 {
434 crDebug("Sync thread killed before DLL_PROCESS_DETACH");
435 }
436
437 if (hNative)
438 {
439 CloseHandle(hNative);
440 }
441 }
442#else
443 if (stub.hSyncThread!=NIL_RTTHREAD)
444 {
445 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
446 {
447 /*RTThreadWait might return too early, which cause our code being unloaded while RT thread wrapper is still running*/
448 int rc = pthread_join(RTThreadGetNative(stub.hSyncThread), NULL);
449 if (!rc)
450 {
451 crDebug("pthread_join failed %i", rc);
452 }
453 }
454 }
455#endif
456 crLockMutex(mutex);
457#endif
458
459#ifndef WINDOWS
460 crNetTearDown();
461#endif
462
463#ifdef CHROMIUM_THREADSAFE
464 crUnlockMutex(mutex);
465 crFreeMutex(mutex);
466#endif
467 crMemset(&stub, 0, sizeof(stub));
468}
469
470
471static void stubExitHandler(void)
472{
473 stubSPUSafeTearDown();
474}
475
476/**
477 * Called when we receive a SIGTERM signal.
478 */
479static void stubSignalHandler(int signo)
480{
481 stubSPUSafeTearDown();
482 exit(0); /* this causes stubExitHandler() to be called */
483}
484
485
486/**
487 * Init variables in the stub structure, install signal handler.
488 */
489static void stubInitVars(void)
490{
491 WindowInfo *defaultWin;
492
493#ifdef CHROMIUM_THREADSAFE
494 crInitMutex(&stub.mutex);
495#endif
496
497 /* At the very least we want CR_RGB_BIT. */
498 stub.haveNativeOpenGL = GL_FALSE;
499 stub.spu = NULL;
500 stub.appDrawCursor = 0;
501 stub.minChromiumWindowWidth = 0;
502 stub.minChromiumWindowHeight = 0;
503 stub.maxChromiumWindowWidth = 0;
504 stub.maxChromiumWindowHeight = 0;
505 stub.matchChromiumWindowCount = 0;
506 stub.matchChromiumWindowID = NULL;
507 stub.matchWindowTitle = NULL;
508 stub.ignoreFreeglutMenus = 0;
509 stub.threadSafe = GL_FALSE;
510 stub.trackWindowSize = 0;
511 stub.trackWindowPos = 0;
512 stub.trackWindowVisibility = 0;
513 stub.trackWindowVisibleRgn = 0;
514 stub.mothershipPID = 0;
515 stub.spu_dir = NULL;
516
517 stub.freeContextNumber = MAGIC_CONTEXT_BASE;
518 stub.contextTable = crAllocHashtable();
519 stub.currentContext = NULL;
520
521 stub.windowTable = crAllocHashtable();
522
523#ifdef CR_NEWWINTRACK
524 stub.bShutdownSyncThread = false;
525 stub.hSyncThread = NIL_RTTHREAD;
526#endif
527
528 defaultWin = (WindowInfo *) crCalloc(sizeof(WindowInfo));
529 defaultWin->type = CHROMIUM;
530 defaultWin->spuWindow = 0; /* window 0 always exists */
531#ifdef WINDOWS
532 defaultWin->hVisibleRegion = INVALID_HANDLE_VALUE;
533#elif defined(GLX)
534 defaultWin->pVisibleRegions = NULL;
535 defaultWin->cVisibleRegions = 0;
536#endif
537 crHashtableAdd(stub.windowTable, 0, defaultWin);
538
539#if 1
540 atexit(stubExitHandler);
541 signal(SIGTERM, stubSignalHandler);
542 signal(SIGINT, stubSignalHandler);
543#ifndef WINDOWS
544 signal(SIGPIPE, SIG_IGN); /* the networking code should catch this */
545#endif
546#else
547 (void) stubExitHandler;
548 (void) stubSignalHandler;
549#endif
550}
551
552
553/**
554 * Return a free port number for the mothership to use, or -1 if we
555 * can't find one.
556 */
557static int
558GenerateMothershipPort(void)
559{
560 const int MAX_PORT = 10100;
561 unsigned short port;
562
563 /* generate initial port number randomly */
564 crRandAutoSeed();
565 port = (unsigned short) crRandInt(10001, MAX_PORT);
566
567#ifdef WINDOWS
568 /* XXX should implement a free port check here */
569 return port;
570#else
571 /*
572 * See if this port number really is free, try another if needed.
573 */
574 {
575 struct sockaddr_in servaddr;
576 int so_reuseaddr = 1;
577 int sock, k;
578
579 /* create socket */
580 sock = socket(AF_INET, SOCK_STREAM, 0);
581 CRASSERT(sock > 2);
582
583 /* deallocate socket/port when we exit */
584 k = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
585 (char *) &so_reuseaddr, sizeof(so_reuseaddr));
586 CRASSERT(k == 0);
587
588 /* initialize the servaddr struct */
589 crMemset(&servaddr, 0, sizeof(servaddr) );
590 servaddr.sin_family = AF_INET;
591 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
592
593 while (port < MAX_PORT) {
594 /* Bind to the given port number, return -1 if we fail */
595 servaddr.sin_port = htons((unsigned short) port);
596 k = bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
597 if (k) {
598 /* failed to create port. try next one. */
599 port++;
600 }
601 else {
602 /* free the socket/port now so mothership can make it */
603 close(sock);
604 return port;
605 }
606 }
607 }
608#endif /* WINDOWS */
609 return -1;
610}
611
612
613/**
614 * Try to determine which mothership configuration to use for this program.
615 */
616static char **
617LookupMothershipConfig(const char *procName)
618{
619 const int procNameLen = crStrlen(procName);
620 FILE *f;
621 const char *home;
622 char configPath[1000];
623
624 /* first, check if the CR_CONFIG env var is set */
625 {
626 const char *conf = crGetenv("CR_CONFIG");
627 if (conf && crStrlen(conf) > 0)
628 return crStrSplit(conf, " ");
629 }
630
631 /* second, look up config name from config file */
632 home = crGetenv("HOME");
633 if (home)
634 sprintf(configPath, "%s/%s", home, CONFIG_LOOKUP_FILE);
635 else
636 crStrcpy(configPath, CONFIG_LOOKUP_FILE); /* from current dir */
637 /* Check if the CR_CONFIG_PATH env var is set. */
638 {
639 const char *conf = crGetenv("CR_CONFIG_PATH");
640 if (conf)
641 crStrcpy(configPath, conf); /* from env var */
642 }
643
644 f = fopen(configPath, "r");
645 if (!f) {
646 return NULL;
647 }
648
649 while (!feof(f)) {
650 char line[1000];
651 char **args;
652 fgets(line, 999, f);
653 line[crStrlen(line) - 1] = 0; /* remove trailing newline */
654 if (crStrncmp(line, procName, procNameLen) == 0 &&
655 (line[procNameLen] == ' ' || line[procNameLen] == '\t'))
656 {
657 crWarning("Using Chromium configuration for %s from %s",
658 procName, configPath);
659 args = crStrSplit(line + procNameLen + 1, " ");
660 return args;
661 }
662 }
663 fclose(f);
664 return NULL;
665}
666
667
668static int Mothership_Awake = 0;
669
670
671/**
672 * Signal handler to determine when mothership is ready.
673 */
674static void
675MothershipPhoneHome(int signo)
676{
677 crDebug("Got signal %d: mothership is awake!", signo);
678 Mothership_Awake = 1;
679}
680
681void stubSetDefaultConfigurationOptions(void)
682{
683 unsigned char key[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
684
685 stub.appDrawCursor = 0;
686 stub.minChromiumWindowWidth = 0;
687 stub.minChromiumWindowHeight = 0;
688 stub.maxChromiumWindowWidth = 0;
689 stub.maxChromiumWindowHeight = 0;
690 stub.matchChromiumWindowID = NULL;
691 stub.numIgnoreWindowID = 0;
692 stub.matchWindowTitle = NULL;
693 stub.ignoreFreeglutMenus = 0;
694 stub.trackWindowSize = 1;
695 stub.trackWindowPos = 1;
696 stub.trackWindowVisibility = 1;
697 stub.trackWindowVisibleRgn = 1;
698 stub.matchChromiumWindowCount = 0;
699 stub.spu_dir = NULL;
700 crNetSetRank(0);
701 crNetSetContextRange(32, 35);
702 crNetSetNodeRange("iam0", "iamvis20");
703 crNetSetKey(key,sizeof(key));
704 stub.force_pbuffers = 0;
705 stub.viewportHack = 0;
706
707#ifdef WINDOWS
708 {
709 char name[1000];
710 int i;
711
712# ifdef VBOX_WITH_WDDM
713 stub.bRunningUnderWDDM = false;
714# endif
715 /* Apply viewport hack only if we're running under wine */
716 if (NULL!=GetModuleHandle("wined3d.dll") || NULL != GetModuleHandle("wined3dwddm.dll"))
717 {
718 crGetProcName(name, 1000);
719 for (i=0; gsViewportHackApps[i]; ++i)
720 {
721 if (!stricmp(name, gsViewportHackApps[i]))
722 {
723 stub.viewportHack = 1;
724 break;
725 }
726 }
727 }
728 }
729#endif
730}
731
732#ifdef CR_NEWWINTRACK
733# ifdef VBOX_WITH_WDDM
734static stubDispatchVisibleRegions(WindowInfo *pWindow)
735{
736 DWORD dwCount;
737 LPRGNDATA lpRgnData;
738
739 dwCount = GetRegionData(pWindow->hVisibleRegion, 0, NULL);
740 lpRgnData = crAlloc(dwCount);
741
742 if (lpRgnData)
743 {
744 GetRegionData(pWindow->hVisibleRegion, dwCount, lpRgnData);
745 crDebug("Dispatched WindowVisibleRegion (%i, cRects=%i)", pWindow->spuWindow, lpRgnData->rdh.nCount);
746 stub.spuDispatch.WindowVisibleRegion(pWindow->spuWindow, lpRgnData->rdh.nCount, (GLint*) lpRgnData->Buffer);
747 crFree(lpRgnData);
748 }
749 else crWarning("GetRegionData failed, VisibleRegions update failed");
750}
751
752static HRGN stubMakeRegionFromRects(PVBOXVIDEOCM_CMD_RECTS pRegions, uint32_t start)
753{
754 HRGN hRgn, hTmpRgn;
755 uint32_t i;
756
757 if (pRegions->RectsInfo.cRects<=start)
758 {
759 return INVALID_HANDLE_VALUE;
760 }
761
762 hRgn = CreateRectRgn(0, 0, 0, 0);
763 for (i=start; i<pRegions->RectsInfo.cRects; ++i)
764 {
765 hTmpRgn = CreateRectRgnIndirect(&pRegions->RectsInfo.aRects[i]);
766 CombineRgn(hRgn, hRgn, hTmpRgn, RGN_OR);
767 DeleteObject(hTmpRgn);
768 }
769 return hRgn;
770}
771
772typedef struct VBOXCR_UPDATEWNDCB
773{
774 VBOXDISPMP_REGIONS Regions;
775 bool fSendUpdateMsg;
776} VBOXCR_UPDATEWNDCB, *PVBOXCR_UPDATEWNDCB;
777
778static void stubSyncTrUpdateWindowCB(unsigned long key, void *data1, void *data2)
779{
780 WindowInfo *pWindow = (WindowInfo *) data1;
781 PVBOXCR_UPDATEWNDCB pCbData = (PVBOXCR_UPDATEWNDCB) data2;
782 VBOXDISPMP_REGIONS *pRegions = &pCbData->Regions;
783 bool bChanged = false;
784 HRGN hNewRgn = INVALID_HANDLE_VALUE;
785
786 if (pRegions->hWnd != pWindow->hWnd)
787 {
788 return;
789 }
790
791 stub.spu->dispatch_table.VBoxPackSetInjectID(pWindow->u32ClientID);
792
793 if (!stubSystemWindowExist(pWindow))
794 {
795 crWindowDestroy((GLint)pWindow->hWnd);
796 return;
797 }
798
799 if (!pWindow->mapped)
800 {
801 pWindow->mapped = GL_TRUE;
802 bChanged = true;
803 crDebug("Dispatched: WindowShow(%i, %i)", pWindow->spuWindow, pWindow->mapped);
804 stub.spu->dispatch_table.WindowShow(pWindow->spuWindow, pWindow->mapped);
805 }
806
807 if (pRegions->pRegions->fFlags.bSetVisibleRects || pRegions->pRegions->fFlags.bSetViewRect)
808 {
809 /* ensure data integrity */
810 Assert(!pRegions->pRegions->fFlags.bAddHiddenRects);
811
812 if (pRegions->pRegions->fFlags.bSetViewRect)
813 {
814 int winX, winY;
815 unsigned int winW, winH;
816 BOOL bRc;
817
818 winX = pRegions->pRegions->RectsInfo.aRects[0].left;
819 winY = pRegions->pRegions->RectsInfo.aRects[0].top;
820 winW = pRegions->pRegions->RectsInfo.aRects[0].right - winX;
821 winH = pRegions->pRegions->RectsInfo.aRects[0].bottom - winY;
822
823 if (stub.trackWindowPos && (winX!=pWindow->x || winY!=pWindow->y))
824 {
825 crDebug("Dispatched WindowPosition (%i)", pWindow->spuWindow);
826 stub.spuDispatch.WindowPosition(pWindow->spuWindow, winX, winY);
827 pWindow->x = winX;
828 pWindow->y = winY;
829 bChanged = true;
830 }
831
832 if (stub.trackWindowSize && (winW!=pWindow->width || winH!=pWindow->height))
833 {
834 crDebug("Dispatched WindowSize (%i)", pWindow->spuWindow);
835 stub.spuDispatch.WindowSize(pWindow->spuWindow, winW, winH);
836 pWindow->width = winW;
837 pWindow->height = winH;
838 bChanged = true;
839 }
840
841 bRc = MoveWindow(pRegions->hWnd, winX, winY, winW, winH, FALSE /*BOOL bRepaint*/);
842 if (!bRc)
843 {
844 DWORD winEr = GetLastError();
845 crWarning("stubSyncTrUpdateWindowCB: MoveWindow failed winEr(%d)", winEr);
846 }
847 }
848
849 if (pRegions->pRegions->fFlags.bSetVisibleRects)
850 {
851 hNewRgn = stubMakeRegionFromRects(pRegions->pRegions, pRegions->pRegions->fFlags.bSetViewRect ? 1 : 0);
852 }
853 }
854 else if (!pRegions->pRegions->fFlags.bHide)
855 {
856 Assert(pRegions->pRegions->fFlags.bAddHiddenRects);
857 hNewRgn = stubMakeRegionFromRects(pRegions->pRegions, 0);
858 }
859 else
860 {
861 Assert(pRegions->pRegions->fFlags.bAddHiddenRects);
862 hNewRgn = CreateRectRgn(pWindow->x, pWindow->y, pWindow->x + pWindow->width, pWindow->y + pWindow->height);
863 }
864
865 if (hNewRgn!=INVALID_HANDLE_VALUE)
866 {
867 if (pRegions->pRegions->fFlags.bSetVisibleRects)
868 {
869 HRGN hEmptyRgn = CreateRectRgn(0, 0, 0, 0);
870
871 if (hEmptyRgn!=INVALID_HANDLE_VALUE)
872 {
873 if (pWindow->hVisibleRegion==INVALID_HANDLE_VALUE || EqualRgn(pWindow->hVisibleRegion, hEmptyRgn))
874 {
875 pCbData->fSendUpdateMsg = true;
876 }
877
878 DeleteObject(hEmptyRgn);
879 }
880 else
881 {
882 crWarning("Failed to created empty region!");
883 }
884 }
885
886 OffsetRgn(hNewRgn, -pWindow->x, -pWindow->y);
887
888 if (pWindow->hVisibleRegion!=INVALID_HANDLE_VALUE)
889 {
890 CombineRgn(hNewRgn, pWindow->hVisibleRegion, hNewRgn,
891 pRegions->pRegions->fFlags.bAddHiddenRects ? RGN_DIFF:RGN_OR);
892
893 if (!EqualRgn(pWindow->hVisibleRegion, hNewRgn))
894 {
895 DeleteObject(pWindow->hVisibleRegion);
896 pWindow->hVisibleRegion = hNewRgn;
897 stubDispatchVisibleRegions(pWindow);
898 bChanged = true;
899 }
900 else
901 {
902 DeleteObject(hNewRgn);
903 }
904 }
905 else
906 {
907 if (pRegions->pRegions->fFlags.bSetVisibleRects)
908 {
909 pWindow->hVisibleRegion = hNewRgn;
910 stubDispatchVisibleRegions(pWindow);
911 bChanged = true;
912 }
913 }
914 }
915
916 if (bChanged)
917 {
918 stub.spu->dispatch_table.Flush();
919 }
920}
921# endif
922
923static void stubSyncTrCheckWindowsCB(unsigned long key, void *data1, void *data2)
924{
925 WindowInfo *pWindow = (WindowInfo *) data1;
926 (void) data2;
927
928 if (pWindow->type!=CHROMIUM || pWindow->spuWindow==0)
929 {
930 return;
931 }
932
933 stub.spu->dispatch_table.VBoxPackSetInjectID(pWindow->u32ClientID);
934
935 if (!stubSystemWindowExist(pWindow))
936 {
937#ifdef WINDOWS
938 crWindowDestroy((GLint)pWindow->hWnd);
939#else
940 crWindowDestroy((GLint)pWindow->drawable);
941#endif
942 /*No need to flush here as crWindowDestroy does it*/
943 return;
944 }
945
946#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
947 if (stub.bRunningUnderWDDM)
948 return;
949#endif
950 stubCheckWindowState(pWindow, GL_TRUE);
951}
952
953static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
954{
955#ifdef WINDOWS
956 MSG msg;
957# ifdef VBOX_WITH_WDDM
958 static VBOXDISPMP_CALLBACKS VBoxDispMpTstCallbacks = {NULL, NULL, NULL};
959 HMODULE hVBoxD3D = NULL;
960 VBOXCR_UPDATEWNDCB RegionsData;
961 HRESULT hr;
962# endif
963#endif
964
965 (void) pvUser;
966
967 crDebug("Sync thread started");
968#ifdef WINDOWS
969 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
970# ifdef VBOX_WITH_WDDM
971 hVBoxD3D = GetModuleHandle("VBoxDispD3D");
972 if (hVBoxD3D)
973 {
974 hVBoxD3D = LoadLibrary("VBoxDispD3D");
975 }
976
977 if (hVBoxD3D)
978 {
979 PFNVBOXDISPMP_GETCALLBACKS pfnVBoxDispMpGetCallbacks;
980 pfnVBoxDispMpGetCallbacks = (PFNVBOXDISPMP_GETCALLBACKS)GetProcAddress(hVBoxD3D, TEXT("VBoxDispMpGetCallbacks"));
981 if (pfnVBoxDispMpGetCallbacks)
982 {
983 hr = pfnVBoxDispMpGetCallbacks(VBOXDISPMP_VERSION, &VBoxDispMpTstCallbacks);
984 if (S_OK==hr)
985 {
986 CRASSERT(VBoxDispMpTstCallbacks.pfnEnableEvents);
987 CRASSERT(VBoxDispMpTstCallbacks.pfnDisableEvents);
988 CRASSERT(VBoxDispMpTstCallbacks.pfnGetRegions);
989
990 hr = VBoxDispMpTstCallbacks.pfnEnableEvents();
991 if (hr != S_OK)
992 {
993 crWarning("VBoxDispMpTstCallbacks.pfnEnableEvents failed");
994 }
995 else
996 {
997 crDebug("running with VBoxDispD3D");
998 stub.trackWindowVisibleRgn = 0;
999 stub.bRunningUnderWDDM = true;
1000 }
1001 }
1002 else
1003 {
1004 crWarning("VBoxDispMpGetCallbacks failed");
1005 }
1006 }
1007 }
1008# endif
1009#endif
1010
1011 crLockMutex(&stub.mutex);
1012 stub.spu->dispatch_table.VBoxPackSetInjectThread();
1013 crUnlockMutex(&stub.mutex);
1014
1015 RTThreadUserSignal(ThreadSelf);
1016
1017 while(!stub.bShutdownSyncThread)
1018 {
1019#ifdef WINDOWS
1020 if (!PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
1021 {
1022# ifdef VBOX_WITH_WDDM
1023 if (VBoxDispMpTstCallbacks.pfnGetRegions)
1024 {
1025 hr = VBoxDispMpTstCallbacks.pfnGetRegions(&RegionsData.Regions, 50);
1026 if (S_OK==hr)
1027 {
1028 RegionsData.fSendUpdateMsg = false;
1029# if 0
1030 uint32_t i;
1031 crDebug(">>>Regions for HWND(0x%x)>>>", RegionsData.Regions.hWnd);
1032 crDebug("Flags(0x%x)", RegionsData.Regions.pRegions->fFlags.Value);
1033 for (i = 0; i < RegionsData.Regions.pRegions->RectsInfo.cRects; ++i)
1034 {
1035 RECT *pRect = &RegionsData.Regions.pRegions->RectsInfo.aRects[i];
1036 crDebug("Rect(%d): left(%d), top(%d), right(%d), bottom(%d)", i, pRect->left, pRect->top, pRect->right, pRect->bottom);
1037 }
1038 crDebug("<<<<<");
1039# endif
1040 /*hacky way to make sure window wouldn't be deleted in another thread as we hold hashtable lock here*/
1041 crHashtableWalk(stub.windowTable, stubSyncTrUpdateWindowCB, &RegionsData);
1042 if (RegionsData.fSendUpdateMsg)
1043 {
1044 SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, SMTO_NORMAL, 1000, NULL);
1045 }
1046 }
1047 else
1048 {
1049 if (WAIT_TIMEOUT!=hr)
1050 {
1051 crWarning("VBoxDispMpTstCallbacks.pfnGetRegions failed with 0x%x", hr);
1052 }
1053 crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
1054 }
1055 }
1056 else
1057# endif
1058 {
1059 crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
1060 RTThreadSleep(50);
1061 }
1062 }
1063 else
1064 {
1065 if (WM_QUIT==msg.message)
1066 {
1067 crDebug("Sync thread got WM_QUIT");
1068 break;
1069 }
1070 else
1071 {
1072 TranslateMessage(&msg);
1073 DispatchMessage(&msg);
1074 }
1075 }
1076#else
1077 crLockMutex(&stub.mutex);
1078 crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
1079 crUnlockMutex(&stub.mutex);
1080 RTThreadSleep(50);
1081#endif
1082 }
1083
1084#ifdef VBOX_WITH_WDDM
1085 if (VBoxDispMpTstCallbacks.pfnDisableEvents)
1086 {
1087 VBoxDispMpTstCallbacks.pfnDisableEvents();
1088 }
1089 if (hVBoxD3D)
1090 {
1091 FreeLibrary(hVBoxD3D);
1092 }
1093#endif
1094 crDebug("Sync thread stopped");
1095 return 0;
1096}
1097#endif
1098
1099/**
1100 * Do one-time initializations for the faker.
1101 * Returns TRUE on success, FALSE otherwise.
1102 */
1103bool
1104stubInit(void)
1105{
1106 /* Here is where we contact the mothership to find out what we're supposed
1107 * to be doing. Networking code in a DLL initializer. I sure hope this
1108 * works :)
1109 *
1110 * HOW can I pass the mothership address to this if I already know it?
1111 */
1112
1113 CRConnection *conn = NULL;
1114 char response[1024];
1115 char **spuchain;
1116 int num_spus;
1117 int *spu_ids;
1118 char **spu_names;
1119 const char *app_id;
1120 int i;
1121 int disable_sync = 0;
1122
1123 if (stub_initialized)
1124 return true;
1125
1126 stubInitVars();
1127
1128 crGetProcName(response, 1024);
1129 crDebug("Stub launched for %s", response);
1130
1131#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
1132 /*@todo when vm boots with compiz turned on, new code causes hang in xcb_wait_for_reply in the sync thread
1133 * as at the start compiz runs our code under XGrabServer.
1134 */
1135 if (!crStrcmp(response, "compiz") || !crStrcmp(response, "compiz_real") || !crStrcmp(response, "compiz.real")
1136 || !crStrcmp(response, "compiz-bin"))
1137 {
1138 disable_sync = 1;
1139 }
1140#endif
1141
1142 /* @todo check if it'd be of any use on other than guests, no use for windows */
1143 app_id = crGetenv( "CR_APPLICATION_ID_NUMBER" );
1144
1145 crNetInit( NULL, NULL );
1146
1147#ifndef WINDOWS
1148 {
1149 CRNetServer ns;
1150
1151 ns.name = "vboxhgcm://host:0";
1152 ns.buffer_size = 1024;
1153 crNetServerConnect(&ns);
1154 if (!ns.conn)
1155 {
1156 crWarning("Failed to connect to host. Make sure 3D acceleration is enabled for this VM.");
1157 return false;
1158 }
1159 else
1160 {
1161 crNetFreeConnection(ns.conn);
1162 }
1163#if 0 && defined(CR_NEWWINTRACK)
1164 {
1165 Status st = XInitThreads();
1166 if (st==0)
1167 {
1168 crWarning("XInitThreads returned %i", (int)st);
1169 }
1170 }
1171#endif
1172 }
1173#endif
1174
1175 strcpy(response, "2 0 feedback 1 pack");
1176 spuchain = crStrSplit( response, " " );
1177 num_spus = crStrToInt( spuchain[0] );
1178 spu_ids = (int *) crAlloc( num_spus * sizeof( *spu_ids ) );
1179 spu_names = (char **) crAlloc( num_spus * sizeof( *spu_names ) );
1180 for (i = 0 ; i < num_spus ; i++)
1181 {
1182 spu_ids[i] = crStrToInt( spuchain[2*i+1] );
1183 spu_names[i] = crStrdup( spuchain[2*i+2] );
1184 crDebug( "SPU %d/%d: (%d) \"%s\"", i+1, num_spus, spu_ids[i], spu_names[i] );
1185 }
1186
1187 stubSetDefaultConfigurationOptions();
1188
1189 stub.spu = crSPULoadChain( num_spus, spu_ids, spu_names, stub.spu_dir, NULL );
1190
1191 crFree( spuchain );
1192 crFree( spu_ids );
1193 for (i = 0; i < num_spus; ++i)
1194 crFree(spu_names[i]);
1195 crFree( spu_names );
1196
1197 // spu chain load failed somewhere
1198 if (!stub.spu) {
1199 return false;
1200 }
1201
1202 crSPUInitDispatchTable( &glim );
1203
1204 /* This is unlikely to change -- We still want to initialize our dispatch
1205 * table with the functions of the first SPU in the chain. */
1206 stubInitSPUDispatch( stub.spu );
1207
1208 /* we need to plug one special stub function into the dispatch table */
1209 glim.GetChromiumParametervCR = stub_GetChromiumParametervCR;
1210
1211#if !defined(VBOX_NO_NATIVEGL)
1212 /* Load pointers to native OpenGL functions into stub.nativeDispatch */
1213 stubInitNativeDispatch();
1214#endif
1215
1216/*crDebug("stub init");
1217raise(SIGINT);*/
1218
1219#ifdef WINDOWS
1220# ifndef CR_NEWWINTRACK
1221 stubInstallWindowMessageHook();
1222# endif
1223#endif
1224
1225#ifdef CR_NEWWINTRACK
1226 {
1227 int rc;
1228
1229 RTR3InitDll(0);
1230
1231 if (!disable_sync)
1232 {
1233 crDebug("Starting sync thread");
1234
1235 rc = RTThreadCreate(&stub.hSyncThread, stubSyncThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Sync");
1236 if (RT_FAILURE(rc))
1237 {
1238 crError("Failed to start sync thread! (%x)", rc);
1239 }
1240 RTThreadUserWait(stub.hSyncThread, 60 * 1000);
1241 RTThreadUserReset(stub.hSyncThread);
1242
1243 crDebug("Going on");
1244 }
1245 }
1246#endif
1247
1248#ifdef GLX
1249 stub.xshmSI.shmid = -1;
1250 stub.bShmInitFailed = GL_FALSE;
1251 stub.pGLXPixmapsHash = crAllocHashtable();
1252
1253 stub.bXExtensionsChecked = GL_FALSE;
1254 stub.bHaveXComposite = GL_FALSE;
1255 stub.bHaveXFixes = GL_FALSE;
1256#endif
1257
1258 stub_initialized = 1;
1259 return true;
1260}
1261
1262/* Sigh -- we can't do initialization at load time, since Windows forbids
1263 * the loading of other libraries from DLLMain. */
1264
1265#ifdef LINUX
1266/* GCC crap
1267 *void (*stub_init_ptr)(void) __attribute__((section(".ctors"))) = __stubInit; */
1268#endif
1269
1270#ifdef WINDOWS
1271#define WIN32_LEAN_AND_MEAN
1272#include <windows.h>
1273
1274/* Windows crap */
1275BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
1276{
1277 (void) lpvReserved;
1278
1279 switch (fdwReason)
1280 {
1281 case DLL_PROCESS_ATTACH:
1282 {
1283 CRNetServer ns;
1284
1285 crNetInit(NULL, NULL);
1286 ns.name = "vboxhgcm://host:0";
1287 ns.buffer_size = 1024;
1288 crNetServerConnect(&ns);
1289 if (!ns.conn)
1290 {
1291 crDebug("Failed to connect to host (is guest 3d acceleration enabled?), aborting ICD load.");
1292 return FALSE;
1293 }
1294 else
1295 crNetFreeConnection(ns.conn);
1296
1297 break;
1298 }
1299
1300 case DLL_PROCESS_DETACH:
1301 {
1302 stubSPUSafeTearDown();
1303 break;
1304 }
1305
1306#if 0
1307 case DLL_THREAD_ATTACH:
1308 {
1309 if (stub_initialized)
1310 {
1311 CRASSERT(stub.spu);
1312 stub.spu->dispatch_table.VBoxPackAttachThread();
1313 }
1314 break;
1315 }
1316
1317 case DLL_THREAD_DETACH:
1318 {
1319 if (stub_initialized)
1320 {
1321 CRASSERT(stub.spu);
1322 stub.spu->dispatch_table.VBoxPackDetachThread();
1323 }
1324 break;
1325 }
1326#endif
1327
1328 default:
1329 break;
1330 }
1331
1332 return TRUE;
1333}
1334#endif
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette