void aio_write(AIO_FUNCPTR fn, void *outbuf, int bytes_to_write) { AIO_BLOCK *block; /* FIXME: Join small blocks together? */ /* FIXME: Support small static buffer as in reading? */ block = malloc(sizeof(AIO_BLOCK) + bytes_to_write); if (block != NULL) { block->data_size = bytes_to_write; memcpy(block->data, outbuf, bytes_to_write); aio_write_nocopy(fn, block); } }
static void send_update(void) { CL_SLOT *cl = (CL_SLOT *)cur_slot; BoxRec fb_rect; RegionRec fb_region, clip_region, outer_region; CARD8 msg_hdr[4] = { 0, 0, 0, 1 }; CARD8 rect_hdr[12]; int num_copy_rects, num_pending_rects, num_all_rects; int raw_bytes = 0, hextile_bytes = 0; int i, idx, rev_order; static int counter = 0; #ifdef NETLOGGER aio_set_serial_number(&cl->s, cl->serial_number); #endif counter++; vncspuLog(1, "Begin send update %d", counter); CRASSERT(vnc_spu.serverBuffer); /*crDebug("Enter send_update to %s", cur_slot->name);*/ /* check if clipping has changed since we got the pixels and update * the pending region if needed. */ if (NewClip) { /*crDebug("Getting updated cliprects");*/ vncspuGetScreenRects(&cl->pending_region); num_pending_rects = REGION_NUM_RECTS(&cl->pending_region); /*crDebug("Now, %d rects", num_pending_rects);*/ if (num_pending_rects == 0 && cl->enable_frame_sync) { /* always need to send _something_ for framesync to work */ BoxRec b; b.x1 = 0; b.y1 = 0; b.x2 = 1; b.y2 = 1; REGION_UNINIT(&cl->pending_region); REGION_INIT(&cl->pending_region, &b, 1); } NewClip = 0; } /*PrintRegion("Sending", &cl->pending_region);*/ /* Process framebuffer size change. */ if (cl->newfbsize_pending) { /* Update framebuffer size, clear newfbsize_pending flag. */ cl->fb_width = g_screen_info.width; cl->fb_height = g_screen_info.height; cl->newfbsize_pending = 0; log_write(LL_DEBUG, "Applying new framebuffer size (%dx%d) to %s", (int)cl->fb_width, (int)cl->fb_height, cur_slot->name); /* In any case, mark all the framebuffer contents as changed. */ fb_rect.x1 = 0; fb_rect.y1 = 0; fb_rect.x2 = cl->fb_width; fb_rect.y2 = cl->fb_height; REGION_INIT(&fb_region, &fb_rect, 1); REGION_COPY(&cl->pending_region, &fb_region); REGION_UNINIT(&fb_region); REGION_EMPTY(&cl->copy_region); /* If NewFBSize is supported by the client, send only NewFBSize pseudo-rectangle, pixel data will be sent in the next update. */ if (cl->enable_newfbsize) { send_newfbsize(); vncspuUnlockFrameBuffer(); return; } } else { /* Exclude CopyRect areas covered by pending_region. */ REGION_SUBTRACT(&cl->copy_region, &cl->copy_region, &cl->pending_region); } #if 00 if (cl->enable_cliprects_enc && cl->new_cliprects) { send_new_cliprects(); vncspuUnlockFrameBuffer(); cl->new_cliprects = 0; return; } #endif /* Clip regions to the rectangle requested by the client. */ REGION_INIT(&clip_region, &cl->update_rect, 1); REGION_INTERSECT(&cl->pending_region, &cl->pending_region, &clip_region); if (REGION_NOTEMPTY(&cl->copy_region)) { REGION_INTERSECT(&cl->copy_region, &cl->copy_region, &clip_region); REGION_INIT(&outer_region, NullBox, 8); REGION_COPY(&outer_region, &cl->copy_region); REGION_TRANSLATE(&clip_region, cl->copy_dx, cl->copy_dy); REGION_INTERSECT(&cl->copy_region, &cl->copy_region, &clip_region); REGION_SUBTRACT(&outer_region, &outer_region, &cl->copy_region); REGION_UNION(&cl->pending_region, &cl->pending_region, &outer_region); REGION_UNINIT(&outer_region); } REGION_UNINIT(&clip_region); /* Reduce the number of rectangles if possible. */ if (cl->enc_prefer == RFB_ENCODING_TIGHT && cl->enable_lastrect) { region_pack(&cl->pending_region, 32); } else { region_pack(&cl->pending_region, 12); } /* Compute the number of rectangles in regions. */ num_pending_rects = REGION_NUM_RECTS(&cl->pending_region); num_copy_rects = REGION_NUM_RECTS(&cl->copy_region); num_all_rects = num_pending_rects + num_copy_rects; if (num_all_rects == 0) { vncspuUnlockFrameBuffer(); return; } log_write(LL_DEBUG, "Sending framebuffer update (min %d rects) to %s", num_all_rects, cur_slot->name); /* Prepare and send FramebufferUpdate message header. */ /* FIXME: Enable Tight encoding even if LastRect is not supported. */ /* FIXME: Do not send LastRect if all the rectangles are CopyRect. */ if (cl->enc_prefer == RFB_ENCODING_TIGHT && cl->enable_lastrect) { buf_put_CARD16(&msg_hdr[2], 0xFFFF); } else { buf_put_CARD16(&msg_hdr[2], num_all_rects); } aio_write(NULL, msg_hdr, 4); /* Determine the order in which CopyRect rectangles should be sent. */ rev_order = (cl->copy_dy > 0 || (cl->copy_dy == 0 && cl->copy_dx > 0)); /* For each CopyRect rectangle: */ for (i = 0; i < num_copy_rects; i++) { FB_RECT rect; AIO_BLOCK *block; idx = (rev_order) ? num_copy_rects - i - 1 : i; rect.x = REGION_RECTS(&cl->copy_region)[idx].x1; rect.y = REGION_RECTS(&cl->copy_region)[idx].y1; rect.w = REGION_RECTS(&cl->copy_region)[idx].x2 - rect.x; rect.h = REGION_RECTS(&cl->copy_region)[idx].y2 - rect.y; rect.src_x = rect.x - cl->copy_dx; rect.src_y = rect.y - cl->copy_dy; rect.enc = RFB_ENCODING_COPYRECT; log_write(LL_DEBUG, "Sending CopyRect rectangle %dx%d at %d,%d to %s", (int)rect.w, (int)rect.h, (int)rect.x, (int)rect.y, cur_slot->name); /* Prepare the CopyRect rectangle. */ block = rfb_encode_copyrect_block(cl, &rect); /* Send the rectangle. FIXME: Check for block == NULL? */ aio_write_nocopy(NULL, block); } if (cl->enc_prefer == RFB_ENCODING_TIGHT) { /* needed for successful caching of zlib-compressed data (tight) */ rfb_reset_tight_encoder(cl); } if (num_pending_rects) { /* Lock around fb access so other thread doesn't change contents while * we're encoding. */ #ifdef NETLOGGER if (vnc_spu.netlogger_url) { NL_info("vncspu", "spu.encode.begin", "NODE=s NUMBER=i", vnc_spu.hostname, cl->serial_number); } #endif /* For each of the usual pending rectangles: */ for (i = 0; i < num_pending_rects; i++) { FB_RECT rect; AIO_BLOCK *block; /* crDebug("sending rect %d of %d: %d, %d .. %d, %d", i, num_pending_rects, REGION_RECTS(&cl->pending_region)[i].x1, REGION_RECTS(&cl->pending_region)[i].y1, REGION_RECTS(&cl->pending_region)[i].x2, REGION_RECTS(&cl->pending_region)[i].y2); */ rect.x = REGION_RECTS(&cl->pending_region)[i].x1; rect.y = REGION_RECTS(&cl->pending_region)[i].y1; rect.w = REGION_RECTS(&cl->pending_region)[i].x2 - rect.x; rect.h = REGION_RECTS(&cl->pending_region)[i].y2 - rect.y; log_write(LL_DEBUG, "Sending rectangle %dx%d at %d,%d to %s enc 0x%x", (int)rect.w, (int)rect.h, (int)rect.x, (int)rect.y, cur_slot->name, cl->enc_prefer); if (cl->enc_prefer == RFB_ENCODING_TIGHT && cl->enable_lastrect) { /* Use Tight encoding */ rect.enc = RFB_ENCODING_TIGHT; /* lock to prevent glReadPixels in other thread changing data */ rfb_encode_tight(cl, &rect); continue; /* Important! */ } else if (cl->enc_prefer == RFB_ENCODING_RAW24) { rect.enc = RFB_ENCODING_RAW24; block = rfb_encode_raw24_block(cl, &rect); } else if ( cl->enc_prefer != RFB_ENCODING_RAW && cl->enc_enable[RFB_ENCODING_HEXTILE] ) { /* Use Hextile encoding */ rect.enc = RFB_ENCODING_HEXTILE; block = rfb_encode_hextile_block(cl, &rect); if (block != NULL) { hextile_bytes += block->data_size; raw_bytes += rect.w * rect.h * (cl->format.bits_pixel / 8); } } else { /* Use Raw encoding */ rect.enc = RFB_ENCODING_RAW; if (vnc_spu.half_rez) { block = rfb_encode_raw_block_halfrez(cl, &rect); } else { block = rfb_encode_raw_block(cl, &rect); } } /* Send the rectangle. FIXME: Check for block == NULL? */ aio_write_nocopy(NULL, block); } } /* if num_pending_rects */ REGION_EMPTY(&cl->pending_region); REGION_EMPTY(&cl->copy_region); /* Send LastRect marker. */ if (cl->enc_prefer == RFB_ENCODING_TIGHT && cl->enable_lastrect) { FB_RECT rect; rect.x = rect.y = rect.w = rect.h = 0; rect.enc = RFB_ENCODING_LASTRECT; put_rect_header(rect_hdr, &rect); aio_write(NULL, rect_hdr, 12); } /* Set the last block's callback function */ /* All prev blocks had NULL callbacks */ assert(cur_slot->outqueue_last); if (cur_slot->outqueue_last) { cur_slot->outqueue_last->func = wf_client_update_finished; } /* Something has been queued for sending. */ cl->update_in_progress = 1; cl->update_requested = 0; #ifdef NETLOGGER if (vnc_spu.netlogger_url) { NL_info("vncspu", "spu.encode.end", "NODE=s NUMBER=i", vnc_spu.hostname, cl->serial_number); } aio_set_serial_number(&cl->s, 0); #endif vncspuUnlockFrameBuffer(); /* encoder done with buffer */ /*crDebug("Leave send_update");*/ vncspuLog(1, "End send update %d", counter); }