VirtualBox

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

Last change on this file since 57541 was 53728, checked in by vboxsync, 10 years ago

VMSVGA3d/darwin: Using the use OpenGL 3.2 Core profile works better, but there are some snags like glGetString(GT_EXTENSIONS). Addressed a bunch of warnings.

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