VirtualBox

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

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

crOpenGL: glGetError fixes

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