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; }
/** * 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 }
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); } }
/** * 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 ); }