static void ARRAYSPU_APIENTRY arrayspu_MakeCurrent( GLint window, GLint nativeWindow, GLint ctx ) { #ifdef CHROMIUM_THREADSAFE crLockMutex(&_ArrayMutex); #endif array_spu.child.MakeCurrent(window, nativeWindow, ctx); if (ctx) { int slot; for (slot=0; slot<array_spu.numContexts; ++slot) if (array_spu.context[slot].clientCtx == ctx) break; CRASSERT(slot < array_spu.numContexts); crStateMakeCurrent(array_spu.context[slot].clientState); } else { crStateMakeCurrent(NULL); } #ifdef CHROMIUM_THREADSAFE crUnlockMutex(&_ArrayMutex); #endif }
void FEEDBACKSPU_APIENTRY feedbackspu_MakeCurrent( GLint window, GLint nativeWindow, GLint ctx ) { #ifdef CHROMIUM_THREADSAFE crLockMutex(&feedback_spu.mutex); #endif feedback_spu.child.MakeCurrent(window, nativeWindow, ctx); if (ctx) { int slot; GLint oldmode; for (slot=0; slot<feedback_spu.numContexts; ++slot) if (feedback_spu.context[slot].clientCtx == ctx) break; CRASSERT(slot < feedback_spu.numContexts); crStateMakeCurrent(feedback_spu.context[slot].clientState); crStateGetIntegerv(GL_RENDER_MODE, &oldmode); if (oldmode!=feedback_spu.render_mode) { feedback_spu.self.RenderMode(oldmode); } } else { crStateMakeCurrent(NULL); } #ifdef CHROMIUM_THREADSAFE crUnlockMutex(&feedback_spu.mutex); #endif }
void PACKSPU_APIENTRY packspu_DestroyContext( GLint ctx ) { const int slot = ctx - MAGIC_OFFSET; ContextInfo *context; GET_THREAD(thread); CRASSERT(slot >= 0); CRASSERT(slot < pack_spu.numContexts); CRASSERT(thread); context = &(pack_spu.context[slot]); if (pack_spu.swap) crPackDestroyContextSWAP( context->serverCtx ); else crPackDestroyContext( context->serverCtx ); crStateDestroyContext( context->clientState ); context->clientState = NULL; context->serverCtx = 0; if (thread->currentContext == context) { thread->currentContext = NULL; crStateMakeCurrent( NULL ); } }
void REPLICATESPU_APIENTRY replicatespu_DestroyContext( GLint ctx ) { unsigned int i; ContextInfo *context = (ContextInfo *) crHashtableSearch(replicate_spu.contextTable, ctx); GET_THREAD(thread); if (!context) { crWarning("Replicate SPU: DestroyContext, bad context %d", ctx); return; } CRASSERT(thread); replicatespuFlushAll( (void *)thread ); for (i = 0; i < CR_MAX_REPLICANTS; i++) { if (!IS_CONNECTED(replicate_spu.rserver[i].conn)) continue; if (replicate_spu.swap) crPackDestroyContextSWAP( context->rserverCtx[i] ); else crPackDestroyContext( context->rserverCtx[i] ); replicatespuFlushOne(thread, i); } crStateDestroyContext( context->State ); /* Although we only allocate a display list manager once, * we free it every time; this is okay since the DLM itself * will track its uses and will only release the resources * when the last user has relinquished it. */ crDLMFreeDLM(context->displayListManager); crDLMFreeContext(context->dlmState); if (thread->currentContext == context) { thread->currentContext = NULL; crStateMakeCurrent( NULL ); crDLMSetCurrentState(NULL); } /* zero, just to be safe */ crMemZero(context, sizeof(ContextInfo)); /* Delete from both the context table, and the context list. */ crHashtableDelete(replicate_spu.contextTable, ctx, crFree); { CRListIterator *foundElement = crListFind(replicate_spu.contextList, (void *)ctx, CompareIntegers); if (foundElement != NULL) { crListErase(replicate_spu.contextList, foundElement); } } }
/** * Process incoming/pending message for the given client (queue entry). * \return CLIENT_GONE if this client has gone away/exited, * CLIENT_NEXT if we can advance to the next client * CLIENT_MORE if we have to process more messages for this client. */ static ClientStatus glStubServiceClient(const RunQueue *qEntry) { CRMessage *msg; CRConnection *conn; /* set current client pointer */ cr_server.curClient = qEntry->client; conn = cr_server.run_queue->client->conn; /* service current client as long as we can */ while (conn && conn->type != CR_NO_CONNECTION && crNetNumMessages(conn) > 0) { unsigned int len; /* crDebug("%d messages on %p", crNetNumMessages(conn), (void *) conn); */ /* Don't use GetMessage, because we want to do our own crNetRecv() calls * here ourself. * Note that crNetPeekMessage() DOES remove the message from the queue * if there is one. */ len = crNetPeekMessage( conn, &msg ); CRASSERT(len > 0); if (msg->header.type != CR_MESSAGE_OPCODES) { crError( "SPU %d sent me CRAP (type=0x%x)", cr_server.curClient->spu_id, msg->header.type ); } /* Do the context switch here. No sense in switching before we * really have any work to process. This is a no-op if we're * not really switching contexts. * * XXX This isn't entirely sound. The crStateMakeCurrent() call * will compute the state difference and dispatch it using * the head SPU's dispatch table. * * This is a problem if this is the first buffer coming in, * and the head SPU hasn't had a chance to do a MakeCurrent() * yet (likely because the MakeCurrent() command is in the * buffer itself). * * At best, in this case, the functions are no-ops, and * are essentially ignored by the SPU. In the typical * case, things aren't too bad; if the SPU just calls * crState*() functions to update local state, everything * will work just fine. * * In the worst (but unusual) case where a nontrivial * SPU is at the head of a gl stub's SPU chain (say, * in a multiple-tiered "tilesort" arrangement, as * seen in the "multitilesort.conf" configuration), the * SPU may rely on state set during the MakeCurrent() that * may not be present yet, because no MakeCurrent() has * yet been dispatched. * * This headache will have to be revisited in the future; * for now, SPUs that could head a gl stub's SPU chain * will have to detect the case that their functions are * being called outside of a MakeCurrent(), and will have * to handle the situation gracefully. (This is currently * the case with the "tilesort" SPU.) */ #if 0 crStateMakeCurrent( cr_server.curClient->currentCtx ); #else crStateMakeCurrent( cr_server.curClient->currentCtx ); /* Check if the current window is the one that the client wants to * draw into. If not, dispatch a MakeCurrent to activate the proper * window. */ if (cr_server.curClient) { int clientWindow = cr_server.curClient->currentWindow; int clientContext = cr_server.curClient->currentContextNumber; if (clientWindow && clientWindow != cr_server.currentWindow) { glStubDispatchMakeCurrent(clientWindow, 0, clientContext); /* CRASSERT(cr_server.currentWindow == clientWindow); */ } } #endif /* Force scissor, viewport and projection matrix update in * glStubSetOutputBounds(). */ cr_server.currentSerialNo = 0; /* Commands get dispatched here */ glStubDispatchMessage(msg); crNetFree( conn, msg ); if (qEntry->blocked) { /* Note/assert: we should not be inside a glBegin/End or glNewList/ * glEndList pair at this time! */ return CLIENT_NEXT; } } /* while */ /* * Check if client/connection is gone */ if (!conn || conn->type == CR_NO_CONNECTION) { crDebug("Delete client %p at %d", cr_server.run_queue->client, __LINE__); glStubDeleteClient( cr_server.run_queue->client ); return CLIENT_GONE; } /* * Determine if we can advance to next client. * If we're currently inside a glBegin/End primitive or building a display * list we can't service another client until we're done with the * primitive/list. */ if (glStubClientInBeginEnd(cr_server.curClient)) { /* The next message has to come from the current client's connection. */ CRASSERT(!qEntry->blocked); return CLIENT_MORE; } else { /* get next client */ return CLIENT_NEXT; } }
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; } }
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; } }
void REPLICATESPU_APIENTRY replicatespu_MakeCurrent( GLint window, GLint nativeWindow, GLint ctx ) { unsigned int i; unsigned int show_window = 0; WindowInfo *winInfo = (WindowInfo *) crHashtableSearch( replicate_spu.windowTable, window ); ContextInfo *newCtx = (ContextInfo *) crHashtableSearch( replicate_spu.contextTable, ctx ); GET_THREAD(thread); if (!winInfo) { crWarning("Replicate SPU: Invalid window ID %d passed to MakeCurrent", window); return; } if (thread) replicatespuFlushAll( (void *)thread ); if (!thread) { thread = replicatespuNewThread( crThreadID() ); } CRASSERT(thread); CRASSERT(thread->packer); if (newCtx && winInfo) { newCtx->currentWindow = winInfo; #if 000 /* This appears to be obsolete code */ if (replicate_spu.render_to_crut_window && !nativeWindow) { char response[8096]; CRConnection *conn = crMothershipConnect(); if (!conn) { crError("Replicate SPU: Couldn't connect to the mothership to get CRUT drawable-- " "I have no idea what to do!"); } crMothershipGetParam( conn, "crut_drawable", response ); nativeWindow = crStrToInt(response); crDebug("Replicate SPU: using CRUT drawable: 0x%x", nativeWindow); crMothershipDisconnect(conn); } #endif if (replicate_spu.glx_display && winInfo && winInfo->nativeWindow != nativeWindow) { winInfo->nativeWindow = nativeWindow; replicatespuMonitorWindow(winInfo); replicatespuRePositionWindow(winInfo); show_window = 1; } CRASSERT(newCtx->State); /* verify valid */ crPackSetContext( thread->packer ); } /* * Send the MakeCurrent to all crservers (vnc viewers) */ for (i = 0; i < CR_MAX_REPLICANTS; i++) { const GLint serverWin = winInfo ? winInfo->id[i] : -1; const GLint serverCtx = newCtx ? newCtx->rserverCtx[i] : -1; if (!IS_CONNECTED(replicate_spu.rserver[i].conn)) continue; /* Note: app's native window ID not needed on server side; pass zero */ if (replicate_spu.swap) crPackMakeCurrentSWAP(serverWin, 0, serverCtx); else crPackMakeCurrent(serverWin, 0, serverCtx); if (show_window) { /* We may find that the window was mapped before we * called MakeCurrent, if that's the case then ensure * the remote end gets the WindowShow event */ if (winInfo->viewable) { if (replicate_spu.swap) crPackWindowShowSWAP(serverWin, GL_TRUE); else crPackWindowShow(serverWin, GL_TRUE); } } replicatespuFlushOne(thread, i); } if (newCtx) { crStateMakeCurrent( newCtx->State ); crDLMSetCurrentState(newCtx->dlmState); } else { crStateMakeCurrent( NULL ); crDLMSetCurrentState(NULL); } thread->currentContext = newCtx; }
void PACKSPU_APIENTRY packspu_MakeCurrent( GLint window, GLint nativeWindow, GLint ctx ) { GET_THREAD(thread); GLint serverCtx; ContextInfo *newCtx; if (!thread) { thread = packspuNewThread( crThreadID() ); } CRASSERT(thread); CRASSERT(thread->packer); if (ctx) { const int slot = ctx - MAGIC_OFFSET; CRASSERT(slot >= 0); CRASSERT(slot < pack_spu.numContexts); newCtx = &pack_spu.context[slot]; CRASSERT(newCtx->clientState); /* verify valid */ if (newCtx->fAutoFlush) { if (newCtx->currentThread && newCtx->currentThread != thread) { crLockMutex(&_PackMutex); /* do a flush for the previusly assigned thread * to ensure all commands issued there are submitted */ if (newCtx->currentThread && newCtx->currentThread->inUse && newCtx->currentThread->netServer.conn && newCtx->currentThread->packer && newCtx->currentThread->packer->currentBuffer) { packspuFlush((void *) newCtx->currentThread); } crUnlockMutex(&_PackMutex); } newCtx->currentThread = thread; } thread->currentContext = newCtx; crPackSetContext( thread->packer ); crStateMakeCurrent( newCtx->clientState ); //crStateSetCurrentPointers(newCtx->clientState, &thread->packer->current); serverCtx = pack_spu.context[slot].serverCtx; } else { thread->currentContext = NULL; crStateMakeCurrent( NULL ); newCtx = NULL; serverCtx = 0; } if (pack_spu.swap) crPackMakeCurrentSWAP( window, nativeWindow, serverCtx ); else crPackMakeCurrent( window, nativeWindow, serverCtx ); { GET_THREAD(t); (void) t; CRASSERT(t); } }
/** * This is the main routine responsible for replicating our GL state * for a new VNC viewer. Called when we detect that a new VNC viewer * has been started. * \param ipaddress the IP address where the new viewer is running. */ void replicatespuReplicate(int ipaddress) { GET_THREAD(thread); struct in_addr addr; char *hosturl; char *ipstring; int i, r_slot; int serverPort; crDebug("Replicate SPU: Enter replicatespuReplicate(ipaddress=0x%x)", ipaddress); replicatespuFlushAll( (void *)thread ); #ifdef CHROMIUM_THREADSAFE_notyet crLockMutex(&_ReplicateMutex); #endif /* * Find empty slot. * Slot 0 is the dummy slot (a non-existant server on devnull connection) */ for (r_slot = 1; r_slot < CR_MAX_REPLICANTS; r_slot++) { if (!IS_CONNECTED(replicate_spu.rserver[r_slot].conn)) break; } if (r_slot == CR_MAX_REPLICANTS) { crWarning("Replicate SPU: no more replicant slots available"); return; } /** ** OK, now rserver[r_slot] is free for use. **/ /* * At this time, we can only support one VNC viewer per host. * Check for that here. */ for (i = 1; i < CR_MAX_REPLICANTS; i++) { if (replicate_spu.ipnumbers[i] == ipaddress) { CRConnection *conn = replicate_spu.rserver[i].conn; /* If the connection appears to be active, it may actually be a dangling * connection. Try flushing it now. If flushing fails, the connection * type will definitely be CR_NO_CONNECTION (which we test below). */ if (conn) { if (conn->type != CR_NO_CONNECTION) { FlushConnection(i); } if (conn->type != CR_NO_CONNECTION) { crWarning("Replicate SPU: Can't connect to multiple VNC viewers on one host."); #if 0 /* The above test isn't 100% reliable and can prevent successful * restart of a viewer on a host. For now, just print warning and * continue. */ return; #endif } } } } replicate_spu.ipnumbers[r_slot] = ipaddress; serverPort = replicate_spu.chromium_start_port + r_slot; if (replicate_spu.vncAvailable) { /* Send a ChromiumStart message to the VNC Server. The VNC Server will * in turn send a ChromiumStart message to all the attached VNC viewers. * The VNC Viewer/Chromium module will tell its crserver that there's * a new OpenGL client. * We pass the mothership port and crserver port in this message. */ char protocol[100], hostname[1000]; const char *mothershipURL; unsigned short mothershipPort; mothershipURL = crGetenv("CRMOTHERSHIP"); crDebug("Replicate SPU: CRMOTHERSHIP env var = %s", mothershipURL); if (mothershipURL) crParseURL(mothershipURL, protocol, hostname, &mothershipPort, DEFAULT_MOTHERSHIP_PORT); else mothershipPort = DEFAULT_MOTHERSHIP_PORT; crDebug("Replicate SPU: Sending ChromiumStart msg to VNC server, port=%d", serverPort); if (!XVncChromiumStart(replicate_spu.glx_display, ipaddress, serverPort, mothershipPort)) { crWarning("Replicate SPU: XVncChromiumStart() call failed"); } } addr.s_addr = ipaddress; ipstring = inet_ntoa(addr); hosturl = crAlloc(crStrlen(ipstring) + 9); sprintf(hosturl, "tcpip://%s", ipstring); crDebug("Replicate SPU attaching to %s on port %d", hosturl, serverPort); /* connect to the remote VNC server */ replicate_spu.rserver[r_slot].name = crStrdup( replicate_spu.name ); replicate_spu.rserver[r_slot].buffer_size = replicate_spu.buffer_size; replicate_spu.rserver[r_slot].conn = crNetConnectToServer( hosturl, serverPort, replicate_spu.rserver[r_slot].buffer_size, 1); if (!replicate_spu.rserver[r_slot].conn) { crWarning("Replicate SPU: failed to connect to %s", hosturl); return; } CRASSERT(replicate_spu.rserver[r_slot].conn); /* * Setup the the packer flush function. While replicating state to * a particular server we definitely don't want to do any broadcast * flushing! */ crPackFlushFunc( thread->packer, replicatespuFlushOnePacker ); crPackSendHugeFunc( thread->packer, replicatespuHugeOnePacker ); NewServerIndex = r_slot; /* * Create server-side windows and contexts by walking tables of app windows * and contexts. Note that windows can be created in random order, * but contexts must be created in the order they were originally * created, or shared contexts will break. */ crHashtableWalk(replicate_spu.windowTable, replicatespuReplicateWindow, thread); crListApply(replicate_spu.contextList, replicatespuReplicateContext, thread); /* MakeCurrent, the current context */ if (thread->currentContext) { int serverWindow = thread->currentContext->currentWindow->id[r_slot]; int serverContext = thread->currentContext->rserverCtx[r_slot]; if (replicate_spu.swap) crPackMakeCurrentSWAP(serverWindow, 0, serverContext); else crPackMakeCurrent(serverWindow, 0, serverContext); crStateMakeCurrent( thread->currentContext->State ); } /* * Set window sizes */ crHashtableWalk(replicate_spu.windowTable, replicatespuResizeWindows, thread); replicatespuFlushOne(thread, NewServerIndex); /* * restore normal, broadcasting packer flush function now. */ crPackFlushFunc( thread->packer, replicatespuFlush ); crPackSendHugeFunc( thread->packer, replicatespuHuge ); NewServerIndex = -1; crDebug("Replicate SPU: leaving replicatespuReplicate"); #ifdef CHROMIUM_THREADSAFE_notyet crUnlockMutex(&_ReplicateMutex); #endif }