VirtualBox

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

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