Redesign update/rendering loop
Every change to the framebuffer is now copied into a single buffer inside a single callback. This simplifies things a lot, and might even perform better.pull/32/head
parent
b39655df15
commit
58a181ccbc
154
src/main.c
154
src/main.c
|
@ -67,7 +67,6 @@ enum frame_capture_backend_type {
|
||||||
|
|
||||||
struct wayvnc {
|
struct wayvnc {
|
||||||
bool do_exit;
|
bool do_exit;
|
||||||
bool please_send_full_frame_next;
|
|
||||||
|
|
||||||
struct wl_display* display;
|
struct wl_display* display;
|
||||||
struct wl_registry* registry;
|
struct wl_registry* registry;
|
||||||
|
@ -95,30 +94,16 @@ struct wayvnc {
|
||||||
struct aml_signal* signal_handler;
|
struct aml_signal* signal_handler;
|
||||||
|
|
||||||
struct nvnc* nvnc;
|
struct nvnc* nvnc;
|
||||||
|
struct nvnc_fb* buffer;
|
||||||
|
|
||||||
struct nvnc_fb* fb[2];
|
struct pixman_region16 current_damage;
|
||||||
int fb_index;
|
|
||||||
|
|
||||||
const char* kb_layout;
|
const char* kb_layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
void wayvnc_exit(struct wayvnc* self);
|
void wayvnc_exit(struct wayvnc* self);
|
||||||
void on_capture_done(struct frame_capture* capture);
|
void on_capture_done(struct frame_capture* capture);
|
||||||
|
static void on_render(struct nvnc* nvnc, struct nvnc_fb* fb);
|
||||||
static struct nvnc_fb* get_current_fb(struct wayvnc* self)
|
|
||||||
{
|
|
||||||
return self->fb[self->fb_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct nvnc_fb* get_last_fb(struct wayvnc* self)
|
|
||||||
{
|
|
||||||
return self->fb[!self->fb_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void swap_fbs(struct wayvnc* self)
|
|
||||||
{
|
|
||||||
self->fb_index ^= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum frame_capture_backend_type
|
static enum frame_capture_backend_type
|
||||||
frame_capture_backend_from_string(const char* str)
|
frame_capture_backend_from_string(const char* str)
|
||||||
|
@ -189,7 +174,7 @@ static void registry_add(void* data, struct wl_registry* registry,
|
||||||
version);
|
version);
|
||||||
self->pointer_manager_version = version;
|
self->pointer_manager_version = version;
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (strcmp(interface, wl_seat_interface.name) == 0) {
|
if (strcmp(interface, wl_seat_interface.name) == 0) {
|
||||||
struct wl_seat* wl_seat =
|
struct wl_seat* wl_seat =
|
||||||
|
@ -437,20 +422,6 @@ bool on_auth(const char* username, const char* password, void* ud)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_fb_req(struct nvnc_client* client, bool is_incremental,
|
|
||||||
uint16_t x, uint16_t y, uint16_t width, uint16_t height)
|
|
||||||
{
|
|
||||||
struct nvnc* nvnc = nvnc_get_server(client);
|
|
||||||
struct wayvnc* self = nvnc_get_userdata(nvnc);
|
|
||||||
|
|
||||||
// TODO: Make this per-client rather than global
|
|
||||||
if (!is_incremental) {
|
|
||||||
self->please_send_full_frame_next = true;
|
|
||||||
frame_capture_stop(self->capture_backend);
|
|
||||||
frame_capture_start(self->capture_backend, CAPTURE_NOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port)
|
int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port)
|
||||||
{
|
{
|
||||||
self->nvnc = nvnc_open(addr, port);
|
self->nvnc = nvnc_open(addr, port);
|
||||||
|
@ -471,7 +442,7 @@ int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port)
|
||||||
output_get_transformed_height(self->selected_output),
|
output_get_transformed_height(self->selected_output),
|
||||||
format);
|
format);
|
||||||
|
|
||||||
nvnc_set_fb_req_fn(self->nvnc, on_fb_req);
|
nvnc_set_render_fn(self->nvnc, on_render);
|
||||||
|
|
||||||
if (self->cfg.enable_auth)
|
if (self->cfg.enable_auth)
|
||||||
nvnc_enable_auth(self->nvnc, self->cfg.private_key_file,
|
nvnc_enable_auth(self->nvnc, self->cfg.private_key_file,
|
||||||
|
@ -491,31 +462,45 @@ int wayvnc_start_capture(struct wayvnc* self, enum frame_capture_options opt)
|
||||||
return frame_capture_start(self->capture_backend, opt);
|
return frame_capture_start(self->capture_backend, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void on_render(struct nvnc* nvnc, struct nvnc_fb* fb)
|
||||||
|
{
|
||||||
|
struct wayvnc* self = nvnc_get_userdata(nvnc);
|
||||||
|
|
||||||
|
struct pixman_box16* ext = pixman_region_extents(&self->current_damage);
|
||||||
|
uint32_t y = ext->y1;
|
||||||
|
uint32_t damage_height = ext->y2 - ext->y1;
|
||||||
|
|
||||||
|
uint32_t* addr = nvnc_fb_get_addr(fb);
|
||||||
|
uint32_t width = nvnc_fb_get_width(fb);
|
||||||
|
|
||||||
|
renderer_read_frame(&self->renderer, addr + y * width, y, damage_height);
|
||||||
|
|
||||||
|
pixman_region_clear(&self->current_damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wayvnc_damage_region(struct wayvnc* self,
|
||||||
|
struct pixman_region16* damage)
|
||||||
|
{
|
||||||
|
pixman_region_union(&self->current_damage, &self->current_damage, damage);
|
||||||
|
nvnc_damage_region(self->nvnc, damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wayvnc_damage_whole(struct wayvnc* self)
|
||||||
|
{
|
||||||
|
uint16_t width = nvnc_fb_get_width(self->buffer);
|
||||||
|
uint16_t height = nvnc_fb_get_height(self->buffer);
|
||||||
|
|
||||||
|
struct pixman_region16 damage;
|
||||||
|
pixman_region_init_rect(&damage, 0, 0, width, height);
|
||||||
|
wayvnc_damage_region(self, &damage);
|
||||||
|
pixman_region_fini(&damage);
|
||||||
|
}
|
||||||
|
|
||||||
static void on_damage_check_done(struct pixman_region16* damage, void* userdata)
|
static void on_damage_check_done(struct pixman_region16* damage, void* userdata)
|
||||||
{
|
{
|
||||||
struct wayvnc* self = userdata;
|
struct wayvnc* self = userdata;
|
||||||
|
|
||||||
if (pixman_region_not_empty(damage)) {
|
wayvnc_damage_region(self, damage);
|
||||||
struct pixman_box16* ext = pixman_region_extents(damage);
|
|
||||||
uint32_t y = ext->y1;
|
|
||||||
uint32_t damage_height = ext->y2 - ext->y1;
|
|
||||||
|
|
||||||
struct nvnc_fb* fb = get_current_fb(self);
|
|
||||||
uint32_t* addr = nvnc_fb_get_addr(fb);
|
|
||||||
uint32_t fb_width = nvnc_fb_get_width(fb);
|
|
||||||
|
|
||||||
renderer_read_frame(&self->renderer, addr + y * fb_width, y,
|
|
||||||
damage_height);
|
|
||||||
|
|
||||||
nvnc_fb_set_flags(fb, nvnc_fb_get_flags(fb) | NVNC_FB_PARTIAL);
|
|
||||||
|
|
||||||
nvnc_fb_unlock(fb);
|
|
||||||
|
|
||||||
nvnc_feed_frame(self->nvnc, fb, damage);
|
|
||||||
swap_fbs(self);
|
|
||||||
} else {
|
|
||||||
nvnc_fb_unlock(get_current_fb(self));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wayvnc_start_capture(self, 0) < 0) {
|
if (wayvnc_start_capture(self, 0) < 0) {
|
||||||
log_error("Failed to start capture. Exiting...\n");
|
log_error("Failed to start capture. Exiting...\n");
|
||||||
|
@ -530,44 +515,22 @@ void wayvnc_process_frame(struct wayvnc* self)
|
||||||
uint32_t height = output_get_transformed_height(self->selected_output);
|
uint32_t height = output_get_transformed_height(self->selected_output);
|
||||||
bool is_first_frame = false;
|
bool is_first_frame = false;
|
||||||
|
|
||||||
struct nvnc_fb* fb = get_current_fb(self);
|
if (!self->buffer) {
|
||||||
if (!fb) {
|
self->buffer = nvnc_fb_new(width, height, format);
|
||||||
self->fb[0] = nvnc_fb_new(width, height, format);
|
nvnc_set_buffer(self->nvnc, self->buffer);
|
||||||
self->fb[1] = nvnc_fb_new(width, height, format);
|
|
||||||
fb = get_current_fb(self);
|
|
||||||
is_first_frame = true;
|
is_first_frame = true;
|
||||||
} else {
|
} else {
|
||||||
// TODO: Reallocate
|
// TODO: Reallocate
|
||||||
assert(width == nvnc_fb_get_width(fb));
|
assert(width == nvnc_fb_get_width(self->buffer));
|
||||||
assert(height == nvnc_fb_get_height(fb));
|
assert(height == nvnc_fb_get_height(self->buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if frame is still in use. This can happen when encoding is too
|
struct nvnc_fb* fb = self->buffer;
|
||||||
* slow to keep up with frames being fed to it.
|
|
||||||
*
|
|
||||||
* We'll just add to the frame that was added last if Neat VNC is busy.
|
|
||||||
*
|
|
||||||
* TODO: Damage hints are not being used now, but if they will be used
|
|
||||||
* then this breaks things.
|
|
||||||
*/
|
|
||||||
if (!nvnc_fb_lock(fb)) {
|
|
||||||
log_debug("nvnc_fb %d still in use. Merging frame.\n",
|
|
||||||
self->fb_index);
|
|
||||||
|
|
||||||
struct nvnc_fb* last_fb = get_last_fb(self);
|
|
||||||
if (!nvnc_fb_lock(last_fb)) {
|
|
||||||
log_error("Whole swap chain locked. Dropping frame.\n");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
swap_fbs(self);
|
|
||||||
fb = get_current_fb(self);
|
|
||||||
assert(fb == last_fb);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// TODO: Fix constness on fb in this function
|
||||||
frame_capture_render(self->capture_backend, &self->renderer, fb);
|
frame_capture_render(self->capture_backend, &self->renderer, fb);
|
||||||
|
|
||||||
if (!self->please_send_full_frame_next && !is_first_frame) {
|
if (!is_first_frame) {
|
||||||
uint32_t hint_x = self->capture_backend->damage_hint.x;
|
uint32_t hint_x = self->capture_backend->damage_hint.x;
|
||||||
uint32_t hint_y = self->capture_backend->damage_hint.y;
|
uint32_t hint_y = self->capture_backend->damage_hint.y;
|
||||||
uint32_t hint_width = self->capture_backend->damage_hint.width;
|
uint32_t hint_width = self->capture_backend->damage_hint.width;
|
||||||
|
@ -597,24 +560,12 @@ void wayvnc_process_frame(struct wayvnc* self)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* addr = nvnc_fb_get_addr(fb);
|
wayvnc_damage_whole(self);
|
||||||
renderer_read_frame(&self->renderer, addr, 0, height);
|
|
||||||
nvnc_fb_set_flags(fb, nvnc_fb_get_flags(fb) & ~NVNC_FB_PARTIAL);
|
|
||||||
nvnc_fb_unlock(fb);
|
|
||||||
|
|
||||||
struct pixman_region16 damage;
|
|
||||||
pixman_region_init_rect(&damage, 0, 0, width, height);
|
|
||||||
nvnc_feed_frame(self->nvnc, fb, &damage);
|
|
||||||
swap_fbs(self);
|
|
||||||
pixman_region_fini(&damage);
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (wayvnc_start_capture(self, 0) < 0) {
|
if (wayvnc_start_capture(self, 0) < 0) {
|
||||||
log_error("Failed to start capture. Exiting...\n");
|
log_error("Failed to start capture. Exiting...\n");
|
||||||
wayvnc_exit(self);
|
wayvnc_exit(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->please_send_full_frame_next = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_capture_done(struct frame_capture* capture)
|
void on_capture_done(struct frame_capture* capture)
|
||||||
|
@ -906,6 +857,8 @@ int main(int argc, char* argv[])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pixman_region_init(&self.current_damage);
|
||||||
|
|
||||||
self.capture_backend->overlay_cursor = overlay_cursor;
|
self.capture_backend->overlay_cursor = overlay_cursor;
|
||||||
|
|
||||||
if (wayvnc_start_capture(&self, 0) < 0)
|
if (wayvnc_start_capture(&self, 0) < 0)
|
||||||
|
@ -921,8 +874,9 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
frame_capture_stop(self.capture_backend);
|
frame_capture_stop(self.capture_backend);
|
||||||
|
|
||||||
if (self.fb[1]) nvnc_fb_unref(self.fb[1]);
|
if (self.buffer) nvnc_fb_unref(self.buffer);
|
||||||
if (self.fb[0]) nvnc_fb_unref(self.fb[0]);
|
|
||||||
|
pixman_region_fini(&self.current_damage);
|
||||||
|
|
||||||
nvnc_close(self.nvnc);
|
nvnc_close(self.nvnc);
|
||||||
renderer_destroy(&self.renderer);
|
renderer_destroy(&self.renderer);
|
||||||
|
|
Loading…
Reference in New Issue