Esempio n. 1
0
static GLint ARRAYSPU_APIENTRY
arrayspu_CreateContext( const char *dpyName, GLint visual, GLint shareCtx )
{
    GLint ctx, slot;

#ifdef CHROMIUM_THREADSAFE
    crLockMutex(&_ArrayMutex);
#endif

    ctx = array_spu.child.CreateContext(dpyName, visual, shareCtx);

    /* find an empty context slot */
    for (slot = 0; slot < array_spu.numContexts; slot++) {
        if (!array_spu.context[slot].clientState) {
            /* found empty slot */
            break;
        }
    }
    if (slot == array_spu.numContexts) {
        array_spu.numContexts++;
    }

    array_spu.context[slot].clientState = crStateCreateContext(NULL, visual, NULL);
    array_spu.context[slot].clientCtx = ctx;
#ifdef CR_ARB_vertex_buffer_object
    array_spu.context[slot].clientState->bufferobject.retainBufferData = GL_TRUE;
#endif

#ifdef CHROMIUM_THREADSAFE
    crUnlockMutex(&_ArrayMutex);
#endif

    return ctx;
}
Esempio n. 2
0
GLint FEEDBACKSPU_APIENTRY
feedbackspu_VBoxCreateContext( GLint con, const char *dpyName, GLint visual, GLint shareCtx )
{
    GLint ctx, slot;

#ifdef CHROMIUM_THREADSAFE
    crLockMutex(&feedback_spu.mutex);
#endif

    ctx = feedback_spu.child.VBoxCreateContext(con, dpyName, visual, shareCtx);

    /* find an empty context slot */
    for (slot = 0; slot < feedback_spu.numContexts; slot++) {
        if (!feedback_spu.context[slot].clientState) {
            /* found empty slot */
            break;
        }
    }
    if (slot == feedback_spu.numContexts) {
        feedback_spu.numContexts++;
    }

    feedback_spu.context[slot].clientState = crStateCreateContext(NULL, visual, NULL);
    feedback_spu.context[slot].clientCtx = ctx;

#ifdef CHROMIUM_THREADSAFE
    crUnlockMutex(&feedback_spu.mutex);
#endif

    return ctx;
}
Esempio n. 3
0
static SPUFunctions *feedbackSPUInit( int id, SPU *child, SPU *self,
                                      unsigned int context_id,
                                      unsigned int num_contexts )
{
    (void) context_id;
    (void) num_contexts;

#ifdef CHROMIUM_THREADSAFE
    crInitMutex(&feedback_spu.mutex);
#endif

    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();

    feedback_spu.defaultctx = crStateCreateContext(NULL, 0, NULL);
    crStateSetCurrent(feedback_spu.defaultctx);

    feedback_spu.numContexts = 0;
    crMemZero(feedback_spu.context, CR_MAX_CONTEXTS * sizeof(ContextInfo));

    return &feedback_functions;
}
Esempio n. 4
0
static SPUFunctions *arraySPUInit( int id, SPU *child, SPU *self,
                                   unsigned int context_id,
                                   unsigned int num_contexts )
{

    (void) context_id;
    (void) num_contexts;

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

    crStateInit();
    array_spu.ctx = crStateCreateContext( NULL, 0, NULL );
#ifdef CR_ARB_vertex_buffer_object
    array_spu.ctx->bufferobject.retainBufferData = GL_TRUE;
#endif
    /* we call SetCurrent instead of MakeCurrent as the differencer
     * isn't setup yet anyway */
    crStateSetCurrent( array_spu.ctx );

    return &array_functions;
}
Esempio n. 5
0
CRContext *
crStateCreateContextEx(const CRLimitsState *limits, GLint visBits, CRContext *share, GLint presetID)
{
    if (presetID>0)
    {
        CRASSERT(!g_availableContexts[presetID]);
        g_availableContexts[presetID] = 1;
        return crStateCreateContextId(presetID, limits, visBits, share);
    }
    else return crStateCreateContext(limits, visBits, share);
}
Esempio n. 6
0
static SPUFunctions *nopSPUInit( int id, SPU *child, SPU *self,
		unsigned int context_id,
		unsigned int num_contexts )
{
	(void) id;
	(void) context_id;
	(void) num_contexts;
	(void) child;
	(void) self;

	nopspuGatherConfiguration();

	crStateInit();
	nop_spu.ctx = crStateCreateContext( NULL, CR_RGB_BIT, NULL );
	crStateSetCurrent( nop_spu.ctx );

	return &nop_functions;
}
Esempio n. 7
0
static SPUFunctions *arraySPUInit( int id, SPU *child, SPU *self,
        unsigned int context_id,
        unsigned int num_contexts )
{

    (void) context_id;
    (void) num_contexts;

#ifdef CHROMIUM_THREADSAFE
    crInitMutex(&_ArrayMutex);
#endif

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

    crStateInit();
/*@todo seems default context ain't needed at all*/
    array_spu.defaultctx = crStateCreateContext( NULL, 0, NULL );
#ifdef CR_ARB_vertex_buffer_object
    array_spu.defaultctx->bufferobject.retainBufferData = GL_TRUE;
#endif
    /* we call SetCurrent instead of MakeCurrent as the differencer
     * isn't setup yet anyway */
    crStateSetCurrent( array_spu.defaultctx );

    array_spu.numContexts = 0;
    crMemZero(array_spu.context, CR_MAX_CONTEXTS * sizeof(ContextInfo));

    return &array_functions;
}
Esempio n. 8
0
/**
 * Do CRServer initializations.  After this, we can begin servicing clients.
 */
