VirtualBox

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

Last change on this file since 50095 was 50095, checked in by vboxsync, 11 years ago

crOpenGL: presentation infrastructure rework (still work in progress)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette