VirtualBox

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

Last change on this file since 25943 was 25383, checked in by vboxsync, 15 years ago

crOpenGL: fix compiz on older gpus (#4404)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.9 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#ifndef WINDOWS
22#include <sys/types.h>
23#include <unistd.h>
24#endif
25#ifdef CHROMIUM_THREADSAFE
26#include "cr_threads.h"
27#endif
28
29/**
30 * If you change this, see the comments in tilesortspu_context.c
31 */
32#define MAGIC_CONTEXT_BASE 500
33
34#define CONFIG_LOOKUP_FILE ".crconfigs"
35
36#ifdef WINDOWS
37#define PYTHON_EXE "python.exe"
38#else
39#define PYTHON_EXE "python"
40#endif
41
42#ifdef WINDOWS
43static char* gsViewportHackApps[] = {"googleearth.exe", NULL};
44#endif
45
46static int stub_initialized = 0;
47
48/* NOTE: 'SPUDispatchTable glim' is declared in NULLfuncs.py now */
49/* NOTE: 'SPUDispatchTable stubThreadsafeDispatch' is declared in tsfuncs.c */
50Stub stub;
51
52
53static void stubInitNativeDispatch( void )
54{
55#define MAX_FUNCS 1000
56 SPUNamedFunctionTable gl_funcs[MAX_FUNCS];
57 int numFuncs;
58
59 numFuncs = crLoadOpenGL( &stub.wsInterface, gl_funcs );
60
61 stub.haveNativeOpenGL = (numFuncs > 0);
62
63 /* XXX call this after context binding */
64 numFuncs += crLoadOpenGLExtensions( &stub.wsInterface, gl_funcs + numFuncs );
65
66 CRASSERT(numFuncs < MAX_FUNCS);
67
68 crSPUInitDispatchTable( &stub.nativeDispatch );
69 crSPUInitDispatch( &stub.nativeDispatch, gl_funcs );
70 crSPUInitDispatchNops( &stub.nativeDispatch );
71#undef MAX_FUNCS
72}
73
74
75/** Pointer to the SPU's real glClear and glViewport functions */
76static ClearFunc_t origClear;
77static ViewportFunc_t origViewport;
78static SwapBuffersFunc_t origSwapBuffers;
79static DrawBufferFunc_t origDrawBuffer;
80static ScissorFunc_t origScissor;
81
82static void stubCheckWindowState(void)
83{
84 WindowInfo *window;
85 bool bForceUpdate = false;
86
87 CRASSERT(stub.trackWindowSize || stub.trackWindowPos);
88
89 if (!stub.currentContext)
90 return;
91
92 window = stub.currentContext->currentDrawable;
93
94#ifdef WINDOWS
95 /* @todo install hook and track for WM_DISPLAYCHANGE */
96 {
97 DEVMODE devMode;
98
99 devMode.dmSize = sizeof(DEVMODE);
100 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode);
101
102 if (devMode.dmPelsWidth!=window->dmPelsWidth || devMode.dmPelsHeight!=window->dmPelsHeight)
103 {
104 crDebug("Resolution changed(%d,%d), forcing window Pos/Size update", devMode.dmPelsWidth, devMode.dmPelsHeight);
105 window->dmPelsWidth = devMode.dmPelsWidth;
106 window->dmPelsHeight = devMode.dmPelsHeight;
107 bForceUpdate = true;
108 }
109 }
110#endif
111
112 stubUpdateWindowGeometry(window, bForceUpdate);
113
114#if defined(GLX) || defined (WINDOWS)
115 if (stub.trackWindowVisibleRgn)
116 {
117 stubUpdateWindowVisibileRegions(window);
118 }
119#endif
120
121 if (stub.trackWindowVisibility && window->type == CHROMIUM && window->drawable) {
122 const int mapped = stubIsWindowVisible(window);
123 if (mapped != window->mapped) {
124 crDebug("Dispatched: WindowShow(%i, %i)", window->spuWindow, mapped);
125 stub.spu->dispatch_table.WindowShow(window->spuWindow, mapped);
126 window->mapped = mapped;
127 }
128 }
129}
130
131
132/**
133 * Override the head SPU's glClear function.
134 * We're basically trapping this function so that we can poll the
135 * application window size at a regular interval.
136 */
137static void SPU_APIENTRY trapClear(GLbitfield mask)
138{
139 stubCheckWindowState();
140 /* call the original SPU glClear function */
141 origClear(mask);
142}
143
144/**
145 * As above, but for glViewport. Most apps call glViewport before
146 * glClear when a window is resized.
147 */
148static void SPU_APIENTRY trapViewport(GLint x, GLint y, GLsizei w, GLsizei h)
149{
150 stubCheckWindowState();
151 /* call the original SPU glViewport function */
152 if (!stub.viewportHack)
153 {
154 origViewport(x, y, w, h);
155 }
156 else
157 {
158 int winX, winY;
159 unsigned int winW, winH;
160 WindowInfo *pWindow;
161 pWindow = stub.currentContext->currentDrawable;
162 stubGetWindowGeometry(pWindow, &winX, &winY, &winW, &winH);
163 origViewport(0, 0, winW, winH);
164 }
165}
166
167static void SPU_APIENTRY trapSwapBuffers(GLint window, GLint flags)
168{
169 stubCheckWindowState();
170 origSwapBuffers(window, flags);
171}
172
173static void SPU_APIENTRY trapDrawBuffer(GLenum buf)
174{
175 stubCheckWindowState();
176 origDrawBuffer(buf);
177}
178
179static void SPU_APIENTRY trapScissor(GLint x, GLint y, GLsizei w, GLsizei h)
180{
181 int winX, winY;
182 unsigned int winW, winH;
183 WindowInfo *pWindow;
184 pWindow = stub.currentContext->currentDrawable;
185 stubGetWindowGeometry(pWindow, &winX, &winY, &winW, &winH);
186 origScissor(0, 0, winW, winH);
187}
188
189/**
190 * Use the GL function pointers in <spu> to initialize the static glim
191 * dispatch table.
192 */
193static void stubInitSPUDispatch(SPU *spu)
194{
195 crSPUInitDispatchTable( &stub.spuDispatch );
196 crSPUCopyDispatchTable( &stub.spuDispatch, &(spu->dispatch_table) );
197
198 if (stub.trackWindowSize || stub.trackWindowPos || stub.trackWindowVisibleRgn) {
199 /* patch-in special glClear/Viewport function to track window sizing */
200 origClear = stub.spuDispatch.Clear;
201 origViewport = stub.spuDispatch.Viewport;
202 origSwapBuffers = stub.spuDispatch.SwapBuffers;
203 origDrawBuffer = stub.spuDispatch.DrawBuffer;
204 origScissor = stub.spuDispatch.Scissor;
205 stub.spuDispatch.Clear = trapClear;
206 stub.spuDispatch.Viewport = trapViewport;
207 if (stub.viewportHack)
208 stub.spuDispatch.Scissor = trapScissor;
209 /*stub.spuDispatch.SwapBuffers = trapSwapBuffers;
210 stub.spuDispatch.DrawBuffer = trapDrawBuffer;*/
211 }
212
213 crSPUCopyDispatchTable( &glim, &stub.spuDispatch );
214}
215
216// Callback function, used to destroy all created contexts
217static void hsWalkStubDestroyContexts(unsigned long key, void *data1, void *data2)
218{
219 stubDestroyContext(key);
220}
221
222/**
223 * This is called when we exit.
224 * We call all the SPU's cleanup functions.
225 */
226static void stubSPUTearDown(void)
227{
228 crDebug("stubSPUTearDown");
229 if (!stub_initialized) return;
230
231 stub_initialized = 0;
232
233#ifdef WINDOWS
234 stubUninstallWindowMessageHook();
235#endif
236
237 //delete all created contexts
238 stubMakeCurrent( NULL, NULL);
239 crHashtableWalk(stub.contextTable, hsWalkStubDestroyContexts, NULL);
240
241 /* shutdown, now trap any calls to a NULL dispatcher */
242 crSPUCopyDispatchTable(&glim, &stubNULLDispatch);
243
244 crSPUUnloadChain(stub.spu);
245 stub.spu = NULL;
246
247#ifndef Linux
248 crUnloadOpenGL();
249#endif
250
251 crNetTearDown();
252
253#ifdef GLX
254 if (stub.xshmSI.shmid>=0)
255 {
256 shmctl(stub.xshmSI.shmid, IPC_RMID, 0);
257 shmdt(stub.xshmSI.shmaddr);
258 }
259 crFreeHashtable(stub.pGLXPixmapsHash, crFree);
260#endif
261
262 crFreeHashtable(stub.windowTable, crFree);
263 crFreeHashtable(stub.contextTable, NULL);
264
265 crMemset(&stub, 0, sizeof(stub) );
266}
267
268static void stubSPUSafeTearDown(void)
269{
270#ifdef CHROMIUM_THREADSAFE
271 CRmutex *mutex;
272#endif
273
274 if (!stub_initialized) return;
275 stub_initialized = 0;
276
277#ifdef CHROMIUM_THREADSAFE
278 mutex = &stub.mutex;
279 crLockMutex(mutex);
280#endif
281 crDebug("stubSPUSafeTearDown");
282 crNetTearDown();
283#ifdef WINDOWS
284 stubUninstallWindowMessageHook();
285#endif
286 crMemset(&stub, 0, sizeof(stub));
287#ifdef CHROMIUM_THREADSAFE
288 crUnlockMutex(mutex);
289 crFreeMutex(mutex);
290#endif
291}
292
293
294static void stubExitHandler(void)
295{
296 stubSPUSafeTearDown();
297}
298
299/**
300 * Called when we receive a SIGTERM signal.
301 */
302static void stubSignalHandler(int signo)
303{
304 stubSPUSafeTearDown();
305 exit(0); /* this causes stubExitHandler() to be called */
306}
307
308
309/**
310 * Init variables in the stub structure, install signal handler.
311 */
312static void stubInitVars(void)
313{
314 WindowInfo *defaultWin;
315
316#ifdef CHROMIUM_THREADSAFE
317 crInitMutex(&stub.mutex);
318#endif
319
320 /* At the very least we want CR_RGB_BIT. */
321 stub.haveNativeOpenGL = GL_FALSE;
322 stub.spu = NULL;
323 stub.appDrawCursor = 0;
324 stub.minChromiumWindowWidth = 0;
325 stub.minChromiumWindowHeight = 0;
326 stub.maxChromiumWindowWidth = 0;
327 stub.maxChromiumWindowHeight = 0;
328 stub.matchChromiumWindowCount = 0;
329 stub.matchChromiumWindowID = NULL;
330 stub.matchWindowTitle = NULL;
331 stub.ignoreFreeglutMenus = 1;
332 stub.threadSafe = GL_FALSE;
333 stub.trackWindowSize = 0;
334 stub.trackWindowPos = 0;
335 stub.trackWindowVisibility = 0;
336 stub.trackWindowVisibleRgn = 0;
337 stub.mothershipPID = 0;
338 stub.spu_dir = NULL;
339
340 stub.freeContextNumber = MAGIC_CONTEXT_BASE;
341 stub.contextTable = crAllocHashtable();
342 stub.currentContext = NULL;
343
344 stub.windowTable = crAllocHashtable();
345
346 defaultWin = (WindowInfo *) crCalloc(sizeof(WindowInfo));
347 defaultWin->type = CHROMIUM;
348 defaultWin->spuWindow = 0; /* window 0 always exists */
349#ifdef WINDOWS
350 defaultWin->hVisibleRegion = INVALID_HANDLE_VALUE;
351#elif defined(GLX)
352 defaultWin->pVisibleRegions = NULL;
353 defaultWin->cVisibleRegions = 0;
354#endif
355 crHashtableAdd(stub.windowTable, 0, defaultWin);
356
357#if 1
358 atexit(stubExitHandler);
359 signal(SIGTERM, stubSignalHandler);
360 signal(SIGINT, stubSignalHandler);
361#ifndef WINDOWS
362 signal(SIGPIPE, SIG_IGN); /* the networking code should catch this */
363#endif
364#else
365 (void) stubExitHandler;
366 (void) stubSignalHandler;
367#endif
368}
369
370
371/**
372 * Return a free port number for the mothership to use, or -1 if we
373 * can't find one.
374 */
375static int
376GenerateMothershipPort(void)
377{
378 const int MAX_PORT = 10100;
379 unsigned short port;
380
381 /* generate initial port number randomly */
382 crRandAutoSeed();
383 port = (unsigned short) crRandInt(10001, MAX_PORT);
384
385#ifdef WINDOWS
386 /* XXX should implement a free port check here */
387 return port;
388#else
389 /*
390 * See if this port number really is free, try another if needed.
391 */
392 {
393 struct sockaddr_in servaddr;
394 int so_reuseaddr = 1;
395 int sock, k;
396
397 /* create socket */
398 sock = socket(AF_INET, SOCK_STREAM, 0);
399 CRASSERT(sock > 2);
400
401 /* deallocate socket/port when we exit */
402 k = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
403 (char *) &so_reuseaddr, sizeof(so_reuseaddr));
404 CRASSERT(k == 0);
405
406 /* initialize the servaddr struct */
407 crMemset(&servaddr, 0, sizeof(servaddr) );
408 servaddr.sin_family = AF_INET;
409 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
410
411 while (port < MAX_PORT) {
412 /* Bind to the given port number, return -1 if we fail */
413 servaddr.sin_port = htons((unsigned short) port);
414 k = bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
415 if (k) {
416 /* failed to create port. try next one. */
417 port++;
418 }
419 else {
420 /* free the socket/port now so mothership can make it */
421 close(sock);
422 return port;
423 }
424 }
425 }
426#endif /* WINDOWS */
427 return -1;
428}
429
430
431/**
432 * Try to determine which mothership configuration to use for this program.
433 */
434static char **
435LookupMothershipConfig(const char *procName)
436{
437 const int procNameLen = crStrlen(procName);
438 FILE *f;
439 const char *home;
440 char configPath[1000];
441
442 /* first, check if the CR_CONFIG env var is set */
443 {
444 const char *conf = crGetenv("CR_CONFIG");
445 if (conf && crStrlen(conf) > 0)
446 return crStrSplit(conf, " ");
447 }
448
449 /* second, look up config name from config file */
450 home = crGetenv("HOME");
451 if (home)
452 sprintf(configPath, "%s/%s", home, CONFIG_LOOKUP_FILE);
453 else
454 crStrcpy(configPath, CONFIG_LOOKUP_FILE); /* from current dir */
455 /* Check if the CR_CONFIG_PATH env var is set. */
456 {
457 const char *conf = crGetenv("CR_CONFIG_PATH");
458 if (conf)
459 crStrcpy(configPath, conf); /* from env var */
460 }
461
462 f = fopen(configPath, "r");
463 if (!f) {
464 return NULL;
465 }
466
467 while (!feof(f)) {
468 char line[1000];
469 char **args;
470 fgets(line, 999, f);
471 line[crStrlen(line) - 1] = 0; /* remove trailing newline */
472 if (crStrncmp(line, procName, procNameLen) == 0 &&
473 (line[procNameLen] == ' ' || line[procNameLen] == '\t'))
474 {
475 crWarning("Using Chromium configuration for %s from %s",
476 procName, configPath);
477 args = crStrSplit(line + procNameLen + 1, " ");
478 return args;
479 }
480 }
481 fclose(f);
482 return NULL;
483}
484
485
486static int Mothership_Awake = 0;
487
488
489/**
490 * Signal handler to determine when mothership is ready.
491 */
492static void
493MothershipPhoneHome(int signo)
494{
495 crDebug("Got signal %d: mothership is awake!", signo);
496 Mothership_Awake = 1;
497}
498
499void stubSetDefaultConfigurationOptions(void)
500{
501 unsigned char key[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
502
503 stub.appDrawCursor = 0;
504 stub.minChromiumWindowWidth = 0;
505 stub.minChromiumWindowHeight = 0;
506 stub.maxChromiumWindowWidth = 0;
507 stub.maxChromiumWindowHeight = 0;
508 stub.matchChromiumWindowID = NULL;
509 stub.numIgnoreWindowID = 0;
510 stub.matchWindowTitle = NULL;
511 stub.ignoreFreeglutMenus = 1;
512 stub.trackWindowSize = 1;
513 stub.trackWindowPos = 1;
514 stub.trackWindowVisibility = 1;
515 stub.trackWindowVisibleRgn = 1;
516 stub.matchChromiumWindowCount = 0;
517 stub.spu_dir = NULL;
518 crNetSetRank(0);
519 crNetSetContextRange(32, 35);
520 crNetSetNodeRange("iam0", "iamvis20");
521 crNetSetKey(key,sizeof(key));
522 stub.force_pbuffers = 0;
523 stub.viewportHack = 0;
524
525#ifdef WINDOWS
526 {
527 char name[1000];
528 int i;
529
530 /* Apply viewport hack only if we're running under wine */
531 if (NULL!=GetModuleHandle("wined3d.dll"))
532 {
533 crGetProcName(name, 1000);
534 for (i=0; gsViewportHackApps[i]; ++i)
535 {
536 if (!stricmp(name, gsViewportHackApps[i]))
537 {
538 stub.viewportHack = 1;
539 break;
540 }
541 }
542 }
543 }
544#endif
545}
546
547/**
548 * Do one-time initializations for the faker.
549 * Returns TRUE on success, FALSE otherwise.
550 */
551bool
552stubInit(void)
553{
554 /* Here is where we contact the mothership to find out what we're supposed
555 * to be doing. Networking code in a DLL initializer. I sure hope this
556 * works :)
557 *
558 * HOW can I pass the mothership address to this if I already know it?
559 */
560
561 CRConnection *conn = NULL;
562 char response[1024];
563 char **spuchain;
564 int num_spus;
565 int *spu_ids;
566 char **spu_names;
567 const char *app_id;
568 int i;
569
570 if (stub_initialized)
571 return true;
572
573 stubInitVars();
574
575 /* @todo check if it'd be of any use on other than guests, no use for windows */
576 app_id = crGetenv( "CR_APPLICATION_ID_NUMBER" );
577
578 crNetInit( NULL, NULL );
579
580#ifndef WINDOWS
581 {
582 CRNetServer ns;
583
584 ns.name = "vboxhgcm://host:0";
585 ns.buffer_size = 1024;
586 crNetServerConnect(&ns);
587 if (!ns.conn)
588 {
589 crWarning("Failed to connect to host. Make sure 3D acceleration is enabled for this VM.");
590 return false;
591 }
592 else
593 {
594 crNetFreeConnection(ns.conn);
595 }
596 }
597#endif
598
599 strcpy(response, "2 0 feedback 1 pack");
600 spuchain = crStrSplit( response, " " );
601 num_spus = crStrToInt( spuchain[0] );
602 spu_ids = (int *) crAlloc( num_spus * sizeof( *spu_ids ) );
603 spu_names = (char **) crAlloc( num_spus * sizeof( *spu_names ) );
604 for (i = 0 ; i < num_spus ; i++)
605 {
606 spu_ids[i] = crStrToInt( spuchain[2*i+1] );
607 spu_names[i] = crStrdup( spuchain[2*i+2] );
608 crDebug( "SPU %d/%d: (%d) \"%s\"", i+1, num_spus, spu_ids[i], spu_names[i] );
609 }
610
611 stubSetDefaultConfigurationOptions();
612
613 stub.spu = crSPULoadChain( num_spus, spu_ids, spu_names, stub.spu_dir, NULL );
614
615 crFree( spuchain );
616 crFree( spu_ids );
617 for (i = 0; i < num_spus; ++i)
618 crFree(spu_names[i]);
619 crFree( spu_names );
620
621 // spu chain load failed somewhere
622 if (!stub.spu) {
623 return false;
624 }
625
626 crSPUInitDispatchTable( &glim );
627
628 /* This is unlikely to change -- We still want to initialize our dispatch
629 * table with the functions of the first SPU in the chain. */
630 stubInitSPUDispatch( stub.spu );
631
632 /* we need to plug one special stub function into the dispatch table */
633 glim.GetChromiumParametervCR = stub_GetChromiumParametervCR;
634
635#if !defined(VBOX_NO_NATIVEGL)
636 /* Load pointers to native OpenGL functions into stub.nativeDispatch */
637 stubInitNativeDispatch();
638#endif
639
640/*crDebug("stub init");
641raise(SIGINT);*/
642
643#ifdef WINDOWS
644 stubInstallWindowMessageHook();
645#endif
646
647#ifdef GLX
648 stub.xshmSI.shmid = -1;
649 stub.bShmInitFailed = GL_FALSE;
650 stub.pGLXPixmapsHash = crAllocHashtable();
651#endif
652
653 stub_initialized = 1;
654 return true;
655}
656
657
658
659/* Sigh -- we can't do initialization at load time, since Windows forbids
660 * the loading of other libraries from DLLMain. */
661
662#ifdef LINUX
663/* GCC crap
664 *void (*stub_init_ptr)(void) __attribute__((section(".ctors"))) = __stubInit; */
665#endif
666
667#ifdef WINDOWS
668#define WIN32_LEAN_AND_MEAN
669#include <windows.h>
670
671/* Windows crap */
672BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
673{
674 (void) lpvReserved;
675
676 switch (fdwReason)
677 {
678 case DLL_PROCESS_ATTACH:
679 {
680 CRNetServer ns;
681
682 crNetInit(NULL, NULL);
683 ns.name = "vboxhgcm://host:0";
684 ns.buffer_size = 1024;
685 crNetServerConnect(&ns);
686 if (!ns.conn)
687 {
688 crDebug("Failed to connect to host (is guest 3d acceleration enabled?), aborting ICD load.");
689 return FALSE;
690 }
691 else
692 crNetFreeConnection(ns.conn);
693
694 break;
695 }
696
697 case DLL_PROCESS_DETACH:
698 {
699 stubSPUSafeTearDown();
700 break;
701 }
702
703 case DLL_THREAD_ATTACH:
704 break;
705
706 case DLL_THREAD_DETACH:
707 break;
708
709 default:
710 break;
711 }
712
713 return TRUE;
714}
715#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