VirtualBox

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

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

crOpenGL->Fe/Qt notification mechanism

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