void
crServerInit(int argc, char *argv[])
{
    int i;
    char *mothership = NULL;
    CRMuralInfo *defaultMural;

    for (i = 1 ; i < argc ; i++)
    {
        if (!crStrcmp( argv[i], "-mothership" ))
        {
            if (i == argc - 1)
            {
                crError( "-mothership requires an argument" );
            }
            mothership = argv[i+1];
            i++;
        }
        else if (!crStrcmp( argv[i], "-port" ))
        {
            /* This is the port on which we'll accept client connections */
            if (i == argc - 1)
            {
                crError( "-port requires an argument" );
            }
            cr_server.tcpip_port = crStrToInt(argv[i+1]);
            i++;
        }
        else if (!crStrcmp( argv[i], "-vncmode" ))
        {
            cr_server.vncMode = 1;
        }
        else if (!crStrcmp( argv[i], "-help" ))
        {
            crPrintHelp();
            exit(0);
        }
    }

    signal( SIGTERM, crServerCleanup );
    signal( SIGINT, crServerCleanup );
#ifndef WINDOWS
    signal( SIGPIPE, SIG_IGN );
#endif

#if DEBUG_FP_EXCEPTIONS
    {
        fpu_control_t mask;
        _FPU_GETCW(mask);
        mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
                  | _FPU_MASK_OM | _FPU_MASK_UM);
        _FPU_SETCW(mask);
    }
#endif

    cr_server.firstCallCreateContext = GL_TRUE;
    cr_server.firstCallMakeCurrent = GL_TRUE;

    /*
     * Create default mural info and hash table.
     */
    cr_server.muralTable = crAllocHashtable();
    defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
    crHashtableAdd(cr_server.muralTable, 0, defaultMural);

    cr_server.programTable = crAllocHashtable();

    crNetInit(crServerRecv, crServerClose);
    crStateInit();

    crServerGatherConfiguration(mothership);

    crStateLimitsInit( &(cr_server.limits) );

    /*
     * Default context
     */
    cr_server.contextTable = crAllocHashtable();
    cr_server.DummyContext = crStateCreateContext( &cr_server.limits,
                             CR_RGB_BIT | CR_DEPTH_BIT, NULL );
    cr_server.curClient->currentCtx = cr_server.DummyContext;

    crServerInitDispatch();
    crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );

    crUnpackSetReturnPointer( &(cr_server.return_ptr) );
    crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );

    cr_server.barriers = crAllocHashtable();
    cr_server.semaphores = crAllocHashtable();
}
Esempio n. 9
0
/**
 * Do CRServer initializations.  After this, we can begin servicing clients.
 */
