VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_blitter.cpp@ 43932

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

crOpenGL: host offscreen rendering to fix gnome-shell issues, repaint problems and more

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1/* $Id: server_blitter.cpp 43932 2012-11-21 19:28:05Z vboxsync $ */
2
3/** @file
4 * Blitter API
5 */
6
7/*
8 * Copyright (C) 2012 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#include "cr_spu.h"
19#include "chromium.h"
20#include "cr_error.h"
21#include "cr_net.h"
22#include "cr_rand.h"
23#include "server_dispatch.h"
24#include "server.h"
25#include "cr_mem.h"
26#include "cr_string.h"
27
28#include <iprt/cdefs.h>
29#include <iprt/types.h>
30#include <iprt/mem.h>
31
32
33int CrBltInit(PCR_BLITTER pBlitter, CRMuralInfo *pCurrentMural)
34{
35 memset(pBlitter, 0, sizeof (*pBlitter));
36
37 if (!cr_server.MainContextInfo.SpuContext)
38 {
39 crWarning("Default share context not initialized!");
40 return VERR_INVALID_STATE;
41 }
42
43
44 pBlitter->CtxInfo.CreateInfo.pszDpyName = "";
45 pBlitter->CtxInfo.CreateInfo.visualBits = pCurrentMural->CreateInfo.visualBits;
46 pBlitter->CtxInfo.SpuContext = cr_server.head_spu->dispatch_table.CreateContext(pBlitter->CtxInfo.CreateInfo.pszDpyName,
47 pBlitter->CtxInfo.CreateInfo.visualBits,
48 cr_server.MainContextInfo.SpuContext);
49 if (!pBlitter->CtxInfo.SpuContext)
50 {
51 crWarning("CreateContext failed!");
52 return VERR_GENERAL_FAILURE;
53 }
54
55 CrBltMuralSetCurrent(pBlitter, pCurrentMural);
56
57 return VINF_SUCCESS;
58}
59
60void CrBltTerm(PCR_BLITTER pBlitter)
61{
62 cr_server.head_spu->dispatch_table.DestroyContext(pBlitter->CtxInfo.SpuContext);
63}
64
65void CrBltMuralSetCurrent(PCR_BLITTER pBlitter, CRMuralInfo *pMural)
66{
67 if (pBlitter->pCurrentMural == pMural)
68 return;
69
70 pBlitter->pCurrentMural = pMural;
71
72 if (!CrBltIsEntered(pBlitter))
73 return;
74
75 if (pMural)
76 cr_server.head_spu->dispatch_table.MakeCurrent(pMural->spuWindow, 0, pBlitter->CtxInfo.SpuContext);
77 else
78 cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
79}
80
81#define CRBLT_FILTER_FROM_FLAGS(_f) (((_f) & CRBLT_F_LINEAR) ? GL_LINEAR : GL_NEAREST)
82
83static DECLCALLBACK(int) crBltBlitTexBufImplFbo(PCR_BLITTER pBlitter, CR_BLITTER_TEXTURE *pSrc, const RTRECT *paSrcRect, const PRTRECTSIZE pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags)
84{
85 GLenum filter = CRBLT_FILTER_FROM_FLAGS(fFlags);
86 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, pBlitter->idFBO);
87 cr_server.head_spu->dispatch_table.FramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pSrc->target, pSrc->hwid, 0);
88 cr_server.head_spu->dispatch_table.ReadBuffer(GL_COLOR_ATTACHMENT0);
89
90 for (uint32_t i = 0; i < cRects; ++i)
91 {
92 const RTRECT * pSrcRect = &paSrcRect[i];
93 const RTRECT * pDstRect = &paDstRect[i];
94 cr_server.head_spu->dispatch_table.BlitFramebufferEXT(
95 pSrcRect->xLeft, pSrcRect->yTop, pSrcRect->xRight, pSrcRect->yBottom,
96 pDstRect->xLeft, pDstRect->yTop, pDstRect->xRight, pDstRect->yBottom,
97 GL_COLOR_BUFFER_BIT, filter);
98 }
99
100 return VINF_SUCCESS;
101}
102
103/* GL_TRIANGLE_FAN */
104DECLINLINE(GLfloat*) crBltVtRectTFNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff)
105{
106 /* xLeft yTop */
107 pBuff[0] = ((float)pRect->xLeft)/((float)normalX);
108 pBuff[1] = ((float)pRect->yTop)/((float)normalY);
109
110 /* xLeft yBottom */
111 pBuff[2] = pBuff[0];
112 pBuff[3] = ((float)pRect->yBottom)/((float)normalY);
113
114 /* xRight yBottom */
115 pBuff[4] = ((float)pRect->xRight)/((float)normalX);
116 pBuff[5] = pBuff[3];
117
118 /* xRight yTop */
119 pBuff[6] = pBuff[4];
120 pBuff[7] = pBuff[1];
121 return &pBuff[8];
122}
123
124DECLINLINE(GLint*) crBltVtRectTF(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff)
125{
126 /* xLeft yTop */
127 pBuff[0] = pRect->xLeft;
128 pBuff[1] = pRect->yTop;
129
130 /* xLeft yBottom */
131 pBuff[2] = pBuff[0];
132 pBuff[3] = pRect->yBottom;
133
134 /* xRight yBottom */
135 pBuff[4] = pRect->xRight;
136 pBuff[5] = pBuff[3];
137
138 /* xRight yTop */
139 pBuff[6] = pBuff[4];
140 pBuff[7] = pBuff[1];
141 return &pBuff[8];
142}
143
144DECLINLINE(GLubyte*) crBltVtFillRectIndicies(GLubyte *pIndex, GLubyte *piBase)
145{
146 GLubyte iBase = *piBase;
147 /* triangle 1 */
148 pIndex[0] = iBase;
149 pIndex[1] = iBase + 1;
150 pIndex[2] = iBase + 2;
151
152 /* triangle 2 */
153 pIndex[3] = iBase;
154 pIndex[4] = iBase + 2;
155 pIndex[5] = iBase + 3;
156 *piBase = iBase + 6;
157 return pIndex + 6;
158}
159
160/* Indexed GL_TRIANGLES */
161DECLINLINE(GLfloat*) crBltVtRectITNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase)
162{
163 GLfloat* ret = crBltVtRectTFNormalized(pRect, normalX, normalY, pBuff);
164
165 if (ppIndex)
166 *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase);
167
168 return ret;
169}
170
171DECLINLINE(GLint*) crBltVtRectIT(RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, GLubyte **ppIndex, GLubyte *piBase)
172{
173 GLint* ret = crBltVtRectTF(pRect, normalX, normalY, pBuff);
174
175 if (ppIndex)
176 *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase);
177
178 return ret;
179}
180
181DECLINLINE(GLuint) crBltVtGetNumVerticiesTF(GLuint cRects)
182{
183 return cRects * 4;
184}
185
186#define crBltVtGetNumVerticiesIT crBltVtGetNumVerticiesTF
187
188DECLINLINE(GLuint) crBltVtGetNumIndiciesIT(GLuint cRects)
189{
190 return 6 * cRects;
191}
192
193
194static GLfloat* crBltVtRectsITNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase)
195{
196 for (uint32_t i = 0; i < cRects; ++i)
197 {
198 pBuff = crBltVtRectITNormalized(&paRects[i], normalX, normalY, pBuff, ppIndex, piBase);
199 }
200 return pBuff;
201}
202
203static void* crBltBufGet(PCR_BLITTER_BUFFER pBuffer, GLuint cbBuffer)
204{
205 if (pBuffer->cbBuffer < cbBuffer)
206 {
207 if (pBuffer->pvBuffer)
208 {
209 RTMemFree(pBuffer->pvBuffer);
210 }
211
212 cbBuffer += 16;
213
214 pBuffer->pvBuffer = RTMemAlloc(cbBuffer);
215 if (pBuffer->pvBuffer)
216 pBuffer->cbBuffer = cbBuffer;
217 else
218 {
219 crWarning("failed to allocate buffer of size %d", cbBuffer);
220 pBuffer->cbBuffer = 0;
221 }
222 }
223 return pBuffer->pvBuffer;
224}
225
226static DECLCALLBACK(int) crBltBlitTexBufImplDraw2D(PCR_BLITTER pBlitter, CR_BLITTER_TEXTURE *pSrc, const RTRECT *paSrcRect, const PRTRECTSIZE pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags)
227{
228 GLuint normalX, normalY;
229
230 if (pBlitter->CurrentSetSize.cx != pDstSize->cx
231 || pBlitter->CurrentSetSize.cy != pDstSize->cy)
232 {
233 const GLdouble aProjection[] =
234 {
235 2.0 / pDstSize->cx, 0.0, 0.0, 0.0,
236 0.0, 2.0 / pDstSize->cy, 0.0, 0.0,
237 0.0, 0.0, 2.0, 0.0,
238 -1.0, -1.0, -1.0, 1.0
239 };
240 cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
241 cr_server.head_spu->dispatch_table.LoadMatrixd(aProjection);
242 cr_server.head_spu->dispatch_table.Viewport(0, 0, pDstSize->cx, pDstSize->cy);
243 pBlitter->CurrentSetSize.cx = pDstSize->cx;
244 pBlitter->CurrentSetSize.cy = pDstSize->cy;
245 }
246
247 switch (pSrc->target)
248 {
249 case GL_TEXTURE_2D:
250 {
251 normalX = pSrc->width;
252 normalY = pSrc->height;
253 break;
254 }
255
256 case GL_TEXTURE_RECTANGLE_ARB:
257 {
258 normalX = 1;
259 normalY = 1;
260 break;
261 }
262
263 default:
264 {
265 crWarning("Unsupported texture target 0x%x", pSrc->target);
266 return VERR_INVALID_PARAMETER;
267 }
268 }
269
270 Assert(pSrc->hwid);
271
272 cr_server.head_spu->dispatch_table.BindTexture(pSrc->target, pSrc->hwid);
273
274 if (cRects == 1)
275 {
276 /* just optimizatino to draw a single rect with GL_TRIANGLE_FAN */
277 bool bUseSameVerticies = paSrcRect == paDstRect && normalX == 1 && normalY == 1;
278 GLfloat *pVerticies;
279 GLfloat *pTexCoords;
280 GLuint cElements = crBltVtGetNumVerticiesTF(1);
281 if (bUseSameVerticies)
282 {
283 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * sizeof (*pVerticies));
284 crBltVtRectTFNormalized(paDstRect, normalX, normalY, pVerticies);
285 pTexCoords = pVerticies;
286 }
287 else
288 {
289 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies));
290 pTexCoords = crBltVtRectTFNormalized(paDstRect, normalX, normalY, pVerticies);
291 crBltVtRectTFNormalized(paSrcRect, normalX, normalY, pTexCoords);
292 }
293
294 cr_server.head_spu->dispatch_table.EnableClientState(GL_VERTEX_ARRAY);
295 cr_server.head_spu->dispatch_table.VertexPointer(2, GL_FLOAT, 0, pVerticies);
296
297 cr_server.head_spu->dispatch_table.EnableClientState(GL_TEXTURE_COORD_ARRAY);
298 cr_server.head_spu->dispatch_table.VertexPointer(2, GL_FLOAT, 0, pTexCoords);
299
300 cr_server.head_spu->dispatch_table.Enable(pSrc->target);
301
302 cr_server.head_spu->dispatch_table.DrawArrays(GL_TRIANGLE_FAN, 0, cElements);
303
304 cr_server.head_spu->dispatch_table.Disable(pSrc->target);
305
306 cr_server.head_spu->dispatch_table.DisableClientState(GL_TEXTURE_COORD_ARRAY);
307 cr_server.head_spu->dispatch_table.DisableClientState(GL_VERTEX_ARRAY);
308 }
309 else
310 {
311 bool bUseSameVerticies = paSrcRect == paDstRect && normalX == 1 && normalY == 1;
312 GLfloat *pVerticies;
313 GLfloat *pTexCoords;
314 GLubyte *pIndicies;
315 GLuint cElements = crBltVtGetNumVerticiesIT(cRects);
316 GLuint cIndicies = crBltVtGetNumIndiciesIT(cRects);
317 GLubyte iIdxBase = 0;
318 if (bUseSameVerticies)
319 {
320 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * sizeof (*pVerticies));
321 crBltVtRectsITNormalized(paDstRect, cRects, normalX, normalY, pVerticies, &pIndicies, &iIdxBase);
322 pTexCoords = pVerticies;
323 }
324 else
325 {
326 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies));
327 pTexCoords = crBltVtRectsITNormalized(paDstRect, cRects, normalX, normalY, pVerticies, &pIndicies, &iIdxBase);
328 crBltVtRectsITNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, NULL, NULL);
329 }
330
331 cr_server.head_spu->dispatch_table.EnableClientState(GL_VERTEX_ARRAY);
332 cr_server.head_spu->dispatch_table.VertexPointer(2, GL_FLOAT, 0, pVerticies);
333
334 cr_server.head_spu->dispatch_table.EnableClientState(GL_TEXTURE_COORD_ARRAY);
335 cr_server.head_spu->dispatch_table.VertexPointer(2, GL_FLOAT, 0, pTexCoords);
336
337 cr_server.head_spu->dispatch_table.Enable(pSrc->target);
338
339 cr_server.head_spu->dispatch_table.DrawElements(GL_TRIANGLES, cIndicies, GL_UNSIGNED_BYTE, pIndicies);
340
341 cr_server.head_spu->dispatch_table.Disable(pSrc->target);
342
343 cr_server.head_spu->dispatch_table.DisableClientState(GL_TEXTURE_COORD_ARRAY);
344 cr_server.head_spu->dispatch_table.DisableClientState(GL_VERTEX_ARRAY);
345 }
346
347 return VINF_SUCCESS;
348}
349
350static int crBltInitOnMakeCurent(PCR_BLITTER pBlitter)
351{
352 const char * pszExtension = (const char*)cr_server.head_spu->dispatch_table.GetString(GL_EXTENSIONS);
353 if (crStrstr(pszExtension, "GL_EXT_framebuffer_object"))
354 {
355 pBlitter->Flags.SupportsFBO = 1;
356 cr_server.head_spu->dispatch_table.GenFramebuffersEXT(1, &pBlitter->idFBO);
357 Assert(pBlitter->idFBO);
358 }
359 else
360 crWarning("GL_EXT_framebuffer_object not supported, blitter can only blit to window");
361
362 if (crStrstr(pszExtension, "GL_EXT_framebuffer_blit"))
363 {
364 pBlitter->Flags.SupportsFBOBlit = 1;
365 pBlitter->pfnBlt = crBltBlitTexBufImplFbo;
366 }
367 else
368 {
369 crWarning("GL_EXT_framebuffer_blit not supported, will use Draw functions for blitting, which might be less efficient");
370 pBlitter->pfnBlt = crBltBlitTexBufImplDraw2D;
371 }
372
373 return VINF_SUCCESS;
374}
375
376void CrBltLeave(PCR_BLITTER pBlitter)
377{
378 Assert(CrBltIsEntered(pBlitter));
379
380 if (pBlitter->pRestoreCtxInfo != &pBlitter->CtxInfo)
381 cr_server.head_spu->dispatch_table.MakeCurrent(pBlitter->pRestoreMural->spuWindow, 0,
382 pBlitter->pRestoreCtxInfo->SpuContext >= 0
383 ? pBlitter->pRestoreCtxInfo->SpuContext : cr_server.MainContextInfo.SpuContext);
384 else
385 cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
386
387 pBlitter->pRestoreCtxInfo = NULL;
388}
389
390int CrBltEnter(PCR_BLITTER pBlitter, CRContextInfo *pRestoreCtxInfo, CRMuralInfo *pRestoreMural)
391{
392 if (!pBlitter->pCurrentMural)
393 {
394 crWarning("current mural not initialized!");
395 return VERR_INVALID_STATE;
396 }
397
398 if (CrBltIsEntered(pBlitter))
399 {
400 crWarning("blitter is entered already!");
401 return VERR_INVALID_STATE;
402 }
403
404 pBlitter->pRestoreCtxInfo = pRestoreCtxInfo ? pRestoreCtxInfo : &pBlitter->CtxInfo;
405 pBlitter->pRestoreMural = pRestoreMural;
406
407 cr_server.head_spu->dispatch_table.MakeCurrent(pBlitter->pCurrentMural->spuWindow, 0, pBlitter->CtxInfo.SpuContext);
408
409 if (pBlitter->Flags.Initialized)
410 return VINF_SUCCESS;
411
412 int rc = crBltInitOnMakeCurent(pBlitter);
413 if (RT_SUCCESS(rc))
414 {
415 pBlitter->Flags.Initialized = 1;
416 return VINF_SUCCESS;
417 }
418
419 crWarning("crBltInitOnMakeCurent failed, rc %d", rc);
420 CrBltLeave(pBlitter);
421 return rc;
422}
423
424static void crBltBlitTexBuf(PCR_BLITTER pBlitter, CR_BLITTER_TEXTURE *pSrc, const RTRECT *paSrcRects, GLenum enmDstBuff, const PRTRECTSIZE pDstSize, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
425{
426 cr_server.head_spu->dispatch_table.DrawBuffer(enmDstBuff);
427
428 pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
429}
430
431void CrBltBlitTexMural(PCR_BLITTER pBlitter, CR_BLITTER_TEXTURE *pSrc, const RTRECT *paSrcRects, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
432{
433 RTRECTSIZE DstSize = {pBlitter->pCurrentMural->width, pBlitter->pCurrentMural->height};
434
435 crBltBlitTexBuf(pBlitter, pSrc, paSrcRects, GL_BACK, &DstSize, paDstRects, cRects, fFlags);
436}
437
438void CrBltBlitTexTex(PCR_BLITTER pBlitter, CR_BLITTER_TEXTURE *pSrc, const RTRECT *pSrcRect, CR_BLITTER_TEXTURE *pDst, const RTRECT *pDstRect, uint32_t cRects, uint32_t fFlags)
439{
440 RTRECTSIZE DstSize = {pDst->width, pDst->height};
441
442 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, pBlitter->idFBO);
443
444 /* TODO: mag/min filters ? */
445
446 cr_server.head_spu->dispatch_table.FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, pDst->hwid, 0);
447
448// cr_server.head_spu->dispatch_table.FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
449// cr_server.head_spu->dispatch_table.FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
450
451 crBltBlitTexBuf(pBlitter, pSrc, pSrcRect, GL_DRAW_FRAMEBUFFER, &DstSize, pDstRect, cRects, fFlags);
452}
453
454void CrBltPresent(PCR_BLITTER pBlitter)
455{
456 if (pBlitter->CtxInfo.CreateInfo.visualBits & CR_DOUBLE_BIT)
457 cr_server.head_spu->dispatch_table.SwapBuffers(pBlitter->pCurrentMural->spuWindow, 0);
458 else
459 cr_server.head_spu->dispatch_table.Flush();
460}
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