VirtualBox

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

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

crOpenGL: fix default mural refs

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