DECLEXPORT(void) STATE_APIENTRY
crStateBindRenderbufferEXT(GLenum target, GLuint renderbuffer)
{
    CRContext *g = GetCurrentContext();
    CRFramebufferObjectState *fbo = &g->framebufferobject;

    CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end");
    CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target");

    if (renderbuffer)
    {
        fbo->renderbuffer = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffer);
        if (!fbo->renderbuffer)
        {
            CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer), GL_INVALID_OPERATION, "name is not a renderbuffer");
            fbo->renderbuffer = crStateRenderbufferAllocate(g, renderbuffer);
        }
        CR_STATE_SHAREDOBJ_USAGE_SET(fbo->renderbuffer, g);
    }
    else fbo->renderbuffer = NULL;
}
void STATE_APIENTRY
crStateBindBufferARB (GLenum target, GLuint buffer)
{
    CRContext *g = GetCurrentContext();
    CRBufferObjectState *b = &(g->bufferobject);
    CRStateBits *sb = GetCurrentBits();
    CRBufferObjectBits *bb = &(sb->bufferobject);
    CRBufferObject *oldObj, *newObj;

    if (g->current.inBeginEnd) {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
                                 "glBindBufferARB called in begin/end");
        return;
    }

    FLUSH();

    oldObj = crStateGetBoundBufferObject(target, b);
    if (!oldObj)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glBindBufferARB(target)");
        return;
    }

    if (buffer == 0) {
        newObj = b->nullBuffer;
    }
    else {
        newObj = (CRBufferObject *) crHashtableSearch(g->shared->buffersTable, buffer);
        if (!newObj) {
            CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->buffersTable, buffer), GL_INVALID_OPERATION, "name is not a buffer object");
            newObj = AllocBufferObject(buffer);
            CRSTATE_CHECKERR(!newObj, GL_OUT_OF_MEMORY, "glBindBuffer");
#ifndef IN_GUEST
            diff_api.GenBuffersARB(1, &newObj->hwid);
            if (!newObj->hwid)
            {
                crWarning("GenBuffersARB failed!");
                crFree(newObj);
                return;
            }
#endif
            crHashtableAdd( g->shared->buffersTable, buffer, newObj );
        }

        CR_STATE_SHAREDOBJ_USAGE_SET(newObj, g);
    }

    newObj->refCount++;
    oldObj->refCount--;

    switch (target)
    {
        case GL_ARRAY_BUFFER_ARB:
            b->arrayBuffer = newObj;
            DIRTY(bb->dirty, g->neg_bitid);
            DIRTY(bb->arrayBinding, g->neg_bitid);
            break;
        case GL_ELEMENT_ARRAY_BUFFER_ARB:
            b->elementsBuffer = newObj;
            DIRTY(bb->dirty, g->neg_bitid);
            DIRTY(bb->elementsBinding, g->neg_bitid);
            break;
#ifdef CR_ARB_pixel_buffer_object
        case GL_PIXEL_PACK_BUFFER_ARB:
            b->packBuffer = newObj;
            DIRTY(bb->dirty, g->neg_bitid);
            DIRTY(bb->packBinding, g->neg_bitid);
            break;
        case GL_PIXEL_UNPACK_BUFFER_ARB:
            b->unpackBuffer = newObj;
            DIRTY(bb->dirty, g->neg_bitid);
            DIRTY(bb->unpackBinding, g->neg_bitid);
            break;
#endif
        default: /*can't get here*/
            CRASSERT(false);
            return;
    }

    if (oldObj->refCount <= 0) {
        /*we shouldn't reach this point*/
        CRASSERT(false);
        crHashtableDelete(g->shared->buffersTable, (unsigned long) oldObj->id, crStateFreeBufferObject);
    }

#ifdef IN_GUEST
    if (target == GL_PIXEL_PACK_BUFFER_ARB)
    {
        newObj->bResyncOnRead = GL_TRUE;
    }
