renderspu.c revision d800c4d5127fc4b317658e72babf7f69f912dba2
/* 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;
}
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;
if (!window)
{
crDebug("Render SPU: MakeCurrent invalid window id: %d", window->BltInfo.Base.id);
return;
}
if (!context)
{
crDebug("Render SPU: MakeCurrent invalid context id: %d", context->BltInfo.Base.id);
return;
}
renderspu_SystemMakeCurrent( window, nativeWindow, context );
if (!context->everCurrent) {
/* 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 (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;
}