GLboolean crVBoxServerInit(void)
{
    CRMuralInfo *defaultMural;

#if DEBUG_FP_EXCEPTIONS
    {
        fpu_control_t mask;
        _FPU_GETCW(mask);
        mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
                            | _FPU_MASK_OM | _FPU_MASK_UM);
        _FPU_SETCW(mask);
    }
#endif

    crNetInit(crServerRecv, crServerClose);

    cr_server.firstCallCreateContext = GL_TRUE;
    cr_server.firstCallMakeCurrent = GL_TRUE;

    cr_server.bIsInLoadingState = GL_FALSE;
    cr_server.bIsInSavingState  = GL_FALSE;

    cr_server.pCleanupClient = NULL;

    /*
     * Create default mural info and hash table.
     */
    cr_server.muralTable = crAllocHashtable();
    defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
    crHashtableAdd(cr_server.muralTable, 0, defaultMural);

    cr_server.programTable = crAllocHashtable();

    crStateInit();

    crStateLimitsInit( &(cr_server.limits) );

    cr_server.barriers = crAllocHashtable();
    cr_server.semaphores = crAllocHashtable();

    crUnpackSetReturnPointer( &(cr_server.return_ptr) );
    crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );

    /*
     * Default context
     */
    cr_server.contextTable = crAllocHashtable();
    cr_server.DummyContext = crStateCreateContext( &cr_server.limits,
                                                   CR_RGB_BIT | CR_DEPTH_BIT, NULL );
    cr_server.pContextCreateInfoTable = crAllocHashtable();
    cr_server.pWindowCreateInfoTable = crAllocHashtable();

    crServerSetVBoxConfigurationHGCM();

    if (!cr_server.head_spu)
        return GL_FALSE;

    crServerInitDispatch();
    crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );

    /*Check for PBO support*/
    if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object)
    {
        cr_server.bUsePBOForReadback=GL_TRUE;
    }

    return GL_TRUE;
}
Esempio n. 10
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;
}
Esempio n. 11
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++;
}
Esempio n. 12
0
GLint PACKSPU_APIENTRY
packspu_CreateContext( const char *dpyName, GLint visual, GLint shareCtx )
{
    GET_THREAD(thread);
    int writeback = 1;
    GLint serverCtx = (GLint) -1;
    int slot;

#ifdef CHROMIUM_THREADSAFE
    crLockMutex(&_PackMutex);
#endif

    if (!thread) {
        thread = packspuNewThread(crThreadID());
    }
    CRASSERT(thread);
    CRASSERT(thread->packer);

    if (shareCtx > 0) {
        /* translate to server ctx id */
        shareCtx -= MAGIC_OFFSET;
        if (shareCtx >= 0 && shareCtx < pack_spu.numContexts) {
            shareCtx = pack_spu.context[shareCtx].serverCtx;
        }
    }

    crPackSetContext( thread->packer );

    /* Pack the command */
    if (pack_spu.swap)
        crPackCreateContextSWAP( dpyName, visual, shareCtx, &serverCtx, &writeback );
    else
        crPackCreateContext( dpyName, visual, shareCtx, &serverCtx, &writeback );

    /* Flush buffer and get return value */
    packspuFlush(thread);
    if (!(thread->netServer.conn->actual_network))
    {
        /* HUMUNGOUS HACK TO MATCH SERVER NUMBERING
         *
         * The hack exists solely to make file networking work for now.  This
         * is totally gross, but since the server expects the numbers to start
         * from 5000, we need to write them out this way.  This would be
         * marginally less gross if the numbers (500 and 5000) were maybe
         * some sort of #define'd constants somewhere so the client and the
         * server could be aware of how each other were numbering things in
         * cases like file networking where they actually
         * care. 
         *
         *  -Humper 
         *
         */
        serverCtx = 5000;
    }
    else {
        while (writeback)
            crNetRecv();

        if (pack_spu.swap) {
            serverCtx = (GLint) SWAP32(serverCtx);
        }
        if (serverCtx < 0) {
#ifdef CHROMIUM_THREADSAFE
            crUnlockMutex(&_PackMutex);
#endif
            crWarning("Failure in packspu_CreateContext");
            return -1;  /* failed */
        }
    }

    /* find an empty context slot */
    for (slot = 0; slot < pack_spu.numContexts; slot++) {
        if (!pack_spu.context[slot].clientState) {
            /* found empty slot */
            break;
        }
    }
    if (slot == pack_spu.numContexts) {
        pack_spu.numContexts++;
    }

    /* Fill in the new context info */
    /* XXX fix-up sharedCtx param here */
    pack_spu.context[slot].clientState = crStateCreateContext(NULL, visual, NULL);
    pack_spu.context[slot].clientState->bufferobject.retainBufferData = GL_TRUE;
    pack_spu.context[slot].serverCtx = serverCtx;

#ifdef CHROMIUM_THREADSAFE
    crUnlockMutex(&_PackMutex);
#endif

    return MAGIC_OFFSET + slot;
}
Esempio n. 13
0
/**
 * Replicate our contexts on a new server (indicated by NewServerIndex).
 * XXX It may be a problem if we try to attach to a shared context,
 * when that shared context has not yet been created.
 */
