wlroots/backend/headless/output.c

150 lines
4.5 KiB
C
Raw Permalink Normal View History

2018-09-17 19:46:39 +00:00
#include <assert.h>
2018-02-12 20:29:23 +00:00
#include <stdlib.h>
2017-12-17 11:56:42 +00:00
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/wlr_renderer.h>
2017-12-17 11:56:42 +00:00
#include <wlr/util/log.h>
#include "backend/headless.h"
2018-02-12 20:29:23 +00:00
#include "util/signal.h"
2017-12-17 11:56:42 +00:00
2018-09-17 19:46:39 +00:00
static struct wlr_headless_output *headless_output_from_output(
struct wlr_output *wlr_output) {
assert(wlr_output_is_headless(wlr_output));
return (struct wlr_headless_output *)wlr_output;
}
static EGLSurface egl_create_surface(struct wlr_egl *egl, unsigned int width,
unsigned int height) {
EGLint attribs[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE};
EGLSurface surf = eglCreatePbufferSurface(egl->display, egl->config, attribs);
if (surf == EGL_NO_SURFACE) {
2018-07-09 21:49:54 +00:00
wlr_log(WLR_ERROR, "Failed to create EGL surface");
return EGL_NO_SURFACE;
}
return surf;
}
static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width,
int32_t height, int32_t refresh) {
2017-12-17 17:49:20 +00:00
struct wlr_headless_output *output =
2018-09-17 19:46:39 +00:00
headless_output_from_output(wlr_output);
struct wlr_headless_backend *backend = output->backend;
if (refresh <= 0) {
refresh = HEADLESS_DEFAULT_REFRESH;
}
wlr_egl_destroy_surface(&backend->egl, output->egl_surface);
output->egl_surface = egl_create_surface(&backend->egl, width, height);
if (output->egl_surface == EGL_NO_SURFACE) {
2018-07-09 21:49:54 +00:00
wlr_log(WLR_ERROR, "Failed to recreate EGL surface");
wlr_output_destroy(wlr_output);
return false;
}
output->frame_delay = 1000000 / refresh;
wlr_output_update_custom_mode(&output->wlr_output, width, height, refresh);
return true;
}
static bool output_attach_render(struct wlr_output *wlr_output,
int *buffer_age) {
2017-12-17 17:49:20 +00:00
struct wlr_headless_output *output =
2018-09-17 19:46:39 +00:00
headless_output_from_output(wlr_output);
return wlr_egl_make_current(&output->backend->egl, output->egl_surface,
buffer_age);
2017-12-17 12:35:07 +00:00
}
static bool output_commit(struct wlr_output *wlr_output) {
// Nothing needs to be done for pbuffers
wlr_output_send_present(wlr_output, NULL);
return true;
2017-12-17 12:35:07 +00:00
}
2017-12-17 11:56:42 +00:00
static void output_destroy(struct wlr_output *wlr_output) {
2017-12-17 17:49:20 +00:00
struct wlr_headless_output *output =
2018-09-17 19:46:39 +00:00
headless_output_from_output(wlr_output);
2017-12-17 11:56:42 +00:00
wl_list_remove(&output->link);
wl_event_source_remove(output->frame_timer);
wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface);
2017-12-17 11:56:42 +00:00
free(output);
}
static const struct wlr_output_impl output_impl = {
.set_custom_mode = output_set_custom_mode,
2017-12-17 11:56:42 +00:00
.destroy = output_destroy,
.attach_render = output_attach_render,
.commit = output_commit,
2017-12-17 11:56:42 +00:00
};
bool wlr_output_is_headless(struct wlr_output *wlr_output) {
return wlr_output->impl == &output_impl;
}
2017-12-17 12:35:07 +00:00
static int signal_frame(void *data) {
2017-12-17 17:49:20 +00:00
struct wlr_headless_output *output = data;
2018-01-26 21:39:23 +00:00
wlr_output_send_frame(&output->wlr_output);
wl_event_source_timer_update(output->frame_timer, output->frame_delay);
2017-12-17 12:35:07 +00:00
return 0;
}
2017-12-17 11:56:42 +00:00
struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend,
unsigned int width, unsigned int height) {
struct wlr_headless_backend *backend =
2018-09-17 19:46:39 +00:00
headless_backend_from_backend(wlr_backend);
2017-12-17 11:56:42 +00:00
2017-12-17 17:49:20 +00:00
struct wlr_headless_output *output =
calloc(1, sizeof(struct wlr_headless_output));
2017-12-17 11:56:42 +00:00
if (output == NULL) {
2018-07-09 21:49:54 +00:00
wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_output");
2017-12-17 11:56:42 +00:00
return NULL;
}
2017-12-17 12:35:07 +00:00
output->backend = backend;
2018-01-04 11:46:15 +00:00
wlr_output_init(&output->wlr_output, &backend->backend, &output_impl,
backend->display);
2017-12-17 11:56:42 +00:00
struct wlr_output *wlr_output = &output->wlr_output;
output->egl_surface = egl_create_surface(&backend->egl, width, height);
2017-12-17 12:35:07 +00:00
if (output->egl_surface == EGL_NO_SURFACE) {
2018-07-09 21:49:54 +00:00
wlr_log(WLR_ERROR, "Failed to create EGL surface");
goto error;
2017-12-17 12:35:07 +00:00
}
2017-12-17 11:56:42 +00:00
output_set_custom_mode(wlr_output, width, height, 0);
strncpy(wlr_output->make, "headless", sizeof(wlr_output->make));
strncpy(wlr_output->model, "headless", sizeof(wlr_output->model));
snprintf(wlr_output->name, sizeof(wlr_output->name), "HEADLESS-%zd",
++backend->last_output_num);
2017-12-17 11:56:42 +00:00
if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface,
NULL)) {
2017-12-17 11:56:42 +00:00
goto error;
}
wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 });
wlr_renderer_end(backend->renderer);
2017-12-17 11:56:42 +00:00
2017-12-17 12:35:07 +00:00
struct wl_event_loop *ev = wl_display_get_event_loop(backend->display);
output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output);
2017-12-17 11:56:42 +00:00
wl_list_insert(&backend->outputs, &output->link);
if (backend->started) {
wl_event_source_timer_update(output->frame_timer, output->frame_delay);
2018-01-04 11:46:15 +00:00
wlr_output_update_enabled(wlr_output, true);
wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output);
}
2017-12-17 11:56:42 +00:00
return wlr_output;
error:
wlr_output_destroy(&output->wlr_output);
return NULL;
}