diff options
Diffstat (limited to 'render/fx_renderer/fx_framebuffer.c')
-rw-r--r-- | render/fx_renderer/fx_framebuffer.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/render/fx_renderer/fx_framebuffer.c b/render/fx_renderer/fx_framebuffer.c new file mode 100644 index 0000000..4de6439 --- /dev/null +++ b/render/fx_renderer/fx_framebuffer.c @@ -0,0 +1,136 @@ +#include <stdio.h> +#include <stdlib.h> +#include <wlr/interfaces/wlr_buffer.h> +#include <wlr/render/allocator.h> +#include <wlr/render/interface.h> +#include <wlr/render/swapchain.h> +#include <wlr/util/log.h> + +#include "render/egl.h" +#include "render/fx_renderer/fx_renderer.h" + +static void handle_buffer_destroy(struct wlr_addon *addon) { + struct fx_framebuffer *buffer = + wl_container_of(addon, buffer, addon); + fx_framebuffer_release(buffer); +} + +static const struct wlr_addon_interface buffer_addon_impl = { + .name = "fx_framebuffer", + .destroy = handle_buffer_destroy, +}; + + +struct fx_framebuffer fx_framebuffer_create(void) { + return (struct fx_framebuffer) { + .initialized = false, + .fbo = -1, + .rbo = -1, + .wlr_buffer = NULL, + .image = NULL, + }; +} + +void fx_framebuffer_bind(struct fx_framebuffer *fx_buffer) { + glBindFramebuffer(GL_FRAMEBUFFER, fx_buffer->fbo); +} + +void fx_framebuffer_bind_wlr_fbo(struct fx_renderer *renderer) { + glBindFramebuffer(GL_FRAMEBUFFER, renderer->wlr_main_buffer_fbo); +} + +void fx_framebuffer_update(struct fx_renderer *fx_renderer, struct fx_framebuffer *fx_buffer, + int width, int height) { + struct wlr_output *output = fx_renderer->wlr_output; + + fx_buffer->renderer = fx_renderer; + + bool first_alloc = false; + + if (!fx_buffer->wlr_buffer || + fx_buffer->wlr_buffer->width != width || + fx_buffer->wlr_buffer->height != height) { + wlr_buffer_drop(fx_buffer->wlr_buffer); + fx_buffer->wlr_buffer = wlr_allocator_create_buffer(output->allocator, + width, height, &output->swapchain->format); + first_alloc = true; + } + + if (fx_buffer->fbo == (uint32_t) -1 || first_alloc) { + glGenFramebuffers(1, &fx_buffer->fbo); + first_alloc = true; + } + + if (fx_buffer->rbo == (uint32_t) -1 || first_alloc) { + struct wlr_dmabuf_attributes dmabuf = {0}; + if (!wlr_buffer_get_dmabuf(fx_buffer->wlr_buffer, &dmabuf)) { + goto error_buffer; + } + + bool external_only; + fx_buffer->image = wlr_egl_create_image_from_dmabuf(fx_renderer->egl, + &dmabuf, &external_only); + if (fx_buffer->image == EGL_NO_IMAGE_KHR) { + goto error_buffer; + } + + glGenRenderbuffers(1, &fx_buffer->rbo); + glBindRenderbuffer(GL_RENDERBUFFER, fx_buffer->rbo); + fx_renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, + fx_buffer->image); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, fx_buffer->fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, fx_buffer->rbo); + GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (fb_status != GL_FRAMEBUFFER_COMPLETE) { + wlr_log(WLR_ERROR, "Failed to create FBO"); + goto error_image; + } + } + + if (!fx_buffer->initialized) { + fx_buffer->initialized = true; + + wlr_addon_init(&fx_buffer->addon, &fx_buffer->wlr_buffer->addons, fx_renderer, + &buffer_addon_impl); + + wl_list_insert(&fx_renderer->buffers, &fx_buffer->link); + } + + if (first_alloc) { + wlr_log(WLR_DEBUG, "Created GL FBO for buffer %dx%d", + fx_buffer->wlr_buffer->width, fx_buffer->wlr_buffer->height); + } + + return; +error_image: + wlr_egl_destroy_image(fx_renderer->egl, fx_buffer->image); +error_buffer: + wlr_log(WLR_ERROR, "Could not create FX buffer! Aborting..."); + abort(); +} + +void fx_framebuffer_release(struct fx_framebuffer *fx_buffer) { + // Release the framebuffer + wl_list_remove(&fx_buffer->link); + wlr_addon_finish(&fx_buffer->addon); + + struct wlr_egl_context prev_ctx; + wlr_egl_save_context(&prev_ctx); + wlr_egl_make_current(fx_buffer->renderer->egl); + + glDeleteFramebuffers(1, &fx_buffer->fbo); + fx_buffer->fbo = -1; + glDeleteRenderbuffers(1, &fx_buffer->rbo); + fx_buffer->rbo = -1; + + wlr_egl_destroy_image(fx_buffer->renderer->egl, fx_buffer->image); + + wlr_egl_restore_context(&prev_ctx); + + fx_buffer->initialized = false; +} |