VirtualBox

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

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

crOpenGL/wddm: more multithreading fixes, vista expirience index works now

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 31.6 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/Miniport/wddm/VBoxVideoIf.h"
37#include "../../WINNT/Graphics/Display/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 (!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(CR_NEWWINTRACK) && !defined(WINDOWS)
201 crLockMutex(&stub.mutex);
202#endif
203
204 stubCheckWindowState(stub.currentContext->currentDrawable, GL_TRUE);
205 crHashtableWalk(stub.windowTable, stubCheckWindowsCB, stub.currentContext);
206
207#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
208 crUnlockMutex(&stub.mutex);
209#endif
210}
211
212
213/**
214 * Override the head SPU's glClear function.
215 * We're basically trapping this function so that we can poll the
216 * application window size at a regular interval.
217 */
218static void SPU_APIENTRY trapClear(GLbitfield mask)
219{
220 stubCheckWindowsState();
221 /* call the original SPU glClear function */
222 origClear(mask);
223}
224
225/**
226 * As above, but for glViewport. Most apps call glViewport before
227 * glClear when a window is resized.
228 */
229static void SPU_APIENTRY trapViewport(GLint x, GLint y, GLsizei w, GLsizei h)
230{
231 stubCheckWindowsState();
232 /* call the original SPU glViewport function */
233 if (!stub.viewportHack)
234 {
235 origViewport(x, y, w, h);
236 }
237 else
238 {
239 int winX, winY;
240 unsigned int winW, winH;
241 WindowInfo *pWindow;
242 pWindow = stub.currentContext->currentDrawable;
243 stubGetWindowGeometry(pWindow, &winX, &winY, &winW, &winH);
244 origViewport(0, 0, winW, winH);
245 }
246}
247
248static void SPU_APIENTRY trapSwapBuffers(GLint window, GLint flags)
249{
250 stubCheckWindowsState();
251 origSwapBuffers(window, flags);
252}
253
254static void SPU_APIENTRY trapDrawBuffer(GLenum buf)
255{
256 stubCheckWindowsState();
257 origDrawBuffer(buf);
258}
259
260static void SPU_APIENTRY trapScissor(GLint x, GLint y, GLsizei w, GLsizei h)
261{
262 int winX, winY;
263 unsigned int winW, winH;
264 WindowInfo *pWindow;
265 pWindow = stub.currentContext->currentDrawable;
266 stubGetWindowGeometry(pWindow, &winX, &winY, &winW, &winH);
267 origScissor(0, 0, winW, winH);
268}
269
270/**
271 * Use the GL function pointers in <spu> to initialize the static glim
272 * dispatch table.
273 */
274static void stubInitSPUDispatch(SPU *spu)
275{
276 crSPUInitDispatchTable( &stub.spuDispatch );
277 crSPUCopyDispatchTable( &stub.spuDispatch, &(spu->dispatch_table) );
278
279 if (stub.trackWindowSize || stub.trackWindowPos || stub.trackWindowVisibleRgn) {
280 /* patch-in special glClear/Viewport function to track window sizing */
281 origClear = stub.spuDispatch.Clear;
282 origViewport = stub.spuDispatch.Viewport;
283 origSwapBuffers = stub.spuDispatch.SwapBuffers;
284 origDrawBuffer = stub.spuDispatch.DrawBuffer;
285 origScissor = stub.spuDispatch.Scissor;
286 stub.spuDispatch.Clear = trapClear;
287 stub.spuDispatch.Viewport = trapViewport;
288
289 if (stub.viewportHack)
290 stub.spuDispatch.Scissor = trapScissor;
291 /*stub.spuDispatch.SwapBuffers = trapSwapBuffers;
292 stub.spuDispatch.DrawBuffer = trapDrawBuffer;*/
293 }
294
295 crSPUCopyDispatchTable( &glim, &stub.spuDispatch );
296}
297
298// Callback function, used to destroy all created contexts
299static void hsWalkStubDestroyContexts(unsigned long key, void *data1, void *data2)
300{
301 stubDestroyContext(key);
302}
303
304/**
305 * This is called when we exit.
306 * We call all the SPU's cleanup functions.
307 */
308static void stubSPUTearDown(void)
309{
310 crDebug("stubSPUTearDown");
311 if (!stub_initialized) return;
312
313 stub_initialized = 0;
314
315#ifdef WINDOWS
316# ifndef CR_NEWWINTRACK
317 stubUninstallWindowMessageHook();
318# endif
319#endif
320
321#ifdef CR_NEWWINTRACK
322 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
323#endif
324
325 //delete all created contexts
326 stubMakeCurrent( NULL, NULL);
327 crHashtableWalk(stub.contextTable, hsWalkStubDestroyContexts, NULL);
328
329 /* shutdown, now trap any calls to a NULL dispatcher */
330 crSPUCopyDispatchTable(&glim, &stubNULLDispatch);
331
332 crSPUUnloadChain(stub.spu);
333 stub.spu = NULL;
334
335#ifndef Linux
336 crUnloadOpenGL();
337#endif
338
339 crNetTearDown();
340
341#ifdef GLX
342 if (stub.xshmSI.shmid>=0)
343 {
344 shmctl(stub.xshmSI.shmid, IPC_RMID, 0);
345 shmdt(stub.xshmSI.shmaddr);
346 }
347 crFreeHashtable(stub.pGLXPixmapsHash, crFree);
348#endif
349
350 crFreeHashtable(stub.windowTable, crFree);
351 crFreeHashtable(stub.contextTable, NULL);
352
353 crMemset(&stub, 0, sizeof(stub));
354}
355
356static void stubSPUSafeTearDown(void)
357{
358#ifdef CHROMIUM_THREADSAFE
359 CRmutex *mutex;
360#endif
361
362 if (!stub_initialized) return;
363 stub_initialized = 0;
364
365#ifdef CHROMIUM_THREADSAFE
366 mutex = &stub.mutex;
367 crLockMutex(mutex);
368#endif
369 crDebug("stubSPUSafeTearDown");
370
371#ifdef WINDOWS
372# ifndef CR_NEWWINTRACK
373 stubUninstallWindowMessageHook();
374# endif
375#endif
376
377#if defined(CR_NEWWINTRACK)
378 crUnlockMutex(mutex);
379# if defined(WINDOWS)
380 if (RTThreadGetState(stub.hSyncThread)!=RTTHREADSTATE_TERMINATED)
381 {
382 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
383 if (PostThreadMessage(RTThreadGetNative(stub.hSyncThread), WM_QUIT, 0, 0))
384 {
385 RTThreadWait(stub.hSyncThread, 1000, NULL);
386 }
387 else
388 {
389 crDebug("Sync thread killed before DLL_PROCESS_DETACH");
390 }
391 }
392#else
393 if (stub.hSyncThread!=NIL_RTTHREAD)
394 {
395 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
396 {
397 /*RTThreadWait might return too early, which cause our code being unloaded while RT thread wrapper is still running*/
398 int rc = pthread_join(RTThreadGetNative(stub.hSyncThread), NULL);
399 if (!rc)
400 {
401 crDebug("pthread_join failed %i", rc);
402 }
403 }
404 }
405#endif
406 crLockMutex(mutex);
407#endif
408
409 crNetTearDown();
410#ifdef CHROMIUM_THREADSAFE
411 crUnlockMutex(mutex);
412 crFreeMutex(mutex);
413#endif
414 crMemset(&stub, 0, sizeof(stub));
415}
416
417
418static void stubExitHandler(void)
419{
420 stubSPUSafeTearDown();
421}
422
423/**
424 * Called when we receive a SIGTERM signal.
425 */
426static void stubSignalHandler(int signo)
427{
428 stubSPUSafeTearDown();
429 exit(0); /* this causes stubExitHandler() to be called */
430}
431
432
433/**
434 * Init variables in the stub structure, install signal handler.
435 */
436static void stubInitVars(void)
437{
438 WindowInfo *defaultWin;
439
440#ifdef CHROMIUM_THREADSAFE
441 crInitMutex(&stub.mutex);
442#endif
443
444 /* At the very least we want CR_RGB_BIT. */
445 stub.haveNativeOpenGL = GL_FALSE;
446 stub.spu = NULL;
447 stub.appDrawCursor = 0;
448 stub.minChromiumWindowWidth = 0;
449 stub.minChromiumWindowHeight = 0;
450 stub.maxChromiumWindowWidth = 0;
451 stub.maxChromiumWindowHeight = 0;
452 stub.matchChromiumWindowCount = 0;
453 stub.matchChromiumWindowID = NULL;
454 stub.matchWindowTitle = NULL;
455 stub.ignoreFreeglutMenus = 0;
456 stub.threadSafe = GL_FALSE;
457 stub.trackWindowSize = 0;
458 stub.trackWindowPos = 0;
459 stub.trackWindowVisibility = 0;
460 stub.trackWindowVisibleRgn = 0;
461 stub.mothershipPID = 0;
462 stub.spu_dir = NULL;
463
464 stub.freeContextNumber = MAGIC_CONTEXT_BASE;
465 stub.contextTable = crAllocHashtable();
466 stub.currentContext = NULL;
467
468 stub.windowTable = crAllocHashtable();
469
470#ifdef CR_NEWWINTRACK
471 stub.bShutdownSyncThread = false;
472 stub.hSyncThread = NIL_RTTHREAD;
473#endif
474
475 defaultWin = (WindowInfo *) crCalloc(sizeof(WindowInfo));
476 defaultWin->type = CHROMIUM;
477 defaultWin->spuWindow = 0; /* window 0 always exists */
478#ifdef WINDOWS
479 defaultWin->hVisibleRegion = INVALID_HANDLE_VALUE;
480#elif defined(GLX)
481 defaultWin->pVisibleRegions = NULL;
482 defaultWin->cVisibleRegions = 0;
483#endif
484 crHashtableAdd(stub.windowTable, 0, defaultWin);
485
486#if 1
487 atexit(stubExitHandler);
488 signal(SIGTERM, stubSignalHandler);
489 signal(SIGINT, stubSignalHandler);
490#ifndef WINDOWS
491 signal(SIGPIPE, SIG_IGN); /* the networking code should catch this */
492#endif
493#else
494 (void) stubExitHandler;
495 (void) stubSignalHandler;
496#endif
497}
498
499
500/**
501 * Return a free port number for the mothership to use, or -1 if we
502 * can't find one.
503 */
504static int
505GenerateMothershipPort(void)
506{
507 const int MAX_PORT = 10100;
508 unsigned short port;
509
510 /* generate initial port number randomly */
511 crRandAutoSeed();
512 port = (unsigned short) crRandInt(10001, MAX_PORT);
513
514#ifdef WINDOWS
515 /* XXX should implement a free port check here */
516 return port;
517#else
518 /*
519 * See if this port number really is free, try another if needed.
520 */
521 {
522 struct sockaddr_in servaddr;
523 int so_reuseaddr = 1;
524 int sock, k;
525
526 /* create socket */
527 sock = socket(AF_INET, SOCK_STREAM, 0);
528 CRASSERT(sock > 2);
529
530 /* deallocate socket/port when we exit */
531 k = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
532 (char *) &so_reuseaddr, sizeof(so_reuseaddr));
533 CRASSERT(k == 0);
534
535 /* initialize the servaddr struct */
536 crMemset(&servaddr, 0, sizeof(servaddr) );
537 servaddr.sin_family = AF_INET;
538 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
539
540 while (port < MAX_PORT) {
541 /* Bind to the given port number, return -1 if we fail */
542 servaddr.sin_port = htons((unsigned short) port);
543 k = bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
544 if (k) {
545 /* failed to create port. try next one. */
546 port++;
547 }
548 else {
549 /* free the socket/port now so mothership can make it */
550 close(sock);
551 return port;
552 }
553 }
554 }
555#endif /* WINDOWS */
556 return -1;
557}
558
559
560/**
561 * Try to determine which mothership configuration to use for this program.
562 */
563static char **
564LookupMothershipConfig(const char *procName)
565{
566 const int procNameLen = crStrlen(procName);
567 FILE *f;
568 const char *home;
569 char configPath[1000];
570
571 /* first, check if the CR_CONFIG env var is set */
572 {
573 const char *conf = crGetenv("CR_CONFIG");
574 if (conf && crStrlen(conf) > 0)
575 return crStrSplit(conf, " ");
576 }
577
578 /* second, look up config name from config file */
579 home = crGetenv("HOME");
580 if (home)
581 sprintf(configPath, "%s/%s", home, CONFIG_LOOKUP_FILE);
582 else
583 crStrcpy(configPath, CONFIG_LOOKUP_FILE); /* from current dir */
584 /* Check if the CR_CONFIG_PATH env var is set. */
585 {
586 const char *conf = crGetenv("CR_CONFIG_PATH");
587 if (conf)
588 crStrcpy(configPath, conf); /* from env var */
589 }
590
591 f = fopen(configPath, "r");
592 if (!f) {
593 return NULL;
594 }
595
596 while (!feof(f)) {
597 char line[1000];
598 char **args;
599 fgets(line, 999, f);
600 line[crStrlen(line) - 1] = 0; /* remove trailing newline */
601 if (crStrncmp(line, procName, procNameLen) == 0 &&
602 (line[procNameLen] == ' ' || line[procNameLen] == '\t'))
603 {
604 crWarning("Using Chromium configuration for %s from %s",
605 procName, configPath);
606 args = crStrSplit(line + procNameLen + 1, " ");
607 return args;
608 }
609 }
610 fclose(f);
611 return NULL;
612}
613
614
615static int Mothership_Awake = 0;
616
617
618/**
619 * Signal handler to determine when mothership is ready.
620 */
621static void
622MothershipPhoneHome(int signo)
623{
624 crDebug("Got signal %d: mothership is awake!", signo);
625 Mothership_Awake = 1;
626}
627
628void stubSetDefaultConfigurationOptions(void)
629{
630 unsigned char key[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
631
632 stub.appDrawCursor = 0;
633 stub.minChromiumWindowWidth = 0;
634 stub.minChromiumWindowHeight = 0;
635 stub.maxChromiumWindowWidth = 0;
636 stub.maxChromiumWindowHeight = 0;
637 stub.matchChromiumWindowID = NULL;
638 stub.numIgnoreWindowID = 0;
639 stub.matchWindowTitle = NULL;
640 stub.ignoreFreeglutMenus = 0;
641 stub.trackWindowSize = 1;
642 stub.trackWindowPos = 1;
643 stub.trackWindowVisibility = 1;
644 stub.trackWindowVisibleRgn = 1;
645 stub.matchChromiumWindowCount = 0;
646 stub.spu_dir = NULL;
647 crNetSetRank(0);
648 crNetSetContextRange(32, 35);
649 crNetSetNodeRange("iam0", "iamvis20");
650 crNetSetKey(key,sizeof(key));
651 stub.force_pbuffers = 0;
652 stub.viewportHack = 0;
653
654#ifdef WINDOWS
655 {
656 char name[1000];
657 int i;
658
659 /* Apply viewport hack only if we're running under wine */
660 if (NULL!=GetModuleHandle("wined3d.dll") || NULL != GetModuleHandle("wined3dwddm.dll"))
661 {
662 crGetProcName(name, 1000);
663 for (i=0; gsViewportHackApps[i]; ++i)
664 {
665 if (!stricmp(name, gsViewportHackApps[i]))
666 {
667 stub.viewportHack = 1;
668 break;
669 }
670 }
671 }
672 }
673#endif
674}
675
676#ifdef CR_NEWWINTRACK
677# ifdef VBOX_WITH_WDDM
678static stubDispatchVisibleRegions(WindowInfo *pWindow)
679{
680 DWORD dwCount;
681 LPRGNDATA lpRgnData;
682
683 dwCount = GetRegionData(pWindow->hVisibleRegion, 0, NULL);
684 lpRgnData = crAlloc(dwCount);
685
686 if (lpRgnData)
687 {
688 GetRegionData(pWindow->hVisibleRegion, dwCount, lpRgnData);
689 crDebug("Dispatched WindowVisibleRegion (%i, cRects=%i)", pWindow->spuWindow, lpRgnData->rdh.nCount);
690 stub.spuDispatch.WindowVisibleRegion(pWindow->spuWindow, lpRgnData->rdh.nCount, (GLint*) lpRgnData->Buffer);
691 crFree(lpRgnData);
692 }
693 else crWarning("GetRegionData failed, VisibleRegions update failed");
694}
695
696static HRGN stubMakeRegionFromRects(PVBOXVIDEOCM_CMD_RECTS pRegions, uint32_t start)
697{
698 HRGN hRgn, hTmpRgn;
699 uint32_t i;
700
701 if (pRegions->RectsInfo.cRects<=start)
702 {
703 return INVALID_HANDLE_VALUE;
704 }
705
706 hRgn = CreateRectRgn(0, 0, 0, 0);
707 for (i=start; i<pRegions->RectsInfo.cRects; ++i)
708 {
709 hTmpRgn = CreateRectRgnIndirect(&pRegions->RectsInfo.aRects[i]);
710 CombineRgn(hRgn, hRgn, hTmpRgn, RGN_OR);
711 DeleteObject(hTmpRgn);
712 }
713 return hRgn;
714}
715
716static void stubSyncTrUpdateWindowCB(unsigned long key, void *data1, void *data2)
717{
718 WindowInfo *pWindow = (WindowInfo *) data1;
719 VBOXDISPMP_REGIONS *pRegions = (VBOXDISPMP_REGIONS*) data2;
720 bool bChanged = false;
721 HRGN hNewRgn = INVALID_HANDLE_VALUE;
722
723 if (pRegions->hWnd != pWindow->hWnd)
724 {
725 return;
726 }
727
728 if (!pWindow->mapped)
729 {
730 pWindow->mapped = GL_TRUE;
731 bChanged = true;
732 crDebug("Dispatched: WindowShow(%i, %i)", pWindow->spuWindow, pWindow->mapped);
733 stub.spu->dispatch_table.WindowShow(pWindow->spuWindow, pWindow->mapped);
734 }
735
736 if (pRegions->pRegions->fFlags.bSetVisibleRects && pRegions->pRegions->fFlags.bSetViewRect)
737 {
738 int winX, winY;
739 unsigned int winW, winH;
740
741 winX = pRegions->pRegions->RectsInfo.aRects[0].left;
742 winY = pRegions->pRegions->RectsInfo.aRects[0].top;
743 winW = pRegions->pRegions->RectsInfo.aRects[0].right - winX;
744 winH = pRegions->pRegions->RectsInfo.aRects[0].bottom - winY;
745
746 if (stub.trackWindowPos && (winX!=pWindow->x || winY!=pWindow->y))
747 {
748 crDebug("Dispatched WindowPosition (%i)", pWindow->spuWindow);
749 stub.spuDispatch.WindowPosition(pWindow->spuWindow, winX, winY);
750 pWindow->x = winX;
751 pWindow->y = winY;
752 bChanged = true;
753 }
754
755 if (stub.trackWindowSize && (winW!=pWindow->width || winH!=pWindow->height))
756 {
757 crDebug("Dispatched WindowSize (%i)", pWindow->spuWindow);
758 stub.spuDispatch.WindowSize(pWindow->spuWindow, winW, winH);
759 pWindow->width = winW;
760 pWindow->height = winH;
761 bChanged = true;
762 }
763
764 hNewRgn = stubMakeRegionFromRects(pRegions->pRegions, 1);
765
766 /* ensure the window is in sync to avoid possible incorrect host notifications */
767 {
768 BOOL bRc = MoveWindow(pRegions->hWnd, winX, winY, winW, winH, FALSE /*BOOL bRepaint*/);
769 if (!bRc)
770 {
771 DWORD winEr = GetLastError();
772 crWarning("stubSyncTrUpdateWindowCB: MoveWindow failed winEr(%d)", winEr);
773 }
774 }
775 }
776 else
777 {
778 hNewRgn = stubMakeRegionFromRects(pRegions->pRegions, 0);
779 }
780
781 if (hNewRgn!=INVALID_HANDLE_VALUE)
782 {
783 OffsetRgn(hNewRgn, -pWindow->x, -pWindow->y);
784
785 if (pWindow->hVisibleRegion!=INVALID_HANDLE_VALUE)
786 {
787 CombineRgn(hNewRgn, pWindow->hVisibleRegion, hNewRgn,
788 pRegions->pRegions->fFlags.bAddHiddenRects ? RGN_DIFF:RGN_OR);
789
790 if (!EqualRgn(pWindow->hVisibleRegion, hNewRgn))
791 {
792 DeleteObject(pWindow->hVisibleRegion);
793 pWindow->hVisibleRegion = hNewRgn;
794 stubDispatchVisibleRegions(pWindow);
795 bChanged = true;
796 }
797 else
798 {
799 DeleteObject(hNewRgn);
800 }
801 }
802 else
803 {
804 if (pRegions->pRegions->fFlags.bSetVisibleRects)
805 {
806 pWindow->hVisibleRegion = hNewRgn;
807 stubDispatchVisibleRegions(pWindow);
808 bChanged = true;
809 }
810 }
811 }
812
813 if (bChanged)
814 {
815 stub.spu->dispatch_table.Flush();
816 }
817}
818# endif
819
820static void stubSyncTrCheckWindowsCB(unsigned long key, void *data1, void *data2)
821{
822 WindowInfo *pWindow = (WindowInfo *) data1;
823 (void) data2;
824
825 if (pWindow->type!=CHROMIUM || pWindow->spuWindow==0)
826 {
827 return;
828 }
829
830 stub.spu->dispatch_table.VBoxPackSetInjectID(pWindow->u32ClientID);
831
832 if (!stubSystemWindowExist(pWindow))
833 {
834#ifdef WINDOWS
835 crWindowDestroy((GLint)pWindow->hWnd);
836#else
837 crWindowDestroy((GLint)pWindow->drawable);
838#endif
839 /*No need to flush here as crWindowDestroy does it*/
840 return;
841 }
842
843 stubCheckWindowState(pWindow, GL_TRUE);
844}
845
846static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
847{
848#ifdef WINDOWS
849 MSG msg;
850# ifdef VBOX_WITH_WDDM
851 static VBOXDISPMP_CALLBACKS VBoxDispMpTstCallbacks = {NULL, NULL, NULL};
852 HMODULE hVBoxD3D = NULL;
853 VBOXDISPMP_REGIONS Regions;
854 HRESULT hr;
855# endif
856#endif
857
858 (void) pvUser;
859
860 crDebug("Sync thread started");
861#ifdef WINDOWS
862 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
863# ifdef VBOX_WITH_WDDM
864 if (GetModuleHandleEx(0, "VBoxDispD3D", &hVBoxD3D))
865 {
866 PFNVBOXDISPMP_GETCALLBACKS pfnVBoxDispMpGetCallbacks;
867 pfnVBoxDispMpGetCallbacks = (PFNVBOXDISPMP_GETCALLBACKS)GetProcAddress(hVBoxD3D, TEXT("VBoxDispMpGetCallbacks"));
868 if (pfnVBoxDispMpGetCallbacks)
869 {
870 hr = pfnVBoxDispMpGetCallbacks(VBOXDISPMP_VERSION, &VBoxDispMpTstCallbacks);
871 if (S_OK==hr)
872 {
873 CRASSERT(VBoxDispMpTstCallbacks.pfnEnableEvents);
874 CRASSERT(VBoxDispMpTstCallbacks.pfnDisableEvents);
875 CRASSERT(VBoxDispMpTstCallbacks.pfnGetRegions);
876
877 hr = VBoxDispMpTstCallbacks.pfnEnableEvents();
878 if (hr != S_OK)
879 {
880 crWarning("VBoxDispMpTstCallbacks.pfnEnableEvents failed");
881 }
882 else
883 {
884 crDebug("running with VBoxDispD3D");
885 stub.trackWindowVisibleRgn = 0;
886 }
887 }
888 else
889 {
890 crWarning("VBoxDispMpGetCallbacks failed");
891 }
892 }
893 }
894# endif
895#endif
896
897 crLockMutex(&stub.mutex);
898 stub.spu->dispatch_table.VBoxPackSetInjectThread();
899 crUnlockMutex(&stub.mutex);
900
901 RTThreadUserSignal(ThreadSelf);
902
903 while(!stub.bShutdownSyncThread)
904 {
905#ifdef WINDOWS
906 if (!PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
907 {
908# ifdef VBOX_WITH_WDDM
909 if (VBoxDispMpTstCallbacks.pfnGetRegions)
910 {
911 hr = VBoxDispMpTstCallbacks.pfnGetRegions(&Regions, 50);
912 if (S_OK==hr)
913 {
914# if 0
915 uint32_t i;
916 crDebug(">>>Regions for HWND(0x%x)>>>", Regions.hWnd);
917 crDebug("Flags(0x%x)", Regions.pRegions->fFlags.Value);
918 for (i = 0; i < Regions.pRegions->RectsInfo.cRects; ++i)
919 {
920 RECT *pRect = &Regions.pRegions->RectsInfo.aRects[i];
921 crDebug("Rect(%d): left(%d), top(%d), right(%d), bottom(%d)", i, pRect->left, pRect->top, pRect->right, pRect->bottom);
922 }
923 crDebug("<<<<<");
924# endif
925 /*hacky way to make sure window wouldn't be deleted in another thread as we hold hashtable lock here*/
926 crHashtableWalk(stub.windowTable, stubSyncTrUpdateWindowCB, &Regions);
927 }
928 else
929 {
930 if (WAIT_TIMEOUT!=hr)
931 {
932 crWarning("VBoxDispMpTstCallbacks.pfnGetRegions failed with 0x%x", hr);
933 }
934 }
935 }
936 else
937# endif
938 {
939 crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
940 RTThreadSleep(50);
941 }
942 }
943 else
944 {
945 if (WM_QUIT==msg.message)
946 {
947 crDebug("Sync thread got WM_QUIT");
948 break;
949 }
950 else
951 {
952 TranslateMessage(&msg);
953 DispatchMessage(&msg);
954 }
955 }
956#else
957 crLockMutex(&stub.mutex);
958 crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
959 crUnlockMutex(&stub.mutex);
960 RTThreadSleep(50);
961#endif
962 }
963
964#ifdef VBOX_WITH_WDDM
965 if (VBoxDispMpTstCallbacks.pfnDisableEvents)
966 {
967 VBoxDispMpTstCallbacks.pfnDisableEvents();
968 }
969 if (hVBoxD3D)
970 {
971 FreeLibrary(hVBoxD3D);
972 }
973#endif
974 crDebug("Sync thread stopped");
975 return 0;
976}
977#endif
978
979/**
980 * Do one-time initializations for the faker.
981 * Returns TRUE on success, FALSE otherwise.
982 */
983bool
984stubInit(void)
985{
986 /* Here is where we contact the mothership to find out what we're supposed
987 * to be doing. Networking code in a DLL initializer. I sure hope this
988 * works :)
989 *
990 * HOW can I pass the mothership address to this if I already know it?
991 */
992
993 CRConnection *conn = NULL;
994 char response[1024];
995 char **spuchain;
996 int num_spus;
997 int *spu_ids;
998 char **spu_names;
999 const char *app_id;
1000 int i;
1001 int disable_sync = 0;
1002
1003 if (stub_initialized)
1004 return true;
1005
1006 stubInitVars();
1007
1008 crGetProcName(response, 1024);
1009 crDebug("Stub launched for %s", response);
1010
1011#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
1012 /*@todo when vm boots with compiz turned on, new code causes hang in xcb_wait_for_reply in the sync thread*/
1013 if (!crStrcmp(response, "compiz") || !crStrcmp(response, "compiz_real")
1014 || !crStrcmp(response, "compiz-bin"))
1015 {
1016 disable_sync = 1;
1017 }
1018#endif
1019
1020 /* @todo check if it'd be of any use on other than guests, no use for windows */
1021 app_id = crGetenv( "CR_APPLICATION_ID_NUMBER" );
1022
1023 crNetInit( NULL, NULL );
1024
1025#ifndef WINDOWS
1026 {
1027 CRNetServer ns;
1028
1029 ns.name = "vboxhgcm://host:0";
1030 ns.buffer_size = 1024;
1031 crNetServerConnect(&ns);
1032 if (!ns.conn)
1033 {
1034 crWarning("Failed to connect to host. Make sure 3D acceleration is enabled for this VM.");
1035 return false;
1036 }
1037 else
1038 {
1039 crNetFreeConnection(ns.conn);
1040 }
1041#if 0 && defined(CR_NEWWINTRACK)
1042 {
1043 Status st = XInitThreads();
1044 if (st==0)
1045 {
1046 crWarning("XInitThreads returned %i", (int)st);
1047 }
1048 }
1049#endif
1050 }
1051#endif
1052
1053 strcpy(response, "2 0 feedback 1 pack");
1054 spuchain = crStrSplit( response, " " );
1055 num_spus = crStrToInt( spuchain[0] );
1056 spu_ids = (int *) crAlloc( num_spus * sizeof( *spu_ids ) );
1057 spu_names = (char **) crAlloc( num_spus * sizeof( *spu_names ) );
1058 for (i = 0 ; i < num_spus ; i++)
1059 {
1060 spu_ids[i] = crStrToInt( spuchain[2*i+1] );
1061 spu_names[i] = crStrdup( spuchain[2*i+2] );
1062 crDebug( "SPU %d/%d: (%d) \"%s\"", i+1, num_spus, spu_ids[i], spu_names[i] );
1063 }
1064
1065 stubSetDefaultConfigurationOptions();
1066
1067 stub.spu = crSPULoadChain( num_spus, spu_ids, spu_names, stub.spu_dir, NULL );
1068
1069 crFree( spuchain );
1070 crFree( spu_ids );
1071 for (i = 0; i < num_spus; ++i)
1072 crFree(spu_names[i]);
1073 crFree( spu_names );
1074
1075 // spu chain load failed somewhere
1076 if (!stub.spu) {
1077 return false;
1078 }
1079
1080 crSPUInitDispatchTable( &glim );
1081
1082 /* This is unlikely to change -- We still want to initialize our dispatch
1083 * table with the functions of the first SPU in the chain. */
1084 stubInitSPUDispatch( stub.spu );
1085
1086 /* we need to plug one special stub function into the dispatch table */
1087 glim.GetChromiumParametervCR = stub_GetChromiumParametervCR;
1088
1089#if !defined(VBOX_NO_NATIVEGL)
1090 /* Load pointers to native OpenGL functions into stub.nativeDispatch */
1091 stubInitNativeDispatch();
1092#endif
1093
1094/*crDebug("stub init");
1095raise(SIGINT);*/
1096
1097#ifdef WINDOWS
1098# ifndef CR_NEWWINTRACK
1099 stubInstallWindowMessageHook();
1100# endif
1101#endif
1102
1103#ifdef CR_NEWWINTRACK
1104 {
1105 int rc;
1106
1107 RTR3Init();
1108
1109 if (!disable_sync)
1110 {
1111 crDebug("Starting sync thread");
1112
1113 rc = RTThreadCreate(&stub.hSyncThread, stubSyncThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Sync");
1114 if (RT_FAILURE(rc))
1115 {
1116 crError("Failed to start sync thread! (%x)", rc);
1117 }
1118 RTThreadUserWait(stub.hSyncThread, 60 * 1000);
1119 RTThreadUserReset(stub.hSyncThread);
1120
1121 crDebug("Going on");
1122 }
1123 }
1124#endif
1125
1126#ifdef GLX
1127 stub.xshmSI.shmid = -1;
1128 stub.bShmInitFailed = GL_FALSE;
1129 stub.pGLXPixmapsHash = crAllocHashtable();
1130
1131 stub.bXExtensionsChecked = GL_FALSE;
1132 stub.bHaveXComposite = GL_FALSE;
1133 stub.bHaveXFixes = GL_FALSE;
1134#endif
1135
1136 stub_initialized = 1;
1137 return true;
1138}
1139
1140/* Sigh -- we can't do initialization at load time, since Windows forbids
1141 * the loading of other libraries from DLLMain. */
1142
1143#ifdef LINUX
1144/* GCC crap
1145 *void (*stub_init_ptr)(void) __attribute__((section(".ctors"))) = __stubInit; */
1146#endif
1147
1148#ifdef WINDOWS
1149#define WIN32_LEAN_AND_MEAN
1150#include <windows.h>
1151
1152/* Windows crap */
1153BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
1154{
1155 (void) lpvReserved;
1156
1157 switch (fdwReason)
1158 {
1159 case DLL_PROCESS_ATTACH:
1160 {
1161 CRNetServer ns;
1162
1163 crNetInit(NULL, NULL);
1164 ns.name = "vboxhgcm://host:0";
1165 ns.buffer_size = 1024;
1166 crNetServerConnect(&ns);
1167 if (!ns.conn)
1168 {
1169 crDebug("Failed to connect to host (is guest 3d acceleration enabled?), aborting ICD load.");
1170 return FALSE;
1171 }
1172 else
1173 crNetFreeConnection(ns.conn);
1174
1175 break;
1176 }
1177
1178 case DLL_PROCESS_DETACH:
1179 {
1180 stubSPUSafeTearDown();
1181 break;
1182 }
1183
1184#if 0
1185 case DLL_THREAD_ATTACH:
1186 {
1187 if (stub_initialized)
1188 {
1189 CRASSERT(stub.spu);
1190 stub.spu->dispatch_table.VBoxPackAttachThread();
1191 }
1192 break;
1193 }
1194
1195 case DLL_THREAD_DETACH:
1196 {
1197 if (stub_initialized)
1198 {
1199 CRASSERT(stub.spu);
1200 stub.spu->dispatch_table.VBoxPackDetachThread();
1201 }
1202 break;
1203 }
1204#endif
1205
1206 default:
1207 break;
1208 }
1209
1210 return TRUE;
1211}
1212#endif
Note: See TracBrowser for help on using the repository browser.

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