git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

scenefx/render/fx_renderer/fx_framebuffer.c (5.5K)

  1 #include <stdlib.h>
  2 #include <wlr/interfaces/wlr_buffer.h>
  3 #include <wlr/render/allocator.h>
  4 #include <wlr/render/interface.h>
  5 #include <wlr/util/log.h>
  6 
  7 #include "render/egl.h"
  8 #include "render/fx_renderer/fx_renderer.h"
  9 
 10 static void handle_buffer_destroy(struct wlr_addon *addon) {
 11 	struct fx_framebuffer *buffer =
 12 		wl_container_of(addon, buffer, addon);
 13 	fx_framebuffer_destroy(buffer);
 14 }
 15 
 16 static const struct wlr_addon_interface buffer_addon_impl = {
 17 	.name = "fx_framebuffer",
 18 	.destroy = handle_buffer_destroy,
 19 };
 20 
 21 GLuint fx_framebuffer_get_fbo(struct fx_framebuffer *buffer) {
 22 	if (buffer->external_only) {
 23 		wlr_log(WLR_ERROR, "DMA-BUF format is external-only");
 24 		return 0;
 25 	}
 26 
 27 	if (buffer->fbo) {
 28 		return buffer->fbo;
 29 	}
 30 
 31 	push_fx_debug(buffer->renderer);
 32 
 33 	if (!buffer->rbo) {
 34 		glGenRenderbuffers(1, &buffer->rbo);
 35 		glBindRenderbuffer(GL_RENDERBUFFER, buffer->rbo);
 36 		buffer->renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
 37 				buffer->image);
 38 		glBindRenderbuffer(GL_RENDERBUFFER, 0);
 39 	}
 40 
 41 	glGenFramebuffers(1, &buffer->fbo);
 42 	glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo);
 43 	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
 44 			GL_RENDERBUFFER, buffer->rbo);
 45 	GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 46 
 47 	// Init stencil buffer
 48 	glGenRenderbuffers(1, &buffer->sb);
 49 	glBindRenderbuffer(GL_RENDERBUFFER, buffer->sb);
 50 	glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
 51 			buffer->buffer->width, buffer->buffer->height);
 52 	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
 53 			GL_RENDERBUFFER, buffer->sb);
 54 	fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 55 
 56 	glBindFramebuffer(GL_FRAMEBUFFER, 0);
 57 
 58 	if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
 59 		wlr_log(WLR_ERROR, "Failed to create FBO");
 60 		glDeleteFramebuffers(1, &buffer->fbo);
 61 		buffer->fbo = 0;
 62 	}
 63 
 64 	pop_fx_debug(buffer->renderer);
 65 
 66 	return buffer->fbo;
 67 }
 68 
 69 void fx_framebuffer_get_or_create_custom(struct fx_renderer *renderer,
 70 		struct wlr_allocator *allocator, int width, int height, bool has_alpha,
 71 		struct fx_framebuffer **fx_framebuffer, bool *failed) {
 72 	if (*failed) {
 73 		return;
 74 	}
 75 
 76 	if (*fx_framebuffer != NULL) {
 77 		struct wlr_buffer *wlr_buffer = (*fx_framebuffer)->buffer;
 78 		if (wlr_buffer != NULL) {
 79 			if (wlr_buffer->width == width && wlr_buffer->height == height) {
 80 				return;
 81 			}
 82 			// Create a new wlr_buffer if it's null or if the output size has
 83 			// changed
 84 			wlr_buffer_drop(wlr_buffer);
 85 		} else {
 86 			fx_framebuffer_destroy(*fx_framebuffer);
 87 		}
 88 		*fx_framebuffer = NULL;
 89 	}
 90 
 91 	// Get the best supported DRM format (DMABUF if supported)
 92 	const struct wlr_drm_format_set *texture_formats = wlr_renderer_get_texture_formats(
 93 			&renderer->wlr_renderer, renderer->wlr_renderer.render_buffer_caps);
 94 	const struct fx_pixel_format *pix_format =
 95 		get_fx_format_from_gl(GL_RGBA, GL_UNSIGNED_BYTE, has_alpha);
 96 	const struct wlr_drm_format *format = wlr_drm_format_set_get(texture_formats, pix_format->drm_format);
 97 	if (format == NULL) {
 98 		wlr_log(WLR_ERROR, "Failed to get a supported texture format while allocating buffer");
 99 		*failed = true;
100 		return;
101 	}
102 
103 	struct wlr_buffer *wlr_buffer = wlr_allocator_create_buffer(allocator, width, height, format);
104 	if (wlr_buffer == NULL) {
105 		wlr_log(WLR_ERROR, "Failed to allocate wlr_buffer");
106 		*failed = true;
107 		return;
108 	}
109 
110 	*fx_framebuffer = fx_framebuffer_get_or_create(renderer, wlr_buffer);
111 	if (*fx_framebuffer == NULL) {
112 		wlr_log(WLR_ERROR, "Failed to allocate fx_buffer");
113 		wlr_buffer_drop(wlr_buffer);
114 		*failed = true;
115 		return;
116 	}
117 	fx_framebuffer_get_fbo(*fx_framebuffer);
118 }
119 
120 struct fx_framebuffer *fx_framebuffer_get_or_create(struct fx_renderer *renderer,
121 		struct wlr_buffer *wlr_buffer) {
122 	struct wlr_addon *addon =
123 		wlr_addon_find(&wlr_buffer->addons, renderer, &buffer_addon_impl);
124 	if (addon) {
125 		struct fx_framebuffer *buffer = wl_container_of(addon, buffer, addon);
126 		return buffer;
127 	}
128 
129 	struct fx_framebuffer *buffer = calloc(1, sizeof(*buffer));
130 	if (buffer == NULL) {
131 		wlr_log_errno(WLR_ERROR, "Allocation failed");
132 		return NULL;
133 	}
134 	buffer->buffer = wlr_buffer;
135 	buffer->renderer = renderer;
136 
137 	struct wlr_dmabuf_attributes dmabuf = {0};
138 	if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
139 		goto error_buffer;
140 	}
141 
142 	buffer->image = wlr_egl_create_image_from_dmabuf(renderer->egl,
143 		&dmabuf, &buffer->external_only);
144 	if (buffer->image == EGL_NO_IMAGE_KHR) {
145 		goto error_buffer;
146 	}
147 
148 	wlr_addon_init(&buffer->addon, &wlr_buffer->addons, renderer,
149 		&buffer_addon_impl);
150 
151 	wl_list_insert(&renderer->buffers, &buffer->link);
152 
153 	wlr_log(WLR_DEBUG, "Created GL FBO for buffer %dx%d",
154 		wlr_buffer->width, wlr_buffer->height);
155 
156 	return buffer;
157 
158 error_buffer:
159 	free(buffer);
160 	return NULL;
161 }
162 
163 void fx_framebuffer_bind(struct fx_framebuffer *fx_buffer) {
164 	glBindFramebuffer(GL_FRAMEBUFFER, fx_framebuffer_get_fbo(fx_buffer));
165 }
166 
167 void fx_framebuffer_destroy(struct fx_framebuffer *fx_buffer) {
168 	if (!fx_buffer) {
169 		wlr_log(WLR_ERROR, "Trying to destroy an already destroyed fx_framebuffer");
170 		return;
171 	}
172 
173 	// Release the framebuffer
174 	wl_list_remove(&fx_buffer->link);
175 	wlr_addon_finish(&fx_buffer->addon);
176 
177 	struct wlr_egl_context prev_ctx;
178 	wlr_egl_make_current(fx_buffer->renderer->egl, &prev_ctx);
179 
180 	glDeleteFramebuffers(1, &fx_buffer->fbo);
181 	fx_buffer->fbo = -1;
182 	glDeleteRenderbuffers(1, &fx_buffer->rbo);
183 	fx_buffer->rbo = -1;
184 	glDeleteTextures(1, &fx_buffer->tex);
185 	fx_buffer->tex = -1;
186 	glDeleteRenderbuffers(1, &fx_buffer->sb);
187 	fx_buffer->sb = -1;
188 
189 	wlr_egl_destroy_image(fx_buffer->renderer->egl, fx_buffer->image);
190 
191 	wlr_egl_restore_context(&prev_ctx);
192 
193 	free(fx_buffer);
194 }
195