render/gles2: implement wlr_renderer_bind_buffer

This commit is contained in:
Simon Ser 2020-07-28 16:56:23 +02:00
parent c88c54fb38
commit 6136fe87d1
2 changed files with 156 additions and 0 deletions

View file

@ -72,9 +72,24 @@ struct wlr_gles2_renderer {
struct wlr_gles2_tex_shader tex_ext; struct wlr_gles2_tex_shader tex_ext;
} shaders; } shaders;
struct wl_list buffers; // wlr_gles2_buffer.link
struct wlr_gles2_buffer *current_buffer;
uint32_t viewport_width, viewport_height; uint32_t viewport_width, viewport_height;
}; };
struct wlr_gles2_buffer {
struct wlr_buffer *buffer;
struct wlr_gles2_renderer *renderer;
struct wl_list link; // wlr_gles2_renderer.buffers
EGLImageKHR image;
GLuint rbo;
GLuint fbo;
struct wl_listener buffer_destroy;
};
struct wlr_gles2_texture { struct wlr_gles2_texture {
struct wlr_texture wlr_texture; struct wlr_texture wlr_texture;
struct wlr_gles2_renderer *renderer; struct wlr_gles2_renderer *renderer;

View file

@ -36,6 +36,139 @@ static struct wlr_gles2_renderer *gles2_get_renderer_in_context(
return renderer; return renderer;
} }
static void destroy_buffer(struct wlr_gles2_buffer *buffer) {
wl_list_remove(&buffer->link);
wl_list_remove(&buffer->buffer_destroy.link);
wlr_egl_make_current(buffer->renderer->egl, EGL_NO_SURFACE, NULL);
push_gles2_debug(buffer->renderer);
glDeleteFramebuffers(1, &buffer->fbo);
glDeleteRenderbuffers(1, &buffer->rbo);
pop_gles2_debug(buffer->renderer);
wlr_egl_destroy_image(buffer->renderer->egl, buffer->image);
wlr_egl_unset_current(buffer->renderer->egl);
free(buffer);
}
static struct wlr_gles2_buffer *get_buffer(struct wlr_gles2_renderer *renderer,
struct wlr_buffer *wlr_buffer) {
struct wlr_gles2_buffer *buffer;
wl_list_for_each(buffer, &renderer->buffers, link) {
if (buffer->buffer == wlr_buffer) {
return buffer;
}
}
return NULL;
}
static void handle_buffer_destroy(struct wl_listener *listener, void *data) {
struct wlr_gles2_buffer *buffer =
wl_container_of(listener, buffer, buffer_destroy);
destroy_buffer(buffer);
}
static struct wlr_gles2_buffer *create_buffer(struct wlr_gles2_renderer *renderer,
struct wlr_buffer *wlr_buffer) {
struct wlr_gles2_buffer *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_gles2_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);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
pop_gles2_debug(renderer);
if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
wlr_log(WLR_ERROR, "Failed to create FBO");
goto error_image;
}
buffer->buffer_destroy.notify = handle_buffer_destroy;
wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy);
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_image:
wlr_egl_destroy_image(renderer->egl, buffer->image);
error_buffer:
free(buffer);
return NULL;
}
static bool gles2_bind_buffer(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *wlr_buffer) {
struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
if (renderer->current_buffer != NULL) {
push_gles2_debug(renderer);
glFlush();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
pop_gles2_debug(renderer);
wlr_buffer_unlock(renderer->current_buffer->buffer);
renderer->current_buffer = NULL;
}
if (wlr_buffer == NULL) {
return true;
}
struct wlr_gles2_buffer *buffer = get_buffer(renderer, wlr_buffer);
if (buffer == NULL) {
buffer = create_buffer(renderer, wlr_buffer);
}
if (buffer == NULL) {
return false;
}
wlr_buffer_lock(wlr_buffer);
renderer->current_buffer = buffer;
push_gles2_debug(renderer);
glBindFramebuffer(GL_FRAMEBUFFER, renderer->current_buffer->fbo);
pop_gles2_debug(renderer);
return true;
}
static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
uint32_t height) { uint32_t height) {
struct wlr_gles2_renderer *renderer = struct wlr_gles2_renderer *renderer =
@ -477,6 +610,11 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) {
wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL);
struct wlr_gles2_buffer *buffer, *buffer_tmp;
wl_list_for_each_safe(buffer, buffer_tmp, &renderer->buffers, link) {
destroy_buffer(buffer);
}
push_gles2_debug(renderer); push_gles2_debug(renderer);
glDeleteProgram(renderer->shaders.quad.program); glDeleteProgram(renderer->shaders.quad.program);
glDeleteProgram(renderer->shaders.ellipse.program); glDeleteProgram(renderer->shaders.ellipse.program);
@ -497,6 +635,7 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) {
static const struct wlr_renderer_impl renderer_impl = { static const struct wlr_renderer_impl renderer_impl = {
.destroy = gles2_destroy, .destroy = gles2_destroy,
.bind_buffer = gles2_bind_buffer,
.begin = gles2_begin, .begin = gles2_begin,
.end = gles2_end, .end = gles2_end,
.clear = gles2_clear, .clear = gles2_clear,
@ -668,6 +807,8 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
} }
wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl); wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl);
wl_list_init(&renderer->buffers);
renderer->egl = egl; renderer->egl = egl;
renderer->exts_str = exts_str; renderer->exts_str = exts_str;