mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-05-07 18:58:00 +02:00
render: gles2: Add NV12 GLES2 buffers
Rendering to NV12 buffers is not directly supported in GL ES2.0, but can be implemented by rendering in 2 passes to 2 different EGL images. This changes makes provisions for multiple EGL images inside a wlr_gles2_buffer and adds a special case for mapping NV12 buffers to multiple EGL images. Signed-off-by: Andri Yngvason <andri@yngvason.is>
This commit is contained in:
parent
1924113a5a
commit
d0034614d0
4 changed files with 66 additions and 28 deletions
|
|
@ -108,9 +108,11 @@ struct wlr_gles2_buffer {
|
|||
struct wl_list link; // wlr_gles2_renderer.buffers
|
||||
bool external_only;
|
||||
|
||||
EGLImageKHR image;
|
||||
GLuint rbo;
|
||||
GLuint fbo;
|
||||
int n_images;
|
||||
EGLImageKHR image[4];
|
||||
GLuint rbo[4];
|
||||
GLuint fbo[4];
|
||||
|
||||
GLuint tex;
|
||||
|
||||
struct wlr_addon addon;
|
||||
|
|
@ -153,7 +155,7 @@ const struct wlr_gles2_pixel_format *get_gles2_format_from_gl(
|
|||
void get_gles2_shm_formats(const struct wlr_gles2_renderer *renderer,
|
||||
struct wlr_drm_format_set *out);
|
||||
|
||||
GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer);
|
||||
GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer, int index);
|
||||
|
||||
struct wlr_gles2_renderer *gles2_get_renderer(
|
||||
struct wlr_renderer *wlr_renderer);
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b
|
|||
}
|
||||
}
|
||||
|
||||
GLint fbo = gles2_buffer_get_fbo(buffer);
|
||||
GLint fbo = gles2_buffer_get_fbo(buffer, 0);
|
||||
if (!fbo) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,13 +59,18 @@ static void destroy_buffer(struct wlr_gles2_buffer *buffer) {
|
|||
|
||||
push_gles2_debug(buffer->renderer);
|
||||
|
||||
glDeleteFramebuffers(1, &buffer->fbo);
|
||||
glDeleteRenderbuffers(1, &buffer->rbo);
|
||||
for (int i = 0; i < buffer->n_images; ++i) {
|
||||
glDeleteFramebuffers(1, &buffer->fbo[i]);
|
||||
glDeleteRenderbuffers(1, &buffer->rbo[i]);
|
||||
}
|
||||
|
||||
glDeleteTextures(1, &buffer->tex);
|
||||
|
||||
pop_gles2_debug(buffer->renderer);
|
||||
|
||||
wlr_egl_destroy_image(buffer->renderer->egl, buffer->image);
|
||||
for (int i = 0; i < buffer->n_images; ++i) {
|
||||
wlr_egl_destroy_image(buffer->renderer->egl, buffer->image[i]);
|
||||
}
|
||||
|
||||
wlr_egl_restore_context(&prev_ctx);
|
||||
|
||||
|
|
@ -83,42 +88,42 @@ static const struct wlr_addon_interface buffer_addon_impl = {
|
|||
.destroy = handle_buffer_destroy,
|
||||
};
|
||||
|
||||
GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer) {
|
||||
GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer, int index) {
|
||||
if (buffer->external_only) {
|
||||
wlr_log(WLR_ERROR, "DMA-BUF format is external-only");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buffer->fbo) {
|
||||
return buffer->fbo;
|
||||
if (buffer->fbo[index]) {
|
||||
return buffer->fbo[index];
|
||||
}
|
||||
|
||||
push_gles2_debug(buffer->renderer);
|
||||
|
||||
if (!buffer->rbo) {
|
||||
glGenRenderbuffers(1, &buffer->rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, buffer->rbo);
|
||||
if (!buffer->rbo[index]) {
|
||||
glGenRenderbuffers(1, &buffer->rbo[index]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, buffer->rbo[index]);
|
||||
buffer->renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
|
||||
buffer->image);
|
||||
buffer->image[index]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
|
||||
glGenFramebuffers(1, &buffer->fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo);
|
||||
glGenFramebuffers(1, &buffer->fbo[index]);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo[index]);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, buffer->rbo);
|
||||
GL_RENDERBUFFER, buffer->rbo[index]);
|
||||
GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
wlr_log(WLR_ERROR, "Failed to create FBO");
|
||||
glDeleteFramebuffers(1, &buffer->fbo);
|
||||
buffer->fbo = 0;
|
||||
glDeleteFramebuffers(1, &buffer->fbo[index]);
|
||||
buffer->fbo[index] = 0;
|
||||
}
|
||||
|
||||
pop_gles2_debug(buffer->renderer);
|
||||
|
||||
return buffer->fbo;
|
||||
return buffer->fbo[index];
|
||||
}
|
||||
|
||||
struct wlr_gles2_buffer *gles2_buffer_get_or_create(struct wlr_gles2_renderer *renderer,
|
||||
|
|
@ -143,10 +148,41 @@ struct wlr_gles2_buffer *gles2_buffer_get_or_create(struct wlr_gles2_renderer *r
|
|||
goto error_buffer;
|
||||
}
|
||||
|
||||
buffer->image = wlr_egl_create_image_from_dmabuf(renderer->egl,
|
||||
&dmabuf, &buffer->external_only);
|
||||
if (buffer->image == EGL_NO_IMAGE_KHR) {
|
||||
goto error_buffer;
|
||||
if (dmabuf.format == DRM_FORMAT_NV12) {
|
||||
buffer->n_images = 2;
|
||||
|
||||
struct wlr_dmabuf_attributes luma = dmabuf;
|
||||
luma.n_planes = 1;
|
||||
luma.format = DRM_FORMAT_R8;
|
||||
buffer->image[0] = wlr_egl_create_image_from_dmabuf(renderer->egl,
|
||||
&luma, &buffer->external_only);
|
||||
if (buffer->image[0] == EGL_NO_IMAGE_KHR) {
|
||||
goto error_buffer;
|
||||
}
|
||||
|
||||
struct wlr_dmabuf_attributes chroma = {
|
||||
.format = DRM_FORMAT_GR88,
|
||||
.n_planes = 1,
|
||||
.offset = { dmabuf.offset[1] },
|
||||
.stride = { dmabuf.stride[1] },
|
||||
.fd = { dmabuf.fd[1] },
|
||||
.width = (dmabuf.width + 1) / 2,
|
||||
.height = (dmabuf.height + 1) / 2,
|
||||
.modifier = dmabuf.modifier,
|
||||
};
|
||||
buffer->image[1] = wlr_egl_create_image_from_dmabuf(renderer->egl,
|
||||
&chroma, &buffer->external_only);
|
||||
if (buffer->image[1] == EGL_NO_IMAGE_KHR) {
|
||||
wlr_egl_destroy_image(renderer->egl, buffer->image[0]);
|
||||
goto error_buffer;
|
||||
}
|
||||
} else {
|
||||
buffer->n_images = 1;
|
||||
buffer->image[0] = wlr_egl_create_image_from_dmabuf(renderer->egl,
|
||||
&dmabuf, &buffer->external_only);
|
||||
if (buffer->image[0] == EGL_NO_IMAGE_KHR) {
|
||||
goto error_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
wlr_addon_init(&buffer->addon, &wlr_buffer->addons, renderer,
|
||||
|
|
@ -278,7 +314,7 @@ GLuint wlr_gles2_renderer_get_buffer_fbo(struct wlr_renderer *wlr_renderer,
|
|||
|
||||
struct wlr_gles2_buffer *buffer = gles2_buffer_get_or_create(renderer, wlr_buffer);
|
||||
if (buffer) {
|
||||
fbo = gles2_buffer_get_fbo(buffer);
|
||||
fbo = gles2_buffer_get_fbo(buffer, 0);
|
||||
}
|
||||
|
||||
wlr_egl_restore_context(&prev_ctx);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ static bool gles2_texture_bind(struct wlr_gles2_texture *texture) {
|
|||
return false;
|
||||
}
|
||||
|
||||
GLuint fbo = gles2_buffer_get_fbo(texture->buffer);
|
||||
GLuint fbo = gles2_buffer_get_fbo(texture->buffer, 0);
|
||||
if (!fbo) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -419,7 +419,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf(
|
|||
glBindTexture(texture->target, buffer->tex);
|
||||
glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
renderer->procs.glEGLImageTargetTexture2DOES(texture->target, buffer->image);
|
||||
renderer->procs.glEGLImageTargetTexture2DOES(texture->target, buffer->image[0]);
|
||||
glBindTexture(texture->target, 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue