VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.1 KB
Line 
1/* $Id: blitter.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * Blitter API implementation
4 */
5
6/*
7 * Copyright (C) 2013-2019 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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#ifdef IN_VMSVGA3D
23# include <OpenGL/OpenGL.h>
24# include <OpenGL/gl3.h>
25# include "../include/cr_blitter.h"
26# include <iprt/assert.h>
27# define WARN AssertMsgFailed
28# define CRASSERT Assert
29DECLINLINE(void) crWarning(const char *format, ... ) {}
30#else
31# include "cr_blitter.h"
32# include "cr_spu.h"
33# include "chromium.h"
34# include "cr_error.h"
35# include "cr_net.h"
36# include "cr_rand.h"
37# include "cr_mem.h"
38# include "cr_string.h"
39# include "cr_bmpscale.h"
40#endif
41
42#include <iprt/errcore.h>
43#include <iprt/mem.h>
44
45
46
47static void crMClrFillMem(uint32_t *pu32Dst, int32_t cbDstPitch, uint32_t width, uint32_t height, uint32_t u32Color)
48{
49 for (uint32_t i = 0; i < height; ++i)
50 {
51 for (uint32_t j = 0; j < width; ++j)
52 {
53 pu32Dst[j] = u32Color;
54 }
55
56 pu32Dst = (uint32_t*)(((uint8_t*)pu32Dst) + cbDstPitch);
57 }
58}
59
60void CrMClrFillImgRect(CR_BLITTER_IMG *pDst, const RTRECT *pCopyRect, uint32_t u32Color)
61{
62 int32_t x = pCopyRect->xLeft;
63 int32_t y = pCopyRect->yTop;
64 int32_t width = pCopyRect->xRight - pCopyRect->xLeft;
65 int32_t height = pCopyRect->yBottom - pCopyRect->yTop;
66 Assert(x >= 0);
67 Assert(y >= 0);
68 uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * y + x * 4;
69
70 crMClrFillMem((uint32_t*)pu8Dst, pDst->pitch, width, height, u32Color);
71}
72
73void CrMClrFillImg(CR_BLITTER_IMG *pImg, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color)
74{
75 RTRECT Rect;
76 Rect.xLeft = 0;
77 Rect.yTop = 0;
78 Rect.xRight = pImg->width;
79 Rect.yBottom = pImg->height;
80
81
82 RTRECT Intersection;
83 /*const RTPOINT ZeroPoint = {0, 0}; - unused */
84
85 for (uint32_t i = 0; i < cRects; ++i)
86 {
87 const RTRECT * pRect = &pRects[i];
88 VBoxRectIntersected(pRect, &Rect, &Intersection);
89
90 if (VBoxRectIsZero(&Intersection))
91 continue;
92
93 CrMClrFillImgRect(pImg, &Intersection, u32Color);
94 }
95}
96
97static void crMBltMem(const uint8_t *pu8Src, int32_t cbSrcPitch, uint8_t *pu8Dst, int32_t cbDstPitch, uint32_t width, uint32_t height)
98{
99 uint32_t cbCopyRow = width * 4;
100
101 for (uint32_t i = 0; i < height; ++i)
102 {
103 memcpy(pu8Dst, pu8Src, cbCopyRow);
104
105 pu8Src += cbSrcPitch;
106 pu8Dst += cbDstPitch;
107 }
108}
109
110void CrMBltImgRect(const CR_BLITTER_IMG *pSrc, const RTPOINT *pSrcDataPoint, bool fSrcInvert, const RTRECT *pCopyRect, CR_BLITTER_IMG *pDst)
111{
112 int32_t srcX = pCopyRect->xLeft - pSrcDataPoint->x;
113 int32_t srcY = pCopyRect->yTop - pSrcDataPoint->y;
114 Assert(srcX >= 0);
115 Assert(srcY >= 0);
116 Assert(srcX < (int32_t)pSrc->width);
117 Assert(srcY < (int32_t)pSrc->height);
118
119 int32_t dstX = pCopyRect->xLeft;
120 int32_t dstY = pCopyRect->yTop;
121 Assert(dstX >= 0);
122 Assert(dstY >= 0);
123 Assert(dstX < (int32_t)pDst->width);
124 Assert(dstY < (int32_t)pDst->height);
125
126 uint8_t *pu8Src = ((uint8_t*)pSrc->pvData) + pSrc->pitch * (!fSrcInvert ? srcY : pSrc->height - srcY - 1) + srcX * 4;
127 uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * dstY + dstX * 4;
128
129 crMBltMem(pu8Src, fSrcInvert ? -((int32_t)pSrc->pitch) : (int32_t)pSrc->pitch, pu8Dst, pDst->pitch, pCopyRect->xRight - pCopyRect->xLeft, pCopyRect->yBottom - pCopyRect->yTop);
130}
131
132void CrMBltImg(const CR_BLITTER_IMG *pSrc, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst)
133{
134 RTRECT Intersection;
135 RTRECT RestrictSrcRect;
136 RestrictSrcRect.xLeft = 0;
137 RestrictSrcRect.yTop = 0;
138 RestrictSrcRect.xRight = pSrc->width;
139 RestrictSrcRect.yBottom = pSrc->height;
140 RTRECT RestrictDstRect;
141 RestrictDstRect.xLeft = 0;
142 RestrictDstRect.yTop = 0;
143 RestrictDstRect.xRight = pDst->width;
144 RestrictDstRect.yBottom = pDst->height;
145
146 for (uint32_t i = 0; i < cRects; ++i)
147 {
148 const RTRECT * pRect = &pRects[i];
149 VBoxRectIntersected(pRect, &RestrictDstRect, &Intersection);
150
151 RTRECT TranslatedSrc;
152 VBoxRectTranslated(&RestrictSrcRect, pPos->x, pPos->y, &TranslatedSrc);
153
154 VBoxRectIntersect(&Intersection, &TranslatedSrc);
155
156 if (VBoxRectIsZero(&Intersection))
157 continue;
158
159 CrMBltImgRect(pSrc, pPos, false, &Intersection, pDst);
160 }
161}
162
163#ifndef IN_VMSVGA3D
164
165void CrMBltImgRectScaled(const CR_BLITTER_IMG *pSrc, const RTPOINT *pPos, bool fSrcInvert, const RTRECT *pCopyRect, float strX, float strY, CR_BLITTER_IMG *pDst)
166{
167 RTPOINT UnscaledPos;
168 UnscaledPos.x = CR_FLOAT_RCAST(int32_t, pPos->x / strX);
169 UnscaledPos.y = CR_FLOAT_RCAST(int32_t, pPos->y / strY);
170
171 RTRECT UnscaledCopyRect;
172
173 VBoxRectUnscaled(pCopyRect, strX, strY, &UnscaledCopyRect);
174
175 if (VBoxRectIsZero(&UnscaledCopyRect))
176 {
177 WARN(("ups"));
178 return;
179 }
180
181 int32_t srcX = UnscaledCopyRect.xLeft - UnscaledPos.x;
182 int32_t srcY = UnscaledCopyRect.yTop - UnscaledPos.y;
183 if (srcX < 0)
184 {
185 WARN(("ups"));
186 srcX = 0;
187 }
188 if (srcY < 0)
189 {
190 WARN(("ups"));
191 srcY = 0;
192 }
193
194 if ((GLuint)srcX >= pSrc->width)
195 {
196 WARN(("ups"));
197 return;
198 }
199
200 if ((GLuint)srcY >= pSrc->height)
201 {
202 WARN(("ups"));
203 return;
204 }
205
206 Assert(srcX >= 0);
207 Assert(srcY >= 0);
208 Assert(srcX < (int32_t)pSrc->width);
209 Assert(srcY < (int32_t)pSrc->height);
210
211 int32_t dstX = pCopyRect->xLeft;
212 int32_t dstY = pCopyRect->yTop;
213 Assert(dstX >= 0);
214 Assert(dstY >= 0);
215
216 int32_t UnscaledSrcWidth = UnscaledCopyRect.xRight - UnscaledCopyRect.xLeft;
217 int32_t UnscaledSrcHeight = UnscaledCopyRect.yBottom - UnscaledCopyRect.yTop;
218
219 if (UnscaledSrcWidth + srcX > (GLint)pSrc->width)
220 UnscaledSrcWidth = pSrc->width - srcX;
221
222 if (UnscaledSrcHeight + srcY > (GLint)pSrc->height)
223 UnscaledSrcHeight = pSrc->height - srcY;
224
225 uint8_t *pu8Src = ((uint8_t*)pSrc->pvData) + pSrc->pitch * (!fSrcInvert ? srcY : pSrc->height - srcY - 1) + srcX * 4;
226 uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * dstY + dstX * 4;
227
228 CrBmpScale32(pu8Dst, pDst->pitch,
229 pCopyRect->xRight - pCopyRect->xLeft, pCopyRect->yBottom - pCopyRect->yTop,
230 pu8Src,
231 fSrcInvert ? -((int32_t)pSrc->pitch) : (int32_t)pSrc->pitch,
232 UnscaledSrcWidth, UnscaledSrcHeight);
233}
234
235
236void CrMBltImgScaled(const CR_BLITTER_IMG *pSrc, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst)
237{
238 int32_t srcWidth = pSrcRectSize->cx;
239 int32_t srcHeight = pSrcRectSize->cy;
240 int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
241 int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
242
243 float strX = ((float)dstWidth) / srcWidth;
244 float strY = ((float)dstHeight) / srcHeight;
245 Assert(dstWidth != srcWidth || dstHeight != srcHeight);
246
247 RTRECT Intersection;
248 RTRECT ScaledRestrictSrcRect;
249 ScaledRestrictSrcRect.xLeft = 0;
250 ScaledRestrictSrcRect.yTop = 0;
251 ScaledRestrictSrcRect.xRight = CR_FLOAT_RCAST(int32_t, pSrc->width * strX);
252 ScaledRestrictSrcRect.yBottom = CR_FLOAT_RCAST(int32_t, pSrc->height * strY);
253 RTRECT RestrictDstRect;
254 RestrictDstRect.xLeft = 0;
255 RestrictDstRect.yTop = 0;
256 RestrictDstRect.xRight = pDst->width;
257 RestrictDstRect.yBottom = pDst->height;
258
259 RTPOINT Pos = {pDstRect->xLeft, pDstRect->yTop};
260
261 for (uint32_t i = 0; i < cRects; ++i)
262 {
263 const RTRECT * pRect = &pRects[i];
264 VBoxRectIntersected(pRect, &RestrictDstRect, &Intersection);
265
266 RTRECT TranslatedSrc;
267 VBoxRectTranslated(&ScaledRestrictSrcRect, Pos.x, Pos.y, &TranslatedSrc);
268
269 VBoxRectIntersect(&Intersection, &TranslatedSrc);
270
271 if (VBoxRectIsZero(&Intersection))
272 continue;
273
274 CrMBltImgRectScaled(pSrc, &Pos, false, &Intersection, strX, strY, pDst);
275 }
276}
277
278#endif /* !IN_VMSVGA3D */
279
280
281/**
282 *
283 * @param pBlitter The blitter to initialize.
284 * @param pCtxBase Contains the blitter context info. Its value is
285 * treated differently depending on the fCreateNewCtx
286 * value.
287 * @param fCreateNewCtx If true, then @a pCtxBase must NOT be NULL. Its
288 * visualBits is used as a visual bits info for the new
289 * context, its id field is used to specified the
290 * shared context id to be used for blitter context.
291 * The id can be null to specify no shared context is
292 * needed
293 *
294 * If false and @a pCtxBase is NOT null AND its id
295 * field is NOT null, then specified the blitter
296 * context to be used blitter treats it as if it has
297 * default ogl state.
298 *
299 * Otherwise, the blitter works in a "no-context" mode,
300 * i.e. the caller is responsible for making a proper
301 * context current before calling the blitter. Note
302 * that BltEnter/Leave MUST still be called, but the
303 * proper context must be set before doing BltEnter,
304 * and ResoreContext info is ignored in that case. Also
305 * note that the blitter caches the current window
306 * info, and assumes the current context's values are
307 * preserved wrt that window before the calls, so if
308 * one uses different contexts for one blitter, the
309 * blitter current window values must be explicitly
310 * reset by doing CrBltMuralSetCurrentInfo(pBlitter,
311 * NULL).
312 * @param fForceDrawBlt If true this forces the blitter to always use
313 * glDrawXxx-based blits even if
314 * GL_EXT_framebuffer_blit. This is needed because
315 * BlitFramebufferEXT is often known to be buggy, and
316 * glDrawXxx-based blits appear to be more reliable.
317 * @param pShaders
318 * @param pDispatch
319 */
320VBOXBLITTERDECL(int) CrBltInit(PCR_BLITTER pBlitter, const CR_BLITTER_CONTEXT *pCtxBase,
321 bool fCreateNewCtx, bool fForceDrawBlt, const CR_GLSL_CACHE *pShaders,
322 SPUDispatchTable *pDispatch)
323{
324 if (pCtxBase && pCtxBase->Base.id < 0)
325 {
326 crWarning("Default share context not initialized!");
327 return VERR_INVALID_PARAMETER;
328 }
329
330 if (!pCtxBase && fCreateNewCtx)
331 {
332 crWarning("pCtxBase is zero while fCreateNewCtx is set!");
333 return VERR_INVALID_PARAMETER;
334 }
335
336 RT_ZERO(*pBlitter);
337
338 pBlitter->pDispatch = pDispatch;
339 if (pCtxBase)
340 pBlitter->CtxInfo = *pCtxBase;
341
342 pBlitter->Flags.ForceDrawBlit = fForceDrawBlt;
343
344 if (fCreateNewCtx)
345 {
346#ifdef IN_VMSVGA3D
347 /** @todo IN_VMSVGA3D */
348 pBlitter->CtxInfo.Base.id = 0;
349#else
350 pBlitter->CtxInfo.Base.id = pDispatch->CreateContext("", pCtxBase->Base.visualBits, pCtxBase->Base.id);
351#endif
352 if (!pBlitter->CtxInfo.Base.id)
353 {
354 RT_ZERO(*pBlitter);
355 crWarning("CreateContext failed!");
356 return VERR_GENERAL_FAILURE;
357 }
358 pBlitter->Flags.CtxCreated = 1;
359 }
360
361 if (pShaders)
362 {
363 pBlitter->pGlslCache = pShaders;
364 pBlitter->Flags.ShadersGloal = 1;
365 }
366 else
367 {
368 CrGlslInit(&pBlitter->LocalGlslCache, pDispatch);
369 pBlitter->pGlslCache = &pBlitter->LocalGlslCache;
370 }
371
372 return VINF_SUCCESS;
373}
374
375VBOXBLITTERDECL(int) CrBltCleanup(PCR_BLITTER pBlitter)
376{
377 if (CrBltIsEntered(pBlitter))
378 {
379 WARN(("CrBltBlitTexTex: blitter is entered"));
380 return VERR_INVALID_STATE;
381 }
382
383 if (pBlitter->Flags.ShadersGloal || !CrGlslNeedsCleanup(&pBlitter->LocalGlslCache))
384 return VINF_SUCCESS;
385
386 int rc = CrBltEnter(pBlitter);
387 if (!RT_SUCCESS(rc))
388 {
389 WARN(("CrBltEnter failed, rc %d", rc));
390 return rc;
391 }
392
393 CrGlslCleanup(&pBlitter->LocalGlslCache);
394
395 CrBltLeave(pBlitter);
396
397 return VINF_SUCCESS;
398}
399
400void CrBltTerm(PCR_BLITTER pBlitter)
401{
402#ifdef IN_VMSVGA3D
403 /** @todo IN_VMSVGA3D */
404#else
405 if (pBlitter->Flags.CtxCreated)
406 pBlitter->pDispatch->DestroyContext(pBlitter->CtxInfo.Base.id);
407#endif
408 memset(pBlitter, 0, sizeof (*pBlitter));
409}
410
411int CrBltMuralSetCurrentInfo(PCR_BLITTER pBlitter, const CR_BLITTER_WINDOW *pMural)
412{
413 if (pMural)
414 {
415 if (!memcmp(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural)))
416 return VINF_SUCCESS;
417 memcpy(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural));
418 }
419 else
420 {
421 if (CrBltIsEntered(pBlitter))
422 {
423 WARN(("can not set null mural for entered bleater"));
424 return VERR_INVALID_STATE;
425 }
426 if (!pBlitter->CurrentMural.Base.id)
427 return VINF_SUCCESS;
428 pBlitter->CurrentMural.Base.id = 0;
429 }
430
431 pBlitter->Flags.CurrentMuralChanged = 1;
432
433 if (!CrBltIsEntered(pBlitter))
434 return VINF_SUCCESS;
435
436 if (!pBlitter->CtxInfo.Base.id)
437 {
438 WARN(("setting current mural for entered no-context blitter"));
439 return VERR_INVALID_STATE;
440 }
441
442 WARN(("changing mural for entered blitter, is is somewhat expected?"));
443
444#ifdef IN_VMSVGA3D
445 /** @todo IN_VMSVGA3D */
446#else
447 pBlitter->pDispatch->Flush();
448
449 pBlitter->pDispatch->MakeCurrent(pMural->Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
450#endif
451
452 return VINF_SUCCESS;
453}
454
455
456#ifndef IN_VMSVGA3D
457
458static 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)
459{
460 GLenum filter = CRBLT_FILTER_FROM_FLAGS(fFlags);
461 pBlitter->pDispatch->BindFramebufferEXT(GL_READ_FRAMEBUFFER, pBlitter->idFBO);
462 pBlitter->pDispatch->FramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pSrc->target, pSrc->hwid, 0);
463 pBlitter->pDispatch->ReadBuffer(GL_COLOR_ATTACHMENT0);
464
465 for (uint32_t i = 0; i < cRects; ++i)
466 {
467 const RTRECT * pSrcRect = &paSrcRect[i];
468 const RTRECT * pDstRect = &paDstRect[i];
469 int32_t srcY1;
470 int32_t srcY2;
471 int32_t dstY1;
472 int32_t dstY2;
473 int32_t srcX1 = pSrcRect->xLeft;
474 int32_t srcX2 = pSrcRect->xRight;
475 int32_t dstX1 = pDstRect->xLeft;
476 int32_t dstX2 = pDstRect->xRight;
477
478 if (CRBLT_F_INVERT_SRC_YCOORDS & fFlags)
479 {
480 srcY1 = pSrc->height - pSrcRect->yTop;
481 srcY2 = pSrc->height - pSrcRect->yBottom;
482 }
483 else
484 {
485 srcY1 = pSrcRect->yTop;
486 srcY2 = pSrcRect->yBottom;
487 }
488
489 if (CRBLT_F_INVERT_DST_YCOORDS & fFlags)
490 {
491 dstY1 = pDstSize->cy - pDstRect->yTop;
492 dstY2 = pDstSize->cy - pDstRect->yBottom;
493 }
494 else
495 {
496 dstY1 = pDstRect->yTop;
497 dstY2 = pDstRect->yBottom;
498 }
499
500 if (srcY1 > srcY2)
501 {
502 if (dstY1 > dstY2)
503 {
504 /* use srcY1 < srcY2 && dstY1 < dstY2 whenever possible to avoid GPU driver bugs */
505 int32_t tmp = srcY1;
506 srcY1 = srcY2;
507 srcY2 = tmp;
508 tmp = dstY1;
509 dstY1 = dstY2;
510 dstY2 = tmp;
511 }
512 }
513
514 if (srcX1 > srcX2)
515 {
516 if (dstX1 > dstX2)
517 {
518 /* use srcX1 < srcX2 && dstX1 < dstX2 whenever possible to avoid GPU driver bugs */
519 int32_t tmp = srcX1;
520 srcX1 = srcX2;
521 srcX2 = tmp;
522 tmp = dstX1;
523 dstX1 = dstX2;
524 dstX2 = tmp;
525 }
526 }
527
528 pBlitter->pDispatch->BlitFramebufferEXT(srcX1, srcY1, srcX2, srcY2,
529 dstX1, dstY1, dstX2, dstY2,
530 GL_COLOR_BUFFER_BIT, filter);
531 }
532
533 return VINF_SUCCESS;
534}
535
536/* GL_TRIANGLE_FAN */
537DECLINLINE(GLfloat*) crBltVtRectTFNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
538{
539 /* going ccw:
540 * 1. (left;top) 4. (right;top)
541 * | ^
542 * > |
543 * 2. (left;bottom) -> 3. (right;bottom) */
544 /* xLeft yTop */
545 pBuff[0] = ((float)pRect->xLeft)/((float)normalX);
546 pBuff[1] = ((float)(height ? height - pRect->yTop : pRect->yTop))/((float)normalY);
547
548 /* xLeft yBottom */
549 pBuff[2] = pBuff[0];
550 pBuff[3] = ((float)(height ? height - pRect->yBottom : pRect->yBottom))/((float)normalY);
551
552 /* xRight yBottom */
553 pBuff[4] = ((float)pRect->xRight)/((float)normalX);
554 pBuff[5] = pBuff[3];
555
556 /* xRight yTop */
557 pBuff[6] = pBuff[4];
558 pBuff[7] = pBuff[1];
559 return &pBuff[8];
560}
561
562DECLINLINE(GLfloat*) crBltVtRectsTFNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
563{
564 for (uint32_t i = 0; i < cRects; ++i)
565 {
566 pBuff = crBltVtRectTFNormalized(&paRects[i], normalX, normalY, pBuff, height);
567 }
568 return pBuff;
569}
570
571DECLINLINE(GLint*) crBltVtRectTF(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, uint32_t height)
572{
573 (void)normalX; (void)normalY;
574
575 /* xLeft yTop */
576 pBuff[0] = pRect->xLeft;
577 pBuff[1] = height ? height - pRect->yTop : pRect->yTop;
578
579 /* xLeft yBottom */
580 pBuff[2] = pBuff[0];
581 pBuff[3] = height ? height - pRect->yBottom : pRect->yBottom;
582
583 /* xRight yBottom */
584 pBuff[4] = pRect->xRight;
585 pBuff[5] = pBuff[3];
586
587 /* xRight yTop */
588 pBuff[6] = pBuff[4];
589 pBuff[7] = pBuff[1];
590 return &pBuff[8];
591}
592
593DECLINLINE(GLubyte*) crBltVtFillRectIndicies(GLubyte *pIndex, GLubyte *piBase)
594{
595 GLubyte iBase = *piBase;
596 /* triangle 1 */
597 pIndex[0] = iBase;
598 pIndex[1] = iBase + 1;
599 pIndex[2] = iBase + 2;
600
601 /* triangle 2 */
602 pIndex[3] = iBase;
603 pIndex[4] = iBase + 2;
604 pIndex[5] = iBase + 3;
605 *piBase = iBase + 4;
606 return pIndex + 6;
607}
608
609/* Indexed GL_TRIANGLES */
610DECLINLINE(GLfloat*) crBltVtRectITNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
611{
612 GLfloat* ret = crBltVtRectTFNormalized(pRect, normalX, normalY, pBuff, height);
613 return ret;
614}
615
616DECLINLINE(GLint*) crBltVtRectIT(RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height)
617{
618 GLint* ret = crBltVtRectTF(pRect, normalX, normalY, pBuff, height);
619
620 if (ppIndex)
621 *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase);
622
623 return ret;
624}
625
626DECLINLINE(GLuint) crBltVtGetNumVerticiesTF(GLuint cRects)
627{
628 return cRects * 4;
629}
630
631#define crBltVtGetNumVerticiesIT crBltVtGetNumVerticiesTF
632
633DECLINLINE(GLuint) crBltVtGetNumIndiciesIT(GLuint cRects)
634{
635 return 6 * cRects;
636}
637
638
639static GLfloat* crBltVtRectsITNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height)
640{
641 uint32_t i;
642 for (i = 0; i < cRects; ++i)
643 {
644 pBuff = crBltVtRectITNormalized(&paRects[i], normalX, normalY, pBuff, height);
645 }
646
647
648 if (ppIndex)
649 {
650 GLubyte *pIndex = (GLubyte*)pBuff;
651 *ppIndex = pIndex;
652 for (i = 0; i < cRects; ++i)
653 {
654 pIndex = crBltVtFillRectIndicies(pIndex, piBase);
655 }
656 pBuff = (GLfloat*)pIndex;
657 }
658
659 return pBuff;
660}
661
662static void *crBltBufGet(PCR_BLITTER_BUFFER pBuffer, GLuint cbBuffer)
663{
664 if (pBuffer->cbBuffer < cbBuffer)
665 {
666 if (pBuffer->pvBuffer)
667 {
668 RTMemFree(pBuffer->pvBuffer);
669 }
670
671#ifndef DEBUG_misha
672 /* debugging: ensure we calculate proper buffer size */
673 cbBuffer += 16;
674#endif
675
676 pBuffer->pvBuffer = RTMemAlloc(cbBuffer);
677 if (pBuffer->pvBuffer)
678 pBuffer->cbBuffer = cbBuffer;
679 else
680 {
681 crWarning("failed to allocate buffer of size %d", cbBuffer);
682 pBuffer->cbBuffer = 0;
683 }
684 }
685 return pBuffer->pvBuffer;
686}
687
688#endif /* !IN_VMSVGA3D */
689
690
691static void crBltCheckSetupViewport(PCR_BLITTER pBlitter, const RTRECTSIZE *pDstSize, bool fFBODraw)
692{
693 bool fUpdateViewport = pBlitter->Flags.CurrentMuralChanged;
694 if ( pBlitter->CurrentSetSize.cx != pDstSize->cx
695 || pBlitter->CurrentSetSize.cy != pDstSize->cy)
696 {
697 pBlitter->CurrentSetSize = *pDstSize;
698#ifdef IN_VMSVGA3D
699 /** @todo IN_VMSVGA3D */
700#else
701 pBlitter->pDispatch->MatrixMode(GL_PROJECTION);
702 pBlitter->pDispatch->LoadIdentity();
703 pBlitter->pDispatch->Ortho(0, pDstSize->cx, 0, pDstSize->cy, -1, 1);
704#endif
705 fUpdateViewport = true;
706 }
707
708 if (fUpdateViewport)
709 {
710#ifdef IN_VMSVGA3D
711 /** @todo IN_VMSVGA3D */
712#else
713 pBlitter->pDispatch->Viewport(0, 0, pBlitter->CurrentSetSize.cx, pBlitter->CurrentSetSize.cy);
714#endif
715 pBlitter->Flags.CurrentMuralChanged = 0;
716 }
717
718 pBlitter->Flags.LastWasFBODraw = fFBODraw;
719}
720
721
722#ifndef IN_VMSVGA3D
723
724static 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)
725{
726 GLuint normalX, normalY;
727 uint32_t srcHeight = (fFlags & CRBLT_F_INVERT_SRC_YCOORDS) ? pSrc->height : 0;
728 uint32_t dstHeight = (fFlags & CRBLT_F_INVERT_DST_YCOORDS) ? pDstSize->cy : 0;
729
730 switch (pSrc->target)
731 {
732 case GL_TEXTURE_2D:
733 {
734 normalX = pSrc->width;
735 normalY = pSrc->height;
736 break;
737 }
738
739 case GL_TEXTURE_RECTANGLE_ARB:
740 {
741 normalX = 1;
742 normalY = 1;
743 break;
744 }
745
746 default:
747 {
748 crWarning("Unsupported texture target 0x%x", pSrc->target);
749 return VERR_INVALID_PARAMETER;
750 }
751 }
752
753 Assert(pSrc->hwid);
754
755 pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
756
757 if (cRects == 1)
758 {
759 /* just optimization to draw a single rect with GL_TRIANGLE_FAN */
760 GLfloat *pVerticies;
761 GLfloat *pTexCoords;
762 GLuint cElements = crBltVtGetNumVerticiesTF(cRects);
763
764 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies));
765 pTexCoords = crBltVtRectsTFNormalized(paDstRect, cRects, 1, 1, pVerticies, dstHeight);
766 crBltVtRectsTFNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, srcHeight);
767
768 pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
769 pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
770
771 pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
772 pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords);
773
774 pBlitter->pDispatch->Enable(pSrc->target);
775
776 pBlitter->pDispatch->DrawArrays(GL_TRIANGLE_FAN, 0, cElements);
777
778 pBlitter->pDispatch->Disable(pSrc->target);
779
780 pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
781 pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
782 }
783 else
784 {
785 GLfloat *pVerticies;
786 GLfloat *pTexCoords;
787 GLubyte *pIndicies;
788 GLuint cElements = crBltVtGetNumVerticiesIT(cRects);
789 GLuint cIndicies = crBltVtGetNumIndiciesIT(cRects);
790 GLubyte iIdxBase = 0;
791
792 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies) + cIndicies * sizeof (*pIndicies));
793 pTexCoords = crBltVtRectsITNormalized(paDstRect, cRects, 1, 1, pVerticies, &pIndicies, &iIdxBase, dstHeight);
794 crBltVtRectsITNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, NULL, NULL, srcHeight);
795
796 pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
797 pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
798
799 pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
800 pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords);
801
802 pBlitter->pDispatch->Enable(pSrc->target);
803
804 pBlitter->pDispatch->DrawElements(GL_TRIANGLES, cIndicies, GL_UNSIGNED_BYTE, pIndicies);
805
806 pBlitter->pDispatch->Disable(pSrc->target);
807
808 pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
809 pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
810 }
811
812 pBlitter->pDispatch->BindTexture(pSrc->target, 0);
813
814 return VINF_SUCCESS;
815}
816
817static int crBltInitOnMakeCurent(PCR_BLITTER pBlitter)
818{
819 const char * pszExtension = (const char*)pBlitter->pDispatch->GetString(GL_EXTENSIONS);
820 if (crStrstr(pszExtension, "GL_EXT_framebuffer_object"))
821 {
822 pBlitter->Flags.SupportsFBO = 1;
823 pBlitter->pDispatch->GenFramebuffersEXT(1, &pBlitter->idFBO);
824 Assert(pBlitter->idFBO);
825 }
826 else
827 crWarning("GL_EXT_framebuffer_object not supported, blitter can only blit to window");
828
829 if (crStrstr(pszExtension, "GL_ARB_pixel_buffer_object"))
830 pBlitter->Flags.SupportsPBO = 1;
831 else
832 crWarning("GL_ARB_pixel_buffer_object not supported");
833
834 /* BlitFramebuffer seems to be buggy on Intel,
835 * try always glDrawXxx for now */
836 if (!pBlitter->Flags.ForceDrawBlit && crStrstr(pszExtension, "GL_EXT_framebuffer_blit"))
837 {
838 pBlitter->pfnBlt = crBltBlitTexBufImplFbo;
839 }
840 else
841 {
842// crWarning("GL_EXT_framebuffer_blit not supported, will use Draw functions for blitting, which might be less efficient");
843 pBlitter->pfnBlt = crBltBlitTexBufImplDraw2D;
844 }
845
846 /* defaults. but just in case */
847 pBlitter->pDispatch->MatrixMode(GL_TEXTURE);
848 pBlitter->pDispatch->LoadIdentity();
849 pBlitter->pDispatch->MatrixMode(GL_MODELVIEW);
850 pBlitter->pDispatch->LoadIdentity();
851
852 return VINF_SUCCESS;
853}
854
855#endif /* !IN_VMSVGA3D */
856
857
858void CrBltLeave(PCR_BLITTER pBlitter)
859{
860 if (!pBlitter->cEnters)
861 {
862 WARN(("blitter not entered!"));
863 return;
864 }
865
866 if (--pBlitter->cEnters)
867 return;
868
869#ifdef IN_VMSVGA3D
870 /** @todo IN_VMSVGA3D */
871#else
872 if (pBlitter->Flags.SupportsFBO)
873 {
874 pBlitter->pDispatch->BindFramebufferEXT(GL_FRAMEBUFFER, 0);
875 pBlitter->pDispatch->DrawBuffer(GL_BACK);
876 pBlitter->pDispatch->ReadBuffer(GL_BACK);
877 }
878
879 pBlitter->pDispatch->Flush();
880
881 if (pBlitter->CtxInfo.Base.id)
882 pBlitter->pDispatch->MakeCurrent(0, 0, 0);
883#endif
884}
885
886int CrBltEnter(PCR_BLITTER pBlitter)
887{
888 if (!pBlitter->CurrentMural.Base.id && pBlitter->CtxInfo.Base.id)
889 {
890 WARN(("current mural not initialized!"));
891 return VERR_INVALID_STATE;
892 }
893
894 if (pBlitter->cEnters++)
895 return VINF_SUCCESS;
896
897 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)*/
898 {
899#ifdef IN_VMSVGA3D
900 /** @todo IN_VMSVGA3D */
901#else
902 pBlitter->pDispatch->MakeCurrent(pBlitter->CurrentMural.Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
903#endif
904 }
905
906 if (pBlitter->Flags.Initialized)
907 return VINF_SUCCESS;
908
909#ifdef IN_VMSVGA3D
910 /** @todo IN_VMSVGA3D */
911 int rc = VINF_SUCCESS;
912#else
913 int rc = crBltInitOnMakeCurent(pBlitter);
914#endif
915 if (RT_SUCCESS(rc))
916 {
917 pBlitter->Flags.Initialized = 1;
918 return VINF_SUCCESS;
919 }
920
921 WARN(("crBltInitOnMakeCurent failed, rc %d", rc));
922 CrBltLeave(pBlitter);
923 return rc;
924}
925
926
927static 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)
928{
929#ifdef IN_VMSVGA3D
930 /** @todo IN_VMSVGA3D */
931#else
932 pBlitter->pDispatch->DrawBuffer(enmDstBuff);
933
934 crBltCheckSetupViewport(pBlitter, pDstSize, enmDstBuff == GL_DRAW_FRAMEBUFFER);
935
936 if (!(fFlags & CRBLT_F_NOALPHA))
937 pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
938 else
939 {
940 int rc = pBlitter->Flags.ShadersGloal
941 ? CrGlslProgUseNoAlpha(pBlitter->pGlslCache, pSrc->target)
942 : CrGlslProgUseGenNoAlpha(&pBlitter->LocalGlslCache, pSrc->target);
943
944 if (!RT_SUCCESS(rc))
945 {
946 crWarning("Failed to use no-alpha program rc %d!, falling back to default blit", rc);
947 pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
948 return;
949 }
950
951 /* since we use shaders, we need to use draw commands rather than framebuffer blits.
952 * force using draw-based blitting */
953 crBltBlitTexBufImplDraw2D(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
954
955 Assert(pBlitter->Flags.ShadersGloal || &pBlitter->LocalGlslCache == pBlitter->pGlslCache);
956
957 CrGlslProgClear(pBlitter->pGlslCache);
958 }
959#endif
960}
961
962void CrBltCheckUpdateViewport(PCR_BLITTER pBlitter)
963{
964 RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height};
965 crBltCheckSetupViewport(pBlitter, &DstSize, false);
966}
967
968void CrBltBlitTexMural(PCR_BLITTER pBlitter, bool fBb, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
969{
970 if (!CrBltIsEntered(pBlitter))
971 {
972 WARN(("CrBltBlitTexMural: blitter not entered"));
973 return;
974 }
975
976 RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height};
977
978#ifdef IN_VMSVGA3D
979 /** @todo IN_VMSVGA3D */
980#else
981 pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
982#endif
983
984 crBltBlitTexBuf(pBlitter, pSrc, paSrcRects, fBb ? GL_BACK : GL_FRONT, &DstSize, paDstRects, cRects, fFlags);
985}
986
987
988#ifndef IN_VMSVGA3D
989
990void CrBltBlitTexTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *pSrcRect, const VBOXVR_TEXTURE *pDst, const RTRECT *pDstRect, uint32_t cRects, uint32_t fFlags)
991{
992 if (!CrBltIsEntered(pBlitter))
993 {
994 WARN(("CrBltBlitTexTex: blitter not entered"));
995 return;
996 }
997
998 RTRECTSIZE DstSize = {(uint32_t)pDst->width, (uint32_t)pDst->height};
999
1000 pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, pBlitter->idFBO);
1001
1002 /** @todo mag/min filters ? */
1003
1004 pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, pDst->hwid, 0);
1005
1006// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
1007// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
1008
1009 crBltBlitTexBuf(pBlitter, pSrc, pSrcRect, GL_DRAW_FRAMEBUFFER, &DstSize, pDstRect, cRects, fFlags);
1010
1011 pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, 0, 0);
1012}
1013
1014void CrBltPresent(PCR_BLITTER pBlitter)
1015{
1016 if (!CrBltIsEntered(pBlitter))
1017 {
1018 WARN(("CrBltPresent: blitter not entered"));
1019 return;
1020 }
1021
1022 if (pBlitter->CtxInfo.Base.visualBits & CR_DOUBLE_BIT)
1023 pBlitter->pDispatch->SwapBuffers(pBlitter->CurrentMural.Base.id, 0);
1024 else
1025 pBlitter->pDispatch->Flush();
1026}
1027
1028static int crBltImgInitBaseForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat)
1029{
1030 memset(pDst, 0, sizeof (*pDst));
1031 if (enmFormat != GL_RGBA
1032 && enmFormat != GL_BGRA)
1033 {
1034 WARN(("unsupported format 0x%x", enmFormat));
1035 return VERR_NOT_IMPLEMENTED;
1036 }
1037
1038 uint32_t bpp = 32;
1039
1040 uint32_t pitch = ((bpp * pSrc->width) + 7) >> 3;
1041 uint32_t cbData = pitch * pSrc->height;
1042 pDst->cbData = cbData;
1043 pDst->enmFormat = enmFormat;
1044 pDst->width = pSrc->width;
1045 pDst->height = pSrc->height;
1046 pDst->bpp = bpp;
1047 pDst->pitch = pitch;
1048 return VINF_SUCCESS;
1049}
1050
1051static int crBltImgCreateForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat)
1052{
1053 int rc = crBltImgInitBaseForTex(pSrc, pDst, enmFormat);
1054 if (!RT_SUCCESS(rc))
1055 {
1056 crWarning("crBltImgInitBaseForTex failed rc %d", rc);
1057 return rc;
1058 }
1059
1060 uint32_t cbData = pDst->cbData;
1061 pDst->pvData = RTMemAllocZ(cbData);
1062 if (!pDst->pvData)
1063 {
1064 crWarning("RTMemAlloc failed");
1065 return VERR_NO_MEMORY;
1066 }
1067
1068#ifdef DEBUG_misha
1069 {
1070 char *pTmp = (char*)pDst->pvData;
1071 for (uint32_t i = 0; i < cbData; ++i)
1072 {
1073 pTmp[i] = (char)((1 << i) % 255);
1074 }
1075 }
1076#endif
1077 return VINF_SUCCESS;
1078}
1079
1080VBOXBLITTERDECL(int) CrBltImgGetTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, GLenum enmFormat, CR_BLITTER_IMG *pDst)
1081{
1082 if (!CrBltIsEntered(pBlitter))
1083 {
1084 WARN(("CrBltImgGetTex: blitter not entered"));
1085 return VERR_INVALID_STATE;
1086 }
1087
1088 int rc = crBltImgCreateForTex(pSrc, pDst, enmFormat);
1089 if (!RT_SUCCESS(rc))
1090 {
1091 crWarning("crBltImgCreateForTex failed, rc %d", rc);
1092 return rc;
1093 }
1094 pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
1095
1096#ifdef DEBUG_misha
1097 {
1098 GLint width = 0, height = 0, depth = 0;
1099 pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_WIDTH, &width);
1100 pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_HEIGHT, &height);
1101 pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_DEPTH, &depth);
1102
1103 Assert(width == pSrc->width);
1104 Assert(height == pSrc->height);
1105// Assert(depth == pSrc->depth);
1106 }
1107#endif
1108
1109 pBlitter->pDispatch->GetTexImage(pSrc->target, 0, enmFormat, GL_UNSIGNED_BYTE, pDst->pvData);
1110
1111 pBlitter->pDispatch->BindTexture(pSrc->target, 0);
1112 return VINF_SUCCESS;
1113}
1114
1115VBOXBLITTERDECL(int) CrBltImgGetMural(PCR_BLITTER pBlitter, bool fBb, CR_BLITTER_IMG *pDst)
1116{
1117 (void)fBb; (void)pDst;
1118 if (!CrBltIsEntered(pBlitter))
1119 {
1120 WARN(("CrBltImgGetMural: blitter not entered"));
1121 return VERR_INVALID_STATE;
1122 }
1123
1124 WARN(("NOT IMPLEMENTED"));
1125 return VERR_NOT_IMPLEMENTED;
1126}
1127
1128VBOXBLITTERDECL(void) CrBltImgFree(PCR_BLITTER pBlitter, CR_BLITTER_IMG *pDst)
1129{
1130 if (!CrBltIsEntered(pBlitter))
1131 {
1132 WARN(("CrBltImgFree: blitter not entered"));
1133 return;
1134 }
1135
1136 if (pDst->pvData)
1137 {
1138 RTMemFree(pDst->pvData);
1139 pDst->pvData = NULL;
1140 }
1141}
1142
1143
1144VBOXBLITTERDECL(bool) CrGlslIsSupported(CR_GLSL_CACHE *pCache)
1145{
1146 if (pCache->iGlVersion == 0)
1147 {
1148 const char * pszStr = (const char*)pCache->pDispatch->GetString(GL_VERSION);
1149 pCache->iGlVersion = crStrParseGlVersion(pszStr);
1150 if (pCache->iGlVersion <= 0)
1151 {
1152 crWarning("crStrParseGlVersion returned %d", pCache->iGlVersion);
1153 pCache->iGlVersion = -1;
1154 }
1155 }
1156
1157 if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0))
1158 return true;
1159
1160 crWarning("GLSL unsuported, gl version %d", pCache->iGlVersion);
1161
1162 /** @todo we could also check for GL_ARB_shader_objects and GL_ARB_fragment_shader,
1163 * but seems like chromium does not support properly gl*Object versions of shader functions used with those extensions */
1164 return false;
1165}
1166
1167#define CR_GLSL_STR_V_120 "#version 120\n"
1168#define CR_GLSL_STR_EXT_TR "#extension GL_ARB_texture_rectangle : enable\n"
1169#define CR_GLSL_STR_2D "2D"
1170#define CR_GLSL_STR_2DRECT "2DRect"
1171
1172#define CR_GLSL_PATTERN_FS_NOALPHA(_ver, _ext, _tex) \
1173 _ver \
1174 _ext \
1175 "uniform sampler" _tex " sampler0;\n" \
1176 "void main()\n" \
1177 "{\n" \
1178 "vec2 srcCoord = vec2(gl_TexCoord[0]);\n" \
1179 "gl_FragData[0].xyz = (texture" _tex "(sampler0, srcCoord).xyz);\n" \
1180 "gl_FragData[0].w = 1.0;\n" \
1181 "}\n"
1182
1183static const char* crGlslGetFsStringNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1184{
1185 if (!CrGlslIsSupported(pCache))
1186 {
1187 crWarning("CrGlslIsSupported is false");
1188 return NULL;
1189 }
1190
1191 if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 1, 0))
1192 {
1193 if (enmTexTarget == GL_TEXTURE_2D)
1194 return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, "", CR_GLSL_STR_2D);
1195 else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB)
1196 return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT);
1197
1198 crWarning("invalid enmTexTarget %#x", enmTexTarget);
1199 return NULL;
1200 }
1201 else if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0))
1202 {
1203 if (enmTexTarget == GL_TEXTURE_2D)
1204 return CR_GLSL_PATTERN_FS_NOALPHA("", "", CR_GLSL_STR_2D);
1205 else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB)
1206 return CR_GLSL_PATTERN_FS_NOALPHA("", CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT);
1207
1208 crWarning("invalid enmTexTarget %#x", enmTexTarget);
1209 return NULL;
1210 }
1211
1212 crError("crGlslGetFsStringNoAlpha: we should not be here!");
1213 return NULL;
1214}
1215
1216static int crGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget, GLuint *puiProgram)
1217{
1218 *puiProgram = 0;
1219
1220 const char*pStrFsShader = crGlslGetFsStringNoAlpha(pCache, enmTexTarget);
1221 if (!pStrFsShader)
1222 {
1223 crWarning("crGlslGetFsStringNoAlpha failed");
1224 return VERR_NOT_SUPPORTED;
1225 }
1226
1227 int rc = VINF_SUCCESS;
1228 GLchar * pBuf = NULL;
1229 GLuint uiProgram = 0;
1230 GLint iUniform = -1;
1231 GLuint uiShader = pCache->pDispatch->CreateShader(GL_FRAGMENT_SHADER);
1232 if (!uiShader)
1233 {
1234 crWarning("CreateShader failed");
1235 return VERR_NOT_SUPPORTED;
1236 }
1237
1238 pCache->pDispatch->ShaderSource(uiShader, 1, &pStrFsShader, NULL);
1239
1240 pCache->pDispatch->CompileShader(uiShader);
1241
1242 GLint compiled = 0;
1243 pCache->pDispatch->GetShaderiv(uiShader, GL_COMPILE_STATUS, &compiled);
1244
1245#ifndef DEBUG_misha
1246 if(!compiled)
1247#endif
1248 {
1249 if (!pBuf)
1250 pBuf = (GLchar *)RTMemAlloc(16300);
1251 pCache->pDispatch->GetShaderInfoLog(uiShader, 16300, NULL, pBuf);
1252#ifdef DEBUG_misha
1253 if (compiled)
1254 crDebug("compile success:\n-------------------\n%s\n--------\n", pBuf);
1255 else
1256#endif
1257 {
1258 crWarning("compile FAILURE:\n-------------------\n%s\n--------\n", pBuf);
1259 rc = VERR_NOT_SUPPORTED;
1260 goto end;
1261 }
1262 }
1263
1264 Assert(compiled);
1265
1266 uiProgram = pCache->pDispatch->CreateProgram();
1267 if (!uiProgram)
1268 {
1269 rc = VERR_NOT_SUPPORTED;
1270 goto end;
1271 }
1272
1273 pCache->pDispatch->AttachShader(uiProgram, uiShader);
1274
1275 pCache->pDispatch->LinkProgram(uiProgram);
1276
1277 GLint linked;
1278 pCache->pDispatch->GetProgramiv(uiProgram, GL_LINK_STATUS, &linked);
1279#ifndef DEBUG_misha
1280 if(!linked)
1281#endif
1282 {
1283 if (!pBuf)
1284 pBuf = (GLchar *)RTMemAlloc(16300);
1285 pCache->pDispatch->GetProgramInfoLog(uiProgram, 16300, NULL, pBuf);
1286#ifdef DEBUG_misha
1287 if (linked)
1288 crDebug("link success:\n-------------------\n%s\n--------\n", pBuf);
1289 else
1290#endif
1291 {
1292 crWarning("link FAILURE:\n-------------------\n%s\n--------\n", pBuf);
1293 rc = VERR_NOT_SUPPORTED;
1294 goto end;
1295 }
1296 }
1297
1298 Assert(linked);
1299
1300 iUniform = pCache->pDispatch->GetUniformLocation(uiProgram, "sampler0");
1301 if (iUniform == -1)
1302 {
1303 crWarning("GetUniformLocation failed for sampler0");
1304 }
1305 else
1306 {
1307 pCache->pDispatch->Uniform1i(iUniform, 0);
1308 }
1309
1310 *puiProgram = uiProgram;
1311
1312 /* avoid end finalizer from cleaning it */
1313 uiProgram = 0;
1314
1315 end:
1316 if (uiShader)
1317 pCache->pDispatch->DeleteShader(uiShader);
1318 if (uiProgram)
1319 pCache->pDispatch->DeleteProgram(uiProgram);
1320 if (pBuf)
1321 RTMemFree(pBuf);
1322 return rc;
1323}
1324
1325DECLINLINE(GLuint) crGlslProgGetNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1326{
1327 switch (enmTexTarget)
1328 {
1329 case GL_TEXTURE_2D:
1330 return pCache->uNoAlpha2DProg;
1331 case GL_TEXTURE_RECTANGLE_ARB:
1332 return pCache->uNoAlpha2DRectProg;
1333 default:
1334 crWarning("invalid tex enmTexTarget %#x", enmTexTarget);
1335 return 0;
1336 }
1337}
1338
1339DECLINLINE(GLuint*) crGlslProgGetNoAlphaPtr(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1340{
1341 switch (enmTexTarget)
1342 {
1343 case GL_TEXTURE_2D:
1344 return &pCache->uNoAlpha2DProg;
1345 case GL_TEXTURE_RECTANGLE_ARB:
1346 return &pCache->uNoAlpha2DRectProg;
1347 default:
1348 crWarning("invalid tex enmTexTarget %#x", enmTexTarget);
1349 return NULL;
1350 }
1351}
1352
1353VBOXBLITTERDECL(int) CrGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1354{
1355 GLuint*puiProgram = crGlslProgGetNoAlphaPtr(pCache, enmTexTarget);
1356 if (!puiProgram)
1357 return VERR_INVALID_PARAMETER;
1358
1359 if (*puiProgram)
1360 return VINF_SUCCESS;
1361
1362 return crGlslProgGenNoAlpha(pCache, enmTexTarget, puiProgram);
1363}
1364
1365VBOXBLITTERDECL(int) CrGlslProgGenAllNoAlpha(CR_GLSL_CACHE *pCache)
1366{
1367 int rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_2D);
1368 if (!RT_SUCCESS(rc))
1369 {
1370 crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_2D failed rc %d", rc);
1371 return rc;
1372 }
1373
1374 rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_RECTANGLE_ARB);
1375 if (!RT_SUCCESS(rc))
1376 {
1377 crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_RECTANGLE failed rc %d", rc);
1378 return rc;
1379 }
1380
1381 return VINF_SUCCESS;
1382}
1383
1384VBOXBLITTERDECL(void) CrGlslProgClear(const CR_GLSL_CACHE *pCache)
1385{
1386 pCache->pDispatch->UseProgram(0);
1387}
1388
1389VBOXBLITTERDECL(int) CrGlslProgUseNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1390{
1391 GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
1392 if (!uiProg)
1393 {
1394 crWarning("request to use inexistent program!");
1395 return VERR_INVALID_STATE;
1396 }
1397
1398 Assert(uiProg);
1399
1400 pCache->pDispatch->UseProgram(uiProg);
1401
1402 return VINF_SUCCESS;
1403}
1404
1405VBOXBLITTERDECL(int) CrGlslProgUseGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
1406{
1407 GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
1408 if (!uiProg)
1409 {
1410 int rc = CrGlslProgGenNoAlpha(pCache, enmTexTarget);
1411 if (!RT_SUCCESS(rc))
1412 {
1413 crWarning("CrGlslProgGenNoAlpha failed, rc %d", rc);
1414 return rc;
1415 }
1416
1417 uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
1418 CRASSERT(uiProg);
1419 }
1420
1421 Assert(uiProg);
1422
1423 pCache->pDispatch->UseProgram(uiProg);
1424
1425 return VINF_SUCCESS;
1426}
1427
1428#endif /* !IN_VMSVGA3D */
1429
1430VBOXBLITTERDECL(bool) CrGlslNeedsCleanup(const CR_GLSL_CACHE *pCache)
1431{
1432 return pCache->uNoAlpha2DProg || pCache->uNoAlpha2DRectProg;
1433}
1434
1435VBOXBLITTERDECL(void) CrGlslCleanup(CR_GLSL_CACHE *pCache)
1436{
1437 if (pCache->uNoAlpha2DProg)
1438 {
1439#ifdef IN_VMSVGA3D
1440 /** @todo IN_VMSVGA3D */
1441#else
1442 pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DProg);
1443#endif
1444 pCache->uNoAlpha2DProg = 0;
1445 }
1446
1447 if (pCache->uNoAlpha2DRectProg)
1448 {
1449#ifdef IN_VMSVGA3D
1450 /** @todo IN_VMSVGA3D */
1451#else
1452 pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DRectProg);
1453#endif
1454 pCache->uNoAlpha2DRectProg = 0;
1455 }
1456}
1457
1458VBOXBLITTERDECL(void) CrGlslTerm(CR_GLSL_CACHE *pCache)
1459{
1460 CRASSERT(!CrGlslNeedsCleanup(pCache));
1461
1462 CrGlslCleanup(pCache);
1463
1464 /* sanity */
1465 memset(pCache, 0, sizeof (*pCache));
1466}
1467
1468#ifndef IN_VMSVGA3D
1469
1470/*TdBlt*/
1471static void crTdBltCheckPBO(PCR_TEXDATA pTex)
1472{
1473 if (pTex->idPBO)
1474 return;
1475
1476 PCR_BLITTER pBlitter = pTex->pBlitter;
1477
1478 if (!pBlitter->Flags.SupportsPBO)
1479 return;
1480
1481 pBlitter->pDispatch->GenBuffersARB(1, &pTex->idPBO);
1482 if (!pTex->idPBO)
1483 {
1484 crWarning("PBO create failed");
1485 return;
1486 }
1487
1488 pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
1489 pBlitter->pDispatch->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
1490 pTex->Tex.width*pTex->Tex.height*4,
1491 0, GL_STREAM_READ_ARB);
1492 pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
1493}
1494
1495static uint32_t crTdBltTexCreate(PCR_BLITTER pBlitter, uint32_t width, uint32_t height, GLenum enmTarget)
1496{
1497 uint32_t tex = 0;
1498 pBlitter->pDispatch->GenTextures(1, &tex);
1499 if (!tex)
1500 {
1501 crWarning("Tex create failed");
1502 return 0;
1503 }
1504
1505 pBlitter->pDispatch->BindTexture(enmTarget, tex);
1506 pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1507 pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1508 pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_WRAP_S, GL_CLAMP);
1509 pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_WRAP_T, GL_CLAMP);
1510 pBlitter->pDispatch->TexImage2D(enmTarget, 0, GL_RGBA8,
1511 width, height,
1512 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
1513
1514
1515 /*Restore gl state*/
1516 pBlitter->pDispatch->BindTexture(enmTarget, 0);
1517
1518 return tex;
1519}
1520
1521int crTdBltCheckInvertTex(PCR_TEXDATA pTex)
1522{
1523 if (pTex->idInvertTex)
1524 return VINF_SUCCESS;
1525
1526 pTex->idInvertTex = crTdBltTexCreate(pTex->pBlitter, pTex->Tex.width, pTex->Tex.height, pTex->Tex.target);
1527 if (!pTex->idInvertTex)
1528 {
1529 crWarning("Invert Tex create failed");
1530 return VERR_GENERAL_FAILURE;
1531 }
1532 return VINF_SUCCESS;
1533}
1534
1535#endif /* !IN_VMSVGA3D */
1536
1537
1538void crTdBltImgRelease(PCR_TEXDATA pTex)
1539{
1540 pTex->Flags.DataValid = 0;
1541}
1542
1543void crTdBltImgFree(PCR_TEXDATA pTex)
1544{
1545 if (!pTex->Img.pvData)
1546 {
1547 Assert(!pTex->Flags.DataValid);
1548 return;
1549 }
1550
1551 crTdBltImgRelease(pTex);
1552
1553 Assert(!pTex->Flags.DataValid);
1554
1555
1556 if (pTex->idPBO)
1557 {
1558 PCR_BLITTER pBlitter = pTex->pBlitter;
1559
1560 Assert(CrBltIsEntered(pBlitter));
1561#ifdef IN_VMSVGA3D
1562 /** @todo IN_VMSVGA3D */
1563#else
1564 pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
1565 pBlitter->pDispatch->UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
1566 pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
1567#endif
1568 }
1569 else
1570 {
1571 Assert(pTex->Img.pvData);
1572 RTMemFree(pTex->Img.pvData);
1573 }
1574
1575 pTex->Img.pvData = NULL;
1576}
1577
1578
1579#ifndef IN_VMSVGA3D
1580
1581int crTdBltImgAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted)
1582{
1583 void *pvData = pTex->Img.pvData;
1584 Assert(!pTex->Flags.DataValid);
1585 int rc = crBltImgInitBaseForTex(&pTex->Tex, &pTex->Img, enmFormat);
1586 if (!RT_SUCCESS(rc))
1587 {
1588 WARN(("crBltImgInitBaseForTex failed rc %d", rc));
1589 return rc;
1590 }
1591
1592 PCR_BLITTER pBlitter = pTex->pBlitter;
1593 Assert(CrBltIsEntered(pBlitter));
1594 pBlitter->pDispatch->BindTexture(pTex->Tex.target, fInverted ? pTex->idInvertTex : pTex->Tex.hwid);
1595
1596 pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
1597
1598 if (pvData)
1599 {
1600 if (pTex->idPBO)
1601 {
1602 pBlitter->pDispatch->UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
1603 pvData = NULL;
1604
1605 }
1606 }
1607 else
1608 {
1609 if (!pTex->idPBO)
1610 {
1611 pvData = RTMemAlloc(4*pTex->Tex.width*pTex->Tex.height);
1612 if (!pvData)
1613 {
1614 WARN(("Out of memory in crTdBltImgAcquire"));
1615 pBlitter->pDispatch->BindTexture(pTex->Tex.target, 0);
1616 return VERR_NO_MEMORY;
1617 }
1618 }
1619 }
1620
1621 Assert(!pvData == !!pTex->idPBO);
1622
1623 /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/
1624 pBlitter->pDispatch->GetTexImage(GL_TEXTURE_2D, 0, enmFormat, GL_UNSIGNED_BYTE, pvData);
1625
1626 /*restore gl state*/
1627 pBlitter->pDispatch->BindTexture(pTex->Tex.target, 0);
1628
1629 if (pTex->idPBO)
1630 {
1631 pvData = pBlitter->pDispatch->MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
1632 if (!pvData)
1633 {
1634 WARN(("Failed to MapBuffer in CrHlpGetTexImage"));
1635 return VERR_GENERAL_FAILURE;
1636 }
1637
1638 pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
1639 }
1640
1641 Assert(pvData);
1642 pTex->Img.pvData = pvData;
1643 pTex->Flags.DataValid = 1;
1644 pTex->Flags.DataInverted = fInverted;
1645 return VINF_SUCCESS;
1646}
1647
1648#endif /* !IN_VMSVGA3D */
1649
1650
1651/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataInvalidateNe or CrTdBltDataCleanup */
1652VBOXBLITTERDECL(int) CrTdBltDataRelease(PCR_TEXDATA pTex)
1653{
1654 if (!pTex->Flags.Entered)
1655 {
1656 WARN(("tex not entered"));
1657 return VERR_INVALID_STATE;
1658 }
1659
1660 if (!pTex->Flags.DataAcquired)
1661 {
1662 WARN(("Data NOT acquired"));
1663 return VERR_INVALID_STATE;
1664 }
1665
1666 Assert(pTex->Img.pvData);
1667 Assert(pTex->Flags.DataValid);
1668
1669 pTex->Flags.DataAcquired = 0;
1670
1671 return VINF_SUCCESS;
1672}
1673
1674static void crTdBltDataFree(PCR_TEXDATA pTex)
1675{
1676 crTdBltImgFree(pTex);
1677
1678 if (pTex->pScaledCache)
1679 CrTdBltDataFreeNe(pTex->pScaledCache);
1680}
1681
1682/* discard the texture data cached with previous CrTdBltDataAcquire.
1683 * Must be called wit data released (CrTdBltDataRelease) */
1684VBOXBLITTERDECL(int) CrTdBltDataFree(PCR_TEXDATA pTex)
1685{
1686 if (!pTex->Flags.Entered)
1687 {
1688 WARN(("tex not entered"));
1689 return VERR_INVALID_STATE;
1690 }
1691
1692 crTdBltDataFree(pTex);
1693
1694 return VINF_SUCCESS;
1695}
1696
1697VBOXBLITTERDECL(void) CrTdBltDataInvalidateNe(PCR_TEXDATA pTex)
1698{
1699 crTdBltImgRelease(pTex);
1700
1701 if (pTex->pScaledCache)
1702 CrTdBltDataInvalidateNe(pTex->pScaledCache);
1703}
1704
1705VBOXBLITTERDECL(int) CrTdBltDataFreeNe(PCR_TEXDATA pTex)
1706{
1707 if (!pTex->Img.pvData)
1708 return VINF_SUCCESS;
1709
1710 bool fEntered = false;
1711 if (pTex->idPBO)
1712 {
1713 int rc = CrTdBltEnter(pTex);
1714 if (!RT_SUCCESS(rc))
1715 {
1716 WARN(("err"));
1717 return rc;
1718 }
1719
1720 fEntered = true;
1721 }
1722
1723 crTdBltDataFree(pTex);
1724
1725 if (fEntered)
1726 CrTdBltLeave(pTex);
1727
1728 return VINF_SUCCESS;
1729}
1730
1731static void crTdBltSdCleanupCacheNe(PCR_TEXDATA pTex)
1732{
1733 if (pTex->pScaledCache)
1734 {
1735 CrTdBltDataCleanupNe(pTex->pScaledCache);
1736 CrTdRelease(pTex->pScaledCache);
1737 pTex->pScaledCache = NULL;
1738 }
1739}
1740
1741static void crTdBltDataCleanup(PCR_TEXDATA pTex)
1742{
1743 crTdBltImgFree(pTex);
1744
1745 PCR_BLITTER pBlitter = pTex->pBlitter;
1746
1747 if (pTex->idPBO)
1748 {
1749 Assert(CrBltIsEntered(pBlitter));
1750#ifdef IN_VMSVGA3D
1751 /** @todo IN_VMSVGA3D */
1752#else
1753 pBlitter->pDispatch->DeleteBuffersARB(1, &pTex->idPBO);
1754#endif
1755 pTex->idPBO = 0;
1756 }
1757
1758 if (pTex->idInvertTex)
1759 {
1760 Assert(CrBltIsEntered(pBlitter));
1761#ifdef IN_VMSVGA3D
1762 /** @todo IN_VMSVGA3D */
1763#else
1764 pBlitter->pDispatch->DeleteTextures(1, &pTex->idInvertTex);
1765#endif
1766 pTex->idInvertTex = 0;
1767 }
1768
1769 crTdBltSdCleanupCacheNe(pTex);
1770}
1771
1772/* does same as CrTdBltDataFree, and in addition cleans up */
1773VBOXBLITTERDECL(int) CrTdBltDataCleanup(PCR_TEXDATA pTex)
1774{
1775 if (!pTex->Flags.Entered)
1776 {
1777 WARN(("tex not entered"));
1778 return VERR_INVALID_STATE;
1779 }
1780
1781 crTdBltDataCleanup(pTex);
1782
1783 return VINF_SUCCESS;
1784}
1785
1786VBOXBLITTERDECL(int) CrTdBltDataCleanupNe(PCR_TEXDATA pTex)
1787{
1788 bool fEntered = false;
1789 if (pTex->idPBO || pTex->idInvertTex)
1790 {
1791 int rc = CrTdBltEnter(pTex);
1792 if (!RT_SUCCESS(rc))
1793 {
1794 WARN(("err"));
1795 return rc;
1796 }
1797
1798 fEntered = true;
1799 }
1800
1801 crTdBltDataCleanup(pTex);
1802
1803 if (fEntered)
1804 CrTdBltLeave(pTex);
1805
1806 return VINF_SUCCESS;
1807}
1808
1809
1810#ifndef IN_VMSVGA3D
1811
1812/* acquire the texture data, returns the cached data in case it is cached.
1813 * the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataFree or CrTdBltDataCleanup.
1814 * */
1815VBOXBLITTERDECL(int) CrTdBltDataAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, const CR_BLITTER_IMG**ppImg)
1816{
1817 if (!pTex->Flags.Entered)
1818 {
1819 WARN(("tex not entered"));
1820 return VERR_INVALID_STATE;
1821 }
1822
1823 if (pTex->Flags.DataAcquired)
1824 {
1825 WARN(("Data acquired already"));
1826 return VERR_INVALID_STATE;
1827 }
1828
1829 if (pTex->Flags.DataValid && pTex->Img.enmFormat == enmFormat && !pTex->Flags.DataInverted == !fInverted)
1830 {
1831 Assert(pTex->Img.pvData);
1832 *ppImg = &pTex->Img;
1833 pTex->Flags.DataAcquired = 1;
1834 return VINF_SUCCESS;
1835 }
1836
1837 crTdBltImgRelease(pTex);
1838
1839 crTdBltCheckPBO(pTex);
1840
1841 int rc;
1842
1843 if (fInverted)
1844 {
1845 rc = crTdBltCheckInvertTex(pTex);
1846 if (!RT_SUCCESS(rc))
1847 {
1848 WARN(("crTdBltCheckInvertTex failed rc %d", rc));
1849 return rc;
1850 }
1851
1852 RTRECT SrcRect, DstRect;
1853 VBOXVR_TEXTURE InvertTex;
1854
1855 InvertTex = pTex->Tex;
1856 InvertTex.hwid = pTex->idInvertTex;
1857
1858 SrcRect.xLeft = 0;
1859 SrcRect.yTop = InvertTex.height;
1860 SrcRect.xRight = InvertTex.width;
1861 SrcRect.yBottom = 0;
1862
1863 DstRect.xLeft = 0;
1864 DstRect.yTop = 0;
1865 DstRect.xRight = InvertTex.width;
1866 DstRect.yBottom = InvertTex.height;
1867
1868 CrBltBlitTexTex(pTex->pBlitter, &pTex->Tex, &SrcRect, &InvertTex, &DstRect, 1, 0);
1869 }
1870
1871 rc = crTdBltImgAcquire(pTex, enmFormat, fInverted);
1872 if (!RT_SUCCESS(rc))
1873 {
1874 WARN(("crTdBltImgAcquire failed rc %d", rc));
1875 return rc;
1876 }
1877
1878 Assert(pTex->Img.pvData);
1879 *ppImg = &pTex->Img;
1880 pTex->Flags.DataAcquired = 1;
1881
1882 return VINF_SUCCESS;
1883}
1884
1885DECLINLINE(void) crTdResize(PCR_TEXDATA pTex, const VBOXVR_TEXTURE *pVrTex)
1886{
1887 crTdBltDataCleanup(pTex);
1888
1889 pTex->Tex = *pVrTex;
1890}
1891
1892static DECLCALLBACK(void) ctTdBltSdReleased(struct CR_TEXDATA *pTexture)
1893{
1894 PCR_BLITTER pBlitter = pTexture->pBlitter;
1895
1896 int rc = CrBltEnter(pBlitter);
1897 if (!RT_SUCCESS(rc))
1898 {
1899 WARN(("CrBltEnter failed, rc %d", rc));
1900 return;
1901 }
1902
1903 CrTdBltDataCleanupNe(pTexture);
1904
1905 pBlitter->pDispatch->DeleteTextures(1, &pTexture->Tex.hwid);
1906
1907 CrBltLeave(pBlitter);
1908
1909 RTMemFree(pTexture);
1910}
1911
1912static int ctTdBltSdCreate(PCR_BLITTER pBlitter, uint32_t width, uint32_t height, GLenum enmTarget, PCR_TEXDATA *ppScaledCache)
1913{
1914 PCR_TEXDATA pScaledCache;
1915
1916 Assert(CrBltIsEntered(pBlitter));
1917
1918 *ppScaledCache = NULL;
1919
1920 pScaledCache = (PCR_TEXDATA)RTMemAlloc(sizeof (*pScaledCache));
1921 if (!pScaledCache)
1922 {
1923 WARN(("RTMemAlloc failed"));
1924 return VERR_NO_MEMORY;
1925 }
1926
1927 VBOXVR_TEXTURE Tex;
1928 Tex.width = width;
1929 Tex.height = height;
1930 Tex.target = enmTarget;
1931 Tex.hwid = crTdBltTexCreate(pBlitter, width, height, enmTarget);
1932 if (!Tex.hwid)
1933 {
1934 WARN(("Tex create failed"));
1935 RTMemFree(pScaledCache);
1936 return VERR_GENERAL_FAILURE;
1937 }
1938
1939 CrTdInit(pScaledCache, &Tex, pBlitter, ctTdBltSdReleased);
1940
1941 *ppScaledCache = pScaledCache;
1942
1943 return VINF_SUCCESS;
1944}
1945
1946static int ctTdBltSdGet(PCR_TEXDATA pTex, uint32_t width, uint32_t height, PCR_TEXDATA *ppScaledCache)
1947{
1948 Assert(CrBltIsEntered(pTex->pBlitter));
1949
1950 PCR_TEXDATA pScaledCache;
1951
1952 *ppScaledCache = NULL;
1953
1954 if (!pTex->pScaledCache)
1955 {
1956 int rc = ctTdBltSdCreate(pTex->pBlitter, width, height, pTex->Tex.target, &pScaledCache);
1957 if (!RT_SUCCESS(rc))
1958 {
1959 WARN(("ctTdBltSdCreate failed %d", rc));
1960 return rc;
1961 }
1962
1963 pTex->pScaledCache = pScaledCache;
1964 }
1965 else
1966 {
1967 int cmp = pTex->pScaledCache->Tex.width - width;
1968 if (cmp <= 0)
1969 cmp = pTex->pScaledCache->Tex.height - height;
1970
1971 if (!cmp)
1972 pScaledCache = pTex->pScaledCache;
1973 else if (cmp < 0) /* current cache is "less" than the requested */
1974 {
1975 int rc = ctTdBltSdCreate(pTex->pBlitter, width, height, pTex->Tex.target, &pScaledCache);
1976 if (!RT_SUCCESS(rc))
1977 {
1978 WARN(("ctTdBltSdCreate failed %d", rc));
1979 return rc;
1980 }
1981
1982 pScaledCache->pScaledCache = pTex->pScaledCache;
1983 pTex->pScaledCache = pScaledCache;
1984 }
1985 else /* cmp > 0 */
1986 {
1987 int rc = ctTdBltSdGet(pTex->pScaledCache, width, height, &pScaledCache);
1988 if (!RT_SUCCESS(rc))
1989 {
1990 WARN(("ctTdBltSdGet failed %d", rc));
1991 return rc;
1992 }
1993 }
1994 }
1995
1996 Assert(pScaledCache);
1997
1998#if 0
1999 {
2000 VBOXVR_TEXTURE Tex;
2001 Tex.width = width;
2002 Tex.height = height;
2003 Tex.target = pTex->Tex.target;
2004 Tex.hwid = crTdBltTexCreate(pTex, width, height);
2005 if (!Tex.hwid)
2006 {
2007 WARN(("Tex create failed"));
2008 return VERR_GENERAL_FAILURE;
2009 }
2010
2011 pTex->pBlitter->pDispatch->DeleteTextures(1, &pTex->pScaledCache->Tex.hwid);
2012
2013 crTdResize(pTex->pScaledCache, &Tex);
2014 }
2015#endif
2016
2017 *ppScaledCache = pScaledCache;
2018 return VINF_SUCCESS;
2019}
2020
2021static int ctTdBltSdGetUpdated(PCR_TEXDATA pTex, uint32_t width, uint32_t height, PCR_TEXDATA *ppScaledCache)
2022{
2023 PCR_TEXDATA pScaledCache;
2024
2025 *ppScaledCache = NULL;
2026 int rc = ctTdBltSdGet(pTex, width, height, &pScaledCache);
2027 if (!RT_SUCCESS(rc))
2028 {
2029 WARN(("ctTdBltSdGet failed %d", rc));
2030 return rc;
2031 }
2032
2033 Assert(width == (uint32_t)pScaledCache->Tex.width);
2034 Assert(height == (uint32_t)pScaledCache->Tex.height);
2035
2036 if (!pScaledCache->Flags.DataValid)
2037 {
2038 RTRECT SrcRect, DstRect;
2039
2040 SrcRect.xLeft = 0;
2041 SrcRect.yTop = 0;
2042 SrcRect.xRight = pTex->Tex.width;
2043 SrcRect.yBottom = pTex->Tex.height;
2044
2045 DstRect.xLeft = 0;
2046 DstRect.yTop = 0;
2047 DstRect.xRight = width;
2048 DstRect.yBottom = height;
2049
2050 CrBltBlitTexTex(pTex->pBlitter, &pTex->Tex, &SrcRect, &pScaledCache->Tex, &DstRect, 1, 0);
2051 }
2052
2053 *ppScaledCache = pScaledCache;
2054
2055 return VINF_SUCCESS;
2056}
2057
2058VBOXBLITTERDECL(int) CrTdBltDataAcquireScaled(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, uint32_t width, uint32_t height, const CR_BLITTER_IMG**ppImg)
2059{
2060 if ((uint32_t)pTex->Tex.width == width && (uint32_t)pTex->Tex.height == height)
2061 return CrTdBltDataAcquire(pTex, enmFormat, fInverted, ppImg);
2062
2063 if (!pTex->Flags.Entered)
2064 {
2065 WARN(("tex not entered"));
2066 return VERR_INVALID_STATE;
2067 }
2068
2069 PCR_TEXDATA pScaledCache;
2070
2071 int rc = ctTdBltSdGetUpdated(pTex, width, height, &pScaledCache);
2072 if (!RT_SUCCESS(rc))
2073 {
2074 WARN(("ctTdBltSdGetUpdated failed rc %d", rc));
2075 return rc;
2076 }
2077
2078 rc = CrTdBltEnter(pScaledCache);
2079 if (!RT_SUCCESS(rc))
2080 {
2081 WARN(("CrTdBltEnter failed rc %d", rc));
2082 return rc;
2083 }
2084
2085 rc = CrTdBltDataAcquire(pScaledCache, enmFormat, fInverted, ppImg);
2086 if (!RT_SUCCESS(rc))
2087 {
2088 WARN(("CrTdBltDataAcquire failed rc %d", rc));
2089 CrTdBltLeave(pTex->pScaledCache);
2090 return rc;
2091 }
2092
2093 return VINF_SUCCESS;
2094}
2095
2096VBOXBLITTERDECL(int) CrTdBltDataReleaseScaled(PCR_TEXDATA pTex, const CR_BLITTER_IMG *pImg)
2097{
2098 PCR_TEXDATA pScaledCache = RT_FROM_MEMBER(pImg, CR_TEXDATA, Img);
2099 int rc = CrTdBltDataRelease(pScaledCache);
2100 if (!RT_SUCCESS(rc))
2101 {
2102 WARN(("CrTdBltDataRelease failed rc %d", rc));
2103 return rc;
2104 }
2105
2106 if (pScaledCache != pTex)
2107 CrTdBltLeave(pScaledCache);
2108
2109 return VINF_SUCCESS;
2110}
2111
2112VBOXBLITTERDECL(void) CrTdBltScaleCacheMoveTo(PCR_TEXDATA pTex, PCR_TEXDATA pDstTex)
2113{
2114 if (!pTex->pScaledCache)
2115 return;
2116
2117 crTdBltSdCleanupCacheNe(pDstTex);
2118
2119 pDstTex->pScaledCache = pTex->pScaledCache;
2120 pTex->pScaledCache = NULL;
2121}
2122
2123#endif /* !IN_VMSVGA3D */
2124
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