VirtualBox

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

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

crOpenGL: offscreen rendering & VRDP+3D-related fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.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 "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 mural->fCompositorPresented = GL_FALSE;
35
36 /*
37 * Have first SPU make a new window.
38 */
39 spuWindow = cr_server.head_spu->dispatch_table.WindowCreate( dpyName, visBits );
40 if (spuWindow < 0) {
41 CrVrScrCompositorTerm(&mural->Compositor);
42 return spuWindow;
43 }
44
45 /* get initial window size */
46 cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, spuWindow, GL_INT, 2, dims);
47
48 Tex.width = dims[0];
49 Tex.height = dims[1];
50 Tex.target = GL_TEXTURE_2D;
51 Tex.hwid = 0;
52 CrVrScrCompositorEntryInit(&mural->CEntry, &Tex);
53
54 defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0);
55 CRASSERT(defaultMural);
56 mural->gX = 0;
57 mural->gY = 0;
58 mural->width = dims[0];
59 mural->height = dims[1];
60
61 mural->spuWindow = spuWindow;
62 mural->screenId = 0;
63 mural->bVisible = GL_FALSE;
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 if (mural->fUseFBO != CR_SERVER_REDIR_NONE)
333 {
334 /* since we're going to change the current compositor & the window we need to avoid
335 * renderspu fron dealing with inconsistent data, i.e. modified compositor and
336 * still unmodified window.
337 * So what we do is:
338 * 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
339 * 2. do necessary modifications
340 * 3. (so far not needed for resize, but in case it is in the future) re-set the compositor */
341
342 /* 1. tell renderspu to stop using the current compositor (see above comment) */
343 crServerVBoxCompositionDisable(mural);
344 }
345
346 mural->fCompositorPresented = GL_FALSE;
347
348 /* 2. do necessary modifications (see above comment) */
349 /* NOTE: we can do it even if mural->fUseFBO == CR_SERVER_REDIR_NONE to make sure the compositor data is always up to date */
350 /* the compositor lock is not needed actually since we have prevented renderspu from using the compositor */
351 /* CrVrScrCompositorLock(&mural->Compositor); */
352 CrVrScrCompositorEntryRemove(&mural->Compositor, &mural->CEntry);
353 CrVrScrCompositorEntryInit(&mural->CEntry, &Tex);
354 /* initially set regions to all visible since this is what some guest assume
355 * and will not post any more visible regions command */
356 Rect.xLeft = 0;
357 Rect.xRight = width;
358 Rect.yTop = 0;
359 Rect.yBottom = height;
360 CrVrScrCompositorEntryRegionsSet(&mural->Compositor, &mural->CEntry, NULL, 1, &Rect);
361 /* CrVrScrCompositorUnlock(&mural->Compositor); */
362 mural->width = width;
363 mural->height = height;
364
365 if (cr_server.currentMural == mural)
366 {
367 crStateGetCurrent()->buffer.width = mural->width;
368 crStateGetCurrent()->buffer.height = mural->height;
369 }
370
371 crServerCheckMuralGeometry(mural);
372
373 cr_server.head_spu->dispatch_table.WindowSize(mural->spuWindow, width, height);
374
375 /* 3. (so far not needed for resize, but in case it is in the future) re-set the compositor (see above comment) */
376 /* uncomment when needed */
377 /* NOTE: !!! we have mural->fCompositorPresented set to GL_FALSE above, so crServerVBoxCompositionReenable will have no effect in any way
378 if (mural->fUseFBO != CR_SERVER_REDIR_NONE)
379 {
380 crServerVBoxCompositionReenable(mural);
381 }
382 */
383 }
384}
385
386void SERVER_DISPATCH_APIENTRY
387crServerDispatchWindowSize( GLint window, GLint width, GLint height )
388{
389 CRMuralInfo *mural;
390
391 /* crDebug("CRServer: Window %d size %d x %d", window, width, height);*/
392 mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
393 if (!mural) {
394#if EXTRA_WARN
395 crWarning("CRServer: invalid window %d passed to WindowSize()", window);
396#endif
397 return;
398 }
399
400 crServerMuralSize(mural, width, height);
401
402 if (cr_server.currentMural == mural)
403 {
404 crServerPerformMakeCurrent( mural, cr_server.currentCtxInfo );
405 }
406}
407
408
409void SERVER_DISPATCH_APIENTRY
410crServerDispatchWindowPosition( GLint window, GLint x, GLint y )
411{
412 CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
413 RTPOINT Pos;
414 /* crDebug("CRServer: Window %d pos %d, %d", window, x, y);*/
415 if (!mural) {
416#if EXTRA_WARN
417 crWarning("CRServer: invalid window %d passed to WindowPosition()", window);
418#endif
419 return;
420 }
421// if (mural->gX != x || mural->gY != y)
422 {
423 if (mural->fUseFBO != CR_SERVER_REDIR_NONE)
424 {
425 /* since we're going to change the current compositor & the window we need to avoid
426 * renderspu fron dealing with inconsistent data, i.e. modified compositor and
427 * still unmodified window.
428 * So what we do is:
429 * 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
430 * 2. do necessary modifications
431 * 3. re-set the compositor */
432
433 /* 1. tell renderspu to stop using the current compositor (see above comment) */
434 crServerVBoxCompositionDisable(mural);
435 }
436
437 /* 2. do necessary modifications (see above comment) */
438 /* NOTE: we can do it even if mural->fUseFBO == CR_SERVER_REDIR_NONE to make sure the compositor data is always up to date */
439 Pos.x = x;
440 Pos.y = y;
441
442 /* the compositor lock is not needed actually since we have prevented renderspu from using the compositor */
443 /* CrVrScrCompositorLock(&mural->Compositor); */
444 /* no need to set position because the position is relative to window */
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 crServerVBoxCompositionReenable(mural);
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 crServerVBoxCompositionDisable(mural);
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 crServerVBoxCompositionReenable(mural);
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.

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