diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index e84dcdb6..a4dcc866 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -2094,7 +2094,9 @@ libxrdp_process_monitor_stream(struct stream *s, } } - /* set wm geometry if the encompassing area is well formed. Otherwise, log and return an error.*/ + /* set wm geometry if the encompassing area is well formed. + Otherwise, log and return an error. + */ if (all_monitors_encompassing_bounds.right > all_monitors_encompassing_bounds.left && all_monitors_encompassing_bounds.bottom @@ -2270,3 +2272,15 @@ libxrdp_process_monitor_ex_stream(struct stream *s, return 0; } +/*****************************************************************************/ +int EXPORT_CC +libxrdp_planar_compress(char *in_data, int width, int height, + struct stream *s, int bpp, int byte_limit, + int start_line, struct stream *temp_s, + int e, int flags) +{ + return xrdp_bitmap32_compress(in_data, width, height, + s, bpp, byte_limit, + start_line, temp_s, + e, flags); +} diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index 51569b9f..5e8ad869 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -308,7 +308,11 @@ libxrdp_fastpath_send_frame_marker(struct xrdp_session *session, int EXPORT_CC libxrdp_send_session_info(struct xrdp_session *session, const char *data, int data_bytes); - +int EXPORT_CC +libxrdp_planar_compress(char *in_data, int width, int height, + struct stream *s, int bpp, int byte_limit, + int start_line, struct stream *temp_s, + int e, int flags); /** * Processes a stream that is based on either * 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR) or 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 77b2bce1..004add1c 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -469,6 +469,10 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self); int xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id); int +xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, + struct xrdp_bitmap *bitmap, + struct xrdp_rect *rect); +int server_begin_update(struct xrdp_mod *mod); int server_end_update(struct xrdp_mod *mod); diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 9644c8ec..18dbb8c5 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -34,6 +34,7 @@ #include "xrdp_encoder.h" #include "xrdp_sockets.h" +#include "xrdp_egfx.h" #include @@ -944,6 +945,140 @@ xrdp_mm_process_rail_drawing_orders(struct xrdp_mm *self, struct stream *s) return rv; } +#define GFX_PLANAR_BYTES (32 * 1024) + +/******************************************************************************/ +int +xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, + struct xrdp_bitmap *bitmap, + struct xrdp_rect *rect) +{ + struct xrdp_egfx_rect gfx_rect; + struct stream *comp_s; + struct stream *temp_s; + char *pixels; + char *src8; + char *dst8; + int index; + int lines; + int comp_bytes; + int xindex; + int yindex; + int bwidth; + int bheight; + int cx; + int cy; + + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap:"); + bwidth = rect->right - rect->left; + bheight = rect->bottom - rect->top; + if ((bwidth < 1) || (bheight < 1)) + { + return 0; + } + if (bwidth < 64) + { + cx = bwidth; + cy = 4096 / cx; + } + else if (bheight < 64) + { + cy = bheight; + cx = 4096 / cy; + } + else + { + cx = 64; + cy = 64; + } + while (cx * cy < 4096) + { + if (cx < cy) + { + cx++; + cy = 4096 / cx; + } + else + { + cy++; + cx = 4096 / cy; + } + } + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: cx %d cy %d", cx, cy); + pixels = g_new(char, GFX_PLANAR_BYTES); + make_stream(comp_s); + init_stream(comp_s, GFX_PLANAR_BYTES); + make_stream(temp_s); + init_stream(temp_s, GFX_PLANAR_BYTES); + if (xrdp_egfx_send_frame_start(self->egfx, 1, 0) != 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " + "xrdp_egfx_send_frame_start error"); + } + + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: left %d top %d right %d " + "bottom %d", rect->left, rect->top, rect->right, rect->bottom); + for (yindex = rect->top; yindex < rect->bottom; yindex += cy) + { + bheight = rect->bottom - yindex; + bheight = MIN(bheight, cy); + for (xindex = rect->left; xindex < rect->right; xindex += cx) + { + bwidth = rect->right - xindex; + bwidth = MIN(bwidth, cx); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: xindex %d " + "yindex %d, bwidth %d bheight %d", + xindex, yindex, bwidth, bheight); + src8 = bitmap->data + bitmap->line_size * yindex + xindex * 4; + dst8 = pixels + (bheight - 1) * bwidth * 4; + for (index = 0; index < bheight; index++) + { + g_memcpy(dst8, src8, bwidth * 4); + src8 += bitmap->line_size; + dst8 -= bwidth * 4; + } + lines = libxrdp_planar_compress(pixels, bwidth, bheight, comp_s, + 32, GFX_PLANAR_BYTES, bheight - 1, + temp_s, 0, 0x10); + comp_s->end = comp_s->p; + comp_s->p = comp_s->data; + if (lines != bheight) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " + "lines(%d) != bheight(%d) error", lines, bheight); + } + else + { + comp_bytes = (int)(comp_s->end - comp_s->data); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: lines %d " + "comp_bytes %d", lines, comp_bytes); + gfx_rect.x1 = xindex; + gfx_rect.y1 = yindex; + gfx_rect.x2 = xindex + bwidth; + gfx_rect.y2 = yindex + bheight; + if (xrdp_egfx_send_wire_to_surface1(self->egfx, self->egfx->surface_id, + XR_RDPGFX_CODECID_PLANAR, + XR_PIXEL_FORMAT_XRGB_8888, + &gfx_rect, comp_s->data, + comp_bytes) != 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " + "xrdp_egfx_send_wire_to_surface1 error"); + } + } + } + } + if (xrdp_egfx_send_frame_end(self->egfx, 1) != 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " + "xrdp_egfx_send_frame_end error"); + } + g_free(pixels); + free_stream(comp_s); + free_stream(temp_s); + return 0; +} + /******************************************************************************/ static int dynamic_monitor_open_response(intptr_t id, int chan_id, int creation_status) @@ -2789,6 +2924,8 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) int cx; int cy; + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_process_enc_done:"); + while (1) { tc_mutex_lock(self->encoder->mutex); @@ -2918,6 +3055,37 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self) xrdp_mm_process_enc_done(self); } } + + if (self->wm->screen_dirty_region != NULL) + { + if (xrdp_region_not_empty(self->wm->screen_dirty_region)) + { + int error; + struct xrdp_rect rect; + int now = g_time3(); + int diff = now - self->wm->last_screen_draw_time; + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_check_wait_objs: not empty diff %d", diff); + if ((diff < 0) || (diff >= 40)) + { + if (self->egfx_up) + { + error = xrdp_region_get_bounds(self->wm->screen_dirty_region, &rect); + if (error == 0) + { + xrdp_mm_egfx_send_planar_bitmap(self, self->wm->screen, &rect); + } + xrdp_region_delete(self->wm->screen_dirty_region); + self->wm->screen_dirty_region = NULL; + self->wm->last_screen_draw_time = now; + } + else + { + LOG(LOG_LEVEL_TRACE, "xrdp_mm_check_wait_objs: egfx is not up"); + } + } + } + } + return rv; } diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index c684052c..a1ced8c2 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -392,6 +392,7 @@ struct xrdp_mm int xr2cr_cid_map[256]; int dynamic_monitor_chanid; struct xrdp_egfx *egfx; + int egfx_up; /* Resize on-the-fly control */ struct display_control_monitor_layout_data *resize_data; @@ -519,6 +520,9 @@ struct xrdp_wm /* configuration derived from xrdp.ini */ struct xrdp_config *xrdp_config; + + struct xrdp_region *screen_dirty_region; + int last_screen_draw_time; }; /* rdp process */ diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index dc546220..858059fa 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -81,6 +81,7 @@ xrdp_wm_delete(struct xrdp_wm *self) return; } + xrdp_region_delete(self->screen_dirty_region); xrdp_mm_delete(self->mm); xrdp_cache_delete(self->cache); xrdp_painter_delete(self->painter);