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);
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,

View File

@ -1095,25 +1095,32 @@ cleanup:
/******************************************************************************/
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;
int error = 0;
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_all:");
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_wm_screen:");
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)
// 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;
}
@ -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)
@ -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:
@ -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)

View File

@ -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
{

View File

@ -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;