VirtualBox

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

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

crOpenGL: scaling bugfixes; rename stretch -> scale

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