VirtualBox

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

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

crOpenGL: some code cleanup and small fixes

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