VirtualBox

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

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

crOpenGL: add opengl feedback/select support, public bug #2920

  • 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 "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;
76static SwapBuffersFunc_t origSwapBuffers;
77static DrawBufferFunc_t origDrawBuffer;
78
79static void stubCheckWindowState(void)
80{
81 int winX, winY;
82 unsigned int winW, winH;
83 WindowInfo *window;
84 bool bForceUpdate = false;
85
86 CRASSERT(stub.trackWindowSize || stub.trackWindowPos);
87
88 if (!stub.currentContext)
89 return;
90
91 window = stub.currentContext->currentDrawable;
92
93 stubGetWindowGeometry( window, &winX, &winY, &winW, &winH );
94
95#ifdef WINDOWS
96 /* @todo install hook and track for WM_DISPLAYCHANGE */
97 {
98 DEVMODE devMode;
99
100 devMode.dmSize = sizeof(DEVMODE);
101 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode);
102
103 if (devMode.dmPelsWidth!=window->dmPelsWidth || devMode.dmPelsHeight!=window->dmPelsHeight)
104 {
105 crDebug("Resolution changed(%d,%d), forcing window Pos/Size update", devMode.dmPelsWidth, devMode.dmPelsHeight);
106 window->dmPelsWidth = devMode.dmPelsWidth;
107 window->dmPelsHeight = devMode.dmPelsHeight;
108 bForceUpdate = true;
109 }
110 }
111#endif
112
113 stubUpdateWindowGeometry(window, bForceUpdate);
114
115#if defined(GLX) || defined (WINDOWS)
116 if (stub.trackWindowVisibleRgn)
117 {
118 stubUpdateWindowVisibileRegions(window);
119 }
120#endif
121
122 if (stub.trackWindowVisibility && window->type == CHROMIUM && window->drawable) {
123 const int mapped = stubIsWindowVisible(window);
124 if (mapped != window->mapped) {
125 crDebug("Dispatched: WindowShow(%i, %i)", window->spuWindow, mapped);
126 stub.spu->dispatch_table.WindowShow(window->spuWindow, mapped);
127 window->mapped = mapped;
128 }
129 }
130}
131
132
133/**
134 * Override the head SPU's glClear function.
135 * We're basically trapping this function so that we can poll the
136 * application window size at a regular interval.
137 */
138static void SPU_APIENTRY trapClear(GLbitfield mask)
139{
140 stubCheckWindowState();
141 /* call the original SPU glClear function */
142 origClear(mask);
143}
144
145/**
146 * As above, but for glViewport. Most apps call glViewport before
147 * glClear when a window is resized.
148 */
149static void SPU_APIENTRY trapViewport(GLint x, GLint y, GLsizei w, GLsizei h)
150{
151 stubCheckWindowState();
152 /* call the original SPU glViewport function */
153 origViewport(x, y, w, h);
154}
155
156static void SPU_APIENTRY trapSwapBuffers(GLint window, GLint flags)
157{
158 stubCheckWindowState();
159 origSwapBuffers(window, flags);
160}
161
162static void SPU_APIENTRY trapDrawBuffer(GLenum buf)
163{
164 stubCheckWindowState();
165 origDrawBuffer(buf);
166}
167
168/**
169 * Use the GL function pointers in <spu> to initialize the static glim
170 * dispatch table.
171 */
172static void stubInitSPUDispatch(SPU *spu)
173{
174 crSPUInitDispatchTable( &stub.spuDispatch );
175 crSPUCopyDispatchTable( &stub.spuDispatch, &(spu->dispatch_table) );
176
177 if (stub.trackWindowSize || stub.trackWindowPos || stub.trackWindowVisibleRgn) {
178 /* patch-in special glClear/Viewport function to track window sizing */
179 origClear = stub.spuDispatch.Clear;
180 origViewport = stub.spuDispatch.Viewport;
181 origSwapBuffers = stub.spuDispatch.SwapBuffers;
182 origDrawBuffer = stub.spuDispatch.DrawBuffer;
183 stub.spuDispatch.Clear = trapClear;
184 stub.spuDispatch.Viewport = trapViewport;
185 /*stub.spuDispatch.SwapBuffers = trapSwapBuffers;
186 stub.spuDispatch.DrawBuffer = trapDrawBuffer;*/
187 }
188
189 crSPUCopyDispatchTable( &glim, &stub.spuDispatch );
190}
191
192// Callback function, used to destroy all created contexts
193static void hsWalkStubDestroyContexts(unsigned long key, void *data1, void *data2)
194{
195 stubDestroyContext(key);
196}
197
198/**
199 * This is called when we exit.
200 * We call all the SPU's cleanup functions.
201 */
202static void stubSPUTearDown(void)
203{
204 crDebug("stubSPUTearDown");
205 if (!stub_initialized) return;
206
207 stub_initialized = 0;
208
209#ifdef WINDOWS
210 stubUninstallWindowMessageHook();
211#endif
212
213 //delete all created contexts
214 stubMakeCurrent( NULL, NULL);
215 crHashtableWalk(stub.contextTable, hsWalkStubDestroyContexts, NULL);
216
217 /* shutdown, now trap any calls to a NULL dispatcher */
218 crSPUCopyDispatchTable(&glim, &stubNULLDispatch);
219
220 crSPUUnloadChain(stub.spu);
221 stub.spu = NULL;
222
223 crUnloadOpenGL();
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 = &stub.mutex;
242 crLockMutex(mutex);
243#endif
244 crDebug("stubSPUSafeTearDown");
245 crNetTearDown();
246#ifdef WINDOWS
247 stubUninstallWindowMessageHook();
248#endif
249 crMemset(&stub, 0, sizeof(stub));
250#ifdef CHROMIUM_THREADSAFE
251 crUnlockMutex(mutex);
252 crFreeMutex(mutex);
253#endif
254}
255
256
257static void stubExitHandler(void)
258{
259 stubSPUSafeTearDown();
260}
261
262/**
263 * Called when we receive a SIGTERM signal.
264 */
265static void stubSignalHandler(int signo)
266{
267 stubSPUSafeTearDown();
268 exit(0); /* this causes stubExitHandler() to be called */
269}
270
271
272/**
273 * Init variables in the stub structure, install signal handler.
274 */
275static void stubInitVars(void)
276{
277 WindowInfo *defaultWin;
278
279#ifdef CHROMIUM_THREADSAFE
280 crInitMutex(&stub.mutex);
281#endif
282
283 /* At the very least we want CR_RGB_BIT. */
284 stub.haveNativeOpenGL = GL_FALSE;
285 stub.spu = NULL;
286 stub.appDrawCursor = 0;
287 stub.minChromiumWindowWidth = 0;
288 stub.minChromiumWindowHeight = 0;
289 stub.maxChromiumWindowWidth = 0;
290 stub.maxChromiumWindowHeight = 0;
291 stub.matchChromiumWindowCount = 0;
292 stub.matchChromiumWindowID = NULL;
293 stub.matchWindowTitle = NULL;
294 stub.ignoreFreeglutMenus = 1;
295 stub.threadSafe = GL_FALSE;
296 stub.trackWindowSize = 0;
297 stub.trackWindowPos = 0;
298 stub.trackWindowVisibility = 0;
299 stub.trackWindowVisibleRgn = 0;
300 stub.mothershipPID = 0;
301 stub.spu_dir = NULL;
302
303 stub.freeContextNumber = MAGIC_CONTEXT_BASE;
304 stub.contextTable = crAllocHashtable();
305 stub.currentContext = NULL;
306
307 stub.windowTable = crAllocHashtable();
308
309 defaultWin = (WindowInfo *) crCalloc(sizeof(WindowInfo));
310 defaultWin->type = CHROMIUM;
311 defaultWin->spuWindow = 0; /* window 0 always exists */
312#ifdef WINDOWS
313 defaultWin->hVisibleRegion = INVALID_HANDLE_VALUE;
314#elif defined(GLX)
315 defaultWin->pVisibleRegions = NULL;
316 defaultWin->cVisibleRegions = 0;
317#endif
318 crHashtableAdd(stub.windowTable, 0, defaultWin);
319
320#if 1
321 atexit(stubExitHandler);
322 signal(SIGTERM, stubSignalHandler);
323 signal(SIGINT, stubSignalHandler);
324#ifndef WINDOWS
325 signal(SIGPIPE, SIG_IGN); /* the networking code should catch this */
326#endif
327#else
328 (void) stubExitHandler;
329 (void) stubSignalHandler;
330#endif
331}
332
333
334/**
335 * Return a free port number for the mothership to use, or -1 if we
336 * can't find one.
337 */
338static int
339GenerateMothershipPort(void)
340{
341 const int MAX_PORT = 10100;
342 unsigned short port;
343
344 /* generate initial port number randomly */
345 crRandAutoSeed();
346 port = (unsigned short) crRandInt(10001, MAX_PORT);
347
348#ifdef WINDOWS
349 /* XXX should implement a free port check here */
350 return port;
351#else
352 /*
353 * See if this port number really is free, try another if needed.
354 */
355 {
356 struct sockaddr_in servaddr;
357 int so_reuseaddr = 1;
358 int sock, k;
359
360 /* create socket */
361 sock = socket(AF_INET, SOCK_STREAM, 0);
362 CRASSERT(sock > 2);
363
364 /* deallocate socket/port when we exit */
365 k = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
366 (char *) &so_reuseaddr, sizeof(so_reuseaddr));
367 CRASSERT(k == 0);
368
369 /* initialize the servaddr struct */
370 crMemset(&servaddr, 0, sizeof(servaddr) );
371 servaddr.sin_family = AF_INET;
372 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
373
374 while (port < MAX_PORT) {
375 /* Bind to the given port number, return -1 if we fail */
376 servaddr.sin_port = htons((unsigned short) port);
377 k = bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
378 if (k) {
379 /* failed to create port. try next one. */
380 port++;
381 }
382 else {
383 /* free the socket/port now so mothership can make it */
384 close(sock);
385 return port;
386 }
387 }
388 }
389#endif /* WINDOWS */
390 return -1;
391}
392
393
394/**
395 * Try to determine which mothership configuration to use for this program.
396 */
397static char **
398LookupMothershipConfig(const char *procName)
399{
400 const int procNameLen = crStrlen(procName);
401 FILE *f;
402 const char *home;
403 char configPath[1000];
404
405 /* first, check if the CR_CONFIG env var is set */
406 {
407 const char *conf = crGetenv("CR_CONFIG");
408 if (conf && crStrlen(conf) > 0)
409 return crStrSplit(conf, " ");
410 }
411
412 /* second, look up config name from config file */
413 home = crGetenv("HOME");
414 if (home)
415 sprintf(configPath, "%s/%s", home, CONFIG_LOOKUP_FILE);
416 else
417 crStrcpy(configPath, CONFIG_LOOKUP_FILE); /* from current dir */
418 /* Check if the CR_CONFIG_PATH env var is set. */
419 {
420 const char *conf = crGetenv("CR_CONFIG_PATH");
421 if (conf)
422 crStrcpy(configPath, conf); /* from env var */
423 }
424
425 f = fopen(configPath, "r");
426 if (!f) {
427 return NULL;
428 }
429
430 while (!feof(f)) {
431 char line[1000];
432 char **args;
433 fgets(line, 999, f);
434 line[crStrlen(line) - 1] = 0; /* remove trailing newline */
435 if (crStrncmp(line, procName, procNameLen) == 0 &&
436 (line[procNameLen] == ' ' || line[procNameLen] == '\t'))
437 {
438 crWarning("Using Chromium configuration for %s from %s",
439 procName, configPath);
440 args = crStrSplit(line + procNameLen + 1, " ");
441 return args;
442 }
443 }
444 fclose(f);
445 return NULL;
446}
447
448
449static int Mothership_Awake = 0;
450
451
452/**
453 * Signal handler to determine when mothership is ready.
454 */
455static void
456MothershipPhoneHome(int signo)
457{
458 crDebug("Got signal %d: mothership is awake!", signo);
459 Mothership_Awake = 1;
460}
461
462void stubSetDefaultConfigurationOptions(void)
463{
464 unsigned char key[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
465
466 stub.appDrawCursor = 0;
467 stub.minChromiumWindowWidth = 0;
468 stub.minChromiumWindowHeight = 0;
469 stub.maxChromiumWindowWidth = 0;
470 stub.maxChromiumWindowHeight = 0;
471 stub.matchChromiumWindowID = NULL;
472 stub.numIgnoreWindowID = 0;
473 stub.matchWindowTitle = NULL;
474 stub.ignoreFreeglutMenus = 1;
475 stub.trackWindowSize = 1;
476 stub.trackWindowPos = 1;
477 stub.trackWindowVisibility = 1;
478 stub.trackWindowVisibleRgn = 1;
479 stub.matchChromiumWindowCount = 0;
480 stub.spu_dir = NULL;
481 crNetSetRank(0);
482 crNetSetContextRange(32, 35);
483 crNetSetNodeRange("iam0", "iamvis20");
484 crNetSetKey(key,sizeof(key));
485 stub.force_pbuffers = 0;
486}
487
488/**
489 * Do one-time initializations for the faker.
490 * Returns TRUE on success, FALSE otherwise.
491 */
492bool
493stubInit(void)
494{
495 /* Here is where we contact the mothership to find out what we're supposed
496 * to be doing. Networking code in a DLL initializer. I sure hope this
497 * works :)
498 *
499 * HOW can I pass the mothership address to this if I already know it?
500 */
501
502 CRConnection *conn = NULL;
503 char response[1024];
504 char **spuchain;
505 int num_spus;
506 int *spu_ids;
507 char **spu_names;
508 const char *app_id;
509 int i;
510
511 if (stub_initialized)
512 return true;
513 stub_initialized = 1;
514
515 stubInitVars();
516
517 /* @todo check if it'd be of any use on other than guests, no use for windows */
518 app_id = crGetenv( "CR_APPLICATION_ID_NUMBER" );
519
520 crNetInit( NULL, NULL );
521 strcpy(response, "3 0 array 1 feedback 2 pack");
522 spuchain = crStrSplit( response, " " );
523 num_spus = crStrToInt( spuchain[0] );
524 spu_ids = (int *) crAlloc( num_spus * sizeof( *spu_ids ) );
525 spu_names = (char **) crAlloc( num_spus * sizeof( *spu_names ) );
526 for (i = 0 ; i < num_spus ; i++)
527 {
528 spu_ids[i] = crStrToInt( spuchain[2*i+1] );
529 spu_names[i] = crStrdup( spuchain[2*i+2] );
530 crDebug( "SPU %d/%d: (%d) \"%s\"", i+1, num_spus, spu_ids[i], spu_names[i] );
531 }
532
533 stubSetDefaultConfigurationOptions();
534
535 stub.spu = crSPULoadChain( num_spus, spu_ids, spu_names, stub.spu_dir, NULL );
536
537 crFree( spuchain );
538 crFree( spu_ids );
539 for (i = 0; i < num_spus; ++i)
540 crFree(spu_names[i]);
541 crFree( spu_names );
542
543 // spu chain load failed somewhere
544 if (!stub.spu) {
545 stub_initialized = 0;
546 return false;
547 }
548
549 crSPUInitDispatchTable( &glim );
550
551 /* This is unlikely to change -- We still want to initialize our dispatch
552 * table with the functions of the first SPU in the chain. */
553 stubInitSPUDispatch( stub.spu );
554
555 /* we need to plug one special stub function into the dispatch table */
556 glim.GetChromiumParametervCR = stub_GetChromiumParametervCR;
557
558 /* Load pointers to native OpenGL functions into stub.nativeDispatch */
559 stubInitNativeDispatch();
560
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