From ddaea0ceab05e20e3d71b983d7aa60e4eccb85dc Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Thu, 10 Oct 2019 20:48:01 +0000 Subject: [PATCH] Add some code for rendering screencopy frames --- .gitignore | 1 + include/render.h | 2 + include/screencopy.h | 14 +++++ src/main.c | 123 ++++++++++++++++++++++++++++++++++--------- src/render.c | 31 +++++------ src/screencopy.c | 25 ++++++++- 6 files changed, 153 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index 994f5b0..6021d22 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build-* *.swp protocols/build .clang_complete +perf.* diff --git a/include/render.h b/include/render.h index 921f3a3..2f13790 100644 --- a/include/render.h +++ b/include/render.h @@ -37,6 +37,8 @@ int renderer_init(struct renderer* self, uint32_t width, uint32_t height); void renderer_destroy(struct renderer* self); int render_dmabuf_frame(struct renderer* self, struct dmabuf_frame* frame); +int render_framebuffer(struct renderer* self, const void* addr, uint32_t format, + uint32_t width, uint32_t height, uint32_t stride); /* Copy a horizontal stripe from the GL frame into a pixel buffer */ void render_copy_pixels(struct renderer* self, void* dst, uint32_t y, diff --git a/include/screencopy.h b/include/screencopy.h index 10d5c68..ce12322 100644 --- a/include/screencopy.h +++ b/include/screencopy.h @@ -19,6 +19,10 @@ enum screencopy_status { struct screencopy { struct wl_shm* wl_shm; struct wl_buffer* buffer; + + void* pixels; + size_t bufsize; + struct zwlr_screencopy_manager_v1* manager; struct zwlr_screencopy_frame_v1* frame; @@ -26,4 +30,14 @@ struct screencopy { struct wl_output* output; enum screencopy_status status; void (*on_done)(struct screencopy*); + + enum wl_shm_format format; + uint32_t width; + uint32_t height; + uint32_t stride; + + void* userdata; }; + +int screencopy_start(struct screencopy* self); +void screencopy_stop(struct screencopy* self); diff --git a/src/main.c b/src/main.c index 4777dc9..74efdd5 100644 --- a/src/main.c +++ b/src/main.c @@ -33,6 +33,7 @@ #include "wlr-screencopy-unstable-v1.h" #include "render.h" #include "dmabuf.h" +#include "screencopy.h" #include "strlcpy.h" #include "logging.h" @@ -55,22 +56,24 @@ struct wayvnc { struct renderer renderer; const struct output* selected_output; - struct wl_shm* wl_shm; - struct zwlr_screencopy_manager_v1* screencopy_manager; - struct dmabuf_capture dmabuf_backend; + struct screencopy screencopy_backend; uv_poll_t wayland_poller; uv_prepare_t flusher; uv_signal_t signal_handler; + uv_timer_t performance_timer; struct nvnc* nvnc; struct nvnc_fb* current_fb; struct nvnc_fb* last_fb; + + uint32_t n_frames; }; void on_capture_done(struct dmabuf_capture* capture); +void on_screencopy_done(struct screencopy* capture); static void output_handle_geometry(void* data, struct wl_output* wl_output, int32_t x, int32_t y, int32_t phys_width, @@ -166,8 +169,8 @@ static void registry_add(void* data, struct wl_registry* registry, } if (strcmp(interface, wl_shm_interface.name) == 0) { - self->wl_shm = wl_registry_bind(registry, id, &wl_shm_interface, - 1); + self->screencopy_backend.wl_shm + = wl_registry_bind(registry, id, &wl_shm_interface, 1); return; } @@ -180,7 +183,7 @@ static void registry_add(void* data, struct wl_registry* registry, } if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) { - self->screencopy_manager = + self->screencopy_backend.manager = wl_registry_bind(registry, id, &zwlr_screencopy_manager_v1_interface, 2); @@ -240,6 +243,9 @@ static int init_wayland(struct wayvnc* self) self->dmabuf_backend.on_done = on_capture_done; self->dmabuf_backend.userdata = self; + self->screencopy_backend.on_done = on_screencopy_done; + self->screencopy_backend.userdata = self; + return 0; export_manager_failure: @@ -256,6 +262,7 @@ int wayvnc_select_first_output(struct wayvnc* self) wl_list_for_each(out, &self->outputs, link) { self->selected_output = out; self->dmabuf_backend.output = out->wl_output; + self->screencopy_backend.output = out->wl_output; return 0; } @@ -290,6 +297,14 @@ void on_signal(uv_signal_t* handle, int signo) wayvnc_exit(); } +void on_performance_tick(uv_timer_t* handle) +{ + struct wayvnc* self = wl_container_of(handle, self, performance_timer); + + printf("%"PRIu32" FPS\n", self->n_frames); + self->n_frames = 0; +} + int init_main_loop(struct wayvnc* self) { uv_loop_t* loop = uv_default_loop(); @@ -304,6 +319,10 @@ int init_main_loop(struct wayvnc* self) uv_signal_init(loop, &self->signal_handler); uv_signal_start(&self->signal_handler, on_signal, SIGINT); + uv_timer_init(loop, &self->performance_timer); + uv_timer_start(&self->performance_timer, on_performance_tick, 1000, + 1000); + return 0; } @@ -340,7 +359,8 @@ int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port) int wayvnc_start_capture(struct wayvnc* self) { - return dmabuf_capture_start(&self->dmabuf_backend); + return screencopy_start(&self->screencopy_backend); +// return dmabuf_capture_start(&self->dmabuf_backend); } void on_damage_check_done(struct pixman_region16* damage, void* userdata) @@ -356,6 +376,34 @@ void on_damage_check_done(struct pixman_region16* damage, void* userdata) } } +void wayvnc_update_vnc(struct wayvnc* self, struct nvnc_fb* fb) +{ + uint32_t width = nvnc_fb_get_width(fb); + uint32_t height = nvnc_fb_get_height(fb); + + if (self->last_fb) + nvnc_fb_unref(self->last_fb); + + self->last_fb = self->current_fb; + self->current_fb = fb; + + if (self->last_fb) { + nvnc_check_damage(self->current_fb, self->last_fb, 0, 0, + width, height, on_damage_check_done, self); + return; + } + + struct pixman_region16 damage; + pixman_region_init_rect(&damage, 0, 0, width, height); + nvnc_feed_frame(self->nvnc, self->current_fb, &damage); + pixman_region_fini(&damage); + + if (wayvnc_start_capture(self) < 0) { + log_error("Failed to start capture. Exiting...\n"); + wayvnc_exit(); + } +} + void wayvnc_process_frame(struct wayvnc* self, struct dmabuf_frame* frame) { uint32_t format = fourcc_from_gl_format(self->renderer.read_format); @@ -366,28 +414,26 @@ void wayvnc_process_frame(struct wayvnc* self, struct dmabuf_frame* frame) render_dmabuf_frame(&self->renderer, frame); render_copy_pixels(&self->renderer, addr, 0, frame->height); - if (self->last_fb) - nvnc_fb_unref(self->last_fb); + wayvnc_update_vnc(self, fb); +} - self->last_fb = self->current_fb; - self->current_fb = fb; +void wayvnc_process_screen(struct wayvnc* self) +{ + uint32_t format = fourcc_from_gl_format(self->renderer.read_format); - if (self->last_fb) { - nvnc_check_damage(self->current_fb, self->last_fb, 0, 0, - frame->width, frame->height, - on_damage_check_done, self); - return; - } + void* pixels = self->screencopy_backend.pixels; + uint32_t width = self->screencopy_backend.width; + uint32_t height = self->screencopy_backend.height; + uint32_t stride = self->screencopy_backend.stride; - struct pixman_region16 damage; - pixman_region_init_rect(&damage, 0, 0, frame->width, frame->height); - nvnc_feed_frame(self->nvnc, self->current_fb, &damage); - pixman_region_fini(&damage); + struct nvnc_fb* fb = nvnc_fb_new(width, height, format); + void* addr = nvnc_fb_get_addr(fb); - if (wayvnc_start_capture(self) < 0) { - log_error("Failed to start capture. Exiting...\n"); - wayvnc_exit(); - } + render_framebuffer(&self->renderer, pixels, format, width, height, + stride); + render_copy_pixels(&self->renderer, addr, 0, height); + + wayvnc_update_vnc(self, fb); } void on_capture_done(struct dmabuf_capture* capture) @@ -408,6 +454,7 @@ void on_capture_done(struct dmabuf_capture* capture) } break; case DMABUF_CAPTURE_DONE: + self->n_frames++; wayvnc_process_frame(self, &capture->frame); break; case DMABUF_CAPTURE_UNSPEC: @@ -415,6 +462,30 @@ void on_capture_done(struct dmabuf_capture* capture) } } +void on_screencopy_done(struct screencopy* capture) +{ + struct wayvnc* self = capture->userdata; + + switch (capture->status) { + case SCREENCOPY_STATUS_CAPTURING: + break; + case SCREENCOPY_STATUS_FATAL: + log_error("Fatal error while capturing. Exiting...\n"); + wayvnc_exit(); + break; + case SCREENCOPY_STATUS_FAILED: + if (wayvnc_start_capture(self) < 0) { + log_error("Failed to start capture. Exiting...\n"); + wayvnc_exit(); + } + break; + case SCREENCOPY_STATUS_DONE: + self->n_frames++; + wayvnc_process_screen(self); + break; + } +} + int main(int argc, char* argv[]) { struct wayvnc self = { 0 }; @@ -454,7 +525,7 @@ int main(int argc, char* argv[]) uv_run(uv_default_loop(), UV_RUN_DEFAULT); - dmabuf_capture_stop(&self.dmabuf_backend); +// dmabuf_capture_stop(&self.dmabuf_backend); if (self.current_fb) nvnc_fb_unref(self.current_fb); if (self.last_fb) nvnc_fb_unref(self.last_fb); diff --git a/src/render.c b/src/render.c index 5f6ca77..3a04272 100644 --- a/src/render.c +++ b/src/render.c @@ -54,22 +54,13 @@ X_GL_EXTENSIONS #undef X -GLenum gl_format_from_wl_shm(GLuint* result, enum wl_shm_format format) +int gl_format_from_wl_shm(GLenum* result, enum wl_shm_format format) { - switch (format) { - case WL_SHM_FORMAT_ARGB8888: - case WL_SHM_FORMAT_XRGB8888: - *result = GL_BGRA_EXT; - return 0; - case WL_SHM_FORMAT_ABGR8888: - case WL_SHM_FORMAT_XBGR8888: - *result = GL_RGBA; - return 0; - default: - break; - } + *result = GL_BGRA_EXT; - return -1; + // TODO: Actually detect the format + + return 0; } static inline void* gl_load_single_extension(const char* name) @@ -185,6 +176,15 @@ static const char dmabuf_fragment_src[] = " gl_FragColor = texture2D(u_tex, v_texture);\n" "}\n"; +static const char texture_vertex_src[] = +"attribute vec2 pos;\n" +"attribute vec2 texture;\n" +"varying vec2 v_texture;\n" +"void main() {\n" +" v_texture = texture;\n" +" gl_Position = vec4(pos, 0, 1);\n" +"}\n"; + static const char texture_fragment_src[] = "precision mediump float;\n" "uniform sampler2D u_tex;\n" @@ -345,7 +345,7 @@ int renderer_init(struct renderer* self, uint32_t width, uint32_t height) goto shader_failure; if (gl_compile_shader_program(&self->texture_shader_program, - dmabuf_vertex_src, + texture_vertex_src, texture_fragment_src) < 0) goto shader_failure; @@ -447,6 +447,7 @@ int render_framebuffer(struct renderer* self, const void* addr, uint32_t format, glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / 4); glTexImage2D(GL_TEXTURE_2D, 0, self->read_format, width, height, 0, gl_format, GL_UNSIGNED_BYTE, addr); + glGenerateMipmap(GL_TEXTURE_2D); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); glUseProgram(self->texture_shader_program); diff --git a/src/screencopy.c b/src/screencopy.c index cd163c7..6bc49ab 100644 --- a/src/screencopy.c +++ b/src/screencopy.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "shm.h" @@ -36,18 +37,33 @@ static int screencopy_buffer_init(struct screencopy* self, if (fd < 0) return -1; + void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (!addr) + goto mmap_failure; + struct wl_shm_pool* pool = wl_shm_create_pool(self->wl_shm, fd, size); - close(fd); if (!pool) - return -1; + goto shm_failure; struct wl_buffer* buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, format); wl_shm_pool_destroy(pool); + if (!buffer) + goto shm_failure; self->buffer = buffer; + self->pixels = addr; + self->bufsize = size; + + close(fd); return 0; + +shm_failure: + munmap(addr, size); +mmap_failure: + close(fd); + return -1; } void screencopy_stop(struct screencopy* self) @@ -71,6 +87,11 @@ static void screencopy_buffer(void* data, self->on_done(self); } + self->format = format; + self->width = width; + self->height = height; + self->stride = stride; + zwlr_screencopy_frame_v1_copy(self->frame, self->buffer); }