From 0983aa066ba2f147b83525ca19d4264456ef5c13 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Sun, 24 Dec 2023 15:35:28 -0500 Subject: [PATCH] More integration work from mainline_merge_shm - Introduce functional EGFX caps. - Prototype of RFX Progressive working. - Update resizing to work with it. - Refactoring --- common/xrdp_client_info.h | 3 +- xrdp/xrdp.h | 3 +- xrdp/xrdp_encoder.c | 32 +- xrdp/xrdp_mm.c | 635 ++++++++++++++++++++++++++++++++------ xrdp/xrdp_types.h | 14 +- xup/xup.c | 171 +++++----- 6 files changed, 658 insertions(+), 200 deletions(-) diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index a588f16c56..ad5012bb77 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -222,7 +222,8 @@ enum xrdp_encoder_flags { NONE = 0, ENCODE_COMPLETE = 1 << 0, - GFX_PROGRESSIVE_RFX = 1 << 1 + GFX_PROGRESSIVE_RFX = 1 << 1, + GFX_H264 = 1 << 2 }; /* yyyymmdd of last incompatible change to xrdp_client_info */ diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 0db9f35bf9..ba281fa002 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -543,7 +543,8 @@ server_set_pointer_large(struct xrdp_mod *mod, int x, int y, char *data, char *mask, int bpp, int width, int height); int -server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, +server_paint_rects_ex(struct xrdp_mod *mod, + int num_drects, short *drects, int num_crects, short *crects, char *data, int left, int top, int width, int height, diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index 8c3d9d0b17..f7a08674b5 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -33,6 +33,7 @@ #endif #define XRDP_SURCMD_PREFIX_BYTES 256 +#define OUT_DATA_BYTES_DEFAULT_SIZE (16 * 1024 * 1024) #ifdef XRDP_RFXCODEC /* LH3 LL3, HH3 HL3, HL2 LH2, LH1 HH2, HH1 HL1 todo check this */ @@ -77,6 +78,8 @@ xrdp_enc_data_done_destructor(void *item, void *closure) struct xrdp_encoder * xrdp_encoder_create(struct xrdp_mm *mm) { + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_encoder_create:"); + struct xrdp_encoder *self; struct xrdp_client_info *client_info; char buf[1024]; @@ -106,7 +109,8 @@ xrdp_encoder_create(struct xrdp_mm *mm) if (client_info->jpeg_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: starting jpeg codec session"); + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " + "starting jpeg codec session"); self->codec_id = client_info->jpeg_codec_id; self->in_codec_mode = 1; self->codec_quality = client_info->jpeg_prop[0]; @@ -136,7 +140,8 @@ xrdp_encoder_create(struct xrdp_mm *mm) } else if (client_info->rfx_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: starting rfx codec session"); + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " + "starting rfx codec session"); self->codec_id = client_info->rfx_codec_id; self->in_codec_mode = 1; client_info->capture_code = 2; @@ -148,7 +153,8 @@ xrdp_encoder_create(struct xrdp_mm *mm) #endif else if (client_info->h264_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: starting h264 codec session"); + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " + "starting h264 codec session"); self->codec_id = client_info->h264_codec_id; self->in_codec_mode = 1; client_info->capture_code = 3; @@ -277,15 +283,18 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) continue; } - LOG_DEVEL(LOG_LEVEL_DEBUG, "process_enc_jpg: x %d y %d cx %d cy %d", x, y, cx, cy); + LOG_DEVEL(LOG_LEVEL_DEBUG, "process_enc_jpg: x %d y %d cx %d cy %d", + x, y, cx, cy); out_data_bytes = MAX((cx + 4) * cy * 4, 8192); - if ((out_data_bytes < 1) || (out_data_bytes > 16 * 1024 * 1024)) + if ((out_data_bytes < 1) + || (out_data_bytes > OUT_DATA_BYTES_DEFAULT_SIZE)) { LOG_DEVEL(LOG_LEVEL_ERROR, "process_enc_jpg: error 2"); return 1; } - out_data = (char *) g_malloc(out_data_bytes + 256 + 2, 0); + out_data = (char *) g_malloc(out_data_bytes + + XRDP_SURCMD_PREFIX_BYTES + 2, 0); if (out_data == 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "process_enc_jpg: error 3"); @@ -298,15 +307,18 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) enc->width, enc->height, enc->width * 4, x, y, cx, cy, quality, - out_data + 256 + 2, &out_data_bytes); + out_data + + XRDP_SURCMD_PREFIX_BYTES + 2, + &out_data_bytes); if (error < 0) { - LOG_DEVEL(LOG_LEVEL_ERROR, "process_enc_jpg: jpeg error %d bytes %d", - error, out_data_bytes); + LOG_DEVEL(LOG_LEVEL_ERROR, "process_enc_jpg: jpeg error %d " + "bytes %d", error, out_data_bytes); g_free(out_data); return 1; } - LOG_DEVEL(LOG_LEVEL_WARNING, "jpeg error %d bytes %d", error, out_data_bytes); + LOG_DEVEL(LOG_LEVEL_WARNING, + "jpeg error %d bytes %d", error, out_data_bytes); enc_done = (XRDP_ENC_DATA_DONE *) g_malloc(sizeof(XRDP_ENC_DATA_DONE), 1); enc_done->comp_bytes = out_data_bytes + 2; diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 8769a61d97..076e87c4ff 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -27,17 +27,15 @@ #include "guid.h" #include "ms-rdpedisp.h" #include "ms-rdpbcgr.h" - #include "scp.h" - #include - #include "xrdp_encoder.h" #include "xrdp_sockets.h" #include "xrdp_egfx.h" +#include "libxrdp.h" +#include "xrdp_channel.h" #include - /* Forward declarations */ static int xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *port); @@ -49,8 +47,6 @@ struct xrdp_mm * xrdp_mm_create(struct xrdp_wm *owner) { struct xrdp_mm *self; - char buf[1024]; - int pid; self = (struct xrdp_mm *)g_malloc(sizeof(struct xrdp_mm), 1); self->wm = owner; @@ -58,17 +54,9 @@ xrdp_mm_create(struct xrdp_wm *owner) self->login_names->auto_free = 1; self->login_values = list_create(); self->login_values->auto_free = 1; - self->resize_queue = list_create(); - self->resize_queue->auto_free = 1; self->uid = -1; /* Never good to default UIDs to 0 */ - pid = g_getpid(); - /* setup wait objects for signalling */ - g_snprintf(buf, sizeof(buf), "xrdp_%8.8x_resize_ready", pid); - self->resize_ready = g_create_wait_obj(buf); - self->resize_data = NULL; - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_create: bpp %d mcs_connection_type %d " "jpeg_codec_id %d v3_codec_id %d rfx_codec_id %d " "h264_codec_id %d", @@ -170,6 +158,7 @@ xrdp_mm_delete(struct xrdp_mm *self) list_delete(self->resize_queue); g_free(self->resize_data); g_delete_wait_obj(self->resize_ready); + xrdp_egfx_shutdown_full(self->egfx); g_free(self); } @@ -1090,6 +1079,30 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, return 0; } +/******************************************************************************/ +static int +xrdp_mm_egfx_invalidate_all(struct xrdp_mm *self) +{ + struct xrdp_rect xr_rect; + struct xrdp_bitmap *screen; + int error; + + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_all:"); + + screen = self->wm->screen; + + xr_rect.left = 0; + xr_rect.top = 0; + xr_rect.right = screen->width; + xr_rect.bottom = screen->height; + if (self->wm->screen_dirty_region == NULL) + { + self->wm->screen_dirty_region = xrdp_region_create(self->wm); + } + error = xrdp_region_add_rect(self->wm->screen_dirty_region, &xr_rect); + return error; +} + /******************************************************************************/ static int dynamic_monitor_open_response(intptr_t id, int chan_id, int creation_status) @@ -1139,6 +1152,265 @@ dynamic_monitor_data_first(intptr_t id, int chan_id, char *data, int bytes, return 0; } +/******************************************************************************/ +int +advance_resize_state_machine(struct xrdp_mm *mm, + enum display_resize_state new_state) +{ + struct display_control_monitor_layout_data *description = mm->resize_data; + LOG_DEVEL(LOG_LEVEL_INFO, + "advance_resize_state_machine:" + " Processing resize to: %d x %d." + " Advancing state from %s to %s." + " Previous state took %d MS.", + description->description.session_width, + description->description.session_height, + XRDP_DISPLAY_RESIZE_STATE_TO_STR(description->state), + XRDP_DISPLAY_RESIZE_STATE_TO_STR(new_state), + g_time3() - description->last_state_update_timestamp); + description->state = new_state; + description->last_state_update_timestamp = g_time3(); + g_set_wait_obj(mm->resize_ready); + return 0; +} + +/******************************************************************************/ +static int +xrdp_mm_egfx_caps_advertise(void *user, int caps_count, + int *versions, int *flagss) +{ + struct xrdp_mm *self; + struct xrdp_bitmap *screen; + int index; + int best_index; + int best_h264_index; + int best_pro_index; + int error; + int version; + int flags; + + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise:"); + self = (struct xrdp_mm *) user; + screen = self->wm->screen; + if (screen->data == NULL) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: can not do gfx"); + } + best_index = -1; + best_h264_index = -1; + best_pro_index = -1; + for (index = 0; index < caps_count; index++) + { + version = versions[index]; + flags = flagss[index]; + LOG(LOG_LEVEL_INFO, " version 0x%8.8x flags 0x%8.8x (index: %d)", + version, flags, index); + switch (version) + { + case XR_RDPGFX_CAPVERSION_8: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_81: + if (flags & XR_RDPGFX_CAPS_FLAG_AVC420_ENABLED) + { + best_h264_index = index; + } + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_10: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_101: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_102: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_103: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_104: + if (!(flags & XR_RDPGFX_CAPS_FLAG_AVC_DISABLED)) + { + best_h264_index = index; + } + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_105: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_106: + best_pro_index = index; + break; + } + } + if (best_pro_index >= 0) + { + best_index = best_pro_index; + self->egfx_flags = XRDP_EGFX_RFX_PRO; + } + /* prefer h264, todo use setting in xrdp.ini for this */ + if (best_h264_index >= 0) + { +#if defined(XRDP_X264) || defined(XRDP_NVENC) + best_index = best_h264_index; + self->egfx_flags = XRDP_EGFX_H264; +#endif + } + if (best_index >= 0) + { + LOG(LOG_LEVEL_INFO, " replying version 0x%8.8x flags 0x%8.8x", + versions[best_index], flagss[best_index]); + error = xrdp_egfx_send_capsconfirm(self->egfx, + versions[best_index], + flagss[best_index]); + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_capsconfirm " + "error %d best_index %d", error, best_index); + error = xrdp_egfx_send_reset_graphics(self->egfx, + screen->width, screen->height, + self->wm->client_info->display_sizes.monitorCount, + self->wm->client_info->display_sizes.minfo_wm); + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_reset_graphics " + "error %d monitorCount %d", + error, self->wm->client_info->display_sizes.monitorCount); + self->egfx_up = 1; + xrdp_egfx_send_create_surface(self->egfx, self->egfx->surface_id, + screen->width, screen->height, + XR_PIXEL_FORMAT_XRGB_8888); + xrdp_egfx_send_map_surface(self->egfx, self->egfx->surface_id, 0, 0); + self->encoder = xrdp_encoder_create(self); + xrdp_mm_egfx_invalidate_all(self); + + if (self->resize_data != NULL + && self->resize_data->state == WMRZ_EGFX_INITALIZING) + { + advance_resize_state_machine(self, WMRZ_EGFX_INITIALIZED); + } + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: egfx created."); + if (self->gfx_delay_autologin) + { + self->gfx_delay_autologin = 0; + xrdp_wm_set_login_state(self->wm, WMLS_START_CONNECT); + } + } + else + { + struct xrdp_rect lrect; + + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: no good gfx, canceling"); + lrect.left = 0; + lrect.top = 0; + lrect.right = screen->width; + lrect.bottom = screen->height; + self->wm->client_info->gfx = 0; + xrdp_encoder_delete(self->encoder); + self->encoder = xrdp_encoder_create(self); + xrdp_bitmap_invalidate(screen, &lrect); + } + return 0; +} + +/*****************************************************************************/ +static int +xrdp_mm_update_module_frame_ack(struct xrdp_mm *self) +{ + int fif; + struct xrdp_encoder *encoder; + + encoder = self->encoder; + fif = encoder->frames_in_flight; + if (encoder->frame_id_client + fif > encoder->frame_id_server) + { + if (encoder->frame_id_server > encoder->frame_id_server_sent) + { + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_update_module_ack: " + "frame_id_server %d", encoder->frame_id_server); + encoder->frame_id_server_sent = encoder->frame_id_server; + self->mod->mod_frame_ack(self->mod, 0, encoder->frame_id_server); + } + } + return 0; +} + +static int +xrdp_mm_egfx_frame_ack(void *user, uint32_t queue_depth, int frame_id, + int frames_decoded) +{ + struct xrdp_mm *self; + struct xrdp_encoder *encoder; + + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack:"); + self = (struct xrdp_mm *) user; + encoder = self->encoder; + if (encoder == NULL) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: encoder is nil"); + return 0; + } + if (queue_depth == XR_SUSPEND_FRAME_ACKNOWLEDGEMENT) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: " + "queue_depth %d frame_id %d frames_decoded %d", + queue_depth, frame_id, frames_decoded); + if (encoder->gfx_ack_off == 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: " + "client request turn off frame acks."); + encoder->gfx_ack_off = 1; + frame_id = -1; + } + } + else + { + if (encoder->gfx_ack_off) + { + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack: " + "client request turn on frame acks"); + encoder->gfx_ack_off = 0; + } + } + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack: " + "incoming %d, client %d, server %d", + frame_id, encoder->frame_id_client, encoder->frame_id_server); + if (frame_id < 0 || frame_id > encoder->frame_id_server) + { + /* if frame_id is negative or bigger then what server last sent + just ack all sent frames */ + /* some clients can send big number just to clear all + pending frames */ + encoder->frame_id_client = encoder->frame_id_server; + } + else + { + /* frame acks can come out of order so ignore older one */ + encoder->frame_id_client = MAX(frame_id, encoder->frame_id_client); + } + xrdp_mm_update_module_frame_ack(self); + return 0; +} + +/******************************************************************************/ +int +egfx_initialize(struct xrdp_mm *self) +{ + LOG_DEVEL(LOG_LEVEL_TRACE, "egfx_initialize"); + if (!(self->wm->client_info->mcs_early_capability_flags + & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL)) + { + return 0; + } + LOG_DEVEL(LOG_LEVEL_INFO, "egfx_initialize: gfx capable client"); + if (xrdp_egfx_create(self, &(self->egfx)) == 0) + { + self->egfx->user = self; + self->egfx->caps_advertise = xrdp_mm_egfx_caps_advertise; + self->egfx->frame_ack = xrdp_mm_egfx_frame_ack; + return 0; + } + LOG_DEVEL(LOG_LEVEL_INFO, "egfx_initialize: xrdp_egfx_create failed"); + return 1; +} + /******************************************************************************/ static const int MAXIMUM_MONITOR_SIZE = sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS; @@ -1162,27 +1434,6 @@ sync_dynamic_monitor_data(struct xrdp_wm *wm, MAXIMUM_MONITOR_SIZE); } -int -advance_resize_state_machine(struct xrdp_mm *mm, - enum display_resize_state new_state) -{ - struct display_control_monitor_layout_data *description = mm->resize_data; - LOG_DEVEL(LOG_LEVEL_INFO, - "advance_resize_state_machine:" - " Processing resize to: %d x %d." - " Advancing state from %s to %s." - " Previous state took %d MS.", - description->description.session_width, - description->description.session_height, - XRDP_DISPLAY_RESIZE_STATE_TO_STR(description->state), - XRDP_DISPLAY_RESIZE_STATE_TO_STR(new_state), - g_time3() - description->last_state_update_timestamp); - description->state = new_state; - description->last_state_update_timestamp = g_time3(); - g_set_wait_obj(mm->resize_ready); - return 0; -} - /******************************************************************************/ static int dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) @@ -1269,7 +1520,8 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) list_add_item(wm->mm->resize_queue, (tintptr)display_size_data); g_set_wait_obj(wm->mm->resize_ready); LOG(LOG_LEVEL_DEBUG, "dynamic_monitor_data:" - " received width %d, received height %d.", display_size_data->session_width, display_size_data->session_height); + " received width %d, received height %d.", + display_size_data->session_width, display_size_data->session_height); return 0; } @@ -1289,6 +1541,9 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) int error = 0; struct xrdp_mm *mm; struct xrdp_mod *module; + struct xrdp_rdp *rdp; + struct xrdp_sec *sec; + struct xrdp_channel *chan; LOG_DEVEL(LOG_LEVEL_TRACE, "process_display_control_monitor_layout_data:"); @@ -1326,6 +1581,56 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) xrdp_encoder_delete(mm->encoder); mm->encoder = NULL; } + if (mm->egfx == 0) + { + advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE); + } + else + { + advance_resize_state_machine(mm, WMRZ_EGFX_DELETE_SURFACE); + } + break; + case WMRZ_EGFX_DELETE_SURFACE: + if (error == 0 && module != 0) + { + xrdp_egfx_shutdown_delete_surface(mm->egfx); + } + advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSE); + break; + case WMRZ_EGFX_CONN_CLOSE: + if (error == 0 && module != 0) + { + xrdp_egfx_shutdown_close_connection(wm->mm->egfx); + } + advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSING); + break; + // Also processed in xrdp_egfx_close_response + case WMRZ_EGFX_CONN_CLOSING: + rdp = (struct xrdp_rdp *) (mm->wm->session->rdp); + sec = rdp->sec_layer; + chan = sec->chan_layer; + + // Continue to check to see if the connection is closed. If it + // ever is, advance the state machine! + if (chan->drdynvcs[mm->egfx->channel_id].status + == XRDP_DRDYNVC_STATUS_CLOSED + || (g_time3() - description->last_state_update_timestamp) > 100) + { + advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSED); + break; + } + g_set_wait_obj(mm->resize_ready); + break; + case WMRZ_EGFX_CONN_CLOSED: + advance_resize_state_machine(mm, WRMZ_EGFX_DELETE); + break; + case WRMZ_EGFX_DELETE: + if (error == 0 && module != 0) + { + xrdp_egfx_shutdown_delete(wm->mm->egfx); + mm->egfx = NULL; + mm->egfx_up = 0; + } advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE); break; case WMRZ_SERVER_MONITOR_RESIZE: @@ -1338,9 +1643,10 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) " mod_server_monitor_resize failed %d", error); return advance_error(error, mm); } - advance_resize_state_machine(mm, WMRZ_SERVER_VERSION_MESSAGE); + advance_resize_state_machine( + mm, WMRZ_SERVER_VERSION_MESSAGE_START); break; - case WMRZ_SERVER_VERSION_MESSAGE: + case WMRZ_SERVER_VERSION_MESSAGE_START: error = module->mod_server_version_message(module); if (error != 0) { @@ -1349,6 +1655,12 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) " mod_server_version_message failed %d", error); return advance_error(error, mm); } + advance_resize_state_machine( + mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING); + break; + // Not processed here. Processed in server_reset + // case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING: + case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED: advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESIZE); break; case WMRZ_XRDP_CORE_RESIZE: @@ -1400,6 +1712,22 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) return advance_error(error, mm); } sync_dynamic_monitor_data(wm, &(description->description)); + advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZE); + break; + case WMRZ_EGFX_INITIALIZE: + if (error == 0 && mm->egfx == NULL && mm->egfx_up == 0) + { + egfx_initialize(mm); + advance_resize_state_machine(mm, WMRZ_EGFX_INITALIZING); + } + else + { + advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZED); + } + break; + // Not processed here. Processed in xrdp_mm_egfx_caps_advertise + // case WMRZ_EGFX_INITALIZING: + case WMRZ_EGFX_INITIALIZED: advance_resize_state_machine(mm, WMRZ_ENCODER_CREATE); break; case WMRZ_ENCODER_CREATE: @@ -1450,7 +1778,7 @@ dynamic_monitor_process_queue(struct xrdp_mm *self) return 0; } - if (self->resize_data == NULL) + if (self->resize_data == NULL && self->resize_queue != NULL) { if (self->resize_queue->count <= 0) { @@ -1518,6 +1846,11 @@ dynamic_monitor_process_queue(struct xrdp_mm *self) " Resize data is not null."); } + if (self->resize_data == NULL) + { + return 0; + } + if (self->resize_data->state == WMRZ_COMPLETE) { LOG(LOG_LEVEL_INFO, "dynamic_monitor_process_queue: Clearing" @@ -1552,6 +1885,8 @@ dynamic_monitor_initialize(struct xrdp_mm *self) struct xrdp_drdynvc_procs d_procs; int flags; int error; + char buf[1024]; + int pid; LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_initialize:"); @@ -1567,9 +1902,20 @@ dynamic_monitor_initialize(struct xrdp_mm *self) &(self->dynamic_monitor_chanid)); if (error != 0) { - LOG(LOG_LEVEL_ERROR, "xrdp_mm_drdynvc_up: " + LOG(LOG_LEVEL_ERROR, "dynamic_monitor_initialize: " "libxrdp_drdynvc_open failed %d", error); + return error; } + + // Initialize xrdp_mm specific variables. + self->resize_queue = list_create(); + self->resize_queue->auto_free = 1; + pid = g_getpid(); + /* setup wait objects for signaling */ + g_snprintf(buf, sizeof(buf), "xrdp_%8.8x_resize_ready", pid); + self->resize_ready = g_create_wait_obj(buf); + self->resize_data = NULL; + return error; } @@ -1583,6 +1929,12 @@ xrdp_mm_drdynvc_up(struct xrdp_mm *self) LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_drdynvc_up:"); + error = egfx_initialize(self); + if (error != 0) + { + return error; + } + enable_dynamic_resize = xrdp_mm_get_value(self, "enable_dynamic_resizing"); /* * User can disable dynamic resizing if necessary @@ -1593,10 +1945,17 @@ xrdp_mm_drdynvc_up(struct xrdp_mm *self) LOG(LOG_LEVEL_INFO, "User has disabled dynamic resizing."); return error; } + error = dynamic_monitor_initialize(self); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "Dynamic monitor initialize failed." + " Client likely does not support it."); + return error; + } ignore_marker = (struct display_control_monitor_layout_data *) - g_malloc(sizeof(struct display_control_monitor_layout_data), 1); + g_malloc(sizeof(struct display_control_monitor_layout_data), + 1); list_add_item(self->resize_queue, (tintptr)ignore_marker); - error = dynamic_monitor_initialize(self); return error; } @@ -2795,7 +3154,10 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) } } - +#define MIN_MS_BETWEEN_FRAMES 40 +/* can not change this to zero yet, g_obj_wait in os_calls.c treats + everything less then 1 to mean wait forever */ +#define MIN_MS_TO_WAIT_FOR_MORE_UPDATES 1 /*****************************************************************************/ int xrdp_mm_get_wait_objs(struct xrdp_mm *self, @@ -2842,6 +3204,25 @@ xrdp_mm_get_wait_objs(struct xrdp_mm *self, read_objs[(*rcount)++] = self->resize_ready; } + if (self->wm->screen_dirty_region != NULL) + { + if (xrdp_region_not_empty(self->wm->screen_dirty_region)) + { + int now = g_time3(); + int next_screen_draw_time = self->wm->last_screen_draw_time + + MIN_MS_BETWEEN_FRAMES; + int diff = next_screen_draw_time - now; + int ltimeout = *timeout; + diff = MAX(diff, MIN_MS_TO_WAIT_FOR_MORE_UPDATES); + diff = MIN(diff, MIN_MS_BETWEEN_FRAMES); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_get_wait_objs:" + " not empty diff %d", diff); + if ((ltimeout < 0) || (ltimeout > diff)) + { + *timeout = diff; + } + } + } return rv; } @@ -2919,28 +3300,6 @@ xrdp_mm_check_chan(struct xrdp_mm *self) return 0; } -/*****************************************************************************/ -static int -xrdp_mm_update_module_frame_ack(struct xrdp_mm *self) -{ - int fif; - struct xrdp_encoder *encoder; - - encoder = self->encoder; - fif = encoder->frames_in_flight; - if (encoder->frame_id_client + fif > encoder->frame_id_server) - { - if (encoder->frame_id_server > encoder->frame_id_server_sent) - { - LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_update_module_ack: frame_id_server %d", - encoder->frame_id_server); - encoder->frame_id_server_sent = encoder->frame_id_server; - self->mod->mod_frame_ack(self->mod, 0, encoder->frame_id_server); - } - } - return 0; -} - /*****************************************************************************/ static int xrdp_mm_process_enc_done(struct xrdp_mm *self) @@ -2973,22 +3332,45 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) cy = enc_done->cy; if (enc_done->comp_bytes > 0) { - if (!enc_done->continuation) + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_process_enc_done: " + "x %d y %d cx %d cy %d frame_id %d use_frame_acks %d", + x, y, cx, cy, enc_done->enc->frame_id, + self->wm->client_info->use_frame_acks); + if (enc_done->flags & GFX_H264) { - libxrdp_fastpath_send_frame_marker(self->wm->session, 0, - enc_done->enc->frame_id); + LOG(LOG_LEVEL_INFO, "GFX H264 Unimplemeted."); } - libxrdp_fastpath_send_surface(self->wm->session, - enc_done->comp_pad_data, - enc_done->pad_bytes, - enc_done->comp_bytes, - x, y, x + cx, y + cy, - 32, self->encoder->codec_id, - cx, cy); - if (enc_done->last) + else if (enc_done->flags & GFX_PROGRESSIVE_RFX) /* gfx progressive rfx */ { - libxrdp_fastpath_send_frame_marker(self->wm->session, 1, - enc_done->enc->frame_id); + xrdp_egfx_send_frame_start(self->egfx, + enc_done->enc->frame_id, 0); + xrdp_egfx_send_wire_to_surface2(self->egfx, + self->egfx->surface_id, 9, 1, + XR_PIXEL_FORMAT_XRGB_8888, + enc_done->comp_pad_data + + enc_done->pad_bytes, + enc_done->comp_bytes); + xrdp_egfx_send_frame_end(self->egfx, enc_done->enc->frame_id); + } + else + { + if (!enc_done->continuation) + { + libxrdp_fastpath_send_frame_marker(self->wm->session, 0, + enc_done->enc->frame_id); + } + libxrdp_fastpath_send_surface(self->wm->session, + enc_done->comp_pad_data, + enc_done->pad_bytes, + enc_done->comp_bytes, + x, y, x + cx, y + cy, + 32, self->encoder->codec_id, + cx, cy); + if (enc_done->last) + { + libxrdp_fastpath_send_frame_marker(self->wm->session, 1, + enc_done->enc->frame_id); + } } } /* free enc_done */ @@ -2996,16 +3378,35 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) { enc = enc_done->enc; LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_process_enc_done: last set"); - if (self->wm->client_info->use_frame_acks == 0) + if (enc_done->flags & GFX_H264) /* gfx */ { - self->mod->mod_frame_ack(self->mod, - enc->flags, - enc->frame_id); + if (self->encoder->gfx_ack_off) + { + /* gfx and client turned off client frame acks */ + self->mod->mod_frame_ack(self->mod, + enc->flags, + enc->frame_id); + } + else + { + self->encoder->frame_id_server = enc->frame_id; + xrdp_mm_update_module_frame_ack(self); + } } else { - self->encoder->frame_id_server = enc->frame_id; - xrdp_mm_update_module_frame_ack(self); + if (self->wm->client_info->use_frame_acks == 0) + { + /* surface commmand and client does not do frame acks */ + self->mod->mod_frame_ack(self->mod, + enc->flags, + enc->frame_id); + } + else + { + self->encoder->frame_id_server = enc_done->enc->frame_id; + xrdp_mm_update_module_frame_ack(self); + } } g_free(enc->drects); g_free(enc->crects); @@ -3143,8 +3544,9 @@ xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id) return 1; } encoder = self->encoder; - LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_frame_ack: incoming %d, client %d, server %d", - frame_id, encoder->frame_id_client, encoder->frame_id_server); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_frame_ack: " + "incoming %d, client %d, server %d", frame_id, + encoder->frame_id_client, encoder->frame_id_server); if ((frame_id < 0) || (frame_id > encoder->frame_id_server)) { /* if frame_id is negative or bigger then what server last sent @@ -3389,9 +3791,11 @@ server_paint_rects(struct xrdp_mod *mod, int num_drects, short *drects, /*****************************************************************************/ int -server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, - int num_crects, short *crects, char *data, - int left, int top, int width, int height, +server_paint_rects_ex(struct xrdp_mod *mod, + int num_drects, short *drects, + int num_crects, short *crects, + char *data, int left, int top, + int width, int height, int flags, int frame_id, void *shmem_ptr, int shmem_bytes) { @@ -3406,7 +3810,7 @@ server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, wm = (struct xrdp_wm *)(mod->wm); mm = wm->mm; - LOG_DEVEL(LOG_LEVEL_DEBUG, "server_paint_rects: %p", mm->encoder); + LOG(LOG_LEVEL_TRACE, "server_paint_rects_ex: %p", mm->encoder); if (mm->encoder != 0) { @@ -3477,7 +3881,12 @@ server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, return 0; } - LOG(LOG_LEVEL_TRACE, "server_paint_rects:"); + if (wm->client_info->gfx) + { + LOG(LOG_LEVEL_DEBUG, "server_paint_rects: gfx session and no encoder"); + mm->mod->mod_frame_ack(mm->mod, flags, frame_id); + return 0; + } p = (struct xrdp_painter *)(mod->painter); if (p == 0) @@ -3796,8 +4205,16 @@ int server_reset(struct xrdp_mod *mod, int width, int height, int bpp) { struct xrdp_wm *wm; + struct xrdp_mm *mm; + + LOG(LOG_LEVEL_TRACE, "server_reset:"); wm = (struct xrdp_wm *)(mod->wm); + if (wm == 0) + { + return 1; + } + mm = wm->mm; if (wm->client_info == 0) { @@ -3810,6 +4227,42 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp) return 0; } + // bpp of zero is impossible. + // This is a signal from xup that + // It is finished resizing. + if (bpp == 0) + { + if (mm == 0) + { + return 1; + } + if (!xrdp_wm_can_resize(wm)) + { + return 1; + } + if (mm->resize_data == NULL) + { + mm->mod->mod_server_monitor_full_invalidate(mm->mod, width, height); + return 0; + } + if (mm->resize_data != NULL + && mm->resize_data->state + == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING) + { + LOG(LOG_LEVEL_INFO, + "server_reset: Advancing server monitor resized."); + advance_resize_state_machine( + mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED); + } + else if (mm->resize_data != NULL + && mm->resize_data->description.session_height == 0 + && mm->resize_data->description.session_width == 0) + { + mm->mod->mod_server_monitor_full_invalidate(mm->mod, width, height); + } + return 0; + } + /* if same (and only one monitor on client) don't need to do anything */ if (wm->client_info->display_sizes.session_width == (uint32_t)width && wm->client_info->display_sizes.session_height == (uint32_t)height && diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index d0bce05706..06ccf4469b 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -28,6 +28,7 @@ #include "xrdp_constants.h" #include "fifo.h" #include "guid.h" +#include "xrdp_client_info.h" #define MAX_NR_CHANNELS 16 #define MAX_CHANNEL_NAME 16 @@ -343,7 +344,9 @@ enum display_resize_state WMRZ_EGFX_CONN_CLOSED, WRMZ_EGFX_DELETE, WMRZ_SERVER_MONITOR_RESIZE, - WMRZ_SERVER_VERSION_MESSAGE, + WMRZ_SERVER_VERSION_MESSAGE_START, + WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING, + WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED, WMRZ_XRDP_CORE_RESIZE, WMRZ_EGFX_INITIALIZE, WMRZ_EGFX_INITALIZING, @@ -362,7 +365,12 @@ enum display_resize_state (status) == WMRZ_EGFX_CONN_CLOSED ? "WMRZ_EGFX_CONN_CLOSED" : \ (status) == WRMZ_EGFX_DELETE ? "WMRZ_EGFX_DELETE" : \ (status) == WMRZ_SERVER_MONITOR_RESIZE ? "WMRZ_SERVER_MONITOR_RESIZE" : \ - (status) == WMRZ_SERVER_VERSION_MESSAGE ? "WMRZ_SERVER_VERSION_MESSAGE" : \ + (status) == WMRZ_SERVER_VERSION_MESSAGE_START ? \ + "WMRZ_SERVER_VERSION_MESSAGE_START" : \ + (status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING ? \ + "WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING" : \ + (status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED ? \ + "WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED" : \ (status) == WMRZ_XRDP_CORE_RESIZE ? "WMRZ_XRDP_CORE_RESIZE" : \ (status) == WMRZ_EGFX_INITIALIZE ? "WMRZ_EGFX_INITIALIZE" : \ (status) == WMRZ_EGFX_INITALIZING ? "WMRZ_EGFX_INITALIZING" : \ @@ -417,7 +425,7 @@ struct xrdp_mm int dynamic_monitor_chanid; struct xrdp_egfx *egfx; int egfx_up; - int egfx_flags; + enum xrdp_egfx_flags egfx_flags; int gfx_delay_autologin; /* Resize on-the-fly control */ struct display_control_monitor_layout_data *resize_data; diff --git a/xup/xup.c b/xup/xup.c index 4215d0bcf7..0b6cbd041a 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -1174,47 +1174,33 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) in_uint16_le(s, height); bmpdata = 0; - if (flags == 0) /* screen */ + if (amod->screen_shmem_id_mapped == 0) { - /* Do we need to map (or remap) the memory - * area shared with the X server ? */ - if (amod->screen_shmem_id_mapped == 0 || - amod->screen_shmem_id != shmem_id) + amod->screen_shmem_id = shmem_id; + amod->screen_shmem_pixels = (char *) g_shmat(amod->screen_shmem_id); + if (amod->screen_shmem_pixels == (void *) -1) { - if (amod->screen_shmem_id_mapped != 0) - { - g_shmdt(amod->screen_shmem_pixels); - } - amod->screen_shmem_pixels = (char *) g_shmat(shmem_id); - if (amod->screen_shmem_pixels == (void *) -1) - { - /* failed */ - if (amod->screen_shmem_id_mapped == 0) - { - LOG(LOG_LEVEL_ERROR, - "Can't attach to shared memory id %d [%s]", - shmem_id, g_get_strerror()); - } - else - { - LOG(LOG_LEVEL_ERROR, - "Can't attach to shared memory id %d from id %d [%s]", - shmem_id, amod->screen_shmem_id, g_get_strerror()); - } - amod->screen_shmem_id = 0; - amod->screen_shmem_pixels = 0; - amod->screen_shmem_id_mapped = 0; - } - else - { - amod->screen_shmem_id = shmem_id; - amod->screen_shmem_id_mapped = 1; - } + /* failed */ + amod->screen_shmem_id = 0; + amod->screen_shmem_pixels = 0; + amod->screen_shmem_id_mapped = 0; } - - if (amod->screen_shmem_pixels != 0) + else + { + amod->screen_shmem_id_mapped = 1; + } + } + else if (amod->screen_shmem_id != shmem_id) + { + amod->screen_shmem_id = shmem_id; + g_shmdt(amod->screen_shmem_pixels); + amod->screen_shmem_pixels = (char *) g_shmat(amod->screen_shmem_id); + if (amod->screen_shmem_pixels == (void *) -1) { - bmpdata = amod->screen_shmem_pixels + shmem_offset; + /* failed */ + amod->screen_shmem_id = 0; + amod->screen_shmem_pixels = 0; + amod->screen_shmem_id_mapped = 0; } } else @@ -1225,7 +1211,10 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) flags, frame_id, shmem_id, shmem_offset, width, height); } - + if (amod->screen_shmem_pixels != 0) + { + bmpdata = amod->screen_shmem_pixels + shmem_offset; + } if (bmpdata != 0) { rv = amod->server_paint_rects(amod, num_drects, ldrects, @@ -1238,9 +1227,6 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) rv = 1; } - //LOG_DEVEL(LOG_LEVEL_TRACE, "frame_id %d", frame_id); - //send_paint_rect_ex_ack(amod, flags, frame_id); - g_free(lcrects); g_free(ldrects); @@ -1680,74 +1666,71 @@ lib_mod_process_message(struct mod *mod, struct stream *s) char *phold; LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_process_message:"); + in_uint16_le(s, type); + in_uint16_le(s, num_orders); + in_uint32_le(s, len); + LOG_DEVEL(LOG_LEVEL_DEBUG, "lib_mod_process_message: type %d", type); + rv = 0; - if (rv == 0) + if (type == 1) /* original order list */ { - in_uint16_le(s, type); - in_uint16_le(s, num_orders); - in_uint32_le(s, len); - LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_process_message: type %d", type); - - if (type == 1) /* original order list */ + for (index = 0; index < num_orders; index++) { - for (index = 0; index < num_orders; index++) - { - in_uint16_le(s, type); - rv = lib_mod_process_orders(mod, type, s); + in_uint16_le(s, type); + rv = lib_mod_process_orders(mod, type, s); - if (rv != 0) - { - break; - } - } - } - else if (type == 2) /* caps */ - { - LOG_DEVEL(LOG_LEVEL_TRACE, - "lib_mod_process_message: type 2 len %d", len); - for (index = 0; index < num_orders; index++) + if (rv != 0) { - phold = s->p; - in_uint16_le(s, type); - in_uint16_le(s, len); - - switch (type) - { - default: - LOG_DEVEL(LOG_LEVEL_TRACE, - "lib_mod_process_message: unknown" - " cap type %d len %d", - type, len); - break; - } - - s->p = phold + len; + break; } - - lib_send_client_info(mod); } - else if (type == 3) /* order list with len after type */ + } + else if (type == 2) /* caps */ + { + LOG_DEVEL(LOG_LEVEL_TRACE, + "lib_mod_process_message: type 2 len %d", len); + for (index = 0; index < num_orders; index++) { - for (index = 0; index < num_orders; index++) - { - phold = s->p; - in_uint16_le(s, type); - in_uint16_le(s, len); - rv = lib_mod_process_orders(mod, type, s); + phold = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); - if (rv != 0) - { + switch (type) + { + default: + LOG_DEVEL(LOG_LEVEL_TRACE, + "lib_mod_process_message: unknown" + " cap type %d len %d", + type, len); break; - } - - s->p = phold + len; } + s->p = phold + len; } - else + lib_send_client_info(mod); + } + else if (type == 3) /* order list with len after type */ + { + LOG_DEVEL(LOG_LEVEL_INFO, + "lib_mod_process_message: type 3 len %d", len); + for (index = 0; index < num_orders; index++) { - LOG_DEVEL(LOG_LEVEL_TRACE, "unknown type %d", type); + phold = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + rv = lib_mod_process_orders(mod, type, s); + + if (rv != 0) + { + break; + } + + s->p = phold + len; } } + else + { + LOG_DEVEL(LOG_LEVEL_TRACE, "unknown type %d", type); + } return rv; }