static void DoSync(void) { CRMessage *in, out; out.header.type = CR_MESSAGE_OOB; if (render_spu.is_swap_master) { int a; for (a = 0; a < render_spu.num_swap_clients; a++) { crNetGetMessage( render_spu.swap_conns[a], &in ); crNetFree( render_spu.swap_conns[a], in); } for (a = 0; a < render_spu.num_swap_clients; a++) crNetSend( render_spu.swap_conns[a], NULL, &out, sizeof(CRMessage)); } else { crNetSend( render_spu.swap_conns[0], NULL, &out, sizeof(CRMessage)); crNetGetMessage( render_spu.swap_conns[0], &in ); crNetFree( render_spu.swap_conns[0], in); } }
void REPLICATESPU_APIENTRY replicatespu_End( void ) { GET_THREAD(thread); CRPackBuffer *buf = &thread->BeginEndBuffer; if ( thread->server.conn->Barf && (thread->BeginEndMode == GL_LINES || thread->BeginEndMode == GL_TRIANGLES || thread->BeginEndMode == GL_QUADS || thread->BeginEndMode == GL_POLYGON ) ) { CRASSERT(buf->pack); crPackReleaseBuffer( thread->packer ); crPackSetBuffer( thread->packer, &thread->normBuffer ); if ( !crPackCanHoldBuffer( buf ) ) replicatespuFlush( (void *) thread ); crPackAppendBuffer( buf ); crNetFree( thread->server.conn, buf->pack ); buf->pack = NULL; } if (thread->currentContext->displayListMode != GL_FALSE) { crDLMCompileEnd(); } if (replicate_spu.swap) { crPackEndSWAP(); } else { crPackEnd(); } }
/* * Send a Chromium opcode buffer across the given net connection. * size - size of opcode buffer in bytes. * exitFlag - if true, send 'exit' code to server. */ static void SendOpcodes(CRConnection *conn, int size, int exitFlag) { char *buffer, *firstCode; CRMessageOpcodes *msg; if (size <= MTU) { buffer = crNetAlloc(conn); msg = (CRMessageOpcodes *) buffer; msg->header.type = CR_MESSAGE_OPCODES; msg->numOpcodes = size; firstCode = buffer + sizeof(CRMessageOpcodes); if (exitFlag) *firstCode = 42; else *firstCode = 99; crNetSend(conn, NULL, buffer, MTU); crNetFree(conn, buffer); } else { /* send "huge" buffer */ const int totalSize = size + 8 + sizeof(CRMessageOpcodes); unsigned int *uiptr; buffer = crAlloc(totalSize); msg = (CRMessageOpcodes *) buffer; msg->header.type = CR_MESSAGE_OPCODES; msg->numOpcodes = 1; uiptr = (unsigned int *) (buffer + sizeof(CRMessageOpcodes) + 4); uiptr[0] = size; firstCode = buffer + sizeof(CRMessageOpcodes); if (exitFlag) *firstCode = 42; else *firstCode = 99; crNetSend(conn, NULL, buffer, size); crFree(buffer); } }
/** * 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; } }
/** * This is the guts of the binaryswap operation. Here, we call glReadPixels * to read a region of the color and depth buffers from the parent (render * SPU) window. We then begin the process of composition using binary swap. * Each node does a glReadPixels and sends its swap region to its swap * partner. Once we receive our partner's frame region, we use draw pixels to * composite against our frame. This repeats for all swap partners. Once we * have all of the regions composited against the one we are responsible for, * we issue another read and send our region to final display by glDrawPixels * (and some other GL functions) on the child/downstream SPU to send our region * to the final display node. * Input: window - the window we're processing * startx, starty - glReadPixels start coordinates * endx, endy - glReadPixels ending coordinates */ static void CompositeNode(WindowInfo * window, int startx, int starty, int endx, int endy) { int i = 0; int read_start_x = 0, read_start_y = 0; int read_width = 0, read_height = 0; CRMessage *incoming_msg = NULL; GLubyte *incoming_color = NULL; GLuint *incoming_depth = NULL; BinarySwapMsg *render_info = NULL; int draw_x = 0, draw_y = 0; int draw_width = 0, draw_height = 0; float other_depth = 0.0; int recalc_end_x = 0, recalc_end_y = 0; int recalc_start_x = 0, recalc_start_y = 0; int recalc_temp; CRASSERT(window->width > 0); CRASSERT(window->height > 0); /* figure out our portion for each stage */ for (i = 0; i < binaryswap_spu.stages; i++) { BinarySwapMsg *msg = (BinarySwapMsg *) window->msgBuffer; /* set up message header */ msg->start_x = window->read_x[i]; msg->start_y = window->read_y[i]; msg->width = window->read_width[i]; msg->height = window->read_height[i]; msg->depth = binaryswap_spu.depth; if (startx < window->read_x[i]) msg->clipped_x = window->read_x[i]; else msg->clipped_x = startx; if (starty < window->read_y[i]) msg->clipped_y = window->read_y[i]; else msg->clipped_y = starty; if (endx > (window->read_x[i] + window->read_width[i])) msg->clipped_width = (window->read_x[i] + window->read_width[i]) - msg->clipped_x; else msg->clipped_width = endx - msg->clipped_x; if (endy > (window->read_y[i] + window->read_height[i])) msg->clipped_height = (window->read_y[i] + window->read_height[i]) - msg->clipped_y; else msg->clipped_height = endy - msg->clipped_y; if (msg->clipped_width < 0) msg->clipped_width = 0; if (msg->clipped_height < 0) msg->clipped_height = 0; read_start_x = msg->clipped_x; read_start_y = msg->clipped_y; read_width = msg->clipped_width; read_height = msg->clipped_height; /* read our portion for this pass */ /* figure out which mode to use, depth or alpha */ if (binaryswap_spu.alpha_composite) { if (read_width > 0 && read_height > 0) binaryswap_spu.super.ReadPixels(read_start_x, read_start_y, read_width, read_height, GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte *) window->msgBuffer + binaryswap_spu.offset); if (binaryswap_spu.highlow[i]) { /* lower of pair => recv,send */ crNetGetMessage(binaryswap_spu.peer_recv[i], &incoming_msg); crNetSend(binaryswap_spu.peer_send[i], NULL, window->msgBuffer, (read_width * read_height * 4) + binaryswap_spu.offset); } else { /* higher of pair => send,recv */ crNetSend(binaryswap_spu.peer_send[i], NULL, window->msgBuffer, (read_width * read_height * 4) + binaryswap_spu.offset); crNetGetMessage(binaryswap_spu.peer_recv[i], &incoming_msg); } if (binaryswap_spu.mtu > binaryswap_spu.peer_send[i]->mtu) binaryswap_spu.mtu = binaryswap_spu.peer_send[i]->mtu; /* get render info from other node */ render_info = (BinarySwapMsg *) incoming_msg; draw_x = render_info->clipped_x; draw_y = render_info->clipped_y; draw_width = render_info->clipped_width; draw_height = render_info->clipped_height; other_depth = render_info->depth; if (draw_width > 0 && draw_height > 0) { /* get incoming fb */ incoming_color = (GLubyte *) ((GLubyte *) incoming_msg + binaryswap_spu.offset); /* figure out blend function based on z */ binaryswap_spu.super.Enable(GL_BLEND); /* Other image is on top of ours! */ if (binaryswap_spu.depth > other_depth) { /* over operator */ binaryswap_spu.super.BlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); binaryswap_spu.super.WindowPos2iARB(draw_x, draw_y); binaryswap_spu.super.DrawPixels(draw_width, draw_height, GL_RGBA, GL_UNSIGNED_BYTE, incoming_color); } /* other image is under ours */ else if(binaryswap_spu.depth < other_depth) { /* under operator */ binaryswap_spu.super.BlendFuncSeparateEXT(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE); binaryswap_spu.super.WindowPos2iARB(draw_x, draw_y); binaryswap_spu.super.DrawPixels(draw_width, draw_height, GL_RGBA, GL_UNSIGNED_BYTE, incoming_color); } else { if(binaryswap_spu.highlow[i]) { /* over operator */ binaryswap_spu.super.BlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); binaryswap_spu.super.WindowPos2iARB(draw_x, draw_y); binaryswap_spu.super.DrawPixels(draw_width, draw_height, GL_RGBA, GL_UNSIGNED_BYTE, incoming_color); } else { /* under operator */ binaryswap_spu.super.BlendFuncSeparateEXT(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE); binaryswap_spu.super.WindowPos2iARB(draw_x, draw_y); binaryswap_spu.super.DrawPixels(draw_width, draw_height, GL_RGBA, GL_UNSIGNED_BYTE, incoming_color); } } if (binaryswap_spu.depth > other_depth) { binaryswap_spu.depth = other_depth; } } } else { /* depth composite */ if (read_width > 0 && read_height > 0) { GLubyte *colors = (GLubyte *) window->msgBuffer + binaryswap_spu.offset; GLuint *depths = (GLuint *) ((GLubyte *) window->msgBuffer + /* base address */ (read_width * read_height * 3) + /* color information */ binaryswap_spu.offset); /* message header */ binaryswap_spu.super.ReadPixels(read_start_x, read_start_y, read_width, read_height, GL_RGB, GL_UNSIGNED_BYTE, colors); binaryswap_spu.super.ReadPixels(read_start_x, read_start_y, read_width, read_height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, depths); } if (binaryswap_spu.highlow[i]) { /* lower of pair => recv,send */ crNetGetMessage(binaryswap_spu.peer_recv[i], &incoming_msg); crNetSend(binaryswap_spu.peer_send[i], NULL, window->msgBuffer, read_width * read_height * (3 + 4) + binaryswap_spu.offset); } else { /* higher of pair => send,recv */ crNetSend(binaryswap_spu.peer_send[i], NULL, window->msgBuffer, read_width * read_height * (3 + 4) + binaryswap_spu.offset); crNetGetMessage(binaryswap_spu.peer_recv[i], &incoming_msg); } if (binaryswap_spu.mtu > binaryswap_spu.peer_send[i]->mtu) binaryswap_spu.mtu = binaryswap_spu.peer_send[i]->mtu; /* get render info from other node */ render_info = (BinarySwapMsg *) incoming_msg; draw_x = render_info->clipped_x; draw_y = render_info->clipped_y; draw_width = render_info->clipped_width; draw_height = render_info->clipped_height; if (draw_width > 0 && draw_height > 0) { /* get incoming fb */ incoming_color = (GLubyte *) ((GLubyte *) incoming_msg + binaryswap_spu.offset); incoming_depth = (GLuint *) (incoming_color + draw_width * draw_height * 3); binaryswap_spu.super.WindowPos2iARB(draw_x, draw_y); /* Draw the depth image into the depth buffer, setting the stencil * to one wherever we pass the Z test, clearinging to zero where * we fail. */ binaryswap_spu.super.ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); binaryswap_spu.super.StencilOp(GL_KEEP, GL_ZERO, GL_REPLACE); binaryswap_spu.super.StencilFunc(GL_ALWAYS, 1, ~0); binaryswap_spu.super.Enable(GL_STENCIL_TEST); binaryswap_spu.super.Enable(GL_DEPTH_TEST); binaryswap_spu.super.DepthFunc(GL_LEQUAL); binaryswap_spu.super.DrawPixels(draw_width, draw_height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, incoming_depth); /* Now draw the RGBA image, only where the stencil is one, reset * stencil to zero as we go * (to avoid calling glClear(STENCIL_BUFFER_BIT)). */ binaryswap_spu.super.Disable(GL_DEPTH_TEST); binaryswap_spu.super.StencilOp(GL_ZERO, GL_ZERO, GL_ZERO); binaryswap_spu.super.StencilFunc(GL_EQUAL, 1, ~0); binaryswap_spu.super.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); binaryswap_spu.super.DrawPixels(draw_width, draw_height, GL_RGB, GL_UNSIGNED_BYTE, incoming_color); binaryswap_spu.super.Disable(GL_STENCIL_TEST); } } /* make sure everything got drawn for next pass */ binaryswap_spu.super.Flush(); /* find optimal starting point for readback based on this node's region and the partner's region */ recalc_start_x = render_info->start_x; if (startx < render_info->clipped_x) { recalc_temp = startx; } else { recalc_temp = render_info->clipped_x; if (render_info->clipped_width > 0 && render_info->clipped_height > 0) startx = recalc_temp; } if (recalc_temp > recalc_start_x) { recalc_start_x = recalc_temp; } recalc_start_y = render_info->start_y; if (starty < render_info->clipped_y) { recalc_temp = starty; } else { recalc_temp = render_info->clipped_y; if (render_info->clipped_width > 0 && render_info->clipped_height > 0) starty = recalc_temp; } if (recalc_temp > recalc_start_y) { recalc_start_y = recalc_temp; } /* find optimal ending point for readback based on * this node's region and the partner's region */ recalc_end_x = render_info->start_x + render_info->width; if (endx > (render_info->clipped_x + render_info->clipped_width)) { recalc_temp = endx; } else { recalc_temp = (render_info->clipped_x + render_info->clipped_width); if (render_info->clipped_width > 0 && render_info->clipped_height > 0) endx = recalc_temp; } if (recalc_end_x > recalc_temp) { recalc_end_x = recalc_temp; } recalc_end_y = render_info->start_y + render_info->height; if (endy > (render_info->clipped_y + render_info->clipped_height)) { recalc_temp = endy; } else { recalc_temp = (render_info->clipped_y + render_info->clipped_height); if (render_info->clipped_width > 0 && render_info->clipped_height > 0) endy = recalc_temp; } if (recalc_end_y > recalc_temp) { recalc_end_y = recalc_temp; } /* clean up the memory allocated for the recv */ crNetFree(binaryswap_spu.peer_recv[i], incoming_msg); } draw_x = recalc_start_x; draw_y = recalc_start_y; draw_width = recalc_end_x - recalc_start_x; draw_height = recalc_end_y - recalc_start_y; if (draw_width > 0 && draw_height > 0) { /* send our final portion off to child */ binaryswap_spu.super.ReadPixels(draw_x, draw_y, draw_width, draw_height, GL_RGB, GL_UNSIGNED_BYTE, window->msgBuffer + binaryswap_spu.offset); /* * Set the downstream viewport. If we don't do this, and the * downstream window is resized, the glRasterPos command doesn't * seem to be reliable. This is a problem both with Mesa and the * NVIDIA drivers. Technically, this may not be a driver bug at * all since we're doing funny stuff. Anyway, this fixes the problem. * Note that the width and height are arbitrary since we only care * about getting the origin right. glDrawPixels, glClear, etc don't * care what the viewport size is. (BrianP) */ CRASSERT(window->width > 0); CRASSERT(window->height > 0); /* Begin critical region */ binaryswap_spu.child.SemaphorePCR(MUTEX_SEMAPHORE); /* Update child window position, in case we're using the windowtracker * and VNC SPUs. */ { GLint pos[2]; binaryswap_spu.child.GetChromiumParametervCR(GL_WINDOW_POSITION_CR, window->childWindow, GL_INT, 2, pos); if (pos[0] != window->child_xpos || pos[1] != window->child_ypos) { binaryswap_spu.child.WindowPosition(window->childWindow, pos[0], pos[1]); window->child_xpos = pos[0]; window->child_ypos = pos[1]; } } binaryswap_spu.child.WindowPos2iARB(draw_x, draw_y); binaryswap_spu.child.DrawPixels(draw_width, draw_height, GL_RGB, GL_UNSIGNED_BYTE, window->msgBuffer + binaryswap_spu.offset); /* end critical region */ binaryswap_spu.child.SemaphoreVCR(MUTEX_SEMAPHORE); } }