diff options
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/render')
10 files changed, 2771 insertions, 1203 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu.c index 1446473e..b907c6a9 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu.c +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu.c @@ -9,9 +9,14 @@ #include "cr_error.h" #include "cr_mem.h" #include "cr_spu.h" +#include "cr_environment.h" #include "renderspu.h" #include "cr_extstring.h" +#include <iprt/asm.h> + +uint32_t renderspuContextRelease(ContextInfo *context); +uint32_t renderspuContextRetain(ContextInfo *context); static void DoSync(void) @@ -78,6 +83,12 @@ renderspuMakeVisString( GLbitfield visAttribs, char *s ) crStrcat(s, ", PBuffer"); } +GLboolean renderspuInitVisual(VisualInfo *pVisInfo, const char *displayName, GLbitfield visAttribs) +{ + pVisInfo->displayName = crStrdup(displayName); + pVisInfo->visAttribs = visAttribs; + return renderspu_SystemInitVisual(pVisInfo); +} /* * Find a VisualInfo which matches the given display name and attribute @@ -115,9 +126,7 @@ renderspuFindVisual(const char *displayName, GLbitfield visAttribs) /* create a new visual */ i = render_spu.numVisuals; - render_spu.visuals[i].displayName = crStrdup(displayName); - render_spu.visuals[i].visAttribs = visAttribs; - if (renderspu_SystemInitVisual(&(render_spu.visuals[i]))) { + if (renderspuInitVisual(&(render_spu.visuals[i]), displayName, visAttribs)) { render_spu.numVisuals++; return &(render_spu.visuals[i]); } @@ -127,79 +136,212 @@ renderspuFindVisual(const char *displayName, GLbitfield visAttribs) } } -/* - * Context functions - */ - -GLint RENDER_APIENTRY -renderspuCreateContext(const char *dpyName, GLint visBits, GLint shareCtx) +static ContextInfo * renderspuCreateContextInternal(const char *dpyName, GLint visBits, GLint idCtx, ContextInfo * sharedContext) { - ContextInfo *context, *sharedContext = NULL; + ContextInfo *context; VisualInfo *visual; - if (shareCtx > 0) { - sharedContext - = (ContextInfo *) crHashtableSearch(render_spu.contextTable, shareCtx); + if (idCtx <= 0) + { + idCtx = (GLint)crHashtableAllocKeys(render_spu.contextTable, 1); + if (idCtx <= 0) + { + crWarning("failed to allocate context id"); + return NULL; + } } + else + { + if (crHashtableIsKeyUsed(render_spu.contextTable, idCtx)) + { + crWarning("the specified ctx key %d is in use", idCtx); + return NULL; + } + } + if (!dpyName || crStrlen(render_spu.display_string)>0) dpyName = render_spu.display_string; visual = renderspuFindVisual(dpyName, visBits); if (!visual) - return -1; + return NULL; context = (ContextInfo *) crCalloc(sizeof(ContextInfo)); if (!context) - return -1; - context->id = render_spu.context_id; + return NULL; + context->BltInfo.Base.id = idCtx; context->shared = sharedContext; if (!renderspu_SystemCreateContext(visual, context, sharedContext)) - return -1; + return NULL; - crHashtableAdd(render_spu.contextTable, render_spu.context_id, context); - render_spu.context_id++; + crHashtableAdd(render_spu.contextTable, idCtx, context); + context->BltInfo.Base.visualBits = visual->visAttribs; /* crDebug("Render SPU: CreateContext(%s, 0x%x) returning %d", - dpyName, visBits, context->id); + dpyName, visBits, context->BltInfo.Base.id); */ - return context->id; -} + if (sharedContext) + renderspuContextRetain(sharedContext); + context->cRefs = 1; -static void RENDER_APIENTRY -renderspuDestroyContext( GLint ctx ) + return context; +} + +GLint renderspuCreateContextEx(const char *dpyName, GLint visBits, GLint id, GLint shareCtx) { - ContextInfo *context; + ContextInfo *context, *sharedContext = NULL; - CRASSERT(ctx); + if (shareCtx) { + sharedContext + = (ContextInfo *) crHashtableSearch(render_spu.contextTable, shareCtx); + CRASSERT(sharedContext); + } - context = (ContextInfo *) crHashtableSearch(render_spu.contextTable, ctx); - CRASSERT(context); + context = renderspuCreateContextInternal(dpyName, visBits, id, sharedContext); + if (context) + return context->BltInfo.Base.id; + return -1; +} + +/* + * Context functions + */ + +GLint RENDER_APIENTRY +renderspuCreateContext(const char *dpyName, GLint visBits, GLint shareCtx) +{ + return renderspuCreateContextEx(dpyName, visBits, 0, shareCtx); +} + +static void renderspuDestroyContextTerminate( ContextInfo *context ) +{ + CRASSERT(context->BltInfo.Base.id == -1); renderspu_SystemDestroyContext( context ); if (context->extensionString) { crFree(context->extensionString); context->extensionString = NULL; } - crHashtableDelete(render_spu.contextTable, ctx, crFree); + + if (context->shared) + renderspuContextRelease( context->shared ); + + crFree(context); } +uint32_t renderspuContextRetain( ContextInfo *context ) +{ + Assert(context->cRefs); + return ASMAtomicIncU32(&context->cRefs); +} -void RENDER_APIENTRY -renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx) +uint32_t renderspuContextRelease( ContextInfo *context ) { - WindowInfo *window; - ContextInfo *context; + uint32_t cRefs = ASMAtomicDecU32(&context->cRefs); + if (!cRefs) + renderspuDestroyContextTerminate( context ); + else + CRASSERT(cRefs < UINT32_MAX/2); + return cRefs; +} - /* - crDebug("%s win=%d native=0x%x ctx=%d", __FUNCTION__, crWindow, (int) nativeWindow, ctx); - */ +uint32_t renderspuContextMarkDeletedAndRelease( ContextInfo *context ) +{ + /* invalidate the context id to mark it as deleted */ + context->BltInfo.Base.id = -1; + + /* some drivers do not like when the base (shared) context is deleted before its referals, + * this is why we keep a context refference counting the base (shared) context will be destroyed as soon as*/ + return renderspuContextRelease( context ); +} + +ContextInfo * renderspuDefaultSharedContextAcquire() +{ + ContextInfo * pCtx = render_spu.defaultSharedContext; + if (!pCtx) + return NULL; + + renderspuContextRetain(pCtx); + return pCtx; +} + +void renderspuDefaultSharedContextRelease(ContextInfo * pCtx) +{ + renderspuContextRelease(pCtx); +} + + +static void RENDER_APIENTRY +renderspuDestroyContext( GLint ctx ) +{ + ContextInfo *context, *curCtx; + + CRASSERT(ctx); + + if (ctx == CR_RENDER_DEFAULT_CONTEXT_ID) + { + crWarning("request to destroy a default context, ignoring"); + return; + } - window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, crWindow); context = (ContextInfo *) crHashtableSearch(render_spu.contextTable, ctx); + if (!context) + { + crWarning("request to delete inexistent context"); + return; + } + + if (render_spu.defaultSharedContext == context) + { + renderspuSetDefaultSharedContext(NULL); + } + + curCtx = GET_CONTEXT_VAL(); +// CRASSERT(curCtx); + if (curCtx == context) + { + renderspuMakeCurrent( CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID ); + curCtx = GET_CONTEXT_VAL(); + Assert(curCtx); + Assert(curCtx != context); + } + + crHashtableDelete(render_spu.contextTable, ctx, NULL); + + renderspuContextMarkDeletedAndRelease(context); +} + +WindowInfo* renderspuGetDummyWindow(GLint visBits) +{ + WindowInfo *window = (WindowInfo *) crHashtableSearch(render_spu.dummyWindowTable, visBits); + if (!window) + { + window = (WindowInfo *)crAlloc(sizeof (*window)); + if (!window) + { + crWarning("crAlloc failed"); + return NULL; + } + + if (!renderspuWindowInit(window, NULL, visBits, -1)) + { + crWarning("renderspuWindowInit failed"); + crFree(window); + return NULL; + } + + crHashtableAdd(render_spu.dummyWindowTable, visBits, window); + } + + return window; +} + +void renderspuPerformMakeCurrent(WindowInfo *window, GLint nativeWindow, ContextInfo *context) +{ if (window && context) { #ifdef CHROMIUM_THREADSAFE @@ -210,12 +352,12 @@ renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx) context->currentWindow = window; if (!window) { - crDebug("Render SPU: MakeCurrent invalid window id: %d", crWindow); + crDebug("Render SPU: MakeCurrent invalid window id: %d", window->BltInfo.Base.id); return; } if (!context) { - crDebug("Render SPU: MakeCurrent invalid context id: %d", ctx); + crDebug("Render SPU: MakeCurrent invalid context id: %d", context->BltInfo.Base.id); return; } @@ -236,9 +378,9 @@ renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx) context->haveWindowPosARB = GL_FALSE; context->everCurrent = GL_TRUE; } - if (crWindow == 0 && window->mapPending && + if (window->BltInfo.Base.id == CR_RENDER_DEFAULT_WINDOW_ID && window->mapPending && !render_spu.render_to_app_window && !render_spu.render_to_crut_window) { - /* Window[0] is special, it's the default window and normally hidden. + /* Window[CR_RENDER_DEFAULT_CONTEXT_ID] is special, it's the default window and normally hidden. * If the mapPending flag is set, then we should now make the window * visible. */ @@ -247,60 +389,75 @@ renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx) } window->everCurrent = GL_TRUE; } - else + else if (!window && !context) { + renderspu_SystemMakeCurrent( NULL, 0, NULL ); #ifdef CHROMIUM_THREADSAFE crSetTSD(&_RenderTSD, NULL); #else render_spu.currentContext = NULL; #endif } + else + { + crError("renderspuMakeCurrent invalid ids: crWindow(%d), ctx(%d)", + window ? window->BltInfo.Base.id : 0, + context ? context->BltInfo.Base.id : 0); + } } - -/* - * Window functions - */ - -GLint RENDER_APIENTRY -renderspuWindowCreate( const char *dpyName, GLint visBits ) +void RENDER_APIENTRY +renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx) { - WindowInfo *window; - VisualInfo *visual; - GLboolean showIt; + WindowInfo *window = NULL; + ContextInfo *context = NULL; - if (!dpyName || crStrlen(render_spu.display_string) > 0) - dpyName = render_spu.display_string; + /* + crDebug("%s win=%d native=0x%x ctx=%d", __FUNCTION__, crWindow, (int) nativeWindow, ctx); + */ - visual = renderspuFindVisual( dpyName, visBits ); - if (!visual) + if (crWindow) { - crWarning( "Render SPU: Couldn't create a window, renderspuFindVisual returned NULL" ); - return -1; + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, crWindow); + if (!window) + { + crWarning("invalid window %d specified", crWindow); + return; + } } - /* Allocate WindowInfo */ - window = (WindowInfo *) crCalloc(sizeof(WindowInfo)); - if (!window) + if (ctx) { - crWarning( "Render SPU: Couldn't create a window" ); - return -1; + context = (ContextInfo *) crHashtableSearch(render_spu.contextTable, ctx); + if (!context) + { + crWarning("invalid context %d specified", ctx); + return; + } } - crHashtableAdd(render_spu.windowTable, render_spu.window_id, window); - window->id = render_spu.window_id; - render_spu.window_id++; + if (!context != !window) + { + crWarning("either window %d or context %d are zero", crWindow, ctx); + return; + } + + renderspuPerformMakeCurrent(window, nativeWindow, context); +} + +GLboolean renderspuWindowInitWithVisual( WindowInfo *window, VisualInfo *visual, GLboolean showIt, GLint id ) +{ + crMemset(window, 0, sizeof (*window)); + RTCritSectInit(&window->CompositorLock); + window->fCompositorPresentEmpty = GL_FALSE; + window->pCompositor = NULL; + + window->BltInfo.Base.id = id; window->x = render_spu.defaultX; window->y = render_spu.defaultY; - window->width = render_spu.defaultWidth; - window->height = render_spu.defaultHeight; - - if (render_spu.force_hidden_wdn_create - || ((render_spu.render_to_app_window || render_spu.render_to_crut_window) && !crGetenv("CRNEWSERVER"))) - showIt = 0; - else - showIt = window->id > 0; + window->BltInfo.width = render_spu.defaultWidth; + window->BltInfo.height = render_spu.defaultHeight; /* Set window->title, replacing %i with the window ID number */ { @@ -310,7 +467,7 @@ renderspuWindowCreate( const char *dpyName, GLint visBits ) window->title = crAlloc(crStrlen(render_spu.window_title) + 10); for (i = 0; render_spu.window_title[i] != '%'; i++) window->title[i] = render_spu.window_title[i]; - k = sprintf(window->title + i, "%d", window->id); + k = sprintf(window->title + i, "%d", window->BltInfo.Base.id); CRASSERT(k < 10); i++; /* skip the 'i' after the '%' */ j = i + k; @@ -321,21 +478,103 @@ renderspuWindowCreate( const char *dpyName, GLint visBits ) window->title = crStrdup(render_spu.window_title); } } - + + window->BltInfo.Base.visualBits = visual->visAttribs; + + /* - crDebug("Render SPU: Creating window (visBits=0x%x, id=%d)", visBits, window->id); + crDebug("Render SPU: Creating window (visBits=0x%x, id=%d)", visBits, window->BltInfo.Base.id); */ /* Have GLX/WGL/AGL create the window */ if (!renderspu_SystemVBoxCreateWindow( visual, showIt, window )) { - crFree(window); crWarning( "Render SPU: Couldn't create a window, renderspu_SystemCreateWindow failed" ); - return -1; + return GL_FALSE; } + + window->visible = !!showIt; CRASSERT(window->visual == visual); + return GL_TRUE; +} + +/* + * Window functions + */ +GLboolean renderspuWindowInit(WindowInfo *pWindow, const char *dpyName, GLint visBits, GLint id) +{ + VisualInfo *visual; + + crMemset(pWindow, 0, sizeof (*pWindow)); - return window->id; + if (!dpyName || crStrlen(render_spu.display_string) > 0) + dpyName = render_spu.display_string; + + visual = renderspuFindVisual( dpyName, visBits ); + if (!visual) + { + crWarning( "Render SPU: Couldn't create a window, renderspuFindVisual returned NULL" ); + return GL_FALSE; + } + + /* + crDebug("Render SPU: Creating window (visBits=0x%x, id=%d)", visBits, window->BltInfo.Base.id); + */ + /* Have GLX/WGL/AGL create the window */ + if (!renderspuWindowInitWithVisual( pWindow, visual, 0, id )) + { + crWarning( "Render SPU: Couldn't create a window, renderspu_SystemCreateWindow failed" ); + return GL_FALSE; + } + + return GL_TRUE; +} + +GLint renderspuWindowCreateEx( const char *dpyName, GLint visBits, GLint id ) +{ + WindowInfo *window; + + if (id <= 0) + { + id = (GLint)crHashtableAllocKeys(render_spu.windowTable, 1); + if (id <= 0) + { + crWarning("failed to allocate window id"); + return -1; + } + } + else + { + if (crHashtableIsKeyUsed(render_spu.windowTable, id)) + { + crWarning("the specified window key %d is in use", id); + return -1; + } + } + + /* Allocate WindowInfo */ + window = (WindowInfo *) crCalloc(sizeof(WindowInfo)); + if (!window) + { + crWarning( "Render SPU: Couldn't create a window" ); + return -1; + } + + if (!renderspuWindowInit(window, dpyName, visBits, id)) + { + crWarning("renderspuWindowInit failed"); + crFree(window); + return -1; + } + + crHashtableAdd(render_spu.windowTable, id, window); + return window->BltInfo.Base.id; +} + +GLint RENDER_APIENTRY +renderspuWindowCreate( const char *dpyName, GLint visBits ) +{ + return renderspuWindowCreateEx( dpyName, visBits, 0 ); } static void renderspuCheckCurrentCtxWindowCB(unsigned long key, void *data1, void *data2) @@ -346,7 +585,46 @@ static void renderspuCheckCurrentCtxWindowCB(unsigned long key, void *data1, voi if (pCtx->currentWindow==pWindow) { - renderspuMakeCurrent(0, 0, pCtx->id); + WindowInfo* pDummy = renderspuGetDummyWindow(pCtx->BltInfo.Base.visualBits); + if (pDummy) + { + renderspuPerformMakeCurrent(pDummy, 0, pCtx); + } + else + { + crWarning("failed to get dummy window"); + renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, pCtx->BltInfo.Base.id); + } + } +} + +void renderspuWindowTerm( WindowInfo *window ) +{ + GET_CONTEXT(pOldCtx); + WindowInfo * pOldWindow = pOldCtx ? pOldCtx->currentWindow : NULL; + CRASSERT(!pOldCtx == !pOldWindow); + /* ensure no concurrent draws can take place */ + renderspuVBoxCompositorSet(window, NULL); + renderspuVBoxPresentBlitterCleanup(window); + renderspu_SystemDestroyWindow( window ); + RTCritSectDelete(&window->CompositorLock); + /* check if this window is bound to some ctx. Note: window pointer is already freed here */ + crHashtableWalk(render_spu.contextTable, renderspuCheckCurrentCtxWindowCB, window); + /* restore current context */ + { + GET_CONTEXT(pNewCtx); + WindowInfo * pNewWindow = pNewCtx ? pNewCtx->currentWindow : NULL; + CRASSERT(!pNewCtx == !pNewWindow); + + if (pOldWindow == window) + renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID); + else if (pNewCtx != pOldCtx || pOldWindow != pNewWindow) + { + if (pOldCtx) + renderspuPerformMakeCurrent(pOldWindow, 0, pOldCtx); + else + renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID); + } } } @@ -354,28 +632,21 @@ void RENDER_APIENTRY renderspuWindowDestroy( GLint win ) { WindowInfo *window; - GET_CONTEXT(pOldCtx); CRASSERT(win >= 0); + if (win == CR_RENDER_DEFAULT_WINDOW_ID) + { + crWarning("request to destroy a default mural, ignoring"); + return; + } window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win); if (window) { crDebug("Render SPU: Destroy window (%d)", win); - renderspu_SystemDestroyWindow( window ); + renderspuWindowTerm( window ); + /* remove window info from hash table, and free it */ crHashtableDelete(render_spu.windowTable, win, crFree); - /* check if this window is bound to some ctx. Note: window pointer is already freed here */ - crHashtableWalk(render_spu.contextTable, renderspuCheckCurrentCtxWindowCB, window); - - /* restore current context */ - { - GET_CONTEXT(pNewCtx); - if (pNewCtx!=pOldCtx) - { - renderspuMakeCurrent(pOldCtx&&pOldCtx->currentWindow ? pOldCtx->currentWindow->id:0, 0, - pOldCtx ? pOldCtx->id:0); - } - } } else { crDebug("Render SPU: Attempt to destroy invalid window (%d)", win); @@ -390,7 +661,17 @@ renderspuWindowSize( GLint win, GLint w, GLint h ) CRASSERT(win >= 0); window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win); if (window) { - renderspu_SystemWindowSize( window, w, h ); + if (w != window->BltInfo.width + || h != window->BltInfo.height) + { + /* window is resized, compositor data is no longer valid + * this set also ensures all redraw operations are done in the redraw thread + * and that no redraw is started until new Present request comes containing a valid presentation data */ + renderspuVBoxCompositorSet( window, NULL); + renderspu_SystemWindowSize( window, w, h ); + window->BltInfo.width = w; + window->BltInfo.height = h; + } } else { crDebug("Render SPU: Attempt to resize invalid window (%d)", win); @@ -416,17 +697,41 @@ renderspuWindowPosition( GLint win, GLint x, GLint y ) } } +#ifdef DEBUG_misha +# define CR_DBG_DUMP_VISIBLE_REGIONS +#endif + +#ifdef CR_DBG_DUMP_VISIBLE_REGIONS +static void renderspuDbgDumpVisibleRegion(GLint win, GLint cRects, const GLint *pRects) +{ + GLint i; + const RTRECT *pRtRects = (const RTRECT *)((const void*)pRects); + + crInfo("Window %d, Vidible Regions%d", win, cRects); + for (i = 0; i < cRects; ++i) + { + crInfo("%d: (%d,%d), (%d,%d)", i, pRtRects[i].xLeft, pRtRects[i].yTop, pRtRects[i].xRight, pRtRects[i].yBottom); + } + crInfo("======"); +} +#endif + static void RENDER_APIENTRY -renderspuWindowVisibleRegion(GLint win, GLint cRects, GLint *pRects) +renderspuWindowVisibleRegion(GLint win, GLint cRects, const GLint *pRects) { WindowInfo *window; CRASSERT(win >= 0); + +#ifdef CR_DBG_DUMP_VISIBLE_REGIONS + renderspuDbgDumpVisibleRegion(win, cRects, pRects); +#endif + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win); if (window) { renderspu_SystemWindowVisibleRegion( window, cRects, pRects ); } else { - crDebug("Render SPU: Attempt to set VisibleRegion for invalid window (%d)", win); + crWarning("Render SPU: Attempt to set VisibleRegion for invalid window (%d)", win); } } @@ -437,6 +742,7 @@ renderspuWindowShow( GLint win, GLint flag ) CRASSERT(win >= 0); window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win); if (window) { + GLboolean visible; if (window->nativeWindow) { /* We're rendering back to the native app window instead of the * new window which we (the Render SPU) created earlier. @@ -444,13 +750,367 @@ renderspuWindowShow( GLint win, GLint flag ) */ flag = 0; } - renderspu_SystemShowWindow( window, (GLboolean) flag ); + + visible = !!flag; + + if (window->visible != visible) + { + renderspu_SystemShowWindow( window, visible ); + window->visible = visible; + } } else { crDebug("Render SPU: Attempt to hide/show invalid window (%d)", win); } } +static void RENDER_APIENTRY +renderspuVBoxPresentComposition( GLint win, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry ) +{ + WindowInfo *window; + CRASSERT(win >= 0); + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win); + if (window) { + if (pCompositor && CrVrScrCompositorIsEmpty(pCompositor) && !window->fCompositorPresentEmpty) + pCompositor = NULL; + + if (pCompositor) + window->fCompositorPresentEmpty = GL_FALSE; + + renderspuVBoxCompositorSet( window, pCompositor); + if (pCompositor) + { + renderspu_SystemVBoxPresentComposition(window, pChangedEntry); + } + } + else { + crDebug("Render SPU: Attempt to PresentComposition for invalid window (%d)", win); + } +} + +void renderspuVBoxCompositorBlitStretched ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter, GLfloat scaleX, GLfloat scaleY) +{ + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + CrVrScrCompositorConstIterInit(pCompositor, &CIter); + while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL) + { + uint32_t cRegions; + const RTRECT *paSrcRegions, *paDstRegions; + int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL); + uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry); + if (RT_SUCCESS(rc)) + { + uint32_t i; + for (i = 0; i < cRegions; ++i) + { + RTRECT DstRect; + const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + DstRect.xLeft = paDstRegions[i].xLeft * scaleX; + DstRect.yTop = paDstRegions[i].yTop * scaleY; + DstRect.xRight = paDstRegions[i].xRight * scaleX; + DstRect.yBottom = paDstRegions[i].yBottom * scaleY; + CrBltBlitTexMural(pBlitter, true, CrTdTexGet(pTexData), &paSrcRegions[i], &DstRect, 1, fFlags); + } + } + else + { + crWarning("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d", rc); + } + } +} + +void renderspuVBoxCompositorBlit ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter) +{ + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + CrVrScrCompositorConstIterInit(pCompositor, &CIter); + while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL) + { + uint32_t cRegions; + const RTRECT *paSrcRegions, *paDstRegions; + int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL); + uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry); + if (RT_SUCCESS(rc)) + { + const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CrBltBlitTexMural(pBlitter, true, CrTdTexGet(pTexData), paSrcRegions, paDstRegions, cRegions, fFlags); + } + else + { + crWarning("Blit: CrVrScrCompositorEntryRegionsGet failed rc %d", rc); + } + } +} + +void renderspuVBoxPresentBlitterCleanup( WindowInfo *window ) +{ + if (!window->pBlitter) + return; + + if (render_spu.blitterTable) + { + const CR_BLITTER_WINDOW * pBltInfo = CrBltMuralGetCurrentInfo(window->pBlitter); + if (pBltInfo && pBltInfo->Base.id == window->BltInfo.Base.id) + { + CrBltMuralSetCurrentInfo(window->pBlitter, NULL); + } + } + else + { + CRASSERT(CrBltMuralGetCurrentInfo(window->pBlitter)->Base.id == window->BltInfo.Base.id); + CrBltMuralSetCurrentInfo(window->pBlitter, NULL); + CrBltTerm(window->pBlitter); + } + window->pBlitter = NULL; +} + +PCR_BLITTER renderspuVBoxPresentBlitterGet( WindowInfo *window ) +{ + PCR_BLITTER pBlitter = window->pBlitter; + if (!pBlitter) + { + if (render_spu.blitterTable) + { + crHashtableLock(render_spu.blitterTable); + pBlitter = (PCR_BLITTER)crHashtableSearch(render_spu.blitterTable, window->visual->visAttribs); + } + + if (!pBlitter) + { + int rc; + ContextInfo * pDefaultCtxInfo; + + pBlitter = (PCR_BLITTER)crCalloc(sizeof (*pBlitter)); + if (!pBlitter) + { + crWarning("failed to allocate blitter"); + return NULL; + } + + pDefaultCtxInfo = renderspuDefaultSharedContextAcquire(); + if (!pDefaultCtxInfo) + { + crWarning("no default ctx info!"); + crFree(pBlitter); + return NULL; + } + + rc = CrBltInit(pBlitter, &pDefaultCtxInfo->BltInfo, true, true, NULL, &render_spu.blitterDispatch); + + /* we can release it either way, since it will be retained when used as a shared context */ + renderspuDefaultSharedContextRelease(pDefaultCtxInfo); + + if (!RT_SUCCESS(rc)) + { + crWarning("CrBltInit failed, rc %d", rc); + crFree(pBlitter); + return NULL; + } + + if (render_spu.blitterTable) + { + crHashtableAdd( render_spu.blitterTable, window->visual->visAttribs, pBlitter ); + } + } + + if (render_spu.blitterTable) + crHashtableUnlock(render_spu.blitterTable); + + Assert(pBlitter); + window->pBlitter = pBlitter; + } + + CrBltMuralSetCurrentInfo(pBlitter, &window->BltInfo); + return pBlitter; +} + +int renderspuVBoxPresentBlitterEnter( PCR_BLITTER pBlitter, int32_t i32MakeCurrentUserData) +{ + int rc; + + CrBltSetMakeCurrentUserData(pBlitter, i32MakeCurrentUserData); + + rc = CrBltEnter(pBlitter); + if (!RT_SUCCESS(rc)) + { + crWarning("CrBltEnter failed, rc %d", rc); + return rc; + } + return VINF_SUCCESS; +} + +PCR_BLITTER renderspuVBoxPresentBlitterGetAndEnter( WindowInfo *window, int32_t i32MakeCurrentUserData ) +{ + PCR_BLITTER pBlitter = renderspuVBoxPresentBlitterGet(window); + if (pBlitter) + { + int rc = renderspuVBoxPresentBlitterEnter(pBlitter, i32MakeCurrentUserData); + if (RT_SUCCESS(rc)) + { + return pBlitter; + } + } + return NULL; +} + +PCR_BLITTER renderspuVBoxPresentBlitterEnsureCreated( WindowInfo *window, int32_t i32MakeCurrentUserData ) +{ + if (!window->pBlitter) + { + const struct VBOXVR_SCR_COMPOSITOR * pTmpCompositor; + /* just use compositor lock to synchronize */ + pTmpCompositor = renderspuVBoxCompositorAcquire(window); + CRASSERT(pTmpCompositor); + if (pTmpCompositor) + { + PCR_BLITTER pBlitter = renderspuVBoxPresentBlitterGet( window ); + if (pBlitter) + { + if (!CrBltIsEverEntered(pBlitter)) + { + int rc = renderspuVBoxPresentBlitterEnter(pBlitter, i32MakeCurrentUserData); + if (RT_SUCCESS(rc)) + { + CrBltLeave(pBlitter); + } + else + { + crWarning("renderspuVBoxPresentBlitterEnter failed rc %d", rc); + } + } + } + else + { + crWarning("renderspuVBoxPresentBlitterGet failed"); + } + + renderspuVBoxCompositorRelease(window); + } + else + { + crWarning("renderspuVBoxCompositorAcquire failed"); + } + } + return window->pBlitter; +} + +void renderspuVBoxPresentCompositionGeneric( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry, int32_t i32MakeCurrentUserData ) +{ + PCR_BLITTER pBlitter = renderspuVBoxPresentBlitterGetAndEnter(window, i32MakeCurrentUserData); + if (!pBlitter) + return; + + renderspuVBoxCompositorBlit(pCompositor, pBlitter); + + renderspu_SystemSwapBuffers(window, 0); + + CrBltLeave(pBlitter); +} + +void renderspuVBoxCompositorSet( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor) +{ + int rc; + /* renderspuVBoxCompositorSet can be invoked from the chromium thread only and is not reentrant, + * no need to synch here + * the lock is actually needed to ensure we're in synch with the redraw thread */ + if (window->pCompositor == pCompositor) + return; + rc = RTCritSectEnter(&window->CompositorLock); + if (RT_SUCCESS(rc)) + { + window->pCompositor = pCompositor; + RTCritSectLeave(&window->CompositorLock); + return; + } + else + { + crWarning("RTCritSectEnter failed rc %d", rc); + } +} + +static void renderspuVBoxCompositorClearAllCB(unsigned long key, void *data1, void *data2) +{ + WindowInfo *window = (WindowInfo *) data1; + renderspuVBoxCompositorSet(window, NULL); +} + +void renderspuVBoxCompositorClearAll() +{ + /* we need to clear window compositor, which is not that trivial though, + * since the lock order used in presentation thread is compositor lock() -> hash table lock (aquired for id->window resolution) + * this is why, to prevent potential deadlocks, we use crHashtableWalkUnlocked that does not hold the table lock + * we are can be sure noone will modify the table here since renderspuVBoxCompositorClearAll can be called in the command (hgcm) thread only, + * and the table can be modified from that thread only as well */ + crHashtableWalkUnlocked(render_spu.windowTable, renderspuVBoxCompositorClearAllCB, NULL); +} + +const struct VBOXVR_SCR_COMPOSITOR * renderspuVBoxCompositorAcquire( WindowInfo *window) +{ + int rc = RTCritSectEnter(&window->CompositorLock); + if (RT_SUCCESS(rc)) + { + const VBOXVR_SCR_COMPOSITOR * pCompositor = window->pCompositor; + if (pCompositor) + return pCompositor; + + /* if no compositor is set, release the lock and return */ + RTCritSectLeave(&window->CompositorLock); + } + else + { + crWarning("RTCritSectEnter failed rc %d", rc); + } + return NULL; +} + +int renderspuVBoxCompositorLock(WindowInfo *window) +{ + int rc = RTCritSectEnter(&window->CompositorLock); + AssertRC(rc); + return rc; +} + +int renderspuVBoxCompositorUnlock(WindowInfo *window) +{ + int rc = RTCritSectLeave(&window->CompositorLock); + AssertRC(rc); + return rc; +} + +int renderspuVBoxCompositorTryAcquire(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor) +{ + int rc = RTCritSectTryEnter(&window->CompositorLock); + if (RT_SUCCESS(rc)) + { + *ppCompositor = window->pCompositor; + if (*ppCompositor) + return VINF_SUCCESS; + + /* if no compositor is set, release the lock and return */ + RTCritSectLeave(&window->CompositorLock); + rc = VERR_INVALID_STATE; + } + else + { + *ppCompositor = NULL; + } + return rc; +} + +void renderspuVBoxCompositorRelease( WindowInfo *window) +{ + int rc; + Assert(window->pCompositor); + if (CrVrScrCompositorIsEmpty(window->pCompositor) && RTCritSectGetRecursion(&window->CompositorLock) == 1) + window->pCompositor = NULL; + rc = RTCritSectLeave(&window->CompositorLock); + if (!RT_SUCCESS(rc)) + { + crWarning("RTCritSectLeave failed rc %d", rc); + } +} + /* * Set the current raster position to the given window coordinate. @@ -691,7 +1351,20 @@ static void RENDER_APIENTRY renderspuSemaphoreVCR( GLuint name ) /* * Misc functions */ +void renderspuSetDefaultSharedContext(ContextInfo *pCtx) +{ + if (pCtx == render_spu.defaultSharedContext) + return; + renderspu_SystemDefaultSharedContextChanged(render_spu.defaultSharedContext, pCtx); + + if (render_spu.defaultSharedContext) + renderspuContextRelease(render_spu.defaultSharedContext); + + if (pCtx) + renderspuContextRetain(pCtx); + render_spu.defaultSharedContext = pCtx; +} static void RENDER_APIENTRY renderspuChromiumParameteriCR(GLenum target, GLint value) @@ -699,9 +1372,17 @@ static void RENDER_APIENTRY renderspuChromiumParameteriCR(GLenum target, GLint v switch (target) { - case GL_HOST_WND_CREATED_HIDDEN: - render_spu.force_hidden_wdn_create = value ? GL_TRUE : GL_FALSE; + case GL_HH_SET_DEFAULT_SHARED_CTX: + { + ContextInfo * pCtx = NULL; + if (value) + pCtx = (ContextInfo *)crHashtableSearch(render_spu.contextTable, value); + else + crWarning("invalid default shared context id %d", value); + + renderspuSetDefaultSharedContext(pCtx); break; + } default: // crWarning("Unhandled target in renderspuChromiumParameteriCR()"); break; @@ -841,7 +1522,7 @@ renderspuChromiumParametervCR(GLenum target, GLenum type, GLsizei count, case GL_WINDOW_SIZE_CR: /* XXX this is old code that should be removed. - * NOTE: we can only resize the default (id=0) window!!! + * NOTE: we can only resize the default (id=CR_RENDER_DEFAULT_WINDOW_ID) window!!! */ { GLint w, h; @@ -851,7 +1532,7 @@ renderspuChromiumParametervCR(GLenum target, GLenum type, GLsizei count, CRASSERT(values); w = ((GLint*)values)[0]; h = ((GLint*)values)[1]; - window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, 0); + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID); if (window) { renderspu_SystemWindowSize(window, w, h); @@ -859,9 +1540,16 @@ renderspuChromiumParametervCR(GLenum target, GLenum type, GLsizei count, } break; + case GL_HH_SET_TMPCTX_MAKE_CURRENT: + if (type == GL_BYTE && count == sizeof (void*)) + memcpy(&render_spu.blitterDispatch.MakeCurrent, values, count); + else + WARN(("unexpected type(%#x) - count(%d) pair", type, count)); + break; + default: #if 0 - crWarning("Unhandled target in renderspuChromiumParametervCR(0x%x)", (int) target); + WARN(("Unhandled target in renderspuChromiumParametervCR(0x%x)", (int) target)); #endif break; } @@ -923,6 +1611,21 @@ renderspuGetChromiumParametervCR(GLenum target, GLuint index, GLenum type, } } break; + case GL_WINDOW_VISIBILITY_CR: + { + GLint *vis = (GLint *) values; + WindowInfo *window; + CRASSERT(type == GL_INT); + CRASSERT(count == 1); + CRASSERT(values); + vis[0] = 0; /* default */ + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index); + if (window) + { + vis[0] = window->visible; + } + } + break; default: ; /* nothing - silence compiler */ } @@ -1001,6 +1704,9 @@ renderspuGetString(GLenum pname) return NULL; } + if (!context) + return (const GLubyte *)nativeExt; + crExt = crStrjoin3(crExtensions, " ", crAppOnlyExtensions); s1 = crStrIntersect(nativeExt, crExt); remove_trailing_space(s1); @@ -1043,6 +1749,13 @@ renderspuGetString(GLenum pname) return NULL; } +static void renderspuReparentWindowCB(unsigned long key, void *data1, void *data2) +{ + WindowInfo *pWindow = (WindowInfo *)data1; + + renderspu_SystemReparentWindow(pWindow); +} + DECLEXPORT(void) renderspuReparentWindow(GLint window) { WindowInfo *pWindow; @@ -1057,46 +1770,13 @@ DECLEXPORT(void) renderspuReparentWindow(GLint window) } renderspu_SystemReparentWindow(pWindow); -} - -#if defined(DARWIN) -# ifdef VBOX_WITH_COCOA_QT -void renderspuFlush() -{ - renderspu_SystemFlush(); -} - -void renderspuFinish() -{ - renderspu_SystemFinish(); -} - -void renderspuBindFramebufferEXT(GLenum target, GLuint framebuffer) -{ - renderspu_SystemBindFramebufferEXT(target, framebuffer); -} -void renderspuCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) -{ - renderspu_SystemCopyPixels(x, y, width, height, type); -} - -void renderspuGetIntegerv(GLenum pname, GLint * params) -{ - renderspu_SystemGetIntegerv(pname, params); -} - -void renderspuDrawBuffer(GLenum mode) -{ - renderspu_SystemDrawBuffer(mode); -} - -void renderspuReadBuffer(GLenum mode) -{ - renderspu_SystemReadBuffer(mode); + /* special case: reparent all internal windows as well */ + if (window == CR_RENDER_DEFAULT_WINDOW_ID) + { + crHashtableWalk(render_spu.dummyWindowTable, renderspuReparentWindowCB, NULL); + } } -# endif -#endif #define FILLIN( NAME, FUNC ) \ table[i].name = crStrdup(NAME); \ @@ -1134,16 +1814,6 @@ renderspuCreateFunctions(SPUNamedFunctionTable table[]) FILLIN( "ChromiumParametervCR", renderspuChromiumParametervCR ); FILLIN( "GetChromiumParametervCR", renderspuGetChromiumParametervCR ); FILLIN( "GetString", renderspuGetString ); -#if defined(DARWIN) -# ifdef VBOX_WITH_COCOA_QT - FILLIN( "Flush", renderspuFlush ); - FILLIN( "Finish", renderspuFinish ); - FILLIN( "BindFramebufferEXT", renderspuBindFramebufferEXT ); - FILLIN( "CopyPixels", renderspuCopyPixels ); - FILLIN( "GetIntegerv", renderspuGetIntegerv ); - FILLIN( "ReadBuffer", renderspuReadBuffer ); - FILLIN( "DrawBuffer", renderspuDrawBuffer ); -# endif -#endif + FILLIN( "VBoxPresentComposition", renderspuVBoxPresentComposition ); return i; } diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu.h b/src/VBox/HostServices/SharedOpenGL/render/renderspu.h index d39af70d..1d7704c1 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu.h +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu.h @@ -27,8 +27,22 @@ #include "cr_spu.h" #include "cr_hash.h" #include "cr_server.h" +#include "cr_blitter.h" +#include "cr_compositor.h" #include <iprt/cdefs.h> +#include <iprt/critsect.h> +#if defined(GLX) /* @todo: unify windows and glx thread creation code */ +#include <iprt/thread.h> +#include <iprt/semaphore.h> + +/* special window id used for representing the command window CRWindowInfo */ +#define CR_RENDER_WINCMD_ID (INT32_MAX-2) +AssertCompile(CR_RENDER_WINCMD_ID != CR_RENDER_DEFAULT_WINDOW_ID); +/* CRHashTable is using unsigned long keys, we use it to trore X Window -> CRWindowInfo association */ +AssertCompile(sizeof (Window) == sizeof (unsigned long)); +#endif + #define MAX_VISUALS 32 @@ -76,19 +90,32 @@ typedef struct { /** * Window info */ -typedef struct { +typedef struct WindowInfo { int x, y; - int width, height; - int id; /**< integer window ID */ +// int width, height; +// int id; /**< integer window ID */ + CR_BLITTER_WINDOW BltInfo; + VisualInfo *visual; GLboolean mapPending; GLboolean visible; GLboolean everCurrent; /**< has this window ever been bound? */ + GLboolean fCompositorPresentEmpty; char *title; + + const VBOXVR_SCR_COMPOSITOR *pCompositor; + /* the composotor lock is used to synchronize the current compositor access, + * i.e. the compositor can be accessed by a gui refraw thread, + * while chromium thread might try to set a new compositor + * note that the compositor internally has its own lock to be used for accessing its data + * see CrVrScrCompositorLock/Unlock; renderspu and crserverlib would use it for compositor data access */ + RTCRITSECT CompositorLock; + PCR_BLITTER pBlitter; #if defined(WINDOWS) HDC nativeWindow; /**< for render_to_app_window */ HWND hWnd; HDC device_context; + HDC redraw_device_context; HRGN hRgn; #elif defined(DARWIN) # ifndef VBOX_WITH_COCOA_QT @@ -124,7 +151,8 @@ typedef struct { * Context Info */ typedef struct _ContextInfo { - int id; /**< integer context ID */ +// int id; /**< integer context ID */ + CR_BLITTER_CONTEXT BltInfo; VisualInfo *visual; GLboolean everCurrent; GLboolean haveWindowPosARB; @@ -142,6 +170,7 @@ typedef struct _ContextInfo { #endif struct _ContextInfo *shared; char *extensionString; + volatile uint32_t cRefs; } ContextInfo; /** @@ -152,6 +181,44 @@ typedef struct { GLuint count; } Barrier; +#ifdef GLX +typedef enum +{ + CR_RENDER_WINCMD_TYPE_UNDEFINED = 0, + /* create the window (not used for now) */ + CR_RENDER_WINCMD_TYPE_WIN_CREATE, + /* destroy the window (not used for now) */ + CR_RENDER_WINCMD_TYPE_WIN_DESTROY, + /* notify the WinCmd thread about window creation */ + CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE, + /* notify the WinCmd thread about window destroy */ + CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY, + /* nop used to synchronize with the WinCmd thread */ + CR_RENDER_WINCMD_TYPE_NOP, + /* exit Win Cmd thread */ + CR_RENDER_WINCMD_TYPE_EXIT, +} CR_RENDER_WINCMD_TYPE; + +typedef struct CR_RENDER_WINCMD +{ + /* command type */ + CR_RENDER_WINCMD_TYPE enmCmd; + /* command result */ + int rc; + /* valid for WIN_CREATE & WIN_DESTROY only */ + WindowInfo *pWindow; +} CR_RENDER_WINCMD, *PCR_RENDER_WINCMD; +#endif + +#ifdef RT_OS_DARWIN +typedef void (*PFNDELETE_OBJECT)(GLhandleARB obj); +typedef void (*PFNGET_ATTACHED_OBJECTS)( GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, GLhandleARB * obj ); +typedef GLhandleARB (*PFNGET_HANDLE)(GLenum pname); +typedef void (*PFNGET_INFO_LOG)( GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog ); +typedef void (*PFNGET_OBJECT_PARAMETERFV)( GLhandleARB obj, GLenum pname, GLfloat * params ); +typedef void (*PFNGET_OBJECT_PARAMETERIV)( GLhandleARB obj, GLenum pname, GLint * params ); +#endif + /** * Renderspu state info */ @@ -159,9 +226,6 @@ typedef struct { SPUDispatchTable self; int id; - unsigned int window_id; - unsigned int context_id; - /** config options */ /*@{*/ char *window_title; @@ -204,6 +268,10 @@ typedef struct { CRHashTable *windowTable; CRHashTable *contextTable; + CRHashTable *dummyWindowTable; + + ContextInfo *defaultSharedContext; + #ifndef CHROMIUM_THREADSAFE ContextInfo *currentContext; #endif @@ -217,6 +285,9 @@ typedef struct { char *swap_master_url; CRConnection **swap_conns; + SPUDispatchTable blitterDispatch; + CRHashTable *blitterTable; + #ifdef USE_OSMESA /** Off screen rendering hooks. */ int use_osmesa; @@ -230,13 +301,34 @@ typedef struct { void (*OSMesaDestroyContext)( OSMesaContext ctx ); #endif +#if defined(GLX) + RTTHREAD hWinCmdThread; + VisualInfo WinCmdVisual; + WindowInfo WinCmdWindow; + RTSEMEVENT hWinCmdCompleteEvent; + /* display connection used to send data to the WinCmd thread */ + Display *pCommunicationDisplay; + Atom WinCmdAtom; + /* X Window -> CRWindowInfo table */ + CRHashTable *pWinToInfoTable; +#endif + #ifdef RT_OS_WINDOWS DWORD dwWinThreadId; HANDLE hWinThreadReadyEvent; #endif #ifdef RT_OS_DARWIN -# ifndef VBOX_WITH_COCOA_QT +# ifdef VBOX_WITH_COCOA_QT + PFNDELETE_OBJECT pfnDeleteObject; + PFNGET_ATTACHED_OBJECTS pfnGetAttachedObjects; + PFNGET_HANDLE pfnGetHandle; + PFNGET_INFO_LOG pfnGetInfoLog; + PFNGET_OBJECT_PARAMETERFV pfnGetObjectParameterfv; + PFNGET_OBJECT_PARAMETERIV pfnGetObjectParameteriv; + + CR_GLSL_CACHE GlobalShaders; +# else RgnHandle hRootVisibleRegion; RTSEMFASTMUTEX syncMutex; EventHandlerUPP hParentEventHandler; @@ -247,8 +339,6 @@ typedef struct { bool fInit; # endif #endif /* RT_OS_DARWIN */ - - int force_hidden_wdn_create; } RenderSPU; #ifdef RT_OS_WINDOWS @@ -279,11 +369,22 @@ extern uint64_t render_spu_parent_window_id; #ifdef CHROMIUM_THREADSAFE extern CRtsd _RenderTSD; -#define GET_CONTEXT(T) ContextInfo *T = (ContextInfo *) crGetTSD(&_RenderTSD) +#define GET_CONTEXT_VAL() ((ContextInfo *) crGetTSD(&_RenderTSD)) +#define SET_CONTEXT_VAL(_v) do { \ + crSetTSD(&_RenderTSD, (_v)); \ + } while (0) #else -#define GET_CONTEXT(T) ContextInfo *T = render_spu.currentContext +#define GET_CONTEXT_VAL() (render_spu.currentContext) +#define SET_CONTEXT_VAL(_v) do { \ + render_spu.currentContext = (_v); \ + } while (0) + #endif +#define GET_CONTEXT(T) ContextInfo *T = GET_CONTEXT_VAL() + + +extern void renderspuSetDefaultSharedContext(ContextInfo *pCtx); extern void renderspuSetVBoxConfiguration( RenderSPU *spu ); extern void renderspuMakeVisString( GLbitfield visAttribs, char *s ); extern VisualInfo *renderspuFindVisual(const char *displayName, GLbitfield visAttribs ); @@ -297,26 +398,41 @@ extern void renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h ); extern void renderspu_SystemGetWindowGeometry( WindowInfo *window, GLint *x, GLint *y, GLint *w, GLint *h ); extern void renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h ); extern void renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y ); -extern void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, GLint* pRects); -extern void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window); -#ifdef RT_OS_DARWIN -extern void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects); -# ifdef VBOX_WITH_COCOA_QT -extern void renderspu_SystemFlush(); -extern void renderspu_SystemFinish(); -extern void renderspu_SystemBindFramebufferEXT(GLenum target, GLuint framebuffer); -extern void renderspu_SystemCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); -extern void renderspu_SystemGetIntegerv(GLenum pname, GLint *params); -extern void renderspu_SystemReadBuffer(GLenum mode); -extern void renderspu_SystemDrawBuffer(GLenum mode); -# endif -#endif +extern void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects); +extern int renderspu_SystemInit(); +extern int renderspu_SystemTerm(); +extern void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext); extern void renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt ); extern void renderspu_SystemMakeCurrent( WindowInfo *window, GLint windowInfor, ContextInfo *context ); extern void renderspu_SystemSwapBuffers( WindowInfo *window, GLint flags ); extern void renderspu_SystemReparentWindow(WindowInfo *window); +extern void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry ); +uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable); extern void renderspu_GCWindow(void); extern int renderspuCreateFunctions( SPUNamedFunctionTable table[] ); +extern void renderspuVBoxCompositorSet( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor); +extern void renderspuVBoxCompositorClearAll(); +extern int renderspuVBoxCompositorLock(WindowInfo *window); +extern int renderspuVBoxCompositorUnlock(WindowInfo *window); +extern const struct VBOXVR_SCR_COMPOSITOR * renderspuVBoxCompositorAcquire( WindowInfo *window); +extern int renderspuVBoxCompositorTryAcquire(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor); +extern void renderspuVBoxCompositorRelease( WindowInfo *window); +extern void renderspuVBoxPresentCompositionGeneric( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry, int32_t i32MakeCurrentUserData ); +extern PCR_BLITTER renderspuVBoxPresentBlitterGet( WindowInfo *window ); +void renderspuVBoxPresentBlitterCleanup( WindowInfo *window ); +extern int renderspuVBoxPresentBlitterEnter( PCR_BLITTER pBlitter, int32_t i32MakeCurrentUserData ); +extern PCR_BLITTER renderspuVBoxPresentBlitterGetAndEnter( WindowInfo *window, int32_t i32MakeCurrentUserData ); +extern PCR_BLITTER renderspuVBoxPresentBlitterEnsureCreated( WindowInfo *window, int32_t i32MakeCurrentUserData ); +extern void renderspuWindowTerm( WindowInfo *window ); +extern WindowInfo* renderspuGetDummyWindow(GLint visBits); +extern void renderspuPerformMakeCurrent(WindowInfo *window, GLint nativeWindow, ContextInfo *context); +extern GLboolean renderspuWindowInit(WindowInfo *pWindow, const char *dpyName, GLint visBits, GLint id); +extern GLboolean renderspuWindowInitWithVisual( WindowInfo *window, VisualInfo *visual, GLboolean showIt, GLint id ); +extern GLboolean renderspuInitVisual(VisualInfo *pVisInfo, const char *displayName, GLbitfield visAttribs); +extern void renderspuVBoxCompositorBlit ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter); +extern void renderspuVBoxCompositorBlitStretched ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter, GLfloat scaleX, GLfloat scaleY); +extern GLint renderspuCreateContextEx(const char *dpyName, GLint visBits, GLint id, GLint shareCtx); +extern GLint renderspuWindowCreateEx( const char *dpyName, GLint visBits, GLint id ); extern GLint RENDER_APIENTRY renderspuWindowCreate( const char *dpyName, GLint visBits ); void RENDER_APIENTRY renderspuWindowDestroy( GLint win ); @@ -324,11 +440,17 @@ extern GLint RENDER_APIENTRY renderspuCreateContext( const char *dpyname, GLint extern void RENDER_APIENTRY renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx); extern void RENDER_APIENTRY renderspuSwapBuffers( GLint window, GLint flags ); +extern uint32_t renderspuContextMarkDeletedAndRelease( ContextInfo *context ); + +ContextInfo * renderspuDefaultSharedContextAcquire(); +void renderspuDefaultSharedContextRelease(ContextInfo * pCtx); +uint32_t renderspuContextRelease(ContextInfo *context); +uint32_t renderspuContextRetain(ContextInfo *context); + #ifdef __cplusplus extern "C" { #endif DECLEXPORT(void) renderspuSetWindowId(uint64_t winId); -DECLEXPORT(void) renderspuSetRootVisibleRegion(GLint cRects, GLint *pRects); DECLEXPORT(void) renderspuReparentWindow(GLint window); #ifdef __cplusplus } diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c index 822e56b9..3d14fa3b 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c @@ -65,6 +65,9 @@ DEBUG_MSG_RESULT(result, text); \ } +static void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window); +static void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects); + /* In some case (like compiz which doesn't provide us with clipping regions) we * have to make sure that *all* open OpenGL windows are clipped to the main * application window. This is done here when called from the event handler @@ -340,7 +343,7 @@ renderspuWindowAttachContext(WindowInfo *wi, WindowRef window, if(!context || !wi) return render_spu.ws.aglSetCurrentContext( NULL ); -/* DEBUG_MSG_POETZSCH (("WindowAttachContext %d\n", wi->id));*/ +/* DEBUG_MSG_POETZSCH (("WindowAttachContext %d\n", wi->BltInfo.Base.id));*/ /* Flush old context first */ if (context->currentWindow->window != window) @@ -349,7 +352,7 @@ renderspuWindowAttachContext(WindowInfo *wi, WindowRef window, * dummy context. */ if (wi->bufferName == -1) { - DEBUG_MSG_POETZSCH (("WindowAttachContext: create context %d\n", wi->id)); + DEBUG_MSG_POETZSCH (("WindowAttachContext: create context %d\n", wi->BltInfo.Base.id)); /* Use the same visual bits as those in the context structure */ AGLPixelFormat pix; if( !renderspuChoosePixelFormat(context, &pix) ) @@ -519,10 +522,10 @@ renderspu_SystemWindowSize(WindowInfo *window, GLint w, GLint h) status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard); CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SendEventToEventTarget Failed"); - DEBUG_MSG_POETZSCH (("Size %d visible %d\n", window->id, IsWindowVisible (window->window))); + DEBUG_MSG_POETZSCH (("Size %d visible %d\n", window->BltInfo.Base.id, IsWindowVisible (window->window))); /* save the new size */ - window->width = w; - window->height = h; + window->BltInfo.width = w; + window->BltInfo.height = h; } void @@ -602,8 +605,11 @@ renderspu_SystemShowWindow(WindowInfo *window, GLboolean showIt) status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard); CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): PostEventToQueue Failed"); } - /* Save the new value */ - window->visible = showIt; +} + +void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry ) +{ + renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0); } void @@ -611,11 +617,13 @@ renderspu_SystemMakeCurrent(WindowInfo *window, GLint nativeWindow, ContextInfo *context) { Boolean result; -/* DEBUG_MSG_POETZSCH (("makecurrent %d: \n", window->id));*/ +/* DEBUG_MSG_POETZSCH (("makecurrent %d: \n", window->BltInfo.Base.id));*/ CRASSERT(render_spu.ws.aglSetCurrentContext); //crDebug( "renderspu_SystemMakeCurrent( %x, %i, %x )", window, nativeWindow, context ); + nativeWindow = 0; + if(window && context) { CRASSERT(window->window); @@ -669,7 +677,7 @@ renderspu_SystemSwapBuffers(WindowInfo *window, GLint flags) crError("Render SPU (renderspu_SystemSwapBuffers): SwapBuffers got a null context from the window"); RTSemFastMutexRequest(render_spu.syncMutex); -// DEBUG_MSG_POETZSCH (("Swapped %d context %x visible: %d\n", window->id, context->context, IsWindowVisible (window->window))); +// DEBUG_MSG_POETZSCH (("Swapped %d context %x visible: %d\n", window->BltInfo.Base.id, context->context, IsWindowVisible (window->window))); if (context->visual && context->visual->visAttribs & CR_DOUBLE_BIT) render_spu.ws.aglSwapBuffers(context->context); @@ -695,7 +703,7 @@ renderspu_SystemSwapBuffers(WindowInfo *window, GLint flags) } } -void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, GLint* pRects) +void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects) { CRASSERT(window); CRASSERT(window->window); @@ -730,7 +738,7 @@ void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, GLint renderspu_SystemWindowApplyVisibleRegion(window); } -void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects) +static void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects) { /* Remember the visible region of the root window if there is one */ if (render_spu.hRootVisibleRegion) @@ -757,7 +765,7 @@ void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects) } /*Assumes that all regions are in the guest coordinates system*/ -void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window) +static void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window) { ContextInfo *c = renderspuGetWindowContext(window); RgnHandle rgn; @@ -777,8 +785,8 @@ void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window) * currently process. */ SetRectRgn(rgn, window->x, window->y, - window->x + window->width, - window->y + window->height); + window->x + window->BltInfo.width, + window->y + window->BltInfo.height); SectRgn(render_spu.hRootVisibleRegion, rgn, rgn); /* Because the clipping is done in the coordinate space of the OpenGL * window we have to remove the x/y position from the newly created @@ -790,7 +798,7 @@ void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window) /* If there is not root clipping region is available, create a base * region with the size of the target window. This covers all * needed/possible space. */ - SetRectRgn(rgn, 0, 0, window->width, window->height); + SetRectRgn(rgn, 0, 0, window->BltInfo.width, window->BltInfo.height); } /* Now intersect the window clipping region with a additional region e.g. @@ -838,8 +846,8 @@ renderspu_SystemVBoxCreateWindow(VisualInfo *visual, GLboolean showIt, windowRect.left = window->x; windowRect.top = window->y; - windowRect.right = window->x + window->width; - windowRect.bottom = window->y + window->height; + windowRect.right = window->x + window->BltInfo.width; + windowRect.bottom = window->y + window->BltInfo.height; status = CreateNewWindow(winClass, winAttr, &windowRect, &window->window); CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): CreateNewWindow Failed", GL_FALSE); @@ -848,7 +856,7 @@ renderspu_SystemVBoxCreateWindow(VisualInfo *visual, GLboolean showIt, CFStringRef title_string; title_string = CFStringCreateWithCStringNoCopy(NULL, window->title, kCFStringEncodingMacRoman, NULL); - SetWindowTitleWithCFString(window->window, title_string); + SetWindowTitleWithCFString(window->BltInfo.window, title_string); CFRelease(title_string); /* The parent has to be in its own group */ @@ -873,8 +881,22 @@ renderspu_SystemVBoxCreateWindow(VisualInfo *visual, GLboolean showIt, renderspu_SystemShowWindow(window, GL_TRUE); crDebug("Render SPU (renderspu_SystemVBoxCreateWindow): actual window (x, y, width, height): %d, %d, %d, %d", - window->x, window->y, window->width, window->height); + window->x, window->y, window->BltInfo.width, window->BltInfo.height); return GL_TRUE; } +int renderspu_SystemInit() +{ + return VINF_SUCCESS; +} + +int renderspu_SystemTerm() +{ + return VINF_SUCCESS; +} + +void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext) +{ + +} diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c index a3b7b157..f9492a2d 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-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; @@ -21,6 +21,9 @@ #include <iprt/string.h> #include <iprt/path.h> +#include <cr_string.h> +#include <cr_mem.h> + GLboolean renderspu_SystemInitVisual(VisualInfo *pVisInfo) { CRASSERT(pVisInfo); @@ -82,7 +85,7 @@ GLboolean renderspu_SystemVBoxCreateWindow(VisualInfo *pVisInfo, GLboolean fShow NativeNSViewRef pParentWin = (NativeNSViewRef)(uint32_t)render_spu_parent_window_id; #endif /* __LP64__ */ - cocoaViewCreate(&pWinInfo->window, pParentWin, pVisInfo->visAttribs); + cocoaViewCreate(&pWinInfo->window, pWinInfo, pParentWin, pVisInfo->visAttribs); if (fShowIt) renderspu_SystemShowWindow(pWinInfo, fShowIt); @@ -151,15 +154,22 @@ void renderspu_SystemShowWindow(WindowInfo *pWinInfo, GLboolean fShowIt) cocoaViewShow(pWinInfo->window, fShowIt); } -void renderspu_SystemMakeCurrent(WindowInfo *pWinInfo, GLint nativeWindow, ContextInfo *pCtxInfo) +void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry ) { - CRASSERT(pWinInfo); - CRASSERT(pCtxInfo); + cocoaViewPresentComposition(window->window, pChangedEntry); +} +void renderspu_SystemMakeCurrent(WindowInfo *pWinInfo, GLint nativeWindow, ContextInfo *pCtxInfo) +{ /* if(pWinInfo->visual != pCtxInfo->visual)*/ /* printf ("visual mismatch .....................\n");*/ - cocoaViewMakeCurrentContext(pWinInfo->window, pCtxInfo->context); + nativeWindow = 0; + + if (pWinInfo && pCtxInfo) + cocoaViewMakeCurrentContext(pWinInfo->window, pCtxInfo->context); + else + cocoaViewMakeCurrentContext(NULL, NULL); } void renderspu_SystemSwapBuffers(WindowInfo *pWinInfo, GLint flags) @@ -169,53 +179,308 @@ void renderspu_SystemSwapBuffers(WindowInfo *pWinInfo, GLint flags) cocoaViewDisplay(pWinInfo->window); } -void renderspu_SystemWindowVisibleRegion(WindowInfo *pWinInfo, GLint cRects, GLint* paRects) +void renderspu_SystemWindowVisibleRegion(WindowInfo *pWinInfo, GLint cRects, const GLint* paRects) { CRASSERT(pWinInfo); cocoaViewSetVisibleRegion(pWinInfo->window, cRects, paRects); } -void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *paRects) +void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *pWinInfo) { } -void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *pWinInfo) +int renderspu_SystemInit() { + return VINF_SUCCESS; } -void renderspu_SystemFlush() +int renderspu_SystemTerm() { - cocoaFlush(); + CrGlslTerm(&render_spu.GlobalShaders); + return VINF_SUCCESS; } -void renderspu_SystemFinish() +static SPUNamedFunctionTable * renderspuFindEntry(SPUNamedFunctionTable *aFunctions, const char *pcszName) { - cocoaFinish(); + SPUNamedFunctionTable *pCur; + + for (pCur = aFunctions ; pCur->name != NULL ; pCur++) + { + if (!crStrcmp( pcszName, pCur->name ) ) + { + return pCur; + } + } + + AssertFailed(); + + return NULL; } -void renderspu_SystemBindFramebufferEXT(GLenum target, GLuint framebuffer) +typedef struct CR_RENDER_CTX_INFO { - cocoaBindFramebufferEXT(target, framebuffer); + ContextInfo * pContext; + WindowInfo * pWindow; +} CR_RENDER_CTX_INFO; + +void renderspuCtxInfoInitCurrent(CR_RENDER_CTX_INFO *pInfo) +{ + GET_CONTEXT(pCurCtx); + pInfo->pContext = pCurCtx; + pInfo->pWindow = pCurCtx->currentWindow; } -void renderspu_SystemCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) +void renderspuCtxInfoRestoreCurrent(CR_RENDER_CTX_INFO *pInfo) { - cocoaCopyPixels(x, y, width, height, type); + GET_CONTEXT(pCurCtx); + if (pCurCtx == pInfo->pContext && (!pCurCtx || pCurCtx->currentWindow == pInfo->pWindow)) + return; + renderspuPerformMakeCurrent(pInfo->pWindow, 0, pInfo->pContext); } -void renderspu_SystemGetIntegerv(GLenum pname, GLint * params) +GLboolean renderspuCtxSetCurrentWithAnyWindow(ContextInfo * pContext, CR_RENDER_CTX_INFO *pInfo) { - cocoaGetIntegerv(pname, params); + WindowInfo * window; + renderspuCtxInfoInitCurrent(pInfo); + + if (pInfo->pContext == pContext) + return GL_TRUE; + + window = pContext->currentWindow; + if (!window) + { + window = renderspuGetDummyWindow(pContext->BltInfo.Base.visualBits); + if (!window) + { + crWarning("renderspuGetDummyWindow failed"); + return GL_FALSE; + } + } + + Assert(window); + + renderspuPerformMakeCurrent(window, 0, pContext); + return GL_TRUE; } -void renderspu_SystemReadBuffer(GLenum mode) +void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext) { - cocoaReadBuffer(mode); + CRASSERT(fromContext != toContext); + + if (!CrGlslIsInited(&render_spu.GlobalShaders)) + { + CrGlslInit(&render_spu.GlobalShaders, &render_spu.blitterDispatch); + } + + if (fromContext) + { + if (CrGlslNeedsCleanup(&render_spu.GlobalShaders)) + { + CR_RENDER_CTX_INFO Info; + if (renderspuCtxSetCurrentWithAnyWindow(fromContext, &Info)) + { + CrGlslCleanup(&render_spu.GlobalShaders); + renderspuCtxInfoRestoreCurrent(&Info); + } + else + crWarning("renderspuCtxSetCurrentWithAnyWindow failed!"); + } + } + else + { + CRASSERT(!CrGlslNeedsCleanup(&render_spu.GlobalShaders)); + } + + CRASSERT(!CrGlslNeedsCleanup(&render_spu.GlobalShaders)); + + if (toContext) + { + CR_RENDER_CTX_INFO Info; + if (renderspuCtxSetCurrentWithAnyWindow(toContext, &Info)) + { + int rc = CrGlslProgGenAllNoAlpha(&render_spu.GlobalShaders); + if (!RT_SUCCESS(rc)) + crWarning("CrGlslProgGenAllNoAlpha failed, rc %d", rc); + + renderspuCtxInfoRestoreCurrent(&Info); + } + else + crWarning("renderspuCtxSetCurrentWithAnyWindow failed!"); + } +} + +AssertCompile(sizeof (GLhandleARB) == sizeof (void*)); + +static VBoxGLhandleARB crHndlSearchVBox(GLhandleARB hNative) +{ + CRASSERT(!(((uintptr_t)hNative) >> 32)); + return (VBoxGLhandleARB)((uintptr_t)hNative); +} + +static GLhandleARB crHndlSearchNative(VBoxGLhandleARB hVBox) +{ + return (GLhandleARB)((uintptr_t)hVBox); +} + +static VBoxGLhandleARB crHndlAcquireVBox(GLhandleARB hNative) +{ + CRASSERT(!(((uintptr_t)hNative) >> 32)); + return (VBoxGLhandleARB)((uintptr_t)hNative); } -void renderspu_SystemDrawBuffer(GLenum mode) +static GLhandleARB crHndlReleaseVBox(VBoxGLhandleARB hVBox) { - cocoaDrawBuffer(mode); + return (GLhandleARB)((uintptr_t)hVBox); } +static void SPU_APIENTRY renderspu_SystemDeleteObjectARB(VBoxGLhandleARB obj) +{ + GLhandleARB hNative = crHndlReleaseVBox(obj); + if (!hNative) + { + crWarning("no native for %d", obj); + return; + } + + render_spu.pfnDeleteObject(hNative); +} + +static void SPU_APIENTRY renderspu_SystemGetAttachedObjectsARB( VBoxGLhandleARB containerObj, GLsizei maxCount, GLsizei * pCount, VBoxGLhandleARB * obj ) +{ + GLhandleARB *paAttachments; + GLhandleARB hNative = crHndlSearchNative(containerObj); + GLsizei count, i; + + if (pCount) + *pCount = 0; + + if (!hNative) + { + crWarning("no native for %d", obj); + return; + } + + paAttachments = crCalloc(maxCount * sizeof (*paAttachments)); + if (!paAttachments) + { + crWarning("crCalloc failed"); + return; + } + + render_spu.pfnGetAttachedObjects(hNative, maxCount, &count, paAttachments); + if (pCount) + *pCount = count; + if (count > maxCount) + { + crWarning("count too big"); + count = maxCount; + } + + for (i = 0; i < count; ++i) + { + obj[i] = crHndlSearchVBox(paAttachments[i]); + CRASSERT(obj[i]); + } + + crFree(paAttachments); +} + +static VBoxGLhandleARB SPU_APIENTRY renderspu_SystemGetHandleARB(GLenum pname) +{ + GLhandleARB hNative = render_spu.pfnGetHandle(pname); + VBoxGLhandleARB hVBox; + if (!hNative) + { + crWarning("pfnGetHandle failed"); + return 0; + } + hVBox = crHndlAcquireVBox(hNative); + CRASSERT(hVBox); + return hVBox; +} + +static void SPU_APIENTRY renderspu_SystemGetInfoLogARB( VBoxGLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog ) +{ + GLhandleARB hNative = crHndlSearchNative(obj); + if (!hNative) + { + crWarning("invalid handle!"); + return; + } + + render_spu.pfnGetInfoLog(hNative, maxLength, length, infoLog); +} + +static void SPU_APIENTRY renderspu_SystemGetObjectParameterfvARB( VBoxGLhandleARB obj, GLenum pname, GLfloat * params ) +{ + GLhandleARB hNative = crHndlSearchNative(obj); + if (!hNative) + { + crWarning("invalid handle!"); + return; + } + + render_spu.pfnGetObjectParameterfv(hNative, pname, params); +} + +static void SPU_APIENTRY renderspu_SystemGetObjectParameterivARB( VBoxGLhandleARB obj, GLenum pname, GLint * params ) +{ + GLhandleARB hNative = crHndlSearchNative(obj); + if (!hNative) + { + crWarning("invalid handle!"); + return; + } + + render_spu.pfnGetObjectParameteriv(hNative, pname, params); +} + +uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable) +{ + SPUNamedFunctionTable * pEntry; + + pEntry = renderspuFindEntry(aFunctions, "DeleteObjectARB"); + if (pEntry) + { + render_spu.pfnDeleteObject = (PFNDELETE_OBJECT)pEntry->fn; + pEntry->fn = (SPUGenericFunction)renderspu_SystemDeleteObjectARB; + } + + pEntry = renderspuFindEntry(aFunctions, "GetAttachedObjectsARB"); + if (pEntry) + { + render_spu.pfnGetAttachedObjects = (PFNGET_ATTACHED_OBJECTS)pEntry->fn; + pEntry->fn = (SPUGenericFunction)renderspu_SystemGetAttachedObjectsARB; + } + + pEntry = renderspuFindEntry(aFunctions, "GetHandleARB"); + if (pEntry) + { + render_spu.pfnGetHandle = (PFNGET_HANDLE)pEntry->fn; + pEntry->fn = (SPUGenericFunction)renderspu_SystemGetHandleARB; + } + + pEntry = renderspuFindEntry(aFunctions, "GetInfoLogARB"); + if (pEntry) + { + render_spu.pfnGetInfoLog = (PFNGET_INFO_LOG)pEntry->fn; + pEntry->fn = (SPUGenericFunction)renderspu_SystemGetInfoLogARB; + } + + pEntry = renderspuFindEntry(aFunctions, "GetObjectParameterfvARB"); + if (pEntry) + { + render_spu.pfnGetObjectParameterfv = (PFNGET_OBJECT_PARAMETERFV)pEntry->fn; + pEntry->fn = (SPUGenericFunction)renderspu_SystemGetObjectParameterfvARB; + } + + pEntry = renderspuFindEntry(aFunctions, "GetObjectParameterivARB"); + if (pEntry) + { + render_spu.pfnGetObjectParameteriv = (PFNGET_OBJECT_PARAMETERIV)pEntry->fn; + pEntry->fn = (SPUGenericFunction)renderspu_SystemGetObjectParameterivARB; + } + + return cFunctions; +} diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h index 2380f289..546f98b6 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009-2011 Oracle Corporation + * Copyright (C) 2009-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; @@ -21,9 +21,14 @@ #include <iprt/cdefs.h> #include <VBox/VBoxCocoa.h> #include <OpenGL/OpenGL.h> +#include <cr_vreg.h> +#include <cr_compositor.h> + RT_C_DECLS_BEGIN +struct WindowInfo; + ADD_COCOA_NATIVE_REF(NSView); ADD_COCOA_NATIVE_REF(NSOpenGLContext); @@ -32,7 +37,7 @@ void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, Na void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx); /* View management */ -void cocoaViewCreate(NativeNSViewRef *ppView, NativeNSViewRef pParentView, GLbitfield fVisParams); +void cocoaViewCreate(NativeNSViewRef *ppView, struct WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams); void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView); void cocoaViewDestroy(NativeNSViewRef pView); void cocoaViewDisplay(NativeNSViewRef pView); @@ -42,16 +47,8 @@ void cocoaViewSetSize(NativeNSViewRef pView, int w, int h); void cocoaViewGetGeometry(NativeNSViewRef pView, int *pX, int *pY, int *pW, int *pH); void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx); -void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, GLint* paRects); - -/* OpenGL wrapper */ -void cocoaFlush(void); -void cocoaFinish(void); -void cocoaBindFramebufferEXT(GLenum target, GLuint framebuffer); -void cocoaCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); -void cocoaGetIntegerv(GLenum pname, GLint *params); -void cocoaReadBuffer(GLenum mode); -void cocoaDrawBuffer(GLenum mode); +void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint* paRects); +void cocoaViewPresentComposition(NativeNSViewRef pView, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry); RT_C_DECLS_END diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m index eb2e5787..db2c00c8 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009-2011 Oracle Corporation + * Copyright (C) 2009-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; @@ -18,6 +18,7 @@ #include "renderspu_cocoa_helper.h" #import <Cocoa/Cocoa.h> +#undef PVM #include "chromium.h" /* For the visual bits of chromium */ @@ -25,6 +26,17 @@ #include <iprt/string.h> #include <iprt/mem.h> #include <iprt/time.h> +#include <iprt/assert.h> + +#include <cr_vreg.h> +#include <cr_error.h> +#include <cr_blitter.h> +#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL +# include <cr_pixeldata.h> +#endif + + +#include "renderspu.h" /** @page pg_opengl_cocoa OpenGL - Cocoa Window System Helper * @@ -74,6 +86,7 @@ /* Debug macros */ #define FBO 1 /* Disable this to see how the output is without the FBO in the middle of the processing chain. */ #if 0 +# define CR_RENDER_FORCE_PRESENT_MAIN_THREAD /* force present schedule to main thread */ # define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */ # define DEBUG_VERBOSE /* Define this to get some debug info about the messages flow. */ #endif @@ -81,9 +94,16 @@ #ifdef DEBUG_misha # define DEBUG_MSG(text) \ printf text +# define DEBUG_WARN(text) do { \ + crWarning text ; \ + Assert(0); \ + } while (0) #else # define DEBUG_MSG(text) \ do {} while (0) +# define DEBUG_WARN(text) do { \ + crWarning text ; \ + } while (0) #endif #ifdef DEBUG_VERBOSE @@ -159,6 +179,114 @@ } \ while(0); +static NSOpenGLContext * vboxCtxGetCurrent() +{ + GET_CONTEXT(pCtxInfo); + if (pCtxInfo) + { + Assert(pCtxInfo->context); + return pCtxInfo->context; + } + + return nil; +} + +static bool vboxCtxSyncCurrentInfo() +{ + GET_CONTEXT(pCtxInfo); + NSOpenGLContext *pCtx = [NSOpenGLContext currentContext]; + NSView *pView = pCtx ? [pCtx view] : nil; + bool fAdjusted = false; + if (pCtxInfo) + { + WindowInfo *pWinInfo = pCtxInfo->currentWindow; + Assert(pWinInfo); + if (pCtxInfo->context != pCtx + || pWinInfo->window != pView) + { + renderspu_SystemMakeCurrent(pWinInfo, 0, pCtxInfo); + fAdjusted = true; + } + } + else + { + if (pCtx) + { + [NSOpenGLContext clearCurrentContext]; + fAdjusted = true; + } + } + + return fAdjusted; +} + +typedef struct VBOX_CR_RENDER_CTX_INFO +{ + bool fIsValid; + NSOpenGLContext *pCtx; + NSView *pView; +} VBOX_CR_RENDER_CTX_INFO, *PVBOX_CR_RENDER_CTX_INFO; + +static void vboxCtxEnter(NSOpenGLContext*pCtx, PVBOX_CR_RENDER_CTX_INFO pCtxInfo) +{ + NSOpenGLContext *pOldCtx = vboxCtxGetCurrent(); + NSView *pOldView = (pOldCtx ? [pOldCtx view] : nil); + NSView *pView = [pCtx view]; + bool fNeedCtxSwitch = (pOldCtx != pCtx || pOldView != pView); + Assert(pCtx); + // Assert(pOldCtx == m_pGLCtx); + // Assert(pOldView == self); + // Assert(fNeedCtxSwitch); + if (fNeedCtxSwitch) + { + if(pOldCtx != nil) + glFlush(); + + [pCtx makeCurrentContext]; + + pCtxInfo->fIsValid = true; + pCtxInfo->pCtx = pOldCtx; + pCtxInfo->pView = pView; + } + else + { + pCtxInfo->fIsValid = false; + } +} + +static void vboxCtxLeave(PVBOX_CR_RENDER_CTX_INFO pCtxInfo) +{ + if (pCtxInfo->fIsValid) + { + NSOpenGLContext *pOldCtx = pCtxInfo->pCtx; + NSView *pOldView = pCtxInfo->pView; + + glFlush(); + if (pOldCtx != nil) + { + if ([pOldCtx view] != pOldView) + { + [pOldCtx setView: pOldView]; + } + + [pOldCtx makeCurrentContext]; + +#ifdef DEBUG + { + NSOpenGLContext *pTstOldCtx = [NSOpenGLContext currentContext]; + NSView *pTstOldView = (pTstOldCtx ? [pTstOldCtx view] : nil); + Assert(pTstOldCtx == pOldCtx); + Assert(pTstOldView == pOldView); + } +#endif + } + else + { + [NSOpenGLContext clearCurrentContext]; + } + } +} + /** Custom OpenGL context class. * * This implementation doesn't allow to set a view to the @@ -193,25 +321,12 @@ NSOpenGLContext *m_pSharedGLCtx; RTTHREAD mThread; -#ifdef FBO GLuint m_FBOId; - /* FBO handling */ - GLuint m_FBOTexBackId; - GLuint m_FBOTexFrontId; - GLuint m_FBOAttBackId; - GLuint m_FBOAttFrontId; - GLuint m_FBODepthStencilPackedId; - NSSize m_FBOTexSize; - - bool m_fFrontDrawing; -#endif /** The corresponding dock tile view of this OpenGL view & all helper * members. */ DockOverlayView *m_DockTileView; - GLuint m_FBOThumbId; - GLuint m_FBOThumbTexId; GLfloat m_FBOThumbScaleX; GLfloat m_FBOThumbScaleY; uint64_t m_uiDockUpdateTime; @@ -225,9 +340,17 @@ NSSize m_Size; /** This is necessary for clipping on the root window */ - NSPoint m_RootShift; -} -- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView; + NSRect m_RootRect; + float m_yInvRootOffset; + + CR_BLITTER *m_pBlitter; + WindowInfo *m_pWinInfo; + bool m_fNeedViewportUpdate; + bool m_fNeedCtxUpdate; + bool m_fDataVisible; + bool m_fEverSized; +} +- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView winInfo:(WindowInfo*)pWinInfo; - (void)setGLCtx:(NSOpenGLContext*)pCtx; - (NSOpenGLContext*)glCtx; @@ -238,28 +361,30 @@ - (void)setPos:(NSPoint)pos; - (NSPoint)pos; +- (bool)isEverSized; - (void)setSize:(NSSize)size; - (NSSize)size; -- (void)updateViewport; -- (void)reshape; +- (void)updateViewportCS; +- (void)vboxReshapePerform; +- (void)vboxReshapeOnResizePerform; +- (void)vboxReshapeOnReparentPerform; -- (void)createFBO; -- (void)deleteFBO; +- (void)createDockTile; +- (void)deleteDockTile; -- (bool)isCurrentFBO; -- (void)updateFBO; - (void)makeCurrentFBO; - (void)swapFBO; -- (void)flushFBO; -- (void)stateInfo:(GLenum)pname withParams:(GLint*)params; -- (void)finishFBO; -- (void)bindFBO:(GLenum)target withFrameBuffer:(GLuint)framebuffer; -- (void)tryDraw; -- (void)renderFBOToView; -- (void)renderFBOToDockTile; +- (void)vboxTryDraw; +- (void)vboxTryDrawUI; +- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR*)pCompositor; +- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor; +- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor; +- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor; +- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY*)pChangedEntry; +- (void)vboxBlitterSyncWindow; - (void)clearVisibleRegions; -- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects; +- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint*)paRects; - (NSView*)dockTileScreen; - (void)reshapeDockTile; @@ -465,7 +590,7 @@ { DEBUG_MSG(("OCTX(%p): setView: new view: %p\n", (void*)self, (void*)view)); -#ifdef FBO +#if 1 /* def FBO */ m_pView = view;; #else [super setView: view]; @@ -474,7 +599,7 @@ -(NSView*)view { -#ifdef FBO +#if 1 /* def FBO */ return m_pView; #else return [super view]; @@ -597,10 +722,16 @@ /* Reposition this window with the help of the OverlayView. Perform the * call in the OpenGL thread. */ /* - [m_pOverlayView performSelector:@selector(reshape) onThread:m_Thread withObject:nil waitUntilDone:YES]; + [m_pOverlayView performSelector:@selector(vboxReshapePerform) onThread:m_Thread withObject:nil waitUntilDone:YES]; */ - [m_pOverlayView reshape]; + if ([m_pOverlayView isEverSized]) + { + if([NSThread isMainThread]) + [m_pOverlayView vboxReshapePerform]; + else + [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO]; + } } - (void)parentWindowChanged:(NSWindow*)pWindow @@ -622,10 +753,17 @@ /* Reshape the overlay view after a short waiting time to let the main * window resize itself properly. */ /* - [m_pOverlayView performSelector:@selector(reshape) withObject:nil afterDelay:0.2]; - [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(reshape) userInfo:nil repeats:NO]; + [m_pOverlayView performSelector:@selector(vboxReshapePerform) withObject:nil afterDelay:0.2]; + [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(vboxReshapePerform) userInfo:nil repeats:NO]; */ - [m_pOverlayView reshape]; + + if ([m_pOverlayView isEverSized]) + { + if([NSThread isMainThread]) + [m_pOverlayView vboxReshapePerform]; + else + [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO]; + } } } @@ -638,30 +776,27 @@ ********************************************************************************/ @implementation OverlayView -- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView +- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView winInfo:(WindowInfo*)pWinInfo { m_pParentView = pParentView; /* Make some reasonable defaults */ m_pGLCtx = nil; m_pSharedGLCtx = nil; mThread = aThread; -#ifdef FBO m_FBOId = 0; - m_FBOTexBackId = 0; - m_FBOTexFrontId = 0; - m_FBOAttBackId = GL_COLOR_ATTACHMENT0_EXT; - m_FBOAttFrontId = GL_COLOR_ATTACHMENT1_EXT; - m_FBODepthStencilPackedId = 0; - m_FBOTexSize = NSZeroSize; -#endif - m_FBOThumbId = 0; - m_FBOThumbTexId = 0; m_cClipRects = 0; m_paClipRects = NULL; m_Pos = NSZeroPoint; m_Size = NSMakeSize(1, 1); - m_RootShift = NSZeroPoint; - + m_RootRect = NSMakeRect(0, 0, m_Size.width, m_Size.height); + m_yInvRootOffset = 0; + m_pBlitter = nil; + m_pWinInfo = pWinInfo; + m_fNeedViewportUpdate = true; + m_fNeedCtxUpdate = true; + m_fDataVisible = false; + m_fEverSized = false; + self = [super initWithFrame:frame]; DEBUG_MSG(("OVIW(%p): init OverlayView\n", (void*)self)); @@ -671,15 +806,10 @@ - (void)cleanupData { - [self deleteFBO]; - - if (m_pGLCtx) - { - if ([m_pGLCtx view] == self) - [m_pGLCtx clearDrawable]; - - m_pGLCtx = nil; - } + [self deleteDockTile]; + + [self setGLCtx:nil]; + if (m_pSharedGLCtx) { if ([m_pSharedGLCtx view] == self) @@ -688,6 +818,12 @@ [m_pSharedGLCtx release]; m_pSharedGLCtx = nil; + + CrBltTerm(m_pBlitter); + + RTMemFree(m_pBlitter); + + m_pBlitter = nil; } [self clearVisibleRegions]; @@ -704,7 +840,7 @@ - (void)drawRect:(NSRect)aRect { - /* Do nothing */ + [self vboxTryDrawUI]; } - (void)setGLCtx:(NSOpenGLContext*)pCtx @@ -715,9 +851,15 @@ /* ensure the context drawable is cleared to avoid holding a reference to inexistent view */ if (m_pGLCtx) + { [m_pGLCtx clearDrawable]; + [m_pGLCtx release]; + /*[m_pGLCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/ + } m_pGLCtx = pCtx; + if (pCtx) + [pCtx retain]; } - (NSOpenGLContext*)glCtx @@ -755,7 +897,16 @@ m_Pos = pos; - [self reshape]; + if (m_fEverSized) + [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO]; + + /* we need to redwar on regions change, however the compositor now is cleared + * because all compositor&window data-related modifications are performed with compositor cleared + * the renderspu client will re-set the compositor after modifications are complete + * this way we indicate renderspu generic code not to ignore the empty compositor */ + /* generally this should not be needed for setPos because compositor should not be zeroed with it, + * in any way setting this flag here should not hurt as it will be re-set on next present */ + m_pWinInfo->fCompositorPresentEmpty = GL_TRUE; } - (NSPoint)pos @@ -763,26 +914,29 @@ return m_Pos; } +- (bool)isEverSized +{ + return m_fEverSized; +} + - (void)setSize:(NSSize)size { + NSOpenGLContext *pCurCtx; + NSView *pCurView; m_Size = size; + + m_fEverSized = true; -#ifdef FBO - if (m_FBOId) - { - DEBUG_MSG(("OVIW(%p): setSize: new size: %dx%d\n", (void*)self, (int)size.width, (int)size.height)); - [self reshape]; - [self updateFBO]; - /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */ - [self updateViewport]; - } - else -#endif - { - DEBUG_MSG(("OVIW(%p): setSize (no FBO): new size: %dx%d\n", (void*)self, (int)size.width, (int)size.height)); - [self reshape]; - [self updateFBO]; - } + DEBUG_MSG(("OVIW(%p): setSize: new size: %dx%d\n", (void*)self, (int)size.width, (int)size.height)); + [self performSelectorOnMainThread:@selector(vboxReshapeOnResizePerform) withObject:nil waitUntilDone:NO]; + + /* we need to redwar on regions change, however the compositor now is cleared + * because all compositor&window data-related modifications are performed with compositor cleared + * the renderspu client will re-set the compositor after modifications are complete + * this way we indicate renderspu generic code not to ignore the empty compositor */ + /* generally this should not be needed for setSize because compositor should not be zeroed with it, + * in any way setting this flag here should not hurt as it will be re-set on next present */ + m_pWinInfo->fCompositorPresentEmpty = GL_TRUE; } - (NSSize)size @@ -790,44 +944,47 @@ return m_Size; } -- (void)updateViewport +- (void)updateViewportCS { - NSRect r; - DEBUG_MSG(("OVIW(%p): updateViewport\n", (void*)self)); -#ifdef FBO - if (m_pSharedGLCtx) + /* Update the viewport for our OpenGL view */ + [m_pSharedGLCtx update]; + + [self vboxBlitterSyncWindow]; + + /* Clear background to transparent */ + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); +} + +- (void)vboxReshapeOnResizePerform +{ + [self vboxReshapePerform]; + + [self createDockTile]; + /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */ + m_fNeedViewportUpdate = true; +#if 0 + pCurCtx = [NSOpenGLContext currentContext]; + if (pCurCtx && pCurCtx == m_pGLCtx && (pCurView = [pCurCtx view]) == self) + { + [m_pGLCtx update]; + m_fNeedCtxUpdate = false; + } + else { - /* Update the viewport for our OpenGL view */ - DEBUG_MSG(("OVIW(%p): makeCurrent (shared) %p\n", (void*)self, (void*)m_pSharedGLCtx)); - [m_pSharedGLCtx makeCurrentContext]; - [m_pSharedGLCtx update]; - - r = [self frame]; - /* Setup all matrices */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glViewport(0, 0, r.size.width, r.size.height); - glOrtho(0, r.size.width, 0, r.size.height, -1, 1); - DEBUG_MSG_1(("OVIW(%p): frame[%i, %i, %i, %i]\n", (void*)self, (int)r.origin.x, (int)r.origin.x, (int)r.size.width, (int)r.size.height)); - DEBUG_MSG_1(("OVIW(%p): m_Pos(%i,%i) m_Size(%i,%i)\n", (void*)self, (int)m_Pos.x, (int)m_Pos.y, (int)m_Size.width, (int)m_Size.height)); - DEBUG_MSG_1(("OVIW(%p): m_RootShift(%i, %i)\n", (void*)self, (int)m_RootShift.x, (int)m_RootShift.y)); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - /* Clear background to transparent */ - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - DEBUG_MSG(("OVIW(%p): makeCurrent (non shared) %p\n", (void*)self, (void*)m_pGLCtx)); - [m_pGLCtx makeCurrentContext]; + /* do it in a lazy way */ + m_fNeedCtxUpdate = true; } #endif } -- (void)reshape +- (void)vboxReshapeOnReparentPerform +{ + [self createDockTile]; +} + +- (void)vboxReshapePerform { NSRect parentFrame = NSZeroRect; NSPoint parentPos = NSZeroPoint; @@ -835,38 +992,60 @@ NSRect childFrame = NSZeroRect; NSRect newFrame = NSZeroRect; - DEBUG_MSG(("OVIW(%p): reshape\n", (void*)self)); - - /* Getting the right screen coordinates of the parents frame is a little bit - * complicated. */ + DEBUG_MSG(("OVIW(%p): vboxReshapePerform\n", (void*)self)); + parentFrame = [m_pParentView frame]; - parentPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:NSMakePoint(parentFrame.origin.x, parentFrame.origin.y + parentFrame.size.height)]]; - parentFrame.origin.x = parentPos.x; - parentFrame.origin.y = parentPos.y; - - /* Calculate the new screen coordinates of the overlay window. */ + DEBUG_MSG(("FIXED parentFrame [%f:%f], [%f:%f]\n", parentFrame.origin.x, parentFrame.origin.y, parentFrame.size.width, parentFrame.size.height)); + parentPos = parentFrame.origin; + parentPos.y += parentFrame.size.height; + DEBUG_MSG(("FIXED(view) parentPos [%f:%f]\n", parentPos.x, parentPos.y)); + parentPos = [m_pParentView convertPoint:parentPos toView:nil]; + DEBUG_MSG(("FIXED parentPos(win) [%f:%f]\n", parentPos.x, parentPos.y)); + parentPos = [[m_pParentView window] convertBaseToScreen:parentPos]; + DEBUG_MSG(("FIXED parentPos(screen) [%f:%f]\n", parentPos.x, parentPos.y)); + parentFrame.origin = parentPos; + childPos = NSMakePoint(m_Pos.x, m_Pos.y + m_Size.height); - childPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:childPos]]; - - /* Make a frame out of it. */ + DEBUG_MSG(("FIXED(view) childPos [%f:%f]\n", childPos.x, childPos.y)); + childPos = [m_pParentView convertPoint:childPos toView:nil]; + DEBUG_MSG(("FIXED(win) childPos [%f:%f]\n", childPos.x, childPos.y)); + childPos = [[m_pParentView window] convertBaseToScreen:childPos]; + DEBUG_MSG(("FIXED childPos(screen) [%f:%f]\n", childPos.x, childPos.y)); childFrame = NSMakeRect(childPos.x, childPos.y, m_Size.width, m_Size.height); + DEBUG_MSG(("FIXED childFrame [%f:%f], [%f:%f]\n", childFrame.origin.x, childFrame.origin.y, childFrame.size.width, childFrame.size.height)); /* We have to make sure that the overlay window will not be displayed out * of the parent window. So intersect both frames & use the result as the new * frame for the window. */ newFrame = NSIntersectionRect(parentFrame, childFrame); - /* Later we have to correct the texture position in the case the window is - * out of the parents window frame. So save the shift values for later use. */ - if (parentFrame.origin.x > childFrame.origin.x) - m_RootShift.x = parentFrame.origin.x - childFrame.origin.x; - else - m_RootShift.x = 0; - if (parentFrame.origin.y > childFrame.origin.y) - m_RootShift.y = parentFrame.origin.y - childFrame.origin.y; - else - m_RootShift.y = 0; + DEBUG_MSG(("[%#p]: parentFrame pos[%f : %f] size[%f : %f]\n", + (void*)self, + parentFrame.origin.x, parentFrame.origin.y, + parentFrame.size.width, parentFrame.size.height)); + DEBUG_MSG(("[%#p]: childFrame pos[%f : %f] size[%f : %f]\n", + (void*)self, + childFrame.origin.x, childFrame.origin.y, + childFrame.size.width, childFrame.size.height)); + + DEBUG_MSG(("[%#p]: newFrame pos[%f : %f] size[%f : %f]\n", + (void*)self, + newFrame.origin.x, newFrame.origin.y, + newFrame.size.width, newFrame.size.height)); + /* Later we have to correct the texture position in the case the window is + * out of the parents window frame. So save the shift values for later use. */ + m_RootRect.origin.x = newFrame.origin.x - childFrame.origin.x; + m_RootRect.origin.y = childFrame.size.height + childFrame.origin.y - (newFrame.size.height + newFrame.origin.y); + m_RootRect.size = newFrame.size; + m_yInvRootOffset = newFrame.origin.y - childFrame.origin.y; + + DEBUG_MSG(("[%#p]: m_RootRect pos[%f : %f] size[%f : %f]\n", + (void*)self, + m_RootRect.origin.x, m_RootRect.origin.y, + m_RootRect.size.width, m_RootRect.size.height)); + + /* NSScrollView *pScrollView = [[[m_pParentView window] contentView] enclosingScrollView]; if (pScrollView) @@ -888,220 +1067,37 @@ [self reshapeDockTile]; /* Make sure the context is updated according */ - [self updateViewport]; -} - -- (void)createFBO -{ - GLint oldTexId = 0; - GLint oldFBId = 0; - NSView *pDockScreen = nil; - GLint maxTexSize = 0; - GLfloat imageAspectRatio = 0; - GLint filter = GL_NEAREST; - - [self deleteFBO]; - -#ifdef FBO - DEBUG_MSG(("OVIW(%p): createFBO\n", (void*)self)); - - glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &oldTexId); - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &oldFBId); - - /* If not previously setup generate IDs for FBO and its associated texture. */ - if (!m_FBOId) - { - /* Make sure the framebuffer extension is supported */ - const GLubyte* strExt; - GLboolean isFBO; - /* Get the extension name string. It is a space-delimited list of the - * OpenGL extensions that are supported by the current renderer. */ - strExt = glGetString(GL_EXTENSIONS); - isFBO = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_object", strExt); - if (!isFBO) - { - DEBUG_MSG(("Your system does not support the GL_EXT_framebuffer_object extension\n")); - } - isFBO = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_blit", strExt); - if (!isFBO) - { - DEBUG_MSG(("Your system does not support the GL_EXT_framebuffer_blit extension\n")); - } - - /* Create FBO object */ - glGenFramebuffersEXT(1, &m_FBOId); - /* & the texture as well the depth/stencil render buffer */ - glGenTextures(1, &m_FBOTexBackId); - glGenTextures(1, &m_FBOTexFrontId); - DEBUG_MSG(("OVIW(%p): gen numbers: FBOId=%d FBOTexBackId=%d FBOTexFrontId=%d\n", (void*)self, m_FBOId, m_FBOTexBackId, m_FBOTexFrontId)); - - glGenRenderbuffersEXT(1, &m_FBODepthStencilPackedId); - } - - m_FBOTexSize = m_Size; - /* Bind to FBO */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId); - - /* - glEnable(GL_TEXTURE_RECTANGLE_ARB); - */ - - imageAspectRatio = m_FBOTexSize.width / m_FBOTexSize.height; - - /* Sanity check against maximum OpenGL texture size. If bigger adjust to - * maximum possible size while maintain the aspect ratio. */ - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); - if (m_FBOTexSize.width > maxTexSize || m_FBOTexSize.height > maxTexSize) + /* [self updateViewport]; */ + if (m_pSharedGLCtx) { - filter = GL_LINEAR; - if (imageAspectRatio > 1) - { - m_FBOTexSize.width = maxTexSize; - m_FBOTexSize.height = maxTexSize / imageAspectRatio; - } - else - { - m_FBOTexSize.width = maxTexSize * imageAspectRatio; - m_FBOTexSize.height = maxTexSize; - } + VBOX_CR_RENDER_CTX_INFO CtxInfo; + vboxCtxEnter(m_pSharedGLCtx, &CtxInfo); + + [self updateViewportCS]; + + vboxCtxLeave(&CtxInfo); } +} - DEBUG_MSG(("OVIW(%p): tex size is: %dx%d\n", (void*)self, (int)m_FBOTexSize.width, (int)m_FBOTexSize.height)); - - /* Initialize FBO Textures */ - /* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination - * others are also valid, but might incur a costly software translation. */ - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexBackId); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width, m_FBOTexSize.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexFrontId); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width, m_FBOTexSize.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - - /* Now attach the textures to the FBO as its color destinations */ - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, m_FBOAttBackId, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexBackId, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, m_FBOAttFrontId, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexFrontId, 0); - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, m_FBOTexSize.width, m_FBOTexSize.height); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId); - - /* Bind the FBOs for reading and drawing. */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId); - - /* Explicitly clear the textures otherwise they would contain old memory stuff. */ - glDrawBuffer(m_FBOAttBackId); - glClear(GL_COLOR_BUFFER_BIT); - glDrawBuffer(m_FBOAttFrontId); - glClear(GL_COLOR_BUFFER_BIT); - - /* Now initially reading/drawing to the back buffer. */ - glReadBuffer(m_FBOAttBackId); - glDrawBuffer(m_FBOAttBackId); - - /* Make sure the FBO was created successfully. */ - if (GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)) - DEBUG_MSG(("OVIW(%p): Framebuffer Object creation or update failed!\n", (void*)self)); - -// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, oldTexId); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)oldFBId ? (GLuint)oldFBId : m_FBOId); - - /* Is there a dock tile preview enabled in the GUI? If so setup a +- (void)createDockTile +{ + NSView *pDockScreen = nil; + [self deleteDockTile]; + + /* Is there a dock tile preview enabled in the GUI? If so setup a * additional thumbnail view for the dock tile. */ - pDockScreen = [self dockTileScreen]; - if (pDockScreen) + pDockScreen = [self dockTileScreen]; + if (pDockScreen) { - if (!m_FBOThumbId) - { - glGenFramebuffersEXT(1, &m_FBOThumbId); - glGenTextures(1, &m_FBOThumbTexId); - } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOThumbId); - /* Initialize FBO Texture */ - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOThumbTexId); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP); - - /* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination - * others are also valid, but might incur a costly software translation. */ - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width * m_FBOThumbScaleX, m_FBOTexSize.height * m_FBOThumbScaleY, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - - /* Now attach texture to the FBO as its color destination */ - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOThumbTexId, 0); - - /* Make sure the FBO was created successfully. */ - if (GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)) - DEBUG_MSG(("OVIW(%p): Framebuffer \"Thumb\" Object creation or update failed!\n", (void*)self)); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, oldTexId); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)oldFBId ? (GLuint)oldFBId : m_FBOId); - m_DockTileView = [[DockOverlayView alloc] init]; [self reshapeDockTile]; [pDockScreen addSubview:m_DockTileView]; } - - /* Initialize with one big visual region over the full size */ - [self clearVisibleRegions]; - m_cClipRects = 1; - m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4); - m_paClipRects[0] = 0; - m_paClipRects[1] = 0; - m_paClipRects[2] = m_FBOTexSize.width; - m_paClipRects[3] = m_FBOTexSize.height; -#endif } -- (void)deleteFBO +- (void)deleteDockTile { - DEBUG_MSG(("OVIW(%p): deleteFBO\n", (void*)self)); - - if (m_pSharedGLCtx) - { - DEBUG_MSG(("OVIW(%p): makeCurrent (shared) %p\n", (void*)self, (void*)m_pSharedGLCtx)); - [m_pSharedGLCtx makeCurrentContext]; - [m_pSharedGLCtx update]; - - glEnable(GL_TEXTURE_RECTANGLE_ARB); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - } - - if (m_pGLCtx) - { - DEBUG_MSG(("OVIW(%p): makeCurrent (non shared) %p\n", (void*)self, (void*)m_pGLCtx)); - [m_pGLCtx makeCurrentContext]; - -#ifdef FBO - if (m_FBODepthStencilPackedId > 0) - { - glDeleteRenderbuffersEXT(1, &m_FBODepthStencilPackedId); - m_FBODepthStencilPackedId = 0; - } - if (m_FBOTexBackId > 0) - { - glDeleteTextures(1, &m_FBOTexBackId); - m_FBOTexBackId = 0; - } - if (m_FBOTexFrontId > 0) - { - glDeleteTextures(1, &m_FBOTexFrontId); - m_FBOTexFrontId = 0; - } - if (m_FBOId > 0) - { - if ([self isCurrentFBO]) - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - glDeleteFramebuffersEXT(1, &m_FBOId); - m_FBOId = 0; - } -#endif - } - - if (m_DockTileView != nil) + if (m_DockTileView != nil) { [m_DockTileView removeFromSuperview]; [m_DockTileView release]; @@ -1109,32 +1105,10 @@ } } -- (void)updateFBO -{ - DEBUG_MSG(("OVIW(%p): updateFBO\n", (void*)self)); - - [self makeCurrentFBO]; - - if (m_pGLCtx) - { -#ifdef FBO - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - [self createFBO]; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId); -#endif - [m_pGLCtx update]; - } -} - - (void)makeCurrentFBO { DEBUG_MSG(("OVIW(%p): makeCurrentFBO\n", (void*)self)); -#ifdef FBO - DEBUG_MSG(("OVIW(%p): FBOId=%d CTX=%p\n", (void*)self, m_FBOId, (void*)m_pGLCtx)); - if([NSOpenGLContext currentContext] != 0) - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId); -#endif if (m_pGLCtx) { if ([m_pGLCtx view] != self) @@ -1151,352 +1125,325 @@ { [m_pGLCtx makeCurrentContext]; CHECK_GL_ERROR(); - /* - [m_pGLCtx update]; - */ + if (m_fNeedCtxUpdate == true) + { + [m_pGLCtx update]; + m_fNeedCtxUpdate = false; + } } + + if (!m_FBOId) + { + glGenFramebuffersEXT(1, &m_FBOId); + Assert(m_FBOId); + } + } -#ifdef FBO - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId); -#endif } -- (bool)isCurrentFBO +- (bool)vboxSharedCtxCreate { -#ifdef FBO - GLint curFBOId = 0; - - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &curFBOId); - DEBUG_MSG_1(("OVIW(%p): isCurrentFBO: curFBOId=%d FBOId=%d\n", (void*)self, curFBOId, m_FBOId)); - return (GLuint)curFBOId == m_FBOId; -#else - return false; -#endif -} - -- (void)tryDraw -{ - if ([self lockFocusIfCanDraw]) + if (m_pSharedGLCtx) + return true; + + Assert(!m_pBlitter); + m_pBlitter = RTMemAlloc(sizeof (*m_pBlitter)); + if (!m_pBlitter) { - [self renderFBOToView]; - [self unlockFocus]; + DEBUG_WARN(("m_pBlitter allocation failed")); + return false; + } + + int rc = CrBltInit(m_pBlitter, NULL, false, false, &render_spu.GlobalShaders, &render_spu.blitterDispatch); + if (RT_SUCCESS(rc)) + { + DEBUG_MSG(("blitter created successfully for view 0x%p\n", (void*)self)); } + else + { + DEBUG_WARN(("CrBltInit failed, rc %d", rc)); + RTMemFree(m_pBlitter); + m_pBlitter = NULL; + return false; + } + + GLint opaque = 0; + /* Create a shared context out of the main context. Use the same pixel format. */ + NSOpenGLContext *pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:[(OverlayOpenGLContext*)m_pGLCtx openGLPixelFormat] shareContext:m_pGLCtx]; + + /* Set the new context as non opaque */ + [pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; + /* Set this view as the drawable for the new context */ + [pSharedGLCtx setView: self]; + m_fNeedViewportUpdate = true; + + m_pSharedGLCtx = pSharedGLCtx; + + return true; } -- (void)swapFBO +- (void)vboxTryDraw { - GLint sw = 0; - GLint readFBOId = 0; - GLint drawFBOId = 0; - GLint readId = 0; - GLint drawId = 0; - - DEBUG_MSG(("OVIW(%p): swapFBO\n", (void*)self)); - -#ifdef FBO - /* Don't use flush buffers cause we are using FBOs here! */ - - /* Before we swap make sure everything is done (This is really - * important. Don't remove.) */ glFlush(); + + /* issue to the gui thread */ + [self setNeedsDisplay:YES]; +} + +- (void)vboxTryDrawUI +{ + const VBOXVR_SCR_COMPOSITOR *pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo); + if (!m_fDataVisible && !pCompositor) + return; - /* Fetch the current used read and draw buffers. */ - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFBOId); - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFBOId); - glGetIntegerv(GL_READ_BUFFER, &readId); - glGetIntegerv(GL_DRAW_BUFFER, &drawId); - - /* Do the swapping of our internal ids */ - sw = m_FBOTexFrontId; - m_FBOTexFrontId = m_FBOTexBackId; - m_FBOTexBackId = sw; - sw = m_FBOAttFrontId; - m_FBOAttFrontId = m_FBOAttBackId; - m_FBOAttBackId = sw; - - DEBUG_MSG_1(("read FBO: %d draw FBO: %d readId: %d drawId: %d\n", readFBOId, drawFBOId, readId, drawId)); - /* We also have to swap the real ids on the current context. */ - if ((GLuint)readFBOId == m_FBOId) + VBOXVR_SCR_COMPOSITOR TmpCompositor; + + if (pCompositor) { - if ((GLuint)readId == m_FBOAttFrontId) - glReadBuffer(m_FBOAttBackId); - if ((GLuint)readId == m_FBOAttBackId) - glReadBuffer(m_FBOAttFrontId); + if (!m_pSharedGLCtx) + { + Assert(!m_fDataVisible); + renderspuVBoxCompositorRelease(m_pWinInfo); + if (![self vboxSharedCtxCreate]) + { + DEBUG_WARN(("vboxSharedCtxCreate failed\n")); + return; + } + + Assert(m_pSharedGLCtx); + + pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo); + Assert(!m_fDataVisible); + if (!pCompositor) + return; + } } - if ((GLuint)drawFBOId == m_FBOId) + else { - if ((GLuint)drawId == m_FBOAttFrontId) - glDrawBuffer(m_FBOAttBackId); - if ((GLuint)drawId == m_FBOAttBackId) - glDrawBuffer(m_FBOAttFrontId); + CrVrScrCompositorInit(&TmpCompositor, NULL); + pCompositor = &TmpCompositor; + } + + if ([self lockFocusIfCanDraw]) + { + [self vboxPresent:pCompositor]; + if (pCompositor != &TmpCompositor) + renderspuVBoxCompositorRelease(m_pWinInfo); + + [self unlockFocus]; + } + else + { + [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(vboxTryDrawUI) userInfo:nil repeats:NO]; } - - if (m_cClipRects) - [self tryDraw]; -#else - [m_pGLCtx flushBuffer]; -#endif } -- (void)flushFBO +- (void)swapFBO { - GLint drawId = 0; - GLint FBOId = 0; - - DEBUG_MSG(("OVIW(%p): flushFBO\n", (void*)self)); - - glFlush(); -#ifdef FBO - /* If at any time OpenGl operations where done in the front buffer, we need - * to reflect this in the FBO as well. This is something which on real - * hardware happens and unfortunately some applications rely on it (grrr ... Compiz). */ - if ( m_fFrontDrawing - && [self isCurrentFBO]) - { - /* Only reset if we aren't currently front. */ - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &FBOId); - glGetIntegerv(GL_DRAW_BUFFER, &drawId); - if (!( (GLuint)FBOId == m_FBOId - && (GLuint)drawId == m_FBOAttFrontId)) - m_fFrontDrawing = false; - if (m_cClipRects) - [self tryDraw]; - } -#endif + [m_pGLCtx flushBuffer]; } -- (void)finishFBO +- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR*)pCompositor { - DEBUG_MSG(("OVIW(%p): finishFBO\n", (void*)self)); + VBOX_CR_RENDER_CTX_INFO CtxInfo; + + DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void*)self)); + + Assert(pCompositor); - glFinish(); -#ifdef FBO - if (m_cClipRects && [self isCurrentFBO]) - [self tryDraw]; -#endif + vboxCtxEnter(m_pSharedGLCtx, &CtxInfo); + + [self vboxPresentCS:pCompositor]; + + vboxCtxLeave(&CtxInfo); } -- (void)stateInfo:(GLenum)pname withParams:(GLint*)params +- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor { - GLint test; -// DEBUG_MSG_1(("StateInfo requested: %d\n", pname)); - - glGetIntegerv(pname, params); -#ifdef FBO - switch(pname) - { - case GL_FRAMEBUFFER_BINDING_EXT: - case GL_READ_FRAMEBUFFER_BINDING: - case GL_READ_FRAMEBUFFER_EXT: - case GL_DRAW_FRAMEBUFFER_EXT: { - if ((GLuint)*params == m_FBOId) - *params = 0; - break; - } - case GL_READ_BUFFER: - { - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &test); - if ((GLuint)test == m_FBOId) + if ([m_pSharedGLCtx view] != self) { - if ((GLuint)*params == m_FBOAttFrontId) - *params = GL_FRONT; - else - if ((GLuint)*params == m_FBOAttBackId) - *params = GL_BACK; + DEBUG_MSG(("OVIW(%p): not current view of shared ctx! Switching ...\n", (void*)self)); + [m_pSharedGLCtx setView: self]; + m_fNeedViewportUpdate = true; } - break; - } - case GL_DRAW_BUFFER: - { - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &test); - if ((GLuint)test == m_FBOId) + + if (m_fNeedViewportUpdate) { - if ((GLuint)*params == m_FBOAttFrontId) - *params = GL_FRONT; - else - if ((GLuint)*params == m_FBOAttBackId) - *params = GL_BACK; + [self updateViewportCS]; + m_fNeedViewportUpdate = false; } - break; - } - } + + /* Render FBO content to the dock tile when necessary. */ + [self vboxPresentToDockTileCS:pCompositor]; + /* change to #if 0 to see thumbnail image */ +#if 1 + [self vboxPresentToViewCS:pCompositor]; +#else + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + [m_pSharedGLCtx flushBuffer]; #endif + + } } -- (void)readBuffer:(GLenum)mode +DECLINLINE(void) vboxNSRectToRect(const NSRect *pR, RTRECT *pRect) { -#ifdef FBO - /* - if ([self isCurrentFBO]) - */ - { - if (mode == GL_FRONT) - { - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId); - glReadBuffer(m_FBOAttFrontId); - } - else if (mode == GL_BACK) - { - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId); - glReadBuffer(m_FBOAttBackId); - } - else - glReadBuffer(mode); - } -#else - glReadBuffer(mode); -#endif + pRect->xLeft = (int)pR->origin.x; + pRect->yTop = (int)pR->origin.y; + pRect->xRight = (int)(pR->origin.x + pR->size.width); + pRect->yBottom = (int)(pR->origin.y + pR->size.height); } -- (void)drawBuffer:(GLenum)mode +DECLINLINE(void) vboxNSRectToRectUnstretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch) { -#ifdef FBO - /* - if ([self isCurrentFBO]) - */ - { - if (mode == GL_FRONT) - { - DEBUG_MSG(("OVIW(%p): front\n", (void*)self)); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId); - glDrawBuffer(m_FBOAttFrontId); - m_fFrontDrawing = true; - } - else if (mode == GL_BACK) - { - DEBUG_MSG(("OVIW(%p): back\n", (void*)self)); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId); - glDrawBuffer(m_FBOAttBackId); - } - else - { - DEBUG_MSG(("OVIW(%p): other: %d\n", (void*)self, mode)); - glDrawBuffer(mode); - } - } -#else - glDrawBuffer(mode); -#endif + pRect->xLeft = (int)(pR->origin.x / xStretch); + pRect->yTop = (int)(pR->origin.y / yStretch); + pRect->xRight = (int)((pR->origin.x + pR->size.width) / xStretch); + pRect->yBottom = (int)((pR->origin.y + pR->size.height) / yStretch); } -- (void)bindFBO:(GLenum)target withFrameBuffer:(GLuint)framebuffer +DECLINLINE(void) vboxNSRectToRectStretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch) { -#ifdef FBO - if (framebuffer != 0) - glBindFramebufferEXT(target, framebuffer); - else - glBindFramebufferEXT(target, m_FBOId); -#else - glBindFramebufferEXT(target, framebuffer); -#endif + pRect->xLeft = (int)(pR->origin.x * xStretch); + pRect->yTop = (int)(pR->origin.y * yStretch); + pRect->xRight = (int)((pR->origin.x + pR->size.width) * xStretch); + pRect->yBottom = (int)((pR->origin.y + pR->size.height) * yStretch); } -- (void)renderFBOToView +- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor { - GLint opaque = 0; - GLint i = 0; - GLint oldReadFBOId = 0; - GLint oldDrawFBOId = 0; - GLint oldReadId = 0; - GLint oldDrawId = 0; - - DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void*)self)); - -#ifdef FBO - - /* Fetch the current used read and draw buffers. */ - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &oldReadFBOId); - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &oldDrawFBOId); - glGetIntegerv(GL_READ_BUFFER, &oldReadId); - glGetIntegerv(GL_DRAW_BUFFER, &oldDrawId); + NSRect r = [self frame]; + float xStretch, yStretch; + DEBUG_MSG(("OVIW(%p): rF2V frame: [%i, %i, %i, %i]\n", (void*)self, (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height)); - if (!m_pSharedGLCtx) - { - /* Create a shared context out of the main context. Use the same pixel format. */ - m_pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:[(OverlayOpenGLContext*)m_pGLCtx openGLPixelFormat] shareContext:m_pGLCtx]; - - /* Set the new context as non opaque */ - [m_pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; - /* Set this view as the drawable for the new context */ - [m_pSharedGLCtx setView: self]; - [self updateViewport]; - } - - if (m_pSharedGLCtx) +#if 1 /* Set to 0 to see the docktile instead of the real output */ + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + + CrVrScrCompositorConstIterInit(pCompositor, &CIter); + + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); + glDrawBuffer(GL_BACK); + + /* Clear background to transparent */ + glClear(GL_COLOR_BUFFER_BIT); + + m_fDataVisible = false; + + CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch); + + while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL) { - NSRect r = [self frame]; - DEBUG_MSG(("OVIW(%p): rF2V frame: [%i, %i, %i, %i]\n", (void*)self, (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height)); - - if (m_FBOTexFrontId > 0) + uint32_t cRegions; + const RTRECT *paSrcRegions, *paDstRegions; + int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL); + uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry); + if (RT_SUCCESS(rc)) { - if ([m_pSharedGLCtx view] != self) - { - DEBUG_MSG(("OVIW(%p): not current view of shared ctx! Switching ...\n", (void*)self)); - [m_pSharedGLCtx setView: self]; - [self updateViewport]; + uint32_t i; + int rc = CrBltEnter(m_pBlitter); + if (RT_SUCCESS(rc)) + { + for (i = 0; i < cRegions; ++i) + { + const RTRECT * pSrcRect = &paSrcRegions[i]; + const RTRECT * pDstRect = &paDstRegions[i]; + RTRECT DstRect, RestrictDstRect; + RTRECT SrcRect, RestrictSrcRect; + + vboxNSRectToRect(&m_RootRect, &RestrictDstRect); + VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect); + + if (VBoxRectIsZero(&DstRect)) + continue; + + VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop); + + vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch); + VBoxRectTranslate(&RestrictSrcRect, -CrVrScrCompositorEntryRectGet(pEntry)->xLeft, -CrVrScrCompositorEntryRectGet(pEntry)->yTop); + VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect); + + if (VBoxRectIsZero(&SrcRect)) + continue; + + pSrcRect = &SrcRect; + pDstRect = &DstRect; + + const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + + CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags | CRBLT_F_NOALPHA); + + m_fDataVisible = true; + } + CrBltLeave(m_pBlitter); } - - [m_pSharedGLCtx makeCurrentContext]; - - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId); - glReadBuffer(m_FBOAttFrontId); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - glDrawBuffer(GL_BACK); - - /* Render FBO content to the dock tile when necessary. */ - [self renderFBOToDockTile]; - -#if 1 /* Set to 0 to see the docktile instead of the real output */ - /* Clear background to transparent */ - glClear(GL_COLOR_BUFFER_BIT); - - /* Blit the content of the FBO to the screen. */ - for (i = 0; i < m_cClipRects; ++i) + else { - GLint x1 = m_paClipRects[4*i]; - GLint y1 = r.size.height - m_paClipRects[4*i+1]; - GLint x2 = m_paClipRects[4*i+2]; - GLint y2 = r.size.height - m_paClipRects[4*i+3]; - glBlitFramebufferEXT(x1, y1 + m_RootShift.y, x2, y2 + m_RootShift.y, - x1 - m_RootShift.x, y1, x2 - m_RootShift.x, y2, - GL_COLOR_BUFFER_BIT, GL_NEAREST); + DEBUG_WARN(("CrBltEnter failed rc %d", rc)); } + } + else + { + Assert(0); + DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc)); + } + } #endif /* glFinish(); */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); [m_pSharedGLCtx flushBuffer]; +} - [m_pGLCtx makeCurrentContext]; - /* Reset to previous buffer bindings. */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, oldReadFBOId); - glReadBuffer(oldReadId); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, oldDrawFBOId); - glDrawBuffer(oldDrawId); - } - } -#else - [m_pGLCtx flushBuffer]; -#endif +- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY*)pChangedEntry +{ + [self vboxTryDraw]; +} + +- (void)vboxBlitterSyncWindow +{ + CR_BLITTER_WINDOW WinInfo; + NSRect r; + + if (!m_pBlitter) + return; + + memset(&WinInfo, 0, sizeof (WinInfo)); + + r = [self frame]; + WinInfo.width = r.size.width; + WinInfo.height = r.size.height; + + Assert(WinInfo.width == m_RootRect.size.width); + Assert(WinInfo.height == m_RootRect.size.height); + + /*CrBltMuralSetCurrentInfo(m_pBlitter, NULL);*/ + + CrBltMuralSetCurrentInfo(m_pBlitter, &WinInfo); + CrBltCheckUpdateViewport(m_pBlitter); } -- (void)renderFBOToDockTile +#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL +static int g_cVBoxTgaCtr = 0; +#endif +- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor { NSRect r = [self frame]; NSRect rr = NSZeroRect; GLint i = 0; NSDockTile *pDT = nil; + float xStretch, yStretch; -#ifdef FBO - if ( m_FBOThumbId - && m_FBOThumbTexId - && [m_DockTileView thumbBitmap] != nil) + if ([m_DockTileView thumbBitmap] != nil) { /* Only update after at least 200 ms, cause glReadPixels is * heavy performance wise. */ uint64_t uiNewTime = RTTimeMilliTS(); + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + if (uiNewTime - m_uiDockUpdateTime > 200) { m_uiDockUpdateTime = uiNewTime; @@ -1516,22 +1463,73 @@ glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); #endif + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); + glDrawBuffer(GL_BACK); + /* Clear background to transparent */ glClear(GL_COLOR_BUFFER_BIT); rr = [m_DockTileView frame]; - - for (i = 0; i < m_cClipRects; ++i) + + CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch); + + CrVrScrCompositorConstIterInit(pCompositor, &CIter); + while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL) { - GLint x1 = m_paClipRects[4*i]; - GLint y1 = r.size.height - m_paClipRects[4*i+1]; - GLint x2 = m_paClipRects[4*i+2]; - GLint y2 = r.size.height - m_paClipRects[4*i+3]; - - glBlitFramebufferEXT(x1, y1 + m_RootShift.y, x2, y2 + m_RootShift.y, - x1 * m_FBOThumbScaleX, y1 * m_FBOThumbScaleY, x2 * m_FBOThumbScaleX, y2 * m_FBOThumbScaleY, - GL_COLOR_BUFFER_BIT, GL_LINEAR); + uint32_t cRegions; + const RTRECT *paSrcRegions, *paDstRegions; + int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL); + uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry); + if (RT_SUCCESS(rc)) + { + uint32_t i; + int rc = CrBltEnter(m_pBlitter); + if (RT_SUCCESS(rc)) + { + for (i = 0; i < cRegions; ++i) + { + const RTRECT * pSrcRect = &paSrcRegions[i]; + const RTRECT * pDstRect = &paDstRegions[i]; + RTRECT SrcRect, DstRect, RestrictSrcRect, RestrictDstRect; + + vboxNSRectToRect(&m_RootRect, &RestrictDstRect); + VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect); + + VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop); + + VBoxRectScale(&DstRect, m_FBOThumbScaleX, m_FBOThumbScaleY); + + if (VBoxRectIsZero(&DstRect)) + continue; + + vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch); + VBoxRectTranslate(&RestrictSrcRect, -CrVrScrCompositorEntryRectGet(pEntry)->xLeft, -CrVrScrCompositorEntryRectGet(pEntry)->yTop); + VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect); + + if (VBoxRectIsZero(&SrcRect)) + continue; + + pSrcRect = &SrcRect; + pDstRect = &DstRect; + + const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + + CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags); + } + CrBltLeave(m_pBlitter); + } + else + { + DEBUG_WARN(("CrBltEnter failed rc %d", rc)); + } + } + else + { + Assert(0); + DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc)); + } } + glFinish(); glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); @@ -1540,23 +1538,24 @@ * happens. We have to lock this access, in the case the dock * is updated currently. */ [m_DockTileView lock]; - glReadPixels(0, 0, rr.size.width, rr.size.height, + glReadPixels(0, m_RootRect.size.height - rr.size.height, rr.size.width, rr.size.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, [[m_DockTileView thumbBitmap] bitmapData]); [m_DockTileView unlock]; - - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId); - glReadBuffer(m_FBOAttFrontId); + +#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL + ++g_cVBoxTgaCtr; + crDumpNamedTGAF((GLint)rr.size.width, (GLint)rr.size.height, + [[m_DockTileView thumbBitmap] bitmapData], "/Users/leo/vboxdumps/dump%d.tga", g_cVBoxTgaCtr); +#endif pDT = [[NSApplication sharedApplication] dockTile]; /* Send a display message to the dock tile in the main thread */ [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:NO]; - } } -#endif } - (void)clearVisibleRegions @@ -1569,7 +1568,7 @@ m_cClipRects = 0; } -- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects +- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint*)paRects { GLint cOldRects = m_cClipRects; @@ -1589,8 +1588,12 @@ m_cClipRects = cRects; memcpy(m_paClipRects, paRects, sizeof(GLint) * 4 * cRects); } - else if (cOldRects) - [self tryDraw]; + + /* we need to redwar on regions change, however the compositor now is cleared + * because all compositor&window data-related modifications are performed with compositor cleared + * the renderspu client will re-set the compositor after modifications are complete + * this way we indicate renderspu generic code not to ignore the empty compositor */ + m_pWinInfo->fCompositorPresentEmpty = GL_TRUE; } - (NSView*)dockTileScreen @@ -1615,11 +1618,12 @@ if (pView != nil) { NSRect dockFrame = [pView frame]; + /* todo: this is not correct, we should use framebuffer size here, while parent view frame size may differ in case of scrolling */ NSRect parentFrame = [m_pParentView frame]; m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width; m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height; - newFrame = NSMakeRect((int)(m_Pos.x * m_FBOThumbScaleX), (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_RootShift.y) * m_FBOThumbScaleY), (int)(m_Size.width * m_FBOThumbScaleX), (int)(m_Size.height * m_FBOThumbScaleY)); + newFrame = NSMakeRect((int)(m_Pos.x * m_FBOThumbScaleX), (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_yInvRootOffset) * m_FBOThumbScaleY), (int)(m_Size.width * m_FBOThumbScaleX), (int)(m_Size.height * m_FBOThumbScaleY)); /* NSRect newFrame = NSMakeRect ((int)roundf(m_Pos.x * m_FBOThumbScaleX), (int)roundf(dockFrame.size.height - (m_Pos.y + m_Size.height) * m_FBOThumbScaleY), (int)roundf(m_Size.width * m_FBOThumbScaleX), (int)roundf(m_Size.height * m_FBOThumbScaleY)); NSRect newFrame = NSMakeRect ((m_Pos.x * m_FBOThumbScaleX), (dockFrame.size.height - (m_Pos.y + m_Size.height) * m_FBOThumbScaleY), (m_Size.width * m_FBOThumbScaleX), (m_Size.height * m_FBOThumbScaleY)); @@ -1727,9 +1731,8 @@ void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx) { NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - /* [pCtx release]; - */ + /*[pCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/ [pPool release]; } @@ -1739,12 +1742,12 @@ void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx) * View management * ********************************************************************************/ -void cocoaViewCreate(NativeNSViewRef *ppView, NativeNSViewRef pParentView, GLbitfield fVisParams) +void cocoaViewCreate(NativeNSViewRef *ppView, WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams) { NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; /* Create our worker view */ - OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView]; + OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView winInfo:pWinInfo]; if (pView) { @@ -1778,7 +1781,8 @@ void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView) if (pParentView != nil) { [[pParentView window] addChildWindow:[pOView overlayWin] ordered:NSWindowAbove]; - [pOView createFBO]; + if ([pOView isEverSized]) + [pOView performSelectorOnMainThread:@selector(vboxReshapeOnReparentPerform) withObject:nil waitUntilDone:NO]; } } @@ -1886,162 +1890,58 @@ void cocoaViewGetGeometry(NativeNSViewRef pView, int *pX, int *pY, int *pW, int [pPool release]; } -void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx) -{ - NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - - DEBUG_MSG(("cocoaViewMakeCurrentContext(%p, %p)\n", (void*)pView, (void*)pCtx)); - - [(OverlayView*)pView setGLCtx:pCtx]; - [(OverlayView*)pView makeCurrentFBO]; - - [pPool release]; -} - -void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, GLint* paRects) +void cocoaViewPresentComposition(NativeNSViewRef pView, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry) { NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - - [(OverlayView*)pView setVisibleRegions:cRects paRects:paRects]; - - [pPool release]; -} - -/******************************************************************************** -* -* Additional OpenGL wrapper -* -********************************************************************************/ -static void performSelectorOnView(SEL selector) -{ - NSOpenGLContext *pCtx = [NSOpenGLContext currentContext]; - - if (pCtx) - { - NSView *pView = [pCtx view]; - if (pView) - { - if ([pView respondsToSelector:selector]) - [pView performSelector:selector]; - } - } -} - -static void performSelectorOnViewOneArg(SEL selector, id arg1) -{ - NSOpenGLContext *pCtx = [NSOpenGLContext currentContext]; - - if (pCtx) - { - NSView *pView = [pCtx view]; - if (pView) - { - if ([pView respondsToSelector:selector]) - [pView performSelector:selector withObject:arg1]; - } - } -} - -static void performSelectorOnViewTwoArgs(SEL selector, id arg1, id arg2) -{ - NSOpenGLContext *pCtx = [NSOpenGLContext currentContext]; - - if (pCtx) + NSOpenGLContext *pCtx; + + /* view should not necesserily have a context set */ + pCtx = [(OverlayView*)pView glCtx]; + if (!pCtx) { - NSView *pView = [pCtx view]; - if (pView) + ContextInfo * pCtxInfo = renderspuDefaultSharedContextAcquire(); + if (!pCtxInfo) { - if ([pView respondsToSelector:selector]) - [pView performSelector:selector withObject:arg1 withObject:arg2]; + DEBUG_WARN(("renderspuDefaultSharedContextAcquire returned NULL")); + + [pPool release]; + return; } + + pCtx = pCtxInfo->context; + + [(OverlayView*)pView setGLCtx:pCtx]; } -} - -void cocoaFlush(void) -{ - NSOpenGLContext *pCtx = nil; - - NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - - DEBUG_MSG_1(("glFlush called\n")); - - performSelectorOnView(@selector(flushFBO)); - - [pPool release]; -} - -void cocoaFinish(void) -{ - NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - - DEBUG_MSG_1(("glFinish called\n")); - - performSelectorOnView(@selector(finishFBO)); - - [pPool release]; -} - -void cocoaBindFramebufferEXT(GLenum target, GLuint framebuffer) -{ - NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - - DEBUG_MSG_1(("glBindFramebufferEXT called target: %d fb: %d\n", target, framebuffer)); - - performSelectorOnViewTwoArgs(@selector(bindFBO:withFrameBuffer:), (id)target, (id)framebuffer); - - [pPool release]; -} - -void cocoaCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) -{ - NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - GLbitfield mask = GL_COLOR_BUFFER_BIT; - - DEBUG_MSG_1(("glCopyPixels called: %d,%d-%dx%d type: %d\n", x, y, width, height, type)); - -#ifdef FBO - if (type == GL_DEPTH) - mask = GL_DEPTH_BUFFER_BIT; - else if (type == GL_STENCIL) - mask = GL_STENCIL_BUFFER_BIT; - glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, mask, GL_NEAREST); -#else - glCopyPixels(x, y, width, height, type); -#endif - - [pPool release]; -} - -void cocoaGetIntegerv(GLenum pname, GLint *params) -{ - NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - -// DEBUG_MSG_1(("getIntergerv called: %d\n", pname)); - - performSelectorOnViewTwoArgs(@selector(stateInfo:withParams:), (id)pname, (id)params); + + [(OverlayView*)pView presentComposition:pChangedEntry]; [pPool release]; } -void cocoaReadBuffer(GLenum mode) +void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx) { NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - DEBUG_MSG_1(("glReadBuffer called: %d\n", mode)); + DEBUG_MSG(("cocoaViewMakeCurrentContext(%p, %p)\n", (void*)pView, (void*)pCtx)); - performSelectorOnViewOneArg(@selector(readBuffer:), (id)mode); + if (pView) + { + [(OverlayView*)pView setGLCtx:pCtx]; + [(OverlayView*)pView makeCurrentFBO]; + } + else + { + [NSOpenGLContext clearCurrentContext]; + } [pPool release]; } -void cocoaDrawBuffer(GLenum mode) +void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint* paRects) { NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init]; - DEBUG_MSG_1(("glDrawBuffer called: %d\n", mode)); - - performSelectorOnViewOneArg(@selector(drawBuffer:), (id)mode); + [(OverlayView*)pView setVisibleRegions:cRects paRects:paRects]; [pPool release]; } - diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c index 734e7a1a..49d745a6 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c @@ -15,13 +15,13 @@ static void set_window_geometry( RenderSPU *render_spu, const char *response ) { - float x, y, w, h; + int x, y, w, h; CRASSERT(response[0] == '['); - sscanf( response, "[ %f, %f, %f, %f ]", &x, &y, &w, &h ); + sscanf( response, "[ %d, %d, %d, %d ]", &x, &y, &w, &h ); render_spu->defaultX = (int) x; render_spu->defaultY = (int) y; - render_spu->defaultWidth = (int) w; - render_spu->defaultHeight = (int) h; + render_spu->defaultWidth = (unsigned int) w; + render_spu->defaultHeight = (unsigned int) h; } static void set_default_visual( RenderSPU *render_spu, const char *response ) @@ -321,7 +321,6 @@ SPUOptions renderSPUOptions[] = { void renderspuSetVBoxConfiguration( RenderSPU *render_spu ) { - CRConnection *conn; int a; for (a=0; a<256; a++) diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c index eceb96f3..9bdcf293 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c @@ -85,6 +85,7 @@ renderDestroyWindow( Display *dpy, Window w ) return WindowExistsFlag; } +#if 0 /* * Garbage collection function. * Loop over all known windows and check if corresponding X window still @@ -109,6 +110,7 @@ renderspu_GCWindow(void) } } } +#endif static Colormap GetLUTColormap( Display *dpy, XVisualInfo *vi ) @@ -401,6 +403,314 @@ chooseFBConfig( Display *dpy, int screen, GLbitfield visAttribs ) } #endif /* GLX_VERSION_1_3 */ +static const char * renderspuGetDisplayName() +{ + const char *dpyName; + + if (render_spu.display_string[0]) + dpyName = render_spu.display_string; + else + { + crWarning("Render SPU: no display.."); + dpyName = NULL; + } + return dpyName; +} + +static int renderspuWinCmdWinCreate(WindowInfo *pWindow) +{ + return VERR_NOT_IMPLEMENTED; +} + +static int renderspuWinCmdWinDestroy(WindowInfo *pWindow) +{ + return VERR_NOT_IMPLEMENTED; +} + +static int renderspuWinCmdInit() +{ + const char * dpyName; + int rc = VERR_GENERAL_FAILURE; + + if (!crHashtableAllocRegisterKey(render_spu.windowTable, CR_RENDER_WINCMD_ID)) + { + crError("CR_RENDER_WINCMD_ID %d is occupied already", CR_RENDER_WINCMD_ID); + return VERR_INVALID_STATE; + } + + render_spu.pWinToInfoTable = crAllocHashtable(); + if (render_spu.pWinToInfoTable) + { + dpyName = renderspuGetDisplayName(); + if (dpyName) + { + GLboolean bRc = renderspuInitVisual(&render_spu.WinCmdVisual, dpyName, render_spu.default_visual); + if (bRc) + { + bRc = renderspuWindowInitWithVisual(&render_spu.WinCmdWindow, &render_spu.WinCmdVisual, GL_FALSE, CR_RENDER_WINCMD_ID); + if (bRc) + { + XSelectInput(render_spu.WinCmdVisual.dpy, render_spu.WinCmdWindow.window, StructureNotifyMask); + render_spu.WinCmdAtom = XInternAtom(render_spu.WinCmdVisual.dpy, "VBoxWinCmd", False); + CRASSERT(render_spu.WinCmdAtom != None); + return VINF_SUCCESS; + } + else + { + crError("renderspuWindowInitWithVisual failed"); + } + /* there is no visual destroy impl currently + * @todo: implement */ + } + else + { + crError("renderspuInitVisual failed"); + } + } + else + { + crError("Render SPU: no display, aborting"); + } + crFreeHashtable(render_spu.pWinToInfoTable, NULL); + render_spu.pWinToInfoTable = NULL; + } + else + { + crError("crAllocHashtable failed"); + } + return rc; +} + +static void renderspuWinCmdTerm() +{ + /* the window is not in the table, this will just ensure the key is freed */ + crHashtableDelete(render_spu.windowTable, CR_RENDER_WINCMD_ID, NULL); + renderspuWindowTerm(&render_spu.WinCmdWindow); + crFreeHashtable(render_spu.pWinToInfoTable, NULL); + /* we do not have visual destroy functionality + * @todo implement */ +} + + +static bool renderspuWinCmdProcess(CR_RENDER_WINCMD* pWinCmd) +{ + bool fExit = false; + /* process commands */ + switch (pWinCmd->enmCmd) + { + case CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE: + crHashtableAdd(render_spu.pWinToInfoTable, pWinCmd->pWindow->window, pWinCmd->pWindow); + XSelectInput(render_spu.WinCmdVisual.dpy, pWinCmd->pWindow->window, ExposureMask); + pWinCmd->rc = VINF_SUCCESS; + break; + case CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY: + crHashtableDelete(render_spu.pWinToInfoTable, pWinCmd->pWindow->window, NULL); + pWinCmd->rc = VINF_SUCCESS; + break; + case CR_RENDER_WINCMD_TYPE_NOP: + pWinCmd->rc = VINF_SUCCESS; + break; + case CR_RENDER_WINCMD_TYPE_EXIT: + renderspuWinCmdTerm(); + pWinCmd->rc = VINF_SUCCESS; + fExit = true; + pWinCmd->rc = VINF_SUCCESS; + break; + case CR_RENDER_WINCMD_TYPE_WIN_CREATE: + pWinCmd->rc = renderspuWinCmdWinCreate(pWinCmd->pWindow); + break; + case CR_RENDER_WINCMD_TYPE_WIN_DESTROY: + pWinCmd->rc = renderspuWinCmdWinDestroy(pWinCmd->pWindow); + break; + default: + crError("unknown WinCmd command! %d", pWinCmd->enmCmd); + pWinCmd->rc = VERR_INVALID_PARAMETER; + break; + } + + RTSemEventSignal(render_spu.hWinCmdCompleteEvent); + return fExit; +} + +static DECLCALLBACK(int) renderspuWinCmdThreadProc(RTTHREAD ThreadSelf, void *pvUser) +{ + int rc; + bool fExit = false; + crDebug("RenderSPU: Window thread started (%x)", crThreadID()); + + rc = renderspuWinCmdInit(); + + /* notify the main cmd thread that we have started */ + RTSemEventSignal(render_spu.hWinCmdCompleteEvent); + + if (!RT_SUCCESS(rc)) + { + CRASSERT(!render_spu.pWinToInfoTable); + return rc; + } + + do + { + XEvent event; + XNextEvent(render_spu.WinCmdVisual.dpy, &event); + + switch (event.type) + { + case ClientMessage: + { + CRASSERT(event.xclient.window == render_spu.WinCmdWindow.window); + if (event.xclient.window == render_spu.WinCmdWindow.window) + { + if (render_spu.WinCmdAtom == event.xclient.message_type) + { + CR_RENDER_WINCMD *pWinCmd; + memcpy(&pWinCmd, event.xclient.data.b, sizeof (pWinCmd)); + fExit = renderspuWinCmdProcess(pWinCmd); + } + } + + break; + } + case Expose: + { + if (!event.xexpose.count) + { + WindowInfo *pWindow = (WindowInfo*)crHashtableSearch(render_spu.pWinToInfoTable, event.xexpose.window); + if (pWindow) + { + const struct VBOXVR_SCR_COMPOSITOR * pCompositor; + + pCompositor = renderspuVBoxCompositorAcquire(pWindow); + if (pCompositor) + { + renderspuVBoxPresentCompositionGeneric(pWindow, pCompositor, NULL, 0); + renderspuVBoxCompositorRelease(pWindow); + } + } + } + break; + } + default: + break; + } + } while (!fExit); + + return 0; +} + +static int renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE enmCmd, WindowInfo *pWindow) +{ + Status status; + XEvent event; + CR_RENDER_WINCMD WinCmd, *pWinCmd; + int rc; + + pWinCmd = &WinCmd; + pWinCmd->enmCmd = enmCmd; + pWinCmd->rc = VERR_GENERAL_FAILURE; + pWinCmd->pWindow = pWindow; + + memset(&event, 0, sizeof (event)); + event.type = ClientMessage; + event.xclient.window = render_spu.WinCmdWindow.window; + event.xclient.message_type = render_spu.WinCmdAtom; + event.xclient.format = 8; + memcpy(event.xclient.data.b, &pWinCmd, sizeof (pWinCmd)); + + status = XSendEvent(render_spu.pCommunicationDisplay, render_spu.WinCmdWindow.window, False, StructureNotifyMask, &event); + if (!status) + { + Assert(0); + crWarning("XSendEvent returned null"); + return VERR_GENERAL_FAILURE; + } + + XFlush(render_spu.pCommunicationDisplay); + rc = RTSemEventWaitNoResume(render_spu.hWinCmdCompleteEvent, RT_INDEFINITE_WAIT); + if (!RT_SUCCESS(rc)) + { + crWarning("RTSemEventWaitNoResume failed rc %d", rc); + return rc; + } + return pWinCmd->rc; +} + +int renderspu_SystemInit() +{ + const char * dpyName; + int rc = VERR_GENERAL_FAILURE; + + if (!render_spu.use_glxchoosevisual) { + /* sometimes want to set this option with ATI drivers */ + render_spu.ws.glXChooseVisual = NULL; + } + + /* setup communication display connection */ + dpyName = renderspuGetDisplayName(); + if (!dpyName) + { + crWarning("no display name, aborting"); + return VERR_GENERAL_FAILURE; + } + + render_spu.pCommunicationDisplay = XOpenDisplay(dpyName); + if (!render_spu.pCommunicationDisplay) + { + crWarning( "Couldn't open X display named '%s'", dpyName ); + return VERR_GENERAL_FAILURE; + } + + if ( !render_spu.ws.glXQueryExtension( render_spu.pCommunicationDisplay, NULL, NULL ) ) + { + crWarning( "Render SPU: Display %s doesn't support GLX", dpyName ); + return VERR_GENERAL_FAILURE; + } + + rc = RTSemEventCreate(&render_spu.hWinCmdCompleteEvent); + if (RT_SUCCESS(rc)) + { + rc = RTThreadCreate(&render_spu.hWinCmdThread, renderspuWinCmdThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBoxCrWinCmd"); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventWait(render_spu.hWinCmdCompleteEvent, RT_INDEFINITE_WAIT); + if (RT_SUCCESS(rc)) + { + return VINF_SUCCESS; + } + else + { + crWarning("RTSemEventWait failed rc %d", rc); + } + + RTThreadWait(render_spu.hWinCmdThread, RT_INDEFINITE_WAIT, NULL); + } + else + { + crWarning("RTThreadCreate failed rc %d", rc); + } + RTSemEventDestroy(render_spu.hWinCmdCompleteEvent); + } + else + { + crWarning("RTSemEventCreate failed rc %d", rc); + } + + return rc; +} + +int renderspu_SystemTerm() +{ + int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_EXIT, NULL); + if (!RT_SUCCESS(rc)) + { + crWarning("renderspuWinCmdSubmit EXIT failed rc %d", rc); + return rc; + } + + RTThreadWait(render_spu.hWinCmdThread, RT_INDEFINITE_WAIT, NULL); + RTSemEventDestroy(render_spu.hWinCmdCompleteEvent); + return VINF_SUCCESS; +} GLboolean renderspu_SystemInitVisual( VisualInfo *visual ) @@ -418,20 +728,15 @@ renderspu_SystemInitVisual( VisualInfo *visual ) } #endif - if (render_spu.display_string[0]) - dpyName = render_spu.display_string; - else if (visual->displayName[0]) - dpyName = visual->displayName; - else - dpyName = NULL; - + dpyName = renderspuGetDisplayName(); if (!dpyName) { crWarning("Render SPU: no display, aborting"); return GL_FALSE; } - crDebug("Render SPU: Opening display %s", dpyName); + + crInfo("Render SPU: Opening display %s", dpyName); if (dpyName && (crStrncmp(dpyName, "localhost:11", 12) == 0 || @@ -640,15 +945,15 @@ createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window ) window->x = 0; window->y = 0; - window->width = xwa.width; - window->height = xwa.height; + window->BltInfo.width = xwa.width; + window->BltInfo.height = xwa.height; } /* i've changed default window size to be 0,0 but X doesn't like it */ - /*CRASSERT(window->width >= 1); - CRASSERT(window->height >= 1);*/ - if (window->width < 1) window->width = 1; - if (window->height < 1) window->height = 1; + /*CRASSERT(window->BltInfo.width >= 1); + CRASSERT(window->BltInfo.height >= 1);*/ + if (window->BltInfo.width < 1) window->BltInfo.width = 1; + if (window->BltInfo.height < 1) window->BltInfo.height = 1; /* * Get a colormap. @@ -707,7 +1012,7 @@ createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window ) crDebug("Render SPU: VBox parent window_id is: %x", render_spu_parent_window_id); window->window = XCreateWindow(dpy, render_spu_parent_window_id, window->x, window->y, - window->width, window->height, + window->BltInfo.width, window->BltInfo.height, 0, visual->visual->depth, InputOutput, visual->visual->visual, flags, &swa); } @@ -720,7 +1025,7 @@ createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window ) crDebug("Render SPU: Creating global window, parent: %x", RootWindow(dpy, visual->visual->screen)); window->window = XCreateWindow(dpy, RootWindow(dpy, visual->visual->screen), window->x, window->y, - window->width, window->height, + window->BltInfo.width, window->BltInfo.height, 0, visual->visual->depth, InputOutput, visual->visual->visual, flags, &swa); } @@ -790,8 +1095,8 @@ createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window ) hints.x = window->x; hints.y = window->y; - hints.width = window->width; - hints.height = window->height; + hints.width = window->BltInfo.width; + hints.height = window->BltInfo.height; hints.min_width = hints.width; hints.min_height = hints.height; hints.max_width = hints.width; @@ -825,7 +1130,6 @@ createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window ) XIfEvent( dpy, &event, WaitForMapNotify, (char *) window->window ); } - window->visible = showIt; if ((window->visual->visAttribs & CR_DOUBLE_BIT) && render_spu.nvSwapGroup) { /* NOTE: @@ -835,7 +1139,7 @@ createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window ) * app window is in a separate swap group while all the back-end windows * which form a mural are in the same swap group. */ - GLuint group = 0; /*render_spu.nvSwapGroup + window->id;*/ + GLuint group = 0; /*render_spu.nvSwapGroup + window->BltInfo.Base.id;*/ GLuint barrier = 0; JoinSwapGroup(dpy, visual->visual->screen, window->window, group, barrier); } @@ -844,9 +1148,15 @@ createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window ) * End GLX code */ crDebug( "Render SPU: actual window x, y, width, height: %d, %d, %d, %d", - window->x, window->y, window->width, window->height ); + window->x, window->y, window->BltInfo.width, window->BltInfo.height ); XSync(dpy, 0); + + if (window->BltInfo.Base.id != CR_RENDER_WINCMD_ID) + { + int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE, window); + AssertRC(rc); + } return GL_TRUE; } @@ -860,15 +1170,15 @@ createPBuffer( VisualInfo *visual, WindowInfo *window ) window->y = 0; window->nativeWindow = 0; - CRASSERT(window->width > 0); - CRASSERT(window->height > 0); + CRASSERT(window->BltInfo.width > 0); + CRASSERT(window->BltInfo.height > 0); #ifdef GLX_VERSION_1_3 { int attribs[100], i = 0, w, h; CRASSERT(visual->fbconfig); - w = window->width; - h = window->height; + w = window->BltInfo.width; + h = window->BltInfo.height; attribs[i++] = GLX_PRESERVED_CONTENTS; attribs[i++] = True; attribs[i++] = GLX_PBUFFER_WIDTH; @@ -896,8 +1206,8 @@ GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window ) { if (visual->visAttribs & CR_PBUFFER_BIT) { - window->width = render_spu.defaultWidth; - window->height = render_spu.defaultHeight; + window->BltInfo.width = render_spu.defaultWidth; + window->BltInfo.height = render_spu.defaultHeight; return createPBuffer(visual, window); } else { @@ -938,6 +1248,11 @@ renderspu_SystemDestroyWindow( WindowInfo *window ) * window. I know...personal responsibility and all... */ if (!window->nativeWindow) { + if (window->BltInfo.Base.id != CR_RENDER_WINCMD_ID) + { + int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY, window); + AssertRC(rc); + } XDestroyWindow(window->visual->dpy, window->window); XSync(window->visual->dpy, 0); } @@ -1000,7 +1315,7 @@ renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, Context if (visual->visual) crDebug("Render SPU: Created %s context (%d) on display %s for visAttribs 0x%x", is_direct ? "DIRECT" : "INDIRECT", - context->id, + context->BltInfo.Base.id, DisplayString(visual->dpy), visual->visAttribs); @@ -1152,18 +1467,18 @@ renderspu_SystemDestroyContext( ContextInfo *context ) static void check_buffer_size( WindowInfo *window ) { - if (window->width != window->in_buffer_width - || window->height != window->in_buffer_height + if (window->BltInfo.width != window->in_buffer_width + || window->BltInfo.height != window->in_buffer_height || ! window->buffer) { crFree(window->buffer); - window->buffer = crCalloc(window->width * window->height + window->buffer = crCalloc(window->BltInfo.width * window->BltInfo.height * 4 * sizeof (GLubyte)); - window->in_buffer_width = window->width; - window->in_buffer_height = window->height; + window->in_buffer_width = window->BltInfo.width; + window->in_buffer_height = window->BltInfo.height; - crDebug("Render SPU: dimensions changed to %d x %d", window->width, window->height); + crDebug("Render SPU: dimensions changed to %d x %d", window->BltInfo.width, window->BltInfo.height); } } #endif @@ -1176,7 +1491,6 @@ renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, Bool b; CRASSERT(render_spu.ws.glXMakeCurrent); - window->appWindow = nativeWindow; /*crDebug("%s nativeWindow=0x%x", __FUNCTION__, (int) nativeWindow);*/ @@ -1185,16 +1499,20 @@ renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, check_buffer_size(window); render_spu.OSMesaMakeCurrent( (OSMesaContext) context->context, window->buffer, GL_UNSIGNED_BYTE, - window->width, window->height); + window->BltInfo.width, window->BltInfo.height); return; } #endif + nativeWindow = 0; + if (window && context) { + window->appWindow = nativeWindow; + if (window->visual != context->visual) { crDebug("Render SPU: MakeCurrent visual mismatch (win(%d) bits:0x%x != ctx(%d) bits:0x%x); remaking window.", - window->id, window->visual->visAttribs, - context->id, context->visual->visAttribs); + window->BltInfo.Base.id, window->visual->visAttribs, + context->BltInfo.Base.id, context->visual->visAttribs); /* * XXX have to revisit this issue!!! * @@ -1273,7 +1591,7 @@ renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, if (vid != (int) context->visual->visual->visualid) { crWarning("Render SPU: Can't bind context %d to CRUT/native window " "0x%x because of different X visuals (0x%x != 0x%x)!", - context->id, (int) nativeWindow, + context->BltInfo.Base.id, (int) nativeWindow, vid, (int) context->visual->visual->visualid); crWarning("Render SPU: Trying to recreate GLX context to match."); /* Try to recreate the GLX context so that it uses the same @@ -1327,7 +1645,7 @@ renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, crWarning("glXMakeCurrent(%p, 0x%x, %p) failed! (winId %d, ctxId %d)", window->visual->dpy, (int) window->window, (void *) context->context, - window->id, context->id ); + window->BltInfo.Base.id, context->BltInfo.Base.id ); } /*CRASSERT(b);*/ } @@ -1344,6 +1662,18 @@ renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, } #endif } + else + { + GET_CONTEXT(pCurCtx); + if (pCurCtx) + { + b = render_spu.ws.glXMakeCurrent( pCurCtx->currentWindow->visual->dpy, None, NULL); + if (!b) { + crWarning("glXMakeCurrent(%p, None, NULL) failed!", pCurCtx->currentWindow->visual->dpy); + } + } + + } #if 0 /* XXX disabled for now due to problem with threadtest.conf */ @@ -1360,8 +1690,8 @@ renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h ) { #ifdef USE_OSMESA if (render_spu.use_osmesa) { - window->width = w; - window->height = h; + window->BltInfo.width = w; + window->BltInfo.height = h; check_buffer_size(window); return; } @@ -1394,7 +1724,7 @@ renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h ) } } - if (window->width != w || window->height != h) { + if (window->BltInfo.width != w || window->BltInfo.height != h) { /* Only resize if the new dimensions really are different */ #ifdef CHROMIUM_THREADSAFE ContextInfo *currentContext = (ContextInfo *) crGetTSD(&_RenderTSD); @@ -1403,10 +1733,10 @@ renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h ) #endif /* Can't resize pbuffers, so destroy it and make a new one */ render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window); - window->width = w; - window->height = h; + window->BltInfo.width = w; + window->BltInfo.height = h; crDebug("Render SPU: Creating new %d x %d PBuffer (id=%d)", - w, h, window->id); + w, h, window->BltInfo.Base.id); if (!createPBuffer(window->visual, window)) { crWarning("Render SPU: Unable to create PBuffer (out of VRAM?)!"); } @@ -1419,6 +1749,15 @@ renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h ) } } else { + if (!w || !h) + { + /* X can not handle zero sizes */ + if (window->visible) + { + renderspu_SystemShowWindow( window, GL_FALSE ); + } + return; + } /* Resize ordinary X window */ /* * This is ugly, but it seems to be the only thing that works. @@ -1432,6 +1771,16 @@ renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h ) crDebug("Render SPU: XResizeWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, w, h); XResizeWindow(window->visual->dpy, window->window, w, h); XSync(window->visual->dpy, 0); + + if (!window->BltInfo.width || !window->BltInfo.height) + { + /* we have hidden the window instead of sizing it to (0;0) since X is unable to handle zero sizes */ + if (window->visible) + { + renderspu_SystemShowWindow( window, GL_TRUE ); + return; + } + } #if 0 for (attempt = 0; attempt < 3; attempt++) { /* try three times max */ XWindowAttributes attribs; @@ -1444,10 +1793,6 @@ renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h ) } #endif } - - /* finally, save the new size */ - window->width = w; - window->height = h; } @@ -1457,8 +1802,8 @@ renderspu_SystemGetWindowGeometry( WindowInfo *window, { #ifdef USE_OSMESA if (render_spu.use_osmesa) { - *w = window->width; - *h = window->height; + *w = window->BltInfo.width; + *h = window->BltInfo.height; return; } #endif @@ -1470,8 +1815,8 @@ renderspu_SystemGetWindowGeometry( WindowInfo *window, { *x = 0; *y = 0; - *w = window->width; - *h = window->height; + *w = window->BltInfo.width; + *h = window->BltInfo.height; } else { @@ -1544,7 +1889,7 @@ renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y ) } void -renderspu_SystemWindowVisibleRegion( WindowInfo *window, GLint cRects, GLint *pRects ) +renderspu_SystemWindowVisibleRegion( WindowInfo *window, GLint cRects, const GLint *pRects ) { #ifdef USE_OSMESA if (render_spu.use_osmesa) @@ -1609,18 +1954,64 @@ renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt ) { if (showIt) { - XMapWindow( window->visual->dpy, window->window ); - XSync(window->visual->dpy, 0); + if (window->BltInfo.width && window->BltInfo.height) + { + XMapWindow( window->visual->dpy, window->window ); + XSync(window->visual->dpy, 0); + } } else { XUnmapWindow( window->visual->dpy, window->window ); XSync(window->visual->dpy, 0); } - window->visible = showIt; } } +void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry ) +{ + /* the CR_RENDER_FORCE_PRESENT_MAIN_THREAD is actually inherited from cocoa backend impl, + * here it forces rendering in WinCmd thread rather than a Main thread. + * it is used for debugging only in any way actually. + * @todo: change to some more generic macro name */ +#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD + const struct VBOXVR_SCR_COMPOSITOR *pCompositor; + /* we do not want to be blocked with the GUI thread here, so only draw her eif we are really able to do that w/o bllocking */ + int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor); + if (RT_SUCCESS(rc)) + { + renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0); + renderspuVBoxCompositorRelease(window); + } + else if (rc == VERR_SEM_BUSY) +#endif + { + Status status; + XEvent event; + render_spu.self.Flush(); + renderspuVBoxPresentBlitterEnsureCreated(window, 0); + + crMemset(&event, 0, sizeof (event)); + event.type = Expose; + event.xexpose.window = window->window; + event.xexpose.width = window->BltInfo.width; + event.xexpose.height = window->BltInfo.height; + status = XSendEvent(render_spu.pCommunicationDisplay, render_spu.WinCmdWindow.window, False, 0, &event); + if (!status) + { + Assert(0); + crWarning("XSendEvent returned null"); + } + XFlush(render_spu.pCommunicationDisplay); + } +#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD + else + { + /* this is somewhat we do not expect */ + crWarning("renderspuVBoxCompositorTryAcquire failed rc %d", rc); + } +#endif +} static void MarkWindow(WindowInfo *w) @@ -1632,7 +2023,7 @@ MarkWindow(WindowInfo *w) gcValues.function = GXnoop; gc = XCreateGC(w->visual->dpy, w->nativeWindow, GCFunction, &gcValues); } - XDrawLine(w->visual->dpy, w->nativeWindow, gc, 0, 0, w->width, w->height); + XDrawLine(w->visual->dpy, w->nativeWindow, gc, 0, 0, w->BltInfo.width, w->BltInfo.height); } @@ -1683,3 +2074,13 @@ void renderspu_SystemReparentWindow(WindowInfo *window) XReparentWindow(window->visual->dpy, window->window, parent, window->x, window->y); XSync(window->visual->dpy, False); } + +void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext) +{ + +} + +uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable) +{ + return cFunctions; +} diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c index d22af98f..6d46faf8 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c @@ -9,6 +9,7 @@ #include "cr_error.h" #include "cr_string.h" #include "cr_url.h" +#include "cr_environment.h" #include "renderspu.h" #include <stdio.h> @@ -94,16 +95,17 @@ static DWORD WINAPI renderSPUWindowThreadProc(void* unused) if (msg.message == WM_VBOX_RENDERSPU_CREATE_WINDOW) { LPCREATESTRUCT pCS = (LPCREATESTRUCT) msg.lParam; - HWND *phWnd; + HWND hWnd; + WindowInfo *pWindow = (WindowInfo *)pCS->lpCreateParams; CRASSERT(msg.lParam && !msg.wParam && pCS->lpCreateParams); - phWnd = pCS->lpCreateParams; - - *phWnd = CreateWindowEx(pCS->dwExStyle, pCS->lpszName, pCS->lpszClass, pCS->style, + hWnd = CreateWindowEx(pCS->dwExStyle, pCS->lpszName, pCS->lpszClass, pCS->style, pCS->x, pCS->y, pCS->cx, pCS->cy, pCS->hwndParent, pCS->hMenu, pCS->hInstance, &render_spu); + pWindow->hWnd = hWnd; + SetEvent(render_spu.hWinThreadReadyEvent); } else if (msg.message == WM_VBOX_RENDERSPU_DESTROY_WINDOW) @@ -138,6 +140,8 @@ renderSPUInit( int id, SPU *child, SPU *self, int numFuncs, numSpecial; GLint defaultWin, defaultCtx; WindowInfo *windowInfo; + const char * pcpwSetting; + int rc; (void) child; (void) context_id; @@ -188,20 +192,39 @@ renderSPUInit( int id, SPU *child, SPU *self, numFuncs += numSpecial; -#ifdef GLX - if (!render_spu.use_glxchoosevisual) { - /* sometimes want to set this option with ATI drivers */ - render_spu.ws.glXChooseVisual = NULL; + render_spu.contextTable = crAllocHashtableEx(1, INT32_MAX); + render_spu.windowTable = crAllocHashtableEx(1, INT32_MAX); + + render_spu.dummyWindowTable = crAllocHashtable(); + + pcpwSetting = crGetenv("CR_RENDER_ENABLE_SINGLE_PRESENT_CONTEXT"); + if (pcpwSetting) + { + if (pcpwSetting[0] == '0') + pcpwSetting = NULL; } -#endif - render_spu.window_id = 0; - render_spu.context_id = 0; - render_spu.contextTable = crAllocHashtable(); - render_spu.windowTable = crAllocHashtable(); + if (pcpwSetting) + { + /* TODO: need proper blitter synchronization, do not use so far! + * the problem is that rendering can be done in multiple thread: the main command (hgcm) thread and the redraw thread + * we currently use per-window synchronization, while we'll need a per-blitter synchronization if one blitter is used for multiple windows + * this is not done currently */ + crWarning("TODO: need proper blitter synchronization, do not use so far!"); + render_spu.blitterTable = crAllocHashtable(); + CRASSERT(render_spu.blitterTable); + } + else + render_spu.blitterTable = NULL; CRASSERT(render_spu.default_visual & CR_RGB_BIT); - + + rc = renderspu_SystemInit(); + if (!RT_SUCCESS(rc)) + { + crError("renderspu_SystemInit failed rc %d", rc); + return NULL; + } #ifdef USE_OSMESA if (render_spu.use_osmesa) { if (!crLoadOSMesa(&render_spu.OSMesaCreateContext, @@ -249,8 +272,8 @@ renderSPUInit( int id, SPU *child, SPU *self, */ crDebug("Render SPU: Creating default window (visBits=0x%x, id=0)", render_spu.default_visual); - defaultWin = renderspuWindowCreate( NULL, render_spu.default_visual ); - if (defaultWin != 0) { + defaultWin = renderspuWindowCreateEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_WINDOW_ID ); + if (defaultWin != CR_RENDER_DEFAULT_WINDOW_ID) { crError("Render SPU: Couldn't get a double-buffered, RGB visual with Z!"); return NULL; } @@ -258,13 +281,16 @@ renderSPUInit( int id, SPU *child, SPU *self, crDebug("Render SPU: Creating default context, visBits=0x%x", render_spu.default_visual ); - defaultCtx = renderspuCreateContext( NULL, render_spu.default_visual, 0 ); - CRASSERT(defaultCtx == 0); + defaultCtx = renderspuCreateContextEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_CONTEXT_ID, 0 ); + if (defaultCtx != CR_RENDER_DEFAULT_CONTEXT_ID) { + crError("Render SPU: failed to create default context!"); + return NULL; + } renderspuMakeCurrent( defaultWin, 0, defaultCtx ); /* Get windowInfo for the default window */ - windowInfo = (WindowInfo *) crHashtableSearch(render_spu.windowTable, 0); + windowInfo = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID); CRASSERT(windowInfo); windowInfo->mapPending = GL_TRUE; @@ -347,17 +373,21 @@ renderSPUInit( int id, SPU *child, SPU *self, render_spu.gather_conns = NULL; + numFuncs = renderspu_SystemPostprocessFunctions(_cr_render_table, numFuncs, RT_ELEMENTS(_cr_render_table)); + crDebug("Render SPU: ---------- End of Init -------------"); return &render_functions; } - static void renderSPUSelfDispatch(SPUDispatchTable *self) { crSPUInitDispatchTable( &(render_spu.self) ); crSPUCopyDispatchTable( &(render_spu.self), self ); + crSPUInitDispatchTable( &(render_spu.blitterDispatch) ); + crSPUCopyDispatchTable( &(render_spu.blitterDispatch), self ); + render_spu.server = (CRServer *)(self->server); { @@ -377,8 +407,7 @@ static void renderSPUSelfDispatch(SPUDispatchTable *self) static void DeleteContextCallback( void *data ) { ContextInfo *context = (ContextInfo *) data; - renderspu_SystemDestroyContext(context); - crFree(context); + renderspuContextMarkDeletedAndRelease(context); } static void DeleteWindowCallback( void *data ) @@ -388,12 +417,45 @@ static void DeleteWindowCallback( void *data ) crFree(window); } +static void DeleteBlitterCallback( void *data ) +{ + PCR_BLITTER pBlitter = (PCR_BLITTER) data; + CrBltTerm(pBlitter); + crFree(pBlitter); +} + +static void renderspuBlitterCleanupCB(unsigned long key, void *data1, void *data2) +{ + WindowInfo *window = (WindowInfo *) data1; + CRASSERT(window); + + renderspuVBoxPresentBlitterCleanup( window ); +} + static int renderSPUCleanup(void) { + renderspuVBoxCompositorClearAll(); + + if (render_spu.blitterTable) + { + crFreeHashtable(render_spu.blitterTable, DeleteBlitterCallback); + render_spu.blitterTable = NULL; + } + else + { + crHashtableWalk(render_spu.windowTable, renderspuBlitterCleanupCB, NULL); + + crHashtableWalk(render_spu.dummyWindowTable, renderspuBlitterCleanupCB, NULL); + } + + renderspuSetDefaultSharedContext(NULL); + crFreeHashtable(render_spu.contextTable, DeleteContextCallback); render_spu.contextTable = NULL; crFreeHashtable(render_spu.windowTable, DeleteWindowCallback); render_spu.windowTable = NULL; + crFreeHashtable(render_spu.dummyWindowTable, DeleteWindowCallback); + render_spu.dummyWindowTable = NULL; crFreeHashtable(render_spu.barrierHash, crFree); render_spu.barrierHash = NULL; @@ -482,26 +544,3 @@ DECLEXPORT(void) renderspuSetWindowId(uint64_t winId) { render_spu_parent_window_id = winId; } - -static void renderspuWindowVisibleRegionCB(unsigned long key, void *data1, void *data2) -{ - WindowInfo *window = (WindowInfo *) data1; - CRASSERT(window); - - renderspu_SystemWindowApplyVisibleRegion(window); -} - -DECLEXPORT(void) renderspuSetRootVisibleRegion(GLint cRects, GLint *pRects) -{ -#ifdef RT_OS_DARWIN - renderspu_SystemSetRootVisibleRegion(cRects, pRects); - - crHashtableWalk(render_spu.windowTable, renderspuWindowVisibleRegionCB, NULL); -#endif -} - -#ifndef RT_OS_DARWIN -void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window) -{ -} -#endif diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c index c1a903f0..1bd745a8 100644 --- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c @@ -425,7 +425,49 @@ MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) /* int w,h; */ switch ( uMsg ) { + case WM_PAINT: + { + WindowInfo *pWindow = (WindowInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + if (pWindow) + { + const struct VBOXVR_SCR_COMPOSITOR * pCompositor; + + pCompositor = renderspuVBoxCompositorAcquire(pWindow); + if (pCompositor) + { + HDC hDC; + PAINTSTRUCT Paint; + + Assert(pWindow->device_context); + hDC = BeginPaint(pWindow->hWnd, &Paint); + if (hDC) + { + BOOL bRc; + pWindow->redraw_device_context = hDC; + renderspuVBoxPresentCompositionGeneric(pWindow, pCompositor, NULL, 1); + + bRc = EndPaint(pWindow->hWnd, &Paint); + + pWindow->redraw_device_context = NULL; + + renderspuVBoxCompositorRelease(pWindow); + + if (!bRc) + { + DWORD winEr = GetLastError(); + crWarning("EndPaint failed, winEr %d", winEr); + } + } + else + { + DWORD winEr = GetLastError(); + crWarning("BeginPaint failed, winEr %d", winEr); + } + } + } + break; + } case WM_SIZE: /* w = LOWORD( lParam ); * h = HIWORD( lParam ); */ @@ -557,7 +599,11 @@ bSetupPixelFormatEXT( HDC hdc, GLbitfield visAttribs) crDebug("Render SPU: wglChoosePixelFormatEXT (vis 0x%x, LastError 0x%x, pixelFormat 0x%x", vis, GetLastError(), pixelFormat); +#ifdef VBOX_CR_SERVER_FORCE_WGL render_spu.ws.wglSetPixelFormat( hdc, pixelFormat, &ppfd ); +#else + SetPixelFormat( hdc, pixelFormat, &ppfd ); +#endif crDebug("Render SPU: wglSetPixelFormat (Last error 0x%x)", GetLastError()); @@ -616,6 +662,7 @@ bSetupPixelFormatNormal( HDC hdc, GLbitfield visAttribs ) * by our faker library, otherwise we have to call the GDI * versions. */ +#ifdef VBOX_CR_SERVER_FORCE_WGL if (crGetenv( "CR_WGL_DO_NOT_USE_GDI" ) != NULL) { pixelformat = render_spu.ws.wglChoosePixelFormat( hdc, ppfd ); @@ -633,6 +680,7 @@ bSetupPixelFormatNormal( HDC hdc, GLbitfield visAttribs ) render_spu.ws.wglDescribePixelFormat( hdc, pixelformat, sizeof(*ppfd), ppfd ); } else +#endif { /* Okay, we were loaded manually. Call the GDI functions. */ pixelformat = ChoosePixelFormat( hdc, ppfd ); @@ -782,27 +830,27 @@ GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, Wi int smCyFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME ) + 1; int smCyCaption = GetSystemMetrics( SM_CYCAPTION ); - window->width = GetSystemMetrics( SM_CXSCREEN ) ; - window->height = GetSystemMetrics( SM_CYSCREEN ) ; + window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ; + window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ; - crDebug( "Render SPU: Window Dims: %d, %d", window->width, window->height ); + crDebug( "Render SPU: Window Dims: %d, %d", window->BltInfo.width, window->BltInfo.height ); window->x = render_spu->defaultX - smCxFixedFrame - 1; window->y = render_spu->defaultY - smCyFixedFrame - smCyCaption; - window_plus_caption_width = window->width + 2 * smCxFixedFrame; - window_plus_caption_height = window->height + 2 * smCyFixedFrame + smCyCaption; + window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame; + window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption; #else /* Since it's undecorated, we don't have to do anything fancy * with these parameters. */ - window->width = GetSystemMetrics( SM_CXSCREEN ) ; - window->height = GetSystemMetrics( SM_CYSCREEN ) ; + window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ; + window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ; window->x = 0; window->y = 0; - window_plus_caption_width = window->width; - window_plus_caption_height = window->height; + window_plus_caption_width = window->BltInfo.width; + window_plus_caption_height = window->BltInfo.height; #endif } @@ -819,8 +867,8 @@ GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, Wi smCyCaption = GetSystemMetrics( SM_CYCAPTION ); crDebug( "Render SPU: Got the Caption " ); - window_plus_caption_width = window->width + 2 * smCxFixedFrame; - window_plus_caption_height = window->height + 2 * smCyFixedFrame + smCyCaption; + window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame; + window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption; window->x = render_spu.defaultX - smCxFixedFrame; window->y = render_spu.defaultY - smCyFixedFrame - smCyCaption; @@ -845,11 +893,11 @@ GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, Wi if (!showIt) { renderspu_SystemShowWindow( window, 0 ); - if (window->height <= 0 || window->width <= 0) + if (window->BltInfo.height <= 0 || window->BltInfo.width <= 0) { renderspu_SystemWindowSize(window, - window->width > 0 ? window->width : 4, - window->height > 0 ? window->height : 4); + window->BltInfo.width > 0 ? window->BltInfo.width : 4, + window->BltInfo.height > 0 ? window->BltInfo.height : 4); } } else @@ -878,6 +926,11 @@ GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, Wi ShowCursor( FALSE ); window->device_context = GetDC( window->hWnd ); + if (!window->device_context) + { + DWORD winEr = GetLastError(); + crWarning("GetDC failed, winEr %d", winEr); + } crDebug( "Render SPU: Got the DC: 0x%x", window->device_context ); @@ -998,27 +1051,27 @@ GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt int smCyFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME ) + 1; int smCyCaption = GetSystemMetrics( SM_CYCAPTION ); - window->width = GetSystemMetrics( SM_CXSCREEN ) ; - window->height = GetSystemMetrics( SM_CYSCREEN ) ; + window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ; + window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ; - crDebug( "Render SPU: Window Dims: %d, %d", window->width, window->height ); + crDebug( "Render SPU: Window Dims: %d, %d", window->BltInfo.width, window->BltInfo.height ); window->x = render_spu->defaultX - smCxFixedFrame - 1; window->y = render_spu->defaultY - smCyFixedFrame - smCyCaption; - window_plus_caption_width = window->width + 2 * smCxFixedFrame; - window_plus_caption_height = window->height + 2 * smCyFixedFrame + smCyCaption; + window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame; + window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption; #else /* Since it's undecorated, we don't have to do anything fancy * with these parameters. */ - window->width = GetSystemMetrics( SM_CXSCREEN ) ; - window->height = GetSystemMetrics( SM_CYSCREEN ) ; + window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ; + window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ; window->x = 0; window->y = 0; - window_plus_caption_width = window->width; - window_plus_caption_height = window->height; + window_plus_caption_width = window->BltInfo.width; + window_plus_caption_height = window->BltInfo.height; #endif } @@ -1034,8 +1087,8 @@ GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt smCyCaption = GetSystemMetrics( SM_CYCAPTION ); crDebug( "Render SPU: Got the Caption " ); - window_plus_caption_width = window->width + 2 * smCxFixedFrame; - window_plus_caption_height = window->height + 2 * smCyFixedFrame + smCyCaption; + window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame; + window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption; window->x = render_spu.defaultX; window->y = render_spu.defaultY; @@ -1046,13 +1099,13 @@ GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt WINDOW_NAME, WINDOW_NAME, window_style, window->x, window->y, - window->width, - window->height, + window->BltInfo.width, + window->BltInfo.height, (void*) render_spu_parent_window_id, NULL, hinstance, &render_spu );*/ { CREATESTRUCT cs; - cs.lpCreateParams = &window->hWnd; + cs.lpCreateParams = window; cs.dwExStyle = WS_EX_NOACTIVATE | WS_EX_NOPARENTNOTIFY; cs.lpszName = WINDOW_NAME; @@ -1060,8 +1113,8 @@ GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt cs.style = window_style; cs.x = window->x; cs.y = window->y; - cs.cx = window->width; - cs.cy = window->height; + cs.cx = window->BltInfo.width; + cs.cy = window->BltInfo.height; cs.hwndParent = (void*) render_spu_parent_window_id; cs.hMenu = NULL; cs.hInstance = hinstance; @@ -1110,16 +1163,20 @@ GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt if (!showIt) { renderspu_SystemShowWindow( window, 0 ); - if (window->height <= 0 || window->width <= 0) + if (window->BltInfo.height <= 0 || window->BltInfo.width <= 0) { renderspu_SystemWindowSize(window, - window->width > 0 ? window->width : 4, - window->height > 0 ? window->height : 4); + window->BltInfo.width > 0 ? window->BltInfo.width : 4, + window->BltInfo.height > 0 ? window->BltInfo.height : 4); } } else { +#ifdef DEBUG_misha + crWarning( "Render SPU: Showing the window" ); +#else crDebug( "Render SPU: Showing the window" ); +#endif crDebug("renderspu_SystemCreateWindow: showwindow: %x", window->hWnd); } @@ -1127,7 +1184,7 @@ GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt /* Intel drivers require a window to be visible for proper 3D rendering, * so set it visible and handle the visibility with visible regions (see below) */ - if (window->id) + if (window->BltInfo.Base.id != CR_RENDER_DEFAULT_WINDOW_ID) { ShowWindow( window->hWnd, SW_SHOWNORMAL ); } @@ -1140,17 +1197,22 @@ GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt //SetForegroundWindow( visual->hWnd ); SetWindowPos( window->hWnd, HWND_TOP, window->x, window->y, - window->width, window->height, + window->BltInfo.width, window->BltInfo.height, ( render_spu.fullscreen ? (SWP_SHOWWINDOW | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOACTIVATE ) : SWP_NOACTIVATE ) ); crDebug("Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd, - window->x, window->y, window->width, window->height); + window->x, window->y, window->BltInfo.width, window->BltInfo.height); if ( render_spu.fullscreen ) ShowCursor( FALSE ); window->device_context = GetDC( window->hWnd ); + if (!window->device_context) + { + DWORD winEr = GetLastError(); + crWarning("GetDC failed, winEr %d", winEr); + } crDebug( "Render SPU: Got the DC: 0x%x", window->device_context ); @@ -1160,16 +1222,52 @@ GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt return GL_FALSE; } + /* set the window pointer data at the last step to ensure our WM_PAINT callback does not do anything until we are fully initialized */ + { + LONG_PTR oldVal = SetWindowLongPtr(window->hWnd, GWLP_USERDATA, (LONG_PTR)window); + DWORD winEr = GetLastError(); + Assert(!oldVal && winEr == NO_ERROR); + } + return GL_TRUE; } +static void renderspuWindowRgnApply(WindowInfo *window) +{ + HRGN hRgn = window->hRgn; + if (hRgn) + { + /* note: according to the docs, SetWindowRgn owns the regions after it is called, + * and the regions will be freed automatically when needed, + * i.e. the caller should not do that. + * this is why we need to make a copy of the regions to be passed in */ + + int result; + hRgn = CreateRectRgn(0, 0, 0, 0); + if (!hRgn) + { + WARN(("CreateRectRgn failed")); + return; + } + + result = CombineRgn(hRgn, window->hRgn, NULL, RGN_COPY); + if (result == ERROR) + { + WARN(("CombineRgn failed")); + return; + } + } + + SetWindowRgn(window->hWnd, hRgn, true); +} + /* Either show or hide the render SPU's window. */ void renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt ) { if (showIt) { crDebug("SHOW renderspu_SystemShowWindow: %x", window->hWnd); - SetWindowRgn(window->hWnd, window->hRgn, true); + renderspuWindowRgnApply(window); } else { @@ -1177,11 +1275,44 @@ void renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt ) crDebug("HIDE renderspu_SystemShowWindow: %x", window->hWnd); hRgn = CreateRectRgn(0, 0, 0, 0); SetWindowRgn(window->hWnd, hRgn, true); - DeleteObject(hRgn); + /* note: according to the docs, SetWindowRgn owns the regions after it is called, + * and the regions will be freed automatically when needed, + * i.e. the caller should not do that */ } window->visible = showIt; } +void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry ) +{ + /* the CR_RENDER_FORCE_PRESENT_MAIN_THREAD is actually inherited from cocoa backend impl, + * here it forces rendering in WinCmd thread rather than a Main thread. + * it is used for debugging only in any way actually. + * @todo: change to some more generic macro name */ +#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD + const struct VBOXVR_SCR_COMPOSITOR *pCompositor; + /* we do not want to be blocked with the GUI thread here, so only draw her eif we are really able to do that w/o bllocking */ + int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor); + if (RT_SUCCESS(rc)) + { + renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0); + renderspuVBoxCompositorRelease(window); + } + else if (rc == VERR_SEM_BUSY) +#endif + { + render_spu.self.Flush(); + renderspuVBoxPresentBlitterEnsureCreated(window, 0); + RedrawWindow(window->hWnd, NULL, NULL, RDW_INTERNALPAINT); + } +#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD + else + { + /* this is somewhat we do not expect */ + crWarning("renderspuVBoxCompositorTryAcquire failed rc %d", rc); + } +#endif +} + GLboolean renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext ) { (void) sharedContext; @@ -1215,29 +1346,20 @@ void renderspu_SystemDestroyContext( ContextInfo *context ) static GLboolean renderspuChkActivateSharedContext(ContextInfo *sharedContext) { - GLint crWindow; WindowInfo *window; if (sharedContext->hRC) return GL_TRUE; - CRASSERT(sharedContext->id); + CRASSERT(sharedContext->BltInfo.Base.id); if (sharedContext->shared) renderspuChkActivateSharedContext(sharedContext->shared); - crWindow = renderspuWindowCreate(sharedContext->visual->displayName, sharedContext->visual->visAttribs); - if (!crWindow) - { - crError("renderspuChkActivateSharedContext: renderspuWindowCreate failed!"); - return GL_FALSE; - } - - window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, crWindow); + window = renderspuGetDummyWindow(sharedContext->visual->visAttribs); if (!window) { - crError("renderspuChkActivateSharedContext: crHashtableSearch failed!"); - renderspuWindowDestroy(crWindow); + crError("renderspuChkActivateSharedContext: renderspuGetDummyWindow failed!"); return GL_FALSE; } @@ -1249,12 +1371,9 @@ static GLboolean renderspuChkActivateSharedContext(ContextInfo *sharedContext) if (!sharedContext->hRC) { crError( "Render SPU: (renderspuChkActivateSharedContext) Couldn't create the context for the window (error 0x%x)", GetLastError() ); - renderspuWindowDestroy(crWindow); return GL_FALSE; } - sharedContext->currentWindow = window; - return GL_TRUE; } @@ -1274,12 +1393,12 @@ void renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, Contex /*@todo Chromium has no correct code to remove window ids and associated info from * various tables. This is hack which just hides the root case. */ - crDebug("Recreating window in renderspu_SystemMakeCurrent\n"); + crWarning("Recreating window in renderspu_SystemMakeCurrent\n"); renderspu_SystemDestroyWindow( window ); renderspu_SystemVBoxCreateWindow( context->visual, window->visible, window ); } - if (render_spu.render_to_app_window && nativeWindow) + if (0/*render_spu.render_to_app_window && nativeWindow*/) { /* The render_to_app_window option * is set and we've got a nativeWindow @@ -1320,6 +1439,7 @@ void renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, Contex else { if (!context->hRC) { + CRASSERT(!nativeWindow); if (context->shared) { /* first make sure we have shared context created */ @@ -1337,11 +1457,16 @@ void renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, Contex && context->hRC) { /* share lists */ - render_spu.ws.wglShareLists(context->shared->hRC, context->hRC); + BOOL bRc = render_spu.ws.wglShareLists(context->shared->hRC, context->hRC); + if (!bRc) + { + DWORD winEr = GetLastError(); + crWarning("wglShareLists failed, winEr %d", winEr); + } } /*Requery ext function pointers, we skip dummy ctx as it should never be used with ext functions*/ - if (0 && context->id) + if (0 && context->BltInfo.Base.id) { int numFuncs, i; SPUNamedFunctionTable ext_table[1000]; @@ -1366,7 +1491,7 @@ void renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, Contex } /*crDebug("MakeCurrent 0x%x, 0x%x", window->device_context, context->hRC);*/ - if (!render_spu.ws.wglMakeCurrent(window->device_context, context->hRC)) + if (!render_spu.ws.wglMakeCurrent(!nativeWindow ? window->device_context : window->redraw_device_context, context->hRC)) { DWORD err = GetLastError(); crError("Render SPU: (MakeCurrent) failed to make 0x%x, 0x%x current with 0x%x error.", window->device_context, context->hRC, err); @@ -1400,8 +1525,8 @@ void renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h ) crDebug("Render SPU: SetWindowSize (%x, %d, %d, %d, %d)", window->hWnd, window->x, window->y, w, h); } /* save the new size */ - window->width = w; - window->height = h; + window->BltInfo.width = w; + window->BltInfo.height = h; } @@ -1443,18 +1568,18 @@ void renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y ) /*SetWindowRgn(window->visual->hWnd, NULL, false);*/ if (!SetWindowPos( window->hWnd, HWND_TOP, - x, y, window->width, window->height, winprop )) { - crWarning("!!!FAILED!!! Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd, x, y, window->width, window->height); + x, y, window->BltInfo.width, window->BltInfo.height, winprop )) { + crWarning("!!!FAILED!!! Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd, x, y, window->BltInfo.width, window->BltInfo.height); } else { crDebug("Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd, - x, y, window->width, window->height); + x, y, window->BltInfo.width, window->BltInfo.height); } /* save the new position */ window->x = x; window->y = y; } -void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, GLint* pRects) +void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects) { GLint i; HRGN hRgn, hTmpRgn; @@ -1477,12 +1602,12 @@ void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, GLint DeleteObject(hTmpRgn); } + window->hRgn = hRgn; + if (window->visible) - SetWindowRgn(window->hWnd, hRgn, true); + renderspuWindowRgnApply(window); crDebug("Render SPU: SetWindowRgn (%x, cRects=%i)", window->hWnd, cRects); - - window->hRgn = hRgn; } static void renderspuHandleWindowMessages( HWND hWnd ) @@ -1502,7 +1627,7 @@ void renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags ) int return_value; /* peek at the windows message queue */ - renderspuHandleWindowMessages( w->hWnd ); +// renderspuHandleWindowMessages( w->hWnd ); /* render_to_app_window: * w->nativeWindow will only be non-zero if the @@ -1511,14 +1636,18 @@ void renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags ) * structure. */ if (render_spu.render_to_app_window && w->nativeWindow) { +#ifdef VBOX_CR_SERVER_FORCE_WGL return_value = render_spu.ws.wglSwapBuffers( w->nativeWindow ); +#else + return_value = SwapBuffers( w->nativeWindow ); +#endif } else { /* HRGN hRgn1, hRgn2, hRgn3; HWND hWndParent; LONG ws; - hRgn1 = CreateRectRgn(0, 0, w->width, w->height); + hRgn1 = CreateRectRgn(0, 0, w->BltInfo.width, w->BltInfo.height); hRgn2 = CreateRectRgn(50, 50, 100, 100); hRgn3 = CreateRectRgn(0, 0, 0, 0); CombineRgn(hRgn3, hRgn1, hRgn2, RGN_DIFF); @@ -1554,7 +1683,11 @@ void renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags ) return_value, NULLREGION, SIMPLEREGION, COMPLEXREGION, ERROR); crDebug("rcClip(%d, %d, %d, %d)", rcClip.left, rcClip.top, rcClip.right, rcClip.bottom); */ +#ifdef VBOX_CR_SERVER_FORCE_WGL return_value = render_spu.ws.wglSwapBuffers( w->device_context ); +#else + return_value = SwapBuffers( w->device_context ); +#endif } if (!return_value) { @@ -1570,3 +1703,23 @@ void renderspu_SystemReparentWindow(WindowInfo *window) { SetParent(window->hWnd, (HWND)render_spu_parent_window_id); } + +int renderspu_SystemInit() +{ + return VINF_SUCCESS; +} + +int renderspu_SystemTerm() +{ + return VINF_SUCCESS; +} + +void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext) +{ + +} + +uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable) +{ + return cFunctions; +} |
