VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c@ 29930

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

crOpenGL: properly cleanup host opengl parts (#2954, #6443)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.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_mem.h"
8#include "cr_spu.h"
9#include "cr_error.h"
10#include "cr_string.h"
11#include "cr_url.h"
12#include "renderspu.h"
13#include <stdio.h>
14
15#ifdef RT_OS_DARWIN
16# include <iprt/semaphore.h>
17#endif /* RT_OS_DARWIN */
18
19static SPUNamedFunctionTable _cr_render_table[1000];
20
21SPUFunctions render_functions = {
22 NULL, /* CHILD COPY */
23 NULL, /* DATA */
24 _cr_render_table /* THE ACTUAL FUNCTIONS */
25};
26
27RenderSPU render_spu;
28uint64_t render_spu_parent_window_id = 0;
29
30#ifdef CHROMIUM_THREADSAFE
31CRtsd _RenderTSD;
32#endif
33
34static void swapsyncConnect(void)
35{
36 char hostname[4096], protocol[4096];
37 unsigned short port;
38
39 crNetInit(NULL, NULL);
40
41 if (!crParseURL( render_spu.swap_master_url, protocol, hostname,
42 &port, 9876))
43 crError( "Bad URL: %s", render_spu.swap_master_url );
44
45 if (render_spu.is_swap_master)
46 {
47 int a;
48
49 render_spu.swap_conns = (CRConnection **)crAlloc(
50 render_spu.num_swap_clients*sizeof(CRConnection *));
51 for (a=0; a<render_spu.num_swap_clients; a++)
52 {
53 render_spu.swap_conns[a] = crNetAcceptClient( protocol, hostname, port,
54 render_spu.swap_mtu, 1);
55 }
56 }
57 else
58 {
59 render_spu.swap_conns = (CRConnection **)crAlloc(sizeof(CRConnection *));
60
61 render_spu.swap_conns[0] = crNetConnectToServer(render_spu.swap_master_url,
62 port, render_spu.swap_mtu, 1);
63 if (!render_spu.swap_conns[0])
64 crError("Failed connection");
65 }
66}
67
68#ifdef RT_OS_WINDOWS
69static DWORD WINAPI renderSPUWindowThreadProc(void* unused)
70{
71 MSG msg;
72 bool bRet;
73
74 (void) unused;
75
76 /* Force system to create the message queue.
77 * Else, there's a chance that render spu will issue PostThreadMessage
78 * before this thread calls GetMessage for first time.
79 */
80 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
81
82 crDebug("RenderSPU: Window thread started (%x)", crThreadID());
83 SetEvent(render_spu.hWinThreadReadyEvent);
84
85 while( (bRet = GetMessage( &msg, 0, 0, 0 )) != 0)
86 {
87 if (bRet == -1)
88 {
89 crError("RenderSPU: Window thread GetMessage failed (%x)", GetLastError());
90 break;
91 }
92 else
93 {
94 if (msg.message == WM_VBOX_RENDERSPU_CREATE_WINDOW)
95 {
96 LPCREATESTRUCT pCS = (LPCREATESTRUCT) msg.lParam;
97 HWND *phWnd;
98
99 CRASSERT(msg.lParam && !msg.wParam && pCS->lpCreateParams);
100
101 phWnd = pCS->lpCreateParams;
102
103 *phWnd = CreateWindowEx(pCS->dwExStyle, pCS->lpszName, pCS->lpszClass, pCS->style,
104 pCS->x, pCS->y, pCS->cx, pCS->cy,
105 pCS->hwndParent, pCS->hMenu, pCS->hInstance, &render_spu);
106
107 SetEvent(render_spu.hWinThreadReadyEvent);
108 }
109 else if (msg.message == WM_VBOX_RENDERSPU_DESTROY_WINDOW)
110 {
111 CRASSERT(msg.lParam && !msg.wParam);
112
113 DestroyWindow(((VBOX_RENDERSPU_DESTROY_WINDOW*) msg.lParam)->hWnd);
114
115 SetEvent(render_spu.hWinThreadReadyEvent);
116 }
117 else
118 {
119 TranslateMessage(&msg);
120 DispatchMessage(&msg);
121 }
122 }
123 }
124
125 render_spu.dwWinThreadId = 0;
126
127 crDebug("RenderSPU: Window thread stopped (%x)", crThreadID());
128 SetEvent(render_spu.hWinThreadReadyEvent);
129
130 return 0;
131}
132#endif
133
134static SPUFunctions *
135renderSPUInit( int id, SPU *child, SPU *self,
136 unsigned int context_id, unsigned int num_contexts )
137{
138 int numFuncs, numSpecial;
139 GLint defaultWin, defaultCtx;
140 WindowInfo *windowInfo;
141
142 (void) child;
143 (void) context_id;
144 (void) num_contexts;
145
146 self->privatePtr = (void *) &render_spu;
147
148#ifdef CHROMIUM_THREADSAFE
149 crDebug("Render SPU: thread-safe");
150#endif
151
152 crMemZero(&render_spu, sizeof(render_spu));
153
154 render_spu.id = id;
155 renderspuSetVBoxConfiguration(&render_spu);
156
157 if (render_spu.swap_master_url)
158 swapsyncConnect();
159
160
161 /* Get our special functions. */
162 numSpecial = renderspuCreateFunctions( _cr_render_table );
163
164#ifdef RT_OS_WINDOWS
165 /* Start thread to create windows and process window messages */
166 crDebug("RenderSPU: Starting windows serving thread");
167 render_spu.hWinThreadReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
168 if (!render_spu.hWinThreadReadyEvent)
169 {
170 crError("RenderSPU: Failed to create WinThreadReadyEvent! (%x)", GetLastError());
171 return NULL;
172 }
173
174 if (!CreateThread(NULL, 0, renderSPUWindowThreadProc, 0, 0, &render_spu.dwWinThreadId))
175 {
176 crError("RenderSPU: Failed to start windows thread! (%x)", GetLastError());
177 return NULL;
178 }
179 WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
180#endif
181
182 /* Get the OpenGL functions. */
183 numFuncs = crLoadOpenGL( &render_spu.ws, _cr_render_table + numSpecial );
184 if (numFuncs == 0) {
185 crError("The render SPU was unable to load the native OpenGL library");
186 return NULL;
187 }
188
189 numFuncs += numSpecial;
190
191#ifdef GLX
192 if (!render_spu.use_glxchoosevisual) {
193 /* sometimes want to set this option with ATI drivers */
194 render_spu.ws.glXChooseVisual = NULL;
195 }
196#endif
197
198 render_spu.window_id = 0;
199 render_spu.context_id = 0;
200 render_spu.contextTable = crAllocHashtable();
201 render_spu.windowTable = crAllocHashtable();
202
203 CRASSERT(render_spu.default_visual & CR_RGB_BIT);
204
205#ifdef USE_OSMESA
206 if (render_spu.use_osmesa) {
207 if (!crLoadOSMesa(&render_spu.OSMesaCreateContext,
208 &render_spu.OSMesaMakeCurrent,
209 &render_spu.OSMesaDestroyContext)) {
210 crError("Unable to load OSMesa library");
211 }
212 }
213#endif
214
215#ifdef DARWIN
216# ifdef VBOX_WITH_COCOA_QT
217# else /* VBOX_WITH_COCOA_QT */
218 render_spu.hRootVisibleRegion = 0;
219 render_spu.currentBufferName = 1;
220 render_spu.uiDockUpdateTS = 0;
221 /* Create a mutex for syncronizing events from the main Qt thread & this
222 thread */
223 RTSemFastMutexCreate(&render_spu.syncMutex);
224 /* Create our window groups */
225 CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pMasterGroup);
226 CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pParentGroup);
227 /* Make the correct z-layering */
228 SendWindowGroupBehind (render_spu.pParentGroup, render_spu.pMasterGroup);
229 /* and set the gParentGroup as parent for gMasterGroup. */
230 SetWindowGroupParent (render_spu.pMasterGroup, render_spu.pParentGroup);
231 /* Install the event handlers */
232 EventTypeSpec eventList[] =
233 {
234 {kEventClassVBox, kEventVBoxUpdateContext}, /* Update the context after show/size/move events */
235 {kEventClassVBox, kEventVBoxBoundsChanged} /* Clip/Pos the OpenGL windows when the main window is changed in pos/size */
236 };
237 /* We need to process events from our main window */
238 render_spu.hParentEventHandler = NewEventHandlerUPP(windowEvtHndlr);
239 InstallApplicationEventHandler (render_spu.hParentEventHandler,
240 GetEventTypeCount(eventList), eventList,
241 NULL, NULL);
242 render_spu.fInit = true;
243# endif /* VBOX_WITH_COCOA_QT */
244#endif /* DARWIN */
245
246 /*
247 * Create the default window and context. Their indexes are zero and
248 * a client can use them without calling CreateContext or WindowCreate.
249 */
250 crDebug("Render SPU: Creating default window (visBits=0x%x, id=0)",
251 render_spu.default_visual);
252 defaultWin = renderspuWindowCreate( NULL, render_spu.default_visual );
253 if (defaultWin != 0) {
254 crError("Render SPU: Couldn't get a double-buffered, RGB visual with Z!");
255 return NULL;
256 }
257 crDebug( "Render SPU: WindowCreate returned %d (0=normal)", defaultWin );
258
259 crDebug("Render SPU: Creating default context, visBits=0x%x",
260 render_spu.default_visual );
261 defaultCtx = renderspuCreateContext( NULL, render_spu.default_visual, 0 );
262 CRASSERT(defaultCtx == 0);
263
264 renderspuMakeCurrent( defaultWin, 0, defaultCtx );
265
266 /* Get windowInfo for the default window */
267 windowInfo = (WindowInfo *) crHashtableSearch(render_spu.windowTable, 0);
268 CRASSERT(windowInfo);
269 windowInfo->mapPending = GL_TRUE;
270
271 /*
272 * Get the OpenGL extension functions.
273 * SIGH -- we have to wait until the very bitter end to load the
274 * extensions, because the context has to be bound before
275 * wglGetProcAddress will work correctly. No such issue with GLX though.
276 */
277 numFuncs += crLoadOpenGLExtensions( &render_spu.ws, _cr_render_table + numFuncs );
278 CRASSERT(numFuncs < 1000);
279
280#ifdef WINDOWS
281 /*
282 * Same problem as above, these are extensions so we need to
283 * load them after a context has been bound. As they're WGL
284 * extensions too, we can't simply tag them into the spu_loader.
285 * So we do them here for now.
286 * Grrr, NVIDIA driver uses EXT for GetExtensionsStringEXT,
287 * but ARB for others. Need furthur testing here....
288 */
289 render_spu.ws.wglGetExtensionsStringEXT =
290 (wglGetExtensionsStringEXTFunc_t)
291 render_spu.ws.wglGetProcAddress( "wglGetExtensionsStringEXT" );
292 render_spu.ws.wglChoosePixelFormatEXT =
293 (wglChoosePixelFormatEXTFunc_t)
294 render_spu.ws.wglGetProcAddress( "wglChoosePixelFormatARB" );
295 render_spu.ws.wglGetPixelFormatAttribivEXT =
296 (wglGetPixelFormatAttribivEXTFunc_t)
297 render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribivARB" );
298 render_spu.ws.wglGetPixelFormatAttribfvEXT =
299 (wglGetPixelFormatAttribfvEXTFunc_t)
300 render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribfvARB" );
301
302 if (render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D"))
303 {
304 _cr_render_table[numFuncs].name = crStrdup("CopyTexSubImage3D");
305 _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D");
306 ++numFuncs;
307 crDebug("Render SPU: Found glCopyTexSubImage3D function");
308 }
309
310 if (render_spu.ws.wglGetProcAddress("glDrawRangeElements"))
311 {
312 _cr_render_table[numFuncs].name = crStrdup("DrawRangeElements");
313 _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glDrawRangeElements");
314 ++numFuncs;
315 crDebug("Render SPU: Found glDrawRangeElements function");
316 }
317
318 if (render_spu.ws.wglGetProcAddress("glTexSubImage3D"))
319 {
320 _cr_render_table[numFuncs].name = crStrdup("TexSubImage3D");
321 _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexSubImage3D");
322 ++numFuncs;
323 crDebug("Render SPU: Found glTexSubImage3D function");
324 }
325
326 if (render_spu.ws.wglGetProcAddress("glTexImage3D"))
327 {
328 _cr_render_table[numFuncs].name = crStrdup("TexImage3D");
329 _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexImage3D");
330 ++numFuncs;
331 crDebug("Render SPU: Found glTexImage3D function");
332 }
333
334 if (render_spu.ws.wglGetExtensionsStringEXT) {
335 crDebug("WGL - found wglGetExtensionsStringEXT\n");
336 }
337 if (render_spu.ws.wglChoosePixelFormatEXT) {
338 crDebug("WGL - found wglChoosePixelFormatEXT\n");
339 }
340#endif
341
342 render_spu.barrierHash = crAllocHashtable();
343
344 render_spu.cursorX = 0;
345 render_spu.cursorY = 0;
346 render_spu.use_L2 = 0;
347
348 render_spu.gather_conns = NULL;
349
350 crDebug("Render SPU: ---------- End of Init -------------");
351
352 return &render_functions;
353}
354
355
356static void renderSPUSelfDispatch(SPUDispatchTable *self)
357{
358 crSPUInitDispatchTable( &(render_spu.self) );
359 crSPUCopyDispatchTable( &(render_spu.self), self );
360
361 render_spu.server = (CRServer *)(self->server);
362}
363
364
365static void DeleteContextCallback( void *data )
366{
367 ContextInfo *context = (ContextInfo *) data;
368 renderspu_SystemDestroyContext(context);
369 crFree(context);
370}
371
372static void DeleteWindowCallback( void *data )
373{
374 WindowInfo *window = (WindowInfo *) data;
375 renderspu_SystemDestroyWindow(window);
376 crFree(window);
377}
378
379static int renderSPUCleanup(void)
380{
381 crFreeHashtable(render_spu.contextTable, DeleteContextCallback);
382 render_spu.contextTable = NULL;
383 crFreeHashtable(render_spu.windowTable, DeleteWindowCallback);
384 render_spu.windowTable = NULL;
385 crFreeHashtable(render_spu.barrierHash, crFree);
386 render_spu.barrierHash = NULL;
387
388#ifdef RT_OS_DARWIN
389# ifndef VBOX_WITH_COCOA_QT
390 render_spu.fInit = false;
391 DisposeEventHandlerUPP(render_spu.hParentEventHandler);
392 ReleaseWindowGroup(render_spu.pMasterGroup);
393 ReleaseWindowGroup(render_spu.pParentGroup);
394 if (render_spu.hRootVisibleRegion)
395 {
396 DisposeRgn(render_spu.hRootVisibleRegion);
397 render_spu.hRootVisibleRegion = 0;
398 }
399 render_spu.currentBufferName = 1;
400 render_spu.uiDockUpdateTS = 0;
401 RTSemFastMutexDestroy(render_spu.syncMutex);
402# else /* VBOX_WITH_COCOA_QT */
403# endif /* VBOX_WITH_COCOA_QT */
404#endif /* RT_OS_DARWIN */
405
406#ifdef RT_OS_WINDOWS
407 if (render_spu.dwWinThreadId)
408 {
409 PostThreadMessage(render_spu.dwWinThreadId, WM_QUIT, 0, 0);
410 WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
411 }
412 CloseHandle(render_spu.hWinThreadReadyEvent);
413 render_spu.hWinThreadReadyEvent = NULL;
414#endif
415
416 crUnloadOpenGL();
417
418#ifdef CHROMIUM_THREADSAFE
419 crFreeTSD(&_RenderTSD);
420#endif
421
422 return 1;
423}
424
425
426extern SPUOptions renderSPUOptions[];
427
428int SPULoad( char **name, char **super, SPUInitFuncPtr *init,
429 SPUSelfDispatchFuncPtr *self, SPUCleanupFuncPtr *cleanup,
430 SPUOptionsPtr *options, int *flags )
431{
432 *name = "render";
433 *super = NULL;
434 *init = renderSPUInit;
435 *self = renderSPUSelfDispatch;
436 *cleanup = renderSPUCleanup;
437 *options = renderSPUOptions;
438 *flags = (SPU_NO_PACKER|SPU_IS_TERMINAL|SPU_MAX_SERVERS_ZERO);
439
440 return 1;
441}
442
443DECLEXPORT(void) renderspuSetWindowId(uint64_t winId)
444{
445 render_spu_parent_window_id = winId;
446}
447
448static void renderspuWindowVisibleRegionCB(unsigned long key, void *data1, void *data2)
449{
450 WindowInfo *window = (WindowInfo *) data1;
451 CRASSERT(window);
452
453 renderspu_SystemWindowApplyVisibleRegion(window);
454}
455
456DECLEXPORT(void) renderspuSetRootVisibleRegion(GLint cRects, GLint *pRects)
457{
458#ifdef RT_OS_DARWIN
459 renderspu_SystemSetRootVisibleRegion(cRects, pRects);
460
461 crHashtableWalk(render_spu.windowTable, renderspuWindowVisibleRegionCB, NULL);
462#endif
463}
464
465#ifndef RT_OS_DARWIN
466void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window)
467{
468}
469#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