static void
replicatespuReplicateContext(void *element, void *arg)
{
	GLint ctx = (GLint) element;
	ThreadInfo *thread = (ThreadInfo *) arg;
	ContextInfo *context = crHashtableSearch(replicate_spu.contextTable, ctx);
	ContextInfo *sharedContext = NULL;
	CRContext *tempState;
	GLint return_val = 0, shareCtx = context->shareCtx, sharedServerCtx = 0;
	int writeback;

	if (!context->State) { /* XXX need this? */
		crWarning("ReplicateSPU: replicating context with no state!");
		return;
	}

	if (shareCtx > 0) {
		sharedContext = (ContextInfo *)
			crHashtableSearch(replicate_spu.contextTable, shareCtx);
		if (sharedContext)
			sharedServerCtx = sharedContext->rserverCtx[NewServerIndex];
	}


	/*
	 * Send CreateContext to new server and get return value
	 */
	if (replicate_spu.swap)
		crPackCreateContextSWAP( replicate_spu.dpyName, context->visBits,
														 sharedServerCtx, &return_val, &writeback);
	else
		crPackCreateContext( replicate_spu.dpyName, context->visBits,
												 sharedServerCtx, &return_val, &writeback);
	replicatespuFlushOne(thread, NewServerIndex);
	writeback = 1;
	while (writeback)
		crNetRecv();
	if (replicate_spu.swap)
		return_val = (GLint) SWAP32(return_val);
	if (return_val <= 0) {
		crWarning("Replicate SPU: CreateContext failed");
		return;
	}

	context->rserverCtx[NewServerIndex] = return_val;

	/*
	 * Create a new CRContext record representing the state of the new
	 * server (all default state).  We'll diff against this to send all the
	 * needed state to the server.
	 * When done, we can dispose of this context.
	 */
	tempState = crStateCreateContext(NULL, context->visBits, NULL);

	/* Bind the remote context. The window's not really significant. */
	{
		int serverWindow;
		if (context->currentWindow)
			serverWindow = context->currentWindow->id[NewServerIndex];
		else
			serverWindow = 0;

		if (replicate_spu.swap)
			crPackMakeCurrentSWAP( serverWindow, 0, return_val );
		else
			crPackMakeCurrent( serverWindow, 0, return_val );
	}

	/* Send state differences, all texture objects and all display lists
	 * to the new server.
	 * XXX We could be more efficient; in the case of a shared context,
	 * we only need to replicate textures and display lists once...
	 */
	crStateDiffContext( tempState, context->State );
	replicatespuReplicateTextures(tempState, context->State);
	replicatespuReplicateLists(tempState, context->displayListManager);
			
	/* XXX this call may not be needed */
	replicatespuFlushOne(thread, NewServerIndex);

	/* Destroy the temporary context, no longer needed */
	crStateDestroyContext( tempState );
}