Add planar compression

Used for the bitmaps transmitted for the login screen over the egfx
channels.
This commit is contained in:
Nexarian 2023-03-15 22:17:05 -04:00
parent 204a6e713b
commit edb8fa7946
6 changed files with 197 additions and 2 deletions

View File

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

View File

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

View File

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

View File

@ -34,6 +34,7 @@
#include "xrdp_encoder.h"
#include "xrdp_sockets.h"
#include "xrdp_egfx.h"
#include <limits.h>
@ -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;
}

View File

@ -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 */

View File

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