示例#1
0
static SPUFunctions *feedbackSPUInit( int id, SPU *child, SPU *self,
		unsigned int context_id,
		unsigned int num_contexts )
{
	CRContext *ctx;
	(void) context_id;
	(void) num_contexts;

	feedback_spu.id = id;
	feedback_spu.has_child = 0;
	if (child)
	{
		crSPUInitDispatchTable( &(feedback_spu.child) );
		crSPUCopyDispatchTable( &(feedback_spu.child), &(child->dispatch_table) );
		feedback_spu.has_child = 1;
	}
	crSPUInitDispatchTable( &(feedback_spu.super) );
	crSPUCopyDispatchTable( &(feedback_spu.super), &(self->superSPU->dispatch_table) );
	feedbackspuGatherConfiguration();

	/* create/init default state tracker */
	crStateInit();
	ctx = crStateGetCurrent();
	CRASSERT(ctx);
	crStateSetCurrentPointers(ctx, &feedback_spu.current);

	return &feedback_functions;
}
示例#2
0
void SERVER_DISPATCH_APIENTRY
crServerDispatchMakeCurrent( GLint window, GLint nativeWindow, GLint context )
{
    CRMuralInfo *mural, *oldMural;
    CRContextInfo *ctxInfo = NULL;
    CRContext *ctx, *oldCtx = NULL;

    if (context >= 0 && window >= 0) {
        mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
        if (!mural)
        {
            crWarning("CRServer: invalid window %d passed to crServerDispatchMakeCurrent()", window);
            return;
        }

        /* Update the state tracker's current context */
        ctxInfo = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, context);
        if (!ctxInfo) {
            crWarning("CRserver: NULL context in MakeCurrent %d", context);
            return;
        }
    }
    else {
#if 0
        oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow);
        if (oldMural && oldMural->bUseFBO && crServerSupportRedirMuralFBO())
        {
            if (!crStateGetCurrent()->framebufferobject.drawFB)
            {
                cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
            }
            if (!crStateGetCurrent()->framebufferobject.readFB)
            {
                cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
            }
        }

        ctxInfo = &cr_server.MainContextInfo;
        window = -1;
        mural = NULL;
