VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.c@ 47425

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

VRDP,Main,SharedOpenGL: enable 3d redirection if a RDP client connects

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.8 KB
Line 
1/* $Id: server_muralfbo.c 47158 2013-07-15 12:37:15Z vboxsync $ */
2
3/** @file
4 * VBox crOpenGL: Window to FBO redirect support.
5 */
6
7/*
8 * Copyright (C) 2010-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "server.h"
20#include "cr_string.h"
21#include "cr_mem.h"
22#include "cr_vreg.h"
23#include "render/renderspu.h"
24
25static int crServerGetPointScreen(GLint x, GLint y)
26{
27 int i;
28
29 for (i=0; i<cr_server.screenCount; ++i)
30 {
31 if ((x>=cr_server.screen[i].x && x<cr_server.screen[i].x+(int)cr_server.screen[i].w)
32 && (y>=cr_server.screen[i].y && y<cr_server.screen[i].y+(int)cr_server.screen[i].h))
33 {
34 return i;
35 }
36 }
37
38 return -1;
39}
40
41static GLboolean crServerMuralCoverScreen(CRMuralInfo *mural, int sId)
42{
43 return mural->gX < cr_server.screen[sId].x
44 && mural->gX+(int)mural->width > cr_server.screen[sId].x+(int)cr_server.screen[sId].w
45 && mural->gY < cr_server.screen[sId].y
46 && mural->gY+(int)mural->height > cr_server.screen[sId].y+(int)cr_server.screen[sId].h;
47}
48
49/* Called when a new CRMuralInfo is created
50 * or when OutputRedirect status is changed.
51 */
52void crServerSetupOutputRedirect(CRMuralInfo *mural)
53{
54 /* Unset the previous redirect. */
55 if (mural->pvOutputRedirectInstance)
56 {
57 cr_server.outputRedirect.CROREnd(mural->pvOutputRedirectInstance);
58 mural->pvOutputRedirectInstance = NULL;
59 }
60
61 /* Setup a new redirect. */
62 if (cr_server.bUseOutputRedirect)
63 {
64 /* Query supported formats. */
65 uint32_t cbFormats = 4096;
66 char *pachFormats = (char *)crAlloc(cbFormats);
67
68 if (pachFormats)
69 {
70 int rc = cr_server.outputRedirect.CRORContextProperty(cr_server.outputRedirect.pvContext,
71 0 /* H3DOR_PROP_FORMATS */, // @todo from a header
72 pachFormats, cbFormats, &cbFormats);
73 if (RT_SUCCESS(rc))
74 {
75 if (RTStrStr(pachFormats, "H3DOR_FMT_RGBA_TOPDOWN"))
76 {
77 cr_server.outputRedirect.CRORBegin(cr_server.outputRedirect.pvContext,
78 &mural->pvOutputRedirectInstance,
79 "H3DOR_FMT_RGBA_TOPDOWN"); // @todo from a header
80 }
81 }
82
83 crFree(pachFormats);
84 }
85
86 /* If this is not NULL then there was a supported format. */
87 if (mural->pvOutputRedirectInstance)
88 {
89 uint32_t cRects;
90 const RTRECT *pRects;
91
92 int rc = CrVrScrCompositorRegionsGet(&mural->Compositor, &cRects, NULL, &pRects, NULL);
93 if (!RT_SUCCESS(rc))
94 {
95 crWarning("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc);
96 return;
97 }
98
99 cr_server.outputRedirect.CRORGeometry(mural->pvOutputRedirectInstance,
100 mural->hX, mural->hY,
101 mural->width, mural->height);
102 // @todo the code assumes that RTRECT == four of GLInts
103 cr_server.outputRedirect.CRORVisibleRegion(mural->pvOutputRedirectInstance,
104 mural->cVisibleRects, (RTRECT *)mural->pVisibleRects);
105
106 crServerPresentFBO(mural);
107 }
108 }
109}
110
111void crServerCheckMuralGeometry(CRMuralInfo *mural)
112{
113 int tlS, brS, trS, blS;
114 int overlappingScreenCount = 0, primaryS = -1 , i;
115 uint64_t winID = 0;
116 GLuint fPresentMode;
117
118 if (!mural->CreateInfo.externalID)
119 return;
120
121 CRASSERT(mural->spuWindow);
122 CRASSERT(mural->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID);
123
124 crServerVBoxCompositionDisableEnter(mural);
125
126 if (!mural->width || !mural->height)
127 {
128 crServerRedirMuralFBO(mural, CR_SERVER_REDIR_F_NONE);
129 crServerDeleteMuralFBO(mural);
130 crServerVBoxCompositionDisableLeave(mural, GL_FALSE);
131 return;
132 }
133
134 tlS = crServerGetPointScreen(mural->gX, mural->gY);
135 brS = crServerGetPointScreen(mural->gX+mural->width-1, mural->gY+mural->height-1);
136
137 if ((tlS==brS && tlS>=0) || cr_server.screenCount <= 1)
138 {
139 if (cr_server.screenCount <= 1)
140 {
141 if (tlS != brS)
142 {
143 if (tlS >= 0)
144 brS = tlS;
145 else
146 tlS = brS;
147 }
148
149 primaryS = 0;
150 }
151
152 Assert(brS == tlS);
153
154 if (tlS>=0 && cr_server.screen[tlS].winID)
155 {
156 overlappingScreenCount = 1;
157 }
158 }
159 else
160 {
161 bool fFoundWindIdScreen = false;
162 trS = crServerGetPointScreen(mural->gX+mural->width-1, mural->gY);
163 blS = crServerGetPointScreen(mural->gX, mural->gY+mural->height-1);
164
165 primaryS = -1; overlappingScreenCount = 0;
166 for (i=0; i<cr_server.screenCount; ++i)
167 {
168 if ((i==tlS) || (i==brS) || (i==trS) || (i==blS)
169 || crServerMuralCoverScreen(mural, i))
170 {
171 if ((!fFoundWindIdScreen && cr_server.screen[i].winID) || primaryS<0)
172 primaryS = i;
173
174 if (cr_server.screen[i].winID)
175 {
176 overlappingScreenCount++;
177 fFoundWindIdScreen = true;
178 }
179 }
180 }
181
182 if (primaryS<0)
183 {
184 primaryS = 0;
185 }
186 }
187
188 winID = overlappingScreenCount ? cr_server.screen[primaryS].winID : 0;
189
190 if (!winID != !mural->fHasParentWindow
191 || (winID && primaryS!=mural->screenId))
192 {
193 mural->fHasParentWindow = !!winID;
194
195 renderspuSetWindowId(winID);
196 renderspuReparentWindow(mural->spuWindow);
197 renderspuSetWindowId(cr_server.screen[0].winID);
198
199 if (mural->bVisible && (mural->fPresentMode & CR_SERVER_REDIR_F_DISPLAY) && mural->fHasParentWindow)
200 crVBoxServerNotifyEvent(mural->screenId);
201 }
202
203 mural->screenId = primaryS;
204
205 mural->hX = mural->gX-cr_server.screen[primaryS].x;
206 mural->hY = mural->gY-cr_server.screen[primaryS].y;
207
208 fPresentMode = cr_server.fPresentMode;
209 if (!overlappingScreenCount)
210 fPresentMode &= ~CR_SERVER_REDIR_F_DISPLAY;
211 else if (overlappingScreenCount > 1)
212 fPresentMode = (fPresentMode | CR_SERVER_REDIR_F_FBO_RAM_VMFB | cr_server.fVramPresentModeDefault) & ~CR_SERVER_REDIR_F_DISPLAY;
213
214 if (!mural->fUseDefaultDEntry)
215 {
216 /* only display matters */
217 fPresentMode &= CR_SERVER_REDIR_F_DISPLAY;
218 }
219
220 fPresentMode = crServerRedirModeAdjust(fPresentMode);
221
222 if (!(fPresentMode & CR_SERVER_REDIR_F_FBO))
223 {
224 crServerRedirMuralFBO(mural, fPresentMode);
225 crServerDeleteMuralFBO(mural);
226 }
227 else
228 {
229 if (mural->fPresentMode & CR_SERVER_REDIR_F_FBO)
230 {
231 if (mural->width!=mural->fboWidth
232 || mural->height!=mural->fboHeight)
233 {
234 crServerRedirMuralFBO(mural, fPresentMode & CR_SERVER_REDIR_F_DISPLAY);
235 crServerDeleteMuralFBO(mural);
236 }
237 }
238
239 crServerRedirMuralFBO(mural, fPresentMode);
240 }
241
242 if (mural->fPresentMode & CR_SERVER_REDIR_F_DISPLAY)
243 {
244 CRScreenViewportInfo *pVieport = &cr_server.screenVieport[mural->screenId];
245
246 cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX - pVieport->x, mural->hY - pVieport->y);
247 }
248
249 if (mural->pvOutputRedirectInstance)
250 {
251 cr_server.outputRedirect.CRORGeometry(mural->pvOutputRedirectInstance,
252 mural->hX, mural->hY,
253 mural->width, mural->height);
254 }
255
256 crServerVBoxCompositionDisableLeave(mural, GL_FALSE);
257}
258
259GLboolean crServerSupportRedirMuralFBO(void)
260{
261 static GLboolean fInited = GL_FALSE;
262 static GLboolean fSupported = GL_FALSE;
263 if (!fInited)
264 {
265 const GLubyte* pExt = cr_server.head_spu->dispatch_table.GetString(GL_REAL_EXTENSIONS);
266
267 fSupported = ( NULL!=crStrstr((const char*)pExt, "GL_ARB_framebuffer_object")
268 || NULL!=crStrstr((const char*)pExt, "GL_EXT_framebuffer_object"))
269 && NULL!=crStrstr((const char*)pExt, "GL_ARB_texture_non_power_of_two");
270 fInited = GL_TRUE;
271 }
272 return fSupported;
273}
274
275static void crServerPresentMuralVRAM(CRMuralInfo *mural, char *pixels);
276
277#define CR_SERVER_MURAL_FROM_RPW_ENTRY(_pEntry) ((CRMuralInfo*)(((uint8_t*)(_pEntry)) - RT_OFFSETOF(CRMuralInfo, RpwEntry)))
278
279static DECLCALLBACK(void) crServerMuralRpwDataCB(const struct CR_SERVER_RPW_ENTRY* pEntry, void *pvEntryTexData)
280{
281 CRMuralInfo *pMural = CR_SERVER_MURAL_FROM_RPW_ENTRY(pEntry);
282
283 Assert(&pMural->RpwEntry == pEntry);
284
285 crServerPresentMuralVRAM(pMural, pvEntryTexData);
286}
287
288static void crServerCreateMuralFBO(CRMuralInfo *mural);
289
290static bool crServerEnableMuralRpw(CRMuralInfo *mural, GLboolean fEnable)
291{
292 if (!mural->CreateInfo.externalID)
293 {
294 crWarning("trying to change Rpw setting for internal mural %d", mural->spuWindow);
295 return !fEnable;
296 }
297
298 if (fEnable)
299 {
300 if (!(mural->fPresentMode & CR_SERVER_REDIR_F_FBO_RPW))
301 {
302 int rc;
303 if (!crServerRpwIsInitialized(&cr_server.RpwWorker))
304 {
305 rc = crServerRpwInit(&cr_server.RpwWorker);
306 if (!RT_SUCCESS(rc))
307 {
308 crWarning("crServerRpwInit failed rc %d", rc);
309 return false;
310 }
311 }
312
313 CRASSERT(!mural->RpwEntry.Size.cx);
314 CRASSERT(!mural->RpwEntry.Size.cy);
315
316 if (!crServerRpwEntryIsInitialized(&mural->RpwEntry))
317 {
318 rc = crServerRpwEntryInit(&cr_server.RpwWorker, &mural->RpwEntry, mural->width, mural->height, crServerMuralRpwDataCB);
319 if (!RT_SUCCESS(rc))
320 {
321 crWarning("crServerRpwEntryInit failed rc %d", rc);
322 return false;
323 }
324 }
325 else
326 {
327 rc = crServerRpwEntryResize(&cr_server.RpwWorker, &mural->RpwEntry, mural->width, mural->height);
328 if (!RT_SUCCESS(rc))
329 {
330 crWarning("crServerRpwEntryResize failed rc %d", rc);
331 return false;
332 }
333 }
334
335 mural->fPresentMode |= CR_SERVER_REDIR_F_FBO_RPW;
336 }
337 }
338 else
339 {
340 if ((mural->fPresentMode & CR_SERVER_REDIR_F_FBO_RPW))
341 {
342// crServerRpwEntryCleanup(&cr_server.RpwWorker, &mural->RpwEntry);
343 mural->fPresentMode &= ~CR_SERVER_REDIR_F_FBO_RPW;
344 }
345 }
346
347 return true;
348}
349
350static void crServerEnableDisplayMuralFBO(CRMuralInfo *mural, GLboolean fEnable)
351{
352 if (!mural->CreateInfo.externalID)
353 {
354 crWarning("trying to change display setting for internal mural %d", mural->spuWindow);
355 return;
356 }
357
358 if (fEnable)
359 {
360 if (!(mural->fPresentMode & CR_SERVER_REDIR_F_DISPLAY))
361 {
362 if (mural->bVisible && mural->fHasParentWindow)
363 {
364 cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, GL_TRUE);
365 crVBoxServerNotifyEvent(mural->screenId);
366 }
367 mural->fPresentMode |= CR_SERVER_REDIR_F_DISPLAY;
368 }
369 }
370 else
371 {
372 if ((mural->fPresentMode & CR_SERVER_REDIR_F_DISPLAY))
373 {
374 if (mural->bVisible)
375 cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, GL_FALSE);
376 mural->fPresentMode &= ~CR_SERVER_REDIR_F_DISPLAY;
377 }
378 }
379}
380
381void crServerRedirMuralFBO(CRMuralInfo *mural, GLuint redir)
382{
383 if (mural->fPresentMode == redir)
384 {
385// if (redir)
386// crWarning("crServerRedirMuralFBO called with the same redir status %d", redir);
387 return;
388 }
389
390 if (!mural->CreateInfo.externalID)
391 {
392 crWarning("trying to change redir setting for internal mural %d", mural->spuWindow);
393 return;
394 }
395
396 crServerVBoxCompositionDisableEnter(mural);
397
398 if (redir & CR_SERVER_REDIR_F_FBO)
399 {
400 if (!crServerSupportRedirMuralFBO())
401 {
402 crWarning("FBO not supported, can't redirect window output");
403 goto end;
404 }
405
406 if (mural->aidFBOs[0]==0)
407 {
408 crServerCreateMuralFBO(mural);
409 }
410
411 if (cr_server.curClient && cr_server.curClient->currentMural == mural)
412 {
413 if (!crStateGetCurrent()->framebufferobject.drawFB)
414 {
415 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer));
416 }
417 if (!crStateGetCurrent()->framebufferobject.readFB)
418 {
419 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
420 }
421
422 crStateGetCurrent()->buffer.width = 0;
423 crStateGetCurrent()->buffer.height = 0;
424 }
425 }
426 else
427 {
428 if (cr_server.curClient && cr_server.curClient->currentMural == mural)
429 {
430 if (!crStateGetCurrent()->framebufferobject.drawFB)
431 {
432 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
433 }
434 if (!crStateGetCurrent()->framebufferobject.readFB)
435 {
436 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
437 }
438
439 crStateGetCurrent()->buffer.width = mural->width;
440 crStateGetCurrent()->buffer.height = mural->height;
441 }
442 }
443
444 crServerEnableMuralRpw(mural, !!(redir & CR_SERVER_REDIR_F_FBO_RPW));
445
446 crServerEnableDisplayMuralFBO(mural, !!(redir & CR_SERVER_REDIR_F_DISPLAY));
447
448 mural->fPresentMode = redir;
449
450end:
451 crServerVBoxCompositionDisableLeave(mural, GL_FALSE);
452}
453
454static void crServerCreateMuralFBO(CRMuralInfo *mural)
455{
456 CRContext *ctx = crStateGetCurrent();
457 GLuint uid, i;
458 GLenum status;
459 SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
460 CRContextInfo *pMuralContextInfo;
461
462 CRASSERT(mural->aidFBOs[0]==0);
463 CRASSERT(mural->aidFBOs[1]==0);
464 CRASSERT(mural->fUseDefaultDEntry);
465 CRASSERT(mural->width == mural->DefaultDEntry.CEntry.Tex.width);
466 CRASSERT(mural->height == mural->DefaultDEntry.CEntry.Tex.height);
467
468 pMuralContextInfo = cr_server.currentCtxInfo;
469 if (!pMuralContextInfo)
470 {
471 /* happens on saved state load */
472 CRASSERT(cr_server.MainContextInfo.SpuContext);
473 pMuralContextInfo = &cr_server.MainContextInfo;
474 cr_server.head_spu->dispatch_table.MakeCurrent(mural->spuWindow, 0, cr_server.MainContextInfo.SpuContext);
475 }
476
477 if (pMuralContextInfo->CreateInfo.visualBits != mural->CreateInfo.visualBits)
478 {
479 crWarning("mural visual bits do not match with current context visual bits!");
480 }
481
482 mural->cBuffers = 2;
483 mural->iBbBuffer = 0;
484 /*Color texture*/
485
486 if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
487 {
488 gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
489 }
490
491 for (i = 0; i < mural->cBuffers; ++i)
492 {
493 gl->GenTextures(1, &mural->aidColorTexs[i]);
494 gl->BindTexture(GL_TEXTURE_2D, mural->aidColorTexs[i]);
495 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
496 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
497 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
498 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
499 gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mural->width, mural->height,
500 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
501 }
502
503 /*Depth&Stencil*/
504 gl->GenRenderbuffersEXT(1, &mural->idDepthStencilRB);
505 gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
506 gl->RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
507 mural->width, mural->height);
508
509 /*FBO*/
510 for (i = 0; i < mural->cBuffers; ++i)
511 {
512 gl->GenFramebuffersEXT(1, &mural->aidFBOs[i]);
513 gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->aidFBOs[i]);
514
515 gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
516 GL_TEXTURE_2D, mural->aidColorTexs[i], 0);
517 gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
518 GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
519 gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
520 GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
521
522 status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
523 if (status!=GL_FRAMEBUFFER_COMPLETE_EXT)
524 {
525 crWarning("FBO status(0x%x) isn't complete", status);
526 }
527 }
528
529 mural->fboWidth = mural->width;
530 mural->fboHeight = mural->height;
531
532 mural->iCurDrawBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer);
533 mural->iCurReadBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer);
534
535 /*PBO*/
536 if (cr_server.bUsePBOForReadback)
537 {
538 gl->GenBuffersARB(1, &mural->idPBO);
539 gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mural->idPBO);
540 gl->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, mural->width*mural->height*4, 0, GL_STREAM_READ_ARB);
541 gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
542
543 if (!mural->idPBO)
544 {
545 crWarning("PBO create failed");
546 }
547 }
548
549 /*Restore gl state*/
550 uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid;
551 gl->BindTexture(GL_TEXTURE_2D, uid);
552
553 uid = ctx->framebufferobject.renderbuffer ? ctx->framebufferobject.renderbuffer->hwid:0;
554 gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, uid);
555
556 uid = ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0;
557 gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, uid);
558
559 uid = ctx->framebufferobject.readFB ? ctx->framebufferobject.readFB->hwid:0;
560 gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER, uid);
561
562 if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
563 {
564 gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid);
565 }
566
567 if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
568 {
569 gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
570 }
571 else
572 {
573 gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
574 }
575
576 CRASSERT(mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
577
578 CrVrScrCompositorEntryTexNameUpdate(&mural->DefaultDEntry.CEntry, mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
579
580// if (mural->fRootVrOn)
581// CrVrScrCompositorEntryTexNameUpdate(&mural->DefaultDEntry.RootVrCEntry, mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
582}
583
584void crServerDeleteMuralFBO(CRMuralInfo *mural)
585{
586 CRASSERT(!(mural->fPresentMode & CR_SERVER_REDIR_F_FBO));
587
588 if (mural->aidFBOs[0]!=0)
589 {
590 GLuint i;
591 for (i = 0; i < mural->cBuffers; ++i)
592 {
593 cr_server.head_spu->dispatch_table.DeleteTextures(1, &mural->aidColorTexs[i]);
594 mural->aidColorTexs[i] = 0;
595 }
596
597 cr_server.head_spu->dispatch_table.DeleteRenderbuffersEXT(1, &mural->idDepthStencilRB);
598 mural->idDepthStencilRB = 0;
599
600 for (i = 0; i < mural->cBuffers; ++i)
601 {
602 cr_server.head_spu->dispatch_table.DeleteFramebuffersEXT(1, &mural->aidFBOs[i]);
603 mural->aidFBOs[i] = 0;
604 }
605 }
606
607 if (mural->idPBO!=0)
608 {
609 CRASSERT(cr_server.bUsePBOForReadback);
610 cr_server.head_spu->dispatch_table.DeleteBuffersARB(1, &mural->idPBO);
611 mural->idPBO = 0;
612 }
613
614 mural->cBuffers = 0;
615
616 if (crServerRpwEntryIsInitialized(&mural->RpwEntry))
617 crServerRpwEntryCleanup(&cr_server.RpwWorker, &mural->RpwEntry);
618}
619
620#define MIN(a, b) ((a) < (b) ? (a) : (b))
621#define MAX(a, b) ((a) > (b) ? (a) : (b))
622
623static GLboolean crServerIntersectRect(CRrecti *a, CRrecti *b, CRrecti *rect)
624{
625 CRASSERT(a && b && rect);
626
627 rect->x1 = MAX(a->x1, b->x1);
628 rect->x2 = MIN(a->x2, b->x2);
629 rect->y1 = MAX(a->y1, b->y1);
630 rect->y2 = MIN(a->y2, b->y2);
631
632 return (rect->x2>rect->x1) && (rect->y2>rect->y1);
633}
634
635static GLboolean crServerIntersectScreen(CRMuralInfo *mural, int sId, CRrecti *rect)
636{
637 rect->x1 = MAX(mural->gX, cr_server.screen[sId].x);
638 rect->x2 = MIN(mural->gX+(int)mural->fboWidth, cr_server.screen[sId].x+(int)cr_server.screen[sId].w);
639 rect->y1 = MAX(mural->gY, cr_server.screen[sId].y);
640 rect->y2 = MIN(mural->gY+(int)mural->fboHeight, cr_server.screen[sId].y+(int)cr_server.screen[sId].h);
641
642 return (rect->x2>rect->x1) && (rect->y2>rect->y1);
643}
644
645static void crServerCopySubImage(char *pDst, char* pSrc, CRrecti *pRect, int srcWidth, int srcHeight)
646{
647 int i;
648 int dstrowsize = 4*(pRect->x2-pRect->x1);
649 int srcrowsize = 4*srcWidth;
650 int height = pRect->y2-pRect->y1;
651
652 pSrc += 4*pRect->x1 + srcrowsize*(srcHeight-1-pRect->y1);
653
654 for (i=0; i<height; ++i)
655 {
656 crMemcpy(pDst, pSrc, dstrowsize);
657
658 pSrc -= srcrowsize;
659 pDst += dstrowsize;
660 }
661}
662
663static void crServerTransformRect(CRrecti *pDst, CRrecti *pSrc, int dx, int dy)
664{
665 pDst->x1 = pSrc->x1+dx;
666 pDst->x2 = pSrc->x2+dx;
667 pDst->y1 = pSrc->y1+dy;
668 pDst->y2 = pSrc->y2+dy;
669}
670
671static void crServerVBoxCompositionPresentPerform(CRMuralInfo *mural)
672{
673 CRMuralInfo *currentMural = cr_server.currentMural;
674 CRContextInfo *curCtxInfo = cr_server.currentCtxInfo;
675 GLuint idDrawFBO, idReadFBO;
676 CRContext *curCtx = curCtxInfo ? curCtxInfo->pContext : NULL;
677
678 CRASSERT(curCtx == crStateGetCurrent());
679
680 Assert((mural->fPresentMode & CR_SERVER_REDIR_F_FBO) || !mural->fUseDefaultDEntry);
681 Assert(mural->fPresentMode & CR_SERVER_REDIR_F_DISPLAY);
682
683 mural->fDataPresented = GL_TRUE;
684
685 if (currentMural)
686 {
687 idDrawFBO = CR_SERVER_FBO_FOR_IDX(currentMural, currentMural->iCurDrawBuffer);
688 idReadFBO = CR_SERVER_FBO_FOR_IDX(currentMural, currentMural->iCurReadBuffer);
689 }
690 else
691 {
692 idDrawFBO = 0;
693 idReadFBO = 0;
694 }
695
696 crStateSwitchPrepare(NULL, curCtx, idDrawFBO, idReadFBO);
697
698 if (!mural->fRootVrOn)
699 cr_server.head_spu->dispatch_table.VBoxPresentComposition(mural->spuWindow, &mural->Compositor, NULL);
700 else
701 cr_server.head_spu->dispatch_table.VBoxPresentComposition(mural->spuWindow, &mural->RootVrCompositor, NULL);
702
703 crStateSwitchPostprocess(curCtx, NULL, idDrawFBO, idReadFBO);
704}
705
706void crServerVBoxCompositionPresent(CRMuralInfo *mural)
707{
708 if (!crServerVBoxCompositionPresentNeeded(mural))
709 return;
710 crServerVBoxCompositionPresentPerform(mural);
711}
712
713static void crServerVBoxCompositionReenable(CRMuralInfo *mural, GLboolean fForcePresent)
714{
715 if (!(mural->fPresentMode & CR_SERVER_REDIR_F_DISPLAY)
716 || (mural->fUseDefaultDEntry && !(mural->fPresentMode & CR_SERVER_REDIR_F_FBO))
717 || !mural->fDataPresented
718 || (!fForcePresent
719 && !crServerVBoxCompositionPresentNeeded(mural)))
720 return;
721
722 crServerVBoxCompositionPresentPerform(mural);
723}
724
725static void crServerVBoxCompositionDisable(CRMuralInfo *mural)
726{
727 if ((mural->fPresentMode & (CR_SERVER_REDIR_F_FBO | CR_SERVER_REDIR_F_DISPLAY)) != (CR_SERVER_REDIR_F_FBO | CR_SERVER_REDIR_F_DISPLAY)
728 || !mural->fDataPresented)
729 return;
730 cr_server.head_spu->dispatch_table.VBoxPresentComposition(mural->spuWindow, NULL, NULL);
731}
732
733void crServerVBoxCompositionDisableEnter(CRMuralInfo *mural)
734{
735 ++mural->cDisabled;
736 Assert(mural->cDisabled);
737 if (mural->cDisabled == 1)
738 {
739 crServerVBoxCompositionDisable(mural);
740 }
741}
742
743void crServerVBoxCompositionDisableLeave(CRMuralInfo *mural, GLboolean fForcePresentOnEnabled)
744{
745 mural->fForcePresentState = fForcePresentOnEnabled;
746 --mural->cDisabled;
747 Assert(mural->cDisabled < UINT32_MAX/2);
748 if (!mural->cDisabled)
749 {
750 crServerVBoxCompositionReenable(mural, mural->fForcePresentState);
751 mural->fForcePresentState = GL_FALSE;
752 }
753}
754
755static void crServerVBoxCompositionSetEnableStateGlobalCB(unsigned long key, void *data1, void *data2)
756{
757 CRMuralInfo *mural = (CRMuralInfo *)data1;
758
759 if (data2)
760 crServerVBoxCompositionDisableLeave(mural, GL_FALSE);
761 else
762 crServerVBoxCompositionDisableEnter(mural);
763}
764
765DECLEXPORT(void) crServerVBoxCompositionSetEnableStateGlobal(GLboolean fEnable)
766{
767 if (!fEnable)
768 ++cr_server.cDisableEvent;
769
770 crHashtableWalk(cr_server.muralTable, crServerVBoxCompositionSetEnableStateGlobalCB, (void*)(uintptr_t)fEnable);
771
772 crHashtableWalk(cr_server.dummyMuralTable, crServerVBoxCompositionSetEnableStateGlobalCB, (void*)(uintptr_t)fEnable);
773
774 if (fEnable)
775 {
776 --cr_server.cDisableEvent;
777 CRASSERT(cr_server.cDisableEvent < UINT32_MAX/2);
778 if(!cr_server.cDisableEvent)
779 {
780 int i;
781 for (i = 0; i < cr_server.screenCount; ++i)
782 {
783 if (!ASMBitTest(cr_server.NotifyEventMap, i))
784 continue;
785
786 cr_server.pfnNotifyEventCB(i, VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_WINDOW, NULL);
787
788 ASMBitClear(cr_server.NotifyEventMap, i);
789 }
790 }
791 }
792}
793
794static void crServerPresentMuralVRAM(CRMuralInfo *mural, char *pixels)
795{
796 char *tmppixels;
797 CRrecti rect, rectwr, sectr;
798 int i, j;
799
800 if (mural->fPresentMode & CR_SERVER_REDIR_F_FBO_RAM_VMFB)
801 {
802 for (i=0; i<cr_server.screenCount; ++i)
803 {
804 if (crServerIntersectScreen(mural, i, &rect))
805 {
806 /* rect in window relative coords */
807 crServerTransformRect(&rectwr, &rect, -mural->gX, -mural->gY);
808
809 if (!mural->pVisibleRects)
810 {
811 /*we don't get any rects info for guest compiz windows, so we treat windows as visible unless explicitly received 0 visible rects*/
812 if (!mural->bReceivedRects)
813 {
814 tmppixels = crAlloc(4*(rect.x2-rect.x1)*(rect.y2-rect.y1));
815 if (!tmppixels)
816 {
817 crWarning("Out of memory in crServerPresentFBO");
818 crFree(pixels);
819 return;
820 }
821
822 crServerCopySubImage(tmppixels, pixels, &rectwr, mural->fboWidth, mural->fboHeight);
823 /*Note: pfnPresentFBO would free tmppixels*/
824 cr_server.pfnPresentFBO(tmppixels, i, rect.x1-cr_server.screen[i].x, rect.y1-cr_server.screen[i].y, rect.x2-rect.x1, rect.y2-rect.y1);
825 }
826 }
827 else
828 {
829 for (j=0; j<mural->cVisibleRects; ++j)
830 {
831 if (crServerIntersectRect(&rectwr, (CRrecti*) &mural->pVisibleRects[4*j], &sectr))
832 {
833 tmppixels = crAlloc(4*(sectr.x2-sectr.x1)*(sectr.y2-sectr.y1));
834 if (!tmppixels)
835 {
836 crWarning("Out of memory in crServerPresentFBO");
837 crFree(pixels);
838 return;
839 }
840
841 crServerCopySubImage(tmppixels, pixels, &sectr, mural->fboWidth, mural->fboHeight);
842 /*Note: pfnPresentFBO would free tmppixels*/
843 cr_server.pfnPresentFBO(tmppixels, i,
844 sectr.x1+mural->gX-cr_server.screen[i].x,
845 sectr.y1+mural->gY-cr_server.screen[i].y,
846 sectr.x2-sectr.x1, sectr.y2-sectr.y1);
847 }
848 }
849 }
850 }
851 }
852 }
853
854 if (mural->pvOutputRedirectInstance)
855 {
856 /* @todo find out why presentfbo is not called but crorframe is called. */
857 cr_server.outputRedirect.CRORFrame(mural->pvOutputRedirectInstance,
858 pixels,
859 4 * mural->fboWidth * mural->fboHeight);
860 }
861}
862
863void crServerPresentFBO(CRMuralInfo *mural)
864{
865 char *pixels=NULL;
866 GLuint idPBO;
867 CRContext *ctx = crStateGetCurrent();
868 VBOXVR_TEXTURE Tex;
869
870 CRASSERT(mural->fPresentMode & CR_SERVER_REDIR_F_FBO);
871 CRASSERT(cr_server.pfnPresentFBO || (mural->fPresentMode & CR_SERVER_REDIR_F_DISPLAY));
872
873 if (!crServerVBoxCompositionPresentNeeded(mural))
874 return;
875
876 if (mural->fPresentMode & CR_SERVER_REDIR_F_DISPLAY)
877 {
878 crServerVBoxCompositionPresentPerform(mural);
879 }
880
881 mural->fDataPresented = GL_TRUE;
882
883 if (!(mural->fPresentMode & CR_SERVER_REDIR_FGROUP_REQUIRE_FBO_RAM))
884 return;
885
886 Tex.width = mural->width;
887 Tex.height = mural->height;
888 Tex.target = GL_TEXTURE_2D;
889 Tex.hwid = mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)];
890 CRASSERT(Tex.hwid);
891
892 if (mural->fPresentMode & CR_SERVER_REDIR_F_FBO_RPW)
893 {
894 /* 1. blit to RPW entry draw texture */
895 CRMuralInfo *pCurrentMural = cr_server.currentMural;
896 CRContextInfo *pCurCtxInfo = cr_server.currentCtxInfo;
897 PCR_BLITTER pBlitter = crServerVBoxBlitterGet();
898 CRMuralInfo *pBlitterMural;
899 CR_SERVER_CTX_SWITCH CtxSwitch;
900 RTRECT Rect;
901 VBOXVR_TEXTURE DstTex;
902 CR_BLITTER_WINDOW BlitterBltInfo, CurrentBltInfo;
903 CR_BLITTER_CONTEXT CtxBltInfo;
904 int rc;
905
906 Rect.xLeft = 0;
907 Rect.yTop = 0;
908 Rect.xRight = Tex.width;
909 Rect.yBottom = Tex.height;
910
911 if (pCurrentMural && pCurrentMural->CreateInfo.visualBits == CrBltGetVisBits(pBlitter))
912 {
913 pBlitterMural = pCurrentMural;
914 }
915 else
916 {
917 pBlitterMural = crServerGetDummyMural(pCurrentMural->CreateInfo.visualBits);
918 if (!pBlitterMural)
919 {
920 crWarning("crServerGetDummyMural failed for blitter mural");
921 return;
922 }
923 }
924
925 crServerRpwEntryDrawSettingsToTex(&mural->RpwEntry, &DstTex);
926
927 crServerCtxSwitchPrepare(&CtxSwitch, NULL);
928
929 crServerVBoxBlitterWinInit(&CurrentBltInfo, pCurrentMural);
930 crServerVBoxBlitterWinInit(&BlitterBltInfo, pBlitterMural);
931 crServerVBoxBlitterCtxInit(&CtxBltInfo, pCurCtxInfo);
932
933 CrBltMuralSetCurrent(pBlitter, &BlitterBltInfo);
934
935 rc = CrBltEnter(pBlitter, &CtxBltInfo, &CurrentBltInfo);
936 if (RT_SUCCESS(rc))
937 {
938 CrBltBlitTexTex(pBlitter, &Tex, &Rect, &DstTex, &Rect, 1, 0);
939 CrBltLeave(pBlitter);
940 }
941 else
942 {
943 crWarning("CrBltEnter failed rc %d", rc);
944 }
945
946 crServerCtxSwitchPostprocess(&CtxSwitch);
947
948#if 1
949 if (RT_SUCCESS(rc))
950 {
951 /* 2. submit RPW entry */
952 rc = crServerRpwEntrySubmit(&cr_server.RpwWorker, &mural->RpwEntry);
953 if (!RT_SUCCESS(rc))
954 {
955 crWarning("crServerRpwEntrySubmit failed rc %d", rc);
956 }
957 }
958#endif
959 return;
960 }
961
962 if (cr_server.bUsePBOForReadback && !mural->idPBO)
963 {
964 crWarning("Mural doesn't have PBO even though bUsePBOForReadback is set!");
965 }
966
967 idPBO = cr_server.bUsePBOForReadback ? mural->idPBO : 0;
968 if (idPBO)
969 {
970 CRASSERT(mural->fboWidth == mural->width);
971 CRASSERT(mural->fboHeight == mural->height);
972 }
973
974 pixels = CrHlpGetTexImage(ctx, &Tex, idPBO, GL_BGRA);
975 if (!pixels)
976 {
977 crWarning("CrHlpGetTexImage failed in crServerPresentFBO");
978 return;
979 }
980
981 crServerPresentMuralVRAM(mural, pixels);
982
983 CrHlpFreeTexImage(ctx, idPBO, pixels);
984}
985
986GLboolean crServerIsRedirectedToFBO()
987{
988#ifdef DEBUG_misha
989 Assert(cr_server.curClient);
990 if (cr_server.curClient)
991 {
992 Assert(cr_server.curClient->currentMural == cr_server.currentMural);
993 Assert(cr_server.curClient->currentCtxInfo == cr_server.currentCtxInfo);
994 }
995#endif
996 return cr_server.curClient
997 && cr_server.curClient->currentMural
998 && (cr_server.curClient->currentMural->fPresentMode & CR_SERVER_REDIR_F_FBO);
999}
1000
1001GLint crServerMuralFBOIdxFromBufferName(CRMuralInfo *mural, GLenum buffer)
1002{
1003 switch (buffer)
1004 {
1005 case GL_FRONT:
1006 case GL_FRONT_LEFT:
1007 case GL_FRONT_RIGHT:
1008 return CR_SERVER_FBO_FB_IDX(mural);
1009 case GL_BACK:
1010 case GL_BACK_LEFT:
1011 case GL_BACK_RIGHT:
1012 return CR_SERVER_FBO_BB_IDX(mural);
1013 case GL_NONE:
1014 case GL_AUX0:
1015 case GL_AUX1:
1016 case GL_AUX2:
1017 case GL_AUX3:
1018 case GL_LEFT:
1019 case GL_RIGHT:
1020 case GL_FRONT_AND_BACK:
1021 return -1;
1022 default:
1023 crWarning("crServerMuralFBOIdxFromBufferName: invalid buffer passed 0x%x", buffer);
1024 return -2;
1025 }
1026}
1027
1028void crServerMuralFBOSwapBuffers(CRMuralInfo *mural)
1029{
1030 CRContext *ctx = crStateGetCurrent();
1031 GLuint iOldCurDrawBuffer = mural->iCurDrawBuffer;
1032 GLuint iOldCurReadBuffer = mural->iCurReadBuffer;
1033 mural->iBbBuffer = ((mural->iBbBuffer + 1) % (mural->cBuffers));
1034 if (mural->iCurDrawBuffer >= 0)
1035 mural->iCurDrawBuffer = ((mural->iCurDrawBuffer + 1) % (mural->cBuffers));
1036 if (mural->iCurReadBuffer >= 0)
1037 mural->iCurReadBuffer = ((mural->iCurReadBuffer + 1) % (mural->cBuffers));
1038 Assert(iOldCurDrawBuffer != mural->iCurDrawBuffer || mural->cBuffers == 1 || mural->iCurDrawBuffer < 0);
1039 Assert(iOldCurReadBuffer != mural->iCurReadBuffer || mural->cBuffers == 1 || mural->iCurReadBuffer < 0);
1040 if (!ctx->framebufferobject.drawFB && iOldCurDrawBuffer != mural->iCurDrawBuffer)
1041 {
1042 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer));
1043 }
1044 if (!ctx->framebufferobject.readFB && iOldCurReadBuffer != mural->iCurReadBuffer)
1045 {
1046 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
1047 }
1048 Assert(mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
1049 Assert(mural->fUseDefaultDEntry);
1050 CrVrScrCompositorEntryTexNameUpdate(&mural->DefaultDEntry.CEntry, mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
1051 if (mural->fRootVrOn)
1052 CrVrScrCompositorEntryTexNameUpdate(&mural->DefaultDEntry.RootVrCEntry, mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
1053}
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