VirtualBox

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

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

crOpenGL: blitter fixes

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