#endif
        cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
        return;
    }

    cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;

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

    oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow);

    /* Ubuntu 11.04 hosts misbehave if context window switch is
     * done with non-default framebuffer object settings.
     * crStateSwichPrepare & crStateSwichPostprocess are supposed to work around this problem
     * crStateSwichPrepare restores the FBO state to its default values before the context window switch,
     * while crStateSwichPostprocess restores it back to the original values */
    oldCtx = crStateSwichPrepare(ctx, cr_server.bUseMultipleContexts, oldMural && oldMural->bUseFBO && crServerSupportRedirMuralFBO() ? oldMural->idFBO : 0);

    /*
    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,
                                                        nativeWindow,
                                                        ctxInfo->SpuContext >= 0
                                                            ? ctxInfo->SpuContext
                                                              : cr_server.MainContextInfo.SpuContext);
        cr_server.firstCallMakeCurrent = GL_FALSE;
        cr_server.currentCtxInfo = ctxInfo;
        cr_server.currentWindow = window;
        cr_server.currentNativeWindow = nativeWindow;
    }

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

    crStateSwichPostprocess(oldCtx, cr_server.bUseMultipleContexts, mural->bUseFBO && crServerSupportRedirMuralFBO() ? mural->idFBO : 0);

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

    if (!mural->bUseFBO)
    {
        ctx->buffer.width = mural->width;
        ctx->buffer.height = mural->height;
    }
    else
    {
        ctx->buffer.width = 0;
        ctx->buffer.height = 0;
    }
}
示例#3
0
GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLint shareCtx, GLint preloadCtxID, int32_t internalID)
{
    GLint retVal = -1;
    CRContext *newCtx;
    CRContextInfo *pContextInfo;
    GLboolean fFirst = GL_FALSE;

    if (shareCtx > 0) {
        crWarning("CRServer: context sharing not implemented.");
        shareCtx = 0;
    }

    pContextInfo = (CRContextInfo *) crAlloc(sizeof (CRContextInfo));
    if (!pContextInfo)
    {
        crWarning("failed to alloc context info!");
        return -1;
    }

    pContextInfo->CreateInfo.visualBits = visualBits;

    /* Since the Cr server serialized all incoming clients/contexts into
     * one outgoing GL stream, we only need to create one context for the
     * head SPU.  We'll only have to make it current once too, below.
     */
    if (cr_server.firstCallCreateContext) {
        cr_server.MainContextInfo.CreateInfo.visualBits = visualBits;
        cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table.
            CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, shareCtx);
        if (cr_server.MainContextInfo.SpuContext < 0) {
            crWarning("crServerDispatchCreateContext() failed.");
            crFree(pContextInfo);
            return -1;
        }
        cr_server.firstCallCreateContext = GL_FALSE;
        fFirst = GL_TRUE;
    }
    else {
        /* second or third or ... context */
        if (!cr_server.bUseMultipleContexts && ((visualBits & cr_server.MainContextInfo.CreateInfo.visualBits) != visualBits)) {
            int oldSpuContext;

            /* the new context needs new visual attributes */
            cr_server.MainContextInfo.CreateInfo.visualBits |= visualBits;
            crDebug("crServerDispatchCreateContext requires new visual (0x%x).",
                    cr_server.MainContextInfo.CreateInfo.visualBits);

            /* Here, we used to just destroy the old rendering context.
             * Unfortunately, this had the side effect of destroying
             * all display lists and textures that had been loaded on
             * the old context as well.
             *
             * Now, first try to create a new context, with a suitable
             * visual, sharing display lists and textures with the
             * old context.  Then destroy the old context.
             */

            /* create new rendering context with suitable visual */
            oldSpuContext = cr_server.MainContextInfo.SpuContext;
            cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table.
                CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, cr_server.MainContextInfo.SpuContext);
            /* destroy old rendering context */
            cr_server.head_spu->dispatch_table.DestroyContext(oldSpuContext);
            if (cr_server.MainContextInfo.SpuContext < 0) {
                crWarning("crServerDispatchCreateContext() failed.");
                crFree(pContextInfo);
                return -1;
            }
        }
    }

    if (cr_server.bUseMultipleContexts) {
        pContextInfo->SpuContext = cr_server.head_spu->dispatch_table.
                CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, cr_server.MainContextInfo.SpuContext);
        if (pContextInfo->SpuContext < 0) {
            crWarning("crServerDispatchCreateContext() failed.");
            crStateEnableDiffOnMakeCurrent(GL_TRUE);
            cr_server.bUseMultipleContexts = GL_FALSE;
            if (!fFirst)
                crError("creating shared context failed, while it is expected to work!");
        }
        else if (fFirst)
        {
            crStateEnableDiffOnMakeCurrent(GL_FALSE);
        }
    }
    else
    {
        pContextInfo->SpuContext = -1;
    }

    /* Now create a new state-tracker context and initialize the
     * dispatch function pointers.
     */
    newCtx = crStateCreateContextEx(&cr_server.limits, visualBits, NULL, internalID);
    if (newCtx) {
        crStateSetCurrentPointers( newCtx, &(cr_server.current) );
        crStateResetCurrentPointers(&(cr_server.current));
        retVal = preloadCtxID<0 ? crServerGenerateID(&cr_server.idsPool.freeContextID) : preloadCtxID;

        pContextInfo->pContext = newCtx;
        pContextInfo->CreateInfo.visualBits = visualBits;
        pContextInfo->CreateInfo.externalID = retVal;
        pContextInfo->CreateInfo.pszDpyName = dpyName ? crStrdup(dpyName) : NULL;
        crHashtableAdd(cr_server.contextTable, retVal, pContextInfo);
    }

    if (retVal != -1 && !cr_server.bIsInLoadingState) {
        int pos;
        for (pos = 0; pos < CR_MAX_CONTEXTS; pos++) {
            if (cr_server.curClient->contextList[pos] == 0) {
                cr_server.curClient->contextList[pos] = retVal;
                break;
            }
        }
    }

    {
        /* As we're using only one host context to serve all client contexts, newly created context will still
         * hold last error value from any previous failed opengl call. Proper solution would be to redirect any
         * client glGetError calls to our state tracker, but right now it's missing quite a lot of checks and doesn't
         * reflect host driver/gpu specific issues. Thus we just reset last opengl error at context creation.
         */
        GLint err;

        err = cr_server.head_spu->dispatch_table.GetError();
        if (err!=GL_NO_ERROR)
        {
#ifdef DEBUG_misha
            crDebug("Cleared gl error %#x on context creation", err);
#else
            crWarning("Cleared gl error %#x on context creation", err);
#endif
        }
    }

    crServerReturnValue( &retVal, sizeof(retVal) );

    return retVal;
}
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;
    }
}
GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLint shareCtx, GLint preloadCtxID, int32_t internalID)
{
    GLint retVal = -1;
    CRContext *newCtx;
    CRContextInfo *pContextInfo;
    GLboolean fFirst = GL_FALSE;

    dpyName = "";

    if (shareCtx > 0) {
        crWarning("CRServer: context sharing not implemented.");
        shareCtx = 0;
    }

    pContextInfo = (CRContextInfo *) crAlloc(sizeof (CRContextInfo));
    if (!pContextInfo)
    {
        crWarning("failed to alloc context info!");
        return -1;
    }

    pContextInfo->currentMural = NULL;

    pContextInfo->CreateInfo.requestedVisualBits = visualBits;

    if (cr_server.fVisualBitsDefault)
        visualBits = cr_server.fVisualBitsDefault;

    pContextInfo->CreateInfo.realVisualBits = visualBits;

    /* Since the Cr server serialized all incoming clients/contexts into
     * one outgoing GL stream, we only need to create one context for the
     * head SPU.  We'll only have to make it current once too, below.
     */
    if (cr_server.firstCallCreateContext) {
        cr_server.MainContextInfo.CreateInfo.realVisualBits = visualBits;
        cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table.
            CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, shareCtx);
        if (cr_server.MainContextInfo.SpuContext < 0) {
            crWarning("crServerDispatchCreateContext() failed.");
            crFree(pContextInfo);
            return -1;
        }
        cr_server.MainContextInfo.pContext = crStateCreateContext(&cr_server.limits, visualBits, NULL);
        CRASSERT(cr_server.MainContextInfo.pContext);
        cr_server.firstCallCreateContext = GL_FALSE;
        fFirst = GL_TRUE;

        cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_SET_DEFAULT_SHARED_CTX, cr_server.MainContextInfo.SpuContext);
    }
    else {
        /* second or third or ... context */
        if (!cr_server.bUseMultipleContexts && ((visualBits & cr_server.MainContextInfo.CreateInfo.realVisualBits) != visualBits)) {
            int oldSpuContext;
            /* should never be here */
            CRASSERT(0);
            /* the new context needs new visual attributes */
            cr_server.MainContextInfo.CreateInfo.realVisualBits |= visualBits;
            crWarning("crServerDispatchCreateContext requires new visual (0x%x).",
                    cr_server.MainContextInfo.CreateInfo.realVisualBits);

            /* Here, we used to just destroy the old rendering context.
             * Unfortunately, this had the side effect of destroying
             * all display lists and textures that had been loaded on
             * the old context as well.
             *
             * Now, first try to create a new context, with a suitable
             * visual, sharing display lists and textures with the
             * old context.  Then destroy the old context.
             */

            /* create new rendering context with suitable visual */
            oldSpuContext = cr_server.MainContextInfo.SpuContext;
            cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table.
                CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, cr_server.MainContextInfo.SpuContext);
            /* destroy old rendering context */
            cr_server.head_spu->dispatch_table.DestroyContext(oldSpuContext);
            if (cr_server.MainContextInfo.SpuContext < 0) {
                crWarning("crServerDispatchCreateContext() failed.");
                crFree(pContextInfo);
                return -1;
            }

            /* we do not need to clean up the old default context explicitly, since the above cr_server.head_spu->dispatch_table.DestroyContext call
             * will do that for us */
            cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_SET_DEFAULT_SHARED_CTX, cr_server.MainContextInfo.SpuContext);
        }
    }

    if (cr_server.bUseMultipleContexts) {
        pContextInfo->SpuContext = cr_server.head_spu->dispatch_table.
                CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, cr_server.MainContextInfo.SpuContext);
        if (pContextInfo->SpuContext < 0) {
            crWarning("crServerDispatchCreateContext() failed.");
            crStateEnableDiffOnMakeCurrent(GL_TRUE);
            cr_server.bUseMultipleContexts = GL_FALSE;
            if (!fFirst)
                crError("creating shared context failed, while it is expected to work!");
        }
        else if (fFirst)
        {
            crStateEnableDiffOnMakeCurrent(GL_FALSE);
        }
    }
    else
    {
        pContextInfo->SpuContext = -1;
    }

    /* Now create a new state-tracker context and initialize the
     * dispatch function pointers.
     */
    newCtx = crStateCreateContextEx(&cr_server.limits, visualBits, NULL, internalID);
    if (newCtx) {
        crStateSetCurrentPointers( newCtx, &(cr_server.current) );
        crStateResetCurrentPointers(&(cr_server.current));
        retVal = preloadCtxID<0 ? (GLint)crHashtableAllocKeys( cr_server.contextTable, 1 ) : preloadCtxID;

        pContextInfo->pContext = newCtx;
        Assert(pContextInfo->CreateInfo.realVisualBits == visualBits);
        pContextInfo->CreateInfo.externalID = retVal;
        pContextInfo->CreateInfo.pszDpyName = dpyName ? crStrdup(dpyName) : NULL;
        crHashtableAdd(cr_server.contextTable, retVal, pContextInfo);
    }

    if (retVal != -1 && !cr_server.bIsInLoadingState) {
        int pos;
        for (pos = 0; pos < CR_MAX_CONTEXTS; pos++) {
            if (cr_server.curClient->contextList[pos] == 0) {
                cr_server.curClient->contextList[pos] = retVal;
                break;
            }
        }
    }

    crServerReturnValue( &retVal, sizeof(retVal) );

    return retVal;
}
示例#6
0
GLint REPLICATESPU_APIENTRY
replicatespu_CreateContext( const char *dpyName, GLint visual, GLint shareCtx )
{
	static GLint freeCtxID = MAGIC_OFFSET;
	char headspuname[10];
	ContextInfo *context, *sharedContext = NULL;
	unsigned int i;

	if (shareCtx > 0) {
		sharedContext = (ContextInfo *)
			crHashtableSearch(replicate_spu.contextTable, shareCtx);
	}

	replicatespuFlushAll( &(replicate_spu.thread[0]) );

#ifdef CHROMIUM_THREADSAFE_notyet
	crLockMutex(&_ReplicateMutex);
#endif

	replicatespuStartVnc(dpyName);

	/*
	 * Alloc new ContextInfo object
	 */
	context = (ContextInfo *) crCalloc(sizeof(ContextInfo));
	if (!context) {
		crWarning("Replicate SPU: Out of memory in CreateContext");
		return -1;
	}

	/* Contexts that don't share display lists get their own
	 * display list managers.  Contexts that do, share the
	 * display list managers of the contexts they're sharing
	 * with (man, some grammarian has to go over that and make
	 * it actually sound like English).
	 */
	if (sharedContext) {
		context->displayListManager = sharedContext->displayListManager;
		/* Let the DLM know that a second context is using the
		 * same display list manager, so it can manage when its
		 * resources are released.
		 */
		crDLMUseDLM(context->displayListManager);
	}
	else {
		context->displayListManager = crDLMNewDLM(0, NULL);
		if (!context->displayListManager) {
			crWarning("Replicate SPU: could not initialize display list manager.");
		}
	}

	/* Fill in the new context info */
	if (sharedContext)
		context->State = crStateCreateContext(NULL, visual, sharedContext->State);
	else
		context->State = crStateCreateContext(NULL, visual, NULL);
	context->rserverCtx[0] = 1; /* not really used */
	context->visBits = visual;
	context->currentWindow = 0; /* not bound */
	context->dlmState
		= crDLMNewContext(context->displayListManager);
	context->displayListMode = GL_FALSE; /* not compiling */
	context->displayListIdentifier = 0;
	context->shareCtx = shareCtx;

#if 0
	/* Set the Current pointers now.... */
	crStateSetCurrentPointers( context->State,
														 &(replicate_spu.thread[0].packer->current) );
#endif

	for (i = 1; i < CR_MAX_REPLICANTS; i++) {
		int r_writeback = 1, rserverCtx = -1;
		int sharedServerCtx;

		sharedServerCtx = sharedContext ? sharedContext->rserverCtx[i] : 0;

		if (!IS_CONNECTED(replicate_spu.rserver[i].conn))
			continue;

		if (replicate_spu.swap)
			crPackCreateContextSWAP( dpyName, visual, sharedServerCtx,
															 &rserverCtx, &r_writeback );
		else
			crPackCreateContext( dpyName, visual, sharedServerCtx,
													 &rserverCtx, &r_writeback );

		/* Flush buffer and get return value */
		replicatespuFlushOne( &(replicate_spu.thread[0]), i );

		while (r_writeback)
			crNetRecv();
		if (replicate_spu.swap)
			rserverCtx = (GLint) SWAP32(rserverCtx);

		if (rserverCtx < 0) {
#ifdef CHROMIUM_THREADSAFE_notyet
			crUnlockMutex(&_ReplicateMutex);
#endif
			crWarning("Replicate SPU: CreateContext failed.");
			return -1;  /* failed */
		}

		context->rserverCtx[i] = rserverCtx;
	}


	if (!crStrcmp( headspuname, "nop" ))
		replicate_spu.NOP = 0;
	else
		replicate_spu.NOP = 1;

#ifdef CHROMIUM_THREADSAFE_notyet
	crUnlockMutex(&_ReplicateMutex);
#endif

	crListPushBack(replicate_spu.contextList, (void *)freeCtxID);
	crHashtableAdd(replicate_spu.contextTable, freeCtxID, context);

	return freeCtxID++;
}