From fa35e9fc1c30b418d40f2da7d21335d1cfeb3dd0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 10 Mar 2020 17:07:49 +0100 Subject: [PATCH] backend/headless: use FBOs instead of pbuffers --- backend/headless/backend.c | 4 +- backend/headless/output.c | 82 ++++++++++++++++++++++++++------------ include/backend/headless.h | 4 +- 3 files changed, 60 insertions(+), 30 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 7b189f4967..56bf0c3016 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "backend/headless.h" #include "util/signal.h" @@ -100,8 +99,7 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display, wl_list_init(&backend->input_devices); static const EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_ALPHA_SIZE, 0, + EGL_SURFACE_TYPE, 0, EGL_BLUE_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_RED_SIZE, 1, diff --git a/backend/headless/output.c b/backend/headless/output.c index a2836159fa..137e7856f9 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -12,33 +14,58 @@ static struct wlr_headless_output *headless_output_from_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}; +static bool create_fbo(struct wlr_headless_output *output, + unsigned int width, unsigned int height) { + if (!wlr_egl_make_current(&output->backend->egl, EGL_NO_SURFACE, NULL)) { + return false; + } - EGLSurface surf = eglCreatePbufferSurface(egl->display, egl->config, attribs); - if (surf == EGL_NO_SURFACE) { - wlr_log(WLR_ERROR, "Failed to create EGL surface"); - return EGL_NO_SURFACE; + GLuint rbo; + glGenRenderbuffers(1, &rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + GLuint fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, rbo); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + wlr_log(WLR_ERROR, "Failed to create FBO"); + return false; } - return surf; + + output->fbo = fbo; + output->rbo = rbo; + return true; +} + +static void destroy_fbo(struct wlr_headless_output *output) { + if (!wlr_egl_make_current(&output->backend->egl, EGL_NO_SURFACE, NULL)) { + return; + } + + glDeleteFramebuffers(1, &output->fbo); + glDeleteRenderbuffers(1, &output->rbo); + output->fbo = 0; + output->rbo = 0; } static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width, int32_t height, int32_t refresh) { struct wlr_headless_output *output = 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) { - wlr_log(WLR_ERROR, "Failed to recreate EGL surface"); + destroy_fbo(output); + if (!create_fbo(output, width, height)) { wlr_output_destroy(wlr_output); return false; } @@ -53,8 +80,17 @@ static bool output_attach_render(struct wlr_output *wlr_output, int *buffer_age) { struct wlr_headless_output *output = headless_output_from_output(wlr_output); - return wlr_egl_make_current(&output->backend->egl, output->egl_surface, - buffer_age); + + if (!wlr_egl_make_current(&output->backend->egl, EGL_NO_SURFACE, NULL)) { + return false; + } + + glBindFramebuffer(GL_FRAMEBUFFER, output->fbo); + + if (buffer_age != NULL) { + *buffer_age = 0; // We only have one buffer + } + return true; } static bool output_commit(struct wlr_output *wlr_output) { @@ -74,7 +110,7 @@ static bool output_commit(struct wlr_output *wlr_output) { } if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { - // Nothing needs to be done for pbuffers + // Nothing needs to be done for FBOs wlr_output_send_present(wlr_output, NULL); } @@ -84,12 +120,9 @@ static bool output_commit(struct wlr_output *wlr_output) { static void output_destroy(struct wlr_output *wlr_output) { struct wlr_headless_output *output = headless_output_from_output(wlr_output); - wl_list_remove(&output->link); - wl_event_source_remove(output->frame_timer); - - wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface); + destroy_fbo(output); free(output); } @@ -126,9 +159,7 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, backend->display); struct wlr_output *wlr_output = &output->wlr_output; - output->egl_surface = egl_create_surface(&backend->egl, width, height); - if (output->egl_surface == EGL_NO_SURFACE) { - wlr_log(WLR_ERROR, "Failed to create EGL surface"); + if (!create_fbo(output, width, height)) { goto error; } @@ -143,8 +174,7 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, "Headless output %zd", backend->last_output_num); wlr_output_set_description(wlr_output, description); - if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, - NULL)) { + if (!output_attach_render(wlr_output, NULL)) { goto error; } diff --git a/include/backend/headless.h b/include/backend/headless.h index 66448071e8..db5941134a 100644 --- a/include/backend/headless.h +++ b/include/backend/headless.h @@ -3,6 +3,7 @@ #include #include +#include #define HEADLESS_DEFAULT_REFRESH (60 * 1000) // 60 Hz @@ -24,7 +25,8 @@ struct wlr_headless_output { struct wlr_headless_backend *backend; struct wl_list link; - void *egl_surface; + GLuint fbo, rbo; + struct wl_event_source *frame_timer; int frame_delay; // ms };