static void send_new_cliprects(void) { CL_SLOT *cl = (CL_SLOT *)cur_slot; CARD8 msg_hdr[4] = { 0, 0, 0, 1 }; CARD8 rect_hdr[12]; FB_RECT rect; crDebug("Sending new cliprects to proxy: %d, %d .. %d, %d", cl->new_clip_bounds.x1, cl->new_clip_bounds.y1, cl->new_clip_bounds.x2, cl->new_clip_bounds.y2); log_write(LL_DEBUG, "Sending NewCliprects (%dx%d) to %s", (int)cl->fb_width, (int)cl->fb_height, cur_slot->name); buf_put_CARD16(&msg_hdr[2], 1); /* one rect */ aio_write(NULL, msg_hdr, 4); rect.x = cl->new_clip_bounds.x1; rect.y = cl->new_clip_bounds.y1; rect.w = cl->new_clip_bounds.x2 - cl->new_clip_bounds.x1; rect.h = cl->new_clip_bounds.y2 - cl->new_clip_bounds.y1; rect.enc = RFB_ENCODING_CLIPRECTS; put_rect_header(rect_hdr, &rect); aio_write(wf_client_update_finished, rect_hdr, 12); /* Something has been queued for sending. */ cl->update_in_progress = 1; cl->update_requested = 0; }
static void send_newfbsize(void) { CL_SLOT *cl = (CL_SLOT *)cur_slot; CARD8 msg_hdr[4] = { 0, 0, 0, 1 }; CARD8 rect_hdr[12]; FB_RECT rect; log_write(LL_DEBUG, "Sending NewFBSize update (%dx%d) to %s", (int)cl->fb_width, (int)cl->fb_height, cur_slot->name); buf_put_CARD16(&msg_hdr[2], 1); aio_write(NULL, msg_hdr, 4); rect.x = 0; rect.y = 0; rect.w = cl->fb_width; rect.h = cl->fb_height; rect.enc = RFB_ENCODING_NEWFBSIZE; put_rect_header(rect_hdr, &rect); aio_write(wf_client_update_finished, rect_hdr, 12); /* Something has been queued for sending. */ cl->update_in_progress = 1; cl->update_requested = 0; }
AIO_BLOCK *rfb_encode_hextile_block(CL_SLOT *cl, FB_RECT *r) { AIO_BLOCK *block; int num_tiles; int aligned_f; int rx1, ry1; FB_RECT tile_r; CARD8 *data_ptr; /* Calculate number of tiles per this rectangle */ num_tiles = ((r->w + 15) / 16) * ((r->h + 15) / 16); /* Check if tiles are aligned on 16-pixel boundary */ aligned_f = (r->x & 0x0F) == 0 && (r->y & 0x0F) == 0; /* Allocate a memory block of maximum possible size */ block = malloc(sizeof(AIO_BLOCK) + 12 + r->w * r->h * (cl->format.bits_pixel / 8) + num_tiles); if (block == NULL) return NULL; put_rect_header(block->data, r); prev_bg_set = 0; data_ptr = (CARD8 *)&block->data[12]; rx1 = r->x + r->w; ry1 = r->y + r->h; tile_r.h = 16; for (tile_r.y = r->y; tile_r.y < ry1; tile_r.y += 16) { if (ry1 - tile_r.y < 16) tile_r.h = ry1 - tile_r.y; tile_r.w = 16; for (tile_r.x = r->x; tile_r.x < rx1; tile_r.x += 16) { if (rx1 - tile_r.x < 16) tile_r.w = rx1 - tile_r.x; switch (cl->format.bits_pixel) { case 8: /* 8-bit color: to cache or not to cache? */ if (aligned_f && cl->bgr233_f && tile_r.w == 16 && tile_r.h == 16) data_ptr += encode_tile_using_cache(data_ptr, cl, &tile_r); else data_ptr += encode_tile8(data_ptr, cl, &tile_r); break; case 16: data_ptr += encode_tile16(data_ptr, cl, &tile_r); break; case 32: data_ptr += encode_tile32(data_ptr, cl, &tile_r); break; } } } block->data_size = data_ptr - (CARD8 *)block->data; return realloc(block, sizeof(AIO_BLOCK) + block->data_size); }
AIO_BLOCK *rfb_encode_copyrect_block(CL_SLOT *cl, FB_RECT *r) { AIO_BLOCK *block; block = malloc(sizeof(AIO_BLOCK) + 12 + 4); if (block) { put_rect_header(block->data, r); buf_put_CARD16(&block->data[12], r->src_x); buf_put_CARD16(&block->data[14], r->src_y); block->data_size = 12 + 4; } return block; }
AIO_BLOCK *rfb_encode_raw_block(CL_SLOT *cl, FB_RECT *r) { AIO_BLOCK *block; block = malloc(sizeof(AIO_BLOCK) + 12 + r->w * r->h * (cl->format.bits_pixel / 8)); if (block) { put_rect_header(block->data, r); (*cl->trans_func)(&block->data[12], r, cl->trans_table); block->data_size = 12 + r->w * r->h * (cl->format.bits_pixel / 8); } return 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); }