Add some code for rendering screencopy frames
parent
1132dd6a3c
commit
ddaea0ceab
|
@ -2,3 +2,4 @@ build-*
|
|||
*.swp
|
||||
protocols/build
|
||||
.clang_complete
|
||||
perf.*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
125
src/main.c
125
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);
|
||||
|
||||
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,
|
||||
frame->width, frame->height,
|
||||
on_damage_check_done, self);
|
||||
return;
|
||||
wayvnc_update_vnc(self, fb);
|
||||
}
|
||||
|
||||
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);
|
||||
void wayvnc_process_screen(struct wayvnc* self)
|
||||
{
|
||||
uint32_t format = fourcc_from_gl_format(self->renderer.read_format);
|
||||
|
||||
if (wayvnc_start_capture(self) < 0) {
|
||||
log_error("Failed to start capture. Exiting...\n");
|
||||
wayvnc_exit();
|
||||
}
|
||||
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 nvnc_fb* fb = nvnc_fb_new(width, height, format);
|
||||
void* addr = nvnc_fb_get_addr(fb);
|
||||
|
||||
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);
|
||||
|
|
29
src/render.c
29
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/mman.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue