GFX: Prevent MM screen being written to the client

In GFX mode, if we're using xorgxrdp, frame updates are send directly
from the client, bypassing the screen buffer in xrdp_mm.

This commit only allows the xrdp_mm screen buffer to be invalidated
if the painter has drawn into it since the module was loaded. This
prevents the unused (and invalid) frame buffer being pushed to the client
in GFX mode with xorgxrdp.
This commit is contained in:
matt335672 2024-02-19 16:26:04 +00:00
parent c21521f80d
commit 09715f4cf4
4 changed files with 64 additions and 37 deletions

View File

@ -502,6 +502,9 @@ int
xrdp_mm_check_wait_objs(struct xrdp_mm *self); xrdp_mm_check_wait_objs(struct xrdp_mm *self);
int int
xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id); xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id);
void
xrdp_mm_efgx_add_dirty_region_to_planar_list(struct xrdp_mm *self,
struct xrdp_region *dirty_region);
int int
xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self,
struct xrdp_bitmap *bitmap, struct xrdp_bitmap *bitmap,

View File

@ -1095,25 +1095,32 @@ cleanup:
/******************************************************************************/ /******************************************************************************/
static int static int
xrdp_mm_egfx_invalidate_all(struct xrdp_mm *self) xrdp_mm_egfx_invalidate_wm_screen(struct xrdp_mm *self)
{ {
struct xrdp_rect xr_rect; int error = 0;
struct xrdp_bitmap *screen;
int error;
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_all:"); LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_wm_screen:");
screen = self->wm->screen; // Only invalidate the WM screen if the module is using the WM screen,
// or we haven't loaded the module yet.
xr_rect.left = 0; //
xr_rect.top = 0; // Otherwise we may send client updates which conflict with the
xr_rect.right = screen->width; // updates sent directly from the module via the encoder.
xr_rect.bottom = screen->height; if (self->mod_uses_wm_screen_for_gfx || self->mod_handle == 0)
if (self->wm->screen_dirty_region == NULL)
{ {
self->wm->screen_dirty_region = xrdp_region_create(self->wm); struct xrdp_bitmap *screen = self->wm->screen;
struct xrdp_rect xr_rect;
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);
} }
error = xrdp_region_add_rect(self->wm->screen_dirty_region, &xr_rect);
return error; return error;
} }
@ -1370,7 +1377,7 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
self->egfx_up = 1; self->egfx_up = 1;
xrdp_mm_egfx_create_surfaces(self); xrdp_mm_egfx_create_surfaces(self);
self->encoder = xrdp_encoder_create(self); self->encoder = xrdp_encoder_create(self);
xrdp_mm_egfx_invalidate_all(self); xrdp_mm_egfx_invalidate_wm_screen(self);
if (self->resize_data != NULL if (self->resize_data != NULL
&& self->resize_data->state == WMRZ_EGFX_INITALIZING) && self->resize_data->state == WMRZ_EGFX_INITALIZING)
@ -1846,20 +1853,13 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
// Ack all frames to speed up resize. // Ack all frames to speed up resize.
module->mod_frame_ack(module, 0, INT_MAX); module->mod_frame_ack(module, 0, INT_MAX);
} }
// Restart module output // Restart module output after invalidating
// the screen. This causes an automatic redraw.
xrdp_bitmap_invalidate(wm->screen, 0);
rdp = (struct xrdp_rdp *) (wm->session->rdp); rdp = (struct xrdp_rdp *) (wm->session->rdp);
xrdp_rdp_suppress_output(rdp, xrdp_rdp_suppress_output(rdp,
0, XSO_REASON_DYNAMIC_RESIZE, 0, XSO_REASON_DYNAMIC_RESIZE,
0, 0, desc_width, desc_height); 0, 0, desc_width, desc_height);
/* redraw */
error = xrdp_bitmap_invalidate(wm->screen, 0);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" xrdp_bitmap_invalidate failed %d", error);
return advance_error(error, mm);
}
advance_resize_state_machine(mm, WMRZ_COMPLETE); advance_resize_state_machine(mm, WMRZ_COMPLETE);
break; break;
default: default:
@ -3535,6 +3535,39 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
return 0; return 0;
} }
/*****************************************************************************/
void
xrdp_mm_efgx_add_dirty_region_to_planar_list(struct xrdp_mm *self,
struct xrdp_region *dirty_region)
{
int jndex = 0;
struct xrdp_rect rect;
int error = xrdp_region_get_rect(dirty_region, jndex, &rect);
if (error == 0)
{
if (self->wm->screen_dirty_region == NULL)
{
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
}
do
{
xrdp_region_add_rect(self->wm->screen_dirty_region, &rect);
jndex++;
error = xrdp_region_get_rect(dirty_region, jndex, &rect);
}
while (error == 0);
if (self->mod_handle != 0)
{
// Module has been writing to WM screen using GFX
self->mod_uses_wm_screen_for_gfx = 1;
}
}
}
/*****************************************************************************/ /*****************************************************************************/
static int static int
xrdp_mm_draw_dirty(struct xrdp_mm *self) xrdp_mm_draw_dirty(struct xrdp_mm *self)

View File

@ -95,18 +95,8 @@ xrdp_painter_send_dirty(struct xrdp_painter *self)
if (self->session->client_info->gfx) if (self->session->client_info->gfx)
{ {
if (self->wm->screen_dirty_region == NULL) xrdp_mm_efgx_add_dirty_region_to_planar_list(self->wm->mm,
{ self->dirty_region);
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
}
jndex = 0;
error = xrdp_region_get_rect(self->dirty_region, jndex, &rect);
while (error == 0)
{
xrdp_region_add_rect(self->wm->screen_dirty_region, &rect);
jndex++;
error = xrdp_region_get_rect(self->dirty_region, jndex, &rect);
}
} }
else else
{ {

View File

@ -439,6 +439,7 @@ struct xrdp_mm
int egfx_up; int egfx_up;
enum xrdp_egfx_flags egfx_flags; enum xrdp_egfx_flags egfx_flags;
int gfx_delay_autologin; int gfx_delay_autologin;
int mod_uses_wm_screen_for_gfx;
/* Resize on-the-fly control */ /* Resize on-the-fly control */
struct display_control_monitor_layout_data *resize_data; struct display_control_monitor_layout_data *resize_data;
struct list *resize_queue; struct list *resize_queue;