VirtualBox

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

Last change on this file since 39485 was 39485, checked in by vboxsync, 13 years ago

crOpenGL: stubInit syncronization needed for win XPDM guests, some debug tooling

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