Encode on worker threads
parent
70b2448c6e
commit
7d4af0e741
|
@ -43,7 +43,7 @@ void on_fb_req(struct nvnc_client *client, bool incremental, uint16_t x, uint16_
|
||||||
struct pixman_region16 region;
|
struct pixman_region16 region;
|
||||||
pixman_region_init_rect(®ion, 0, 0, draw->fb.width,
|
pixman_region_init_rect(®ion, 0, 0, draw->fb.width,
|
||||||
draw->fb.height);
|
draw->fb.height);
|
||||||
nvnc_update_fb(server, &draw->fb, ®ion);
|
nvnc_update_fb(server, &draw->fb, ®ion, NULL);
|
||||||
pixman_region_fini(®ion);
|
pixman_region_fini(®ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ void on_pointer_event(struct nvnc_client *client, uint16_t x, uint16_t y,
|
||||||
pixman_region_init_rect(®ion, 0, 0, draw->fb.width,
|
pixman_region_init_rect(®ion, 0, 0, draw->fb.width,
|
||||||
draw->fb.height);
|
draw->fb.height);
|
||||||
pixman_region_intersect_rect(®ion, ®ion, x, y, 1, 1);
|
pixman_region_intersect_rect(®ion, ®ion, x, y, 1, 1);
|
||||||
nvnc_update_fb(server, &draw->fb, ®ion);
|
nvnc_update_fb(server, &draw->fb, ®ion, NULL);
|
||||||
pixman_region_fini(®ion);
|
pixman_region_fini(®ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ void on_fb_req(struct nvnc_client *client, bool incremental,
|
||||||
|
|
||||||
struct pixman_region16 region;
|
struct pixman_region16 region;
|
||||||
pixman_region_init_rect(®ion, 0, 0, fb->width, fb->height);
|
pixman_region_init_rect(®ion, 0, 0, fb->width, fb->height);
|
||||||
nvnc_update_fb(server, fb, ®ion);
|
nvnc_update_fb(server, fb, ®ion, NULL);
|
||||||
pixman_region_fini(®ion);
|
pixman_region_fini(®ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ typedef void (*nvnc_fb_req_fn)(struct nvnc_client*, bool is_incremental,
|
||||||
uint16_t width, uint16_t height);
|
uint16_t width, uint16_t height);
|
||||||
typedef void (*nvnc_client_fn)(struct nvnc_client*);
|
typedef void (*nvnc_client_fn)(struct nvnc_client*);
|
||||||
typedef void (*nvnc_damage_fn)(struct pixman_region16 *damage, void *userdata);
|
typedef void (*nvnc_damage_fn)(struct pixman_region16 *damage, void *userdata);
|
||||||
|
typedef void (*nvnc_update_done_fn)(struct nvnc*);
|
||||||
|
|
||||||
struct nvnc *nvnc_open(const char *addr, uint16_t port);
|
struct nvnc *nvnc_open(const char *addr, uint16_t port);
|
||||||
void nvnc_close(struct nvnc *self);
|
void nvnc_close(struct nvnc *self);
|
||||||
|
@ -80,7 +81,8 @@ void nvnc_set_client_cleanup_fn(struct nvnc_client *self, nvnc_client_fn fn);
|
||||||
* Only the region specified by the region argument is updated.
|
* Only the region specified by the region argument is updated.
|
||||||
*/
|
*/
|
||||||
int nvnc_update_fb(struct nvnc *self, const struct nvnc_fb* fb,
|
int nvnc_update_fb(struct nvnc *self, const struct nvnc_fb* fb,
|
||||||
const struct pixman_region16* region);
|
const struct pixman_region16* region,
|
||||||
|
nvnc_update_done_fn on_update_done);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the regions that differ between fb0 and fb1. Regions outside the hinted
|
* Find the regions that differ between fb0 and fb1. Regions outside the hinted
|
||||||
|
|
100
src/server.c
100
src/server.c
|
@ -28,6 +28,7 @@
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
#include <libdrm/drm_fourcc.h>
|
#include <libdrm/drm_fourcc.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#ifndef DRM_FORMAT_INVALID
|
#ifndef DRM_FORMAT_INVALID
|
||||||
#define DRM_FORMAT_INVALID 0
|
#define DRM_FORMAT_INVALID 0
|
||||||
|
@ -100,12 +101,23 @@ struct nvnc {
|
||||||
struct nvnc_client_list clients;
|
struct nvnc_client_list clients;
|
||||||
struct vnc_display display;
|
struct vnc_display display;
|
||||||
void *userdata;
|
void *userdata;
|
||||||
|
int n_pending_updates;
|
||||||
nvnc_key_fn key_fn;
|
nvnc_key_fn key_fn;
|
||||||
nvnc_pointer_fn pointer_fn;
|
nvnc_pointer_fn pointer_fn;
|
||||||
nvnc_fb_req_fn fb_req_fn;
|
nvnc_fb_req_fn fb_req_fn;
|
||||||
nvnc_client_fn new_client_fn;
|
nvnc_client_fn new_client_fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fb_update_work {
|
||||||
|
uv_work_t work;
|
||||||
|
struct nvnc_client *client;
|
||||||
|
struct pixman_region16 region;
|
||||||
|
struct rfb_pixel_format server_fmt;
|
||||||
|
struct vec frame;
|
||||||
|
const struct nvnc_fb *fb;
|
||||||
|
nvnc_update_done_fn on_done;
|
||||||
|
};
|
||||||
|
|
||||||
static const char* fourcc_to_string(uint32_t fourcc)
|
static const char* fourcc_to_string(uint32_t fourcc)
|
||||||
{
|
{
|
||||||
static char buffer[5];
|
static char buffer[5];
|
||||||
|
@ -784,9 +796,78 @@ static void free_write_buffer(uv_write_t *req, int status)
|
||||||
free(rq->buffer.base);
|
free(rq->buffer.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_client_update_fb(uv_work_t *work)
|
||||||
|
{
|
||||||
|
struct fb_update_work *update = (void*)work;
|
||||||
|
struct nvnc_client *client = update->client;
|
||||||
|
const struct nvnc_fb *fb = update->fb;
|
||||||
|
|
||||||
|
zrle_encode_frame(&client->z_stream, &update->frame, &client->pixfmt,
|
||||||
|
fb, &update->server_fmt, &update->region);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_client_update_fb_done(uv_work_t *work, int status)
|
||||||
|
{
|
||||||
|
(void)status;
|
||||||
|
|
||||||
|
struct fb_update_work *update = (void*)work;
|
||||||
|
struct nvnc_client *client = update->client;
|
||||||
|
struct nvnc *server = client->server;
|
||||||
|
struct vec *frame = &update->frame;
|
||||||
|
|
||||||
|
vnc__write((uv_stream_t*)&client->stream_handle,
|
||||||
|
frame->data, frame->len, free_write_buffer);
|
||||||
|
|
||||||
|
if (--server->n_pending_updates == 0)
|
||||||
|
if (update->on_done)
|
||||||
|
update->on_done(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
int schedule_client_update_fb(struct nvnc_client *client,
|
||||||
|
const struct nvnc_fb *fb,
|
||||||
|
struct pixman_region16 *region,
|
||||||
|
nvnc_update_done_fn on_update_done)
|
||||||
|
{
|
||||||
|
struct fb_update_work *work = calloc(1, sizeof(*work));
|
||||||
|
if (!work)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (rfb_pixfmt_from_fourcc(&work->server_fmt, fb->fourcc_format) < 0)
|
||||||
|
goto pixfmt_failure;
|
||||||
|
|
||||||
|
work->client = client;
|
||||||
|
work->fb = fb;
|
||||||
|
work->on_done = on_update_done;
|
||||||
|
|
||||||
|
/* The client's region is exchanged for an empty one */
|
||||||
|
work->region = client->requested_region;
|
||||||
|
pixman_region_init(&client->requested_region);
|
||||||
|
|
||||||
|
int rc = vec_init(&work->frame, fb->width * fb->height * 3 / 2);
|
||||||
|
if (rc < 0)
|
||||||
|
goto vec_failure;
|
||||||
|
|
||||||
|
rc = uv_queue_work(uv_default_loop(), &work->work, do_client_update_fb,
|
||||||
|
on_client_update_fb_done);
|
||||||
|
if (rc < 0)
|
||||||
|
goto queue_failure;
|
||||||
|
|
||||||
|
client->server->n_pending_updates++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
queue_failure:
|
||||||
|
vec_destroy(&work->frame);
|
||||||
|
vec_failure:
|
||||||
|
pixfmt_failure:
|
||||||
|
free(work);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT
|
EXPORT
|
||||||
int nvnc_update_fb(struct nvnc *self, const struct nvnc_fb *fb,
|
int nvnc_update_fb(struct nvnc *self, const struct nvnc_fb *fb,
|
||||||
const struct pixman_region16 *input_region)
|
const struct pixman_region16 *input_region,
|
||||||
|
nvnc_update_done_fn on_update_done)
|
||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
|
@ -794,8 +875,8 @@ int nvnc_update_fb(struct nvnc *self, const struct nvnc_fb *fb,
|
||||||
if (fb->fourcc_modifier != DRM_FORMAT_MOD_LINEAR)
|
if (fb->fourcc_modifier != DRM_FORMAT_MOD_LINEAR)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
struct rfb_pixel_format server_fmt;
|
/* Scheduling new updates would cause racing */
|
||||||
if (rfb_pixfmt_from_fourcc(&server_fmt, fb->fourcc_format) < 0)
|
if (self->n_pending_updates > 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
struct pixman_region16 region;
|
struct pixman_region16 region;
|
||||||
|
@ -818,18 +899,7 @@ int nvnc_update_fb(struct nvnc *self, const struct nvnc_fb *fb,
|
||||||
if (!pixman_region_not_empty(cregion))
|
if (!pixman_region_not_empty(cregion))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
struct vec frame;
|
schedule_client_update_fb(client, fb, ®ion, on_update_done);
|
||||||
rc = vec_init(&frame, fb->width * fb->height * 3 / 2);
|
|
||||||
if (rc < 0)
|
|
||||||
goto failure;
|
|
||||||
|
|
||||||
zrle_encode_frame(&client->z_stream, &frame, &client->pixfmt,
|
|
||||||
fb, &server_fmt, cregion);
|
|
||||||
|
|
||||||
pixman_region_clear(cregion);
|
|
||||||
|
|
||||||
vnc__write((uv_stream_t*)&client->stream_handle, frame.data,
|
|
||||||
frame.len, free_write_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
Loading…
Reference in New Issue