From 5116e680d5faa3927d9fc56304b7760ee0e612ce Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Fri, 3 Jul 2020 14:53:52 +0800 Subject: [PATCH 22/74] HACK: pixman-renderer: Support mali egl client and egl buffer attaching The mali clients requires mali_buffer_sharing extension, and it needs lots of hacks to attach a wl_buffer created in that way. Signed-off-by: Jeffy Chen --- libweston/meson.build | 10 +- libweston/pixman-renderer.c | 365 ++++++++++++++++++++++++++++-------- 2 files changed, 290 insertions(+), 85 deletions(-) diff --git a/libweston/meson.build b/libweston/meson.build index 257d695..a73e932 100644 --- a/libweston/meson.build +++ b/libweston/meson.build @@ -70,12 +70,10 @@ srcs_libweston = [ weston_direct_display_server_protocol_h, ] -if get_option('renderer-gl') - dep_egl = dependency('egl', required: false) - if not dep_egl.found() - error('libweston + gl-renderer requires egl which was not found. Or, you can use \'-Drenderer-gl=false\'.') - endif - deps_libweston += dep_egl +dep_egl = dependency('egl', required: false) +dep_gbm = dependency('gbm', required: false) +if dep_egl.found() and dep_gbm.found() + deps_libweston += [ dep_egl, dep_gbm ] endif lib_weston = shared_library( diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c index d5c5422..ece4d91 100644 --- a/libweston/pixman-renderer.c +++ b/libweston/pixman-renderer.c @@ -46,6 +46,19 @@ #include "linux-dmabuf.h" #include "linux-dmabuf-unstable-v1-server-protocol.h" +#ifdef ENABLE_EGL +#include +#include + +#include +#include +#include +#include +#include +#include "shared/platform.h" +#include "shared/weston-egl-ext.h" /* for PFN* stuff */ +#endif + struct pixman_output_state { void *shadow_buffer; pixman_image_t *shadow_image; @@ -75,6 +88,18 @@ struct pixman_renderer { struct wl_signal destroy_signal; struct weston_drm_format_array supported_formats; + +#ifdef ENABLE_EGL + PFNEGLBINDWAYLANDDISPLAYWL bind_display; + PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display; + PFNEGLQUERYWAYLANDBUFFERWL query_buffer; + EGLDisplay egl_display; + + int drm_fd; + struct gbm_device *gbm; + + bool egl_inited; +#endif }; struct dmabuf_data { @@ -82,6 +107,16 @@ struct dmabuf_data { size_t size; }; +#ifdef ENABLE_EGL +/* HACK: For mali_buffer_sharing */ +struct egl_buffer_info { + int dma_fd; + int width; + int height; + unsigned int stride; +}; +#endif + static inline struct pixman_output_state * get_output_state(struct weston_output *output) { @@ -636,6 +671,90 @@ buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data) ps->buffer_destroy_listener.notify = NULL; } +static void +pixman_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf) +{ + struct dmabuf_data *data = dmabuf->user_data; + linux_dmabuf_buffer_set_user_data(dmabuf, NULL, NULL); + + if (data) { + if (data->ptr) + munmap(data->ptr, data->size); + + free(data); + } +} + +static bool +pixman_renderer_prepare_dmabuf(struct linux_dmabuf_buffer *dmabuf) +{ + struct dmabuf_attributes *attributes = &dmabuf->attributes; + struct dmabuf_data *data; + size_t total_size, vstride0; + void *ptr; + int i; + + data = linux_dmabuf_buffer_get_user_data(dmabuf); + if (data) + return true; + + total_size = lseek(attributes->fd[0], 0, SEEK_END); + + for (i = 0; i < attributes->n_planes; i++) { + if (attributes->modifier[i] != DRM_FORMAT_MOD_INVALID) + return false; + } + + /* reject all flags we do not recognize or handle */ + if (attributes->flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) + return false; + + if (attributes->n_planes < 0) + return false; + + if (attributes->n_planes == 1) + goto out; + + vstride0 = (attributes->offset[1] - attributes->offset[0]) / + attributes->stride[0]; + + for (i = 1; i < attributes->n_planes; i++) { + size_t size = attributes->offset[i] - attributes->offset[i - 1]; + size_t vstride = size / attributes->stride[i - 1]; + + /* not contig */ + if (size <= 0 || vstride <= 0 || + attributes->offset[i - 1] + size > total_size) + return false; + + /* stride unmatched */ + if ((vstride != vstride0 && vstride != vstride0 / 2) || + (attributes->stride[i] != attributes->stride[0] && + attributes->stride[i] != attributes->stride[0] / 2)) + return false; + } + +out: + /* Handle contig dma buffer */ + + ptr = mmap(NULL, total_size, PROT_READ, + MAP_SHARED, attributes->fd[0], 0); + if (!ptr) + return false; + + data = zalloc(sizeof *data); + if (!data) { + munmap(ptr, total_size); + return false; + } + + data->size = total_size; + data->ptr = ptr; + linux_dmabuf_buffer_set_user_data(dmabuf, data, + pixman_renderer_destroy_dmabuf); + return true; +} + static void pixman_renderer_attach_dmabuf(struct weston_surface *es, struct weston_buffer *buffer, @@ -647,13 +766,12 @@ pixman_renderer_attach_dmabuf(struct weston_surface *es, pixman_format_code_t pixman_format; size_t vstride; + if (!pixman_renderer_prepare_dmabuf(dmabuf)) + goto err; + data = linux_dmabuf_buffer_get_user_data(dmabuf); - if (!data || !data->ptr) { - weston_buffer_reference(&ps->buffer_ref, NULL); - weston_buffer_release_reference(&ps->buffer_release_ref, - NULL); - return; - } + if (!data || !data->ptr) + goto err; buffer->width = attributes->width; buffer->height = attributes->height; @@ -694,10 +812,7 @@ pixman_renderer_attach_dmabuf(struct weston_surface *es, #endif default: weston_log("Unsupported dmabuf format\n"); - weston_buffer_reference(&ps->buffer_ref, NULL); - weston_buffer_release_reference(&ps->buffer_release_ref, - NULL); - return; + goto err; break; } @@ -710,16 +825,25 @@ pixman_renderer_attach_dmabuf(struct weston_surface *es, buffer_state_handle_buffer_destroy; wl_signal_add(&buffer->destroy_signal, &ps->buffer_destroy_listener); + return; +err: + weston_buffer_reference(&ps->buffer_ref, NULL); + weston_buffer_release_reference(&ps->buffer_release_ref, NULL); } static void pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) { + struct pixman_renderer *pr = get_renderer(es->compositor); struct pixman_surface_state *ps = get_surface_state(es); struct wl_shm_buffer *shm_buffer; struct linux_dmabuf_buffer *dmabuf; const struct pixel_format_info *pixel_info; +#ifdef ENABLE_EGL + EGLint format; +#endif + weston_buffer_reference(&ps->buffer_ref, buffer); weston_buffer_release_reference(&ps->buffer_release_ref, es->buffer_release_ref.buffer_release); @@ -742,7 +866,56 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) if (! shm_buffer) { if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource))) { pixman_renderer_attach_dmabuf(es, buffer, dmabuf); +#ifdef ENABLE_EGL + } else if (pr->egl_inited && + pr->query_buffer(pr->egl_display, + (void *)buffer->resource, + EGL_TEXTURE_FORMAT, &format)){ + struct egl_buffer_info *info; + struct linux_dmabuf_buffer dmabuf = { 0 }; + struct dmabuf_attributes *attributes = + &dmabuf.attributes; + struct stat s; + int width, height; + + pr->query_buffer(pr->egl_display, + (void *)buffer->resource, + EGL_WIDTH, &width); + pr->query_buffer(pr->egl_display, + (void *)buffer->resource, + EGL_HEIGHT, &height); + + info = wl_resource_get_user_data(buffer->resource); + if (!info) + goto err; + + if (fstat(info->dma_fd, &s) < 0 || + info->width != width || info->height != height) + goto err; + + switch (format) { + case EGL_TEXTURE_RGB: + attributes->format = DRM_FORMAT_RGB888; + break; + case EGL_TEXTURE_RGBA: + attributes->format = DRM_FORMAT_ARGB8888; + break; + default: + goto err; + } + + attributes->n_planes = 1; + attributes->fd[0] = info->dma_fd; + attributes->width = info->width; + attributes->height = info->height; + attributes->stride[0] = info->stride; + + pixman_renderer_attach_dmabuf(es, buffer, &dmabuf); + } else { +err: +#else } else { +#endif weston_log("unhandled buffer type!\n"); weston_buffer_reference(&ps->buffer_ref, NULL); weston_buffer_release_reference(&ps->buffer_release_ref, @@ -880,6 +1053,21 @@ pixman_renderer_destroy(struct weston_compositor *ec) { struct pixman_renderer *pr = get_renderer(ec); +#ifdef ENABLE_EGL + if (pr->egl_inited) { + if (pr->unbind_display) + pr->unbind_display(pr->egl_display, ec->wl_display); + + eglTerminate(pr->egl_display); + eglReleaseThread(); + + if (pr->gbm) + gbm_device_destroy(pr->gbm); + + close(pr->drm_fd); + } +#endif + wl_signal_emit(&pr->destroy_signal, pr); weston_binding_destroy(pr->debug_binding); @@ -958,79 +1146,11 @@ debug_binding(struct weston_keyboard *keyboard, const struct timespec *time, } } -static void -pixman_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf) -{ - struct dmabuf_data *data = dmabuf->user_data; - linux_dmabuf_buffer_set_user_data(dmabuf, NULL, NULL); - - if (data) { - if (data->ptr) - munmap(data->ptr, data->size); - - free(data); - } -} - static bool pixman_renderer_import_dmabuf(struct weston_compositor *ec, struct linux_dmabuf_buffer *dmabuf) { - struct dmabuf_attributes *attributes = &dmabuf->attributes; - struct dmabuf_data *data; - size_t total_size, vstride0; - int i; - - for (i = 0; i < attributes->n_planes; i++) { - if (attributes->modifier[i] != DRM_FORMAT_MOD_INVALID) - return false; - } - - /* reject all flags we do not recognize or handle */ - if (attributes->flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) - return false; - - if (attributes->n_planes < 0) - return false; - - if (attributes->n_planes == 1) - goto out; - - total_size = lseek(attributes->fd[0], 0, SEEK_END); - vstride0 = (attributes->offset[1] - attributes->offset[0]) / - attributes->stride[0]; - - for (i = 1; i < attributes->n_planes; i++) { - size_t size = attributes->offset[i] - attributes->offset[i - 1]; - size_t vstride = size / attributes->stride[i - 1]; - - /* not contig */ - if (size <= 0 || vstride <= 0 || - attributes->offset[i - 1] + size > total_size) - return false; - - /* stride unmatched */ - if ((vstride != vstride0 && vstride != vstride0 / 2) || - (attributes->stride[i] != attributes->stride[0] && - attributes->stride[i] != attributes->stride[0] / 2)) - return false; - } - -out: - /* Handle contig dma buffer */ - - data = zalloc(sizeof *data); - if (!data) - return false; - - linux_dmabuf_buffer_set_user_data(dmabuf, data, - pixman_renderer_destroy_dmabuf); - - data->size = lseek(attributes->fd[0], 0, SEEK_END); - - data->ptr = mmap(NULL, data->size, PROT_READ, - MAP_SHARED, attributes->fd[0], 0); - return data->ptr != MAP_FAILED; + return pixman_renderer_prepare_dmabuf(dmabuf); } static const struct weston_drm_format_array * @@ -1086,6 +1206,89 @@ out: return ret; } +#ifdef ENABLE_EGL +static bool +pixman_renderer_init_egl(struct pixman_renderer *pr, + struct weston_compositor *ec) +{ + PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display; + const char *extensions; + + get_platform_display = + (void *) eglGetProcAddress("eglGetPlatformDisplayEXT"); + pr->query_buffer = + (void *) eglGetProcAddress("eglQueryWaylandBufferWL"); + pr->bind_display = + (void *) eglGetProcAddress("eglBindWaylandDisplayWL"); + pr->unbind_display = + (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL"); + + if (!get_platform_display || !pr->query_buffer || + !pr->bind_display || !pr->unbind_display) { + weston_log("Failed to get egl proc\n"); + return false; + } + + pr->drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); + if (pr->drm_fd < 0) { + weston_log("Failed to open drm dev\n"); + return false; + } + + pr->gbm = gbm_create_device(pr->drm_fd); + if (!pr->gbm) { + weston_log("Failed to create gbm device\n"); + goto err_close_fd; + } + + pr->egl_display = get_platform_display(EGL_PLATFORM_GBM_KHR, + (void*) pr->gbm, NULL); + if (pr->egl_display == EGL_NO_DISPLAY) { + weston_log("Failed to create egl display\n"); + goto err_destroy_gbm; + } + + if (!eglInitialize(pr->egl_display, NULL, NULL)) { + weston_log("Failed to initialize egl\n"); + goto err_terminate_display; + } + + extensions = + (const char *) eglQueryString(pr->egl_display, EGL_EXTENSIONS); + if (!extensions) { + weston_log("Retrieving EGL extension string failed.\n"); + goto err_terminate_display; + } + + if (!weston_check_egl_extension(extensions, + "EGL_WL_bind_wayland_display")) { + weston_log("Wayland extension not supported.\n"); + goto err_terminate_display; + } + + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + weston_log("Failed to bind api\n"); + goto err_terminate_display; + } + + if (!pr->bind_display(pr->egl_display, ec->wl_display)) + goto err_terminate_display; + + pr->egl_inited = true; + return true; + +err_terminate_display: + eglTerminate(pr->egl_display); +err_destroy_gbm: + gbm_device_destroy(pr->gbm); + pr->gbm = NULL; +err_close_fd: + close(pr->drm_fd); + pr->drm_fd = -1; + return false; +} +#endif + WL_EXPORT int pixman_renderer_init(struct weston_compositor *ec) { @@ -1150,6 +1353,10 @@ pixman_renderer_init(struct weston_compositor *ec) renderer->base.get_supported_formats = pixman_renderer_get_supported_formats; +#ifdef ENABLE_EGL + pixman_renderer_init_egl(renderer, ec); +#endif + return 0; } -- 2.20.1