summaryrefslogtreecommitdiff
path: root/render/fx_renderer/fx_framebuffer.c
diff options
context:
space:
mode:
authorErik Reider <[email protected]>2024-01-06 02:31:14 +0100
committerGitHub <[email protected]>2024-01-06 02:31:14 +0100
commit6759e8da7ab53a46b0eb04e5045b8c67262c3a11 (patch)
treec65ed83ca04b61bdbae7e1b8a7f2c16f29b89730 /render/fx_renderer/fx_framebuffer.c
parentb929a2bbadf467864796ad4ec90882ce86cfebff (diff)
parentace97585b2b4d8cbb5ead6cd0f72fa8e8889c9d7 (diff)
Merge pull request #24 from wlrfx/wlroots-0.17-rebase
Rebase to wlroots 0.17
Diffstat (limited to 'render/fx_renderer/fx_framebuffer.c')
-rw-r--r--render/fx_renderer/fx_framebuffer.c137
1 files changed, 137 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..fea101b
--- /dev/null
+++ b/render/fx_renderer/fx_framebuffer.c
@@ -0,0 +1,137 @@
+#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_destroy(buffer);
+}
+
+static const struct wlr_addon_interface buffer_addon_impl = {
+ .name = "fx_framebuffer",
+ .destroy = handle_buffer_destroy,
+};
+
+struct fx_framebuffer *fx_framebuffer_get_or_create(struct fx_renderer *renderer,
+ struct wlr_buffer *wlr_buffer) {
+ struct wlr_addon *addon =
+ wlr_addon_find(&wlr_buffer->addons, renderer, &buffer_addon_impl);
+ if (addon) {
+ struct fx_framebuffer *buffer = wl_container_of(addon, buffer, addon);
+ return buffer;
+ }
+
+ struct fx_framebuffer *buffer = calloc(1, sizeof(*buffer));
+ if (buffer == NULL) {
+ wlr_log_errno(WLR_ERROR, "Allocation failed");
+ return NULL;
+ }
+ buffer->buffer = wlr_buffer;
+ buffer->renderer = renderer;
+
+ struct wlr_dmabuf_attributes dmabuf = {0};
+ if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
+ goto error_buffer;
+ }
+
+ bool external_only;
+ buffer->image = wlr_egl_create_image_from_dmabuf(renderer->egl,
+ &dmabuf, &external_only);
+ if (buffer->image == EGL_NO_IMAGE_KHR) {
+ goto error_buffer;
+ }
+
+ push_fx_debug(renderer);
+
+ glGenRenderbuffers(1, &buffer->rbo);
+ glBindRenderbuffer(GL_RENDERBUFFER, buffer->rbo);
+ renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
+ buffer->image);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ glGenFramebuffers(1, &buffer->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, buffer->rbo);
+ GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
+ wlr_log(WLR_ERROR, "Failed to create FBO");
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ goto error_image;
+ }
+
+ // Init stencil buffer
+ glGenRenderbuffers(1, &buffer->sb);
+ glBindRenderbuffer(GL_RENDERBUFFER, buffer->sb);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
+ wlr_buffer->width, wlr_buffer->height);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, buffer->sb);
+ fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
+ wlr_log(WLR_ERROR,
+ "Stencil buffer incomplete, couldn't create! (FB status: %i)",
+ fb_status);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ goto error_stencil;
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ pop_fx_debug(renderer);
+
+ wlr_addon_init(&buffer->addon, &wlr_buffer->addons, renderer,
+ &buffer_addon_impl);
+
+ wl_list_insert(&renderer->buffers, &buffer->link);
+
+ wlr_log(WLR_DEBUG, "Created GL FBO for buffer %dx%d",
+ wlr_buffer->width, wlr_buffer->height);
+
+ return buffer;
+
+error_stencil:
+ glDeleteRenderbuffers(1, &buffer->sb);
+error_image:
+ wlr_egl_destroy_image(renderer->egl, buffer->image);
+error_buffer:
+ free(buffer);
+ return 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->current_buffer->fbo);
+}
+
+void fx_framebuffer_destroy(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);
+
+ free(fx_buffer);
+}