Add some code for rendering screencopy frames

shader-damage
Andri Yngvason 2019-10-10 20:48:01 +00:00
parent 1132dd6a3c
commit ddaea0ceab
6 changed files with 153 additions and 43 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ build-*
*.swp *.swp
protocols/build protocols/build
.clang_complete .clang_complete
perf.*

View File

@ -37,6 +37,8 @@ int renderer_init(struct renderer* self, uint32_t width, uint32_t height);
void renderer_destroy(struct renderer* self); void renderer_destroy(struct renderer* self);
int render_dmabuf_frame(struct renderer* self, struct dmabuf_frame* frame); 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 */ /* Copy a horizontal stripe from the GL frame into a pixel buffer */
void render_copy_pixels(struct renderer* self, void* dst, uint32_t y, void render_copy_pixels(struct renderer* self, void* dst, uint32_t y,

View File

@ -19,6 +19,10 @@ enum screencopy_status {
struct screencopy { struct screencopy {
struct wl_shm* wl_shm; struct wl_shm* wl_shm;
struct wl_buffer* buffer; struct wl_buffer* buffer;
void* pixels;
size_t bufsize;
struct zwlr_screencopy_manager_v1* manager; struct zwlr_screencopy_manager_v1* manager;
struct zwlr_screencopy_frame_v1* frame; struct zwlr_screencopy_frame_v1* frame;
@ -26,4 +30,14 @@ struct screencopy {
struct wl_output* output; struct wl_output* output;
enum screencopy_status status; enum screencopy_status status;
void (*on_done)(struct screencopy*); 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);

View File

@ -33,6 +33,7 @@
#include "wlr-screencopy-unstable-v1.h" #include "wlr-screencopy-unstable-v1.h"
#include "render.h" #include "render.h"
#include "dmabuf.h" #include "dmabuf.h"
#include "screencopy.h"
#include "strlcpy.h" #include "strlcpy.h"
#include "logging.h" #include "logging.h"
@ -55,22 +56,24 @@ struct wayvnc {
struct renderer renderer; struct renderer renderer;
const struct output* selected_output; const struct output* selected_output;
struct wl_shm* wl_shm;
struct zwlr_screencopy_manager_v1* screencopy_manager;
struct dmabuf_capture dmabuf_backend; struct dmabuf_capture dmabuf_backend;
struct screencopy screencopy_backend;
uv_poll_t wayland_poller; uv_poll_t wayland_poller;
uv_prepare_t flusher; uv_prepare_t flusher;
uv_signal_t signal_handler; uv_signal_t signal_handler;
uv_timer_t performance_timer;
struct nvnc* nvnc; struct nvnc* nvnc;
struct nvnc_fb* current_fb; struct nvnc_fb* current_fb;
struct nvnc_fb* last_fb; struct nvnc_fb* last_fb;
uint32_t n_frames;
}; };
void on_capture_done(struct dmabuf_capture* capture); 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, static void output_handle_geometry(void* data, struct wl_output* wl_output,
int32_t x, int32_t y, int32_t phys_width, 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) { if (strcmp(interface, wl_shm_interface.name) == 0) {
self->wl_shm = wl_registry_bind(registry, id, &wl_shm_interface, self->screencopy_backend.wl_shm
1); = wl_registry_bind(registry, id, &wl_shm_interface, 1);
return; 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) { if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) {
self->screencopy_manager = self->screencopy_backend.manager =
wl_registry_bind(registry, id, wl_registry_bind(registry, id,
&zwlr_screencopy_manager_v1_interface, &zwlr_screencopy_manager_v1_interface,
2); 2);
@ -240,6 +243,9 @@ static int init_wayland(struct wayvnc* self)
self->dmabuf_backend.on_done = on_capture_done; self->dmabuf_backend.on_done = on_capture_done;
self->dmabuf_backend.userdata = self; self->dmabuf_backend.userdata = self;
self->screencopy_backend.on_done = on_screencopy_done;
self->screencopy_backend.userdata = self;
return 0; return 0;
export_manager_failure: export_manager_failure:
@ -256,6 +262,7 @@ int wayvnc_select_first_output(struct wayvnc* self)
wl_list_for_each(out, &self->outputs, link) { wl_list_for_each(out, &self->outputs, link) {
self->selected_output = out; self->selected_output = out;
self->dmabuf_backend.output = out->wl_output; self->dmabuf_backend.output = out->wl_output;
self->screencopy_backend.output = out->wl_output;
return 0; return 0;
} }
@ -290,6 +297,14 @@ void on_signal(uv_signal_t* handle, int signo)
wayvnc_exit(); 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) int init_main_loop(struct wayvnc* self)
{ {
uv_loop_t* loop = uv_default_loop(); 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_init(loop, &self->signal_handler);
uv_signal_start(&self->signal_handler, on_signal, SIGINT); 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; 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) 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) 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) void wayvnc_process_frame(struct wayvnc* self, struct dmabuf_frame* frame)
{ {
uint32_t format = fourcc_from_gl_format(self->renderer.read_format); 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_dmabuf_frame(&self->renderer, frame);
render_copy_pixels(&self->renderer, addr, 0, frame->height); render_copy_pixels(&self->renderer, addr, 0, frame->height);
if (self->last_fb) wayvnc_update_vnc(self, fb);
nvnc_fb_unref(self->last_fb); }
self->last_fb = self->current_fb; void wayvnc_process_screen(struct wayvnc* self)
self->current_fb = fb; {
uint32_t format = fourcc_from_gl_format(self->renderer.read_format);
if (self->last_fb) { void* pixels = self->screencopy_backend.pixels;
nvnc_check_damage(self->current_fb, self->last_fb, 0, 0, uint32_t width = self->screencopy_backend.width;
frame->width, frame->height, uint32_t height = self->screencopy_backend.height;
on_damage_check_done, self); uint32_t stride = self->screencopy_backend.stride;
return;
}
struct pixman_region16 damage; struct nvnc_fb* fb = nvnc_fb_new(width, height, format);
pixman_region_init_rect(&damage, 0, 0, frame->width, frame->height); void* addr = nvnc_fb_get_addr(fb);
nvnc_feed_frame(self->nvnc, self->current_fb, &damage);
pixman_region_fini(&damage);
if (wayvnc_start_capture(self) < 0) { render_framebuffer(&self->renderer, pixels, format, width, height,
log_error("Failed to start capture. Exiting...\n"); stride);
wayvnc_exit(); render_copy_pixels(&self->renderer, addr, 0, height);
}
wayvnc_update_vnc(self, fb);
} }
void on_capture_done(struct dmabuf_capture* capture) void on_capture_done(struct dmabuf_capture* capture)
@ -408,6 +454,7 @@ void on_capture_done(struct dmabuf_capture* capture)
} }
break; break;
case DMABUF_CAPTURE_DONE: case DMABUF_CAPTURE_DONE:
self->n_frames++;
wayvnc_process_frame(self, &capture->frame); wayvnc_process_frame(self, &capture->frame);
break; break;
case DMABUF_CAPTURE_UNSPEC: 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[]) int main(int argc, char* argv[])
{ {
struct wayvnc self = { 0 }; struct wayvnc self = { 0 };
@ -454,7 +525,7 @@ int main(int argc, char* argv[])
uv_run(uv_default_loop(), UV_RUN_DEFAULT); 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.current_fb) nvnc_fb_unref(self.current_fb);
if (self.last_fb) nvnc_fb_unref(self.last_fb); if (self.last_fb) nvnc_fb_unref(self.last_fb);

View File

@ -54,22 +54,13 @@
X_GL_EXTENSIONS X_GL_EXTENSIONS
#undef X #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; *result = GL_BGRA_EXT;
return 0;
case WL_SHM_FORMAT_ABGR8888:
case WL_SHM_FORMAT_XBGR8888:
*result = GL_RGBA;
return 0;
default:
break;
}
return -1; // TODO: Actually detect the format
return 0;
} }
static inline void* gl_load_single_extension(const char* name) 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" " gl_FragColor = texture2D(u_tex, v_texture);\n"
"}\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[] = static const char texture_fragment_src[] =
"precision mediump float;\n" "precision mediump float;\n"
"uniform sampler2D u_tex;\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; goto shader_failure;
if (gl_compile_shader_program(&self->texture_shader_program, if (gl_compile_shader_program(&self->texture_shader_program,
dmabuf_vertex_src, texture_vertex_src,
texture_fragment_src) < 0) texture_fragment_src) < 0)
goto shader_failure; 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); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / 4);
glTexImage2D(GL_TEXTURE_2D, 0, self->read_format, width, height, 0, glTexImage2D(GL_TEXTURE_2D, 0, self->read_format, width, height, 0,
gl_format, GL_UNSIGNED_BYTE, addr); gl_format, GL_UNSIGNED_BYTE, addr);
glGenerateMipmap(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
glUseProgram(self->texture_shader_program); glUseProgram(self->texture_shader_program);

View File

@ -18,6 +18,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/mman.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "shm.h" #include "shm.h"
@ -36,18 +37,33 @@ static int screencopy_buffer_init(struct screencopy* self,
if (fd < 0) if (fd < 0)
return -1; 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); struct wl_shm_pool* pool = wl_shm_create_pool(self->wl_shm, fd, size);
close(fd);
if (!pool) if (!pool)
return -1; goto shm_failure;
struct wl_buffer* buffer = struct wl_buffer* buffer =
wl_shm_pool_create_buffer(pool, 0, width, height, stride, wl_shm_pool_create_buffer(pool, 0, width, height, stride,
format); format);
wl_shm_pool_destroy(pool); wl_shm_pool_destroy(pool);
if (!buffer)
goto shm_failure;
self->buffer = buffer; self->buffer = buffer;
self->pixels = addr;
self->bufsize = size;
close(fd);
return 0; return 0;
shm_failure:
munmap(addr, size);
mmap_failure:
close(fd);
return -1;
} }
void screencopy_stop(struct screencopy* self) void screencopy_stop(struct screencopy* self)
@ -71,6 +87,11 @@ static void screencopy_buffer(void* data,
self->on_done(self); 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); zwlr_screencopy_frame_v1_copy(self->frame, self->buffer);
} }