VirtualBox

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

Last change on this file since 17839 was 17839, checked in by vboxsync, 16 years ago

crOpenGL: don't load native opengl library in the stub code on linux

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