mirror of https://github.com/neutrinolabs/xrdp
Merge pull request #3013 from jsorg71/too_big_for_max
gfx send multiple wire to surface messages when compressed data is la…
This commit is contained in:
commit
e73f26c7c1
|
@ -1 +1 @@
|
|||
Subproject commit ab9b65cee1d96eefe154de721fb375f7a4d3946a
|
||||
Subproject commit 015fdffff98584c47966aca617acdc0d1e6dbdca
|
|
@ -28,11 +28,22 @@
|
|||
#include "thread_calls.h"
|
||||
#include "fifo.h"
|
||||
#include "xrdp_egfx.h"
|
||||
#include "string_calls.h"
|
||||
|
||||
#ifdef XRDP_RFXCODEC
|
||||
#include "rfxcodec_encode.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_XRDP_GFX_FRAMES_IN_FLIGHT 2
|
||||
/* limits used for validate env var XRDP_GFX_FRAMES_IN_FLIGHT */
|
||||
#define MIN_XRDP_GFX_FRAMES_IN_FLIGHT 1
|
||||
#define MAX_XRDP_GFX_FRAMES_IN_FLIGHT 16
|
||||
|
||||
#define DEFAULT_XRDP_GFX_MAX_COMPRESSED_BYTES (3 * 1024 * 1024)
|
||||
/* limits used for validate env var XRDP_GFX_MAX_COMPRESSED_BYTES */
|
||||
#define MIN_XRDP_GFX_MAX_COMPRESSED_BYTES (64 * 1024)
|
||||
#define MAX_XRDP_GFX_MAX_COMPRESSED_BYTES (256 * 1024 * 1024)
|
||||
|
||||
#define XRDP_SURCMD_PREFIX_BYTES 256
|
||||
#define OUT_DATA_BYTES_DEFAULT_SIZE (16 * 1024 * 1024)
|
||||
|
||||
|
@ -85,40 +96,6 @@ xrdp_enc_data_done_destructor(void *item, void *closure)
|
|||
g_free(enc_done);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static unsigned int
|
||||
get_largest_monitor_pixels(struct xrdp_mm *mm)
|
||||
{
|
||||
unsigned int max_pixels;
|
||||
|
||||
struct xrdp_client_info *client_info = mm->wm->client_info;
|
||||
struct display_size_description *display_sizes;
|
||||
display_sizes = &client_info->display_sizes;
|
||||
|
||||
if (display_sizes->monitorCount < 1)
|
||||
{
|
||||
max_pixels = display_sizes->session_width *
|
||||
display_sizes->session_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
max_pixels = 0;
|
||||
struct monitor_info *minfo = display_sizes->minfo;
|
||||
unsigned int i;
|
||||
for (i = 0 ; i < display_sizes->monitorCount; ++i)
|
||||
{
|
||||
unsigned int pixels = (minfo[i].right + 1) - minfo[i].left;
|
||||
pixels *= (minfo[i].bottom + 1) - minfo[i].top;
|
||||
if (pixels > max_pixels)
|
||||
{
|
||||
max_pixels = pixels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max_pixels;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
struct xrdp_encoder *
|
||||
xrdp_encoder_create(struct xrdp_mm *mm)
|
||||
|
@ -223,10 +200,44 @@ xrdp_encoder_create(struct xrdp_mm *mm)
|
|||
self->xrdp_encoder_term = g_create_wait_obj(buf);
|
||||
if (client_info->gfx)
|
||||
{
|
||||
// Assume compressor needs to cope with largest monitor with
|
||||
// ineffective compression
|
||||
self->frames_in_flight = 2;
|
||||
self->max_compressed_bytes = get_largest_monitor_pixels(mm) * 4;
|
||||
const char *env_var = g_getenv("XRDP_GFX_FRAMES_IN_FLIGHT");
|
||||
self->frames_in_flight = DEFAULT_XRDP_GFX_FRAMES_IN_FLIGHT;
|
||||
if (env_var != NULL)
|
||||
{
|
||||
int fif = g_atoix(env_var);
|
||||
if (fif >= MIN_XRDP_GFX_FRAMES_IN_FLIGHT &&
|
||||
fif <= MAX_XRDP_GFX_FRAMES_IN_FLIGHT)
|
||||
{
|
||||
self->frames_in_flight = fif;
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
|
||||
"XRDP_GFX_FRAMES_IN_FLIGHT set to %d", fif);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
|
||||
"XRDP_GFX_FRAMES_IN_FLIGHT set but invalid %s",
|
||||
env_var);
|
||||
}
|
||||
}
|
||||
env_var = g_getenv("XRDP_GFX_MAX_COMPRESSED_BYTES");
|
||||
self->max_compressed_bytes = DEFAULT_XRDP_GFX_MAX_COMPRESSED_BYTES;
|
||||
if (env_var != NULL)
|
||||
{
|
||||
int mcb = g_atoix(env_var);
|
||||
if (mcb >= MIN_XRDP_GFX_MAX_COMPRESSED_BYTES &&
|
||||
mcb <= MAX_XRDP_GFX_MAX_COMPRESSED_BYTES)
|
||||
{
|
||||
self->max_compressed_bytes = mcb;
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
|
||||
"XRDP_GFX_MAX_COMPRESSED_BYTES set to %d", mcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
|
||||
"XRDP_GFX_MAX_COMPRESSED_BYTES set but invalid %s",
|
||||
env_var);
|
||||
}
|
||||
}
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "Using %d max_compressed_bytes for encoder",
|
||||
self->max_compressed_bytes);
|
||||
}
|
||||
|
@ -563,16 +574,50 @@ process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||
|
||||
#ifdef XRDP_RFXCODEC
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
gfx_send_done(struct xrdp_encoder *self, XRDP_ENC_DATA *enc,
|
||||
int comp_bytes, int pad_bytes, char *comp_pad_data,
|
||||
int got_frame_id, int frame_id, int is_last)
|
||||
|
||||
{
|
||||
XRDP_ENC_DATA_DONE *enc_done;
|
||||
|
||||
enc_done = g_new0(XRDP_ENC_DATA_DONE, 1);
|
||||
if (enc_done == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_GFX_BIT);
|
||||
enc_done->enc = enc;
|
||||
enc_done->last = is_last;
|
||||
enc_done->pad_bytes = pad_bytes;
|
||||
enc_done->comp_bytes = comp_bytes;
|
||||
enc_done->comp_pad_data = comp_pad_data;
|
||||
if (got_frame_id)
|
||||
{
|
||||
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_FRAME_ID_BIT);
|
||||
enc_done->frame_id = frame_id;
|
||||
}
|
||||
/* inform main thread done */
|
||||
tc_mutex_lock(self->mutex);
|
||||
fifo_add_item(self->fifo_processed, enc_done);
|
||||
tc_mutex_unlock(self->mutex);
|
||||
/* signal completion for main thread */
|
||||
g_set_wait_obj(self->xrdp_encoder_event_processed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static struct stream *
|
||||
gfx_wiretosurface1(struct xrdp_encoder *self,
|
||||
struct xrdp_egfx_bulk *bulk, struct stream *in_s,
|
||||
struct xrdp_enc_gfx_cmd *enc_gfx_cmd)
|
||||
XRDP_ENC_DATA *enc)
|
||||
{
|
||||
(void)self;
|
||||
(void)bulk;
|
||||
(void)in_s;
|
||||
(void)enc_gfx_cmd;
|
||||
(void)enc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -580,7 +625,7 @@ gfx_wiretosurface1(struct xrdp_encoder *self,
|
|||
static struct stream *
|
||||
gfx_wiretosurface2(struct xrdp_encoder *self,
|
||||
struct xrdp_egfx_bulk *bulk, struct stream *in_s,
|
||||
struct xrdp_enc_gfx_cmd *enc_gfx_cmd)
|
||||
XRDP_ENC_DATA *enc)
|
||||
{
|
||||
int index;
|
||||
int surface_id;
|
||||
|
@ -598,10 +643,10 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
|
|||
int bitmap_data_length;
|
||||
struct rfx_tile *tiles;
|
||||
struct rfx_rect *rfxrects;
|
||||
int tiles_compressed;
|
||||
int flags;
|
||||
int total_tiles;
|
||||
int tiles_written;
|
||||
int do_free;
|
||||
int do_send;
|
||||
int mon_index;
|
||||
|
||||
if (!s_check_rem(in_s, 15))
|
||||
|
@ -687,21 +732,11 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
|
|||
RFX_FLAGS_RLGR1 | RFX_FLAGS_PRO1);
|
||||
if (self->codec_handle_prfx_gfx[mon_index] == NULL)
|
||||
{
|
||||
g_free(tiles);
|
||||
g_free(rfxrects);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
do_free = 0;
|
||||
do_send = 0;
|
||||
if (ENC_IS_BIT_SET(flags, 0))
|
||||
{
|
||||
/* already compressed */
|
||||
bitmap_data_length = enc_gfx_cmd->data_bytes;
|
||||
bitmap_data = enc_gfx_cmd->data;
|
||||
do_send = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap_data_length = self->max_compressed_bytes;
|
||||
bitmap_data = g_new(char, bitmap_data_length);
|
||||
if (bitmap_data == NULL)
|
||||
|
@ -710,35 +745,58 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
|
|||
g_free(rfxrects);
|
||||
return NULL;
|
||||
}
|
||||
do_free = 1;
|
||||
tiles_written = rfxcodec_encode(self->codec_handle_prfx_gfx[mon_index],
|
||||
rv = NULL;
|
||||
tiles_written = 0;
|
||||
total_tiles = num_rects_c;
|
||||
for (;;)
|
||||
{
|
||||
tiles_compressed =
|
||||
rfxcodec_encode(self->codec_handle_prfx_gfx[mon_index],
|
||||
bitmap_data,
|
||||
&bitmap_data_length,
|
||||
enc_gfx_cmd->data,
|
||||
enc->u.gfx.data,
|
||||
width, height,
|
||||
((width + 63) & ~63) * 4,
|
||||
rfxrects, num_rects_d,
|
||||
tiles, num_rects_c,
|
||||
tiles + tiles_written, total_tiles - tiles_written,
|
||||
self->quants, self->num_quants);
|
||||
if (tiles_written > 0)
|
||||
if (tiles_compressed < 1)
|
||||
{
|
||||
do_send = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_free(tiles);
|
||||
g_free(rfxrects);
|
||||
rv = NULL;
|
||||
if (do_send)
|
||||
{
|
||||
tiles_written += tiles_compressed;
|
||||
rv = xrdp_egfx_wire_to_surface2(bulk, surface_id,
|
||||
codec_id, codec_context_id,
|
||||
pixel_format,
|
||||
bitmap_data, bitmap_data_length);
|
||||
}
|
||||
if (do_free)
|
||||
if (rv == NULL)
|
||||
{
|
||||
g_free(bitmap_data);
|
||||
break;
|
||||
}
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR, "gfx_wiretosurface2: "
|
||||
"tiles_compressed %d total_tiles %d tiles_written %d",
|
||||
tiles_compressed, total_tiles,
|
||||
tiles_written);
|
||||
if (tiles_written >= total_tiles)
|
||||
{
|
||||
/* ok, done with last tile set */
|
||||
break;
|
||||
}
|
||||
/* we have another tile set, send this one to main thread */
|
||||
if (gfx_send_done(self, enc, (int)(rv->end - rv->data), 0,
|
||||
rv->data, 0, 0, 0) != 0)
|
||||
{
|
||||
free_stream(rv);
|
||||
rv = NULL;
|
||||
break;
|
||||
}
|
||||
g_free(rv); /* don't call free_stream() here so s->data is valid */
|
||||
rv = NULL;
|
||||
bitmap_data_length = self->max_compressed_bytes;
|
||||
}
|
||||
g_free(tiles);
|
||||
g_free(rfxrects);
|
||||
g_free(bitmap_data);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -939,20 +997,14 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||
struct stream *s;
|
||||
struct stream in_s;
|
||||
struct xrdp_egfx_bulk *bulk;
|
||||
XRDP_ENC_DATA_DONE *enc_done;
|
||||
struct fifo *fifo_processed;
|
||||
tbus mutex;
|
||||
tbus event_processed;
|
||||
int cmd_id;
|
||||
int cmd_bytes;
|
||||
int frame_id;
|
||||
int got_frame_id;
|
||||
int error;
|
||||
char *holdp;
|
||||
char *holdend;
|
||||
|
||||
fifo_processed = self->fifo_processed;
|
||||
mutex = self->mutex;
|
||||
event_processed = self->xrdp_encoder_event_processed;
|
||||
bulk = self->mm->egfx->bulk;
|
||||
g_memset(&in_s, 0, sizeof(in_s));
|
||||
in_s.data = enc->u.gfx.cmd;
|
||||
|
@ -977,10 +1029,10 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||
switch (cmd_id)
|
||||
{
|
||||
case XR_RDPGFX_CMDID_WIRETOSURFACE_1: /* 0x0001 */
|
||||
s = gfx_wiretosurface1(self, bulk, &in_s, &(enc->u.gfx));
|
||||
s = gfx_wiretosurface1(self, bulk, &in_s, enc);
|
||||
break;
|
||||
case XR_RDPGFX_CMDID_WIRETOSURFACE_2: /* 0x0002 */
|
||||
s = gfx_wiretosurface2(self, bulk, &in_s, &(enc->u.gfx));
|
||||
s = gfx_wiretosurface2(self, bulk, &in_s, enc);
|
||||
break;
|
||||
case XR_RDPGFX_CMDID_SOLIDFILL: /* 0x0004 */
|
||||
s = gfx_solidfill(self, bulk, &in_s);
|
||||
|
@ -1010,38 +1062,24 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (s == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "process_enc_egfx: cmd_id %d s = nil", cmd_id);
|
||||
return 1;
|
||||
}
|
||||
/* setup for next cmd */
|
||||
in_s.p = holdp + cmd_bytes;
|
||||
in_s.end = holdend;
|
||||
/* setup enc_done struct */
|
||||
enc_done = g_new0(XRDP_ENC_DATA_DONE, 1);
|
||||
if (enc_done == NULL)
|
||||
if (s != NULL)
|
||||
{
|
||||
/* send message to main thread */
|
||||
error = gfx_send_done(self, enc, (int) (s->end - s->data),
|
||||
0, s->data, got_frame_id, frame_id,
|
||||
!s_check_rem(&in_s, 8));
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "process_enc_egfx: gfx_send_done failed "
|
||||
"error %d", error);
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_GFX_BIT);
|
||||
enc_done->enc = enc;
|
||||
enc_done->last = !s_check_rem(&in_s, 8);
|
||||
enc_done->comp_bytes = (int) (s->end - s->data);
|
||||
enc_done->comp_pad_data = s->data;
|
||||
if (got_frame_id)
|
||||
{
|
||||
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_FRAME_ID_BIT);
|
||||
enc_done->frame_id = frame_id;
|
||||
}
|
||||
g_free(s); /* don't call free_stream() here so s->data is valid */
|
||||
/* inform main thread done */
|
||||
tc_mutex_lock(mutex);
|
||||
fifo_add_item(fifo_processed, enc_done);
|
||||
tc_mutex_unlock(mutex);
|
||||
/* signal completion for main thread */
|
||||
g_set_wait_obj(event_processed);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue