VirtualBox

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

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

crOpenGL: 3d data visibility notifications, bugfixes

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