VirtualBox

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

Last change on this file since 28534 was 28534, checked in by vboxsync, 15 years ago

crOpenGL: add visible region support for host offscreen rendering

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: server_muralfbo.c 28534 2010-04-20 18:30:11Z vboxsync $ */
2
3/** @file
4 * VBox crOpenGL: Window to FBO redirect support.
5 */
6
7/*
8 * Copyright (C) 2010 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. 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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include "server.h"
24#include "cr_string.h"
25#include "cr_mem.h"
26#include "render/renderspu.h"
27
28static int crServerGetPointScreen(GLint x, GLint y)
29{
30 int i;
31
32 for (i=0; i<cr_server.screenCount; ++i)
33 {
34 if ((x>=cr_server.screen[i].x && x<=cr_server.screen[i].x+(int)cr_server.screen[i].w)
35 && (y>=cr_server.screen[i].y && y<=cr_server.screen[i].y+(int)cr_server.screen[i].h))
36 {
37 return i;
38 }
39 }
40
41 return -1;
42}
43
44static GLboolean crServerMuralCoverScreen(CRMuralInfo *mural, int sId)
45{
46 return mural->gX<=cr_server.screen[sId].x
47 && mural->gX>=cr_server.screen[sId].x+(int)cr_server.screen[sId].w
48 && mural->gY<=cr_server.screen[sId].y
49 && mural->gY>=cr_server.screen[sId].y+(int)cr_server.screen[sId].h;
50}
51
52void crServerCheckMuralGeometry(CRMuralInfo *mural)
53{
54 int tlS, brS, trS, blS;
55 int overlappingScreenCount, primaryS, i;
56
57 if (cr_server.screenCount<2)
58 {
59 CRASSERT(cr_server.screenCount>0);
60
61 mural->hX = mural->gX-cr_server.screen[0].x;
62 mural->hY = mural->gY-cr_server.screen[0].y;
63
64 cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
65
66 return;
67 }
68
69 tlS = crServerGetPointScreen(mural->gX, mural->gY);
70 brS = crServerGetPointScreen(mural->gX+mural->width, mural->gY+mural->height);
71
72 if (tlS==brS && tlS>=0)
73 {
74 overlappingScreenCount = 1;
75 primaryS = tlS;
76 }
77 else
78 {
79 trS = crServerGetPointScreen(mural->gX+mural->width, mural->gY);
80 blS = crServerGetPointScreen(mural->gX, mural->gY+mural->height);
81
82 primaryS = -1; overlappingScreenCount = 0;
83 for (i=0; i<cr_server.screenCount; ++i)
84 {
85 if ((i==tlS) || (i==brS) || (i==trS) || (i==blS)
86 || crServerMuralCoverScreen(mural, i))
87 {
88 overlappingScreenCount++;
89 primaryS = primaryS<0 ? i:primaryS;
90 }
91 }
92
93 if (!overlappingScreenCount)
94 {
95 primaryS = 0;
96 }
97 }
98
99 if (primaryS!=mural->screenId)
100 {
101 mural->screenId = primaryS;
102
103 renderspuSetWindowId(cr_server.screen[primaryS].winID);
104 renderspuReparentWindow(mural->spuWindow);
105 renderspuSetWindowId(cr_server.screen[0].winID);
106 }
107
108 mural->hX = mural->gX-cr_server.screen[primaryS].x;
109 mural->hY = mural->gY-cr_server.screen[primaryS].y;
110
111 if (overlappingScreenCount<2)
112 {
113 if (mural->bUseFBO)
114 {
115 crServerRedirMuralFBO(mural, GL_FALSE);
116 crServerDeleteMuralFBO(mural);
117 }
118
119 cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
120 }
121 else
122 {
123 if (!mural->bUseFBO)
124 {
125 crServerRedirMuralFBO(mural, GL_TRUE);
126 }
127 else
128 {
129 if (mural->width!=mural->fboWidth
130 || mural->height!=mural->height)
131 {
132 crServerRedirMuralFBO(mural, GL_FALSE);
133 crServerDeleteMuralFBO(mural);
134 crServerRedirMuralFBO(mural, GL_TRUE);
135 }
136 }
137
138 if (!mural->bUseFBO)
139 {
140 cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
141 }
142 }
143}
144
145GLboolean crServerSupportRedirMuralFBO(void)
146{
147 const GLubyte* pExt = cr_server.head_spu->dispatch_table.GetString(GL_REAL_EXTENSIONS);
148
149 return ( NULL!=crStrstr((const char*)pExt, "GL_ARB_framebuffer_object")
150 || NULL!=crStrstr((const char*)pExt, "GL_EXT_framebuffer_object"))
151 && NULL!=crStrstr((const char*)pExt, "GL_ARB_texture_non_power_of_two");
152}
153
154void crServerRedirMuralFBO(CRMuralInfo *mural, GLboolean redir)
155{
156 if (redir)
157 {
158 if (!crServerSupportRedirMuralFBO())
159 {
160 crWarning("FBO not supported, can't redirect window output");
161 return;
162 }
163
164 cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, GL_FALSE);
165
166 if (mural->idFBO==0)
167 {
168 crServerCreateMuralFBO(mural);
169 }
170
171 if (!crStateGetCurrent()->framebufferobject.drawFB)
172 {
173 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->idFBO);
174 }
175 }
176 else
177 {
178 cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, mural->bVisible);
179
180 if (mural->bUseFBO && crServerSupportRedirMuralFBO()
181 && !crStateGetCurrent()->framebufferobject.drawFB)
182 {
183 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
184 }
185 }
186
187 mural->bUseFBO = redir;
188}
189
190void crServerCreateMuralFBO(CRMuralInfo *mural)
191{
192 CRContext *ctx = crStateGetCurrent();
193 GLuint uid;
194 GLenum status;
195
196 CRASSERT(mural->idFBO==0);
197
198 /*Color texture*/
199 cr_server.head_spu->dispatch_table.GenTextures(1, &mural->idColorTex);
200 cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, mural->idColorTex);
201 cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
202 cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
203 cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
204 cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
205 cr_server.head_spu->dispatch_table.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mural->width, mural->height,
206 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
207
208 /*Depth&Stencil*/
209 cr_server.head_spu->dispatch_table.GenRenderbuffersEXT(1, &mural->idDepthStencilRB);
210 cr_server.head_spu->dispatch_table.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
211 cr_server.head_spu->dispatch_table.RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
212 mural->width, mural->height);
213
214 /*FBO*/
215 cr_server.head_spu->dispatch_table.GenFramebuffersEXT(1, &mural->idFBO);
216 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->idFBO);
217
218 cr_server.head_spu->dispatch_table.FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
219 GL_TEXTURE_2D, mural->idColorTex, 0);
220 cr_server.head_spu->dispatch_table.FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
221 GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
222 cr_server.head_spu->dispatch_table.FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
223 GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
224
225 status = cr_server.head_spu->dispatch_table.CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
226 if (status!=GL_FRAMEBUFFER_COMPLETE_EXT)
227 {
228 crWarning("FBO status(0x%x) isn't complete", status);
229 }
230
231 mural->fboWidth = mural->width;
232 mural->fboHeight = mural->height;
233
234 /*Restore gl state*/
235 uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->name;
236 cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, uid);
237
238 uid = ctx->framebufferobject.renderbuffer ? ctx->framebufferobject.renderbuffer->hwid:0;
239 cr_server.head_spu->dispatch_table.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
240
241 uid = ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0;
242 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_FRAMEBUFFER_EXT, uid);
243}
244
245void crServerDeleteMuralFBO(CRMuralInfo *mural)
246{
247 CRASSERT(!mural->bUseFBO);
248
249 if (mural->idFBO!=0)
250 {
251 cr_server.head_spu->dispatch_table.DeleteTextures(1, &mural->idColorTex);
252 cr_server.head_spu->dispatch_table.DeleteRenderbuffersEXT(1, &mural->idDepthStencilRB);
253 cr_server.head_spu->dispatch_table.DeleteFramebuffersEXT(1, &mural->idFBO);
254
255 mural->idFBO = 0;
256 mural->idColorTex = 0;
257 mural->idDepthStencilRB = 0;
258 }
259}
260
261#define MIN(a, b) ((a) < (b) ? (a) : (b))
262#define MAX(a, b) ((a) > (b) ? (a) : (b))
263
264static GLboolean crServerIntersectRect(CRrecti *a, CRrecti *b, CRrecti *rect)
265{
266 CRASSERT(a && b && rect);
267
268 rect->x1 = MAX(a->x1, b->x1);
269 rect->x2 = MIN(a->x2, b->x2);
270 rect->y1 = MAX(a->y1, b->y1);
271 rect->y2 = MIN(a->y2, b->y2);
272
273 return (rect->x2>rect->x1) && (rect->y2>rect->y1);
274}
275
276static GLboolean crServerIntersectScreen(CRMuralInfo *mural, int sId, CRrecti *rect)
277{
278 rect->x1 = MAX(mural->gX, cr_server.screen[sId].x);
279 rect->x2 = MIN(mural->gX+(int)mural->fboWidth, cr_server.screen[sId].x+(int)cr_server.screen[sId].w);
280 rect->y1 = MAX(mural->gY, cr_server.screen[sId].y);
281 rect->y2 = MIN(mural->gY+(int)mural->fboHeight, cr_server.screen[sId].y+(int)cr_server.screen[sId].h);
282
283 return (rect->x2>rect->x1) && (rect->y2>rect->y1);
284}
285
286static void crServerCopySubImage(char *pDst, char* pSrc, CRrecti *pRect, int srcWidth, int srcHeight)
287{
288 int i;
289 int dstrowsize = 4*(pRect->x2-pRect->x1);
290 int srcrowsize = 4*srcWidth;
291 int height = pRect->y2-pRect->y1;
292
293 pSrc += 4*pRect->x1 + srcrowsize*(srcHeight-1-pRect->y1);
294
295 for (i=0; i<height; ++i)
296 {
297 crMemcpy(pDst, pSrc, dstrowsize);
298
299 pSrc -= srcrowsize;
300 pDst += dstrowsize;
301 }
302}
303
304static void crServerTransformRect(CRrecti *pDst, CRrecti *pSrc, int dx, int dy)
305{
306 pDst->x1 = pSrc->x1+dx;
307 pDst->x2 = pSrc->x2+dx;
308 pDst->y1 = pSrc->y1+dy;
309 pDst->y2 = pSrc->y2+dy;
310}
311
312void crServerPresentFBO(CRMuralInfo *mural)
313{
314 char *pixels, *tmppixels;
315 GLuint uid;
316 int i, j;
317 CRrecti rect, rectwr, sectr;
318 CRContext *ctx = crStateGetCurrent();
319
320 CRASSERT(cr_server.pfnPresentFBO);
321
322 if (!mural->bVisible)
323 {
324 return;
325 }
326
327 pixels = crAlloc(4*mural->fboWidth*mural->fboHeight);
328 if (!pixels)
329 {
330 crWarning("Out of memory in crServerPresentFBO");
331 return;
332 }
333
334 cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, mural->idColorTex);
335 cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
336 uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->name;
337 cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, uid);
338
339 for (i=0; i<cr_server.screenCount; ++i)
340 {
341 if (crServerIntersectScreen(mural, i, &rect))
342 {
343 tmppixels = crAlloc(4*(rect.x2-rect.x1)*(rect.y2-rect.y1));
344 if (!tmppixels)
345 {
346 crWarning("Out of memory in crServerPresentFBO");
347 crFree(pixels);
348 return;
349 }
350
351 /* rect in window relative coords */
352 crServerTransformRect(&rectwr, &rect, -mural->gX, -mural->gY);
353
354 if (!mural->pVisibleRects)
355 {
356 crServerCopySubImage(tmppixels, pixels, &rectwr, mural->fboWidth, mural->fboHeight);
357 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);
358 }
359 else
360 {
361 for (j=0; j<mural->cVisibleRects; ++j)
362 {
363 if (crServerIntersectRect(&rectwr, (CRrecti*) &mural->pVisibleRects[4*j], &sectr))
364 {
365 crServerCopySubImage(tmppixels, pixels, &sectr, mural->fboWidth, mural->fboHeight);
366 cr_server.pfnPresentFBO(tmppixels, i,
367 sectr.x1+mural->gX-cr_server.screen[i].x,
368 sectr.y1+mural->gY-cr_server.screen[i].y,
369 sectr.x2-sectr.x1, sectr.y2-sectr.y1);
370 }
371 }
372 }
373
374 crFree(tmppixels);
375 }
376 }
377 crFree(pixels);
378}
379
380GLboolean crServerIsRedirectedToFBO()
381{
382 return cr_server.curClient
383 && cr_server.curClient->currentMural
384 && cr_server.curClient->currentMural->bUseFBO;
385}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette