Capture a new frame immediately when a client requests a whole frame

pull/31/head
Andri Yngvason 2020-04-04 15:01:38 +00:00
parent ee4917f200
commit 238c196e6b
5 changed files with 51 additions and 15 deletions

View File

@ -31,6 +31,10 @@ enum frame_capture_status {
CAPTURE_DONE,
};
enum frame_capture_options {
CAPTURE_NOW = 1 << 0,
};
struct frame_capture {
enum frame_capture_status status;
@ -57,14 +61,14 @@ struct frame_capture {
struct {
void (*render)(struct frame_capture*, struct renderer*,
struct nvnc_fb* fb);
int (*start)(struct frame_capture*);
int (*start)(struct frame_capture*, enum frame_capture_options);
void (*stop)(struct frame_capture*);
} backend;
};
static inline int frame_capture_start(struct frame_capture* self)
static inline int frame_capture_start(struct frame_capture* self, enum frame_capture_options options)
{
return self->backend.start(self);
return self->backend.start(self, options);
}
static inline void frame_capture_stop(struct frame_capture* self)

View File

@ -55,6 +55,7 @@ struct screencopy {
struct smooth delay_smoother;
double delay;
bool is_immediate_copy;
};
void screencopy_init(struct screencopy* self);

View File

@ -133,7 +133,7 @@ static void dmabuf_frame_ready(void* data,
if (time_left >= 0.0) {
aml_set_duration(self->timer, time_left);
aml_start(aml_get_default(), self->timer);
frame_capture_start(fc);
frame_capture_start(fc, 0);
return;
}
@ -161,7 +161,8 @@ static void dmabuf_frame_cancel(void* data,
dmabuf_close_fds(self);
}
static int dmabuf_capture_start(struct frame_capture* fc)
static int dmabuf_capture_start(struct frame_capture* fc,
enum frame_capture_options options)
{
struct dmabuf_capture* self = (void*)fc;

View File

@ -35,6 +35,7 @@
#include <pixman.h>
#include <sys/param.h>
#include "frame-capture.h"
#include "wlr-export-dmabuf-unstable-v1.h"
#include "wlr-screencopy-unstable-v1.h"
#include "wlr-virtual-pointer-unstable-v1.h"
@ -438,8 +439,11 @@ static void on_fb_req(struct nvnc_client* client, bool is_incremental,
struct wayvnc* self = nvnc_get_userdata(nvnc);
// TODO: Make this per-client rather than global
if (!is_incremental)
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)
@ -475,9 +479,9 @@ int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port)
return 0;
}
int wayvnc_start_capture(struct wayvnc* self)
int wayvnc_start_capture(struct wayvnc* self, enum frame_capture_options opt)
{
return frame_capture_start(self->capture_backend);
return frame_capture_start(self->capture_backend, opt);
}
static void on_damage_check_done(struct pixman_region16* damage, void* userdata)
@ -491,10 +495,16 @@ static void on_damage_check_done(struct pixman_region16* damage, void* userdata)
struct nvnc_fb* fb = get_current_fb(self);
uint32_t* addr = nvnc_fb_get_addr(fb);
uint32_t fb_width = nvnc_fb_get_width(get_current_fb(self));
uint32_t fb_width = nvnc_fb_get_width(fb);
uint32_t fb_height = nvnc_fb_get_height(fb);
renderer_read_frame(&self->renderer, addr + y * fb_width, y,
damage_height);
if (damage_height != fb_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);
@ -503,7 +513,7 @@ static void on_damage_check_done(struct pixman_region16* damage, void* userdata)
nvnc_fb_unlock(get_current_fb(self));
}
if (wayvnc_start_capture(self) < 0) {
if (wayvnc_start_capture(self, 0) < 0) {
log_error("Failed to start capture. Exiting...\n");
wayvnc_exit(self);
}
@ -577,6 +587,7 @@ void wayvnc_process_frame(struct wayvnc* self)
void* addr = nvnc_fb_get_addr(fb);
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;
@ -586,7 +597,7 @@ void wayvnc_process_frame(struct wayvnc* self)
pixman_region_fini(&damage);
done:
if (wayvnc_start_capture(self) < 0) {
if (wayvnc_start_capture(self, 0) < 0) {
log_error("Failed to start capture. Exiting...\n");
wayvnc_exit(self);
}
@ -608,7 +619,7 @@ void on_capture_done(struct frame_capture* capture)
wayvnc_exit(self);
break;
case CAPTURE_FAILED:
if (wayvnc_start_capture(self) < 0) {
if (wayvnc_start_capture(self, CAPTURE_NOW) < 0) {
log_error("Failed to start capture. Exiting...\n");
wayvnc_exit(self);
}
@ -885,7 +896,7 @@ int main(int argc, char* argv[])
self.capture_backend->overlay_cursor = overlay_cursor;
if (wayvnc_start_capture(&self) < 0)
if (wayvnc_start_capture(&self, 0) < 0)
goto capture_failure;
wl_display_dispatch(self.display);

View File

@ -24,6 +24,7 @@
#include <libdrm/drm_fourcc.h>
#include <aml.h>
#include "frame-capture.h"
#include "shm.h"
#include "screencopy.h"
#include "smooth.h"
@ -91,6 +92,8 @@ static void screencopy_stop(struct frame_capture* fc)
aml_stop(aml_get_default(), self->timer);
self->frame_capture.status = CAPTURE_STOPPED;
if (self->frame) {
zwlr_screencopy_frame_v1_destroy(self->frame);
self->frame = NULL;
@ -116,7 +119,11 @@ static void screencopy_buffer(void* data,
self->frame_capture.frame_info.height = height;
self->frame_capture.frame_info.stride = stride;
zwlr_screencopy_frame_v1_copy_with_damage(self->frame, self->buffer);
if (self->is_immediate_copy)
zwlr_screencopy_frame_v1_copy(self->frame, self->buffer);
else
zwlr_screencopy_frame_v1_copy_with_damage(self->frame,
self->buffer);
}
static void screencopy_flags(void* data,
@ -149,6 +156,15 @@ static void screencopy_ready(void* data,
double delay = (self->last_time - self->start_time) * 1.0e-6;
self->delay = smooth(&self->delay_smoother, delay);
if (self->is_immediate_copy) {
self->frame_capture.damage_hint.x = 0;
self->frame_capture.damage_hint.y = 0;
self->frame_capture.damage_hint.width =
self->frame_capture.frame_info.width;
self->frame_capture.damage_hint.height =
self->frame_capture.frame_info.height;
}
self->frame_capture.status = CAPTURE_DONE;
self->frame_capture.on_done(&self->frame_capture);
}
@ -217,13 +233,16 @@ static void screencopy__poll(void* obj)
screencopy__start_capture(fc);
}
static int screencopy_start(struct frame_capture* fc)
static int screencopy_start(struct frame_capture* fc,
enum frame_capture_options options)
{
struct screencopy* self = (void*)fc;
if (fc->status == CAPTURE_IN_PROGRESS)
return -1;
self->is_immediate_copy = !!(options & CAPTURE_NOW);
uint64_t now = gettime_us();
double dt = (now - self->last_time) * 1.0e-6;
double time_left = (1.0 / RATE_LIMIT - dt - self->delay) * 1.0e3;