Capture a new frame immediately when a client requests a whole frame
parent
ee4917f200
commit
238c196e6b
|
@ -31,6 +31,10 @@ enum frame_capture_status {
|
||||||
CAPTURE_DONE,
|
CAPTURE_DONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum frame_capture_options {
|
||||||
|
CAPTURE_NOW = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
struct frame_capture {
|
struct frame_capture {
|
||||||
enum frame_capture_status status;
|
enum frame_capture_status status;
|
||||||
|
|
||||||
|
@ -57,14 +61,14 @@ struct frame_capture {
|
||||||
struct {
|
struct {
|
||||||
void (*render)(struct frame_capture*, struct renderer*,
|
void (*render)(struct frame_capture*, struct renderer*,
|
||||||
struct nvnc_fb* fb);
|
struct nvnc_fb* fb);
|
||||||
int (*start)(struct frame_capture*);
|
int (*start)(struct frame_capture*, enum frame_capture_options);
|
||||||
void (*stop)(struct frame_capture*);
|
void (*stop)(struct frame_capture*);
|
||||||
} backend;
|
} 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)
|
static inline void frame_capture_stop(struct frame_capture* self)
|
||||||
|
|
|
@ -55,6 +55,7 @@ struct screencopy {
|
||||||
|
|
||||||
struct smooth delay_smoother;
|
struct smooth delay_smoother;
|
||||||
double delay;
|
double delay;
|
||||||
|
bool is_immediate_copy;
|
||||||
};
|
};
|
||||||
|
|
||||||
void screencopy_init(struct screencopy* self);
|
void screencopy_init(struct screencopy* self);
|
||||||
|
|
|
@ -133,7 +133,7 @@ static void dmabuf_frame_ready(void* data,
|
||||||
if (time_left >= 0.0) {
|
if (time_left >= 0.0) {
|
||||||
aml_set_duration(self->timer, time_left);
|
aml_set_duration(self->timer, time_left);
|
||||||
aml_start(aml_get_default(), self->timer);
|
aml_start(aml_get_default(), self->timer);
|
||||||
frame_capture_start(fc);
|
frame_capture_start(fc, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +161,8 @@ static void dmabuf_frame_cancel(void* data,
|
||||||
dmabuf_close_fds(self);
|
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;
|
struct dmabuf_capture* self = (void*)fc;
|
||||||
|
|
||||||
|
|
27
src/main.c
27
src/main.c
|
@ -35,6 +35,7 @@
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include "frame-capture.h"
|
||||||
#include "wlr-export-dmabuf-unstable-v1.h"
|
#include "wlr-export-dmabuf-unstable-v1.h"
|
||||||
#include "wlr-screencopy-unstable-v1.h"
|
#include "wlr-screencopy-unstable-v1.h"
|
||||||
#include "wlr-virtual-pointer-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);
|
struct wayvnc* self = nvnc_get_userdata(nvnc);
|
||||||
|
|
||||||
// TODO: Make this per-client rather than global
|
// TODO: Make this per-client rather than global
|
||||||
if (!is_incremental)
|
if (!is_incremental) {
|
||||||
self->please_send_full_frame_next = true;
|
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)
|
||||||
|
@ -475,9 +479,9 @@ int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port)
|
||||||
return 0;
|
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)
|
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);
|
struct nvnc_fb* fb = get_current_fb(self);
|
||||||
uint32_t* addr = nvnc_fb_get_addr(fb);
|
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,
|
renderer_read_frame(&self->renderer, addr + y * fb_width, y,
|
||||||
damage_height);
|
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_fb_unlock(fb);
|
||||||
|
|
||||||
nvnc_feed_frame(self->nvnc, fb, damage);
|
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));
|
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");
|
log_error("Failed to start capture. Exiting...\n");
|
||||||
wayvnc_exit(self);
|
wayvnc_exit(self);
|
||||||
}
|
}
|
||||||
|
@ -577,6 +587,7 @@ void wayvnc_process_frame(struct wayvnc* self)
|
||||||
|
|
||||||
void* addr = nvnc_fb_get_addr(fb);
|
void* addr = nvnc_fb_get_addr(fb);
|
||||||
renderer_read_frame(&self->renderer, addr, 0, height);
|
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);
|
nvnc_fb_unlock(fb);
|
||||||
|
|
||||||
struct pixman_region16 damage;
|
struct pixman_region16 damage;
|
||||||
|
@ -586,7 +597,7 @@ void wayvnc_process_frame(struct wayvnc* self)
|
||||||
pixman_region_fini(&damage);
|
pixman_region_fini(&damage);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (wayvnc_start_capture(self) < 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);
|
||||||
}
|
}
|
||||||
|
@ -608,7 +619,7 @@ void on_capture_done(struct frame_capture* capture)
|
||||||
wayvnc_exit(self);
|
wayvnc_exit(self);
|
||||||
break;
|
break;
|
||||||
case CAPTURE_FAILED:
|
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");
|
log_error("Failed to start capture. Exiting...\n");
|
||||||
wayvnc_exit(self);
|
wayvnc_exit(self);
|
||||||
}
|
}
|
||||||
|
@ -885,7 +896,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
self.capture_backend->overlay_cursor = overlay_cursor;
|
self.capture_backend->overlay_cursor = overlay_cursor;
|
||||||
|
|
||||||
if (wayvnc_start_capture(&self) < 0)
|
if (wayvnc_start_capture(&self, 0) < 0)
|
||||||
goto capture_failure;
|
goto capture_failure;
|
||||||
|
|
||||||
wl_display_dispatch(self.display);
|
wl_display_dispatch(self.display);
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <libdrm/drm_fourcc.h>
|
#include <libdrm/drm_fourcc.h>
|
||||||
#include <aml.h>
|
#include <aml.h>
|
||||||
|
|
||||||
|
#include "frame-capture.h"
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
#include "screencopy.h"
|
#include "screencopy.h"
|
||||||
#include "smooth.h"
|
#include "smooth.h"
|
||||||
|
@ -91,6 +92,8 @@ static void screencopy_stop(struct frame_capture* fc)
|
||||||
|
|
||||||
aml_stop(aml_get_default(), self->timer);
|
aml_stop(aml_get_default(), self->timer);
|
||||||
|
|
||||||
|
self->frame_capture.status = CAPTURE_STOPPED;
|
||||||
|
|
||||||
if (self->frame) {
|
if (self->frame) {
|
||||||
zwlr_screencopy_frame_v1_destroy(self->frame);
|
zwlr_screencopy_frame_v1_destroy(self->frame);
|
||||||
self->frame = NULL;
|
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.height = height;
|
||||||
self->frame_capture.frame_info.stride = stride;
|
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,
|
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;
|
double delay = (self->last_time - self->start_time) * 1.0e-6;
|
||||||
self->delay = smooth(&self->delay_smoother, delay);
|
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.status = CAPTURE_DONE;
|
||||||
self->frame_capture.on_done(&self->frame_capture);
|
self->frame_capture.on_done(&self->frame_capture);
|
||||||
}
|
}
|
||||||
|
@ -217,13 +233,16 @@ static void screencopy__poll(void* obj)
|
||||||
screencopy__start_capture(fc);
|
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;
|
struct screencopy* self = (void*)fc;
|
||||||
|
|
||||||
if (fc->status == CAPTURE_IN_PROGRESS)
|
if (fc->status == CAPTURE_IN_PROGRESS)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
self->is_immediate_copy = !!(options & CAPTURE_NOW);
|
||||||
|
|
||||||
uint64_t now = gettime_us();
|
uint64_t now = gettime_us();
|
||||||
double dt = (now - self->last_time) * 1.0e-6;
|
double dt = (now - self->last_time) * 1.0e-6;
|
||||||
double time_left = (1.0 / RATE_LIMIT - dt - self->delay) * 1.0e3;
|
double time_left = (1.0 / RATE_LIMIT - dt - self->delay) * 1.0e3;
|
||||||
|
|
Loading…
Reference in New Issue