VirtualBox

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

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

crOpenGL: saved state and dummy mural/context fixes

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