#endif
}
void crServerPerformMakeCurrent( CRMuralInfo *mural, CRContextInfo *ctxInfo )
{
    CRMuralInfo *oldMural;
    CRContext *ctx, *oldCtx = NULL;
    GLuint idDrawFBO, idReadFBO;
    GLint context = ctxInfo->CreateInfo.externalID;
    GLint window = mural->CreateInfo.externalID;

    cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;

    ctx = ctxInfo->pContext;
    CRASSERT(ctx);

    oldMural = cr_server.currentMural;

    /* Ubuntu 11.04 hosts misbehave if context window switch is
     * done with non-default framebuffer object settings.
     * crStateSwitchPrepare & crStateSwitchPostprocess are supposed to work around this problem
     * crStateSwitchPrepare restores the FBO state to its default values before the context window switch,
     * while crStateSwitchPostprocess restores it back to the original values */
    oldCtx = crStateGetCurrent();
    if (oldMural && oldMural->fRedirected && crServerSupportRedirMuralFBO())
    {
        idDrawFBO = CR_SERVER_FBO_FOR_IDX(oldMural, oldMural->iCurDrawBuffer);
        idReadFBO = CR_SERVER_FBO_FOR_IDX(oldMural, oldMural->iCurReadBuffer);
    }
    else
    {
        idDrawFBO = 0;
        idReadFBO = 0;
    }
    crStateSwitchPrepare(cr_server.bUseMultipleContexts ? NULL : ctx, oldCtx, idDrawFBO, idReadFBO);

    if (cr_server.curClient)
    {
        /*
        crDebug("**** %s client %d  curCtx=%d curWin=%d", __func__,
                        cr_server.curClient->number, ctxPos, window);
        */
        cr_server.curClient->currentContextNumber = context;
        cr_server.curClient->currentCtxInfo = ctxInfo;
        cr_server.curClient->currentMural = mural;
        cr_server.curClient->currentWindow = window;

        CRASSERT(cr_server.curClient->currentCtxInfo);
        CRASSERT(cr_server.curClient->currentCtxInfo->pContext);
    }

    /* This is a hack to force updating the 'current' attribs */
    crStateUpdateColorBits();

    if (ctx)
        crStateSetCurrentPointers( ctx, &(cr_server.current) );

    /* check if being made current for first time, update viewport */
#if 0
    if (ctx) {
        /* initialize the viewport */
        if (ctx->viewport.viewportW == 0) {
            ctx->viewport.viewportW = mural->width;
            ctx->viewport.viewportH = mural->height;
            ctx->viewport.scissorW = mural->width;
            ctx->viewport.scissorH = mural->height;
        }
    }
#endif

    /*
    crDebug("**** %s  currentWindow %d  newWindow %d", __func__,
                    cr_server.currentWindow, window);
    */

    if (1/*cr_server.firstCallMakeCurrent ||
            cr_server.currentWindow != window ||
            cr_server.currentNativeWindow != nativeWindow*/) {
        /* Since the cr server serialized all incoming contexts/clients into
         * one output stream of GL commands, we only need to call the head
         * SPU's MakeCurrent() function once.
         * BUT, if we're rendering to multiple windows, we do have to issue
         * MakeCurrent() calls sometimes.  The same GL context will always be
         * used though.
         */
        cr_server.head_spu->dispatch_table.MakeCurrent( mural->spuWindow,
                                                        0,
                                                        ctxInfo->SpuContext >= 0
                                                            ? ctxInfo->SpuContext
                                                              : cr_server.MainContextInfo.SpuContext);

        CR_STATE_SHAREDOBJ_USAGE_SET(mural, ctx);
        if (cr_server.currentCtxInfo)
            cr_server.currentCtxInfo->currentMural = NULL;
        ctxInfo->currentMural = mural;

        cr_server.firstCallMakeCurrent = GL_FALSE;
        cr_server.currentCtxInfo = ctxInfo;
        cr_server.currentWindow = window;
        cr_server.currentNativeWindow = 0;
        cr_server.currentMural = mural;
    }

    /* This used to be earlier, after crStateUpdateColorBits() call */
    crStateMakeCurrent( ctx );

    if (mural && mural->fRedirected  && crServerSupportRedirMuralFBO())
    {
        GLuint id = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer);
        if (id != mural->iCurDrawBuffer)
        {
            crDebug("DBO draw buffer changed on make current");
            mural->iCurDrawBuffer = id;
        }

        id = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer);
        if (id != mural->iCurReadBuffer)
        {
            crDebug("DBO read buffer changed on make current");
            mural->iCurReadBuffer = id;
        }

        idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer);
        idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer);
    }
    else
    {
        idDrawFBO = 0;
        idReadFBO = 0;
    }
    crStateSwitchPostprocess(ctx, cr_server.bUseMultipleContexts ? NULL : oldCtx, idDrawFBO, idReadFBO);

    if (!ctx->framebufferobject.drawFB
            && (ctx->buffer.drawBuffer == GL_FRONT || ctx->buffer.drawBuffer == GL_FRONT_LEFT)
            && cr_server.curClient)
        cr_server.curClient->currentMural->bFbDraw = GL_TRUE;

    if (!mural->fRedirected)
    {
        ctx->buffer.width = mural->width;
        ctx->buffer.height = mural->height;
    }
    else
    {
        ctx->buffer.width = 0;
        ctx->buffer.height = 0;
    }
}