VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c@ 45066

Last change on this file since 45066 was 45066, checked in by vboxsync, 12 years ago

crOpenGL: misc bugfixes & cleanups

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.6 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 "server.h"
8#include "server_dispatch.h"
9#include "cr_mem.h"
10#include "cr_rand.h"
11#include "cr_string.h"
12
13GLint SERVER_DISPATCH_APIENTRY
14crServerDispatchWindowCreate(const char *dpyName, GLint visBits)
15{
16 return crServerDispatchWindowCreateEx(dpyName, visBits, -1);
17}
18
19GLint crServerMuralInit(CRMuralInfo *mural, const char *dpyName, GLint visBits, GLint preloadWinID)
20{
21 CRMuralInfo *defaultMural;
22 GLint dims[2];
23 GLint windowID = -1;
24 GLint spuWindow;
25 VBOXVR_TEXTURE Tex = {0};
26
27 int rc = CrVrScrCompositorInit(&mural->Compositor);
28 if (!RT_SUCCESS(rc))
29 {
30 crWarning("CrVrScrCompositorInit failed, rc %d", rc);
31 return -1;
32 }
33
34 /*
35 * Have first SPU make a new window.
36 */
37 spuWindow = cr_server.head_spu->dispatch_table.WindowCreate( dpyName, visBits );
38 if (spuWindow < 0) {
39 CrVrScrCompositorTerm(&mural->Compositor);
40 return spuWindow;
41 }
42
43 /* get initial window size */
44 cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, spuWindow, GL_INT, 2, dims);
45
46 Tex.width = dims[0];
47 Tex.height = dims[1];
48 Tex.target = GL_TEXTURE_2D;
49 Tex.hwid = 0;
50 CrVrScrCompositorEntryInit(&mural->CEntry, &Tex);
51
52 defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0);
53 CRASSERT(defaultMural);
54 mural->gX = 0;
55 mural->gY = 0;
56 mural->width = dims[0];
57 mural->height = dims[1];
58
59 cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_VISIBILITY_CR, spuWindow, GL_INT, 1, dims);
60
61 mural->spuWindow = spuWindow;
62 mural->screenId = 0;
63 mural->bVisible = !!dims[0];
64 mural->fUseFBO = CR_SERVER_REDIR_NONE;
65
66 mural->cVisibleRects = 0;
67 mural->pVisibleRects = NULL;
68 mural->bReceivedRects = GL_FALSE;
69
70 mural->pvOutputRedirectInstance = NULL;
71
72 /* generate ID for this new window/mural (special-case for file conns) */
73 if (cr_server.curClient && cr_server.curClient->conn->type == CR_FILE)
74 windowID = spuWindow;
75 else
76 windowID = preloadWinID<0 ? (GLint)crHashtableAllocKeys( cr_server.muralTable, 1 ) : preloadWinID;
77
78 mural->CreateInfo.visualBits = visBits;
79 mural->CreateInfo.externalID = windowID;
80 mural->CreateInfo.pszDpyName = dpyName ? crStrdup(dpyName) : NULL;
81
82 CR_STATE_SHAREDOBJ_USAGE_INIT(mural);
83
84 crServerSetupOutputRedirect(mural);
85
86 return windowID;
87}
88
89GLint
90crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preloadWinID)
91{
92 CRMuralInfo *mural;
93 GLint windowID = -1;
94
95 dpyName = "";
96
97 if (cr_server.sharedWindows) {
98 int pos, j;
99
100 /* find empty position in my (curclient) windowList */
101 for (pos = 0; pos < CR_MAX_WINDOWS; pos++) {
102 if (cr_server.curClient->windowList[pos] == 0) {
103 break;
104 }
105 }
106 if (pos == CR_MAX_WINDOWS) {
107 crWarning("Too many windows in crserver!");
108 return -1;
109 }
110
111 /* Look if any other client has a window for this slot */
112 for (j = 0; j < cr_server.numClients; j++) {
113 if (cr_server.clients[j]->windowList[pos] != 0) {
114 /* use that client's window */
115 windowID = cr_server.clients[j]->windowList[pos];
116 cr_server.curClient->windowList[pos] = windowID;
117 crServerReturnValue( &windowID, sizeof(windowID) ); /* real return value */
118 crDebug("CRServer: client %p sharing window %d",
119 cr_server.curClient, windowID);
120 return windowID;
121 }
122 }
123 }
124
125
126 /*
127 * Create a new mural for the new window.
128 */
129 mural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
130 if (!mural)
131 {
132 crWarning("crCalloc failed!");
133 return -1;
134 }
135
136 windowID = crServerMuralInit(mural, dpyName, visBits, preloadWinID);
137 if (windowID < 0)
138 {
139 crWarning("crServerMuralInit failed!");
140 crServerReturnValue( &windowID, sizeof(windowID) );
141 crFree(mural);
142 return windowID;
143 }
144
145 crHashtableAdd(cr_server.muralTable, windowID, mural);
146
147 crDebug("CRServer: client %p created new window %d (SPU window %d)",
148 cr_server.curClient, windowID, mural->spuWindow);
149
150 if (windowID != -1 && !cr_server.bIsInLoadingState) {
151 int pos;
152 for (pos = 0; pos < CR_MAX_WINDOWS; pos++) {
153 if (cr_server.curClient->windowList[pos] == 0) {
154 cr_server.curClient->windowList[pos] = windowID;
155 break;
156 }
157 }
158 }
159
160 /* ensure we have a dummy mural created right away to avoid potential deadlocks on VM shutdown */
161 crServerGetDummyMural(mural->CreateInfo.visualBits);
162
163 crServerReturnValue( &windowID, sizeof(windowID) );
164 return windowID;
165}
166
167static int crServerRemoveClientWindow(CRClient *pClient, GLint window)
168{
169 int pos;
170
171 for (pos = 0; pos < CR_MAX_WINDOWS; ++pos)
172 {
173 if (pClient->windowList[pos] == window)
174 {
175 pClient->windowList[pos] = 0;
176 return true;
177 }
178 }
179
180 return false;
181}
182
183void crServerMuralTerm(CRMuralInfo *mural)
184{
185 if (mural->pvOutputRedirectInstance)
186 {
187 cr_server.outputRedirect.CROREnd(mural->pvOutputRedirectInstance);
188 mural->pvOutputRedirectInstance = NULL;
189 }
190
191 crServerRedirMuralFBO(mural, CR_SERVER_REDIR_NONE);
192 crServerDeleteMuralFBO(mural);
193
194 if (cr_server.currentMural == mural)
195 {
196 CRMuralInfo *dummyMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
197 /* reset the current context to some dummy values to ensure render spu does not switch to a default "0" context,
198 * which might lead to muralFBO (offscreen rendering) gl entities being created in a scope of that context */
199 cr_server.head_spu->dispatch_table.MakeCurrent(dummyMural->spuWindow, 0, cr_server.MainContextInfo.SpuContext);
200 cr_server.currentWindow = -1;
201 cr_server.currentMural = NULL;
202 }
203 else
204 {
205 CRASSERT(cr_server.currentWindow != mural->CreateInfo.externalID);
206 }
207
208
209 cr_server.head_spu->dispatch_table.WindowDestroy( mural->spuWindow );
210
211 if (mural->pVisibleRects)
212 {
213 crFree(mural->pVisibleRects);
214 }
215
216 if (mural->CreateInfo.pszDpyName)
217 crFree(mural->CreateInfo.pszDpyName);
218}
219
220static void crServerCleanupCtxMuralRefsCB(unsigned long key, void *data1, void *data2)
221{
222 CRContextInfo *ctxInfo = (CRContextInfo *) data1;
223 CRMuralInfo *mural = (CRMuralInfo *) data2;
224
225 if (ctxInfo->currentMural == mural)
226 ctxInfo->currentMural = NULL;
227}
228
229void SERVER_DISPATCH_APIENTRY
230crServerDispatchWindowDestroy( GLint window )
231{
232 CRMuralInfo *mural;
233 int32_t client;
234 CRClientNode *pNode;
235 int found=false;
236
237 if (!window)
238 {
239 crWarning("Unexpected attempt to delete default mural, ignored!");
240 return;
241 }
242
243 mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
244 if (!mural) {
245 crWarning("CRServer: invalid window %d passed to WindowDestroy()", window);
246 return;
247 }
248
249 crDebug("CRServer: Destroying window %d (spu window %d)", window, mural->spuWindow);
250
251 crHashtableWalk(cr_server.contextTable, crServerCleanupCtxMuralRefsCB, mural);
252
253 crServerMuralTerm(mural);
254
255 CRASSERT(cr_server.currentWindow != window);
256
257 if (cr_server.curClient)
258 {
259 if (cr_server.curClient->currentMural == mural)
260 {
261 cr_server.curClient->currentMural = NULL;
262 cr_server.curClient->currentWindow = -1;
263 }
264
265 found = crServerRemoveClientWindow(cr_server.curClient, window);
266
267 /*Same as with contexts, some apps destroy it not in a thread where it was created*/
268 if (!found)
269 {
270 for (client=0; client<cr_server.numClients; ++client)
271 {
272 if (cr_server.clients[client]==cr_server.curClient)
273 continue;
274
275 found = crServerRemoveClientWindow(cr_server.clients[client], window);
276
277 if (found) break;
278 }
279 }
280
281 if (!found)
282 {
283 pNode=cr_server.pCleanupClient;
284
285 while (pNode && !found)
286 {
287 found = crServerRemoveClientWindow(pNode->pClient, window);
288 pNode = pNode->next;
289 }
290 }
291
292 CRASSERT(found);
293 }
294
295 /*Make sure this window isn't active in other clients*/
296 for (client=0; client<cr_server.numClients; ++client)
297 {
298 if (cr_server.clients[client]->currentMural == mural)
299 {
300 cr_server.clients[client]->currentMural = NULL;
301 cr_server.clients[client]->currentWindow = -1;
302 }
303 }
304
305 pNode=cr_server.pCleanupClient;
306 while (pNode)
307 {
308 if (pNode->pClient->currentMural == mural)
309 {
310 pNode->pClient->currentMural = NULL;
311 pNode->pClient->currentWindow = -1;
312 }
313 pNode = pNode->next;
314 }
315
316 CrVrScrCompositorTerm(&mural->Compositor);
317
318 crHashtableDelete(cr_server.muralTable, window, crFree);
319}
320
321void crServerMuralSize(CRMuralInfo *mural, GLint width, GLint height)
322{
323 if (mural->width != width || mural->height != height)
324 {
325 RTRECT Rect;
326 VBOXVR_TEXTURE Tex;
327 Tex.width = width;
328 Tex.height = height;
329 Tex.target = GL_TEXTURE_2D;
330 Tex.hwid = 0;
331
332
333 /* since we're going to change the current compositor & the window we need to avoid
334 * renderspu fron dealing with inconsistent data, i.e. modified compositor and
335 * still unmodified window.
336 * So what we do is:
337 * 1. tell renderspu to stop using the current compositor -> renderspu would do necessary synchronization with its redraw thread to ensure compositor is no longer used
338 * 2. do necessary modifications
339 * 3. (so far not needed for resize, but in case it is in the future) re-set the compositor */
340
341 /* 1. tell renderspu to stop using the current compositor (see above comment) */
342 crServerVBoxCompositionDisable(mural);
343
344 /* 2. do necessary modifications (see above comment) */
345 /* NOTE: we can do it even if mural->fUseFBO == CR_SERVER_REDIR_NONE to make sure the compositor data is always up to date */
346 /* the compositor lock is not needed actually since we have prevented renderspu from using the compositor */
347 /* CrVrScrCompositorLock(&mural->Compositor); */
348 CrVrScrCompositorEntryRemove(&mural->Compositor, &mural->CEntry);
349 CrVrScrCompositorEntryInit(&mural->CEntry, &Tex);
350 /* initially set regions to all visible since this is what some guest assume
351 * and will not post any more visible regions command */
352 Rect.xLeft = 0;
353 Rect.xRight = width;
354 Rect.yTop = 0;
355 Rect.yBottom = height;
356 CrVrScrCompositorEntryRegionsSet(&mural->Compositor, &mural->CEntry, NULL, 1, &Rect);
357 /* CrVrScrCompositorUnlock(&mural->Compositor); */
358 mural->width = width;
359 mural->height = height;
360
361 if (cr_server.currentMural == mural)
362 {
363 crStateGetCurrent()->buffer.width = mural->width;
364 crStateGetCurrent()->buffer.height = mural->height;
365 }
366
367 crServerCheckMuralGeometry(mural);
368
369 cr_server.head_spu->dispatch_table.WindowSize(mural->spuWindow, width, height);
370
371 /* 3. (so far not needed for resize, but in case it is in the future) re-set the compositor (see above comment) */
372 /* uncomment when needed */
373 /* NOTE: !!! we have mural->fHasPresentationData set to GL_FALSE above, so crServerVBoxCompositionReenable will have no effect in any way
374 crServerVBoxCompositionReenable(mural);
375 */
376 }
377}
378
379void SERVER_DISPATCH_APIENTRY
380crServerDispatchWindowSize( GLint window, GLint width, GLint height )
381{
382 CRMuralInfo *mural;
383
384 /* crDebug("CRServer: Window %d size %d x %d", window, width, height);*/
385 mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
386 if (!mural) {
387#if EXTRA_WARN
388 crWarning("CRServer: invalid window %d passed to WindowSize()", window);
389#endif
390 return;
391 }
392
393 crServerMuralSize(mural, width, height);
394
395 if (cr_server.currentMural == mural)
396 {
397 crServerPerformMakeCurrent( mural, cr_server.currentCtxInfo );
398 }
399}
400
401
402void SERVER_DISPATCH_APIENTRY
403crServerDispatchWindowPosition( GLint window, GLint x, GLint y )
404{
405 CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
406 RTPOINT Pos;
407 /* crDebug("CRServer: Window %d pos %d, %d", window, x, y);*/
408 if (!mural) {
409#if EXTRA_WARN
410 crWarning("CRServer: invalid window %d passed to WindowPosition()", window);
411#endif
412 return;
413 }
414// if (mural->gX != x || mural->gY != y)
415 {
416 /* since we're going to change the current compositor & the window we need to avoid
417 * renderspu fron dealing with inconsistent data, i.e. modified compositor and
418 * still unmodified window.
419 * So what we do is:
420 * 1. tell renderspu to stop using the current compositor -> renderspu would do necessary synchronization with its redraw thread to ensure compositor is no longer used
421 * 2. do necessary modifications
422 * 3. re-set the compositor */
423
424 /* 1. tell renderspu to stop using the current compositor (see above comment) */
425 crServerVBoxCompositionDisable(mural);
426
427 /* 2. do necessary modifications (see above comment) */
428 /* NOTE: we can do it even if mural->fUseFBO == CR_SERVER_REDIR_NONE to make sure the compositor data is always up to date */
429 Pos.x = x;
430 Pos.y = y;
431
432 /* the compositor lock is not needed actually since we have prevented renderspu from using the compositor */
433 /* CrVrScrCompositorLock(&mural->Compositor); */
434 /* no need to set position because the position is relative to window */
435 /*CrVrScrCompositorEntryPosSet(&mural->Compositor, &mural->CEntry, &Pos);*/
436 /*CrVrScrCompositorUnlock(&mural->Compositor);*/
437
438 mural->gX = x;
439 mural->gY = y;
440
441 crServerCheckMuralGeometry(mural);
442
443 /* 3. re-set the compositor (see above comment) */
444 crServerVBoxCompositionReenable(mural, GL_FALSE);
445 }
446}
447
448void SERVER_DISPATCH_APIENTRY
449crServerDispatchWindowVisibleRegion( GLint window, GLint cRects, GLint *pRects )
450{
451 CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
452 GLboolean fForcePresent = crServerVBoxCompositionPresentNeeded(mural);
453 if (!mural) {
454#if EXTRA_WARN
455 crWarning("CRServer: invalid window %d passed to WindowVisibleRegion()", window);
456#endif
457 return;
458 }
459
460 /* since we're going to change the current compositor & the window we need to avoid
461 * renderspu fron dealing with inconsistent data, i.e. modified compositor and
462 * still unmodified window.
463 * So what we do is:
464 * 1. tell renderspu to stop using the current compositor -> renderspu would do necessary synchronization with its redraw thread to ensure compositor is no longer used
465 * 2. do necessary modifications
466 * 3. re-set the compositor */
467
468 /* 1. tell renderspu to stop using the current compositor (see above comment) */
469 crServerVBoxCompositionDisable(mural);
470
471 /* 2. do necessary modifications (see above comment) */
472 /* NOTE: we can do it even if mural->fUseFBO = CR_SERVER_REDIR_NONE to make sure the compositor data is always up to date */
473 /* the compositor lock is not needed actually since we have prevented renderspu from using the compositor */
474 /* CrVrScrCompositorLock(&mural->Compositor); */
475 CrVrScrCompositorEntryRegionsSet(&mural->Compositor, &mural->CEntry, NULL, cRects, (const RTRECT *)pRects);
476 /*CrVrScrCompositorUnlock(&mural->Compositor);*/
477
478 if (mural->pVisibleRects)
479 {
480 crFree(mural->pVisibleRects);
481 mural->pVisibleRects = NULL;
482 }
483
484 mural->cVisibleRects = cRects;
485 mural->bReceivedRects = GL_TRUE;
486 if (cRects)
487 {
488 mural->pVisibleRects = (GLint*) crAlloc(4*sizeof(GLint)*cRects);
489 if (!mural->pVisibleRects)
490 {
491 crError("Out of memory in crServerDispatchWindowVisibleRegion");
492 }
493 crMemcpy(mural->pVisibleRects, pRects, 4*sizeof(GLint)*cRects);
494 }
495
496 cr_server.head_spu->dispatch_table.WindowVisibleRegion(mural->spuWindow, cRects, pRects);
497
498 if (mural->pvOutputRedirectInstance)
499 {
500 /* @todo the code assumes that RTRECT == four GLInts. */
501 cr_server.outputRedirect.CRORVisibleRegion(mural->pvOutputRedirectInstance,
502 cRects, (RTRECT *)pRects);
503 }
504
505 /* 3. re-set the compositor (see above comment) */
506 crServerVBoxCompositionReenable(mural, fForcePresent);
507}
508
509void SERVER_DISPATCH_APIENTRY
510crServerDispatchWindowShow( GLint window, GLint state )
511{
512 CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
513 if (!mural) {
514#if EXTRA_WARN
515 crWarning("CRServer: invalid window %d passed to WindowShow()", window);
516#endif
517 return;
518 }
519
520 if (mural->fUseFBO != CR_SERVER_REDIR_FBO_RAM)
521 {
522 cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, state);
523 }
524
525 mural->bVisible = state;
526}
527
528
529GLint
530crServerSPUWindowID(GLint serverWindow)
531{
532 CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, serverWindow);
533 if (!mural) {
534#if EXTRA_WARN
535 crWarning("CRServer: invalid window %d passed to crServerSPUWindowID()",
536 serverWindow);
537#endif
538 return -1;
539 }
540 return mural->spuWindow;
541}
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