VirtualBox

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

Last change on this file since 37613 was 37613, checked in by vboxsync, 14 years ago

wddm/3d: fix snapshots with aero

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.5 KB
Line 
1/* $Id: server_muralfbo.c 37613 2011-06-23 12:42:08Z vboxsync $ */
2
3/** @file
4 * VBox crOpenGL: Window to FBO redirect support.
5 */
6
7/*
8 * Copyright (C) 2010 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 "render/renderspu.h"
23
24static int crServerGetPointScreen(GLint x, GLint y)
25{
26 int i;
27
28 for (i=0; i<cr_server.screenCount; ++i)
29 {
30 if ((x>=cr_server.screen[i].x && x<cr_server.screen[i].x+(int)cr_server.screen[i].w)
31 && (y>=cr_server.screen[i].y && y<cr_server.screen[i].y+(int)cr_server.screen[i].h))
32 {
33 return i;
34 }
35 }
36
37 return -1;
38}
39
40static GLboolean crServerMuralCoverScreen(CRMuralInfo *mural, int sId)
41{
42 return mural->gX < cr_server.screen[sId].x
43 && mural->gX+(int)mural->width > cr_server.screen[sId].x+(int)cr_server.screen[sId].w
44 && mural->gY < cr_server.screen[sId].y
45 && mural->gY+(int)mural->height > cr_server.screen[sId].y+(int)cr_server.screen[sId].h;
46}
47
48/* Called when a new CRMuralInfo is created
49 * or when OutputRedirect status is changed.
50 */
51void crServerSetupOutputRedirect(CRMuralInfo *mural)
52{
53 /* Unset the previous redirect. */
54 if (mural->pvOutputRedirectInstance)
55 {
56 cr_server.outputRedirect.CROREnd(mural->pvOutputRedirectInstance);
57 mural->pvOutputRedirectInstance = NULL;
58 }
59
60 /* Setup a new redirect. */
61 if (cr_server.bUseOutputRedirect)
62 {
63 /* Query supported formats. */
64 uint32_t cbFormats = 4096;
65 char *pachFormats = (char *)crAlloc(cbFormats);
66
67 if (pachFormats)
68 {
69 int rc = cr_server.outputRedirect.CRORContextProperty(cr_server.outputRedirect.pvContext,
70 0 /* H3DOR_PROP_FORMATS */, // @todo from a header
71 pachFormats, cbFormats, &cbFormats);
72 if (RT_SUCCESS(rc))
73 {
74 if (RTStrStr(pachFormats, "H3DOR_FMT_RGBA_TOPDOWN"))
75 {
76 cr_server.outputRedirect.CRORBegin(cr_server.outputRedirect.pvContext,
77 &mural->pvOutputRedirectInstance,
78 "H3DOR_FMT_RGBA_TOPDOWN"); // @todo from a header
79 }
80 }
81
82 crFree(pachFormats);
83 }
84
85 /* If this is not NULL then there was a supported format. */
86 if (mural->pvOutputRedirectInstance)
87 {
88 cr_server.outputRedirect.CRORGeometry(mural->pvOutputRedirectInstance,
89 mural->hX, mural->hY,
90 mural->width, mural->height);
91 // @todo the code assumes that RTRECT == four of GLInts
92 cr_server.outputRedirect.CRORVisibleRegion(mural->pvOutputRedirectInstance,
93 mural->cVisibleRects, (RTRECT *)mural->pVisibleRects);
94 }
95 }
96}
97
98void crServerCheckMuralGeometry(CRMuralInfo *mural)
99{
100 int tlS, brS, trS, blS;
101 int overlappingScreenCount, primaryS, i;
102
103 if (cr_server.screenCount<2 && !cr_server.bForceOffscreenRendering)
104 {
105 CRASSERT(cr_server.screenCount>0);
106
107 mural->hX = mural->gX-cr_server.screen[0].x;
108 mural->hY = mural->gY-cr_server.screen[0].y;
109
110 cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
111
112 return;
113 }
114
115 tlS = crServerGetPointScreen(mural->gX, mural->gY);
116 brS = crServerGetPointScreen(mural->gX+mural->width-1, mural->gY+mural->height-1);
117
118 if (tlS==brS && tlS>=0)
119 {
120 overlappingScreenCount = 1;
121 primaryS = tlS;
122 }
123 else
124 {
125 trS = crServerGetPointScreen(mural->gX+mural->width-1, mural->gY);
126 blS = crServerGetPointScreen(mural->gX, mural->gY+mural->height-1);
127
128 primaryS = -1; overlappingScreenCount = 0;
129 for (i=0; i<cr_server.screenCount; ++i)
130 {
131 if ((i==tlS) || (i==brS) || (i==trS) || (i==blS)
132 || crServerMuralCoverScreen(mural, i))
133 {
134 overlappingScreenCount++;
135 primaryS = primaryS<0 ? i:primaryS;
136 }
137 }
138
139 if (!overlappingScreenCount)
140 {
141 primaryS = 0;
142 }
143 }
144
145 if (primaryS!=mural->screenId)
146 {
147 mural->screenId = primaryS;
148
149 renderspuSetWindowId(cr_server.screen[primaryS].winID);
150 renderspuReparentWindow(mural->spuWindow);
151 renderspuSetWindowId(cr_server.screen[0].winID);
152 }
153
154 mural->hX = mural->gX-cr_server.screen[primaryS].x;
155 mural->hY = mural->gY-cr_server.screen[primaryS].y;
156
157 if (overlappingScreenCount<2 && !cr_server.bForceOffscreenRendering)
158 {
159 if (mural->bUseFBO)
160 {
161 crServerRedirMuralFBO(mural, GL_FALSE);
162 crServerDeleteMuralFBO(mural);
163 }
164
165 cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
166 }
167 else
168 {
169 if (!mural->bUseFBO)
170 {
171 crServerRedirMuralFBO(mural, GL_TRUE);
172 }
173 else
174 {
175 if (mural->width!=mural->fboWidth
176 || mural->height!=mural->height)
177 {
178 crServerRedirMuralFBO(mural, GL_FALSE);
179 crServerDeleteMuralFBO(mural);
180 crServerRedirMuralFBO(mural, GL_TRUE);
181 }
182 }
183
184 if (!mural->bUseFBO)
185 {
186 cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
187 }
188 }
189
190 if (mural->pvOutputRedirectInstance)
191 {
192 cr_server.outputRedirect.CRORGeometry(mural->pvOutputRedirectInstance,
193 mural->hX, mural->hY,
194 mural->width, mural->height);
195 }
196}
197
198GLboolean crServerSupportRedirMuralFBO(void)
199{
200 const GLubyte* pExt = cr_server.head_spu->dispatch_table.GetString(GL_REAL_EXTENSIONS);
201
202 return ( NULL!=crStrstr((const char*)pExt, "GL_ARB_framebuffer_object")
203 || NULL!=crStrstr((const char*)pExt, "GL_EXT_framebuffer_object"))
204 && NULL!=crStrstr((const char*)pExt, "GL_ARB_texture_non_power_of_two");
205}
206
207void crServerRedirMuralFBO(CRMuralInfo *mural, GLboolean redir)
208{
209 if (redir)
210 {
211 if (!crServerSupportRedirMuralFBO())
212 {
213 crWarning("FBO not supported, can't redirect window output");
214 return;
215 }
216
217 cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, GL_FALSE);
218
219 if (mural->idFBO==0)
220 {
221 crServerCreateMuralFBO(mural);
222 }
223
224 if (!crStateGetCurrent()->framebufferobject.drawFB)
225 {
226 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, mural->idFBO);
227 }
228 if (!crStateGetCurrent()->framebufferobject.readFB)
229 {
230 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, mural->idFBO);
231 }
232
233 crStateGetCurrent()->buffer.width = 0;
234 crStateGetCurrent()->buffer.height = 0;
235 }
236 else
237 {
238 cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, mural->bVisible);
239
240 if (mural->bUseFBO && crServerSupportRedirMuralFBO())
241 {
242 if (!crStateGetCurrent()->framebufferobject.drawFB)
243 {
244 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
245 }
246 if (!crStateGetCurrent()->framebufferobject.readFB)
247 {
248 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
249 }
250 }
251
252 crStateGetCurrent()->buffer.width = mural->width;
253 crStateGetCurrent()->buffer.height = mural->height;
254 }
255
256 mural->bUseFBO = redir;
257}
258
259void crServerCreateMuralFBO(CRMuralInfo *mural)
260{
261 CRContext *ctx = crStateGetCurrent();
262 GLuint uid;
263 GLenum status;
264 SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
265
266 CRASSERT(mural->idFBO==0);
267
268 /*Color texture*/
269 gl->GenTextures(1, &mural->idColorTex);
270 gl->BindTexture(GL_TEXTURE_2D, mural->idColorTex);
271 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
272 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
273 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
274 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
275 if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
276 {
277 gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
278 }
279 gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mural->width, mural->height,
280 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
281
282 /*Depth&Stencil*/
283 gl->GenRenderbuffersEXT(1, &mural->idDepthStencilRB);
284 gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
285 gl->RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
286 mural->width, mural->height);
287
288 /*FBO*/
289 gl->GenFramebuffersEXT(1, &mural->idFBO);
290 gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->idFBO);
291
292 gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
293 GL_TEXTURE_2D, mural->idColorTex, 0);
294 gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
295 GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
296 gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
297 GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
298
299 status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
300 if (status!=GL_FRAMEBUFFER_COMPLETE_EXT)
301 {
302 crWarning("FBO status(0x%x) isn't complete", status);
303 }
304
305 mural->fboWidth = mural->width;
306 mural->fboHeight = mural->height;
307
308 /*PBO*/
309 if (cr_server.bUsePBOForReadback)
310 {
311 gl->GenBuffersARB(1, &mural->idPBO);
312 gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mural->idPBO);
313 gl->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, mural->width*mural->height*4, 0, GL_STREAM_READ_ARB);
314 gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
315
316 if (!mural->idPBO)
317 {
318 crWarning("PBO create failed");
319 }
320 }
321
322 /*Restore gl state*/
323 uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid;
324 gl->BindTexture(GL_TEXTURE_2D, uid);
325
326 uid = ctx->framebufferobject.renderbuffer ? ctx->framebufferobject.renderbuffer->hwid:0;
327 gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, uid);
328
329 uid = ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0;
330 gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, uid);
331
332 uid = ctx->framebufferobject.readFB ? ctx->framebufferobject.readFB->hwid:0;
333 gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER, uid);
334
335 if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
336 {
337 gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid);
338 }
339}
340
341void crServerDeleteMuralFBO(CRMuralInfo *mural)
342{
343 CRASSERT(!mural->bUseFBO);
344
345 if (mural->idFBO!=0)
346 {
347 cr_server.head_spu->dispatch_table.DeleteTextures(1, &mural->idColorTex);
348 cr_server.head_spu->dispatch_table.DeleteRenderbuffersEXT(1, &mural->idDepthStencilRB);
349 cr_server.head_spu->dispatch_table.DeleteFramebuffersEXT(1, &mural->idFBO);
350
351 mural->idFBO = 0;
352 mural->idColorTex = 0;
353 mural->idDepthStencilRB = 0;
354 }
355
356 if (mural->idPBO!=0)
357 {
358 CRASSERT(cr_server.bUsePBOForReadback);
359 cr_server.head_spu->dispatch_table.DeleteBuffersARB(1, &mural->idPBO);
360 mural->idPBO = 0;
361 }
362}
363
364#define MIN(a, b) ((a) < (b) ? (a) : (b))
365#define MAX(a, b) ((a) > (b) ? (a) : (b))
366
367static GLboolean crServerIntersectRect(CRrecti *a, CRrecti *b, CRrecti *rect)
368{
369 CRASSERT(a && b && rect);
370
371 rect->x1 = MAX(a->x1, b->x1);
372 rect->x2 = MIN(a->x2, b->x2);
373 rect->y1 = MAX(a->y1, b->y1);
374 rect->y2 = MIN(a->y2, b->y2);
375
376 return (rect->x2>rect->x1) && (rect->y2>rect->y1);
377}
378
379static GLboolean crServerIntersectScreen(CRMuralInfo *mural, int sId, CRrecti *rect)
380{
381 rect->x1 = MAX(mural->gX, cr_server.screen[sId].x);
382 rect->x2 = MIN(mural->gX+(int)mural->fboWidth, cr_server.screen[sId].x+(int)cr_server.screen[sId].w);
383 rect->y1 = MAX(mural->gY, cr_server.screen[sId].y);
384 rect->y2 = MIN(mural->gY+(int)mural->fboHeight, cr_server.screen[sId].y+(int)cr_server.screen[sId].h);
385
386 return (rect->x2>rect->x1) && (rect->y2>rect->y1);
387}
388
389static void crServerCopySubImage(char *pDst, char* pSrc, CRrecti *pRect, int srcWidth, int srcHeight)
390{
391 int i;
392 int dstrowsize = 4*(pRect->x2-pRect->x1);
393 int srcrowsize = 4*srcWidth;
394 int height = pRect->y2-pRect->y1;
395
396 pSrc += 4*pRect->x1 + srcrowsize*(srcHeight-1-pRect->y1);
397
398 for (i=0; i<height; ++i)
399 {
400 crMemcpy(pDst, pSrc, dstrowsize);
401
402 pSrc -= srcrowsize;
403 pDst += dstrowsize;
404 }
405}
406
407static void crServerTransformRect(CRrecti *pDst, CRrecti *pSrc, int dx, int dy)
408{
409 pDst->x1 = pSrc->x1+dx;
410 pDst->x2 = pSrc->x2+dx;
411 pDst->y1 = pSrc->y1+dy;
412 pDst->y2 = pSrc->y2+dy;
413}
414
415void crServerPresentFBO(CRMuralInfo *mural)
416{
417 char *pixels=NULL, *tmppixels;
418 GLuint uid;
419 int i, j;
420 CRrecti rect, rectwr, sectr;
421 GLboolean bUsePBO;
422 CRContext *ctx = crStateGetCurrent();
423
424 CRASSERT(cr_server.pfnPresentFBO);
425
426 if (!mural->bVisible)
427 {
428 return;
429 }
430
431 if (!mural->width || !mural->height)
432 {
433 return;
434 }
435
436 if (cr_server.bUsePBOForReadback && !mural->idPBO)
437 {
438 crWarning("Mural doesn't have PBO even though bUsePBOForReadback is set!");
439 }
440
441 bUsePBO = cr_server.bUsePBOForReadback && mural->idPBO;
442
443 cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, mural->idColorTex);
444
445 if (bUsePBO)
446 {
447 CRASSERT(mural->idPBO);
448 cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mural->idPBO);
449 }
450 else
451 {
452 if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
453 {
454 cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
455 }
456
457 pixels = crAlloc(4*mural->fboWidth*mural->fboHeight);
458 if (!pixels)
459 {
460 crWarning("Out of memory in crServerPresentFBO");
461 return;
462 }
463 }
464
465 /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/
466 cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
467
468 /*restore gl state*/
469 uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid;
470 cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, uid);
471
472 if (bUsePBO)
473 {
474 pixels = cr_server.head_spu->dispatch_table.MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
475 if (!pixels)
476 {
477 crWarning("Failed to MapBuffer in crServerPresentFBO");
478 return;
479 }
480 }
481
482 for (i=0; i<cr_server.screenCount; ++i)
483 {
484 if (crServerIntersectScreen(mural, i, &rect))
485 {
486 /* rect in window relative coords */
487 crServerTransformRect(&rectwr, &rect, -mural->gX, -mural->gY);
488
489 if (!mural->pVisibleRects)
490 {
491 /*we don't get any rects info for guest compiz windows, so we treat windows as visible unless explicitly received 0 visible rects*/
492 if (!mural->bReceivedRects)
493 {
494 tmppixels = crAlloc(4*(rect.x2-rect.x1)*(rect.y2-rect.y1));
495 if (!tmppixels)
496 {
497 crWarning("Out of memory in crServerPresentFBO");
498 crFree(pixels);
499 return;
500 }
501
502 crServerCopySubImage(tmppixels, pixels, &rectwr, mural->fboWidth, mural->fboHeight);
503 /*Note: pfnPresentFBO would free tmppixels*/
504 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);
505 }
506 }
507 else
508 {
509 for (j=0; j<mural->cVisibleRects; ++j)
510 {
511 if (crServerIntersectRect(&rectwr, (CRrecti*) &mural->pVisibleRects[4*j], &sectr))
512 {
513 tmppixels = crAlloc(4*(sectr.x2-sectr.x1)*(sectr.y2-sectr.y1));
514 if (!tmppixels)
515 {
516 crWarning("Out of memory in crServerPresentFBO");
517 crFree(pixels);
518 return;
519 }
520
521 crServerCopySubImage(tmppixels, pixels, &sectr, mural->fboWidth, mural->fboHeight);
522 /*Note: pfnPresentFBO would free tmppixels*/
523 cr_server.pfnPresentFBO(tmppixels, i,
524 sectr.x1+mural->gX-cr_server.screen[i].x,
525 sectr.y1+mural->gY-cr_server.screen[i].y,
526 sectr.x2-sectr.x1, sectr.y2-sectr.y1);
527 }
528 }
529 }
530 }
531 }
532
533 if (mural->pvOutputRedirectInstance)
534 {
535 /* @todo find out why presentfbo is not called but crorframe is called. */
536 cr_server.outputRedirect.CRORFrame(mural->pvOutputRedirectInstance,
537 pixels,
538 4 * mural->fboWidth * mural->fboHeight);
539 }
540
541 if (bUsePBO)
542 {
543 cr_server.head_spu->dispatch_table.UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
544 cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
545 }
546 else
547 {
548 crFree(pixels);
549 if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
550 {
551 cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
552 }
553 }
554}
555
556GLboolean crServerIsRedirectedToFBO()
557{
558 return cr_server.curClient
559 && cr_server.curClient->currentMural
560 && cr_server.curClient->currentMural->bUseFBO;
561}
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