backend-rdp: Add renderbuffer's discarded event support

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
This commit is contained in:
Loïc Molinari 2024-08-02 09:33:36 +02:00
parent f2fc277fb2
commit a2e6086bc6
2 changed files with 123 additions and 98 deletions

View file

@ -58,6 +58,12 @@
extern PWtsApiFunctionTable FreeRDP_InitWtsApi(void);
static struct rdp_buffer *
rdp_buffer_create(struct rdp_output *output);
static void
rdp_buffer_destroy(struct rdp_buffer *buffer);
static BOOL
xf_peer_adjust_monitor_layout(freerdp_peer *client);
@ -261,11 +267,11 @@ rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer)
rdpSettings *settings = peer->context->settings;
if (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec))
rdp_peer_refresh_rfx(region, output->shadow_surface, peer);
rdp_peer_refresh_rfx(region, output->buffer->shadow_surface, peer);
else if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
rdp_peer_refresh_nsc(region, output->shadow_surface, peer);
rdp_peer_refresh_nsc(region, output->buffer->shadow_surface, peer);
else
rdp_peer_refresh_raw(region, output->shadow_surface, peer);
rdp_peer_refresh_raw(region, output->buffer->shadow_surface, peer);
}
static int
@ -295,7 +301,7 @@ rdp_output_repaint(struct weston_output *output_base)
weston_output_flush_damage_for_primary_plane(output_base, &damage);
ec->renderer->repaint_output(&output->base, &damage,
output->renderbuffer);
output->buffer->rb);
if (pixman_region32_not_empty(&damage)) {
pixman_region32_t transformed_damage;
@ -346,52 +352,15 @@ rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode)
struct weston_output *output = base;
struct rdp_peers_item *rdpPeer;
rdpSettings *settings;
weston_renderbuffer_t new_renderbuffer;
mode->refresh = b->rdp_monitor_refresh_rate;
weston_output_set_single_mode(base, mode);
if (base->enabled) {
const struct weston_renderer *renderer;
pixman_image_t *new_image;
if (base->enabled)
weston_renderer_resize_output(output, &(struct weston_size){
.width = output->current_mode->width,
.height = output->current_mode->height }, NULL);
new_image = pixman_image_create_bits(b->formats[0]->pixman_format,
mode->width, mode->height,
NULL, mode->width * 4);
renderer = b->compositor->renderer;
switch (renderer->type) {
case WESTON_RENDERER_PIXMAN: {
const struct pixman_renderer_interface *pixman;
pixman = renderer->pixman;
new_renderbuffer =
pixman->create_image_from_ptr(output, b->formats[0],
mode->width, mode->height,
pixman_image_get_data(new_image),
mode->width * 4,
NULL, NULL);
break;
}
case WESTON_RENDERER_GL:
new_renderbuffer =
renderer->gl->create_fbo(output, b->formats[0],
mode->width, mode->height,
pixman_image_get_data(new_image),
NULL, NULL);
break;
default:
unreachable("cannot have auto renderer at runtime");
}
renderer->destroy_renderbuffer(rdpOutput->renderbuffer);
rdpOutput->renderbuffer = new_renderbuffer;
pixman_image_unref(rdpOutput->shadow_surface);
rdpOutput->shadow_surface = new_image;
}
/* Apparently settings->DesktopWidth is supposed to be primary only.
* For now we only work with a single monitor, so we don't need to
* check that we're primary here.
@ -435,11 +404,104 @@ rdp_head_get_monitor(struct weston_head *base,
monitor->desktop_scale = h->config.attributes.desktopScaleFactor;
}
static bool
rdp_rb_discarded_cb(weston_renderbuffer_t rb, void *data)
{
struct rdp_buffer *buffer = (struct rdp_buffer *) data;
struct rdp_output *output = buffer->output;
rdp_buffer_destroy(buffer);
output->buffer = rdp_buffer_create(output);
if (output->buffer == NULL)
return false;
return true;
}
static struct rdp_buffer *
rdp_buffer_create(struct rdp_output *output)
{
const struct pixel_format_info *format = output->backend->formats[0];
struct weston_renderer *rdr = output->base.compositor->renderer;
pixman_image_t *shadow_surface;
weston_renderbuffer_t rb;
struct rdp_buffer *buffer;
shadow_surface = pixman_image_create_bits(format->pixman_format,
output->base.current_mode->width,
output->base.current_mode->height,
NULL,
output->base.current_mode->width * 4);
buffer = xmalloc(sizeof *buffer);
switch (rdr->type) {
case WESTON_RENDERER_PIXMAN: {
rb = rdr->pixman->create_image_from_ptr(&output->base, format,
output->base.current_mode->width,
output->base.current_mode->height,
pixman_image_get_data(shadow_surface),
output->base.current_mode->width * 4,
rdp_rb_discarded_cb,
buffer);
break;
}
case WESTON_RENDERER_GL: {
rb = rdr->gl->create_fbo(&output->base, format,
output->base.current_mode->width,
output->base.current_mode->height,
pixman_image_get_data(shadow_surface),
rdp_rb_discarded_cb, buffer);
break;
}
default:
unreachable("cannot have auto renderer at runtime");
}
if (rb == NULL) {
weston_log("Failed to create offscreen renderbuffer.\n");
pixman_image_unref(shadow_surface);
free(buffer);
return NULL;
}
buffer->output = output;
buffer->shadow_surface = shadow_surface;
buffer->rb = rb;
return buffer;
}
static void
rdp_buffer_destroy(struct rdp_buffer *buffer)
{
struct weston_renderer *rdr = buffer->output->base.compositor->renderer;
pixman_image_unref(buffer->shadow_surface);
rdr->destroy_renderbuffer(buffer->rb);
free(buffer);
}
static void
rdp_renderer_output_destroy(struct weston_output *base)
{
struct weston_renderer *rdr = base->compositor->renderer;
switch (rdr->type) {
case WESTON_RENDERER_PIXMAN:
rdr->pixman->output_destroy(base);
break;
case WESTON_RENDERER_GL:
rdr->gl->output_destroy(base);
break;
default:
unreachable("cannot have auto renderer at runtime");
}
}
static int
rdp_output_enable(struct weston_output *base)
{
const struct weston_renderer *renderer = base->compositor->renderer;
const struct pixman_renderer_interface *pixman = renderer->pixman;
struct rdp_output *output = to_rdp_output(base);
struct rdp_backend *b;
struct wl_event_loop *loop;
@ -448,12 +510,6 @@ rdp_output_enable(struct weston_output *base)
b = output->backend;
output->shadow_surface = pixman_image_create_bits(b->formats[0]->pixman_format,
output->base.current_mode->width,
output->base.current_mode->height,
NULL,
output->base.current_mode->width * 4);
switch (renderer->type) {
case WESTON_RENDERER_PIXMAN: {
const struct pixman_renderer_output_options options = {
@ -464,24 +520,8 @@ rdp_output_enable(struct weston_output *base)
.format = b->formats[0],
};
if (renderer->pixman->output_create(&output->base, &options) < 0) {
if (renderer->pixman->output_create(&output->base, &options) < 0)
return -1;
}
output->renderbuffer =
pixman->create_image_from_ptr(&output->base, options.format,
output->base.current_mode->width,
output->base.current_mode->height,
pixman_image_get_data(output->shadow_surface),
output->base.current_mode->width * 4,
NULL, NULL);
if (output->renderbuffer == NULL) {
weston_log("Failed to create surface for frame buffer.\n");
renderer->pixman->output_destroy(&output->base);
pixman_image_unref(output->shadow_surface);
output->shadow_surface = NULL;
return -1;
}
break;
}
case WESTON_RENDERER_GL: {
@ -496,20 +536,7 @@ rdp_output_enable(struct weston_output *base)
},
};
if (renderer->gl->output_fbo_create(&output->base, &options) < 0)
return -1;
output->renderbuffer =
renderer->gl->create_fbo(&output->base, b->formats[0],
output->base.current_mode->width,
output->base.current_mode->height,
pixman_image_get_data(output->shadow_surface),
NULL, NULL);
if (output->renderbuffer == NULL) {
weston_log("Failed to create surface for frame buffer.\n");
renderer->pixman->output_destroy(&output->base);
pixman_image_unref(output->shadow_surface);
output->shadow_surface = NULL;
if (renderer->gl->output_fbo_create(&output->base, &options) < 0) {
return -1;
}
break;
@ -518,6 +545,12 @@ rdp_output_enable(struct weston_output *base)
unreachable("cannot have auto renderer at runtime");
}
output->buffer = rdp_buffer_create(output);
if (output->buffer == NULL) {
rdp_renderer_output_destroy(base);
return -1;
}
loop = wl_display_get_event_loop(b->compositor->wl_display);
output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
@ -527,7 +560,6 @@ rdp_output_enable(struct weston_output *base)
static int
rdp_output_disable(struct weston_output *base)
{
struct weston_renderer *renderer = base->compositor->renderer;
struct rdp_output *output = to_rdp_output(base);
assert(output);
@ -535,21 +567,9 @@ rdp_output_disable(struct weston_output *base)
if (!output->base.enabled)
return 0;
renderer->destroy_renderbuffer(output->renderbuffer);
output->renderbuffer = NULL;
switch (renderer->type) {
case WESTON_RENDERER_PIXMAN:
renderer->pixman->output_destroy(&output->base);
break;
case WESTON_RENDERER_GL:
renderer->gl->output_destroy(&output->base);
break;
default:
unreachable("cannot have auto renderer at runtime");
}
pixman_image_unref(output->shadow_surface);
output->shadow_surface = NULL;
rdp_buffer_destroy(output->buffer);
output->buffer = NULL;
rdp_renderer_output_destroy(base);
wl_event_source_remove(output->finish_frame_timer);
return 0;

View file

@ -146,12 +146,17 @@ struct rdp_head {
rdpMonitor config;
};
struct rdp_buffer {
struct rdp_output *output;
pixman_image_t *shadow_surface;
weston_renderbuffer_t rb;
};
struct rdp_output {
struct weston_output base;
struct rdp_backend *backend;
struct wl_event_source *finish_frame_timer;
weston_renderbuffer_t renderbuffer;
pixman_image_t *shadow_surface;
struct rdp_buffer *buffer;
};
struct rdp_peer_context {