Skip to content

Commit

Permalink
GFX: Prevent MM screen being written to the client
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matt335672 authored and metalefty committed Feb 20, 2024
1 parent 05d431d commit d536228
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 37 deletions.
3 changes: 3 additions & 0 deletions xrdp/xrdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,9 @@ int
xrdp_mm_check_wait_objs(struct xrdp_mm *self);
int
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
xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self,
struct xrdp_bitmap *bitmap,
Expand Down
83 changes: 58 additions & 25 deletions xrdp/xrdp_mm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1095,25 +1095,32 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self,

/******************************************************************************/
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;
struct xrdp_bitmap *screen;
int error;

LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_all:");
int error = 0;

screen = self->wm->screen;
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_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)
// Only invalidate the WM screen if the module is using the WM screen,
// or we haven't loaded the module yet.
//
// Otherwise we may send client updates which conflict with the
// updates sent directly from the module via the encoder.
if (self->mod_uses_wm_screen_for_gfx || self->mod_handle == 0)
{
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;
}

Expand Down Expand Up @@ -1370,7 +1377,7 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
self->egfx_up = 1;
xrdp_mm_egfx_create_surfaces(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
&& self->resize_data->state == WMRZ_EGFX_INITALIZING)
Expand Down Expand Up @@ -1846,20 +1853,13 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
// Ack all frames to speed up resize.
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);
xrdp_rdp_suppress_output(rdp,
0, XSO_REASON_DYNAMIC_RESIZE,
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);
break;
default:
Expand Down Expand Up @@ -3535,6 +3535,39 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
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
xrdp_mm_draw_dirty(struct xrdp_mm *self)
Expand Down
14 changes: 2 additions & 12 deletions xrdp/xrdp_painter.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,8 @@ xrdp_painter_send_dirty(struct xrdp_painter *self)

if (self->session->client_info->gfx)
{
if (self->wm->screen_dirty_region == NULL)
{
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);
}
xrdp_mm_efgx_add_dirty_region_to_planar_list(self->wm->mm,
self->dirty_region);
}
else
{
Expand Down
1 change: 1 addition & 0 deletions xrdp/xrdp_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ struct xrdp_mm
int egfx_up;
enum xrdp_egfx_flags egfx_flags;
int gfx_delay_autologin;
int mod_uses_wm_screen_for_gfx;
/* Resize on-the-fly control */
struct display_control_monitor_layout_data *resize_data;
struct list *resize_queue;
Expand Down

0 comments on commit d536228

Please sign in to comment.