VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/crOpenGL/load.c@ 16480

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

crOpenGL: track visible regions on linux guests + some more exports

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