142 lines
3.8 KiB
C
142 lines
3.8 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <wlr/interfaces/wlr_buffer.h>
|
|
#include <wlr/render/interface.h>
|
|
#include <wlr/render/allocator.h>
|
|
#include <wlr/render/swapchain.h>
|
|
|
|
#include "log.h"
|
|
#include "render/egl.h"
|
|
#include "render/gles2.h"
|
|
#include "sway/desktop/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
|
|
struct wlr_egl_context prev_ctx;
|
|
if (fx_buffer->initialized) {
|
|
wl_list_remove(&fx_buffer->link);
|
|
wlr_addon_finish(&fx_buffer->addon);
|
|
|
|
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;
|
|
|
|
|
|
if (fx_buffer->initialized) {
|
|
wlr_egl_destroy_image(fx_buffer->renderer->egl, fx_buffer->image);
|
|
|
|
wlr_egl_restore_context(&prev_ctx);
|
|
}
|
|
|
|
fx_buffer->initialized = false;
|
|
}
|