summaryrefslogtreecommitdiff
path: root/src/VBox/GuestHost/OpenGL/util
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/GuestHost/OpenGL/util
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/util')
-rw-r--r--src/VBox/GuestHost/OpenGL/util/blitter.cpp1751
-rw-r--r--src/VBox/GuestHost/OpenGL/util/bmpscale.cpp319
-rw-r--r--src/VBox/GuestHost/OpenGL/util/compositor.cpp1015
-rw-r--r--src/VBox/GuestHost/OpenGL/util/dll.c74
-rw-r--r--src/VBox/GuestHost/OpenGL/util/error.c27
-rw-r--r--src/VBox/GuestHost/OpenGL/util/hash.c492
-rw-r--r--src/VBox/GuestHost/OpenGL/util/htable.cpp195
-rw-r--r--src/VBox/GuestHost/OpenGL/util/net.c18
-rw-r--r--src/VBox/GuestHost/OpenGL/util/pixel.c20
-rw-r--r--src/VBox/GuestHost/OpenGL/util/string.c123
-rw-r--r--src/VBox/GuestHost/OpenGL/util/util.def4
-rw-r--r--src/VBox/GuestHost/OpenGL/util/vboxhgcm.c149
-rw-r--r--src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c2
-rw-r--r--src/VBox/GuestHost/OpenGL/util/vreg.cpp1692
14 files changed, 5535 insertions, 346 deletions
diff --git a/src/VBox/GuestHost/OpenGL/util/blitter.cpp b/src/VBox/GuestHost/OpenGL/util/blitter.cpp
new file mode 100644
index 00000000..a14c0916
--- /dev/null
+++ b/src/VBox/GuestHost/OpenGL/util/blitter.cpp
@@ -0,0 +1,1751 @@
+/* $Id$ */
+
+/** @file
+ * Blitter API implementation
+ */
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#include "cr_blitter.h"
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_net.h"
+#include "cr_rand.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+#include <iprt/mem.h>
+
+/* @param pCtxBase - contains the blitter context info. Its value is treated differently depending on the fCreateNewCtx value
+ * @param fCreateNewCtx - if true - the pCtxBase must NOT be NULL. its visualBits is used as a visual bits info for the new context,
+ * its id field is used to specified the shared context id to be used for blitter context.
+ * The id can be null to specify no shared context is needed
+ * if false - if pCtxBase is NOT null AND its id field is NOT null -
+ * specified the blitter context to be used
+ * blitter treats it as if it has default ogl state.
+ * otherwise -
+ * the blitter works in a "no-context" mode, i.e. a caller is responsible
+ * to making a proper context current before calling the blitter.
+ * Note that BltEnter/Leave MUST still be called, but the proper context
+ * must be set before doing BltEnter, and ResoreContext info is ignored in that case.
+ * Also note that blitter caches the current window info, and assumes the current context's values are preserved
+ * wrt that window before the calls, so if one uses different contexts for one blitter,
+ * the blitter current window values must be explicitly reset by doing CrBltMuralSetCurrentInfo(pBlitter, NULL)
+ * @param fForceDrawBlt - if true - forces the blitter to always use glDrawXxx-based blits even if GL_EXT_framebuffer_blit.
+ * This is needed because BlitFramebufferEXT is known to be often buggy, and glDrawXxx-based blits appear to be more reliable
+ */
+VBOXBLITTERDECL(int) CrBltInit(PCR_BLITTER pBlitter, const CR_BLITTER_CONTEXT *pCtxBase, bool fCreateNewCtx, bool fForceDrawBlt, const CR_GLSL_CACHE *pShaders, SPUDispatchTable *pDispatch)
+{
+ if (pCtxBase && pCtxBase->Base.id < 0)
+ {
+ crWarning("Default share context not initialized!");
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (!pCtxBase && fCreateNewCtx)
+ {
+ crWarning("pCtxBase is zero while fCreateNewCtx is set!");
+ return VERR_INVALID_PARAMETER;
+ }
+
+ memset(pBlitter, 0, sizeof (*pBlitter));
+
+ pBlitter->pDispatch = pDispatch;
+ if (pCtxBase)
+ pBlitter->CtxInfo = *pCtxBase;
+
+ pBlitter->Flags.ForceDrawBlit = fForceDrawBlt;
+
+ if (fCreateNewCtx)
+ {
+ pBlitter->CtxInfo.Base.id = pDispatch->CreateContext("", pCtxBase->Base.visualBits, pCtxBase->Base.id);
+ if (!pBlitter->CtxInfo.Base.id)
+ {
+ memset(pBlitter, 0, sizeof (*pBlitter));
+ crWarning("CreateContext failed!");
+ return VERR_GENERAL_FAILURE;
+ }
+ pBlitter->Flags.CtxCreated = 1;
+ }
+
+ if (pShaders)
+ {
+ pBlitter->pGlslCache = pShaders;
+ pBlitter->Flags.ShadersGloal = 1;
+ }
+ else
+ {
+ CrGlslInit(&pBlitter->LocalGlslCache, pDispatch);
+ pBlitter->pGlslCache = &pBlitter->LocalGlslCache;
+ }
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrBltCleanup(PCR_BLITTER pBlitter)
+{
+ if (CrBltIsEntered(pBlitter))
+ {
+ WARN(("CrBltBlitTexTex: blitter is entered"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pBlitter->Flags.ShadersGloal || !CrGlslNeedsCleanup(&pBlitter->LocalGlslCache))
+ return VINF_SUCCESS;
+
+ int rc = CrBltEnter(pBlitter);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrBltEnter failed, rc %d", rc));
+ return rc;
+ }
+
+ CrGlslCleanup(&pBlitter->LocalGlslCache);
+
+ CrBltLeave(pBlitter);
+
+ return VINF_SUCCESS;
+}
+
+void CrBltTerm(PCR_BLITTER pBlitter)
+{
+ if (pBlitter->Flags.CtxCreated)
+ pBlitter->pDispatch->DestroyContext(pBlitter->CtxInfo.Base.id);
+ memset(pBlitter, 0, sizeof (*pBlitter));
+}
+
+int CrBltMuralSetCurrentInfo(PCR_BLITTER pBlitter, const CR_BLITTER_WINDOW *pMural)
+{
+ if (pMural)
+ {
+ if (!memcmp(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural)))
+ return VINF_SUCCESS;
+ memcpy(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural));
+ }
+ else
+ {
+ if (CrBltIsEntered(pBlitter))
+ {
+ WARN(("can not set null mural for entered bleater"));
+ return VERR_INVALID_STATE;
+ }
+ if (!pBlitter->CurrentMural.Base.id)
+ return VINF_SUCCESS;
+ pBlitter->CurrentMural.Base.id = 0;
+ }
+
+ pBlitter->Flags.CurrentMuralChanged = 1;
+
+ if (!CrBltIsEntered(pBlitter))
+ return VINF_SUCCESS;
+ else if (!pBlitter->CtxInfo.Base.id)
+ {
+ WARN(("setting current mural for entered no-context blitter"));
+ return VERR_INVALID_STATE;
+ }
+
+ WARN(("changing mural for entered blitter, is is somewhat expected?"));
+
+ pBlitter->pDispatch->Flush();
+
+ pBlitter->pDispatch->MakeCurrent(pMural->Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
+
+ return VINF_SUCCESS;
+}
+
+static 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)
+{
+ GLenum filter = CRBLT_FILTER_FROM_FLAGS(fFlags);
+ pBlitter->pDispatch->BindFramebufferEXT(GL_READ_FRAMEBUFFER, pBlitter->idFBO);
+ pBlitter->pDispatch->FramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pSrc->target, pSrc->hwid, 0);
+ pBlitter->pDispatch->ReadBuffer(GL_COLOR_ATTACHMENT0);
+
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ const RTRECT * pSrcRect = &paSrcRect[i];
+ const RTRECT * pDstRect = &paDstRect[i];
+ int32_t srcY1;
+ int32_t srcY2;
+ int32_t dstY1;
+ int32_t dstY2;
+ int32_t srcX1 = pSrcRect->xLeft;
+ int32_t srcX2 = pSrcRect->xRight;
+ int32_t dstX1 = pDstRect->xLeft;
+ int32_t dstX2 = pDstRect->xRight;
+
+ if (CRBLT_F_INVERT_SRC_YCOORDS & fFlags)
+ {
+ srcY1 = pSrc->height - pSrcRect->yTop;
+ srcY2 = pSrc->height - pSrcRect->yBottom;
+ }
+ else
+ {
+ srcY1 = pSrcRect->yTop;
+ srcY2 = pSrcRect->yBottom;
+ }
+
+ if (CRBLT_F_INVERT_DST_YCOORDS & fFlags)
+ {
+ dstY1 = pDstSize->cy - pDstRect->yTop;
+ dstY2 = pDstSize->cy - pDstRect->yBottom;
+ }
+ else
+ {
+ dstY1 = pDstRect->yTop;
+ dstY2 = pDstRect->yBottom;
+ }
+
+ if (srcY1 > srcY2)
+ {
+ if (dstY1 > dstY2)
+ {
+ /* use srcY1 < srcY2 && dstY1 < dstY2 whenever possible to avoid GPU driver bugs */
+ int32_t tmp = srcY1;
+ srcY1 = srcY2;
+ srcY2 = tmp;
+ tmp = dstY1;
+ dstY1 = dstY2;
+ dstY2 = tmp;
+ }
+ }
+
+ if (srcX1 > srcX2)
+ {
+ if (dstX1 > dstX2)
+ {
+ /* use srcX1 < srcX2 && dstX1 < dstX2 whenever possible to avoid GPU driver bugs */
+ int32_t tmp = srcX1;
+ srcX1 = srcX2;
+ srcX2 = tmp;
+ tmp = dstX1;
+ dstX1 = dstX2;
+ dstX2 = tmp;
+ }
+ }
+
+ pBlitter->pDispatch->BlitFramebufferEXT(srcX1, srcY1, srcX2, srcY2,
+ dstX1, dstY1, dstX2, dstY2,
+ GL_COLOR_BUFFER_BIT, filter);
+ }
+
+ return VINF_SUCCESS;
+}
+
+/* GL_TRIANGLE_FAN */
+DECLINLINE(GLfloat*) crBltVtRectTFNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
+{
+ /* going ccw:
+ * 1. (left;top) 4. (right;top)
+ * | ^
+ * > |
+ * 2. (left;bottom) -> 3. (right;bottom) */
+ /* xLeft yTop */
+ pBuff[0] = ((float)pRect->xLeft)/((float)normalX);
+ pBuff[1] = ((float)(height ? height - pRect->yTop : pRect->yTop))/((float)normalY);
+
+ /* xLeft yBottom */
+ pBuff[2] = pBuff[0];
+ pBuff[3] = ((float)(height ? height - pRect->yBottom : pRect->yBottom))/((float)normalY);
+
+ /* xRight yBottom */
+ pBuff[4] = ((float)pRect->xRight)/((float)normalX);
+ pBuff[5] = pBuff[3];
+
+ /* xRight yTop */
+ pBuff[6] = pBuff[4];
+ pBuff[7] = pBuff[1];
+ return &pBuff[8];
+}
+
+DECLINLINE(GLfloat*) crBltVtRectsTFNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
+{
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ pBuff = crBltVtRectTFNormalized(&paRects[i], normalX, normalY, pBuff, height);
+ }
+ return pBuff;
+}
+
+DECLINLINE(GLint*) crBltVtRectTF(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, uint32_t height)
+{
+ /* xLeft yTop */
+ pBuff[0] = pRect->xLeft;
+ pBuff[1] = height ? height - pRect->yTop : pRect->yTop;
+
+ /* xLeft yBottom */
+ pBuff[2] = pBuff[0];
+ pBuff[3] = height ? height - pRect->yBottom : pRect->yBottom;
+
+ /* xRight yBottom */
+ pBuff[4] = pRect->xRight;
+ pBuff[5] = pBuff[3];
+
+ /* xRight yTop */
+ pBuff[6] = pBuff[4];
+ pBuff[7] = pBuff[1];
+ return &pBuff[8];
+}
+
+DECLINLINE(GLubyte*) crBltVtFillRectIndicies(GLubyte *pIndex, GLubyte *piBase)
+{
+ GLubyte iBase = *piBase;
+ /* triangle 1 */
+ pIndex[0] = iBase;
+ pIndex[1] = iBase + 1;
+ pIndex[2] = iBase + 2;
+
+ /* triangle 2 */
+ pIndex[3] = iBase;
+ pIndex[4] = iBase + 2;
+ pIndex[5] = iBase + 3;
+ *piBase = iBase + 4;
+ return pIndex + 6;
+}
+
+/* Indexed GL_TRIANGLES */
+DECLINLINE(GLfloat*) crBltVtRectITNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height)
+{
+ GLfloat* ret = crBltVtRectTFNormalized(pRect, normalX, normalY, pBuff, height);
+ return ret;
+}
+
+DECLINLINE(GLint*) crBltVtRectIT(RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height)
+{
+ GLint* ret = crBltVtRectTF(pRect, normalX, normalY, pBuff, height);
+
+ if (ppIndex)
+ *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase);
+
+ return ret;
+}
+
+DECLINLINE(GLuint) crBltVtGetNumVerticiesTF(GLuint cRects)
+{
+ return cRects * 4;
+}
+
+#define crBltVtGetNumVerticiesIT crBltVtGetNumVerticiesTF
+
+DECLINLINE(GLuint) crBltVtGetNumIndiciesIT(GLuint cRects)
+{
+ return 6 * cRects;
+}
+
+
+static GLfloat* crBltVtRectsITNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height)
+{
+ uint32_t i;
+ for (i = 0; i < cRects; ++i)
+ {
+ pBuff = crBltVtRectITNormalized(&paRects[i], normalX, normalY, pBuff, height);
+ }
+
+
+ if (ppIndex)
+ {
+ GLubyte *pIndex = (GLubyte*)pBuff;
+ *ppIndex = pIndex;
+ for (i = 0; i < cRects; ++i)
+ {
+ pIndex = crBltVtFillRectIndicies(pIndex, piBase);
+ }
+ pBuff = (GLfloat*)pIndex;
+ }
+
+ return pBuff;
+}
+
+static void* crBltBufGet(PCR_BLITTER_BUFFER pBuffer, GLuint cbBuffer)
+{
+ if (pBuffer->cbBuffer < cbBuffer)
+ {
+ if (pBuffer->pvBuffer)
+ {
+ RTMemFree(pBuffer->pvBuffer);
+ }
+
+#ifndef DEBUG_misha
+ /* debugging: ensure we calculate proper buffer size */
+ cbBuffer += 16;
+#endif
+
+ pBuffer->pvBuffer = RTMemAlloc(cbBuffer);
+ if (pBuffer->pvBuffer)
+ pBuffer->cbBuffer = cbBuffer;
+ else
+ {
+ crWarning("failed to allocate buffer of size %d", cbBuffer);
+ pBuffer->cbBuffer = 0;
+ }
+ }
+ return pBuffer->pvBuffer;
+}
+
+static void crBltCheckSetupViewport(PCR_BLITTER pBlitter, const RTRECTSIZE *pDstSize, bool fFBODraw)
+{
+ bool fUpdateViewport = pBlitter->Flags.CurrentMuralChanged;
+ if (pBlitter->CurrentSetSize.cx != pDstSize->cx
+ || pBlitter->CurrentSetSize.cy != pDstSize->cy)
+ {
+ pBlitter->CurrentSetSize = *pDstSize;
+ pBlitter->pDispatch->MatrixMode(GL_PROJECTION);
+ pBlitter->pDispatch->LoadIdentity();
+ pBlitter->pDispatch->Ortho(0, pDstSize->cx, 0, pDstSize->cy, -1, 1);
+ fUpdateViewport = true;
+ }
+
+ if (fUpdateViewport)
+ {
+ pBlitter->pDispatch->Viewport(0, 0, pBlitter->CurrentSetSize.cx, pBlitter->CurrentSetSize.cy);
+ pBlitter->Flags.CurrentMuralChanged = 0;
+ }
+
+ pBlitter->Flags.LastWasFBODraw = fFBODraw;
+}
+
+static 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)
+{
+ GLuint normalX, normalY;
+ uint32_t srcHeight = (fFlags & CRBLT_F_INVERT_SRC_YCOORDS) ? pSrc->height : 0;
+ uint32_t dstHeight = (fFlags & CRBLT_F_INVERT_DST_YCOORDS) ? pDstSize->cy : 0;
+
+ switch (pSrc->target)
+ {
+ case GL_TEXTURE_2D:
+ {
+ normalX = pSrc->width;
+ normalY = pSrc->height;
+ break;
+ }
+
+ case GL_TEXTURE_RECTANGLE_ARB:
+ {
+ normalX = 1;
+ normalY = 1;
+ break;
+ }
+
+ default:
+ {
+ crWarning("Unsupported texture target 0x%x", pSrc->target);
+ return VERR_INVALID_PARAMETER;
+ }
+ }
+
+ Assert(pSrc->hwid);
+
+ pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
+
+ if (cRects == 1)
+ {
+ /* just optimization to draw a single rect with GL_TRIANGLE_FAN */
+ GLfloat *pVerticies;
+ GLfloat *pTexCoords;
+ GLuint cElements = crBltVtGetNumVerticiesTF(cRects);
+
+ pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies));
+ pTexCoords = crBltVtRectsTFNormalized(paDstRect, cRects, 1, 1, pVerticies, dstHeight);
+ crBltVtRectsTFNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, srcHeight);
+
+ pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
+ pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
+
+ pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
+ pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords);
+
+ pBlitter->pDispatch->Enable(pSrc->target);
+
+ pBlitter->pDispatch->DrawArrays(GL_TRIANGLE_FAN, 0, cElements);
+
+ pBlitter->pDispatch->Disable(pSrc->target);
+
+ pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
+ pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
+ }
+ else
+ {
+ GLfloat *pVerticies;
+ GLfloat *pTexCoords;
+ GLubyte *pIndicies;
+ GLuint cElements = crBltVtGetNumVerticiesIT(cRects);
+ GLuint cIndicies = crBltVtGetNumIndiciesIT(cRects);
+ GLubyte iIdxBase = 0;
+
+ pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies) + cIndicies * sizeof (*pIndicies));
+ pTexCoords = crBltVtRectsITNormalized(paDstRect, cRects, 1, 1, pVerticies, &pIndicies, &iIdxBase, dstHeight);
+ crBltVtRectsITNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, NULL, NULL, srcHeight);
+
+ pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
+ pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
+
+ pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
+ pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords);
+
+ pBlitter->pDispatch->Enable(pSrc->target);
+
+ pBlitter->pDispatch->DrawElements(GL_TRIANGLES, cIndicies, GL_UNSIGNED_BYTE, pIndicies);
+
+ pBlitter->pDispatch->Disable(pSrc->target);
+
+ pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
+ pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
+ }
+
+ pBlitter->pDispatch->BindTexture(pSrc->target, 0);
+
+ return VINF_SUCCESS;
+}
+
+static int crBltInitOnMakeCurent(PCR_BLITTER pBlitter)
+{
+ const char * pszExtension = (const char*)pBlitter->pDispatch->GetString(GL_EXTENSIONS);
+ if (crStrstr(pszExtension, "GL_EXT_framebuffer_object"))
+ {
+ pBlitter->Flags.SupportsFBO = 1;
+ pBlitter->pDispatch->GenFramebuffersEXT(1, &pBlitter->idFBO);
+ Assert(pBlitter->idFBO);
+ }
+ else
+ crWarning("GL_EXT_framebuffer_object not supported, blitter can only blit to window");
+
+ if (crStrstr(pszExtension, "GL_ARB_pixel_buffer_object"))
+ pBlitter->Flags.SupportsPBO = 1;
+ else
+ crWarning("GL_ARB_pixel_buffer_object not supported");
+
+ /* BlitFramebuffer seems to be buggy on Intel,
+ * try always glDrawXxx for now */
+ if (!pBlitter->Flags.ForceDrawBlit && crStrstr(pszExtension, "GL_EXT_framebuffer_blit"))
+ {
+ pBlitter->pfnBlt = crBltBlitTexBufImplFbo;
+ }
+ else
+ {
+// crWarning("GL_EXT_framebuffer_blit not supported, will use Draw functions for blitting, which might be less efficient");
+ pBlitter->pfnBlt = crBltBlitTexBufImplDraw2D;
+ }
+
+ /* defaults. but just in case */
+ pBlitter->pDispatch->MatrixMode(GL_TEXTURE);
+ pBlitter->pDispatch->LoadIdentity();
+ pBlitter->pDispatch->MatrixMode(GL_MODELVIEW);
+ pBlitter->pDispatch->LoadIdentity();
+
+ return VINF_SUCCESS;
+}
+
+void CrBltLeave(PCR_BLITTER pBlitter)
+{
+ if (!pBlitter->cEnters)
+ {
+ WARN(("blitter not entered!"));
+ return;
+ }
+
+ if (--pBlitter->cEnters)
+ return;
+
+ if (pBlitter->Flags.SupportsFBO)
+ {
+ pBlitter->pDispatch->BindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ pBlitter->pDispatch->DrawBuffer(GL_BACK);
+ pBlitter->pDispatch->ReadBuffer(GL_BACK);
+ }
+
+ pBlitter->pDispatch->Flush();
+
+ if (pBlitter->CtxInfo.Base.id)
+ pBlitter->pDispatch->MakeCurrent(0, 0, 0);
+}
+
+int CrBltEnter(PCR_BLITTER pBlitter)
+{
+ if (!pBlitter->CurrentMural.Base.id && pBlitter->CtxInfo.Base.id)
+ {
+ WARN(("current mural not initialized!"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pBlitter->cEnters++)
+ return VINF_SUCCESS;
+
+ 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)*/
+ {
+ pBlitter->pDispatch->MakeCurrent(pBlitter->CurrentMural.Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
+ }
+
+ if (pBlitter->Flags.Initialized)
+ return VINF_SUCCESS;
+
+ int rc = crBltInitOnMakeCurent(pBlitter);
+ if (RT_SUCCESS(rc))
+ {
+ pBlitter->Flags.Initialized = 1;
+ return VINF_SUCCESS;
+ }
+
+ WARN(("crBltInitOnMakeCurent failed, rc %d", rc));
+ CrBltLeave(pBlitter);
+ return rc;
+}
+
+static 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)
+{
+ pBlitter->pDispatch->DrawBuffer(enmDstBuff);
+
+ crBltCheckSetupViewport(pBlitter, pDstSize, enmDstBuff == GL_DRAW_FRAMEBUFFER);
+
+ if (!(fFlags & CRBLT_F_NOALPHA))
+ pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
+ else
+ {
+ int rc = pBlitter->Flags.ShadersGloal ?
+ CrGlslProgUseNoAlpha(pBlitter->pGlslCache, pSrc->target)
+ :
+ CrGlslProgUseGenNoAlpha(&pBlitter->LocalGlslCache, pSrc->target);
+
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("Failed to use no-alpha program rc %d!, falling back to default blit", rc);
+ pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
+ return;
+ }
+
+ /* since we use shaders, we need to use draw commands rather than framebuffer blits.
+ * force using draw-based blitting */
+ crBltBlitTexBufImplDraw2D(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
+
+ Assert(pBlitter->Flags.ShadersGloal || &pBlitter->LocalGlslCache == pBlitter->pGlslCache);
+
+ CrGlslProgClear(pBlitter->pGlslCache);
+ }
+}
+
+void CrBltCheckUpdateViewport(PCR_BLITTER pBlitter)
+{
+ RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height};
+ crBltCheckSetupViewport(pBlitter, &DstSize, false);
+}
+
+void CrBltBlitTexMural(PCR_BLITTER pBlitter, bool fBb, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
+{
+ if (!CrBltIsEntered(pBlitter))
+ {
+ WARN(("CrBltBlitTexMural: blitter not entered"));
+ return;
+ }
+
+ RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height};
+
+ pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
+
+ crBltBlitTexBuf(pBlitter, pSrc, paSrcRects, fBb ? GL_BACK : GL_FRONT, &DstSize, paDstRects, cRects, fFlags);
+}
+
+void CrBltBlitTexTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *pSrcRect, const VBOXVR_TEXTURE *pDst, const RTRECT *pDstRect, uint32_t cRects, uint32_t fFlags)
+{
+ if (!CrBltIsEntered(pBlitter))
+ {
+ WARN(("CrBltBlitTexTex: blitter not entered"));
+ return;
+ }
+
+ RTRECTSIZE DstSize = {(uint32_t)pDst->width, (uint32_t)pDst->height};
+
+ pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, pBlitter->idFBO);
+
+ /* TODO: mag/min filters ? */
+
+ pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, pDst->hwid, 0);
+
+// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
+// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
+
+ crBltBlitTexBuf(pBlitter, pSrc, pSrcRect, GL_DRAW_FRAMEBUFFER, &DstSize, pDstRect, cRects, fFlags);
+
+ pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, 0, 0);
+}
+
+void CrBltPresent(PCR_BLITTER pBlitter)
+{
+ if (!CrBltIsEntered(pBlitter))
+ {
+ WARN(("CrBltPresent: blitter not entered"));
+ return;
+ }
+
+ if (pBlitter->CtxInfo.Base.visualBits & CR_DOUBLE_BIT)
+ pBlitter->pDispatch->SwapBuffers(pBlitter->CurrentMural.Base.id, 0);
+ else
+ pBlitter->pDispatch->Flush();
+}
+
+static int crBltImgInitBaseForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat)
+{
+ memset(pDst, 0, sizeof (*pDst));
+ if (enmFormat != GL_RGBA
+ && enmFormat != GL_BGRA)
+ {
+ WARN(("unsupported format 0x%x", enmFormat));
+ return VERR_NOT_IMPLEMENTED;
+ }
+
+ uint32_t bpp = 32;
+
+ uint32_t pitch = ((bpp * pSrc->width) + 7) >> 3;
+ uint32_t cbData = pitch * pSrc->height;
+ pDst->cbData = cbData;
+ pDst->enmFormat = enmFormat;
+ pDst->width = pSrc->width;
+ pDst->height = pSrc->height;
+ pDst->bpp = bpp;
+ pDst->pitch = pitch;
+ return VINF_SUCCESS;
+}
+
+static int crBltImgCreateForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat)
+{
+ int rc = crBltImgInitBaseForTex(pSrc, pDst, enmFormat);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crBltImgInitBaseForTex failed rc %d", rc);
+ return rc;
+ }
+
+ uint32_t cbData = pDst->cbData;
+ pDst->pvData = RTMemAllocZ(cbData);
+ if (!pDst->pvData)
+ {
+ crWarning("RTMemAlloc failed");
+ return VERR_NO_MEMORY;
+ }
+
+#ifdef DEBUG_misha
+ {
+ char *pTmp = (char*)pDst->pvData;
+ for (uint32_t i = 0; i < cbData; ++i)
+ {
+ pTmp[i] = (char)((1 << i) % 255);
+ }
+ }
+#endif
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrBltImgGetTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, GLenum enmFormat, CR_BLITTER_IMG *pDst)
+{
+ if (!CrBltIsEntered(pBlitter))
+ {
+ WARN(("CrBltImgGetTex: blitter not entered"));
+ return VERR_INVALID_STATE;
+ }
+
+ int rc = crBltImgCreateForTex(pSrc, pDst, enmFormat);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crBltImgCreateForTex failed, rc %d", rc);
+ return rc;
+ }
+ pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
+
+#ifdef DEBUG_misha
+ {
+ GLint width = 0, height = 0, depth = 0;
+ pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_WIDTH, &width);
+ pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_HEIGHT, &height);
+ pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_DEPTH, &depth);
+
+ Assert(width == pSrc->width);
+ Assert(height == pSrc->height);
+// Assert(depth == pSrc->depth);
+ }
+#endif
+
+ pBlitter->pDispatch->GetTexImage(pSrc->target, 0, enmFormat, GL_UNSIGNED_BYTE, pDst->pvData);
+
+ pBlitter->pDispatch->BindTexture(pSrc->target, 0);
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrBltImgGetMural(PCR_BLITTER pBlitter, bool fBb, CR_BLITTER_IMG *pDst)
+{
+ if (!CrBltIsEntered(pBlitter))
+ {
+ WARN(("CrBltImgGetMural: blitter not entered"));
+ return VERR_INVALID_STATE;
+ }
+
+ crWarning("NOT IMPLEMENTED");
+ return VERR_NOT_IMPLEMENTED;
+}
+
+VBOXBLITTERDECL(void) CrBltImgFree(PCR_BLITTER pBlitter, CR_BLITTER_IMG *pDst)
+{
+ if (!CrBltIsEntered(pBlitter))
+ {
+ WARN(("CrBltImgFree: blitter not entered"));
+ return;
+ }
+
+ if (pDst->pvData)
+ {
+ RTMemFree(pDst->pvData);
+ pDst->pvData = NULL;
+ }
+}
+
+
+VBOXBLITTERDECL(bool) CrGlslIsSupported(CR_GLSL_CACHE *pCache)
+{
+ if (pCache->iGlVersion == 0)
+ {
+ const char * pszStr = (const char*)pCache->pDispatch->GetString(GL_VERSION);
+ pCache->iGlVersion = crStrParseGlVersion(pszStr);
+ if (pCache->iGlVersion <= 0)
+ {
+ crWarning("crStrParseGlVersion returned %d", pCache->iGlVersion);
+ pCache->iGlVersion = -1;
+ }
+ }
+
+ if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0))
+ return true;
+
+ crWarning("GLSL unsuported, gl version %d", pCache->iGlVersion);
+
+ /* @todo: we could also check for GL_ARB_shader_objects and GL_ARB_fragment_shader,
+ * but seems like chromium does not support properly gl*Object versions of shader functions used with those extensions */
+ return false;
+}
+
+#define CR_GLSL_STR_V_120 "#version 120\n"
+#define CR_GLSL_STR_EXT_TR "#extension GL_ARB_texture_rectangle : enable\n"
+#define CR_GLSL_STR_2D "2D"
+#define CR_GLSL_STR_2DRECT "2DRect"
+
+#define CR_GLSL_PATTERN_FS_NOALPHA(_ver, _ext, _tex) \
+ _ver \
+ _ext \
+ "uniform sampler" _tex " sampler0;\n" \
+ "void main()\n" \
+ "{\n" \
+ "vec2 srcCoord = vec2(gl_TexCoord[0]);\n" \
+ "gl_FragData[0].xyz = (texture" _tex "(sampler0, srcCoord).xyz);\n" \
+ "gl_FragData[0].w = 1.0;\n" \
+ "}\n"
+
+static const char* crGlslGetFsStringNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
+{
+ if (!CrGlslIsSupported(pCache))
+ {
+ crWarning("CrGlslIsSupported is false");
+ return NULL;
+ }
+
+ if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 1, 0))
+ {
+ if (enmTexTarget == GL_TEXTURE_2D)
+ return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, "", CR_GLSL_STR_2D);
+ else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB)
+ return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT);
+
+ crWarning("invalid enmTexTarget %#x", enmTexTarget);
+ return NULL;
+ }
+ else if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0))
+ {
+ if (enmTexTarget == GL_TEXTURE_2D)
+ return CR_GLSL_PATTERN_FS_NOALPHA("", "", CR_GLSL_STR_2D);
+ else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB)
+ return CR_GLSL_PATTERN_FS_NOALPHA("", CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT);
+
+ crWarning("invalid enmTexTarget %#x", enmTexTarget);
+ return NULL;
+ }
+
+ crError("crGlslGetFsStringNoAlpha: we should not be here!");
+ return NULL;
+}
+
+static int crGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget, GLuint *puiProgram)
+{
+ *puiProgram = 0;
+
+ const char*pStrFsShader = crGlslGetFsStringNoAlpha(pCache, enmTexTarget);
+ if (!pStrFsShader)
+ {
+ crWarning("crGlslGetFsStringNoAlpha failed");
+ return VERR_NOT_SUPPORTED;
+ }
+
+ int rc = VINF_SUCCESS;
+ GLchar * pBuf = NULL;
+ GLuint uiProgram = 0;
+ GLint iUniform = -1;
+ GLuint uiShader = pCache->pDispatch->CreateShader(GL_FRAGMENT_SHADER);
+ if (!uiShader)
+ {
+ crWarning("CreateShader failed");
+ return VERR_NOT_SUPPORTED;
+ }
+
+ pCache->pDispatch->ShaderSource(uiShader, 1, &pStrFsShader, NULL);
+
+ pCache->pDispatch->CompileShader(uiShader);
+
+ GLint compiled = 0;
+ pCache->pDispatch->GetShaderiv(uiShader, GL_COMPILE_STATUS, &compiled);
+
+#ifndef DEBUG_misha
+ if(!compiled)
+#endif
+ {
+ if (!pBuf)
+ pBuf = (GLchar *)RTMemAlloc(16300);
+ pCache->pDispatch->GetShaderInfoLog(uiShader, 16300, NULL, pBuf);
+#ifdef DEBUG_misha
+ if (compiled)
+ crDebug("compile success:\n-------------------\n%s\n--------\n", pBuf);
+ else
+#endif
+ {
+ crWarning("compile FAILURE:\n-------------------\n%s\n--------\n", pBuf);
+ rc = VERR_NOT_SUPPORTED;
+ goto end;
+ }
+ }
+
+ Assert(compiled);
+
+ uiProgram = pCache->pDispatch->CreateProgram();
+ if (!uiProgram)
+ {
+ rc = VERR_NOT_SUPPORTED;
+ goto end;
+ }
+
+ pCache->pDispatch->AttachShader(uiProgram, uiShader);
+
+ pCache->pDispatch->LinkProgram(uiProgram);
+
+ GLint linked;
+ pCache->pDispatch->GetProgramiv(uiProgram, GL_LINK_STATUS, &linked);
+#ifndef DEBUG_misha
+ if(!linked)
+#endif
+ {
+ if (!pBuf)
+ pBuf = (GLchar *)RTMemAlloc(16300);
+ pCache->pDispatch->GetProgramInfoLog(uiProgram, 16300, NULL, pBuf);
+#ifdef DEBUG_misha
+ if (linked)
+ crDebug("link success:\n-------------------\n%s\n--------\n", pBuf);
+ else
+#endif
+ {
+ crWarning("link FAILURE:\n-------------------\n%s\n--------\n", pBuf);
+ rc = VERR_NOT_SUPPORTED;
+ goto end;
+ }
+ }
+
+ Assert(linked);
+
+ iUniform = pCache->pDispatch->GetUniformLocation(uiProgram, "sampler0");
+ if (iUniform == -1)
+ {
+ crWarning("GetUniformLocation failed for sampler0");
+ }
+ else
+ {
+ pCache->pDispatch->Uniform1i(iUniform, 0);
+ }
+
+ *puiProgram = uiProgram;
+
+ /* avoid end finalizer from cleaning it */
+ uiProgram = 0;
+
+ end:
+ if (uiShader)
+ pCache->pDispatch->DeleteShader(uiShader);
+ if (uiProgram)
+ pCache->pDispatch->DeleteProgram(uiProgram);
+ if (pBuf)
+ RTMemFree(pBuf);
+ return rc;
+}
+
+DECLINLINE(GLuint) crGlslProgGetNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
+{
+ switch (enmTexTarget)
+ {
+ case GL_TEXTURE_2D:
+ return pCache->uNoAlpha2DProg;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ return pCache->uNoAlpha2DRectProg;
+ default:
+ crWarning("invalid tex enmTexTarget %#x", enmTexTarget);
+ return 0;
+ }
+}
+
+DECLINLINE(GLuint*) crGlslProgGetNoAlphaPtr(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
+{
+ switch (enmTexTarget)
+ {
+ case GL_TEXTURE_2D:
+ return &pCache->uNoAlpha2DProg;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ return &pCache->uNoAlpha2DRectProg;
+ default:
+ crWarning("invalid tex enmTexTarget %#x", enmTexTarget);
+ return NULL;
+ }
+}
+
+VBOXBLITTERDECL(int) CrGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
+{
+ GLuint*puiProgram = crGlslProgGetNoAlphaPtr(pCache, enmTexTarget);
+ if (!puiProgram)
+ return VERR_INVALID_PARAMETER;
+
+ if (*puiProgram)
+ return VINF_SUCCESS;
+
+ return crGlslProgGenNoAlpha(pCache, enmTexTarget, puiProgram);
+}
+
+VBOXBLITTERDECL(int) CrGlslProgGenAllNoAlpha(CR_GLSL_CACHE *pCache)
+{
+ int rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_2D);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_2D failed rc %d", rc);
+ return rc;
+ }
+
+ rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_RECTANGLE_ARB);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_RECTANGLE failed rc %d", rc);
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(void) CrGlslProgClear(const CR_GLSL_CACHE *pCache)
+{
+ pCache->pDispatch->UseProgram(0);
+}
+
+VBOXBLITTERDECL(int) CrGlslProgUseNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
+{
+ GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
+ if (!uiProg)
+ {
+ crWarning("request to use inexistent program!");
+ return VERR_INVALID_STATE;
+ }
+
+ Assert(uiProg);
+
+ pCache->pDispatch->UseProgram(uiProg);
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrGlslProgUseGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget)
+{
+ GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
+ if (!uiProg)
+ {
+ int rc = CrGlslProgGenNoAlpha(pCache, enmTexTarget);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrGlslProgGenNoAlpha failed, rc %d", rc);
+ return rc;
+ }
+
+ uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget);
+ CRASSERT(uiProg);
+ }
+
+ Assert(uiProg);
+
+ pCache->pDispatch->UseProgram(uiProg);
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(bool) CrGlslNeedsCleanup(const CR_GLSL_CACHE *pCache)
+{
+ return pCache->uNoAlpha2DProg || pCache->uNoAlpha2DRectProg;
+}
+
+VBOXBLITTERDECL(void) CrGlslCleanup(CR_GLSL_CACHE *pCache)
+{
+ if (pCache->uNoAlpha2DProg)
+ {
+ pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DProg);
+ pCache->uNoAlpha2DProg = 0;
+ }
+
+ if (pCache->uNoAlpha2DRectProg)
+ {
+ pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DRectProg);
+ pCache->uNoAlpha2DRectProg = 0;
+ }
+}
+
+VBOXBLITTERDECL(void) CrGlslTerm(CR_GLSL_CACHE *pCache)
+{
+ CRASSERT(!CrGlslNeedsCleanup(pCache));
+
+ CrGlslCleanup(pCache);
+
+ /* sanity */
+ memset(pCache, 0, sizeof (*pCache));
+}
+
+
+/*TdBlt*/
+static void crTdBltCheckPBO(PCR_TEXDATA pTex)
+{
+ if (pTex->idPBO)
+ return;
+
+ PCR_BLITTER pBlitter = pTex->pBlitter;
+
+ if (!pBlitter->Flags.SupportsPBO)
+ return;
+
+ pBlitter->pDispatch->GenBuffersARB(1, &pTex->idPBO);
+ if (!pTex->idPBO)
+ {
+ crWarning("PBO create failed");
+ return;
+ }
+
+ pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
+ pBlitter->pDispatch->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
+ pTex->Tex.width*pTex->Tex.height*4,
+ 0, GL_STREAM_READ_ARB);
+ pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+}
+
+static uint32_t crTdBltTexCreate(PCR_BLITTER pBlitter, uint32_t width, uint32_t height, GLenum enmTarget)
+{
+ uint32_t tex = 0;
+ pBlitter->pDispatch->GenTextures(1, &tex);
+ if (!tex)
+ {
+ crWarning("Tex create failed");
+ return 0;
+ }
+
+ pBlitter->pDispatch->BindTexture(enmTarget, tex);
+ pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ pBlitter->pDispatch->TexImage2D(enmTarget, 0, GL_RGBA8,
+ width, height,
+ 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+
+
+ /*Restore gl state*/
+ pBlitter->pDispatch->BindTexture(enmTarget, 0);
+
+ return tex;
+}
+
+int crTdBltCheckInvertTex(PCR_TEXDATA pTex)
+{
+ if (pTex->idInvertTex)
+ return VINF_SUCCESS;
+
+ pTex->idInvertTex = crTdBltTexCreate(pTex->pBlitter, pTex->Tex.width, pTex->Tex.height, pTex->Tex.target);
+ if (!pTex->idInvertTex)
+ {
+ crWarning("Invert Tex create failed");
+ return VERR_GENERAL_FAILURE;
+ }
+ return VINF_SUCCESS;
+}
+
+void crTdBltImgRelease(PCR_TEXDATA pTex)
+{
+ pTex->Flags.DataValid = 0;
+}
+
+void crTdBltImgFree(PCR_TEXDATA pTex)
+{
+ if (!pTex->Img.pvData)
+ {
+ Assert(!pTex->Flags.DataValid);
+ return;
+ }
+
+ crTdBltImgRelease(pTex);
+
+ Assert(!pTex->Flags.DataValid);
+
+
+ if (pTex->idPBO)
+ {
+ PCR_BLITTER pBlitter = pTex->pBlitter;
+
+ Assert(CrBltIsEntered(pBlitter));
+ pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
+ pBlitter->pDispatch->UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
+ pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ }
+ else
+ {
+ Assert(pTex->Img.pvData);
+ RTMemFree(pTex->Img.pvData);
+ }
+
+ pTex->Img.pvData = NULL;
+}
+
+int crTdBltImgAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted)
+{
+ void *pvData = pTex->Img.pvData;
+ Assert(!pTex->Flags.DataValid);
+ int rc = crBltImgInitBaseForTex(&pTex->Tex, &pTex->Img, enmFormat);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crBltImgInitBaseForTex failed rc %d", rc));
+ return rc;
+ }
+
+ PCR_BLITTER pBlitter = pTex->pBlitter;
+ Assert(CrBltIsEntered(pBlitter));
+ pBlitter->pDispatch->BindTexture(pTex->Tex.target, fInverted ? pTex->idInvertTex : pTex->Tex.hwid);
+
+ pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
+
+ if (pvData)
+ {
+ if (pTex->idPBO)
+ {
+ pBlitter->pDispatch->UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
+ pvData = NULL;
+
+ }
+ }
+ else
+ {
+ if (!pTex->idPBO)
+ {
+ pvData = RTMemAlloc(4*pTex->Tex.width*pTex->Tex.height);
+ if (!pvData)
+ {
+ WARN(("Out of memory in crTdBltImgAcquire"));
+ pBlitter->pDispatch->BindTexture(pTex->Tex.target, 0);
+ return VERR_NO_MEMORY;
+ }
+ }
+ }
+
+ Assert(!pvData == !!pTex->idPBO);
+
+ /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/
+ pBlitter->pDispatch->GetTexImage(GL_TEXTURE_2D, 0, enmFormat, GL_UNSIGNED_BYTE, pvData);
+
+ /*restore gl state*/
+ pBlitter->pDispatch->BindTexture(pTex->Tex.target, 0);
+
+ if (pTex->idPBO)
+ {
+ pvData = pBlitter->pDispatch->MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
+ if (!pvData)
+ {
+ WARN(("Failed to MapBuffer in CrHlpGetTexImage"));
+ return VERR_GENERAL_FAILURE;
+ }
+
+ pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ }
+
+ Assert(pvData);
+ pTex->Img.pvData = pvData;
+ pTex->Flags.DataValid = 1;
+ pTex->Flags.DataInverted = fInverted;
+ return VINF_SUCCESS;
+}
+
+/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataInvalidateNe or CrTdBltDataCleanup */
+VBOXBLITTERDECL(int) CrTdBltDataRelease(PCR_TEXDATA pTex)
+{
+ if (!pTex->Flags.Entered)
+ {
+ WARN(("tex not entered"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (!pTex->Flags.DataAcquired)
+ {
+ WARN(("Data NOT acquired"));
+ return VERR_INVALID_STATE;
+ }
+
+ Assert(pTex->Img.pvData);
+ Assert(pTex->Flags.DataValid);
+
+ pTex->Flags.DataAcquired = 0;
+
+ return VINF_SUCCESS;
+}
+
+static void crTdBltDataFree(PCR_TEXDATA pTex)
+{
+ crTdBltImgFree(pTex);
+
+ if (pTex->pScaledCache)
+ CrTdBltDataFreeNe(pTex->pScaledCache);
+}
+
+/* discard the texture data cached with previous CrTdBltDataAcquire.
+ * Must be called wit data released (CrTdBltDataRelease) */
+VBOXBLITTERDECL(int) CrTdBltDataFree(PCR_TEXDATA pTex)
+{
+ if (!pTex->Flags.Entered)
+ {
+ WARN(("tex not entered"));
+ return VERR_INVALID_STATE;
+ }
+
+ crTdBltDataFree(pTex);
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(void) CrTdBltDataInvalidateNe(PCR_TEXDATA pTex)
+{
+ crTdBltImgRelease(pTex);
+
+ if (pTex->pScaledCache)
+ CrTdBltDataInvalidateNe(pTex->pScaledCache);
+}
+
+VBOXBLITTERDECL(int) CrTdBltDataFreeNe(PCR_TEXDATA pTex)
+{
+ if (!pTex->Img.pvData)
+ return VINF_SUCCESS;
+
+ bool fEntered = false;
+ if (pTex->idPBO)
+ {
+ int rc = CrTdBltEnter(pTex);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ fEntered = true;
+ }
+
+ crTdBltDataFree(pTex);
+
+ if (fEntered)
+ CrTdBltLeave(pTex);
+
+ return VINF_SUCCESS;
+}
+
+static void crTdBltSdCleanupCacheNe(PCR_TEXDATA pTex)
+{
+ if (pTex->pScaledCache)
+ {
+ CrTdBltDataCleanupNe(pTex->pScaledCache);
+ CrTdRelease(pTex->pScaledCache);
+ pTex->pScaledCache = NULL;
+ }
+}
+
+static void crTdBltDataCleanup(PCR_TEXDATA pTex)
+{
+ crTdBltImgFree(pTex);
+
+ PCR_BLITTER pBlitter = pTex->pBlitter;
+
+ if (pTex->idPBO)
+ {
+ Assert(CrBltIsEntered(pBlitter));
+ pBlitter->pDispatch->DeleteBuffersARB(1, &pTex->idPBO);
+ pTex->idPBO = 0;
+ }
+
+ if (pTex->idInvertTex)
+ {
+ Assert(CrBltIsEntered(pBlitter));
+ pBlitter->pDispatch->DeleteTextures(1, &pTex->idInvertTex);
+ pTex->idInvertTex = 0;
+ }
+
+ crTdBltSdCleanupCacheNe(pTex);
+}
+
+/* does same as CrTdBltDataFree, and in addition cleans up */
+VBOXBLITTERDECL(int) CrTdBltDataCleanup(PCR_TEXDATA pTex)
+{
+ if (!pTex->Flags.Entered)
+ {
+ WARN(("tex not entered"));
+ return VERR_INVALID_STATE;
+ }
+
+ crTdBltDataCleanup(pTex);
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrTdBltDataCleanupNe(PCR_TEXDATA pTex)
+{
+ bool fEntered = false;
+ if (pTex->idPBO || pTex->idInvertTex)
+ {
+ int rc = CrTdBltEnter(pTex);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ fEntered = true;
+ }
+
+ crTdBltDataCleanup(pTex);
+
+ if (fEntered)
+ CrTdBltLeave(pTex);
+
+ return VINF_SUCCESS;
+}
+
+/* acquire the texture data, returns the cached data in case it is cached.
+ * the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataFree or CrTdBltDataCleanup.
+ * */
+VBOXBLITTERDECL(int) CrTdBltDataAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, const CR_BLITTER_IMG**ppImg)
+{
+ if (!pTex->Flags.Entered)
+ {
+ WARN(("tex not entered"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pTex->Flags.DataAcquired)
+ {
+ WARN(("Data acquired already"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pTex->Flags.DataValid && pTex->Img.enmFormat == enmFormat && !pTex->Flags.DataInverted == !fInverted)
+ {
+ Assert(pTex->Img.pvData);
+ *ppImg = &pTex->Img;
+ pTex->Flags.DataAcquired = 1;
+ return VINF_SUCCESS;
+ }
+
+ crTdBltImgRelease(pTex);
+
+ crTdBltCheckPBO(pTex);
+
+ int rc;
+
+ if (fInverted)
+ {
+ rc = crTdBltCheckInvertTex(pTex);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crTdBltCheckInvertTex failed rc %d", rc));
+ return rc;
+ }
+
+ RTRECT SrcRect, DstRect;
+ VBOXVR_TEXTURE InvertTex;
+
+ InvertTex = pTex->Tex;
+ InvertTex.hwid = pTex->idInvertTex;
+
+ SrcRect.xLeft = 0;
+ SrcRect.yTop = InvertTex.height;
+ SrcRect.xRight = InvertTex.width;
+ SrcRect.yBottom = 0;
+
+ DstRect.xLeft = 0;
+ DstRect.yTop = 0;
+ DstRect.xRight = InvertTex.width;
+ DstRect.yBottom = InvertTex.height;
+
+ CrBltBlitTexTex(pTex->pBlitter, &pTex->Tex, &SrcRect, &InvertTex, &DstRect, 1, 0);
+ }
+
+ rc = crTdBltImgAcquire(pTex, enmFormat, fInverted);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crTdBltImgAcquire failed rc %d", rc));
+ return rc;
+ }
+
+ Assert(pTex->Img.pvData);
+ *ppImg = &pTex->Img;
+ pTex->Flags.DataAcquired = 1;
+
+ return VINF_SUCCESS;
+}
+
+DECLINLINE(void) crTdResize(PCR_TEXDATA pTex, const VBOXVR_TEXTURE *pVrTex)
+{
+ crTdBltDataCleanup(pTex);
+
+ pTex->Tex = *pVrTex;
+}
+
+static DECLCALLBACK(void) ctTdBltSdReleased(struct CR_TEXDATA *pTexture)
+{
+ PCR_BLITTER pBlitter = pTexture->pBlitter;
+
+ int rc = CrBltEnter(pBlitter);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrBltEnter failed, rc %d", rc));
+ return;
+ }
+
+ CrTdBltDataCleanupNe(pTexture);
+
+ pBlitter->pDispatch->DeleteTextures(1, &pTexture->Tex.hwid);
+
+ CrBltLeave(pBlitter);
+
+ RTMemFree(pTexture);
+}
+
+static int ctTdBltSdCreate(PCR_BLITTER pBlitter, uint32_t width, uint32_t height, GLenum enmTarget, PCR_TEXDATA *ppScaledCache)
+{
+ PCR_TEXDATA pScaledCache;
+
+ Assert(CrBltIsEntered(pBlitter));
+
+ *ppScaledCache = NULL;
+
+ pScaledCache = (PCR_TEXDATA)RTMemAlloc(sizeof (*pScaledCache));
+ if (!pScaledCache)
+ {
+ WARN(("RTMemAlloc failed"));
+ return VERR_NO_MEMORY;
+ }
+
+ VBOXVR_TEXTURE Tex;
+ Tex.width = width;
+ Tex.height = height;
+ Tex.target = enmTarget;
+ Tex.hwid = crTdBltTexCreate(pBlitter, width, height, enmTarget);
+ if (!Tex.hwid)
+ {
+ WARN(("Tex create failed"));
+ RTMemFree(pScaledCache);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ CrTdInit(pScaledCache, &Tex, pBlitter, ctTdBltSdReleased);
+
+ *ppScaledCache = pScaledCache;
+
+ return VINF_SUCCESS;
+}
+
+static int ctTdBltSdGet(PCR_TEXDATA pTex, uint32_t width, uint32_t height, PCR_TEXDATA *ppScaledCache)
+{
+ Assert(CrBltIsEntered(pTex->pBlitter));
+
+ PCR_TEXDATA pScaledCache;
+
+ *ppScaledCache = NULL;
+
+ if (!pTex->pScaledCache)
+ {
+ int rc = ctTdBltSdCreate(pTex->pBlitter, width, height, pTex->Tex.target, &pScaledCache);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("ctTdBltSdCreate failed %d", rc));
+ return rc;
+ }
+
+ pTex->pScaledCache = pScaledCache;
+ }
+ else
+ {
+ int cmp = pTex->pScaledCache->Tex.width - width;
+ if (cmp <= 0)
+ cmp = pTex->pScaledCache->Tex.height - height;
+
+ if (!cmp)
+ pScaledCache = pTex->pScaledCache;
+ else if (cmp < 0) /* current cache is "less" than the requested */
+ {
+ int rc = ctTdBltSdCreate(pTex->pBlitter, width, height, pTex->Tex.target, &pScaledCache);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("ctTdBltSdCreate failed %d", rc));
+ return rc;
+ }
+
+ pScaledCache->pScaledCache = pTex->pScaledCache;
+ pTex->pScaledCache = pScaledCache;
+ }
+ else /* cmp > 0 */
+ {
+ int rc = ctTdBltSdGet(pTex->pScaledCache, width, height, &pScaledCache);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("ctTdBltSdGet failed %d", rc));
+ return rc;
+ }
+ }
+ }
+
+ Assert(pScaledCache);
+
+#if 0
+ {
+ VBOXVR_TEXTURE Tex;
+ Tex.width = width;
+ Tex.height = height;
+ Tex.target = pTex->Tex.target;
+ Tex.hwid = crTdBltTexCreate(pTex, width, height);
+ if (!Tex.hwid)
+ {
+ WARN(("Tex create failed"));
+ return VERR_GENERAL_FAILURE;
+ }
+
+ pTex->pBlitter->pDispatch->DeleteTextures(1, &pTex->pScaledCache->Tex.hwid);
+
+ crTdResize(pTex->pScaledCache, &Tex);
+ }
+#endif
+
+ *ppScaledCache = pScaledCache;
+ return VINF_SUCCESS;
+}
+
+static int ctTdBltSdGetUpdated(PCR_TEXDATA pTex, uint32_t width, uint32_t height, PCR_TEXDATA *ppScaledCache)
+{
+ PCR_TEXDATA pScaledCache;
+
+ *ppScaledCache = NULL;
+ int rc = ctTdBltSdGet(pTex, width, height, &pScaledCache);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("ctTdBltSdGet failed %d", rc));
+ return rc;
+ }
+
+ Assert(width == pScaledCache->Tex.width);
+ Assert(height == pScaledCache->Tex.height);
+
+ if (!pScaledCache->Flags.DataValid)
+ {
+ RTRECT SrcRect, DstRect;
+
+ SrcRect.xLeft = 0;
+ SrcRect.yTop = 0;
+ SrcRect.xRight = pTex->Tex.width;
+ SrcRect.yBottom = pTex->Tex.height;
+
+ DstRect.xLeft = 0;
+ DstRect.yTop = 0;
+ DstRect.xRight = width;
+ DstRect.yBottom = height;
+
+ CrBltBlitTexTex(pTex->pBlitter, &pTex->Tex, &SrcRect, &pScaledCache->Tex, &DstRect, 1, 0);
+ }
+
+ *ppScaledCache = pScaledCache;
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrTdBltDataAcquireScaled(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, uint32_t width, uint32_t height, const CR_BLITTER_IMG**ppImg)
+{
+ if (pTex->Tex.width == width && pTex->Tex.height == height)
+ return CrTdBltDataAcquire(pTex, enmFormat, fInverted, ppImg);
+
+ if (!pTex->Flags.Entered)
+ {
+ WARN(("tex not entered"));
+ return VERR_INVALID_STATE;
+ }
+
+ PCR_TEXDATA pScaledCache;
+
+ int rc = ctTdBltSdGetUpdated(pTex, width, height, &pScaledCache);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("ctTdBltSdGetUpdated failed rc %d", rc));
+ return rc;
+ }
+
+ rc = CrTdBltEnter(pScaledCache);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltEnter failed rc %d", rc));
+ return rc;
+ }
+
+ rc = CrTdBltDataAcquire(pScaledCache, enmFormat, fInverted, ppImg);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltDataAcquire failed rc %d", rc));
+ CrTdBltLeave(pTex->pScaledCache);
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrTdBltDataReleaseScaled(PCR_TEXDATA pTex, const CR_BLITTER_IMG *pImg)
+{
+ PCR_TEXDATA pScaledCache = RT_FROM_MEMBER(pImg, CR_TEXDATA, Img);
+ int rc = CrTdBltDataRelease(pScaledCache);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltDataRelease failed rc %d", rc));
+ return rc;
+ }
+
+ if (pScaledCache != pTex)
+ CrTdBltLeave(pScaledCache);
+
+ return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(void) CrTdBltScaleCacheMoveTo(PCR_TEXDATA pTex, PCR_TEXDATA pDstTex)
+{
+ if (!pTex->pScaledCache)
+ return;
+
+ crTdBltSdCleanupCacheNe(pDstTex);
+
+ pDstTex->pScaledCache = pTex->pScaledCache;
+ pTex->pScaledCache = NULL;
+}
diff --git a/src/VBox/GuestHost/OpenGL/util/bmpscale.cpp b/src/VBox/GuestHost/OpenGL/util/bmpscale.cpp
new file mode 100644
index 00000000..1b32487b
--- /dev/null
+++ b/src/VBox/GuestHost/OpenGL/util/bmpscale.cpp
@@ -0,0 +1,319 @@
+/** @file
+ * Image resampling code, used for snapshot thumbnails.
+ */
+
+/*
+ * Copyright (C) 2009-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * Based on gdImageCopyResampled from libgd.
+ * Original copyright notice follows:
+
+ Portions copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Pierre-Alain Joye (pierre@libgd.org).
+
+ Permission has been granted to copy, distribute and modify gd in
+ any context without fee, including a commercial application,
+ provided that this notice is present in user-accessible supporting
+ documentation.
+
+ This does not affect your ownership of the derived work itself, and
+ the intent is to assure proper credit for the authors of gd, not to
+ interfere with your productive use of gd. If you have questions,
+ ask. "Derived works" includes all programs that utilize the
+ library. Credit must be given in user-accessible documentation.
+
+ This software is provided "AS IS." The copyright holders disclaim
+ all warranties, either express or implied, including but not
+ limited to implied warranties of merchantability and fitness for a
+ particular purpose, with respect to this code and accompanying
+ documentation.
+ */
+
+/*
+ *
+ * @todo Simplify: Offsets of images are 0,0 => no dstX, dstY, srcX, srcY;
+ * Screenshot has no alpha channel => no processing of alpha byte.
+ */
+
+#include <cr_bmpscale.h>
+
+/* 2.0.10: cast instead of floor() yields 35% performance improvement.
+ Thanks to John Buckman. */
+
+#define floor2(exp) ((long) exp)
+/*#define floor2(exp) floor(exp)*/
+
+typedef uint8_t *gdImagePtr;
+
+DECLINLINE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y, int w)
+{
+ return *(int32_t *)(im + y * w * 4 + x * 4);
+}
+
+DECLINLINE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color, int cbLine)
+{
+ *(int32_t *)(im + y * cbLine + x * 4) = color;
+}
+
+#define gdAlphaMax 127
+#define gdAlphaOpaque 0
+#define gdAlphaTransparent 127
+#define gdRedMax 255
+#define gdGreenMax 255
+#define gdBlueMax 255
+#define gdTrueColorGetAlpha(c) (((c) & 0x7F000000) >> 24)
+#define gdTrueColorGetRed(c) (((c) & 0xFF0000) >> 16)
+#define gdTrueColorGetGreen(c) (((c) & 0x00FF00) >> 8)
+#define gdTrueColorGetBlue(c) ((c) & 0x0000FF)
+#define gdTrueColorAlpha(r, g, b, a) (((a) << 24) + \
+ ((r) << 16) + \
+ ((g) << 8) + \
+ (b))
+
+void gdImageCopyResampled (uint8_t *dst,
+ uint8_t *src,
+ int dstX, int dstY,
+ int srcX, int srcY,
+ int dstW, int dstH, int srcW, int srcH)
+{
+ int x, y;
+ double sy1, sy2, sx1, sx2;
+ for (y = dstY; (y < dstY + dstH); y++)
+ {
+ sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
+ sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH /
+ (double) dstH;
+ for (x = dstX; (x < dstX + dstW); x++)
+ {
+ double sx, sy;
+ double spixels = 0;
+ double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
+ sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
+ sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
+ sy = sy1;
+ do
+ {
+ double yportion;
+ if (floor2 (sy) == floor2 (sy1))
+ {
+ yportion = 1.0 - (sy - floor2 (sy));
+ if (yportion > sy2 - sy1)
+ {
+ yportion = sy2 - sy1;
+ }
+ sy = floor2 (sy);
+ }
+ else if (sy == floor2 (sy2))
+ {
+ yportion = sy2 - floor2 (sy2);
+ }
+ else
+ {
+ yportion = 1.0;
+ }
+ sx = sx1;
+ do
+ {
+ double xportion;
+ double pcontribution;
+ int p;
+ if (floor2 (sx) == floor2 (sx1))
+ {
+ xportion = 1.0 - (sx - floor2 (sx));
+ if (xportion > sx2 - sx1)
+ {
+ xportion = sx2 - sx1;
+ }
+ sx = floor2 (sx);
+ }
+ else if (sx == floor2 (sx2))
+ {
+ xportion = sx2 - floor2 (sx2);
+ }
+ else
+ {
+ xportion = 1.0;
+ }
+ pcontribution = xportion * yportion;
+ /* 2.08: previously srcX and srcY were ignored.
+ Andrew Pattison */
+ p = gdImageGetTrueColorPixel (src,
+ (int) sx + srcX,
+ (int) sy + srcY, srcW);
+ red += gdTrueColorGetRed (p) * pcontribution;
+ green += gdTrueColorGetGreen (p) * pcontribution;
+ blue += gdTrueColorGetBlue (p) * pcontribution;
+ alpha += gdTrueColorGetAlpha (p) * pcontribution;
+ spixels += xportion * yportion;
+ sx += 1.0;
+ }
+ while (sx < sx2);
+ sy += 1.0;
+ }
+ while (sy < sy2);
+ if (spixels != 0.0)
+ {
+ red /= spixels;
+ green /= spixels;
+ blue /= spixels;
+ alpha /= spixels;
+ }
+ /* Clamping to allow for rounding errors above */
+ if (red > 255.0)
+ {
+ red = 255.0;
+ }
+ if (green > 255.0)
+ {
+ green = 255.0;
+ }
+ if (blue > 255.0)
+ {
+ blue = 255.0;
+ }
+ if (alpha > gdAlphaMax)
+ {
+ alpha = gdAlphaMax;
+ }
+ gdImageSetPixel (dst,
+ x, y,
+ gdTrueColorAlpha ((int) red,
+ (int) green,
+ (int) blue, (int) alpha), dstW * 4);
+ }
+ }
+}
+
+/* Fast integer implementation for 32 bpp bitmap scaling.
+ * Use fixed point values * 16.
+ */
+typedef int32_t FIXEDPOINT;
+#define INT_TO_FIXEDPOINT(i) (FIXEDPOINT)((i) << 4)
+#define FIXEDPOINT_TO_INT(v) (int)((v) >> 4)
+#define FIXEDPOINT_FLOOR(v) ((v) & ~0xF)
+#define FIXEDPOINT_FRACTION(v) ((v) & 0xF)
+
+/* For 32 bit source only. */
+VBOXBMPSCALEDECL(void) CrBmpScale32 (uint8_t *dst,
+ int iDstDeltaLine,
+ int dstW, int dstH,
+ const uint8_t *src,
+ int iSrcDeltaLine,
+ int srcW, int srcH)
+{
+ int x, y;
+
+ for (y = 0; y < dstH; y++)
+ {
+ FIXEDPOINT sy1 = INT_TO_FIXEDPOINT(y * srcH) / dstH;
+ FIXEDPOINT sy2 = INT_TO_FIXEDPOINT((y + 1) * srcH) / dstH;
+
+ for (x = 0; x < dstW; x++)
+ {
+ FIXEDPOINT red = 0, green = 0, blue = 0;
+
+ FIXEDPOINT sx1 = INT_TO_FIXEDPOINT(x * srcW) / dstW;
+ FIXEDPOINT sx2 = INT_TO_FIXEDPOINT((x + 1) * srcW) / dstW;
+
+ FIXEDPOINT spixels = (sx2 - sx1) * (sy2 - sy1);
+
+ FIXEDPOINT sy = sy1;
+
+ do
+ {
+ FIXEDPOINT yportion;
+ if (FIXEDPOINT_FLOOR (sy) == FIXEDPOINT_FLOOR (sy1))
+ {
+ yportion = INT_TO_FIXEDPOINT(1) - FIXEDPOINT_FRACTION(sy);
+ if (yportion > sy2 - sy1)
+ {
+ yportion = sy2 - sy1;
+ }
+ sy = FIXEDPOINT_FLOOR (sy);
+ }
+ else if (sy == FIXEDPOINT_FLOOR (sy2))
+ {
+ yportion = FIXEDPOINT_FRACTION(sy2);
+ }
+ else
+ {
+ yportion = INT_TO_FIXEDPOINT(1);
+ }
+
+ const uint8_t *pu8SrcLine = src + iSrcDeltaLine * FIXEDPOINT_TO_INT(sy);
+ FIXEDPOINT sx = sx1;
+ do
+ {
+ FIXEDPOINT xportion;
+ FIXEDPOINT pcontribution;
+ int p;
+ if (FIXEDPOINT_FLOOR (sx) == FIXEDPOINT_FLOOR (sx1))
+ {
+ xportion = INT_TO_FIXEDPOINT(1) - FIXEDPOINT_FRACTION(sx);
+ if (xportion > sx2 - sx1)
+ {
+ xportion = sx2 - sx1;
+ }
+ pcontribution = xportion * yportion;
+ sx = FIXEDPOINT_FLOOR (sx);
+ }
+ else if (sx == FIXEDPOINT_FLOOR (sx2))
+ {
+ xportion = FIXEDPOINT_FRACTION(sx2);
+ pcontribution = xportion * yportion;
+ }
+ else
+ {
+ xportion = INT_TO_FIXEDPOINT(1);
+ pcontribution = xportion * yportion;
+ }
+ /* Color depth specific code begin */
+ p = *(uint32_t *)(pu8SrcLine + FIXEDPOINT_TO_INT(sx) * 4);
+ /* Color depth specific code end */
+ red += gdTrueColorGetRed (p) * pcontribution;
+ green += gdTrueColorGetGreen (p) * pcontribution;
+ blue += gdTrueColorGetBlue (p) * pcontribution;
+
+ sx += INT_TO_FIXEDPOINT(1);
+ } while (sx < sx2);
+
+ sy += INT_TO_FIXEDPOINT(1);
+ } while (sy < sy2);
+
+ if (spixels != 0)
+ {
+ red /= spixels;
+ green /= spixels;
+ blue /= spixels;
+ }
+ /* Clamping to allow for rounding errors above */
+ if (red > 255)
+ {
+ red = 255;
+ }
+ if (green > 255)
+ {
+ green = 255;
+ }
+ if (blue > 255)
+ {
+ blue = 255;
+ }
+ gdImageSetPixel (dst,
+ x, y,
+ ( ((int) red) << 16) + (((int) green) << 8) + ((int) blue),
+ iDstDeltaLine);
+ }
+ }
+}
+
diff --git a/src/VBox/GuestHost/OpenGL/util/compositor.cpp b/src/VBox/GuestHost/OpenGL/util/compositor.cpp
new file mode 100644
index 00000000..f7c50bcd
--- /dev/null
+++ b/src/VBox/GuestHost/OpenGL/util/compositor.cpp
@@ -0,0 +1,1015 @@
+/* $Id: compositor.cpp $ */
+
+/** @file
+ * Compositor impl
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#include <cr_compositor.h>
+
+#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX
+
+
+static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects)
+{
+ Assert(cRects);
+
+ if (pCompositor->cRectsBuffer >= cRects)
+ {
+ pCompositor->cRects = cRects;
+ return VINF_SUCCESS;
+ }
+
+ if (pCompositor->cRectsBuffer)
+ {
+ Assert(pCompositor->paSrcRects);
+ RTMemFree(pCompositor->paSrcRects);
+ pCompositor->paSrcRects = NULL;
+ Assert(pCompositor->paDstRects);
+ RTMemFree(pCompositor->paDstRects);
+ pCompositor->paDstRects = NULL;
+ Assert(pCompositor->paDstUnstretchedRects);
+ RTMemFree(pCompositor->paDstUnstretchedRects);
+ pCompositor->paDstUnstretchedRects = NULL;
+ }
+ else
+ {
+ Assert(!pCompositor->paSrcRects);
+ Assert(!pCompositor->paDstRects);
+ Assert(!pCompositor->paDstUnstretchedRects);
+ }
+
+ pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects);
+ if (pCompositor->paSrcRects)
+ {
+ pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects);
+ if (pCompositor->paDstRects)
+ {
+ pCompositor->paDstUnstretchedRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstUnstretchedRects) * cRects);
+ if (pCompositor->paDstUnstretchedRects)
+ {
+ pCompositor->cRects = cRects;
+ pCompositor->cRectsBuffer = cRects;
+ return VINF_SUCCESS;
+ }
+
+ RTMemFree(pCompositor->paDstRects);
+ pCompositor->paDstRects = NULL;
+ }
+ else
+ {
+ WARN(("RTMemAlloc failed!"));
+ }
+ RTMemFree(pCompositor->paSrcRects);
+ pCompositor->paSrcRects = NULL;
+ }
+ else
+ {
+ WARN(("RTMemAlloc failed!"));
+ }
+
+ pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
+ pCompositor->cRectsBuffer = 0;
+
+ return VERR_NO_MEMORY;
+}
+
+static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor)
+{
+ pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
+}
+
+static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor)
+{
+ uint32_t* pCounter = (uint32_t*)pvVisitor;
+ Assert(VBoxVrListRectsCount(&pEntry->Vr));
+ *pCounter += VBoxVrListRectsCount(&pEntry->Vr);
+ return true;
+}
+
+typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER
+{
+ PRTRECT paSrcRects;
+ PRTRECT paDstRects;
+ PRTRECT paDstUnstretchedRects;
+ uint32_t cRects;
+} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER;
+
+static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
+{
+ PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor;
+ PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
+ pEntry->paSrcRects = pData->paSrcRects;
+ pEntry->paDstRects = pData->paDstRects;
+ pEntry->paDstUnstretchedRects = pData->paDstUnstretchedRects;
+ uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr);
+ Assert(cRects);
+ Assert(cRects <= pData->cRects);
+ int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstUnstretchedRects);
+ AssertRC(rc);
+
+ if (!pEntry->Rect.xLeft && !pEntry->Rect.yTop)
+ {
+ memcpy(pEntry->paSrcRects, pEntry->paDstUnstretchedRects, cRects * sizeof (*pEntry->paSrcRects));
+ }
+ else
+ {
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstUnstretchedRects[i].xLeft - pEntry->Rect.xLeft));
+ pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstUnstretchedRects[i].yTop - pEntry->Rect.yTop));
+ pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstUnstretchedRects[i].xRight - pEntry->Rect.xLeft));
+ pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstUnstretchedRects[i].yBottom - pEntry->Rect.yTop));
+ }
+ }
+
+#ifndef IN_RING0
+ if (pCompositor->StretchX != 1. || pCompositor->StretchY != 1.)
+ {
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ if (pCompositor->StretchX != 1.)
+ {
+ pEntry->paDstRects[i].xLeft = (int32_t)(pEntry->paDstUnstretchedRects[i].xLeft * pCompositor->StretchX);
+ pEntry->paDstRects[i].xRight = (int32_t)(pEntry->paDstUnstretchedRects[i].xRight * pCompositor->StretchX);
+ }
+ if (pCompositor->StretchY != 1.)
+ {
+ pEntry->paDstRects[i].yTop = (int32_t)(pEntry->paDstUnstretchedRects[i].yTop * pCompositor->StretchY);
+ pEntry->paDstRects[i].yBottom = (int32_t)(pEntry->paDstUnstretchedRects[i].yBottom * pCompositor->StretchY);
+ }
+ }
+ }
+ else
+#endif
+ {
+ memcpy(pEntry->paDstRects, pEntry->paDstUnstretchedRects, cRects * sizeof (*pEntry->paDstUnstretchedRects));
+ }
+
+#if 0//ndef IN_RING0
+ bool canZeroX = (pCompositor->StretchX < 1.);
+ bool canZeroY = (pCompositor->StretchY < 1.);
+ if (canZeroX && canZeroY)
+ {
+ /* filter out zero rectangles*/
+ uint32_t iOrig, iNew;
+ for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig)
+ {
+ PRTRECT pOrigRect = &pEntry->paDstRects[iOrig];
+ if (pOrigRect->xLeft != pOrigRect->xRight
+ && pOrigRect->yTop != pOrigRect->yBottom)
+ continue;
+
+ if (iNew != iOrig)
+ {
+ PRTRECT pNewRect = &pEntry->paSrcRects[iNew];
+ *pNewRect = *pOrigRect;
+ }
+
+ ++iNew;
+ }
+
+ Assert(iNew <= iOrig);
+
+ uint32_t cDiff = iOrig - iNew;
+
+ if (cDiff)
+ {
+ pCompositor->cRects -= cDiff;
+ cRects -= cDiff;
+ }
+ }
+#endif
+
+ pEntry->cRects = cRects;
+ pData->paDstRects += cRects;
+ pData->paSrcRects += cRects;
+ pData->paDstUnstretchedRects += cRects;
+ pData->cRects -= cRects;
+ return true;
+}
+
+static int crVrScrCompositorRectsCheckInit(const VBOXVR_SCR_COMPOSITOR *pcCompositor)
+{
+ VBOXVR_SCR_COMPOSITOR *pCompositor = const_cast<VBOXVR_SCR_COMPOSITOR*>(pcCompositor);
+
+ if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED)
+ return VINF_SUCCESS;
+
+ uint32_t cRects = 0;
+ VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects);
+
+ if (!cRects)
+ {
+ pCompositor->cRects = 0;
+ return VINF_SUCCESS;
+ }
+
+ int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects);
+ if (!RT_SUCCESS(rc))
+ return rc;
+
+ VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData;
+ AssignerData.paSrcRects = pCompositor->paSrcRects;
+ AssignerData.paDstRects = pCompositor->paDstRects;
+ AssignerData.paDstUnstretchedRects = pCompositor->paDstUnstretchedRects;
+ AssignerData.cRects = pCompositor->cRects;
+ VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData);
+ Assert(!AssignerData.cRects);
+ return VINF_SUCCESS;
+}
+
+
+static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangedFlags)
+{
+ uint32_t fChangedFlags = 0;
+ PVBOXVR_COMPOSITOR_ENTRY pReplacedEntry;
+ int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, pEntry ? &pEntry->Ce : NULL, cRegions, paRegions, &pReplacedEntry, &fChangedFlags);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
+ return rc;
+ }
+
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacedEntry);
+
+ if (fChangedFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED)
+ {
+ crVrScrCompositorRectsInvalidate(pCompositor);
+ }
+ else if (fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED)
+ {
+ Assert(pReplacedScrEntry);
+ }
+
+ if (fChangedFlags & VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED)
+ {
+ CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
+ }
+ else if ((fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED) && pEntry)
+ {
+ CrVrScrCompositorEntrySetChanged(pEntry, true);
+ }
+
+ if (pfChangedFlags)
+ *pfChangedFlags = fChangedFlags;
+
+ if (ppReplacedScrEntry)
+ *ppReplacedScrEntry = pReplacedScrEntry;
+
+ return VINF_SUCCESS;
+}
+
+static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
+{
+ bool fChanged;
+ int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc));
+ return rc;
+ }
+
+ if (fChanged)
+ {
+ CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
+ if (!CrVrScrCompositorEntryIsInList(pEntry))
+ {
+ pEntry->cRects = 0;
+ pEntry->paSrcRects = NULL;
+ pEntry->paDstRects = NULL;
+ pEntry->paDstUnstretchedRects = NULL;
+ }
+ crVrScrCompositorRectsInvalidate(pCompositor);
+ }
+
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+ return VINF_SUCCESS;
+}
+
+static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged)
+{
+ if (pfChanged)
+ *pfChanged = false;
+ if (pEntry && (pEntry->Rect.xLeft != pPos->x || pEntry->Rect.yTop != pPos->y))
+ {
+ if (VBoxVrCompositorEntryIsInList(&pEntry->Ce))
+ {
+ int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Rect.xLeft, pPos->y - pEntry->Rect.yTop, pfChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc));
+ return rc;
+ }
+
+ crVrScrCompositorRectsInvalidate(pCompositor);
+ }
+
+ VBoxRectMove(&pEntry->Rect, pPos->x, pPos->y);
+ CrVrScrCompositorEntrySetChanged(pEntry, true);
+
+ if (pfChanged)
+ *pfChanged = true;
+ }
+ return VINF_SUCCESS;
+}
+
+static int crVrScrCompositorEntryEnsureRegionsBounds(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, bool *pfChanged)
+{
+ RTRECT Rect;
+ Rect.xLeft = RT_MAX(pCompositor->Rect.xLeft, pEntry->Rect.xLeft);
+ Rect.yTop = RT_MAX(pCompositor->Rect.yTop, pEntry->Rect.yTop);
+ Rect.xRight = RT_MIN(pCompositor->Rect.xRight, pEntry->Rect.xRight);
+ Rect.yBottom = RT_MIN(pCompositor->Rect.yBottom, pEntry->Rect.yBottom);
+ bool fChanged = false;
+
+ if (pfChanged)
+ *pfChanged = false;
+
+ int rc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, 1, &Rect, &fChanged);
+ if (!RT_SUCCESS(rc))
+ WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", rc));
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+ return rc;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangeFlags)
+{
+ int rc;
+ uint32_t fChangeFlags = 0;
+ bool fPosChanged = false;
+ RTRECT *paTranslatedRects = NULL;
+ if (pPos)
+ {
+ rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc));
+ return rc;
+ }
+ }
+
+ if (fPosRelated)
+ {
+ if (!pEntry)
+ {
+ WARN(("Entry is expected to be specified for pos-related regions"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (cRegions && (pEntry->Rect.xLeft || pEntry->Rect.yTop))
+ {
+ paTranslatedRects = (RTRECT*)RTMemAlloc(sizeof (RTRECT) * cRegions);
+ if (!paTranslatedRects)
+ {
+ WARN(("RTMemAlloc failed"));
+ return VERR_NO_MEMORY;
+ }
+ memcpy (paTranslatedRects, paRegions, sizeof (RTRECT) * cRegions);
+ for (uint32_t i = 0; i < cRegions; ++i)
+ {
+ VBoxRectTranslate(&paTranslatedRects[i], pEntry->Rect.xLeft, pEntry->Rect.yTop);
+ paRegions = paTranslatedRects;
+ }
+ }
+ }
+
+ rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, ppReplacedScrEntry, &fChangeFlags);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc));
+ goto done;
+ }
+
+ if ((fPosChanged || (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)) && pEntry)
+ {
+ bool fAdjusted = false;
+ rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, &fAdjusted);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc));
+ goto done;
+ }
+
+ if (fAdjusted)
+ {
+ if (CrVrScrCompositorEntryIsUsed(pEntry))
+ {
+ fChangeFlags &= ~VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED;
+ fChangeFlags |= VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED;
+ }
+ else
+ {
+ fChangeFlags = 0;
+ }
+ }
+ }
+
+ if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED)
+ fPosChanged = false;
+ else if (ppReplacedScrEntry)
+ *ppReplacedScrEntry = NULL;
+
+ if (pfChangeFlags)
+ {
+ if (fPosChanged)
+ {
+ /* means entry was in list and was moved, so regions changed */
+ *pfChangeFlags = VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED;
+ }
+ else
+ *pfChangeFlags = fChangeFlags;
+ }
+
+done:
+
+ if (paTranslatedRects)
+ RTMemFree(paTranslatedRects);
+
+ return rc;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryRectSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTRECT *pRect)
+{
+ if (!memcmp(&pEntry->Rect, pRect, sizeof (*pRect)))
+ {
+ return VINF_SUCCESS;
+ }
+ RTPOINT Point = {pRect->xLeft, pRect->yTop};
+ bool fChanged = false;
+ int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, &Point, &fChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorEntryPositionSet failed %d", rc));
+ return rc;
+ }
+
+ pEntry->Rect = *pRect;
+
+ if (!CrVrScrCompositorEntryIsUsed(pEntry))
+ return VINF_SUCCESS;
+
+ rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryTexAssign(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, CR_TEXDATA *pTex)
+{
+ if (pEntry->pTex == pTex)
+ return VINF_SUCCESS;
+
+ if (pEntry->pTex)
+ CrTdRelease(pEntry->pTex);
+ if (pTex)
+ CrTdAddRef(pTex);
+ pEntry->pTex = pTex;
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, bool *pfChanged)
+{
+ /* @todo: the fChanged sate calculation is really rough now, this is enough for now though */
+ bool fChanged = false, fPosChanged = false;
+ bool fWasInList = CrVrScrCompositorEntryIsInList(pEntry);
+ RTRECT *paTranslatedRects = NULL;
+ int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc));
+ return rc;
+ }
+
+ if (pPos)
+ {
+ rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
+ return rc;
+ }
+ }
+
+ if (fPosRelated)
+ {
+ if (!pEntry)
+ {
+ WARN(("Entry is expected to be specified for pos-related regions"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (cRegions && (pEntry->Rect.xLeft || pEntry->Rect.yTop))
+ {
+ paTranslatedRects = (RTRECT*)RTMemAlloc(sizeof (RTRECT) * cRegions);
+ if (!paTranslatedRects)
+ {
+ WARN(("RTMemAlloc failed"));
+ return VERR_NO_MEMORY;
+ }
+ memcpy (paTranslatedRects, paRegions, sizeof (RTRECT) * cRegions);
+ for (uint32_t i = 0; i < cRegions; ++i)
+ {
+ VBoxRectTranslate(&paTranslatedRects[i], pEntry->Rect.xLeft, pEntry->Rect.yTop);
+ paRegions = paTranslatedRects;
+ }
+ }
+ }
+
+ rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, &fChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorEntryRegionsSet failed, rc %d", rc));
+ return rc;
+ }
+
+ if (fChanged && CrVrScrCompositorEntryIsUsed(pEntry))
+ {
+ rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc));
+ return rc;
+ }
+ }
+
+ if (pfChanged)
+ *pfChanged = fPosChanged || fChanged || fWasInList;
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
+{
+ bool fChanged = false;
+ int rc = VBoxVrCompositorEntryListIntersect(&pCompositor->Compositor, &pEntry->Ce, pList2, &fChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
+ return rc;
+ }
+
+ if (fChanged)
+ {
+ CrVrScrCompositorEntrySetChanged(pEntry, true);
+ crVrScrCompositorRectsInvalidate(pCompositor);
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
+{
+ bool fChanged = false;
+ int rc = VBoxVrCompositorEntryRegionsIntersect(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
+ return rc;
+ }
+
+ if (fChanged)
+ crVrScrCompositorRectsInvalidate(pCompositor);
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
+{
+ VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
+ CrVrScrCompositorIterInit(pCompositor, &Iter);
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
+ int rc = VINF_SUCCESS;
+ bool fChanged = false;
+
+ while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
+ {
+ bool fTmpChanged = false;
+ int tmpRc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
+ if (RT_SUCCESS(tmpRc))
+ {
+ fChanged |= fTmpChanged;
+ }
+ else
+ {
+ WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
+ rc = tmpRc;
+ }
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return rc;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
+{
+ VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
+ CrVrScrCompositorIterInit(pCompositor, &Iter);
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
+ int rc = VINF_SUCCESS;
+ bool fChanged = false;
+
+ while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
+ {
+ bool fTmpChanged = false;
+ int tmpRc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
+ if (RT_SUCCESS(tmpRc))
+ {
+ fChanged |= fTmpChanged;
+ }
+ else
+ {
+ WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
+ rc = tmpRc;
+ }
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return rc;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos)
+{
+ int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
+ return rc;
+ }
+
+ rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RegionsSet: crVrScrCompositorEntryEnsureRegionsBounds failed rc %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+/* regions are valid until the next CrVrScrCompositor call */
+VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects)
+{
+ if (CrVrScrCompositorEntryIsUsed(pEntry))
+ {
+ int rc = crVrScrCompositorRectsCheckInit(pCompositor);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
+ return rc;
+ }
+ }
+
+ Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
+
+ *pcRegions = pEntry->cRects;
+ if (ppaSrcRegions)
+ *ppaSrcRegions = pEntry->paSrcRects;
+ if (ppaDstRegions)
+ *ppaDstRegions = pEntry->paDstRects;
+ if (ppaDstUnstretchedRects)
+ *ppaDstUnstretchedRects = pEntry->paDstUnstretchedRects;
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(uint32_t) CrVrScrCompositorEntryFlagsCombinedGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry)
+{
+ return CRBLT_FOP_COMBINE(pCompositor->fFlags, pEntry->fFlags);
+}
+
+VBOXVREGDECL(void) CrVrScrCompositorEntryFlagsSet(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t fFlags)
+{
+ if (pEntry->fFlags == fFlags)
+ return;
+
+ pEntry->fFlags = fFlags;
+ CrVrScrCompositorEntrySetChanged(pEntry, true);
+}
+
+static void crVrScrCompositorEntryDataCleanup(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
+{
+ pEntry->cRects = 0;
+ pEntry->paSrcRects = NULL;
+ pEntry->paDstRects = NULL;
+ pEntry->paDstUnstretchedRects = NULL;
+}
+
+static void crVrScrCompositorEntryDataCopy(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pToEntry)
+{
+ pToEntry->cRects = pEntry->cRects;
+ pToEntry->paSrcRects = pEntry->paSrcRects;
+ pToEntry->paDstRects = pEntry->paDstRects;
+ pToEntry->paDstUnstretchedRects = pEntry->paDstUnstretchedRects;
+ crVrScrCompositorEntryDataCleanup(pEntry);
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
+{
+ if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce))
+ return VINF_SUCCESS;
+
+ CrVrScrCompositorEntrySetChanged(pEntry, true);
+ crVrScrCompositorEntryDataCleanup(pEntry);
+
+ crVrScrCompositorRectsInvalidate(pCompositor);
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(bool) CrVrScrCompositorEntryReplace(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pNewEntry)
+{
+ Assert(!CrVrScrCompositorEntryIsUsed(pNewEntry));
+
+ if (!VBoxVrCompositorEntryReplace(&pCompositor->Compositor, &pEntry->Ce, &pNewEntry->Ce))
+ return false;
+
+ CrVrScrCompositorEntrySetChanged(pEntry, true);
+ crVrScrCompositorEntryDataCopy(pEntry, pNewEntry);
+ CrVrScrCompositorEntrySetChanged(pNewEntry, true);
+
+ return true;
+}
+
+static DECLCALLBACK(void) crVrScrCompositorEntryReleasedCB(const struct VBOXVR_COMPOSITOR *pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
+{
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pCEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pEntry);
+
+ CrVrScrCompositorEntrySetChanged(pCEntry, true);
+
+ Assert(!CrVrScrCompositorEntryIsInList(pCEntry));
+
+ if (pReplacingEntry)
+ {
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pCReplacingEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacingEntry);
+ Assert(CrVrScrCompositorEntryIsInList(pCReplacingEntry));
+ pCReplacingEntry->cRects = pCEntry->cRects;
+ pCReplacingEntry->paSrcRects = pCEntry->paSrcRects;
+ pCReplacingEntry->paDstRects = pCEntry->paDstRects;
+ pCReplacingEntry->paDstUnstretchedRects = pCEntry->paDstUnstretchedRects;
+ }
+
+ if (pCEntry->pfnEntryReleased)
+ {
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pCReplacingEntry = pReplacingEntry ? VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacingEntry) : NULL;
+ PVBOXVR_SCR_COMPOSITOR pCConpositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCompositor);
+ pCEntry->pfnEntryReleased(pCConpositor, pCEntry, pCReplacingEntry);
+ }
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorRectSet(PVBOXVR_SCR_COMPOSITOR pCompositor, const RTRECT *pRect, bool *pfChanged)
+{
+ if (!memcmp(&pCompositor->Rect, pRect, sizeof (pCompositor->Rect)))
+ {
+ if (pfChanged)
+ *pfChanged = false;
+ return VINF_SUCCESS;
+ }
+
+ pCompositor->Rect = *pRect;
+
+ VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
+ CrVrScrCompositorIterInit(pCompositor, &Iter);
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
+ while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
+ {
+ int rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(void) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor, const RTRECT *pRect)
+{
+ memset(pCompositor, 0, sizeof (*pCompositor));
+ VBoxVrCompositorInit(&pCompositor->Compositor, crVrScrCompositorEntryReleasedCB);
+ pCompositor->fFlags = CRBLT_F_LINEAR | CRBLT_F_INVERT_YCOORDS;
+ if (pRect)
+ pCompositor->Rect = *pRect;
+#ifndef IN_RING0
+ pCompositor->StretchX = 1.0;
+ pCompositor->StretchY = 1.0;
+#endif
+}
+
+VBOXVREGDECL(void) CrVrScrCompositorRegionsClear(PVBOXVR_SCR_COMPOSITOR pCompositor, bool *pfChanged)
+{
+ /* set changed flag first, while entries are in the list and we have them */
+ CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
+ VBoxVrCompositorRegionsClear(&pCompositor->Compositor, pfChanged);
+ crVrScrCompositorRectsInvalidate(pCompositor);
+}
+
+VBOXVREGDECL(void) CrVrScrCompositorClear(PVBOXVR_SCR_COMPOSITOR pCompositor)
+{
+ CrVrScrCompositorRegionsClear(pCompositor, NULL);
+ if (pCompositor->paDstRects)
+ {
+ RTMemFree(pCompositor->paDstRects);
+ pCompositor->paDstRects = NULL;
+ }
+ if (pCompositor->paSrcRects)
+ {
+ RTMemFree(pCompositor->paSrcRects);
+ pCompositor->paSrcRects = NULL;
+ }
+ if (pCompositor->paDstUnstretchedRects)
+ {
+ RTMemFree(pCompositor->paDstUnstretchedRects);
+ pCompositor->paDstUnstretchedRects = NULL;
+ }
+
+ pCompositor->cRects = 0;
+ pCompositor->cRectsBuffer = 0;
+}
+
+VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged)
+{
+ VBOXVR_SCR_COMPOSITOR_ITERATOR CIter;
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pCurEntry;
+ CrVrScrCompositorIterInit(pCompositor, &CIter);
+
+ while ((pCurEntry = CrVrScrCompositorIterNext(&CIter)) != NULL)
+ {
+ CrVrScrCompositorEntrySetChanged(pCurEntry, fChanged);
+ }
+}
+
+#ifndef IN_RING0
+VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY)
+{
+ if (pCompositor->StretchX == StretchX && pCompositor->StretchY == StretchY)
+ return;
+
+ pCompositor->StretchX = StretchX;
+ pCompositor->StretchY = StretchY;
+ crVrScrCompositorRectsInvalidate(pCompositor);
+ CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
+}
+#endif
+
+/* regions are valid until the next CrVrScrCompositor call */
+VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects)
+{
+ int rc = crVrScrCompositorRectsCheckInit(pCompositor);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
+ return rc;
+ }
+
+ Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
+
+ *pcRegions = pCompositor->cRects;
+ if (ppaSrcRegions)
+ *ppaSrcRegions = pCompositor->paSrcRects;
+ if (ppaDstRegions)
+ *ppaDstRegions = pCompositor->paDstRects;
+ if (ppaDstUnstretchedRects)
+ *ppaDstUnstretchedRects = pCompositor->paDstUnstretchedRects;
+
+ return VINF_SUCCESS;
+}
+
+typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB
+{
+ PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor;
+ void *pvVisitor;
+} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB;
+
+static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
+{
+ PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor;
+ PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
+ return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor);
+}
+
+VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
+{
+ VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data;
+ Data.pfnVisitor = pfnVisitor;
+ Data.pvVisitor = pvVisitor;
+ VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data);
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorClone(const VBOXVR_SCR_COMPOSITOR *pCompositor, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor)
+{
+ /* for simplicity just copy from one to another */
+ CrVrScrCompositorInit(pDstCompositor, CrVrScrCompositorRectGet(pCompositor));
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+ int rc = VINF_SUCCESS;
+ uint32_t cRects;
+ const RTRECT *pRects;
+
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ /* get source rects, that will be non-stretched and entry pos - pased */
+ rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRects, NULL, NULL, &pRects);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc));
+ return rc;
+ }
+
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pDstEntry = pfnEntryFor(pEntry, pvEntryFor);
+ if (!pDstEntry)
+ {
+ WARN(("pfnEntryFor failed"));
+ return VERR_INVALID_STATE;
+ }
+
+ rc = CrVrScrCompositorEntryRegionsSet(pDstCompositor, pDstEntry, NULL, cRects, pRects, false, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc));
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorIntersectList(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pVr, bool *pfChanged)
+{
+ VBOXVR_SCR_COMPOSITOR_ITERATOR CIter;
+ PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
+ CrVrScrCompositorIterInit(pCompositor, &CIter);
+ int rc = VINF_SUCCESS;
+ bool fChanged = false;
+
+ while ((pEntry = CrVrScrCompositorIterNext(&CIter)) != NULL)
+ {
+ bool fCurChanged = false;
+
+ rc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pVr, &fCurChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc));
+ break;
+ }
+
+ fChanged |= fCurChanged;
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return rc;
+}
+
+VBOXVREGDECL(int) CrVrScrCompositorIntersectedList(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_LIST *pVr, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor, bool *pfChanged)
+{
+ int rc = CrVrScrCompositorClone(pCompositor, pDstCompositor, pfnEntryFor, pvEntryFor);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorClone failed, rc %d", rc));
+ return rc;
+ }
+
+ rc = CrVrScrCompositorIntersectList(pDstCompositor, pVr, pfChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorIntersectList failed, rc %d", rc));
+ CrVrScrCompositorClear(pDstCompositor);
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/GuestHost/OpenGL/util/dll.c b/src/VBox/GuestHost/OpenGL/util/dll.c
index a3245a36..dbc61759 100644
--- a/src/VBox/GuestHost/OpenGL/util/dll.c
+++ b/src/VBox/GuestHost/OpenGL/util/dll.c
@@ -18,6 +18,10 @@
#include <dlfcn.h>
#endif
+#ifdef WINDOWS
+#include <Shlwapi.h>
+#endif
+
#ifdef DARWIN
#include <Carbon/Carbon.h>
@@ -147,7 +151,6 @@ int get_dll_type( const char *name ) {
#endif
-
/*
* Open the named shared library.
* If resolveGlobal is non-zero, unresolved symbols can be satisfied by
@@ -162,14 +165,77 @@ CRDLL *crDLLOpen( const char *dllname, int resolveGlobal )
{
CRDLL *dll;
char *dll_err;
+#if defined(WINDOWS)
+ WCHAR szwPath[MAX_PATH];
+ UINT cwcPath = 0;
+
+ (void) resolveGlobal;
+
+# ifndef CR_NO_GL_SYSTEM_PATH
+ if (PathIsRelative(dllname))
+ {
+ size_t cName = strlen(dllname) + 1;
+# ifdef IN_GUEST
+ cwcPath = GetSystemDirectoryW(szwPath, RT_ELEMENTS(szwPath));
+ if (!cwcPath || cwcPath >= MAX_PATH)
+ {
+ DWORD winEr = GetLastError();
+ crError("GetSystemDirectoryW failed err %d", winEr);
+ SetLastError(winEr);
+ return NULL;
+ }
+# else
+ WCHAR * pszwSlashFile;
+ cwcPath = GetModuleFileNameW(NULL, szwPath, RT_ELEMENTS(szwPath));
+ if (!cwcPath || cwcPath >= MAX_PATH)
+ {
+ DWORD winEr = GetLastError();
+ crError("GetModuleFileNameW failed err %d", winEr);
+ SetLastError(winEr);
+ return NULL;
+ }
+
+ pszwSlashFile = wcsrchr(szwPath, L'\\');
+ if (!pszwSlashFile)
+ {
+ crError("failed to match file name");
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return NULL;
+ }
+
+ cwcPath = pszwSlashFile - szwPath;
+# endif
+
+ if (cwcPath + 1 + cName > MAX_PATH)
+ {
+ crError("invalid path specified");
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return NULL;
+ }
+ szwPath[cwcPath] = '\\';
+ ++cwcPath;
+ }
+
+ if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, dllname, -1, &szwPath[cwcPath], MAX_PATH - cwcPath))
+ {
+ DWORD winEr = GetLastError();
+ crError("MultiByteToWideChar failed err %d", winEr);
+ SetLastError(winEr);
+ return NULL;
+ }
+# endif // CR_NO_GL_SYSTEM_PATH
+#endif
dll = (CRDLL *) crAlloc( sizeof( CRDLL ) );
dll->name = crStrdup( dllname );
#if defined(WINDOWS)
- (void) resolveGlobal;
- dll->hinstLib = LoadLibrary( dllname );
- dll_err = NULL;
+ dll->hinstLib = LoadLibraryW( szwPath );
+ if (!dll->hinstLib)
+ {
+ crError("failed to load dll %s", dllname);
+ }
+ dll_err = NULL;
#elif defined(DARWIN)
/* XXX \todo Get better error handling in here */
dll->type = get_dll_type( dllname );
diff --git a/src/VBox/GuestHost/OpenGL/util/error.c b/src/VBox/GuestHost/OpenGL/util/error.c
index 4a8254b3..48fbc577 100644
--- a/src/VBox/GuestHost/OpenGL/util/error.c
+++ b/src/VBox/GuestHost/OpenGL/util/error.c
@@ -125,7 +125,7 @@ static void __crCheckAustralia(void)
static void outputChromiumMessage( FILE *output, char *str )
{
- fprintf( output, "%s%s%s%s\n", str,
+ fprintf( output, "%s%s%s%s\n", str,
swedish_chef ? " BORK BORK BORK!" : "",
canada ? ", eh?" : "",
australia ? ", mate!" : ""
@@ -219,7 +219,7 @@ DECLEXPORT(void) crError(const char *format, ... )
MessageBox( NULL, txt, "Chromium Error", MB_OK );
}
else
- {
+ {
#endif
va_end( args );
#ifdef WINDOWS
@@ -241,10 +241,13 @@ DECLEXPORT(void) crError(const char *format, ... )
}
void crEnableWarnings(int onOff)
-{
+{
warnings_enabled = onOff;
}
+#ifdef DEBUG_misha
+# undef crWarning
+#endif
DECLEXPORT(void) crWarning(const char *format, ... )
{
if (warnings_enabled) {
@@ -268,7 +271,7 @@ DECLEXPORT(void) crWarning(const char *format, ... )
#endif
va_end( args );
-#if defined(WINDOWS) && defined(DEBUG) && !defined(IN_GUEST)
+#if defined(WINDOWS) && defined(DEBUG) && !defined(IN_GUEST) && defined(DEBUG_misha)
DebugBreak();
#endif
}
@@ -373,13 +376,13 @@ DECLEXPORT(void) crDebug(const char *format, ... )
if (crStrlen(fnamePrefix) < sizeof (str) - sizeof (pname) - 20)
{
crGetProcName(pname, 1024);
- sprintf(str, "%s_%s_%u.txt", fnamePrefix, pname,
+ sprintf(str,
#ifdef RT_OS_WINDOWS
- GetCurrentProcessId()
+ "%s_%s_%u.txt", fnamePrefix, pname, GetCurrentProcessId()
#else
- crGetPID()
+ "%s_%s_%lu.txt", fnamePrefix, pname, crGetPID()
#endif
- );
+ );
fname = &str[0];
}
}
@@ -399,7 +402,7 @@ DECLEXPORT(void) crDebug(const char *format, ... )
output = fopen( fname, "w" );
if (!output)
{
- crError( "Couldn't open debug log %s", fname );
+ crError( "Couldn't open debug log %s", fname );
}
}
else
@@ -495,18 +498,16 @@ DECLEXPORT(void) crDebug(const char *format, ... )
outputChromiumMessage( output, txt );
#else
if (!output
-# ifndef DEBUG_misha
+#ifndef DEBUG_misha
|| output==stderr
-# endif
+#endif
)
{
LogRel(("%s\n", txt));
}
else
{
-# ifndef DEBUG_misha
LogRel(("%s\n", txt));
-# endif
outputChromiumMessage(output, txt);
}
#endif
diff --git a/src/VBox/GuestHost/OpenGL/util/hash.c b/src/VBox/GuestHost/OpenGL/util/hash.c
index c91c4ad0..95f3ab65 100644
--- a/src/VBox/GuestHost/OpenGL/util/hash.c
+++ b/src/VBox/GuestHost/OpenGL/util/hash.c
@@ -9,20 +9,25 @@
#include "cr_mem.h"
#include "cr_error.h"
+#include <iprt/list.h>
+
#define CR_MAXUINT ((GLuint) 0xFFFFFFFF)
+#define CR_HASH_ID_MIN ((GLuint)1)
+#define CR_HASH_ID_MAX CR_MAXUINT
#define CR_NUM_BUCKETS 1047
typedef struct FreeElemRec {
+ RTLISTNODE Node;
GLuint min;
GLuint max;
- struct FreeElemRec *next;
- struct FreeElemRec *prev;
} FreeElem;
-typedef struct CRHashIdPoolRec {
- FreeElem *freeList;
-} CRHashIdPool;
+struct CRHashIdPool {
+ RTLISTNODE freeList;
+ GLuint min;
+ GLuint max;
+};
typedef struct CRHashNode {
unsigned long key;
@@ -40,86 +45,124 @@ struct CRHashTable {
};
-static CRHashIdPool *crAllocHashIdPool( void )
+CRHashIdPool *crAllocHashIdPoolEx( GLuint min, GLuint max )
{
- CRHashIdPool *pool = (CRHashIdPool *) crCalloc(sizeof(CRHashIdPool));
- pool->freeList = (FreeElem *) crCalloc(sizeof(FreeElem));
- pool->freeList->min = 1;
- pool->freeList->max = CR_MAXUINT;
- pool->freeList->next = NULL;
- pool->freeList->prev = NULL;
+ CRHashIdPool *pool;
+ FreeElem *elem;
+ if (min < CR_HASH_ID_MIN || max > CR_HASH_ID_MAX || min >= max)
+ {
+ crWarning("invalid min man vals");
+ return NULL;
+ }
+ pool = (CRHashIdPool *) crCalloc(sizeof(CRHashIdPool));
+ elem = (FreeElem *) crCalloc(sizeof(FreeElem));
+ RTListInit(&pool->freeList);
+ elem->min = min;
+ elem->max = max;
+ RTListAppend(&pool->freeList, &elem->Node);
+ pool->min = min;
+ pool->max = max;
return pool;
}
-static void crFreeHashIdPool( CRHashIdPool *pool )
+CRHashIdPool *crAllocHashIdPool( void )
+{
+ return crAllocHashIdPoolEx( CR_HASH_ID_MIN, CR_HASH_ID_MAX );
+}
+
+void crFreeHashIdPool( CRHashIdPool *pool )
{
FreeElem *i, *next;
- for (i = pool->freeList; i; i = next)
+ RTListForEachSafe(&pool->freeList, i, next, FreeElem, Node)
{
- next = i->next;
crFree(i);
}
+
crFree(pool);
}
+#ifdef DEBUG_misha
+static void crHashIdPoolDbgCheckConsistency(CRHashIdPool *pool)
+{
+ FreeElem *i;
+ GLuint min = 0;
+
+ /* null is a special case, it is always treated as allocated */
+ Assert(!crHashIdPoolIsIdFree(pool, 0));
+
+ /* first ensure entries have correct values */
+ RTListForEach(&pool->freeList, i, FreeElem, Node)
+ {
+ Assert(i->min >= pool->min);
+ Assert(i->max <= pool->max);
+ Assert(i->min < i->max);
+ }
+
+ /* now ensure entries do not intersect */
+ /* and that they are sorted */
+ RTListForEach(&pool->freeList, i, FreeElem, Node)
+ {
+ Assert(min < i->min);
+ min = i->max;
+ }
+}
+
+static void crHashIdPoolDbgCheckUsed( const CRHashIdPool *pool, GLuint start, GLuint count, GLboolean fUsed )
+{
+ GLuint i;
+ CRASSERT(count);
+ CRASSERT(start >= pool->min);
+ CRASSERT(start + count <= pool->max);
+ CRASSERT(start + count > start);
+ for (i = 0; i < count; ++i)
+ {
+ Assert(!fUsed == !!crHashIdPoolIsIdFree( pool, start + i ));
+ }
+}
+
+# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { \
+ crHashIdPoolDbgCheckConsistency((_p)); \
+ crHashIdPoolDbgCheckUsed( (_p), (_start), (_count), (_used) ); \
+ } while (0)
+
+# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { crHashIdPoolDbgCheckConsistency((_p)); } while (0)
+#else
+# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { } while (0)
+# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { } while (0)
+#endif
+
/*
* Allocate a block of <count> IDs. Return index of first one.
* Return 0 if we fail.
*/
-static GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count )
+GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count )
{
- FreeElem *f;
+ FreeElem *f, *next;
GLuint ret;
CRASSERT(count > 0);
-
- f = pool->freeList;
- while (f)
+ RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node)
{
- if (f->max - f->min + 1 >= (GLuint) count)
+ Assert(f->max > f->min);
+ if (f->max - f->min >= (GLuint) count)
{
/* found a sufficiently large enough block */
ret = f->min;
f->min += count;
-
if (f->min == f->max)
{
- /* remove this block from linked list */
- if (f == pool->freeList)
- {
- /* remove from head */
- pool->freeList = pool->freeList->next;
- pool->freeList->prev = NULL;
- }
- else
- {
- /* remove from elsewhere */
- f->prev->next = f->next;
- f->next->prev = f->prev;
- }
+ RTListNodeRemove(&f->Node);
crFree(f);
}
-#ifdef DEBUG
- /* make sure the IDs really are allocated */
- {
- GLuint i;
- for (i = 0; i < count; i++)
- {
- //CRASSERT(crHashIdPoolIsIdUsed(pool, ret + i));
- }
- }
-#endif
-
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, ret, count, GL_TRUE);
return ret;
}
- else {
- f = f->next;
- }
}
/* failed to find free block */
- crDebug("crHashIdPoolAllocBlock failed");
+ crWarning("crHashIdPoolAllocBlock failed");
+ CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(pool);
return 0;
}
@@ -127,107 +170,91 @@ static GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count )
/*
* Free a block of <count> IDs starting at <first>.
*/
-static void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count )
+void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count )
{
- FreeElem *i;
- FreeElem *newelem;
-
- /*********************************/
- /* Add the name to the freeList */
- /* Find the bracketing sequences */
+ FreeElem *f;
+ GLuint last;
+ GLuint newMax;
+ FreeElem *cur, *curNext;
- for (i = pool->freeList; i && i->next && i->next->min < first; i = i->next)
+ /* null is a special case, it is always treated as allocated */
+ if (!first)
{
- /* EMPTY BODY */
+ Assert(!crHashIdPoolIsIdFree(pool, 0));
+ ++first;
+ --count;
+ if (!count)
+ return;
}
- /* j will always be valid */
- if (!i) {
- return;
- }
- if (!i->next && i->max == first) {
- return;
- }
+ last = first + count;
+ CRASSERT(count > 0);
+ CRASSERT(last > first);
+ CRASSERT(first >= pool->min);
+ CRASSERT(last <= pool->max);
- /* Case: j:(~,first-1) */
- if (i->max + 1 == first)
+ /* the id list is sorted, first find a place to insert */
+ RTListForEach(&pool->freeList, f, FreeElem, Node)
{
- i->max += count;
- if (i->next && i->max+1 >= i->next->min)
+ Assert(f->max > f->min);
+
+ if (f->max < first)
+ continue;
+
+ if (f->min > last)
{
- /* Collapse */
- i->next->min = i->min;
- i->next->prev = i->prev;
- if (i->prev)
- {
- i->prev->next = i->next;
- }
- if (i == pool->freeList)
- {
- pool->freeList = i->next;
- }
- crFree(i);
+ /* we are here because first is > than prevEntry->max
+ * otherwise the previous loop iterations should handle that */
+ FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
+ elem->min = first;
+ elem->max = last;
+ RTListNodeInsertBefore(&f->Node, &elem->Node);
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
+ return;
}
- return;
- }
- /* Case: j->next: (first+1, ~) */
- if (i->next && i->next->min - count == first)
- {
- i->next->min -= count;
- if (i->max + 1 >= i->next->min)
+ /* now we have f->min <= last and f->max >= first,
+ * so we have either intersection */
+
+ if (f->min > first)
+ f->min = first; /* first is guaranteed not to touch any prev regions */
+
+ newMax = last;
+
+ if (f->max >= last)
{
- /* Collapse */
- i->next->min = i->min;
- i->next->prev = i->prev;
- if (i->prev)
- {
- i->prev->next = i->next;
- }
- if (i == pool->freeList)
- {
- pool->freeList = i->next;
- }
- crFree(i);
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
+ return;
}
- return;
- }
- /* Case: j: (first+1, ~) j->next: null */
- if (!i->next && i->min - count == first)
- {
- i->min -= count;
- return;
- }
+ for (cur = RTListNodeGetNext(&f->Node, FreeElem, Node),
+ curNext = RT_FROM_MEMBER(cur->Node.pNext, FreeElem, Node);
+ !RTListNodeIsDummy(&pool->freeList, cur, FreeElem, Node);
+ cur = curNext,
+ curNext = RT_FROM_MEMBER((cur)->Node.pNext, FreeElem, Node) )
+ {
+ if (cur->min > last)
+ break;
- /* allocate a new FreeElem node */
- newelem = (FreeElem *) crCalloc(sizeof(FreeElem));
- newelem->min = first;
- newelem->max = first + count - 1;
+ newMax = cur->max;
+ RTListNodeRemove(&cur->Node);
+ crFree(cur);
- /* Case: j: (~,first-(2+)) j->next: (first+(2+), ~) or null */
- if (first > i->max)
- {
- newelem->prev = i;
- newelem->next = i->next;
- if (i->next)
- {
- i->next->prev = newelem;
+ if (newMax >= last)
+ break;
}
- i->next = newelem;
- return;
- }
- /* Case: j: (first+(2+), ~) */
- /* Can only happen if j = t->freeList! */
- if (i == pool->freeList && i->min > first)
- {
- newelem->next = i;
- newelem->prev = i->prev;
- i->prev = newelem;
- pool->freeList = newelem;
+ f->max = newMax;
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
return;
}
+
+ /* we are here because either the list is empty or because all list rande elements have smaller values */
+ f = (FreeElem *) crCalloc(sizeof(FreeElem));
+ f->min = first;
+ f->max = last;
+ RTListAppend(&pool->freeList, &f->Node);
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
}
@@ -235,68 +262,116 @@ static void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint coun
/*
* Mark the given Id as being allocated.
*/
-static void crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id )
+GLboolean crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id )
{
- FreeElem *f;
+ FreeElem *f, *next;
+
+ if (!id)
+ {
+ /* null is a special case, it is always treated as allocated */
+ Assert(!crHashIdPoolIsIdFree(pool, 0));
+ return GL_FALSE;
+ }
+
+// Assert(id != 2);
- f = pool->freeList;
- while (f)
+ RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node)
{
- if (id >= f->min && id <= f->max)
+ if (f->max <= id)
+ continue;
+ if (f->min > id)
{
- /* found the block */
- if (id == f->min)
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
+ return GL_FALSE;
+ }
+
+ /* f->min <= id && f->max > id */
+ if (id > f->min)
+ {
+ if (id + 1 < f->max)
{
- f->min++;
+ FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
+ elem->min = id + 1;
+ elem->max = f->max;
+ RTListNodeInsertAfter(&f->Node, &elem->Node);
}
- else if (id == f->max)
+ f->max = id;
+
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
+ }
+ else
+ {
+ Assert(id == f->min);
+ if (id + 1 < f->max)
{
- f->max--;
+ f->min = id + 1;
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
}
else
{
- /* somewhere in the middle - split the block */
- FreeElem *newelem = (FreeElem *) crCalloc(sizeof(FreeElem));
- newelem->min = id + 1;
- newelem->max = f->max;
- f->max = id - 1;
- newelem->next = f->next;
- if (f->next)
- f->next->prev = newelem;
- newelem->prev = f;
- f->next = newelem;
+ RTListNodeRemove(&f->Node);
+ crFree(f);
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
}
- return;
}
- f = f->next;
+
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
+ return GL_TRUE;
}
/* if we get here, the ID was already allocated - that's OK */
+ CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
+ return GL_FALSE;
}
/*
* Determine if the given id is free. Return GL_TRUE if so.
*/
-static GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id )
+GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id )
{
- FreeElem *i;
+ FreeElem *f;
+ CRASSERT(id <= pool->max);
- /* First find which region it fits in */
- for (i = pool->freeList; i && !(i->min <= id && id <= i->max); i=i->next)
+ RTListForEach(&pool->freeList, f, FreeElem, Node)
{
- /* EMPTY BODY */
- }
-
- if (i)
+ if (f->max <= id)
+ continue;
+ if (f->min > id)
+ return GL_FALSE;
return GL_TRUE;
- else
- return GL_FALSE;
+ }
+ return GL_FALSE;
}
+void crHashIdWalkKeys( CRHashIdPool *pool, CRHashIdWalkKeys walkFunc , void *data)
+{
+ FreeElem *prev = NULL, *f;
+
+ RTListForEach(&pool->freeList, f, FreeElem, Node)
+ {
+ if (prev)
+ {
+ Assert(prev->max < f->min);
+ walkFunc(prev->max+1, f->min - prev->max, data);
+ }
+ else if (f->min > pool->min)
+ {
+ walkFunc(pool->min, f->min - pool->min, data);
+ }
+
+ prev = f;
+ }
+ Assert(prev->max <= pool->max);
-CRHashTable *crAllocHashtable( void )
+ if (prev->max < pool->max)
+ {
+ walkFunc(prev->max+1, pool->max - prev->max, data);
+ }
+}
+
+CRHashTable *crAllocHashtableEx( GLuint min, GLuint max )
{
int i;
CRHashTable *hash = (CRHashTable *) crCalloc( sizeof( CRHashTable )) ;
@@ -305,13 +380,18 @@ CRHashTable *crAllocHashtable( void )
{
hash->buckets[i] = NULL;
}
- hash->idPool = crAllocHashIdPool();
+ hash->idPool = crAllocHashIdPoolEx( min, max );
#ifdef CHROMIUM_THREADSAFE
crInitMutex(&hash->mutex);
#endif
return hash;
}
+CRHashTable *crAllocHashtable( void )
+{
+ return crAllocHashtableEx(CR_HASH_ID_MIN, CR_HASH_ID_MAX);
+}
+
void crFreeHashtable( CRHashTable *hash, CRHashtableCallback deleteFunc )
{
int i;
@@ -366,17 +446,11 @@ void crHashtableUnlock(CRHashTable *h)
#endif
}
-void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
+void crHashtableWalkUnlocked( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
{
int i;
CRHashNode *entry, *next;
- if (!hash)
- return;
-
-#ifdef CHROMIUM_THREADSAFE
- crLockMutex(&hash->mutex);
-#endif
for (i = 0; i < CR_NUM_BUCKETS; i++)
{
entry = hash->buckets[i];
@@ -390,6 +464,17 @@ void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void
entry = next;
}
}
+}
+
+void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
+{
+ if (!hash)
+ return;
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&hash->mutex);
+#endif
+ crHashtableWalkUnlocked(hash, walkFunc , dataPtr2);
#ifdef CHROMIUM_THREADSAFE
crUnlockMutex(&hash->mutex);
#endif
@@ -417,6 +502,30 @@ void crHashtableAdd( CRHashTable *h, unsigned long key, void *data )
#endif
}
+GLboolean crHashtableAllocRegisterKey( CRHashTable *h, GLuint key)
+{
+ GLboolean fAllocated;
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&h->mutex);
+#endif
+ fAllocated = crHashIdPoolAllocId (h->idPool, key);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&h->mutex);
+#endif
+ return fAllocated;
+}
+
+void crHashtableWalkKeys( CRHashTable *h, CRHashIdWalkKeys walkFunc , void *data)
+{
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&h->mutex);
+#endif
+ crHashIdWalkKeys(h->idPool, walkFunc , data);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&h->mutex);
+#endif
+}
+
GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
{
GLuint res;
@@ -426,6 +535,14 @@ GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
crLockMutex(&h->mutex);
#endif
res = crHashIdPoolAllocBlock (h->idPool, range);
+#ifdef DEBUG_misha
+ Assert(res);
+ for (i = 0; i < range; ++i)
+ {
+ void *search = crHashtableSearch( h, res+i );
+ Assert(!search);
+ }
+#endif
#ifdef CHROMIUM_THREADSAFE
crUnlockMutex(&h->mutex);
#endif
@@ -446,23 +563,20 @@ void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback d
break;
beftemp = temp;
}
- if ( !temp ) {
-#ifdef CHROMIUM_THREADSAFE
- crUnlockMutex(&h->mutex);
-#endif
- return; /* not an error */
- }
- if ( beftemp )
- beftemp->next = temp->next;
- else
- h->buckets[index] = temp->next;
- h->num_elements--;
- if (temp->data && deleteFunc) {
- (*deleteFunc)( temp->data );
- }
-
- crFree( temp );
+ if ( temp )
+ {
+ if ( beftemp )
+ beftemp->next = temp->next;
+ else
+ h->buckets[index] = temp->next;
+ h->num_elements--;
+ if (temp->data && deleteFunc) {
+ (*deleteFunc)( temp->data );
+ }
+ crFree( temp );
+ }
+
crHashIdPoolFreeBlock( h->idPool, key, 1 );
#ifdef CHROMIUM_THREADSAFE
crUnlockMutex(&h->mutex);
diff --git a/src/VBox/GuestHost/OpenGL/util/htable.cpp b/src/VBox/GuestHost/OpenGL/util/htable.cpp
new file mode 100644
index 00000000..bb9434c7
--- /dev/null
+++ b/src/VBox/GuestHost/OpenGL/util/htable.cpp
@@ -0,0 +1,195 @@
+/* $Id: htable.cpp $ */
+
+/** @file
+ * uint32_t handle to void simple table impl
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#include <iprt/cdefs.h>
+#include <iprt/asm.h>
+#include "cr_spu.h"
+#include "cr_vreg.h"
+
+#include "cr_htable.h"
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_net.h"
+#include "cr_rand.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+#include <iprt/mem.h>
+#include <iprt/err.h>
+
+VBOXHTABLEDECL(int) CrHTableCreate(PCRHTABLE pTbl, uint32_t cSize)
+{
+ memset(pTbl, 0, sizeof (*pTbl));
+ if (!cSize)
+ return VINF_SUCCESS;
+ pTbl->paData = (void**)RTMemAllocZ(sizeof (pTbl->paData[0]) * cSize);
+ if (pTbl->paData)
+ {
+ pTbl->cSize = cSize;
+ return VINF_SUCCESS;
+ }
+ WARN(("RTMemAllocZ failed!"));
+ return VERR_NO_MEMORY;
+}
+
+VBOXHTABLEDECL(void) CrHTableDestroy(PCRHTABLE pTbl)
+{
+ if (!pTbl->paData)
+ return;
+
+ RTMemFree(pTbl->paData);
+}
+
+int crHTableRealloc(PCRHTABLE pTbl, uint32_t cNewSize)
+{
+ Assert(cNewSize > pTbl->cSize);
+ if (cNewSize > pTbl->cSize)
+ {
+ void **pvNewData = (void**)RTMemAllocZ(sizeof (pTbl->paData[0]) * cNewSize);
+ if (!pvNewData)
+ {
+ WARN(("RTMemAllocZ failed for size (%d)", (int)(sizeof (pTbl->paData[0]) * cNewSize)));
+ return VERR_NO_MEMORY;
+ }
+ memcpy(pvNewData, pTbl->paData, sizeof (pTbl->paData[0]) * pTbl->cSize);
+ RTMemFree(pTbl->paData);
+ pTbl->iNext2Search = pTbl->cSize;
+ pTbl->cSize = cNewSize;
+ pTbl->paData = pvNewData;
+ return VINF_SUCCESS;
+ }
+ else if (cNewSize >= pTbl->cData)
+ {
+ WARN(("not implemented"));
+ return VERR_NOT_IMPLEMENTED;
+ }
+ WARN(("invalid parameter"));
+ return VERR_INVALID_PARAMETER;
+
+}
+
+VBOXHTABLEDECL(int) CrHTableRealloc(PCRHTABLE pTbl, uint32_t cNewSize)
+{
+ return crHTableRealloc(pTbl, cNewSize);
+}
+
+VBOXHTABLEDECL(void) CrHTableEmpty(PCRHTABLE pTbl)
+{
+ pTbl->cData = 0;
+ pTbl->iNext2Search = 0;
+ if (pTbl->cSize)
+ memset(pTbl->paData, 0, sizeof (pTbl->paData[0]) * pTbl->cSize);
+}
+
+static void* crHTablePutToSlot(PCRHTABLE pTbl, uint32_t iSlot, void* pvData)
+{
+ Assert(pvData);
+ void* pvOld = pTbl->paData[iSlot];
+ pTbl->paData[iSlot] = pvData;
+ if (!pvOld)
+ ++pTbl->cData;
+ Assert(pTbl->cData <= pTbl->cSize);
+ return pvOld;
+}
+
+VBOXHTABLEDECL(int) CrHTablePutToSlot(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle, void* pvData)
+{
+ if (!pvData)
+ {
+ AssertMsgFailed(("pvData is NULL\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+ uint32_t iIndex = crHTableHandle2Index(hHandle);
+ if (iIndex >= pTbl->cSize)
+ {
+ int rc = crHTableRealloc(pTbl, iIndex + RT_MAX(10, pTbl->cSize/4));
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crHTableRealloc failed rc %d", rc));
+ return CRHTABLE_HANDLE_INVALID;
+ }
+ }
+
+ crHTablePutToSlot(pTbl, iIndex, pvData);
+
+ return VINF_SUCCESS;
+}
+
+VBOXHTABLEDECL(CRHTABLE_HANDLE) CrHTablePut(PCRHTABLE pTbl, void* pvData)
+{
+ if (!pvData)
+ {
+ AssertMsgFailed(("pvData is NULL\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (pTbl->cSize == pTbl->cData)
+ {
+ int rc = crHTableRealloc(pTbl, pTbl->cSize + RT_MAX(10, pTbl->cSize/4));
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crHTableRealloc failed rc %d", rc));
+ return CRHTABLE_HANDLE_INVALID;
+ }
+ }
+ for (uint32_t i = pTbl->iNext2Search; ; ++i, i %= pTbl->cSize)
+ {
+ Assert(i < pTbl->cSize);
+ if (!pTbl->paData[i])
+ {
+ void *pvOld = crHTablePutToSlot(pTbl, i, pvData);
+ Assert(!pvOld);
+ pTbl->iNext2Search = i+1;
+ pTbl->iNext2Search %= pTbl->cSize;
+ return crHTableIndex2Handle(i);
+ }
+ }
+ WARN(("should not be here"));
+ return CRHTABLE_HANDLE_INVALID;
+}
+
+VBOXHTABLEDECL(void*) CrHTableRemove(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle)
+{
+ uint32_t iIndex = crHTableHandle2Index(hHandle);
+ Assert(iIndex < pTbl->cSize);
+ if (iIndex < pTbl->cSize)
+ {
+ void* pvData = pTbl->paData[iIndex];
+ if (pvData)
+ {
+ pTbl->paData[iIndex] = NULL;
+ --pTbl->cData;
+ Assert(pTbl->cData <= pTbl->cSize);
+ pTbl->iNext2Search = iIndex;
+ }
+ return pvData;
+ }
+ WARN(("invalid handle supplied %d", hHandle));
+ return NULL;
+}
+
+VBOXHTABLEDECL(void*) CrHTableGet(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle)
+{
+ uint32_t iIndex = crHTableHandle2Index(hHandle);
+ if (iIndex < pTbl->cSize)
+ return pTbl->paData[iIndex];
+ LOG(("invalid handle supplied %d", hHandle));
+ return NULL;
+}
diff --git a/src/VBox/GuestHost/OpenGL/util/net.c b/src/VBox/GuestHost/OpenGL/util/net.c
index cc2966f9..72d9f7ae 100644
--- a/src/VBox/GuestHost/OpenGL/util/net.c
+++ b/src/VBox/GuestHost/OpenGL/util/net.c
@@ -993,7 +993,7 @@ crNetRecvFlowControl( CRConnection *conn, CRMessageFlowControl *msg,
conn->InstantReclaim( conn, (CRMessage *) msg );
}
-
+#ifdef IN_GUEST
/**
* Called by the main receive function when we get a CR_MESSAGE_WRITEBACK
* message. Writeback is used to implement glGet*() functions.
@@ -1026,7 +1026,7 @@ crNetRecvReadback( CRMessageReadback *rb, unsigned int len )
(*writeback)--;
crMemcpy( dest_ptr, ((char *)rb) + sizeof(*rb), payload_len );
}
-
+#endif
/**
* This is used by the SPUs that do packing (such as Pack, Tilesort and
@@ -1104,13 +1104,21 @@ crNetDefaultRecv( CRConnection *conn, CRMessage *msg, unsigned int len )
}
break;
case CR_MESSAGE_READ_PIXELS:
- crError( "Can't handle read pixels" );
+ WARN(( "Can't handle read pixels" ));
return;
case CR_MESSAGE_WRITEBACK:
+#ifdef IN_GUEST
crNetRecvWriteback( &(pRealMsg->writeback) );
+#else
+ WARN(("CR_MESSAGE_WRITEBACK not expected\n"));
+#endif
return;
case CR_MESSAGE_READBACK:
+#ifdef IN_GUEST
crNetRecvReadback( &(pRealMsg->readback), len );
+#else
+ WARN(("CR_MESSAGE_READBACK not expected\n"));
+#endif
return;
case CR_MESSAGE_CRUT:
/* nothing */
@@ -1128,10 +1136,10 @@ crNetDefaultRecv( CRConnection *conn, CRMessage *msg, unsigned int len )
{
char string[128];
crBytesToString( string, sizeof(string), msg, len );
- crError("crNetDefaultRecv: received a bad message: type=%d buf=[%s]\n"
+ WARN(("crNetDefaultRecv: received a bad message: type=%d buf=[%s]\n"
"Did you add a new message type and forget to tell "
"crNetDefaultRecv() about it?\n",
- msg->header.type, string );
+ msg->header.type, string ));
}
}
diff --git a/src/VBox/GuestHost/OpenGL/util/pixel.c b/src/VBox/GuestHost/OpenGL/util/pixel.c
index c153dee2..5bea3e1f 100644
--- a/src/VBox/GuestHost/OpenGL/util/pixel.c
+++ b/src/VBox/GuestHost/OpenGL/util/pixel.c
@@ -11,6 +11,8 @@
#include <stdio.h>
#include <math.h>
+#include <iprt/string.h>
+
#if defined(WINDOWS)
# include <float.h>
# define isnan(x) _isnan(x)
@@ -1691,7 +1693,9 @@ void crPixelCopy3D( GLsizei width, GLsizei height, GLsizei depth,
/*@todo this should be implemented properly*/
+#ifndef DEBUG_misha
crWarning( "crPixelCopy3D: simply crMemcpy'ing from srcPtr to dstPtr" );
+#endif
if (dstFormat != srcFormat)
crWarning( "crPixelCopy3D: formats don't match!" );
if (dstType != srcType)
@@ -1841,3 +1845,19 @@ void crDumpNamedTGA(const char* fname, GLint w, GLint h, GLvoid *data)
fclose(out);
}
+
+void crDumpNamedTGAV(GLint w, GLint h, GLvoid *data, const char* fname, va_list va)
+{
+ char szName[4096];
+ RTStrPrintfV(szName, sizeof(szName), fname, va);
+ crDumpNamedTGA(szName, w, h, data);
+}
+
+void crDumpNamedTGAF(GLint w, GLint h, GLvoid *data, const char* fname, ...)
+{
+ va_list va;
+ int rc;
+ va_start(va, fname);
+ crDumpNamedTGAV(w, h, data, fname, va);
+ va_end(va);
+}
diff --git a/src/VBox/GuestHost/OpenGL/util/string.c b/src/VBox/GuestHost/OpenGL/util/string.c
index 75df10bc..0d7fff0b 100644
--- a/src/VBox/GuestHost/OpenGL/util/string.c
+++ b/src/VBox/GuestHost/OpenGL/util/string.c
@@ -6,6 +6,7 @@
#include "cr_mem.h"
#include "cr_string.h"
+#include "cr_error.h"
#include <string.h>
#include <stdio.h>
@@ -408,3 +409,125 @@ int crIsDigit(char c)
{
return c >= '0' && c <= '9';
}
+
+
+static int crStrParseGlSubver(const char * ver, const char ** pNext, bool bSpacePrefixAllowed)
+{
+ const char * initVer = ver;
+ int val = 0;
+
+ for(;;++ver)
+ {
+ if(*ver >= '0' && *ver <= '9')
+ {
+ if(!val)
+ {
+ if(*ver == '0')
+ continue;
+ }
+ else
+ {
+ val *= 10;
+ }
+ val += *ver - '0';
+ }
+ else if(*ver == '.')
+ {
+ *pNext = ver+1;
+ break;
+ }
+ else if(*ver == '\0')
+ {
+ *pNext = NULL;
+ break;
+ }
+ else if(*ver == ' ' || *ver == '\t' || *ver == 0x0d || *ver == 0x0a)
+ {
+ if(bSpacePrefixAllowed)
+ {
+ if(!val)
+ {
+ continue;
+ }
+ }
+
+ /* treat this as the end of version string */
+ *pNext = NULL;
+ break;
+ }
+ else
+ {
+ crWarning("error parsing version %s", initVer);
+ val = -1;
+ break;
+ }
+ }
+
+ return val;
+}
+
+int crStrParseGlVersion(const char * ver)
+{
+ const char * initVer = ver;
+ int tmp;
+ int iVer = crStrParseGlSubver(ver, &ver, true);
+ if(iVer <= 0)
+ {
+ crWarning("parsing major version returned %d, '%s'", iVer, initVer);
+ return iVer;
+ }
+
+ if (iVer > CR_GLVERSION_MAX_MAJOR)
+ {
+ crWarning("major version %d is bigger than the max supported %#x, this is somewhat not expected, failing", iVer, CR_GLVERSION_MAX_MAJOR);
+ return -1;
+ }
+
+ iVer <<= CR_GLVERSION_OFFSET_MAJOR;
+ if(!ver)
+ {
+ crDebug("no minor version supplied");
+ goto done;
+ }
+
+ tmp = crStrParseGlSubver(ver, &ver, false);
+ if (tmp < 0)
+ {
+ crWarning("parsing minor version failed, '%s'", initVer);
+ return -1;
+ }
+
+ if (tmp > CR_GLVERSION_MAX_MINOR)
+ {
+ crWarning("minor version %d is bigger than the max supported %#x, this is somewhat not expected, failing", iVer, CR_GLVERSION_MAX_MAJOR);
+ return -1;
+ }
+
+ iVer |= tmp << CR_GLVERSION_OFFSET_MINOR;
+
+ if (!ver)
+ {
+ crDebug("no build version supplied");
+ goto done;
+ }
+
+ tmp = crStrParseGlSubver(ver, &ver, false);
+ if (tmp < 0)
+ {
+ crWarning("parsing build version failed, '%s', using 0", initVer);
+ tmp = 0;
+ }
+
+ if (tmp > CR_GLVERSION_MAX_BUILD)
+ {
+ crWarning("build version %d is bigger than the max supported, using max supported val %#x", tmp, CR_GLVERSION_MAX_BUILD);
+ tmp = CR_GLVERSION_MAX_MAJOR;
+ }
+
+ iVer |= tmp << CR_GLVERSION_OFFSET_BUILD;
+
+done:
+ crDebug("returning version %#x for string '%s'", iVer, initVer);
+
+ return iVer;
+}
diff --git a/src/VBox/GuestHost/OpenGL/util/util.def b/src/VBox/GuestHost/OpenGL/util/util.def
index d4b6cd64..4fa97058 100644
--- a/src/VBox/GuestHost/OpenGL/util/util.def
+++ b/src/VBox/GuestHost/OpenGL/util/util.def
@@ -82,7 +82,10 @@ crHashtableSearch
crHashtableReplace
crHashtableNumElements
crHashtableWalk
+crHashtableWalkUnlocked
+crHashtableAllocRegisterKey
crAllocHashtable
+crAllocHashtableEx
crFreeHashtable
crHashtableGetDataKey
crDetermineEndianness
@@ -145,7 +148,6 @@ crGetCurrentDir
crHashtableAllocKeys
crHashtableDeleteBlock
crHashtableIsKeyUsed
-crHashtableWalk
crMatrixInit
crMatrixInitFromString
crMatrixInitFromFloats
diff --git a/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c b/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c
index fbf35304..d5d057d9 100644
--- a/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c
+++ b/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -195,9 +195,6 @@ typedef enum {
CR_VBOXHGCM_USERALLOCATED,
CR_VBOXHGCM_MEMORY,
CR_VBOXHGCM_MEMORY_BIG
-#ifdef RT_OS_WINDOWS
- ,CR_VBOXHGCM_DDRAW_SURFACE
-#endif
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
,CR_VBOXHGCM_UHGSMI_BUFFER
#endif
@@ -220,9 +217,6 @@ typedef struct CRVBOXHGCMBUFFER {
PVBOXUHGSMI_BUFFER pBuffer;
#endif
};
-#ifdef RT_OS_WINDOWS
- LPDIRECTDRAWSURFACE pDDS;
-#endif
} CRVBOXHGCMBUFFER;
#ifndef RT_OS_WINDOWS
@@ -705,92 +699,6 @@ static void *_crVBoxHGCMAlloc(CRConnection *conn)
(void *) g_crvboxhgcm.bufpool,
(unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size);
-#if defined(IN_GUEST) && defined(RT_OS_WINDOWS)
- /* Try to start DDRAW on guest side */
- if (!g_crvboxhgcm.pDirectDraw && 0)
- {
- HRESULT hr;
-
- hr = DirectDrawCreate(NULL, &g_crvboxhgcm.pDirectDraw, NULL);
- if (hr != DD_OK)
- {
- crWarning("Failed to create DirectDraw interface (%x)\n", hr);
- g_crvboxhgcm.pDirectDraw = NULL;
- }
- else
- {
- hr = IDirectDraw_SetCooperativeLevel(g_crvboxhgcm.pDirectDraw, NULL, DDSCL_NORMAL);
- if (hr != DD_OK)
- {
- crWarning("Failed to SetCooperativeLevel (%x)\n", hr);
- IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
- g_crvboxhgcm.pDirectDraw = NULL;
- }
- crDebug("Created DirectDraw and set CooperativeLevel successfully\n");
- }
- }
-
- /* Try to allocate buffer via DDRAW */
- if (g_crvboxhgcm.pDirectDraw)
- {
- DDSURFACEDESC ddsd;
- HRESULT hr;
- LPDIRECTDRAWSURFACE lpDDS;
-
- memset(&ddsd, 0, sizeof(ddsd));
- ddsd.dwSize = sizeof(ddsd);
-
- /* @todo DDSCAPS_VIDEOMEMORY ain't working for some reason
- * also, it would be better to request dwLinearSize but it fails too
- * ddsd.dwLinearSize = sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size;
- */
-
- ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
- ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
- /* use 1 byte per pixel format */
- ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
- ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
- ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
- ddsd.ddpfPixelFormat.dwRBitMask = 0xFF;
- ddsd.ddpfPixelFormat.dwGBitMask = 0;
- ddsd.ddpfPixelFormat.dwBBitMask = 0;
- /* request given buffer size, rounded to 1k */
- ddsd.dwWidth = 1024;
- ddsd.dwHeight = (sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size + ddsd.dwWidth-1)/ddsd.dwWidth;
-
- hr = IDirectDraw_CreateSurface(g_crvboxhgcm.pDirectDraw, &ddsd, &lpDDS, NULL);
- if (hr != DD_OK)
- {
- crWarning("Failed to create DirectDraw surface (%x)\n", hr);
- }
- else
- {
- crDebug("Created DirectDraw surface (%x)\n", lpDDS);
-
- hr = IDirectDrawSurface_Lock(lpDDS, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL);
- if (hr != DD_OK)
- {
- crWarning("Failed to lock DirectDraw surface (%x)\n", hr);
- IDirectDrawSurface_Release(lpDDS);
- }
- else
- {
- uint32_t cbLocked;
- cbLocked = (ddsd.dwFlags & DDSD_LINEARSIZE) ? ddsd.dwLinearSize : ddsd.lPitch*ddsd.dwHeight;
-
- crDebug("Locked %d bytes DirectDraw surface\n", cbLocked);
-
- buf = (CRVBOXHGCMBUFFER *) ddsd.lpSurface;
- CRASSERT(buf);
- buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
- buf->kind = CR_VBOXHGCM_DDRAW_SURFACE;
- buf->allocated = cbLocked;
- buf->pDDS = lpDDS;
- }
- }
- }
-#endif
-
/* We're either on host side, or we failed to allocate DDRAW buffer */
if (!buf)
{
@@ -800,9 +708,6 @@ static void *_crVBoxHGCMAlloc(CRConnection *conn)
buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
buf->kind = CR_VBOXHGCM_MEMORY;
buf->allocated = conn->buffer_size;
-#ifdef RT_OS_WINDOWS
- buf->pDDS = NULL;
-#endif
}
}
@@ -944,18 +849,9 @@ crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len,
parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
parms.hdr.cParms = SHCRGL_CPARMS_WRITE_READ;
- //if (bufferKind != CR_VBOXHGCM_DDRAW_SURFACE)
- {
- parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
- parms.pBuffer.u.Pointer.size = len;
- parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
- }
- /*else ///@todo it fails badly, have to check why. bird: This fails because buf isn't a physical address?
- {
- parms.pBuffer.type = VMMDevHGCMParmType_PhysAddr;
- parms.pBuffer.u.Pointer.size = len;
- parms.pBuffer.u.Pointer.u.physAddr = (uintptr_t) buf;
- }*/
+ parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
+ parms.pBuffer.u.Pointer.size = len;
+ parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
CRASSERT(!conn->pBuffer); //make sure there's no data to process
parms.pWriteback.type = VMMDevHGCMParmType_LinAddr_Out;
@@ -1202,9 +1098,6 @@ static void _crVBoxHGCMFree(CRConnection *conn, void *buf)
switch (hgcm_buffer->kind)
{
case CR_VBOXHGCM_MEMORY:
-#ifdef RT_OS_WINDOWS
- case CR_VBOXHGCM_DDRAW_SURFACE:
-#endif
#ifdef CHROMIUM_THREADSAFE
crLockMutex(&g_crvboxhgcm.mutex);
#endif
@@ -1283,7 +1176,7 @@ static void _crVBoxHGCMReceiveMessage(CRConnection *conn)
else
{
/* we should NEVER have redir_ptr disabled with HGSMI command now */
- CRASSERT(!conn->CmdData.pCmd);
+ CRASSERT(!conn->CmdData.pvCmd);
if ( len <= conn->buffer_size )
{
/* put in pre-allocated buffer */
@@ -1298,9 +1191,6 @@ static void _crVBoxHGCMReceiveMessage(CRConnection *conn)
hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
-# ifdef RT_OS_WINDOWS
- hgcm_buffer->pDDS = NULL;
-# endif
}
hgcm_buffer->len = len;
@@ -1998,25 +1888,30 @@ _crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void
else if (VERR_BUFFER_OVERFLOW == rc)
{
VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
- PVBOXUHGSMI_BUFFER pOldBuf = pClient->pHGBuffer;
+ PVBOXUHGSMI_BUFFER pNewBuf;
CRASSERT(!pClient->pvHGBuffer);
CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
- rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback), Flags, &pClient->pHGBuffer);
+ rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback), Flags, &pNewBuf);
if (RT_SUCCESS(rc))
{
- rc = pOldBuf->pfnDestroy(pOldBuf);
+ rc = pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
CRASSERT(RT_SUCCESS(rc));
+ pClient->pHGBuffer = pNewBuf;
+
_crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
}
else
{
crWarning("_crVBoxHGSMIWriteReadExact: pfnBufferCreate(%d) failed!", CRVBOXHGSMI_PAGE_ALIGN(cbWriteback));
- crFree(conn->pHostBuffer);
- conn->cbHostBufferAllocated = cbWriteback;
- conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
+ if (conn->cbHostBufferAllocated < cbWriteback)
+ {
+ crFree(conn->pHostBuffer);
+ conn->cbHostBufferAllocated = cbWriteback;
+ conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
+ }
crVBoxHGCMReadExact(conn, NULL, cbWriteback);
}
}
@@ -2415,9 +2310,6 @@ void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned
/* Callback function used to free buffer pool entries */
void crVBoxHGCMBufferFree(void *data)
{
-#ifdef RT_OS_WINDOWS
- LPDIRECTDRAWSURFACE lpDDS;
-#endif
CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
@@ -2427,15 +2319,6 @@ void crVBoxHGCMBufferFree(void *data)
case CR_VBOXHGCM_MEMORY:
crFree( hgcm_buffer );
break;
-#ifdef RT_OS_WINDOWS
- case CR_VBOXHGCM_DDRAW_SURFACE:
- lpDDS = hgcm_buffer->pDDS;
- CRASSERT(lpDDS);
- IDirectDrawSurface_Unlock(lpDDS, NULL);
- IDirectDrawSurface_Release(lpDDS);
- crDebug("DDraw surface freed (%x)\n", lpDDS);
- break;
-#endif
case CR_VBOXHGCM_MEMORY_BIG:
crFree( hgcm_buffer );
break;
diff --git a/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c b/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c
index 60d5ce21..3da3496a 100644
--- a/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c
+++ b/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/GuestHost/OpenGL/util/vreg.cpp b/src/VBox/GuestHost/OpenGL/util/vreg.cpp
new file mode 100644
index 00000000..e2cea3b3
--- /dev/null
+++ b/src/VBox/GuestHost/OpenGL/util/vreg.cpp
@@ -0,0 +1,1692 @@
+/* $Id: vreg.cpp $ */
+
+/** @file
+ * Visible Regions processing API implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#include <cr_vreg.h>
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+
+#include <cr_error.h>
+
+#ifdef DEBUG_misha
+# define VBOXVDBG_VR_LAL_DISABLE
+#endif
+
+#ifndef IN_RING0
+#include <iprt/memcache.h>
+#ifndef VBOXVDBG_VR_LAL_DISABLE
+static RTMEMCACHE g_VBoxVrLookasideList;
+#define vboxVrRegLaAlloc(_c) RTMemCacheAlloc((_c))
+#define vboxVrRegLaFree(_c, _e) RTMemCacheFree((_c), (_e))
+DECLINLINE(int) vboxVrLaCreate(RTMEMCACHE *pCache, size_t cbElement)
+{
+ int rc = RTMemCacheCreate(pCache, cbElement,
+ 0, /* size_t cbAlignment */
+ UINT32_MAX, /* uint32_t cMaxObjects */
+ NULL, /* PFNMEMCACHECTOR pfnCtor*/
+ NULL, /* PFNMEMCACHEDTOR pfnDtor*/
+ NULL, /* void *pvUser*/
+ 0 /* uint32_t fFlags*/
+ );
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RTMemCacheCreate failed rc %d", rc));
+ return rc;
+ }
+ return VINF_SUCCESS;
+}
+#define vboxVrLaDestroy(_c) RTMemCacheDestroy((_c))
+#endif
+#else
+# ifdef RT_OS_WINDOWS
+# ifdef PAGE_SIZE
+# undef PAGE_SIZE
+# endif
+# ifdef PAGE_SHIFT
+# undef PAGE_SHIFT
+# endif
+# define VBOX_WITH_WORKAROUND_MISSING_PACK
+# if (_MSC_VER >= 1400) && !defined(VBOX_WITH_PATCHED_DDK)
+# define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap
+# define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap
+# define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap
+# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap
+# define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap
+# define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap
+# define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap
+# define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap
+# pragma warning(disable : 4163)
+# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK
+# pragma warning(disable : 4103)
+# endif
+# include <ntddk.h>
+# pragma warning(default : 4163)
+# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK
+# pragma pack()
+# pragma warning(default : 4103)
+# endif
+# undef _InterlockedExchange
+# undef _InterlockedExchangeAdd
+# undef _InterlockedCompareExchange
+# undef _InterlockedAddLargeStatistic
+# undef _interlockedbittestandset
+# undef _interlockedbittestandreset
+# undef _interlockedbittestandset64
+# undef _interlockedbittestandreset64
+# else
+# include <ntddk.h>
+# endif
+#ifndef VBOXVDBG_VR_LAL_DISABLE
+static LOOKASIDE_LIST_EX g_VBoxVrLookasideList;
+#define vboxVrRegLaAlloc(_c) ExAllocateFromLookasideListEx(&(_c))
+#define vboxVrRegLaFree(_c, _e) ExFreeToLookasideListEx(&(_c), (_e))
+#define VBOXWDDMVR_MEMTAG 'vDBV'
+DECLINLINE(int) vboxVrLaCreate(LOOKASIDE_LIST_EX *pCache, size_t cbElement)
+{
+ NTSTATUS Status = ExInitializeLookasideListEx(pCache,
+ NULL, /* PALLOCATE_FUNCTION_EX Allocate */
+ NULL, /* PFREE_FUNCTION_EX Free */
+ NonPagedPool,
+ 0, /* ULONG Flags */
+ cbElement,
+ VBOXWDDMVR_MEMTAG,
+ 0 /* USHORT Depth - reserved, must be null */
+ );
+ if (!NT_SUCCESS(Status))
+ {
+ WARN(("ExInitializeLookasideListEx failed, Status (0x%x)", Status));
+ return VERR_GENERAL_FAILURE;
+ }
+
+ return VINF_SUCCESS;
+}
+#define vboxVrLaDestroy(_c) ExDeleteLookasideListEx(&(_c))
+#endif
+# else
+# error "port me!"
+# endif
+#endif
+
+static volatile int32_t g_cVBoxVrInits = 0;
+
+static PVBOXVR_REG vboxVrRegCreate()
+{
+#ifndef VBOXVDBG_VR_LAL_DISABLE
+ PVBOXVR_REG pReg = (PVBOXVR_REG)vboxVrRegLaAlloc(g_VBoxVrLookasideList);
+ if (!pReg)
+ {
+ WARN(("ExAllocateFromLookasideListEx failed!"));
+ }
+ return pReg;
+#else
+ return (PVBOXVR_REG)RTMemAlloc(sizeof (VBOXVR_REG));
+#endif
+}
+
+static void vboxVrRegTerm(PVBOXVR_REG pReg)
+{
+#ifndef VBOXVDBG_VR_LAL_DISABLE
+ vboxVrRegLaFree(g_VBoxVrLookasideList, pReg);
+#else
+ RTMemFree(pReg);
+#endif
+}
+
+VBOXVREGDECL(void) VBoxVrListClear(PVBOXVR_LIST pList)
+{
+ PVBOXVR_REG pReg, pRegNext;
+
+ RTListForEachSafe(&pList->ListHead, pReg, pRegNext, VBOXVR_REG, ListEntry)
+ {
+ vboxVrRegTerm(pReg);
+ }
+ VBoxVrListInit(pList);
+}
+
+/* moves list data to pDstList and empties the pList */
+VBOXVREGDECL(void) VBoxVrListMoveTo(PVBOXVR_LIST pList, PVBOXVR_LIST pDstList)
+{
+ *pDstList = *pList;
+ pDstList->ListHead.pNext->pPrev = &pDstList->ListHead;
+ pDstList->ListHead.pPrev->pNext = &pDstList->ListHead;
+ VBoxVrListInit(pList);
+}
+
+#define VBOXVR_MEMTAG 'vDBV'
+
+VBOXVREGDECL(int) VBoxVrInit()
+{
+ int32_t cNewRefs = ASMAtomicIncS32(&g_cVBoxVrInits);
+ Assert(cNewRefs >= 1);
+ Assert(cNewRefs == 1); /* <- debugging */
+ if (cNewRefs > 1)
+ return VINF_SUCCESS;
+
+#ifndef VBOXVDBG_VR_LAL_DISABLE
+ int rc = vboxVrLaCreate(&g_VBoxVrLookasideList, sizeof (VBOXVR_REG));
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("ExInitializeLookasideListEx failed, rc (%d)", rc));
+ return rc;
+ }
+#endif
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(void) VBoxVrTerm()
+{
+ int32_t cNewRefs = ASMAtomicDecS32(&g_cVBoxVrInits);
+ Assert(cNewRefs >= 0);
+ if (cNewRefs > 0)
+ return;
+
+#ifndef VBOXVDBG_VR_LAL_DISABLE
+ vboxVrLaDestroy(g_VBoxVrLookasideList);
+#endif
+}
+
+typedef DECLCALLBACK(int) FNVBOXVR_CB_COMPARATOR(const VBOXVR_REG *pReg1, const VBOXVR_REG *pReg2);
+typedef FNVBOXVR_CB_COMPARATOR *PFNVBOXVR_CB_COMPARATOR;
+
+static DECLCALLBACK(int) vboxVrRegNonintersectedComparator(const RTRECT* pRect1, const RTRECT* pRect2)
+{
+ Assert(!VBoxRectIsIntersect(pRect1, pRect2));
+ if (pRect1->yTop != pRect2->yTop)
+ return pRect1->yTop - pRect2->yTop;
+ return pRect1->xLeft - pRect2->xLeft;
+}
+
+#ifdef DEBUG_misha
+static void vboxVrDbgListDoVerify(PVBOXVR_LIST pList)
+{
+ PVBOXVR_REG pReg1, pReg2;
+ RTListForEach(&pList->ListHead, pReg1, VBOXVR_REG, ListEntry)
+ {
+ Assert(!VBoxRectIsZero(&pReg1->Rect));
+ for (RTLISTNODE *pEntry2 = pReg1->ListEntry.pNext; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->pNext)
+ {
+ pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
+ Assert(vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0);
+ }
+ }
+}
+
+#define vboxVrDbgListVerify vboxVrDbgListDoVerify
+#else
+#define vboxVrDbgListVerify(_p) do {} while (0)
+#endif
+
+static int vboxVrListUniteIntersection(PVBOXVR_LIST pList, PVBOXVR_LIST pIntersection);
+
+#define VBOXVR_INVALID_COORD (~0U)
+
+DECLINLINE(void) vboxVrListRegAdd(PVBOXVR_LIST pList, PVBOXVR_REG pReg, PRTLISTNODE pPlace, bool fAfter)
+{
+ if (fAfter)
+ RTListPrepend(pPlace, &pReg->ListEntry);
+ else
+ RTListAppend(pPlace, &pReg->ListEntry);
+ ++pList->cEntries;
+ vboxVrDbgListVerify(pList);
+}
+
+DECLINLINE(void) vboxVrListRegRemove(PVBOXVR_LIST pList, PVBOXVR_REG pReg)
+{
+ RTListNodeRemove(&pReg->ListEntry);
+ --pList->cEntries;
+ vboxVrDbgListVerify(pList);
+}
+
+static void vboxVrListRegAddOrder(PVBOXVR_LIST pList, PRTLISTNODE pMemberEntry, PVBOXVR_REG pReg)
+{
+ do
+ {
+ if (pMemberEntry != &pList->ListHead)
+ {
+ PVBOXVR_REG pMemberReg = PVBOXVR_REG_FROM_ENTRY(pMemberEntry);
+ if (vboxVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0)
+ {
+ pMemberEntry = pMemberEntry->pNext;
+ continue;
+ }
+ }
+ vboxVrListRegAdd(pList, pReg, pMemberEntry, false);
+ break;
+ } while (1);
+}
+
+static void vboxVrListAddNonintersected(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
+{
+ PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
+
+ for (PRTLISTNODE pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.pNext)
+ {
+ PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
+ do {
+ if (pEntry1 != &pList1->ListHead)
+ {
+ PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+ if (vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0)
+ {
+ pEntry1 = pEntry1->pNext;
+ continue;
+ }
+ }
+ vboxVrListRegRemove(pList2, pReg2);
+ vboxVrListRegAdd(pList1, pReg2, pEntry1, false);
+ break;
+ } while (1);
+ }
+
+ Assert(VBoxVrListIsEmpty(pList2));
+}
+
+static int vboxVrListRegIntersectSubstNoJoin(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2)
+{
+ uint32_t topLim = VBOXVR_INVALID_COORD;
+ uint32_t bottomLim = VBOXVR_INVALID_COORD;
+ RTLISTNODE List;
+ PVBOXVR_REG pBottomReg = NULL;
+#ifdef DEBUG_misha
+ RTRECT tmpRect = pReg1->Rect;
+ vboxVrDbgListVerify(pList1);
+#endif
+ Assert(!VBoxRectIsZero(pRect2));
+
+ RTListInit(&List);
+
+ Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
+
+ if (pReg1->Rect.yTop < pRect2->yTop)
+ {
+ Assert(pRect2->yTop < pReg1->Rect.yBottom);
+ PVBOXVR_REG pRegResult = vboxVrRegCreate();
+ pRegResult->Rect.yTop = pReg1->Rect.yTop;
+ pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
+ pRegResult->Rect.yBottom = pRect2->yTop;
+ pRegResult->Rect.xRight = pReg1->Rect.xRight;
+ topLim = pRect2->yTop;
+ RTListAppend(&List, &pRegResult->ListEntry);
+ }
+
+ if (pReg1->Rect.yBottom > pRect2->yBottom)
+ {
+ Assert(pRect2->yBottom > pReg1->Rect.yTop);
+ PVBOXVR_REG pRegResult = vboxVrRegCreate();
+ pRegResult->Rect.yTop = pRect2->yBottom;
+ pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
+ pRegResult->Rect.yBottom = pReg1->Rect.yBottom;
+ pRegResult->Rect.xRight = pReg1->Rect.xRight;
+ bottomLim = pRect2->yBottom;
+ pBottomReg = pRegResult;
+ }
+
+ if (pReg1->Rect.xLeft < pRect2->xLeft)
+ {
+ Assert(pRect2->xLeft < pReg1->Rect.xRight);
+ PVBOXVR_REG pRegResult = vboxVrRegCreate();
+ pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
+ pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
+ pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
+ pRegResult->Rect.xRight = pRect2->xLeft;
+ RTListAppend(&List, &pRegResult->ListEntry);
+ }
+
+ if (pReg1->Rect.xRight > pRect2->xRight)
+ {
+ Assert(pRect2->xRight > pReg1->Rect.xLeft);
+ PVBOXVR_REG pRegResult = vboxVrRegCreate();
+ pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
+ pRegResult->Rect.xLeft = pRect2->xRight;
+ pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
+ pRegResult->Rect.xRight = pReg1->Rect.xRight;
+ RTListAppend(&List, &pRegResult->ListEntry);
+ }
+
+ if (pBottomReg)
+ RTListAppend(&List, &pBottomReg->ListEntry);
+
+ PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
+ vboxVrListRegRemove(pList1, pReg1);
+ vboxVrRegTerm(pReg1);
+
+ if (RTListIsEmpty(&List))
+ return VINF_SUCCESS; /* the region is covered by the pRect2 */
+
+ PRTLISTNODE pEntry = List.pNext, pNext;
+ for (; pEntry != &List; pEntry = pNext)
+ {
+ pNext = pEntry->pNext;
+ PVBOXVR_REG pReg = PVBOXVR_REG_FROM_ENTRY(pEntry);
+
+ vboxVrListRegAddOrder(pList1, pMemberEntry, pReg);
+ pMemberEntry = pEntry->pNext; /* the following elements should go after the given pEntry since they are ordered already */
+ }
+ return VINF_SUCCESS;
+}
+
+/* @returns Entry to be used for continuing the rectangles iterations being made currently on the callback call.
+ * ListHead is returned to break the current iteration
+ * @param ppNext specifies next reg entry to be used for iteration. the default is pReg1->ListEntry.pNext */
+typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_INTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2, void *pvContext, PRTLISTNODE *ppNext);
+typedef FNVBOXVR_CB_INTERSECTED_VISITOR *PFNVBOXVR_CB_INTERSECTED_VISITOR;
+
+static void vboxVrListVisitIntersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
+{
+ PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
+ PRTLISTNODE pNext1;
+ uint32_t iFirst2 = 0;
+
+ for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
+ {
+ pNext1 = pEntry1->pNext;
+ PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+ for (uint32_t i = iFirst2; i < cRects; ++i)
+ {
+ const RTRECT *pRect2 = &aRects[i];
+ if (VBoxRectIsZero(pRect2))
+ continue;
+
+ if (!VBoxRectIsIntersect(&pReg1->Rect, pRect2))
+ continue;
+
+ /* the visitor can modify the list 1, apply necessary adjustments after it */
+ pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1);
+ if (pEntry1 == &pList1->ListHead)
+ break;
+ else
+ pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+ }
+ }
+}
+
+/* @returns Entry to be iterated next. ListHead is returned to break the iteration
+ *
+ */
+typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_NONINTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext);
+typedef FNVBOXVR_CB_NONINTERSECTED_VISITOR *PFNVBOXVR_CB_NONINTERSECTED_VISITOR;
+
+static void vboxVrListVisitNonintersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_NONINTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
+{
+ PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
+ PRTLISTNODE pNext1;
+ uint32_t iFirst2 = 0;
+
+ for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
+ {
+ PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+ uint32_t i = iFirst2;
+ for (; i < cRects; ++i)
+ {
+ const RTRECT *pRect2 = &aRects[i];
+ if (VBoxRectIsZero(pRect2))
+ continue;
+
+ if (VBoxRectIsIntersect(&pReg1->Rect, pRect2))
+ break;
+ }
+
+ if (i == cRects)
+ pNext1 = pfnVisitor(pList1, pReg1, pvVisitor);
+ else
+ pNext1 = pEntry1->pNext;
+ }
+}
+
+static void vboxVrListJoinRectsHV(PVBOXVR_LIST pList, bool fHorizontal)
+{
+ PRTLISTNODE pNext1, pNext2;
+
+ for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
+ {
+ PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+ pNext1 = pEntry1->pNext;
+ for (PRTLISTNODE pEntry2 = pEntry1->pNext; pEntry2 != &pList->ListHead; pEntry2 = pNext2)
+ {
+ PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
+ pNext2 = pEntry2->pNext;
+ if (fHorizontal)
+ {
+ if (pReg1->Rect.yTop == pReg2->Rect.yTop)
+ {
+ if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
+ {
+ /* join rectangles */
+ vboxVrListRegRemove(pList, pReg2);
+ if (pReg1->Rect.yBottom > pReg2->Rect.yBottom)
+ {
+ int32_t oldRight1 = pReg1->Rect.xRight;
+ int32_t oldBottom1 = pReg1->Rect.yBottom;
+ pReg1->Rect.xRight = pReg2->Rect.xRight;
+ pReg1->Rect.yBottom = pReg2->Rect.yBottom;
+
+ vboxVrDbgListVerify(pList);
+
+ pReg2->Rect.xLeft = pReg1->Rect.xLeft;
+ pReg2->Rect.yTop = pReg1->Rect.yBottom;
+ pReg2->Rect.xRight = oldRight1;
+ pReg2->Rect.yBottom = oldBottom1;
+ vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
+ /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
+ * and thus can match one of the previous rects */
+ pNext1 = pList->ListHead.pNext;
+ break;
+ }
+ else if (pReg1->Rect.yBottom < pReg2->Rect.yBottom)
+ {
+ pReg1->Rect.xRight = pReg2->Rect.xRight;
+ vboxVrDbgListVerify(pList);
+ pReg2->Rect.yTop = pReg1->Rect.yBottom;
+ vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
+ /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
+ * and thus can match one of the previous rects */
+ pNext1 = pList->ListHead.pNext;
+ break;
+ }
+ else
+ {
+ pReg1->Rect.xRight = pReg2->Rect.xRight;
+ vboxVrDbgListVerify(pList);
+ /* reset the pNext1 since it could be the pReg2 being destroyed */
+ pNext1 = pEntry1->pNext;
+ /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
+ vboxVrRegTerm(pReg2);
+ }
+ }
+ continue;
+ }
+ else if (pReg1->Rect.yBottom == pReg2->Rect.yBottom)
+ {
+ Assert(pReg1->Rect.yTop < pReg2->Rect.yTop); /* <- since pReg1 > pReg2 && pReg1->Rect.yTop != pReg2->Rect.yTop*/
+ if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
+ {
+ /* join rectangles */
+ vboxVrListRegRemove(pList, pReg2);
+
+ pReg1->Rect.yBottom = pReg2->Rect.yTop;
+ vboxVrDbgListVerify(pList);
+ pReg2->Rect.xLeft = pReg1->Rect.xLeft;
+
+ vboxVrListRegAddOrder(pList, pNext2, pReg2);
+
+ /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
+ * and thus can match one of the previous rects */
+ pNext1 = pList->ListHead.pNext;
+ break;
+ }
+ else if (pReg1->Rect.xLeft == pReg2->Rect.xRight)
+ {
+ /* join rectangles */
+ vboxVrListRegRemove(pList, pReg2);
+
+ pReg1->Rect.yBottom = pReg2->Rect.yTop;
+ vboxVrDbgListVerify(pList);
+ pReg2->Rect.xRight = pReg1->Rect.xRight;
+
+ vboxVrListRegAddOrder(pList, pNext2, pReg2);
+
+ /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
+ * and thus can match one of the previous rects */
+ pNext1 = pList->ListHead.pNext;
+ break;
+ }
+ continue;
+ }
+ }
+ else
+ {
+ if (pReg1->Rect.yBottom == pReg2->Rect.yTop)
+ {
+ if (pReg1->Rect.xLeft == pReg2->Rect.xLeft)
+ {
+ if (pReg1->Rect.xRight == pReg2->Rect.xRight)
+ {
+ /* join rects */
+ vboxVrListRegRemove(pList, pReg2);
+
+ pReg1->Rect.yBottom = pReg2->Rect.yBottom;
+ vboxVrDbgListVerify(pList);
+
+ /* reset the pNext1 since it could be the pReg2 being destroyed */
+ pNext1 = pEntry1->pNext;
+ /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
+ vboxVrRegTerm(pReg2);
+ continue;
+ }
+ /* no more to be done for for pReg1 */
+ break;
+ }
+ else if (pReg1->Rect.xRight > pReg2->Rect.xLeft)
+ {
+ /* no more to be done for for pReg1 */
+ break;
+ }
+
+ continue;
+ }
+ else if (pReg1->Rect.yBottom < pReg2->Rect.yTop)
+ {
+ /* no more to be done for for pReg1 */
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void vboxVrListJoinRects(PVBOXVR_LIST pList)
+{
+ vboxVrListJoinRectsHV(pList, true);
+ vboxVrListJoinRectsHV(pList, false);
+}
+
+typedef struct VBOXVR_CBDATA_SUBST
+{
+ int rc;
+ bool fChanged;
+} VBOXVR_CBDATA_SUBST, *PVBOXVR_CBDATA_SUBST;
+
+static DECLCALLBACK(PRTLISTNODE) vboxVrListSubstNoJoinCb(PVBOXVR_LIST pList, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
+{
+ PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
+ /* store the prev to get the new pNext out of it*/
+ PRTLISTNODE pPrev = pReg1->ListEntry.pPrev;
+ pData->fChanged = true;
+
+ Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
+
+ /* NOTE: the pReg1 will be invalid after the vboxVrListRegIntersectSubstNoJoin call!!! */
+ int rc = vboxVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2);
+ if (RT_SUCCESS(rc))
+ {
+ *ppNext = pPrev->pNext;
+ return &pList->ListHead;
+ }
+ WARN(("vboxVrListRegIntersectSubstNoJoin failed!"));
+ Assert(!RT_SUCCESS(rc));
+ pData->rc = rc;
+ *ppNext = &pList->ListHead;
+ return &pList->ListHead;
+}
+
+static int vboxVrListSubstNoJoin(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
+{
+ if (pfChanged)
+ *pfChanged = false;
+
+ if (VBoxVrListIsEmpty(pList))
+ return VINF_SUCCESS;
+
+ VBOXVR_CBDATA_SUBST Data;
+ Data.rc = VINF_SUCCESS;
+ Data.fChanged = false;
+
+ vboxVrListVisitIntersected(pList, cRects, aRects, vboxVrListSubstNoJoinCb, &Data);
+ if (!RT_SUCCESS(Data.rc))
+ {
+ WARN(("vboxVrListVisitIntersected failed!"));
+ return Data.rc;
+ }
+
+ if (pfChanged)
+ *pfChanged = Data.fChanged;
+
+ return VINF_SUCCESS;
+}
+
+#if 0
+static const RTRECT * vboxVrRectsOrder(uint32_t cRects, const RTRECT * aRects)
+{
+#ifdef DEBUG
+ {
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ RTRECT *pRectI = &aRects[i];
+ for (uint32_t j = i + 1; j < cRects; ++j)
+ {
+ RTRECT *pRectJ = &aRects[j];
+ Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
+ }
+ }
+ }
+#endif
+
+ RTRECT * pRects = (RTRECT *)aRects;
+ /* check if rects are ordered already */
+ for (uint32_t i = 0; i < cRects - 1; ++i)
+ {
+ RTRECT *pRect1 = &pRects[i];
+ RTRECT *pRect2 = &pRects[i+1];
+ if (vboxVrRegNonintersectedComparator(pRect1, pRect2) < 0)
+ continue;
+
+ WARN(("rects are unoreded!"));
+
+ if (pRects == aRects)
+ {
+ pRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cRects);
+ if (!pRects)
+ {
+ WARN(("RTMemAlloc failed!"));
+ return NULL;
+ }
+
+ memcpy(pRects, aRects, sizeof (RTRECT) * cRects);
+ }
+
+ Assert(pRects != aRects);
+
+ int j = (int)i - 1;
+ do {
+ RTRECT Tmp = *pRect1;
+ *pRect1 = *pRect2;
+ *pRect2 = Tmp;
+
+ if (j < 0)
+ break;
+
+ if (vboxVrRegNonintersectedComparator(pRect1, pRect1-1) > 0)
+ break;
+
+ pRect2 = pRect1--;
+ --j;
+ } while (1);
+ }
+
+ return pRects;
+}
+#endif
+
+VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y)
+{
+ for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
+ {
+ PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+ VBoxRectTranslate(&pReg1->Rect, x, y);
+ }
+}
+
+static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinNonintersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext)
+{
+ VBOXVR_CBDATA_SUBST *pData = (VBOXVR_CBDATA_SUBST*)pvContext;
+
+ PRTLISTNODE pNext = pReg1->ListEntry.pNext;
+
+ vboxVrDbgListVerify(pList1);
+
+ vboxVrListRegRemove(pList1, pReg1);
+ vboxVrRegTerm(pReg1);
+
+ vboxVrDbgListVerify(pList1);
+
+ pData->fChanged = true;
+
+ return pNext;
+}
+
+static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinIntersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
+{
+ PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
+ pData->fChanged = true;
+
+ vboxVrDbgListVerify(pList1);
+
+ PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
+
+ Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
+ Assert(!VBoxRectIsZero(pRect2));
+
+ vboxVrListRegRemove(pList1, pReg1);
+ VBoxRectIntersect(&pReg1->Rect, pRect2);
+ Assert(!VBoxRectIsZero(&pReg1->Rect));
+
+ vboxVrListRegAddOrder(pList1, pMemberEntry, pReg1);
+
+ vboxVrDbgListVerify(pList1);
+
+ return &pReg1->ListEntry;
+}
+
+static int vboxVrListIntersectNoJoin(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged)
+{
+ bool fChanged = false;
+ *pfChanged = false;
+
+ if (VBoxVrListIsEmpty(pList))
+ return VINF_SUCCESS;
+
+ if (VBoxVrListIsEmpty(pList2))
+ {
+ if (pfChanged)
+ *pfChanged = true;
+
+ VBoxVrListClear(pList);
+ return VINF_SUCCESS;
+ }
+
+ PRTLISTNODE pNext1;
+
+ for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
+ {
+ pNext1 = pEntry1->pNext;
+ PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+ RTRECT RegRect1 = pReg1->Rect;
+ PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
+
+ for (const RTLISTNODE *pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pEntry2->pNext)
+ {
+ const VBOXVR_REG *pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
+ const RTRECT *pRect2 = &pReg2->Rect;
+
+ if (!VBoxRectIsIntersect(&RegRect1, pRect2))
+ continue;
+
+ if (pReg1)
+ {
+ if (VBoxRectCovers(pRect2, &RegRect1))
+ {
+ /* no change */
+
+ /* zero up the pReg1 to mark it as intersected (see the code after this inner loop) */
+ pReg1 = NULL;
+
+ if (!VBoxRectCmp(pRect2, &RegRect1))
+ break; /* and we can break the iteration here */
+ }
+ else
+ {
+ /*just to ensure the VBoxRectCovers is true for equal rects */
+ Assert(VBoxRectCmp(pRect2, &RegRect1));
+
+ /* @todo: this can have false-alarming sometimes if the separated rects will then be joind into the original rect,
+ * so far this should not be a problem for VReg clients, so keep it this way for now */
+ fChanged = true;
+
+ /* re-use the reg entry */
+ vboxVrListRegRemove(pList, pReg1);
+ VBoxRectIntersect(&pReg1->Rect, pRect2);
+ Assert(!VBoxRectIsZero(&pReg1->Rect));
+
+ vboxVrListRegAddOrder(pList, pMemberEntry, pReg1);
+ pReg1 = NULL;
+ }
+ }
+ else
+ {
+ Assert(fChanged); /* <- should be set by the if branch above */
+ PVBOXVR_REG pReg = vboxVrRegCreate();
+ if (!pReg)
+ {
+ WARN(("vboxVrRegCreate failed!"));
+ return VERR_NO_MEMORY;
+ }
+ VBoxRectIntersected(&RegRect1, pRect2, &pReg->Rect);
+ Assert(!VBoxRectIsZero(&pReg->Rect));
+ vboxVrListRegAddOrder(pList, pList->ListHead.pNext, pReg);
+ }
+ }
+
+ if (pReg1)
+ {
+ /* the region has no intersections, remove it */
+ vboxVrListRegRemove(pList, pReg1);
+ vboxVrRegTerm(pReg1);
+ fChanged = true;
+ }
+ }
+
+ *pfChanged = fChanged;
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) VBoxVrListIntersect(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged)
+{
+ if (pfChanged)
+ *pfChanged = false;
+
+ int rc = vboxVrListIntersectNoJoin(pList, pList2, pfChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("vboxVrListSubstNoJoin failed!"));
+ return rc;
+ }
+
+ if (*pfChanged)
+ {
+ vboxVrListJoinRects(pList);
+ }
+
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrListRectsIntersect(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
+{
+ if (pfChanged)
+ *pfChanged = false;
+
+ if (VBoxVrListIsEmpty(pList))
+ return VINF_SUCCESS;
+
+ if (!cRects)
+ {
+ if (pfChanged)
+ *pfChanged = true;
+
+ VBoxVrListClear(pList);
+ return VINF_SUCCESS;
+ }
+
+ /* we perform intersection using lists because the algorythm axpects the rects to be non-intersected,
+ * which list guaranties to us */
+
+ VBOXVR_LIST TmpList;
+ VBoxVrListInit(&TmpList);
+
+ int rc = VBoxVrListRectsAdd(&TmpList, cRects, aRects, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VBoxVrListIntersect(pList, &TmpList, pfChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListIntersect failed! rc %d", rc));
+ }
+ }
+ else
+ {
+ WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
+ }
+ VBoxVrListClear(&TmpList);
+
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
+{
+#if 0
+ const RTRECT * pRects = vboxVrRectsOrder(cRects, aRects);
+ if (!pRects)
+ {
+ WARN(("vboxVrRectsOrder failed!"));
+ return VERR_NO_MEMORY;
+ }
+#endif
+
+ bool fChanged = false;
+
+ int rc = vboxVrListSubstNoJoin(pList, cRects, aRects, &fChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("vboxVrListSubstNoJoin failed!"));
+ goto done;
+ }
+
+ if (fChanged)
+ goto done;
+
+ vboxVrListJoinRects(pList);
+
+done:
+#if 0
+ if (pRects != aRects)
+ RTMemFree(pRects);
+#endif
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrListRectsSet(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
+{
+ if (pfChanged)
+ *pfChanged = false;
+
+ if (!cRects && VBoxVrListIsEmpty(pList))
+ {
+ return VINF_SUCCESS;
+ }
+
+ /* @todo: fChanged will have false alarming here, fix if needed */
+ VBoxVrListClear(pList);
+
+ int rc = VBoxVrListRectsAdd(pList, cRects, aRects, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListRectsSet failed rc %d", rc));
+ return rc;
+ }
+
+ if (pfChanged)
+ *pfChanged = true;
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
+{
+ uint32_t cCovered = 0;
+
+ if (pfChanged)
+ *pfChanged = false;
+
+#if 0
+#ifdef DEBUG
+ {
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ RTRECT *pRectI = &aRects[i];
+ for (uint32_t j = i + 1; j < cRects; ++j)
+ {
+ RTRECT *pRectJ = &aRects[j];
+ Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
+ }
+ }
+ }
+#endif
+#endif
+
+ /* early sort out the case when there are no new rects */
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ if (VBoxRectIsZero(&aRects[i]))
+ {
+ cCovered++;
+ continue;
+ }
+
+ for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
+ {
+ PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+
+ if (VBoxRectCovers(&pReg1->Rect, &aRects[i]))
+ {
+ cCovered++;
+ break;
+ }
+ }
+ }
+
+ if (cCovered == cRects)
+ return VINF_SUCCESS;
+
+ /* rects are not covered, need to go the slow way */
+
+ VBOXVR_LIST DiffList;
+ VBoxVrListInit(&DiffList);
+ RTRECT * pListRects = NULL;
+ uint32_t cAllocatedRects = 0;
+ bool fNeedRectreate = true;
+ bool fChanged = false;
+ int rc = VINF_SUCCESS;
+
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ if (VBoxRectIsZero(&aRects[i]))
+ continue;
+
+ PVBOXVR_REG pReg = vboxVrRegCreate();
+ if (!pReg)
+ {
+ WARN(("vboxVrRegCreate failed!"));
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+ pReg->Rect = aRects[i];
+
+ uint32_t cListRects = VBoxVrListRectsCount(pList);
+ if (!cListRects)
+ {
+ vboxVrListRegAdd(pList, pReg, &pList->ListHead, false);
+ fChanged = true;
+ continue;
+ }
+ else
+ {
+ Assert(VBoxVrListIsEmpty(&DiffList));
+ vboxVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, false);
+ }
+
+ if (cAllocatedRects < cListRects)
+ {
+ cAllocatedRects = cListRects + cRects;
+ Assert(fNeedRectreate);
+ if (pListRects)
+ RTMemFree(pListRects);
+ pListRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cAllocatedRects);
+ if (!pListRects)
+ {
+ WARN(("RTMemAlloc failed!"));
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+ }
+
+
+ if (fNeedRectreate)
+ {
+ rc = VBoxVrListRectsGet(pList, cListRects, pListRects);
+ Assert(rc == VINF_SUCCESS);
+ fNeedRectreate = false;
+ }
+
+ bool fDummyChanged = false;
+ rc = vboxVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("vboxVrListSubstNoJoin failed!"));
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+
+ if (!VBoxVrListIsEmpty(&DiffList))
+ {
+ vboxVrListAddNonintersected(pList, &DiffList);
+ fNeedRectreate = true;
+ fChanged = true;
+ }
+
+ Assert(VBoxVrListIsEmpty(&DiffList));
+ }
+
+ if (pListRects)
+ RTMemFree(pListRects);
+
+ Assert(VBoxVrListIsEmpty(&DiffList) || rc != VINF_SUCCESS);
+ VBoxVrListClear(&DiffList);
+
+ if (fChanged)
+ vboxVrListJoinRects(pList);
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects)
+{
+ if (cRects < VBoxVrListRectsCount(pList))
+ return VERR_BUFFER_OVERFLOW;
+
+ uint32_t i = 0;
+ for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext, ++i)
+ {
+ PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
+ aRects[i] = pReg1->Rect;
+ }
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) VBoxVrListCmp(const VBOXVR_LIST *pList1, const VBOXVR_LIST *pList2)
+{
+ int cTmp = pList1->cEntries - pList2->cEntries;
+ if (cTmp)
+ return cTmp;
+
+ PVBOXVR_REG pReg1, pReg2;
+
+ for (pReg1 = RTListNodeGetNext(&pList1->ListHead, VBOXVR_REG, ListEntry),
+ pReg2 = RTListNodeGetNext(&pList2->ListHead, VBOXVR_REG, ListEntry);
+ !RTListNodeIsDummy(&pList1->ListHead, pReg1, VBOXVR_REG, ListEntry);
+ pReg1 = RT_FROM_MEMBER(pReg1->ListEntry.pNext, VBOXVR_REG, ListEntry),
+ pReg2 = RT_FROM_MEMBER(pReg2->ListEntry.pNext, VBOXVR_REG, ListEntry))
+ {
+ Assert(!RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
+ cTmp = VBoxRectCmp(&pReg1->Rect, &pReg2->Rect);
+ if (cTmp)
+ return cTmp;
+ }
+ Assert(RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
+ return 0;
+}
+
+VBOXVREGDECL(int) VBoxVrListClone(const VBOXVR_LIST *pList, VBOXVR_LIST *pDstList)
+{
+ VBoxVrListInit(pDstList);
+ const VBOXVR_REG *pReg;
+ RTListForEach(&pList->ListHead, pReg, const VBOXVR_REG, ListEntry)
+ {
+ PVBOXVR_REG pDstReg = vboxVrRegCreate();
+ if (!pDstReg)
+ {
+ WARN(("vboxVrRegLaAlloc failed"));
+ VBoxVrListClear(pDstList);
+ return VERR_NO_MEMORY;
+ }
+ pDstReg->Rect = pReg->Rect;
+ vboxVrListRegAdd(pDstList, pDstReg, &pDstList->ListHead, true /*bool fAfter*/);
+ }
+
+ Assert(pDstList->cEntries == pList->cEntries);
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased)
+{
+ RTListInit(&pCompositor->List);
+ pCompositor->pfnEntryReleased = pfnEntryReleased;
+}
+
+VBOXVREGDECL(void) VBoxVrCompositorRegionsClear(PVBOXVR_COMPOSITOR pCompositor, bool *pfChanged)
+{
+ bool fChanged = false;
+ PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
+ RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
+ {
+ VBoxVrCompositorEntryRemove(pCompositor, pEntry);
+ fChanged = true;
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+}
+
+VBOXVREGDECL(void) VBoxVrCompositorClear(PVBOXVR_COMPOSITOR pCompositor)
+{
+ VBoxVrCompositorRegionsClear(pCompositor, NULL);
+}
+
+DECLINLINE(void) vboxVrCompositorEntryRelease(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
+{
+ if (--pEntry->cRefs)
+ {
+ Assert(pEntry->cRefs < UINT32_MAX/2);
+ return;
+ }
+
+ Assert(!VBoxVrCompositorEntryIsInList(pEntry));
+
+ if (pCompositor->pfnEntryReleased)
+ pCompositor->pfnEntryReleased(pCompositor, pEntry, pReplacingEntry);
+}
+
+DECLINLINE(void) vboxVrCompositorEntryAddRef(PVBOXVR_COMPOSITOR_ENTRY pEntry)
+{
+ ++pEntry->cRefs;
+}
+
+DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
+{
+ RTListPrepend(&pCompositor->List, &pEntry->Node);
+ vboxVrCompositorEntryAddRef(pEntry);
+}
+
+DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
+{
+ RTListNodeRemove(&pEntry->Node);
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, pReplacingEntry);
+}
+
+static void vboxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
+{
+ VBoxVrListMoveTo(&pEntry->Vr, &pReplacingEntry->Vr);
+
+ pReplacingEntry->Node = pEntry->Node;
+ pReplacingEntry->Node.pNext->pPrev = &pReplacingEntry->Node;
+ pReplacingEntry->Node.pPrev->pNext = &pReplacingEntry->Node;
+ pEntry->Node.pNext = NULL;
+ pEntry->Node.pPrev = NULL;
+
+ vboxVrCompositorEntryAddRef(pReplacingEntry);
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, pReplacingEntry);
+}
+
+
+
+VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry)
+{
+ VBoxVrListInit(&pEntry->Vr);
+ pEntry->cRefs = 0;
+}
+
+VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
+{
+ if (!VBoxVrCompositorEntryIsInList(pEntry))
+ return false;
+
+ vboxVrCompositorEntryAddRef(pEntry);
+
+ VBoxVrListClear(&pEntry->Vr);
+ vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+ return true;
+}
+
+VBOXVREGDECL(bool) VBoxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pNewEntry)
+{
+ if (!VBoxVrCompositorEntryIsInList(pEntry))
+ return false;
+
+ vboxVrCompositorEntryReplace(pCompositor, pEntry, pNewEntry);
+
+ return true;
+}
+
+static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
+{
+ bool fChanged;
+ vboxVrCompositorEntryAddRef(pEntry);
+
+ int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged);
+ if (RT_SUCCESS(rc))
+ {
+ if (VBoxVrListIsEmpty(&pEntry->Vr))
+ {
+ Assert(fChanged);
+ vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
+ }
+ if (pfChanged)
+ *pfChanged = false;
+ }
+ else
+ WARN(("VBoxVrListRectsSubst failed, rc %d", rc));
+
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, PVBOXVR_COMPOSITOR_ENTRY *ppReplacedEntry, uint32_t *pfChangeFlags)
+{
+ bool fOthersChanged = false, fCurChanged = false, fEntryChanged = false, fEntryWasInList = false;
+ PVBOXVR_COMPOSITOR_ENTRY pCur, pNext, pReplacedEntry = NULL;
+ int rc = VINF_SUCCESS;
+
+ if (pEntry)
+ vboxVrCompositorEntryAddRef(pEntry);
+
+ if (!cRects)
+ {
+ if (pfChangeFlags)
+ *pfChangeFlags = 0;
+ if (pEntry)
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+ return VINF_SUCCESS;
+ }
+
+ if (pEntry)
+ {
+ fEntryWasInList = VBoxVrCompositorEntryIsInList(pEntry);
+ rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged);
+ if (RT_SUCCESS(rc))
+ {
+ if (VBoxVrListIsEmpty(&pEntry->Vr))
+ {
+// WARN(("Empty rectangles passed in, is it expected?"));
+ if (pfChangeFlags)
+ *pfChangeFlags = 0;
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+ return VINF_SUCCESS;
+ }
+ }
+ else
+ {
+ WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+ return rc;
+ }
+
+ Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
+ }
+ else
+ {
+ fEntryChanged = true;
+ }
+
+ RTListForEachSafe(&pCompositor->List, pCur, pNext, VBOXVR_COMPOSITOR_ENTRY, Node)
+ {
+ Assert(!VBoxVrListIsEmpty(&pCur->Vr));
+ if (pCur != pEntry)
+ {
+ if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr))
+ {
+ VBoxVrListClear(&pCur->Vr);
+ pReplacedEntry = pCur;
+ vboxVrCompositorEntryAddRef(pReplacedEntry);
+ vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry);
+ if (ppReplacedEntry)
+ *ppReplacedEntry = pReplacedEntry;
+ break;
+ }
+ else
+ {
+ rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged);
+ if (RT_SUCCESS(rc))
+ fOthersChanged |= fCurChanged;
+ else
+ {
+ WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc));
+ return rc;
+ }
+ }
+ }
+ }
+
+ AssertRC(rc);
+
+ if (pEntry)
+ {
+ if (!fEntryWasInList)
+ {
+ Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
+ vboxVrCompositorEntryAdd(pCompositor, pEntry);
+ }
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+ }
+
+ uint32_t fFlags = 0;
+ if (fOthersChanged)
+ {
+ Assert(!pReplacedEntry);
+ fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED;
+ }
+ else if (pReplacedEntry)
+ {
+ vboxVrCompositorEntryRelease(pCompositor, pReplacedEntry, pEntry);
+ Assert(fEntryChanged);
+ fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED;
+ }
+ else if (fEntryChanged)
+ {
+ Assert(!pReplacedEntry);
+ fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED;
+ }
+ else
+ {
+ Assert(!pReplacedEntry);
+ }
+
+ if (!fEntryWasInList)
+ Assert(fEntryChanged);
+
+ if (pfChangeFlags)
+ *pfChangeFlags = fFlags;
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
+{
+ if (!pEntry)
+ {
+ WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!"));
+ if (pfChanged)
+ *pfChanged = false;
+ return VERR_INVALID_PARAMETER;
+ }
+
+ vboxVrCompositorEntryAddRef(pEntry);
+
+ if (VBoxVrListIsEmpty(&pEntry->Vr))
+ {
+ if (pfChanged)
+ *pfChanged = false;
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+ return VINF_SUCCESS;
+ }
+
+ int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged);
+ if (!RT_SUCCESS(rc))
+ WARN(("pfChanged failed, rc %d", rc));
+
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
+{
+ if (!pEntry)
+ {
+ WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!"));
+ if (pfChanged)
+ *pfChanged = false;
+ return VERR_INVALID_PARAMETER;
+ }
+
+ vboxVrCompositorEntryAddRef(pEntry);
+
+ bool fChanged = false, fCurChanged = false;
+ uint32_t fChangeFlags = 0;
+ int rc;
+ fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry);
+ fChanged |= fCurChanged;
+
+ rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, NULL, &fChangeFlags);
+ if (RT_SUCCESS(rc))
+ {
+ fChanged |= !!fChangeFlags;
+ if (pfChanged)
+ *pfChanged = fChanged;
+ }
+ else
+ WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
+
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+
+ return VINF_SUCCESS;
+}
+
+VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
+{
+ int rc = VINF_SUCCESS;
+ bool fChanged = false;
+
+ vboxVrCompositorEntryAddRef(pEntry);
+
+ if (VBoxVrCompositorEntryIsInList(pEntry))
+ {
+ rc = VBoxVrListIntersect(&pEntry->Vr, pList2, &fChanged);
+ if (RT_SUCCESS(rc))
+ {
+ if (VBoxVrListIsEmpty(&pEntry->Vr))
+ {
+ Assert(fChanged);
+ vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
+ }
+ }
+ else
+ {
+ WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
+ }
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
+{
+ int rc = VINF_SUCCESS;
+ bool fChanged = false;
+
+ vboxVrCompositorEntryAddRef(pEntry);
+
+ if (VBoxVrCompositorEntryIsInList(pEntry))
+ {
+ rc = VBoxVrListRectsIntersect(&pEntry->Vr, cRects, paRects, &fChanged);
+ if (RT_SUCCESS(rc))
+ {
+ if (VBoxVrListIsEmpty(&pEntry->Vr))
+ {
+ Assert(fChanged);
+ vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
+ }
+ }
+ else
+ {
+ WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
+ }
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersectAll(PVBOXVR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
+{
+ VBOXVR_COMPOSITOR_ITERATOR Iter;
+ VBoxVrCompositorIterInit(pCompositor, &Iter);
+ PVBOXVR_COMPOSITOR_ENTRY pEntry;
+ int rc = VINF_SUCCESS;
+ bool fChanged = false;
+
+ while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
+ {
+ bool fTmpChanged = false;
+ int tmpRc = VBoxVrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
+ if (RT_SUCCESS(tmpRc))
+ {
+ fChanged |= fChanged;
+ }
+ else
+ {
+ WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
+ rc = tmpRc;
+ }
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersectAll(PVBOXVR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
+{
+ VBOXVR_COMPOSITOR_ITERATOR Iter;
+ VBoxVrCompositorIterInit(pCompositor, &Iter);
+ PVBOXVR_COMPOSITOR_ENTRY pEntry;
+ int rc = VINF_SUCCESS;
+ bool fChanged = false;
+
+ while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
+ {
+ bool fTmpChanged = false;
+ int tmpRc = VBoxVrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
+ if (RT_SUCCESS(tmpRc))
+ {
+ fChanged |= fChanged;
+ }
+ else
+ {
+ WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
+ rc = tmpRc;
+ }
+ }
+
+ if (pfChanged)
+ *pfChanged = fChanged;
+
+ return rc;
+}
+
+VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged)
+{
+ if (!pEntry)
+ {
+ WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!"));
+ if (pfChanged)
+ *pfChanged = false;
+ return VERR_INVALID_PARAMETER;
+ }
+
+ vboxVrCompositorEntryAddRef(pEntry);
+
+ if ((!x && !y)
+ || !VBoxVrCompositorEntryIsInList(pEntry))
+ {
+ if (pfChanged)
+ *pfChanged = false;
+
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+ return VINF_SUCCESS;
+ }
+
+ VBoxVrListTranslate(&pEntry->Vr, x, y);
+
+ Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
+
+ PVBOXVR_COMPOSITOR_ENTRY pCur;
+ uint32_t cRects = 0;
+ RTRECT *paRects = NULL;
+ int rc = VINF_SUCCESS;
+ RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
+ {
+ Assert(!VBoxVrListIsEmpty(&pCur->Vr));
+
+ if (pCur == pEntry)
+ continue;
+
+ if (!paRects)
+ {
+ cRects = VBoxVrListRectsCount(&pEntry->Vr);
+ Assert(cRects);
+ paRects = (RTRECT*)RTMemAlloc(cRects * sizeof (RTRECT));
+ if (!paRects)
+ {
+ WARN(("RTMemAlloc failed!"));
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+
+ rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListRectsGet failed! rc %d", rc));
+ break;
+ }
+ }
+
+ rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc));
+ break;
+ }
+ }
+
+ if (pfChanged)
+ *pfChanged = true;
+
+ if (paRects)
+ RTMemFree(paRects);
+
+ vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
+
+ return rc;
+}
+
+VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
+{
+ PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
+ RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
+ {
+ if (!pfnVisitor(pCompositor, pEntry, pvVisitor))
+ return;
+ }
+}