mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-06-13 14:32:57 -04: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 change 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
2283e05c30
commit
c074f6e83f
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
|
struct wl_list link; // wlr_gles2_renderer.buffers
|
||||||
bool external_only;
|
bool external_only;
|
||||||
|
|
||||||
EGLImageKHR image;
|
int n_images;
|
||||||
GLuint rbo;
|
EGLImageKHR image[4];
|
||||||
GLuint fbo;
|
GLuint rbo[4];
|
||||||
|
GLuint fbo[4];
|
||||||
|
|
||||||
GLuint tex;
|
GLuint tex;
|
||||||
|
|
||||||
struct wlr_addon addon;
|
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,
|
void get_gles2_shm_formats(const struct wlr_gles2_renderer *renderer,
|
||||||
struct wlr_drm_format_set *out);
|
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_gles2_renderer *gles2_get_renderer(
|
||||||
struct wlr_renderer *wlr_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) {
|
if (!fbo) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,13 +59,18 @@ static void destroy_buffer(struct wlr_gles2_buffer *buffer) {
|
||||||
|
|
||||||
push_gles2_debug(buffer->renderer);
|
push_gles2_debug(buffer->renderer);
|
||||||
|
|
||||||
glDeleteFramebuffers(1, &buffer->fbo);
|
for (int i = 0; i < buffer->n_images; ++i) {
|
||||||
glDeleteRenderbuffers(1, &buffer->rbo);
|
glDeleteFramebuffers(1, &buffer->fbo[i]);
|
||||||
|
glDeleteRenderbuffers(1, &buffer->rbo[i]);
|
||||||
|
}
|
||||||
|
|
||||||
glDeleteTextures(1, &buffer->tex);
|
glDeleteTextures(1, &buffer->tex);
|
||||||
|
|
||||||
pop_gles2_debug(buffer->renderer);
|
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);
|
wlr_egl_restore_context(&prev_ctx);
|
||||||
|
|
||||||
|
|
@ -83,42 +88,42 @@ static const struct wlr_addon_interface buffer_addon_impl = {
|
||||||
.destroy = handle_buffer_destroy,
|
.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) {
|
if (buffer->external_only) {
|
||||||
wlr_log(WLR_ERROR, "DMA-BUF format is external-only");
|
wlr_log(WLR_ERROR, "DMA-BUF format is external-only");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer->fbo) {
|
if (buffer->fbo[index]) {
|
||||||
return buffer->fbo;
|
return buffer->fbo[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
push_gles2_debug(buffer->renderer);
|
push_gles2_debug(buffer->renderer);
|
||||||
|
|
||||||
if (!buffer->rbo) {
|
if (!buffer->rbo[index]) {
|
||||||
glGenRenderbuffers(1, &buffer->rbo);
|
glGenRenderbuffers(1, &buffer->rbo[index]);
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, buffer->rbo);
|
glBindRenderbuffer(GL_RENDERBUFFER, buffer->rbo[index]);
|
||||||
buffer->renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
|
buffer->renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
|
||||||
buffer->image);
|
buffer->image[index]);
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
glGenFramebuffers(1, &buffer->fbo);
|
glGenFramebuffers(1, &buffer->fbo[index]);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo[index]);
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||||
GL_RENDERBUFFER, buffer->rbo);
|
GL_RENDERBUFFER, buffer->rbo[index]);
|
||||||
GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
|
if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
wlr_log(WLR_ERROR, "Failed to create FBO");
|
wlr_log(WLR_ERROR, "Failed to create FBO");
|
||||||
glDeleteFramebuffers(1, &buffer->fbo);
|
glDeleteFramebuffers(1, &buffer->fbo[index]);
|
||||||
buffer->fbo = 0;
|
buffer->fbo[index] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_gles2_debug(buffer->renderer);
|
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,
|
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;
|
goto error_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->image = wlr_egl_create_image_from_dmabuf(renderer->egl,
|
if (dmabuf.format == DRM_FORMAT_NV12) {
|
||||||
&dmabuf, &buffer->external_only);
|
buffer->n_images = 2;
|
||||||
if (buffer->image == EGL_NO_IMAGE_KHR) {
|
|
||||||
goto error_buffer;
|
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,
|
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);
|
struct wlr_gles2_buffer *buffer = gles2_buffer_get_or_create(renderer, wlr_buffer);
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
fbo = gles2_buffer_get_fbo(buffer);
|
fbo = gles2_buffer_get_fbo(buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_egl_restore_context(&prev_ctx);
|
wlr_egl_restore_context(&prev_ctx);
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ static bool gles2_texture_bind(struct wlr_gles2_texture *texture) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint fbo = gles2_buffer_get_fbo(texture->buffer);
|
GLuint fbo = gles2_buffer_get_fbo(texture->buffer, 0);
|
||||||
if (!fbo) {
|
if (!fbo) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -419,7 +419,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf(
|
||||||
glBindTexture(texture->target, buffer->tex);
|
glBindTexture(texture->target, buffer->tex);
|
||||||
glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, 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);
|
glBindTexture(texture->target, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue