VirtualBox

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

Last change on this file since 62521 was 60940, checked in by vboxsync, 8 years ago

bugref:8087: Additions/x11: support non-root X server: install our OpenGL libraries in a location that persists over reboots but still check on each boot whether they should be installed or removed. Should fix an X server crash after a hard reboot.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use