VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/blitter.cpp@ 48366

Last change on this file since 48366 was 48366, checked in by vboxsync, 11 years ago

crOpenGL: fix debug defines, sigh

  • Property svn:executable set to *
File size: 35.8 KB
Line 
1/* $Id$ */
2
3/** @file
4 * Blitter API implementation
5 */
6/*
7 * Copyright (C) 2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#include "cr_blitter.h"
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 "cr_mem.h"
24#include "cr_string.h"
25
26#include <iprt/cdefs.h>
27#include <iprt/types.h>
28#include <iprt/mem.h>
29
30/* @param pCtxBase - contains the blitter context info. Its value is treated differently depending on the fCreateNewCtx value
31 * @param fCreateNewCtx - if true - the pCtxBase must NOT be NULL. its visualBits is used as a visual bits info for the new context,
32 * its id field is used to specified the shared context id to be used for blitter context.
33 * The id can be null to specify no shared context is needed
34 * if false - if pCtxBase is NOT null AND its id field is NOT null -
35 * specified the blitter context to be used
36 * blitter treats it as if it has default ogl state.
37 * otherwise -
38 * the blitter works in a "no-context" mode, i.e. a caller is responsible
39 * to making a proper context current before calling the blitter.
40 * Note that BltEnter/Leave MUST still be called, but the proper context
41 * must be set before doing BltEnter, and ResoreContext info is ignored in that case.
42 * Also note that blitter caches the current window info, and assumes the current context's values are preserved
43 * wrt that window before the calls, so if one uses different contexts for one blitter,
44 * the blitter current window values must be explicitly reset by doing CrBltMuralSetCurrent(pBlitter, NULL)
45 * @param fForceDrawBlt - if true - forces the blitter to always use glDrawXxx-based blits even if GL_EXT_framebuffer_blit.
46 * This is needed because BlitFramebufferEXT is known to be often buggy, and glDrawXxx-based blits appear to be more reliable
47 */
48VBOXBLITTERDECL(int) CrBltInit(PCR_BLITTER pBlitter, const CR_BLITTER_CONTEXT *pCtxBase, bool fCreateNewCtx, bool fForceDrawBlt, const CR_GLSL_CACHE *pShaders, SPUDispatchTable *pDispatch)
49{
50 if (pCtxBase && pCtxBase->Base.id < 0)
51 {
52 crWarning("Default share context not initialized!");
53 return VERR_INVALID_PARAMETER;
54 }
55
56 if (!pCtxBase && fCreateNewCtx)
57 {
58 crWarning("pCtxBase is zero while fCreateNewCtx is set!");
59 return VERR_INVALID_PARAMETER;
60 }
61
62 memset(pBlitter, 0, sizeof (*pBlitter));
63
64 pBlitter->pDispatch = pDispatch;
65 if (pCtxBase)
66 pBlitter->CtxInfo = *pCtxBase;
67
68 pBlitter->Flags.ForceDrawBlit = fForceDrawBlt;
69
70 if (fCreateNewCtx)
71 {
72 pBlitter->CtxInfo.Base.id = pDispatch->CreateContext("", pCtxBase->Base.visualBits, pCtxBase->Base.id);
73 if (!pBlitter->CtxInfo.Base.id)
74 {
75 memset(pBlitter, 0, sizeof (*pBlitter));
76 crWarning("CreateContext failed!");
77 return VERR_GENERAL_FAILURE;
78 }
79 pBlitter->Flags.CtxCreated = 1;
80 }
81
82 if (pShaders)
83 {
84 pBlitter->pGlslCache = pShaders;
85 pBlitter->Flags.ShadersGloal = 1;
86 }
87 else
88 {
89 CrGlslInit(&pBlitter->LocalGlslCache, pDispatch);
90 pBlitter->pGlslCache = &pBlitter->LocalGlslCache;
91 }
92
93 return VINF_SUCCESS;
94}
95
96VBOXBLITTERDECL(int) CrBltCleanup(PCR_BLITTER pBlitter, const CR_BLITTER_CONTEXT *pRestoreCtxInfo, const CR_BLITTER_WINDOW *pRestoreMural)
97{
98 if (CrBltIsEntered(pBlitter))
99 {
100 crWarning("CrBltBlitTexTex: blitter is entered");
101 return VERR_INVALID_STATE;
102 }
103
104 if (pBlitter->Flags.ShadersGloal || !CrGlslNeedsCleanup(&pBlitter->LocalGlslCache))
105 return VINF_SUCCESS;
106
107 int rc = CrBltEnter(pBlitter, pRestoreCtxInfo, pRestoreMural);
108 if (!RT_SUCCESS(rc))
109 {
110 crWarning("CrBltEnter failed, rc %d", rc);
111 return rc;
112 }
113
114 CrGlslCleanup(&pBlitter->LocalGlslCache);
115
116 CrBltLeave(pBlitter);
117
118 return VINF_SUCCESS;
119}
120
121void CrBltTerm(PCR_BLITTER pBlitter)
122{
123 if (pBlitter->Flags.CtxCreated)
124 pBlitter->pDispatch->DestroyContext(pBlitter->CtxInfo.Base.id);
125 memset(pBlitter, 0, sizeof (*pBlitter));
126}
127
128int CrBltMuralSetCurrent(PCR_BLITTER pBlitter, const CR_BLITTER_WINDOW *pMural)
129{
130 if (pMural)
131 {
132 if (!memcmp(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural)))
133 return VINF_SUCCESS;
134 memcpy(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural));
135 }
136 else
137 {
138 if (CrBltIsEntered(pBlitter))
139 {
140 crWarning("can not set null mural for entered bleater");
141 return VERR_INVALID_STATE;
142 }
143 if (!pBlitter->CurrentMural.Base.id)
144 return VINF_SUCCESS;
145 pBlitter->CurrentMural.Base.id = 0;
146 }
147
148 pBlitter->Flags.CurrentMuralChanged = 1;
149
150 if (!CrBltIsEntered(pBlitter))
151 return VINF_SUCCESS;
152 else if (!pBlitter->CtxInfo.Base.id)
153 {
154 crWarning("setting current mural for entered no-context blitter");
155 return VERR_INVALID_STATE;
156 }
157
158 crWarning("changing mural for entered blitter, is is somewhat expected?");
159
160 pBlitter->pDispatch->Flush();
161
162 pBlitter->pDispatch->MakeCurrent(pMural->Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
163
164 return VINF_SUCCESS;
165}
166
167static DECLCALLBACK(int) crBltBlitTexBufImplFbo(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const RTRECTSIZE *pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags)
168{
169 GLenum filter = CRBLT_FILTER_FROM_FLAGS(fFlags);
170 pBlitter->pDispatch->BindFramebufferEXT(GL_READ_FRAMEBUFFER, pBlitter->idFBO);
171 pBlitter->pDispatch->FramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pSrc->target, pSrc->hwid, 0);
172 pBlitter->pDispatch->ReadBuffer(GL_COLOR_ATTACHMENT0);
173
174 for (uint32_t i = 0; i < cRects; ++i)
175 {
176 const RTRECT * pSrcRect = &paSrcRect[i];
177 const RTRECT * pDstRect = &paDstRect[i];
178 int32_t srcY1;
179 int32_t srcY2;
180 int32_t dstY1;
181 int32_t dstY2;
182 int32_t srcX1 = pSrcRect->xLeft;
183 int32_t srcX2 = pSrcRect->xRight;
184 int32_t dstX1 = pDstRect->xLeft;
185 int32_t dstX2 = pDstRect->xRight;
186
187 if (CRBLT_F_INVERT_SRC_YCOORDS & fFlags)
188 {
189 srcY1 = pSrc->height - pSrcRect->yTop;
190 srcY2 = pSrc->height - pSrcRect->yBottom;
191 }
192 else
193 {
194 srcY1 = pSrcRect->yTop;
195 srcY2 = pSrcRect->yBottom;
196 }
197
198 if (CRBLT_F_INVERT_DST_YCOORDS & fFlags)
199 {
200 dstY1 = pDstSize->cy - pDstRect->yTop;
201 dstY2 = pDstSize->cy - pDstRect->yBottom;
202 }
203 else
204 {
205 dstY1 = pDstRect->yTop;
206 dstY2 = pDstRect->yBottom;
207 }
208
209 if (srcY1 > srcY2)
210 {
211 if (dstY1 > dstY2)
212 {
213 /* use srcY1 < srcY2 && dstY1 < dstY2 whenever possible to avoid GPU driver bugs */
214 int32_t tmp = srcY1;
215 srcY1 = srcY2;
216 srcY2 = tmp;
217 tmp = dstY1;
218 dstY1 = dstY2;
219 dstY2 = tmp;
220 }
221 }
222
223 if (srcX1 > srcX2)
224 {
225 if (dstX1 > dstX2)
226 {
227 /* use srcX1 < srcX2 && dstX1 < dstX2 whenever possible to avoid GPU driver bugs */
228 int32_t tmp = srcX1;
229 srcX1 = srcX2;
230 srcX2 = tmp;
231 tmp = dstX1;
232 dstX1 = dstX2;
233 dstX2 = tmp;
234 }
235 }
236
237 pBlitter->pDispatch->BlitFramebufferEXT(srcX1, srcY1, srcX2, srcY2,
238 dstX1, dstY1, dstX2, dstY2,
239 GL_COLOR_BUFFER_BIT, filter);
240 }
241
242 return VINF_SUCCESS;
243}
244
245/* GL_TRIANGLE_FAN */
246DECLINLINE(GLfloat*) crBltVtRectTFNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
247{
248 /* going ccw:
249 * 1. (left;top) 4. (right;top)
250 * | ^
251 * > |
252 * 2. (left;bottom) -> 3. (right;bottom) */
253 /* xLeft yTop */
254 pBuff[0] = ((float)pRect->xLeft)/((float)normalX);
255 pBuff[1] = ((float)(height ? height - pRect->yTop : pRect->yTop))/((float)normalY);
256
257 /* xLeft yBottom */
258 pBuff[2] = pBuff[0];
259 pBuff[3] = ((float)(height ? height - pRect->yBottom : pRect->yBottom))/((float)normalY);
260
261 /* xRight yBottom */
262 pBuff[4] = ((float)pRect->xRight)/((float)normalX);
263 pBuff[5] = pBuff[3];
264
265 /* xRight yTop */
266 pBuff[6] = pBuff[4];
267 pBuff[7] = pBuff[1];
268 return &pBuff[8];
269}
270
271DECLINLINE(GLfloat*) crBltVtRectsTFNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
272{
273 for (uint32_t i = 0; i < cRects; ++i)
274 {
275 pBuff = crBltVtRectTFNormalized(&paRects[i], normalX, normalY, pBuff, height);
276 }
277 return pBuff;
278}
279
280DECLINLINE(GLint*) crBltVtRectTF(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, uint32_t height)
281{
282 /* xLeft yTop */
283 pBuff[0] = pRect->xLeft;
284 pBuff[1] = height ? height - pRect->yTop : pRect->yTop;
285
286 /* xLeft yBottom */
287 pBuff[2] = pBuff[0];
288 pBuff[3] = height ? height - pRect->yBottom : pRect->yBottom;
289
290 /* xRight yBottom */
291 pBuff[4] = pRect->xRight;
292 pBuff[5] = pBuff[3];
293
294 /* xRight yTop */
295 pBuff[6] = pBuff[4];
296 pBuff[7] = pBuff[1];
297 return &pBuff[8];
298}
299
300DECLINLINE(GLubyte*) crBltVtFillRectIndicies(GLubyte *pIndex, GLubyte *piBase)
301{
302 GLubyte iBase = *piBase;
303 /* triangle 1 */
304 pIndex[0] = iBase;
305 pIndex[1] = iBase + 1;
306 pIndex[2] = iBase + 2;
307
308 /* triangle 2 */
309 pIndex[3] = iBase;
310 pIndex[4] = iBase + 2;
311 pIndex[5] = iBase + 3;
312 *piBase = iBase + 4;
313 return pIndex + 6;
314}
315
316/* Indexed GL_TRIANGLES */
317DECLINLINE(GLfloat*) crBltVtRectITNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
318{
319 GLfloat* ret = crBltVtRectTFNormalized(pRect, normalX, normalY, pBuff, height);
320 return ret;
321}
322
323DECLINLINE(GLint*) crBltVtRectIT(RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height)
324{
325 GLint* ret = crBltVtRectTF(pRect, normalX, normalY, pBuff, height);
326
327 if (ppIndex)
328 *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase);
329
330 return ret;
331}
332
333DECLINLINE(GLuint) crBltVtGetNumVerticiesTF(GLuint cRects)
334{
335 return cRects * 4;
336}
337
338#define crBltVtGetNumVerticiesIT crBltVtGetNumVerticiesTF
339
340DECLINLINE(GLuint) crBltVtGetNumIndiciesIT(GLuint cRects)
341{
342 return 6 * cRects;
343}
344
345
346static GLfloat* crBltVtRectsITNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height)
347{
348 uint32_t i;
349 for (i = 0; i < cRects; ++i)
350 {
351 pBuff = crBltVtRectITNormalized(&paRects[i], normalX, normalY, pBuff, height);
352 }
353
354
355 if (ppIndex)
356 {
357 GLubyte *pIndex = (GLubyte*)pBuff;
358 *ppIndex = pIndex;
359 for (i = 0; i < cRects; ++i)
360 {
361 pIndex = crBltVtFillRectIndicies(pIndex, piBase);
362 }
363 pBuff = (GLfloat*)pIndex;
364 }
365
366 return pBuff;
367}
368
369static void* crBltBufGet(PCR_BLITTER_BUFFER pBuffer, GLuint cbBuffer)
370{
371 if (pBuffer->cbBuffer < cbBuffer)
372 {
373 if (pBuffer->pvBuffer)
374 {
375 RTMemFree(pBuffer->pvBuffer);
376 }
377
378#ifndef DEBUG_misha
379 /* debugging: ensure we calculate proper buffer size */
380 cbBuffer += 16;
381#endif
382
383 pBuffer->pvBuffer = RTMemAlloc(cbBuffer);
384 if (pBuffer->pvBuffer)
385 pBuffer->cbBuffer = cbBuffer;
386 else
387 {
388 crWarning("failed to allocate buffer of size %d", cbBuffer);
389 pBuffer->cbBuffer = 0;
390 }
391 }
392 return pBuffer->pvBuffer;
393}
394
395static void crBltCheckSetupViewport(PCR_BLITTER pBlitter, const RTRECTSIZE *pDstSize, bool fFBODraw)
396{
397 bool fUpdateViewport = pBlitter->Flags.CurrentMuralChanged;
398 if (pBlitter->CurrentSetSize.cx != pDstSize->cx
399 || pBlitter->CurrentSetSize.cy != pDstSize->cy)
400 {
401 pBlitter->CurrentSetSize = *pDstSize;
402 pBlitter->pDispatch->MatrixMode(GL_PROJECTION);
403 pBlitter->pDispatch->LoadIdentity();
404 pBlitter->pDispatch->Ortho(0, pDstSize->cx, 0, pDstSize->cy, -1, 1);
405 fUpdateViewport = true;
406 }
407
408 if (fUpdateViewport)
409 {
410 pBlitter->pDispatch->Viewport(0, 0, pBlitter->CurrentSetSize.cx, pBlitter->CurrentSetSize.cy);
411 pBlitter->Flags.CurrentMuralChanged = 0;
412 }
413
414 pBlitter->Flags.LastWasFBODraw = fFBODraw;
415}
416
417static DECLCALLBACK(int) crBltBlitTexBufImplDraw2D(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const RTRECTSIZE *pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags)
418{
419 GLuint normalX, normalY;
420 uint32_t srcHeight = (fFlags & CRBLT_F_INVERT_SRC_YCOORDS) ? pSrc->height : 0;
421 uint32_t dstHeight = (fFlags & CRBLT_F_INVERT_DST_YCOORDS) ? pDstSize->cy : 0;
422
423 switch (pSrc->target)
424 {
425 case GL_TEXTURE_2D:
426 {
427 normalX = pSrc->width;
428 normalY = pSrc->height;
429 break;
430 }
431
432 case GL_TEXTURE_RECTANGLE_ARB:
433 {
434 normalX = 1;
435 normalY = 1;
436 break;
437 }
438
439 default:
440 {
441 crWarning("Unsupported texture target 0x%x", pSrc->target);
442 return VERR_INVALID_PARAMETER;
443 }
444 }
445
446 Assert(pSrc->hwid);
447
448 pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
449
450 if (cRects == 1)
451 {
452 /* just optimization to draw a single rect with GL_TRIANGLE_FAN */
453 GLfloat *pVerticies;
454 GLfloat *pTexCoords;
455 GLuint cElements = crBltVtGetNumVerticiesTF(cRects);
456
457 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies));
458 pTexCoords = crBltVtRectsTFNormalized(paDstRect, cRects, 1, 1, pVerticies, dstHeight);
459 crBltVtRectsTFNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, srcHeight);
460
461 pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
462 pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
463
464 pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
465 pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords);
466
467 pBlitter->pDispatch->Enable(pSrc->target);
468
469 pBlitter->pDispatch->DrawArrays(GL_TRIANGLE_FAN, 0, cElements);
470
471 pBlitter->pDispatch->Disable(pSrc->target);
472
473 pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
474 pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
475 }
476 else
477 {
478 GLfloat *pVerticies;
479 GLfloat *pTexCoords;
480 GLubyte *pIndicies;
481 GLuint cElements = crBltVtGetNumVerticiesIT(cRects);
482 GLuint cIndicies = crBltVtGetNumIndiciesIT(cRects);
483 GLubyte iIdxBase = 0;
484
485 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies) + cIndicies * sizeof (*pIndicies));
486 pTexCoords = crBltVtRectsITNormalized(paDstRect, cRects, 1, 1, pVerticies, &pIndicies, &iIdxBase, dstHeight);
487 crBltVtRectsITNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, NULL, NULL, srcHeight);
488
489 pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
490 pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
491
492 pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
493 pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords);
494
495 pBlitter->pDispatch->Enable(pSrc->target);
496
497 pBlitter->pDispatch->DrawElements(GL_TRIANGLES, cIndicies, GL_UNSIGNED_BYTE, pIndicies);
498
499 pBlitter->pDispatch->Disable(pSrc->target);
500
501 pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
502 pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
503 }
504
505 pBlitter->pDispatch->BindTexture(pSrc->target, 0);
506
507 return VINF_SUCCESS;
508}
509
510static int crBltInitOnMakeCurent(PCR_BLITTER pBlitter)
511{
512 const char * pszExtension = (const char*)pBlitter->pDispatch->GetString(GL_EXTENSIONS);
513 if (crStrstr(pszExtension, "GL_EXT_framebuffer_object"))
514 {
515 pBlitter->Flags.SupportsFBO = 1;
516 pBlitter->pDispatch->GenFramebuffersEXT(1, &pBlitter->idFBO);
517 Assert(pBlitter->idFBO);
518 }
519 else
520 crWarning("GL_EXT_framebuffer_object not supported, blitter can only blit to window");
521
522 /* BlitFramebuffer seems to be buggy on Intel,
523 * try always glDrawXxx for now */
524 if (!pBlitter->Flags.ForceDrawBlit && crStrstr(pszExtension, "GL_EXT_framebuffer_blit"))
525 {
526 pBlitter->pfnBlt = crBltBlitTexBufImplFbo;
527 }
528 else
529 {
530// crWarning("GL_EXT_framebuffer_blit not supported, will use Draw functions for blitting, which might be less efficient");
531 pBlitter->pfnBlt = crBltBlitTexBufImplDraw2D;
532 }
533
534 /* defaults. but just in case */
535 pBlitter->pDispatch->MatrixMode(GL_TEXTURE);
536 pBlitter->pDispatch->LoadIdentity();
537 pBlitter->pDispatch->MatrixMode(GL_MODELVIEW);
538 pBlitter->pDispatch->LoadIdentity();
539
540 return VINF_SUCCESS;
541}
542
543void CrBltLeave(PCR_BLITTER pBlitter)
544{
545 if (!CrBltIsEntered(pBlitter))
546 {
547 crWarning("CrBltLeave: blitter not entered");
548 return;
549 }
550
551 if (pBlitter->Flags.SupportsFBO)
552 {
553 pBlitter->pDispatch->BindFramebufferEXT(GL_FRAMEBUFFER, 0);
554 pBlitter->pDispatch->DrawBuffer(GL_BACK);
555 pBlitter->pDispatch->ReadBuffer(GL_BACK);
556 }
557
558 pBlitter->pDispatch->Flush();
559
560 if (pBlitter->CtxInfo.Base.id)
561 {
562 if (pBlitter->pRestoreCtxInfo != &pBlitter->CtxInfo)
563 {
564 pBlitter->pDispatch->MakeCurrent(pBlitter->pRestoreMural->Base.id, 0, pBlitter->pRestoreCtxInfo->Base.id);
565 }
566 else
567 {
568 pBlitter->pDispatch->MakeCurrent(0, 0, 0);
569 }
570 }
571
572 pBlitter->pRestoreCtxInfo = NULL;
573}
574
575int CrBltEnter(PCR_BLITTER pBlitter, const CR_BLITTER_CONTEXT *pRestoreCtxInfo, const CR_BLITTER_WINDOW *pRestoreMural)
576{
577 if (!pBlitter->CurrentMural.Base.id && pBlitter->CtxInfo.Base.id)
578 {
579 crWarning("current mural not initialized!");
580 return VERR_INVALID_STATE;
581 }
582
583 if (CrBltIsEntered(pBlitter))
584 {
585 crWarning("blitter is entered already!");
586 return VERR_INVALID_STATE;
587 }
588
589 if (pBlitter->CurrentMural.Base.id) /* <- pBlitter->CurrentMural.Base.id can be null if the blitter is in a "no-context" mode (see comments to BltInit for detail)*/
590 {
591 if (pRestoreCtxInfo)
592 pBlitter->pDispatch->Flush();
593 pBlitter->pDispatch->MakeCurrent(pBlitter->CurrentMural.Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
594 }
595 else
596 {
597 if (pRestoreCtxInfo)
598 {
599 crWarning("pRestoreCtxInfo is not NULL for \"no-context\" blitter");
600 pRestoreCtxInfo = NULL;
601 }
602 }
603
604 if (pRestoreCtxInfo)
605 {
606 pBlitter->pRestoreCtxInfo = pRestoreCtxInfo;
607 pBlitter->pRestoreMural = pRestoreMural;
608 }
609 else
610 {
611 pBlitter->pRestoreCtxInfo = &pBlitter->CtxInfo;
612 }
613
614 if (pBlitter->Flags.Initialized)
615 return VINF_SUCCESS;
616
617 int rc = crBltInitOnMakeCurent(pBlitter);
618 if (RT_SUCCESS(rc))
619 {
620 pBlitter->Flags.Initialized = 1;
621 return VINF_SUCCESS;
622 }
623
624 crWarning("crBltInitOnMakeCurent failed, rc %d", rc);
625 CrBltLeave(pBlitter);
626 return rc;
627}
628
629static void crBltBlitTexBuf(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, GLenum enmDstBuff, const RTRECTSIZE *pDstSize, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
630{
631 pBlitter->pDispatch->DrawBuffer(enmDstBuff);
632
633 crBltCheckSetupViewport(pBlitter, pDstSize, enmDstBuff == GL_DRAW_FRAMEBUFFER);
634
635 if (!(fFlags & CRBLT_F_NOALPHA))
636 pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
637 else
638 {
639 int rc = pBlitter->Flags.ShadersGloal ?
640 CrGlslProgUseNoAlpha(pBlitter->pGlslCache, pSrc->target)
641 :
642 CrGlslProgUseGenNoAlpha(&pBlitter->LocalGlslCache, pSrc->target);
643
644 if (!RT_SUCCESS(rc))
645 {
646 crWarning("Failed to use no-alpha program rc %d!, falling back to default blit", rc);
647 pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
648 return;
649 }
650
651 /* since we use shaders, we need to use draw commands rather than framebuffer blits.
652 * force using draw-based blitting */
653 crBltBlitTexBufImplDraw2D(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
654
655 Assert(pBlitter->Flags.ShadersGloal || &pBlitter->LocalGlslCache == pBlitter->pGlslCache);
656
657 CrGlslProgClear(pBlitter->pGlslCache);
658 }
659}
660
661void CrBltCheckUpdateViewport(PCR_BLITTER pBlitter)
662{
663 RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height};
664 crBltCheckSetupViewport(pBlitter, &DstSize, false);
665}
666
667void CrBltBlitTexMural(PCR_BLITTER pBlitter, bool fBb, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
668{
669 if (!CrBltIsEntered(pBlitter))
670 {
671 crWarning("CrBltBlitTexMural: blitter not entered");
672 return;
673 }
674
675 RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height};
676
677 pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
678
679 crBltBlitTexBuf(pBlitter, pSrc, paSrcRects, fBb ? GL_BACK : GL_FRONT, &DstSize, paDstRects, cRects, fFlags);
680}
681
682void CrBltBlitTexTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *pSrcRect, const VBOXVR_TEXTURE *pDst, const RTRECT *pDstRect, uint32_t cRects, uint32_t fFlags)
683{
684 if (!CrBltIsEntered(pBlitter))
685 {
686 crWarning("CrBltBlitTexTex: blitter not entered");
687 return;
688 }
689
690 RTRECTSIZE DstSize = {(uint32_t)pDst->width, (uint32_t)pDst->height};
691
692 pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, pBlitter->idFBO);
693
694 /* TODO: mag/min filters ? */
695
696 pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, pDst->hwid, 0);
697
698// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
699// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
700
701 crBltBlitTexBuf(pBlitter, pSrc, pSrcRect, GL_DRAW_FRAMEBUFFER, &DstSize, pDstRect, cRects, fFlags);
702
703 pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, 0, 0);
704}
705
706void CrBltPresent(PCR_BLITTER pBlitter)
707{
708 if (!CrBltIsEntered(pBlitter))
709 {
710 crWarning("CrBltPresent: blitter not entered");
711 return;
712 }
713
714 if (pBlitter->CtxInfo.Base.visualBits & CR_DOUBLE_BIT)
715 pBlitter->pDispatch->SwapBuffers(pBlitter->CurrentMural.Base.id, 0);
716 else
717 pBlitter->pDispatch->Flush();
718}
719
720static int crBltImgCreateForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat)
721{
722 memset(pDst, 0, sizeof (*pDst));
723 if (enmFormat != GL_RGBA
724 && enmFormat != GL_BGRA)
725 {
726 crWarning("unsupported format 0x%x", enmFormat);
727 return VERR_NOT_IMPLEMENTED;
728 }
729
730 uint32_t bpp = 32;
731
732 uint32_t pitch = ((bpp * pSrc->width) + 7) >> 3;
733 uint32_t cbData = pitch * pSrc->height;
734 pDst->pvData = RTMemAllocZ(cbData);
735 if (!pDst->pvData)
736 {
737 crWarning("RTMemAlloc failed");
738 return VERR_NO_MEMORY;
739 }
740
741#ifdef DEBUG_misha
742 {
743 char *pTmp = (char*)pDst->pvData;
744 for (uint32_t i = 0; i < cbData; ++i)
745 {
746 pTmp[i] = (char)((1 << i) % 255);
747 }
748 }
749#endif
750
751 pDst->cbData = cbData;
752 pDst->enmFormat = enmFormat;
753 pDst->width = pSrc->width;
754 pDst->height = pSrc->height;
755 pDst->bpp = bpp;
756 pDst->pitch = pitch;
757 return VINF_SUCCESS;
758}
759
760VBOXBLITTERDECL(int) CrBltImgGetTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, GLenum enmFormat, CR_BLITTER_IMG *pDst)
761{
762 if (!CrBltIsEntered(pBlitter))
763 {
764 crWarning("CrBltImgGetTex: blitter not entered");
765 return VERR_INVALID_STATE;
766 }
767
768 int rc = crBltImgCreateForTex(pSrc, pDst, enmFormat);
769 if (!RT_SUCCESS(rc))
770 {
771 crWarning("crBltImgCreateForTex failed, rc %d", rc);
772 return rc;
773 }
774 pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
775
776#ifdef DEBUG_misha
777 {
778 GLint width = 0, height = 0, depth = 0;
779 pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_WIDTH, &width);
780 pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_HEIGHT, &height);
781 pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_DEPTH, &depth);
782
783 Assert(width == pSrc->width);
784 Assert(height == pSrc->height);
785// Assert(depth == pSrc->depth);
786 }
787#endif
788
789 pBlitter->pDispatch->GetTexImage(pSrc->target, 0, enmFormat, GL_UNSIGNED_BYTE, pDst->pvData);
790
791 pBlitter->pDispatch->BindTexture(pSrc->target, 0);
792 return VINF_SUCCESS;
793}
794
795VBOXBLITTERDECL(int) CrBltImgGetMural(PCR_BLITTER pBlitter, bool fBb, CR_BLITTER_IMG *pDst)
796{
797 if (!CrBltIsEntered(pBlitter))
798 {
799 crWarning("CrBltImgGetMural: blitter not entered");
800 return VERR_INVALID_STATE;
801 }
802
803 crWarning("NOT IMPLEMENTED");
804 return VERR_NOT_IMPLEMENTED;
805}
806
807VBOXBLITTERDECL(void) CrBltImgFree(PCR_BLITTER pBlitter, CR_BLITTER_IMG *pDst)
808{
809 if (!CrBltIsEntered(pBlitter))
810 {
811 crWarning("CrBltImgFree: blitter not entered");
812 return;
813 }
814
815 if (pDst->pvData)
816 {
817 RTMemFree(pDst->pvData);
818 pDst->pvData = NULL;
819 }
820}
821
822
823VBOXBLITTERDECL(bool) CrGlslIsSupported(CR_GLSL_CACHE *pCache)
824{
825 if (pCache->iGlVersion == 0)
826 {
827 const char * pszStr = (const char*)pCache->pDispatch->GetString(GL_VERSION);
828 pCache->iGlVersion = crStrParseGlVersion(pszStr);
829 if (pCache->iGlVersion <= 0)
830 {
831 crWarning("crStrParseGlVersion returned %d", pCache->iGlVersion);
832 pCache->iGlVersion = -1;
833 }
834 }
835
836 if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0))
837 return true;
838
839 crWarning("GLSL unsuported, gl version %d", pCache->iGlVersion);
840
841 /* @todo: we could also check for GL_ARB_shader_objects and GL_ARB_fragment_shader,
842 * but seems like chromium does not support properly gl*Object versions of shader functions used with those extensions */
843 return false;
844}
845
846#define CR_GLSL_STR_V_120 "#version 120\n"
847#define CR_GLSL_STR_EXT_TR "#extension GL_ARB_texture_rectangle : enable\n"
848#define CR_GLSL_STR_2D "2D"
849#define CR_GLSL_STR_2DRECT "2DRect"
850
851#define CR_GLSL_PATTERN_FS_NOALPHA(_ver, _ext, _tex) \
852 _ver \
853 _ext \
854 "uniform sampler" _tex " sampler0;\n" \
855 "void main()\n" \
856 "{\n" \
857 "vec2 srcCoord = vec2(gl_TexCoord[0]);\n" \
858 "gl_FragData[0].xyz = (texture" _tex "(sampler0, srcCoord).xyz);\n" \
859 "gl_FragData[0].w = 1.0;\n" \
860 "}\n"
861
862static const char* crGlslGetFsStringNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
863{
864 if (!CrGlslIsSupported(pCache))
865 {
866 crWarning("CrGlslIsSupported is false");
867 return NULL;
868 }
869
870 if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 1, 0))
871 {
872 if (enmTexTarget == GL_TEXTURE_2D)
873 return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, "", CR_GLSL_STR_2D);
874 else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB)
875 return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT);
876
877 crWarning("invalid enmTexTarget %#x", enmTexTarget);
878 return NULL;
879 }
880 else if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0))
881 {
882 if (enmTexTarget == GL_TEXTURE_2D)
883 return CR_GLSL_PATTERN_FS_NOALPHA("", "", CR_GLSL_STR_2D);
884 else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB)
885 return CR_GLSL_PATTERN_FS_NOALPHA("", CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT);
886
887 crWarning("invalid enmTexTarget %#x", enmTexTarget);
888 return NULL;
889 }
890
891 crError("crGlslGetFsStringNoAlpha: we should not be here!");
892 return NULL;
893}
894
895static int crGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget, GLuint *puiProgram)
896{
897 *puiProgram = 0;
898
899 const char*pStrFsShader = crGlslGetFsStringNoAlpha(pCache, enmTexTarget);
900 if (!pStrFsShader)
901 {
902 crWarning("crGlslGetFsStringNoAlpha failed");
903 return VERR_NOT_SUPPORTED;
904 }
905
906 int rc = VINF_SUCCESS;
907 GLchar * pBuf = NULL;
908 GLuint uiProgram = 0;
909 GLint iUniform = -1;
910 GLuint uiShader = pCache->pDispatch->CreateShader(GL_FRAGMENT_SHADER);
911 if (!uiShader)
912 {
913 crWarning("CreateShader failed");
914 return VERR_NOT_SUPPORTED;
915 }
916
917 pCache->pDispatch->ShaderSource(uiShader, 1, &pStrFsShader, NULL);
918
919 pCache->pDispatch->CompileShader(uiShader);
920
921 GLint compiled = 0;
922 pCache->pDispatch->GetShaderiv(uiShader, GL_COMPILE_STATUS, &compiled);
923
924#ifndef DEBUG_misha
925 if(!compiled)
926#endif
927 {
928 if (!pBuf)
929 pBuf = (GLchar *)RTMemAlloc(16300);
930 pCache->pDispatch->GetShaderInfoLog(uiShader, 16300, NULL, pBuf);
931#ifdef DEBUG_misha
932 if (compiled)
933 crDebug("compile success:\n-------------------\n%s\n--------\n", pBuf);
934 else
935#endif
936 {
937 crWarning("compile FAILURE:\n-------------------\n%s\n--------\n", pBuf);
938 rc = VERR_NOT_SUPPORTED;
939 goto end;
940 }
941 }
942
943 Assert(compiled);
944
945 uiProgram = pCache->pDispatch->CreateProgram();
946 if (!uiProgram)
947 {
948 rc = VERR_NOT_SUPPORTED;
949 goto end;
950 }
951
952 pCache->pDispatch->AttachShader(uiProgram, uiShader);
953
954 pCache->pDispatch->LinkProgram(uiProgram);
955
956 GLint linked;
957 pCache->pDispatch->GetProgramiv(uiProgram, GL_LINK_STATUS, &linked);
958#ifndef DEBUG_misha
959 if(!linked)
960#endif
961 {
962 if (!pBuf)
963 pBuf = (GLchar *)RTMemAlloc(16300);
964 pCache->pDispatch->GetProgramInfoLog(uiProgram, 16300, NULL, pBuf);
965#ifdef DEBUG_misha
966 if (linked)
967 crDebug("link success:\n-------------------\n%s\n--------\n", pBuf);
968 else
969#endif
970 {
971 crWarning("link FAILURE:\n-------------------\n%s\n--------\n", pBuf);
972 rc = VERR_NOT_SUPPORTED;
973 goto end;
974 }
975 }
976
977 Assert(linked);
978
979 iUniform = pCache->pDispatch->GetUniformLocation(uiProgram, "sampler0");
980 if (iUniform == -1)
981 {
982 crWarning("GetUniformLocation failed for sampler0");
983 }
984 else
985 {
986 pCache->pDispatch->Uniform1i(iUniform, 0);
987 }
988
989 *puiProgram = uiProgram;
990
991 /* avoid end finalizer from cleaning it */
992 uiProgram = 0;
993
994 end:
995 if (uiShader)
996 pCache->pDispatch->DeleteShader(uiShader);
997 if (uiProgram)
998 pCache->pDispatch->DeleteProgram(uiProgram);
999 if (pBuf)
1000 RTMemFree(pBuf);
1001 return rc;
1002}
1003
1004DECLINLINE(GLuint) crGlslProgGetNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1005{
1006 switch (enmTexTarget)
1007 {
1008 case GL_TEXTURE_2D:
1009 return pCache->uNoAlpha2DProg;
1010 case GL_TEXTURE_RECTANGLE_ARB:
1011 return pCache->uNoAlpha2DRectProg;
1012 default:
1013 crWarning("invalid tex enmTexTarget %#x", enmTexTarget);
1014 return 0;
1015 }
1016}
1017
1018DECLINLINE(GLuint*) crGlslProgGetNoAlphaPtr(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1019{
1020 switch (enmTexTarget)
1021 {
1022 case GL_TEXTURE_2D:
1023 return &pCache->uNoAlpha2DProg;
1024 case GL_TEXTURE_RECTANGLE_ARB:
1025 return &pCache->uNoAlpha2DRectProg;
1026 default:
1027 crWarning("invalid tex enmTexTarget %#x", enmTexTarget);
1028 return NULL;
1029 }
1030}
1031
1032VBOXBLITTERDECL(int) CrGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1033{
1034 GLuint*puiProgram = crGlslProgGetNoAlphaPtr(pCache, enmTexTarget);
1035 if (!puiProgram)
1036 return VERR_INVALID_PARAMETER;
1037
1038 if (*puiProgram)
1039 return VINF_SUCCESS;
1040
1041 return crGlslProgGenNoAlpha(pCache, enmTexTarget, puiProgram);
1042}
1043
1044VBOXBLITTERDECL(int) CrGlslProgGenAllNoAlpha(CR_GLSL_CACHE *pCache)
1045{
1046 int rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_2D);
1047 if (!RT_SUCCESS(rc))
1048 {
1049 crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_2D failed rc %d", rc);
1050 return rc;
1051 }
1052
1053 rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_RECTANGLE_ARB);
1054 if (!RT_SUCCESS(rc))
1055 {
1056 crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_RECTANGLE failed rc %d", rc);
1057 return rc;
1058 }
1059
1060 return VINF_SUCCESS;
1061}
1062
1063VBOXBLITTERDECL(void) CrGlslProgClear(const CR_GLSL_CACHE *pCache)
1064{
1065 pCache->pDispatch->UseProgram(0);
1066}
1067
1068VBOXBLITTERDECL(int) CrGlslProgUseNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1069{
1070 GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
1071 if (!uiProg)
1072 {
1073 crWarning("request to use inexistent program!");
1074 return VERR_INVALID_STATE;
1075 }
1076
1077 Assert(uiProg);
1078
1079 pCache->pDispatch->UseProgram(uiProg);
1080
1081 return VINF_SUCCESS;
1082}
1083
1084VBOXBLITTERDECL(int) CrGlslProgUseGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1085{
1086 GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
1087 if (!uiProg)
1088 {
1089 int rc = CrGlslProgGenNoAlpha(pCache, enmTexTarget);
1090 if (!RT_SUCCESS(rc))
1091 {
1092 crWarning("CrGlslProgGenNoAlpha failed, rc %d", rc);
1093 return rc;
1094 }
1095
1096 uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
1097 CRASSERT(uiProg);
1098 }
1099
1100 Assert(uiProg);
1101
1102 pCache->pDispatch->UseProgram(uiProg);
1103
1104 return VINF_SUCCESS;
1105}
1106
1107VBOXBLITTERDECL(bool) CrGlslNeedsCleanup(const CR_GLSL_CACHE *pCache)
1108{
1109 return pCache->uNoAlpha2DProg || pCache->uNoAlpha2DRectProg;
1110}
1111
1112VBOXBLITTERDECL(void) CrGlslCleanup(CR_GLSL_CACHE *pCache)
1113{
1114 if (pCache->uNoAlpha2DProg)
1115 {
1116 pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DProg);
1117 pCache->uNoAlpha2DProg = 0;
1118 }
1119
1120 if (pCache->uNoAlpha2DRectProg)
1121 {
1122 pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DRectProg);
1123 pCache->uNoAlpha2DRectProg = 0;
1124 }
1125}
1126
1127VBOXBLITTERDECL(void) CrGlslTerm(CR_GLSL_CACHE *pCache)
1128{
1129 CRASSERT(!CrGlslNeedsCleanup(pCache));
1130
1131 CrGlslCleanup(pCache);
1132
1133 /* sanity */
1134 memset(pCache, 0, sizeof (*pCache));
1135}
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