diff options
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/render/renderspu.c')
-rw-r--r-- | src/VBox/HostServices/SharedOpenGL/render/renderspu.c | 1960 |
1 files changed, 1960 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu.c new file mode 100644 index 00000000..52a1dfca --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu.c @@ -0,0 +1,1960 @@ +/* Copyright (c) 2001, Stanford University + * All rights reserved + * + * See the file LICENSE.txt for information on redistributing this software. + */ + +#include "cr_environment.h" +#include "cr_string.h" +#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) +{ + CRMessage *in, out; + + out.header.type = CR_MESSAGE_OOB; + + if (render_spu.is_swap_master) + { + int a; + + for (a = 0; a < render_spu.num_swap_clients; a++) + { + crNetGetMessage( render_spu.swap_conns[a], &in ); + crNetFree( render_spu.swap_conns[a], in); + } + + for (a = 0; a < render_spu.num_swap_clients; a++) + crNetSend( render_spu.swap_conns[a], NULL, &out, sizeof(CRMessage)); + } + else + { + crNetSend( render_spu.swap_conns[0], NULL, &out, sizeof(CRMessage)); + + crNetGetMessage( render_spu.swap_conns[0], &in ); + crNetFree( render_spu.swap_conns[0], in); + } +} + + + +/* + * Visual functions + */ + +/** + * used for debugging and giving info to the user. + */ +void +renderspuMakeVisString( GLbitfield visAttribs, char *s ) +{ + s[0] = 0; + + if (visAttribs & CR_RGB_BIT) + crStrcat(s, "RGB"); + if (visAttribs & CR_ALPHA_BIT) + crStrcat(s, "A"); + if (visAttribs & CR_DOUBLE_BIT) + crStrcat(s, ", Doublebuffer"); + if (visAttribs & CR_STEREO_BIT) + crStrcat(s, ", Stereo"); + if (visAttribs & CR_DEPTH_BIT) + crStrcat(s, ", Z"); + if (visAttribs & CR_STENCIL_BIT) + crStrcat(s, ", Stencil"); + if (visAttribs & CR_ACCUM_BIT) + crStrcat(s, ", Accum"); + if (visAttribs & CR_MULTISAMPLE_BIT) + crStrcat(s, ", Multisample"); + if (visAttribs & CR_OVERLAY_BIT) + crStrcat(s, ", Overlay"); + if (visAttribs & CR_PBUFFER_BIT) + 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 + * bitmask, or return a pointer to a new visual. + */ +VisualInfo * +renderspuFindVisual(const char *displayName, GLbitfield visAttribs) +{ + int i; + + if (!displayName) + displayName = ""; + + /* first, try to find a match */ +#if defined(WINDOWS) || defined(DARWIN) + for (i = 0; i < render_spu.numVisuals; i++) { + if (visAttribs == render_spu.visuals[i].visAttribs) { + return &(render_spu.visuals[i]); + } + } +#elif defined(GLX) + for (i = 0; i < render_spu.numVisuals; i++) { + if (crStrcmp(displayName, render_spu.visuals[i].displayName) == 0 + && visAttribs == render_spu.visuals[i].visAttribs) { + return &(render_spu.visuals[i]); + } + } +#endif + + if (render_spu.numVisuals >= MAX_VISUALS) + { + crWarning("Render SPU: Couldn't create a visual, too many visuals already"); + return NULL; + } + + /* create a new visual */ + i = render_spu.numVisuals; + if (renderspuInitVisual(&(render_spu.visuals[i]), displayName, visAttribs)) { + render_spu.numVisuals++; + return &(render_spu.visuals[i]); + } + else { + crWarning("Render SPU: Couldn't get a visual, renderspu_SystemInitVisual failed"); + return NULL; + } +} + +static ContextInfo * renderspuCreateContextInternal(const char *dpyName, GLint visBits, GLint idCtx, ContextInfo * sharedContext) +{ + ContextInfo *context; + VisualInfo *visual; + + 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 NULL; + + context = (ContextInfo *) crCalloc(sizeof(ContextInfo)); + if (!context) + return NULL; + context->BltInfo.Base.id = idCtx; + context->shared = sharedContext; + if (!renderspu_SystemCreateContext(visual, context, sharedContext)) + return NULL; + + crHashtableAdd(render_spu.contextTable, idCtx, context); + + context->BltInfo.Base.visualBits = visual->visAttribs; + /* + crDebug("Render SPU: CreateContext(%s, 0x%x) returning %d", + dpyName, visBits, context->BltInfo.Base.id); + */ + + if (sharedContext) + renderspuContextRetain(sharedContext); + + context->cRefs = 1; + + return context; +} + +GLint renderspuCreateContextEx(const char *dpyName, GLint visBits, GLint id, GLint shareCtx) +{ + ContextInfo *context, *sharedContext = NULL; + + if (shareCtx) { + sharedContext + = (ContextInfo *) crHashtableSearch(render_spu.contextTable, shareCtx); + CRASSERT(sharedContext); + } + + 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; + } + + if (context->shared) + renderspuContextRelease( context->shared ); + + crFree(context); +} + +uint32_t renderspuContextRetain( ContextInfo *context ) +{ + Assert(context->cRefs); + return ASMAtomicIncU32(&context->cRefs); +} + +uint32_t renderspuContextRelease( ContextInfo *context ) +{ + uint32_t cRefs = ASMAtomicDecU32(&context->cRefs); + if (!cRefs) + renderspuDestroyContextTerminate( context ); + else + CRASSERT(cRefs < UINT32_MAX/2); + return cRefs; +} + +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; + } + + 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* renderspuWinCreate(GLint visBits, GLint id) +{ + WindowInfo* window = (WindowInfo *)crAlloc(sizeof (*window)); + if (!window) + { + crWarning("crAlloc failed"); + return NULL; + } + + if (!renderspuWinInit(window, NULL, visBits, id)) + { + crWarning("renderspuWinInit failed"); + crFree(window); + return NULL; + } + + return window; +} + +void renderspuWinTermOnShutdown(WindowInfo *window) +{ + renderspuVBoxCompositorSet(window, NULL); + renderspuVBoxPresentBlitterCleanup(window); + window->BltInfo.Base.id = -1; + renderspu_SystemDestroyWindow( window ); +} + +static void renderspuCheckCurrentCtxWindowCB(unsigned long key, void *data1, void *data2) +{ + ContextInfo *pCtx = (ContextInfo *) data1; + WindowInfo *pWindow = data2; + (void) key; + + if (pCtx->currentWindow==pWindow) + { + 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 renderspuWinTerm( WindowInfo *window ) +{ + if (!renderspuWinIsTermed(window)) + { + + GET_CONTEXT(pOldCtx); + WindowInfo * pOldWindow = pOldCtx ? pOldCtx->currentWindow : NULL; + CRASSERT(!pOldCtx == !pOldWindow); + /* ensure no concurrent draws can take place */ + renderspuWinTermOnShutdown(window); + /* 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); + } + } + + } +} + +void renderspuWinCleanup(WindowInfo *window) +{ + renderspuWinTerm( window ); + RTCritSectDelete(&window->CompositorLock); +} + +void renderspuWinDestroy(WindowInfo *window) +{ + renderspuWinCleanup(window); + crFree(window); +} + +WindowInfo* renderspuGetDummyWindow(GLint visBits) +{ + WindowInfo *window = (WindowInfo *) crHashtableSearch(render_spu.dummyWindowTable, visBits); + if (!window) + { + window = renderspuWinCreate(visBits, -1); + if (!window) + { + WARN(("renderspuWinCreate failed")); + return NULL; + } + + crHashtableAdd(render_spu.dummyWindowTable, visBits, window); + } + + return window; +} + +/* Check that OpenGL extensions listed in pszRequiredExts string also exist in the pszAvailableExts string. */ +static void renderCompareGLExtensions(const char *pszAvailableExts, const char *pszRequiredExts) +{ + unsigned char fPrintHeader = 1; + const char *pszExt = pszRequiredExts; + + for (;;) + { + const char *pszSrc = pszAvailableExts; + size_t offExtEnd; + + while (*pszExt == ' ') + ++pszExt; + + if (!*pszExt) + break; + + offExtEnd = RTStrOffCharOrTerm(pszExt, ' '); + + for (;;) + { + size_t offSrcEnd; + + while (*pszSrc == ' ') + ++pszSrc; + + if (!*pszSrc) + break; + + offSrcEnd = RTStrOffCharOrTerm(pszSrc, ' '); + + if ( offSrcEnd == offExtEnd + && memcmp(pszSrc, pszExt, offSrcEnd) == 0) + break; + + pszSrc += offSrcEnd; + } + + if (!*pszSrc) + { + if (fPrintHeader) + { + fPrintHeader = 0; + crInfo("Host does not support OpenGL extension(s):"); + } + crInfo(" %.*s", offExtEnd, pszExt); + } + + pszExt += offExtEnd; + } +} + +void renderspuPerformMakeCurrent(WindowInfo *window, GLint nativeWindow, ContextInfo *context) +{ + if (window && context) + { +#ifdef CHROMIUM_THREADSAFE + crSetTSD(&_RenderTSD, context); +#else + render_spu.currentContext = context; +#endif + context->currentWindow = window; + + renderspu_SystemMakeCurrent( window, nativeWindow, context ); + if (!context->everCurrent) { + static volatile uint32_t u32ExtCompared = 0; + /* print OpenGL info */ + const char *extString = (const char *) render_spu.ws.glGetString( GL_EXTENSIONS ); + /* + crDebug( "Render SPU: GL_EXTENSIONS: %s", render_spu.ws.glGetString( GL_EXTENSIONS ) ); + */ + crInfo( "Render SPU: GL_VENDOR: %s", render_spu.ws.glGetString( GL_VENDOR ) ); + crInfo( "Render SPU: GL_RENDERER: %s", render_spu.ws.glGetString( GL_RENDERER ) ); + crInfo( "Render SPU: GL_VERSION: %s", render_spu.ws.glGetString( GL_VERSION ) ); + crInfo( "Render SPU: GL_EXTENSIONS: %s", render_spu.ws.glGetString( GL_EXTENSIONS ) ); + + if (ASMAtomicCmpXchgU32(&u32ExtCompared, 1, 0)) + renderCompareGLExtensions(extString, crExtensions); + + if (crStrstr(extString, "GL_ARB_window_pos")) + context->haveWindowPosARB = GL_TRUE; + else + context->haveWindowPosARB = GL_FALSE; + context->everCurrent = GL_TRUE; + } + 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[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. + */ + /*renderspu_SystemShowWindow( window, GL_TRUE );*/ + window->mapPending = GL_FALSE; + } + window->everCurrent = GL_TRUE; + } + 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); + } +} + +void RENDER_APIENTRY +renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx) +{ + WindowInfo *window = NULL; + ContextInfo *context = NULL; + + /* + crDebug("%s win=%d native=0x%x ctx=%d", __FUNCTION__, crWindow, (int) nativeWindow, ctx); + */ + + if (crWindow) + { + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, crWindow); + if (!window) + { + crWarning("invalid window %d specified", crWindow); + return; + } + } + + if (ctx) + { + context = (ContextInfo *) crHashtableSearch(render_spu.contextTable, ctx); + if (!context) + { + crWarning("invalid context %d specified", ctx); + return; + } + } + + if (!context != !window) + { + crWarning("either window %d or context %d are zero", crWindow, ctx); + return; + } + + renderspuPerformMakeCurrent(window, nativeWindow, context); +} + +GLboolean renderspuWinInitWithVisual( WindowInfo *window, VisualInfo *visual, GLboolean showIt, GLint id ) +{ + crMemset(window, 0, sizeof (*window)); + RTCritSectInit(&window->CompositorLock); + window->pCompositor = NULL; + + window->BltInfo.Base.id = id; + + window->x = render_spu.defaultX; + window->y = render_spu.defaultY; + window->BltInfo.width = render_spu.defaultWidth; + window->BltInfo.height = render_spu.defaultHeight; + + /* Set window->title, replacing %i with the window ID number */ + { + const char *s = crStrstr(render_spu.window_title, "%i"); + if (s) { + int i, j, k; + 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->BltInfo.Base.id); + CRASSERT(k < 10); + i++; /* skip the 'i' after the '%' */ + j = i + k; + for (; (window->title[j] = s[i]) != 0; i++, j++) + ; + } + else { + window->title = crStrdup(render_spu.window_title); + } + } + + window->BltInfo.Base.visualBits = visual->visAttribs; + + window->cRefs = 1; + + /* + 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 )) + { + crWarning( "Render SPU: Couldn't create a window, renderspu_SystemCreateWindow failed" ); + return GL_FALSE; + } + + window->visible = !!showIt; + + CRASSERT(window->visual == visual); + return GL_TRUE; +} + +/* + * Window functions + */ +GLboolean renderspuWinInit(WindowInfo *pWindow, const char *dpyName, GLint visBits, GLint id) +{ + VisualInfo *visual; + + crMemset(pWindow, 0, sizeof (*pWindow)); + + 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 (!renderspuWinInitWithVisual( 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 = renderspuWinCreate(visBits, id); + + if (!window) + { + crWarning("renderspuWinCreate 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 ); +} + +void renderspuWinReleaseCb(void*pvWindow) +{ + renderspuWinRelease((WindowInfo*)pvWindow); +} + +void +RENDER_APIENTRY renderspuWindowDestroy( GLint win ) +{ + WindowInfo *window; + + 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); + /* since os-specific backend can hold its own reference to the window object (e.g. on OSX), + * we need to explicitly issue a window destroy command + * this ensures the backend will eventually release the reference, + * the window object itself will remain valid until its ref count reaches zero */ + renderspuWinTerm( window ); + + /* remove window info from hash table, and free it */ + crHashtableDelete(render_spu.windowTable, win, renderspuWinReleaseCb); + + } + else { + crDebug("Render SPU: Attempt to destroy invalid window (%d)", win); + } +} + + +static void RENDER_APIENTRY +renderspuWindowSize( GLint win, GLint w, GLint h ) +{ + WindowInfo *window; + CRASSERT(win >= 0); + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win); + if (window) { + 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 { + WARN(("Render SPU: Attempt to resize invalid window (%d)", win)); + } +} + + +static void RENDER_APIENTRY +renderspuWindowPosition( GLint win, GLint x, GLint y ) +{ + if (!render_spu.ignore_window_moves) { + WindowInfo *window; + CRASSERT(win >= 0); + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win); + if (window) { + renderspu_SystemWindowPosition( window, x, y ); + window->x = x; + window->y = y; + } + else { + crDebug("Render SPU: Attempt to move invalid window (%d)", win); + } + } +} + +#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, 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 { + crWarning("Render SPU: Attempt to set VisibleRegion for invalid window (%d)", win); + } +} + +static void RENDER_APIENTRY +renderspuWindowShow( GLint win, GLint flag ) +{ + WindowInfo *window; + 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. + * So, we never want to show the Render SPU's window. + */ + flag = 0; + } + + 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 (renderspuVBoxCompositorSet(window, 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, bool fRedraw ) +{ + PCR_BLITTER pBlitter = fRedraw ? window->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, + bool fRedraw ) +{ + PCR_BLITTER pBlitter = renderspuVBoxPresentBlitterGetAndEnter(window, i32MakeCurrentUserData, fRedraw); + if (!pBlitter) + return; + + renderspuVBoxCompositorBlit(pCompositor, pBlitter); + + renderspu_SystemSwapBuffers(window, 0); + + CrBltLeave(pBlitter); +} + +GLboolean renderspuVBoxCompositorSet( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor) +{ + int rc; + GLboolean fEmpty = pCompositor && CrVrScrCompositorIsEmpty(pCompositor); + GLboolean fNeedPresent; + + /* 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 && !fEmpty) + return !!pCompositor; + + rc = RTCritSectEnter(&window->CompositorLock); + if (RT_SUCCESS(rc)) + { + if (!fEmpty) + fNeedPresent = !!pCompositor; + else + { + fNeedPresent = renderspu_SystemWindowNeedEmptyPresent(window); + pCompositor = NULL; + } + + window->pCompositor = !fEmpty ? pCompositor : NULL; + RTCritSectLeave(&window->CompositorLock); + return fNeedPresent; + } + else + { + WARN(("RTCritSectEnter failed rc %d", rc)); + } + + return GL_FALSE; +} + +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) + { + Assert(!CrVrScrCompositorIsEmpty(window->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, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor) +{ + int rc = RTCritSectEnter(&window->CompositorLock); + if (RT_SUCCESS(rc)) + { + if (ppCompositor) + *ppCompositor = window->pCompositor; + } + else + WARN(("RTCritSectEnter failed %d", 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) + { + Assert(!CrVrScrCompositorIsEmpty(window->pCompositor)); + 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); + Assert(!CrVrScrCompositorIsEmpty(window->pCompositor)); + rc = RTCritSectLeave(&window->CompositorLock); + if (!RT_SUCCESS(rc)) + { + crWarning("RTCritSectLeave failed rc %d", rc); + } +} + + +/* + * Set the current raster position to the given window coordinate. + */ +static void +SetRasterPos( GLint winX, GLint winY ) +{ + GLfloat fx, fy; + + /* Push current matrix mode and viewport attributes */ + render_spu.self.PushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT ); + + /* Setup projection parameters */ + render_spu.self.MatrixMode( GL_PROJECTION ); + render_spu.self.PushMatrix(); + render_spu.self.LoadIdentity(); + render_spu.self.MatrixMode( GL_MODELVIEW ); + render_spu.self.PushMatrix(); + render_spu.self.LoadIdentity(); + + render_spu.self.Viewport( winX - 1, winY - 1, 2, 2 ); + + /* set the raster (window) position */ + /* huh ? */ + fx = (GLfloat) (winX - (int) winX); + fy = (GLfloat) (winY - (int) winY); + render_spu.self.RasterPos4f( fx, fy, 0.0, 1.0 ); + + /* restore matrices, viewport and matrix mode */ + render_spu.self.PopMatrix(); + render_spu.self.MatrixMode( GL_PROJECTION ); + render_spu.self.PopMatrix(); + + render_spu.self.PopAttrib(); +} + + +/* + * Draw the mouse pointer bitmap at (x,y) in window coords. + */ +static void DrawCursor( GLint x, GLint y ) +{ +#define POINTER_WIDTH 32 +#define POINTER_HEIGHT 32 + /* Somebody artistic could probably do better here */ + static const char *pointerImage[POINTER_HEIGHT] = + { + "XX..............................", + "XXXX............................", + ".XXXXX..........................", + ".XXXXXXX........................", + "..XXXXXXXX......................", + "..XXXXXXXXXX....................", + "...XXXXXXXXXXX..................", + "...XXXXXXXXXXXXX................", + "....XXXXXXXXXXXXXX..............", + "....XXXXXXXXXXXXXXXX............", + ".....XXXXXXXXXXXXXXXXX..........", + ".....XXXXXXXXXXXXXXXXXXX........", + "......XXXXXXXXXXXXXXXXXXXX......", + "......XXXXXXXXXXXXXXXXXXXXXX....", + ".......XXXXXXXXXXXXXXXXXXXXXXX..", + ".......XXXXXXXXXXXXXXXXXXXXXXXX.", + "........XXXXXXXXXXXXX...........", + "........XXXXXXXX.XXXXX..........", + ".........XXXXXX...XXXXX.........", + ".........XXXXX.....XXXXX........", + "..........XXX.......XXXXX.......", + "..........XX.........XXXXX......", + "......................XXXXX.....", + ".......................XXXXX....", + "........................XXX.....", + ".........................X......", + "................................", + "................................", + "................................", + "................................", + "................................", + "................................" + + }; + static GLubyte pointerBitmap[POINTER_HEIGHT][POINTER_WIDTH / 8]; + static GLboolean firstCall = GL_TRUE; + GLboolean lighting, depthTest, scissorTest; + + if (firstCall) { + /* Convert pointerImage into pointerBitmap */ + GLint i, j; + for (i = 0; i < POINTER_HEIGHT; i++) { + for (j = 0; j < POINTER_WIDTH; j++) { + if (pointerImage[POINTER_HEIGHT - i - 1][j] == 'X') { + GLubyte bit = 128 >> (j & 0x7); + pointerBitmap[i][j / 8] |= bit; + } + } + } + firstCall = GL_FALSE; + } + + render_spu.self.GetBooleanv(GL_LIGHTING, &lighting); + render_spu.self.GetBooleanv(GL_DEPTH_TEST, &depthTest); + render_spu.self.GetBooleanv(GL_SCISSOR_TEST, &scissorTest); + render_spu.self.Disable(GL_LIGHTING); + render_spu.self.Disable(GL_DEPTH_TEST); + render_spu.self.Disable(GL_SCISSOR_TEST); + render_spu.self.PixelStorei(GL_UNPACK_ALIGNMENT, 1); + + render_spu.self.Color3f(1, 1, 1); + + /* save current raster pos */ + render_spu.self.PushAttrib(GL_CURRENT_BIT); + SetRasterPos(x, y); + render_spu.self.Bitmap(POINTER_WIDTH, POINTER_HEIGHT, 1.0, 31.0, 0, 0, + (const GLubyte *) pointerBitmap); + /* restore current raster pos */ + render_spu.self.PopAttrib(); + + if (lighting) + render_spu.self.Enable(GL_LIGHTING); + if (depthTest) + render_spu.self.Enable(GL_DEPTH_TEST); + if (scissorTest) + render_spu.self.Enable(GL_SCISSOR_TEST); +} + +void RENDER_APIENTRY renderspuSwapBuffers( GLint window, GLint flags ) +{ + WindowInfo *w = (WindowInfo *) crHashtableSearch(render_spu.windowTable, window); + + if (!w) + { + crDebug("Render SPU: SwapBuffers invalid window id: %d", window); + return; + } + + if (flags & CR_SUPPRESS_SWAP_BIT) + { + render_spu.self.Finish(); + return; + } + + if (render_spu.drawCursor) + DrawCursor( render_spu.cursorX, render_spu.cursorY ); + + if (render_spu.swap_master_url) + DoSync(); + + renderspu_SystemSwapBuffers( w, flags ); +} + + +/* + * Barrier functions + * Normally, we'll have a crserver somewhere that handles the barrier calls. + * However, if we're running the render SPU on the client node, then we + * should handle barriers here. The threadtest demo illustrates this. + * If we have N threads calling using this SPU we need these barrier + * functions to synchronize them. + */ + +static void RENDER_APIENTRY renderspuBarrierCreateCR( GLuint name, GLuint count ) +{ + Barrier *b; + + if (render_spu.ignore_papi) + return; + + b = (Barrier *) crHashtableSearch( render_spu.barrierHash, name ); + if (b) { + /* HACK -- this allows everybody to create a barrier, and all + but the first creation are ignored, assuming the count + match. */ + if ( b->count != count ) { + crError( "Render SPU: Barrier name=%u created with count=%u, but already " + "exists with count=%u", name, count, b->count ); + } + } + else { + b = (Barrier *) crAlloc( sizeof(Barrier) ); + b->count = count; + crInitBarrier( &b->barrier, count ); + crHashtableAdd( render_spu.barrierHash, name, b ); + } +} + +static void RENDER_APIENTRY renderspuBarrierDestroyCR( GLuint name ) +{ + if (render_spu.ignore_papi) + return; + crHashtableDelete( render_spu.barrierHash, name, crFree ); +} + +static void RENDER_APIENTRY renderspuBarrierExecCR( GLuint name ) +{ + Barrier *b; + + if (render_spu.ignore_papi) + return; + + b = (Barrier *) crHashtableSearch( render_spu.barrierHash, name ); + if (b) { + crWaitBarrier( &(b->barrier) ); + } + else { + crWarning("Render SPU: Bad barrier name %d in BarrierExec()", name); + } +} + + +/* + * Semaphore functions + * XXX we should probably implement these too, for the same reason as + * barriers (see above). + */ + +static void RENDER_APIENTRY renderspuSemaphoreCreateCR( GLuint name, GLuint count ) +{ + (void) name; + (void) count; +} + +static void RENDER_APIENTRY renderspuSemaphoreDestroyCR( GLuint name ) +{ + (void) name; +} + +static void RENDER_APIENTRY renderspuSemaphorePCR( GLuint name ) +{ + (void) name; +} + +static void RENDER_APIENTRY renderspuSemaphoreVCR( GLuint name ) +{ + (void) 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) +{ + switch (target) + { + 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; + } + case GL_HH_RENDERTHREAD_INFORM: + { + if (value) + { + int rc = renderspuDefaultCtxInit(); + if (RT_FAILURE(rc)) + { + WARN(("renderspuDefaultCtxInit failed")); + break; + } + } + else + { + renderspuCleanupBase(false); + } + break; + } + default: +// crWarning("Unhandled target in renderspuChromiumParameteriCR()"); + break; + } +} + +static void RENDER_APIENTRY +renderspuChromiumParameterfCR(GLenum target, GLfloat value) +{ + (void) target; + (void) value; + +#if 0 + switch (target) { + default: + crWarning("Unhandled target in renderspuChromiumParameterfCR()"); + break; + } +#endif +} + +bool renderspuCalloutAvailable() +{ + return render_spu.pfnClientCallout != NULL; +} + +bool renderspuCalloutClient(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void *pvCb) +{ + if (render_spu.pfnClientCallout) + { + render_spu.pfnClientCallout(pfnCb, pvCb); + return true; + } + return false; +} + +static void RENDER_APIENTRY +renderspuChromiumParametervCR(GLenum target, GLenum type, GLsizei count, + const GLvoid *values) +{ + int client_num; + unsigned short port; + CRMessage *msg, pingback; + unsigned char *privbuf = NULL; + + switch (target) { + case GL_HH_SET_CLIENT_CALLOUT: + render_spu.pfnClientCallout = (PFNVCRSERVER_CLIENT_CALLOUT)values; + break; + case GL_GATHER_CONNECT_CR: + if (render_spu.gather_userbuf_size) + privbuf = (unsigned char *)crAlloc(1024*768*4); + + port = ((GLint *) values)[0]; + + if (render_spu.gather_conns == NULL) + render_spu.gather_conns = crAlloc(render_spu.server->numClients*sizeof(CRConnection *)); + else + { + crError("Oh bother! duplicate GL_GATHER_CONNECT_CR getting through"); + } + + for (client_num=0; client_num< render_spu.server->numClients; client_num++) + { + switch (render_spu.server->clients[client_num]->conn->type) + { + case CR_TCPIP: + crDebug("Render SPU: AcceptClient from %s on %d", + render_spu.server->clients[client_num]->conn->hostname, render_spu.gather_port); + render_spu.gather_conns[client_num] = + crNetAcceptClient("tcpip", NULL, port, 1024*1024, 1); + break; + + case CR_GM: + render_spu.gather_conns[client_num] = + crNetAcceptClient("gm", NULL, port, 1024*1024, 1); + break; + + default: + crError("Render SPU: Unknown Network Type to Open Gather Connection"); + } + + + if (render_spu.gather_userbuf_size) + { + render_spu.gather_conns[client_num]->userbuf = privbuf; + render_spu.gather_conns[client_num]->userbuf_len = render_spu.gather_userbuf_size; + } + else + { + render_spu.gather_conns[client_num]->userbuf = NULL; + render_spu.gather_conns[client_num]->userbuf_len = 0; + } + + if (render_spu.gather_conns[client_num]) + { + crDebug("Render SPU: success! from %s", render_spu.gather_conns[client_num]->hostname); + } + } + + break; + + case GL_GATHER_DRAWPIXELS_CR: + pingback.header.type = CR_MESSAGE_OOB; + + for (client_num=0; client_num< render_spu.server->numClients; client_num++) + { + crNetGetMessage(render_spu.gather_conns[client_num], &msg); + if (msg->header.type == CR_MESSAGE_GATHER) + { + crNetFree(render_spu.gather_conns[client_num], msg); + } + else + { + crError("Render SPU: expecting MESSAGE_GATHER. got crap! (%d of %d)", + client_num, render_spu.server->numClients-1); + } + } + + /* + * We're only hitting the case if we're not actually calling + * child.SwapBuffers from readback, so a switch about which + * call to DoSync() we really want [this one, or the one + * in SwapBuffers above] is not necessary -- karl + */ + + if (render_spu.swap_master_url) + DoSync(); + + for (client_num=0; client_num< render_spu.server->numClients; client_num++) + crNetSend(render_spu.gather_conns[client_num], NULL, &pingback, + sizeof(CRMessageHeader)); + + render_spu.self.RasterPos2i(((GLint *)values)[0], ((GLint *)values)[1]); + render_spu.self.DrawPixels( ((GLint *)values)[2], ((GLint *)values)[3], + ((GLint *)values)[4], ((GLint *)values)[5], + render_spu.gather_conns[0]->userbuf); + + + render_spu.self.SwapBuffers(((GLint *)values)[6], 0); + break; + + case GL_CURSOR_POSITION_CR: + if (type == GL_INT && count == 2) { + render_spu.cursorX = ((GLint *) values)[0]; + render_spu.cursorY = ((GLint *) values)[1]; + crDebug("Render SPU: GL_CURSOR_POSITION_CR (%d, %d)", render_spu.cursorX, render_spu.cursorY); + } + else { + crWarning("Render SPU: Bad type or count for ChromiumParametervCR(GL_CURSOR_POSITION_CR)"); + } + break; + + case GL_WINDOW_SIZE_CR: + /* XXX this is old code that should be removed. + * NOTE: we can only resize the default (id=CR_RENDER_DEFAULT_WINDOW_ID) window!!! + */ + { + GLint w, h; + WindowInfo *window; + CRASSERT(type == GL_INT); + CRASSERT(count == 2); + CRASSERT(values); + w = ((GLint*)values)[0]; + h = ((GLint*)values)[1]; + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID); + if (window) + { + renderspu_SystemWindowSize(window, w, h); + } + } + 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 + WARN(("Unhandled target in renderspuChromiumParametervCR(0x%x)", (int) target)); +#endif + break; + } +} + + +static void RENDER_APIENTRY +renderspuGetChromiumParametervCR(GLenum target, GLuint index, GLenum type, + GLsizei count, GLvoid *values) +{ + switch (target) { + case GL_WINDOW_SIZE_CR: + { + GLint x, y, w, h, *size = (GLint *) values; + WindowInfo *window; + CRASSERT(type == GL_INT); + CRASSERT(count == 2); + CRASSERT(values); + size[0] = size[1] = 0; /* default */ + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index); + if (window) + { + renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h); + size[0] = w; + size[1] = h; + } + } + break; + case GL_WINDOW_POSITION_CR: + /* return window position, as a screen coordinate */ + { + GLint *pos = (GLint *) values; + GLint x, y, w, h; + WindowInfo *window; + CRASSERT(type == GL_INT); + CRASSERT(count == 2); + CRASSERT(values); + pos[0] = pos[1] = 0; /* default */ + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index); + if (window) + { + renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h); + pos[0] = x;/*window->x;*/ + pos[1] = y;/*window->y;*/ + } + } + break; + case GL_MAX_WINDOW_SIZE_CR: + { + GLint *maxSize = (GLint *) values; + WindowInfo *window; + CRASSERT(type == GL_INT); + CRASSERT(count == 2); + CRASSERT(values); + window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index); + if (window) + { + renderspu_SystemGetMaxWindowSize(window, maxSize + 0, maxSize + 1); + } + } + 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 */ + } +} + + +static void RENDER_APIENTRY +renderspuBoundsInfoCR( CRrecti *bounds, GLbyte *payload, GLint len, + GLint num_opcodes ) +{ + (void) bounds; + (void) payload; + (void) len; + (void) num_opcodes; + /* draw the bounding box */ + if (render_spu.draw_bbox) { + GET_CONTEXT(context); + WindowInfo *window = context->currentWindow; + GLint x, y, w, h; + + renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h); + + render_spu.self.PushMatrix(); + render_spu.self.LoadIdentity(); + render_spu.self.MatrixMode(GL_PROJECTION); + render_spu.self.PushMatrix(); + render_spu.self.LoadIdentity(); + render_spu.self.Ortho(0, w, 0, h, -1, 1); + render_spu.self.Color3f(1, 1, 1); + render_spu.self.Begin(GL_LINE_LOOP); + render_spu.self.Vertex2i(bounds->x1, bounds->y1); + render_spu.self.Vertex2i(bounds->x2, bounds->y1); + render_spu.self.Vertex2i(bounds->x2, bounds->y2); + render_spu.self.Vertex2i(bounds->x1, bounds->y2); + render_spu.self.End(); + render_spu.self.PopMatrix(); + render_spu.self.MatrixMode(GL_MODELVIEW); + render_spu.self.PopMatrix(); + } +} + + +static void RENDER_APIENTRY +renderspuWriteback( GLint *writeback ) +{ + (void) writeback; +} + + +static void +remove_trailing_space(char *s) +{ + int k = crStrlen(s); + while (k > 0 && s[k-1] == ' ') + k--; + s[k] = 0; +} + +static const GLubyte * RENDER_APIENTRY +renderspuGetString(GLenum pname) +{ + static char tempStr[1000]; + GET_CONTEXT(context); + + if (pname == GL_EXTENSIONS) + { + const char *nativeExt; + char *crExt, *s1, *s2; + + if (!render_spu.ws.glGetString) + return NULL; + + nativeExt = (const char *) render_spu.ws.glGetString(GL_EXTENSIONS); + if (!nativeExt) { + /* maybe called w/out current context. */ + return NULL; + } + + if (!context) + return (const GLubyte *)nativeExt; + + crExt = crStrjoin3(crExtensions, " ", crAppOnlyExtensions); + s1 = crStrIntersect(nativeExt, crExt); + remove_trailing_space(s1); + s2 = crStrjoin3(s1, " ", crChromiumExtensions); + remove_trailing_space(s2); + crFree(crExt); + crFree(s1); + if (context->extensionString) + crFree(context->extensionString); + context->extensionString = s2; + return (const GLubyte *) s2; + } + else if (pname == GL_VENDOR) + return (const GLubyte *) CR_VENDOR; + else if (pname == GL_VERSION) + return render_spu.ws.glGetString(GL_VERSION); + else if (pname == GL_RENDERER) { +#ifdef VBOX + snprintf(tempStr, sizeof(tempStr), "Chromium (%s)", (char *) render_spu.ws.glGetString(GL_RENDERER)); +#else + sprintf(tempStr, "Chromium (%s)", (char *) render_spu.ws.glGetString(GL_RENDERER)); +#endif + return (const GLubyte *) tempStr; + } +#ifdef CR_OPENGL_VERSION_2_0 + else if (pname == GL_SHADING_LANGUAGE_VERSION) + return render_spu.ws.glGetString(GL_SHADING_LANGUAGE_VERSION); +#endif +#ifdef GL_CR_real_vendor_strings + else if (pname == GL_REAL_VENDOR) + return render_spu.ws.glGetString(GL_VENDOR); + else if (pname == GL_REAL_VERSION) + return render_spu.ws.glGetString(GL_VERSION); + else if (pname == GL_REAL_RENDERER) + return render_spu.ws.glGetString(GL_RENDERER); + else if (pname == GL_REAL_EXTENSIONS) + return render_spu.ws.glGetString(GL_EXTENSIONS); +#endif + else + 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; + CRASSERT(window >= 0); + + pWindow = (WindowInfo *) crHashtableSearch(render_spu.windowTable, window); + + if (!pWindow) + { + crDebug("Render SPU: Attempt to reparent invalid window (%d)", window); + return; + } + + renderspu_SystemReparentWindow(pWindow); + + /* special case: reparent all internal windows as well */ + if (window == CR_RENDER_DEFAULT_WINDOW_ID) + { + crHashtableWalk(render_spu.dummyWindowTable, renderspuReparentWindowCB, NULL); + } +} + +DECLEXPORT(void) renderspuSetUnscaledHiDPI(bool fEnable) +{ + render_spu.fUnscaledHiDPI = fEnable; +} + +#define FILLIN( NAME, FUNC ) \ + table[i].name = crStrdup(NAME); \ + table[i].fn = (SPUGenericFunction) FUNC; \ + i++; + + +/* These are the functions which the render SPU implements, not OpenGL. + */ +int +renderspuCreateFunctions(SPUNamedFunctionTable table[]) +{ + int i = 0; + FILLIN( "SwapBuffers", renderspuSwapBuffers ); + FILLIN( "CreateContext", renderspuCreateContext ); + FILLIN( "DestroyContext", renderspuDestroyContext ); + FILLIN( "MakeCurrent", renderspuMakeCurrent ); + FILLIN( "WindowCreate", renderspuWindowCreate ); + FILLIN( "WindowDestroy", renderspuWindowDestroy ); + FILLIN( "WindowSize", renderspuWindowSize ); + FILLIN( "WindowPosition", renderspuWindowPosition ); + FILLIN( "WindowVisibleRegion", renderspuWindowVisibleRegion ); + FILLIN( "WindowShow", renderspuWindowShow ); + FILLIN( "BarrierCreateCR", renderspuBarrierCreateCR ); + FILLIN( "BarrierDestroyCR", renderspuBarrierDestroyCR ); + FILLIN( "BarrierExecCR", renderspuBarrierExecCR ); + FILLIN( "BoundsInfoCR", renderspuBoundsInfoCR ); + FILLIN( "SemaphoreCreateCR", renderspuSemaphoreCreateCR ); + FILLIN( "SemaphoreDestroyCR", renderspuSemaphoreDestroyCR ); + FILLIN( "SemaphorePCR", renderspuSemaphorePCR ); + FILLIN( "SemaphoreVCR", renderspuSemaphoreVCR ); + FILLIN( "Writeback", renderspuWriteback ); + FILLIN( "ChromiumParameteriCR", renderspuChromiumParameteriCR ); + FILLIN( "ChromiumParameterfCR", renderspuChromiumParameterfCR ); + FILLIN( "ChromiumParametervCR", renderspuChromiumParametervCR ); + FILLIN( "GetChromiumParametervCR", renderspuGetChromiumParametervCR ); + FILLIN( "GetString", renderspuGetString ); + FILLIN( "VBoxPresentComposition", renderspuVBoxPresentComposition ); + return i; +} |