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