From 0dceb98f796c5d6a8d1237287e7224a811ac03e9 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sun, 6 Oct 2019 14:08:52 +0000 Subject: [PATCH] Add dmabuf import & render --- src/render.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/src/render.c b/src/render.c index 87c7487..a810b21 100644 --- a/src/render.c +++ b/src/render.c @@ -44,6 +44,27 @@ struct renderer { EGLSurface surface; EGLContext context; GLuint shader_program; + uint32_t width; + uint32_t height; + GLint read_format; + GLint read_type; +}; + +struct dmabuf_plane { + int fd; + uint32_t offset; + uint32_t size; + uint32_t pitch; + uint64_t modifier; +}; + +struct dmabuf_frame { + uint32_t width; + uint32_t height; + uint32_t format; + + uint32_t n_planes; + struct dmabuf_plane plane[4]; }; static inline void* gl_load_single_extension(const char* name) @@ -240,7 +261,7 @@ void renderer_destroy(struct renderer* self) glDeleteProgram(self->shader_program); } -int renderer_init(struct renderer* self, int width, int height) +int renderer_init(struct renderer* self, uint32_t width, uint32_t height) { if (!eglBindAPI(EGL_OPENGL_ES_API)) return -1; @@ -308,6 +329,11 @@ int renderer_init(struct renderer* self, int width, int height) glUseProgram(self->shader_program); + self->width = width; + self->height = height; + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &self->read_format); + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &self->read_type); + glViewport(0, 0, width, height); gl_clear(); @@ -321,3 +347,75 @@ surface_failure: eglDestroyContext(self->display, self->context); return -1; } + +static inline void append_attr(EGLint* dst, int* i, EGLint name, EGLint value) +{ + dst[*i] = name; + i[0] += 1; + dst[*i] = value; + i[0] += 1; +} + +static void dmabuf_attr_append_planes(EGLint* dst, int* i, + struct dmabuf_frame* frame) +{ +#define APPEND_PLANE_ATTR(n) \ + if (frame->n_planes <= n) \ + return; \ +\ + append_attr(dst, i, EGL_DMA_BUF_PLANE##n##_FD_EXT, frame->plane[n].fd); \ + append_attr(dst, i, EGL_DMA_BUF_PLANE##n##_OFFSET_EXT, frame->plane[n].offset); \ + append_attr(dst, i, EGL_DMA_BUF_PLANE##n##_PITCH_EXT, frame->plane[n].pitch); \ + append_attr(dst, i, EGL_DMA_BUF_PLANE##n##_MODIFIER_LO_EXT, frame->plane[n].modifier); \ + append_attr(dst, i, EGL_DMA_BUF_PLANE##n##_MODIFIER_HI_EXT, frame->plane[n].modifier >> 32); \ + + APPEND_PLANE_ATTR(0); + APPEND_PLANE_ATTR(1); + APPEND_PLANE_ATTR(2); + APPEND_PLANE_ATTR(3); +#undef APPEND_PLANE_ATTR +} + +int render_dmabuf_frame(struct renderer* self, struct dmabuf_frame* frame) +{ + int index = 0; + EGLint attr[6 + 10 * 4 + 1]; + + if (frame->n_planes == 0) + return -1; + + append_attr(attr, &index, EGL_WIDTH, frame->width); + append_attr(attr, &index, EGL_HEIGHT, frame->height); + append_attr(attr, &index, EGL_LINUX_DRM_FOURCC_EXT, frame->format); + dmabuf_attr_append_planes(attr, &index, frame); + attr[index++] = EGL_NONE; + + EGLImageKHR image = + eglCreateImageKHR(self->display, EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, NULL, attr); + if (!image) + return -1; + + GLuint tex; + glGenTextures(1, &tex); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); + + gl_render(); + + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &tex); + eglDestroyImageKHR(self->display, image); + + return 0; +} + +/* Copy a horizontal stripe from the GL frame into a pixel buffer */ +void render_copy_pixels(struct renderer* self, void* dst, uint32_t y, uint32_t height) +{ + assert(y + height <= self->height); + + glReadPixels(0, y, self->width, height, self->read_format, + self->read_type, dst); +}