From 16302ea084be281cbd71bb40ceda7d30b1c44eff Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Fri, 3 Jul 2020 14:53:52 +0800 Subject: [PATCH 25/95] 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 | 427 ++++++++++++++++++++++++++++-------- 2 files changed, 338 insertions(+), 99 deletions(-) diff --git a/libweston/meson.build b/libweston/meson.build index 313a84f..6a845cc 100644 --- a/libweston/meson.build +++ b/libweston/meson.build @@ -73,12 +73,10 @@ srcs_libweston = [ subdir('desktop') -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 07b7888..7339541 100644 --- a/libweston/pixman-renderer.c +++ b/libweston/pixman-renderer.c @@ -47,6 +47,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 { pixman_image_t *shadow_image; pixman_image_t *hw_buffer; @@ -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) { @@ -669,6 +704,91 @@ pixman_renderer_surface_set_color(struct weston_surface *es, ps->image = pixman_image_create_solid_fill(&color); } +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 && + attributes->modifier[i] != DRM_FORMAT_MOD_LINEAR) + 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, @@ -680,14 +800,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, - BUFFER_WILL_NOT_BE_ACCESSED); - weston_buffer_release_reference(&ps->buffer_release_ref, - NULL); - return; - } + if (!data || !data->ptr) + goto err; buffer->width = attributes->width; buffer->height = attributes->height; @@ -752,11 +870,7 @@ pixman_renderer_attach_dmabuf(struct weston_surface *es, #endif default: weston_log("Unsupported dmabuf format\n"); - weston_buffer_reference(&ps->buffer_ref, NULL, - BUFFER_WILL_NOT_BE_ACCESSED); - weston_buffer_release_reference(&ps->buffer_release_ref, - NULL); - return; + goto err; break; } @@ -769,6 +883,11 @@ 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, + BUFFER_WILL_NOT_BE_ACCESSED); + weston_buffer_release_reference(&ps->buffer_release_ref, NULL); } static void @@ -776,7 +895,6 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) { 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; weston_buffer_reference(&ps->buffer_ref, buffer, @@ -810,17 +928,40 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) return; } - if (buffer->type != WESTON_BUFFER_SHM) { - if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource))) { - pixman_renderer_attach_dmabuf(es, buffer, dmabuf); - } else { - weston_log("unhandled buffer type!\n"); - weston_buffer_reference(&ps->buffer_ref, NULL, - BUFFER_WILL_NOT_BE_ACCESSED); - weston_buffer_release_reference(&ps->buffer_release_ref, - NULL); - } + if (buffer->type == WESTON_BUFFER_DMABUF) { + struct linux_dmabuf_buffer *dmabuf = + linux_dmabuf_buffer_get(buffer->resource); + pixman_renderer_attach_dmabuf(es, buffer, dmabuf); + return; + } + +#ifdef ENABLE_EGL + if (buffer->type == WESTON_BUFFER_RENDERER_OPAQUE) { + struct egl_buffer_info *info; + struct linux_dmabuf_buffer dmabuf = { 0 }; + struct dmabuf_attributes *attributes = &dmabuf.attributes; + + info = wl_resource_get_user_data(buffer->resource); + attributes->format = buffer->pixel_format->format; + attributes->width = buffer->width; + attributes->height = buffer->height; + + attributes->n_planes = 1; + attributes->fd[0] = info->dma_fd; + attributes->stride[0] = info->stride; + + pixman_renderer_attach_dmabuf(es, buffer, &dmabuf); + return; + } +#endif + + if (buffer->type != WESTON_BUFFER_SHM) { + weston_log("unhandled buffer type!\n"); + weston_buffer_reference(&ps->buffer_ref, NULL, + BUFFER_WILL_NOT_BE_ACCESSED); + weston_buffer_release_reference(&ps->buffer_release_ref, + NULL); return; } @@ -849,6 +990,70 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) &ps->buffer_destroy_listener); } +#ifdef ENABLE_EGL +static bool +pixman_renderer_fill_buffer_info(struct weston_compositor *ec, + struct weston_buffer *buffer) +{ + struct pixman_renderer *pr = get_renderer(ec); + struct egl_buffer_info *info; + struct stat s; + EGLint format; + uint32_t fourcc; + EGLint y_inverted; + bool ret = true; + + if (!pr->egl_inited) + return false; + + info = wl_resource_get_user_data(buffer->resource); + if (!info) + return false; + + buffer->legacy_buffer = (struct wl_buffer *)buffer->resource; + ret &= pr->query_buffer(pr->egl_display, buffer->legacy_buffer, + EGL_WIDTH, &buffer->width); + ret &= pr->query_buffer(pr->egl_display, buffer->legacy_buffer, + EGL_HEIGHT, &buffer->height); + ret &= pr->query_buffer(pr->egl_display, buffer->legacy_buffer, + EGL_TEXTURE_FORMAT, &format); + if (!ret) { + weston_log("eglQueryWaylandBufferWL failed\n"); + return false; + } + + if (fstat(info->dma_fd, &s) < 0 || + info->width != buffer->width || info->height != buffer->height) + return false; + + switch (format) { + case EGL_TEXTURE_RGB: + fourcc = DRM_FORMAT_XRGB8888; + break; + case EGL_TEXTURE_RGBA: + fourcc = DRM_FORMAT_ARGB8888; + break; + default: + return false; + } + + buffer->pixel_format = pixel_format_get_info(fourcc); + assert(buffer->pixel_format); + buffer->format_modifier = DRM_FORMAT_MOD_INVALID; + + /* Assume scanout co-ordinate space i.e. (0,0) is top-left + * if the query fails */ + ret = pr->query_buffer(pr->egl_display, buffer->legacy_buffer, + EGL_WAYLAND_Y_INVERTED_WL, &y_inverted); + if (!ret || y_inverted) + buffer->buffer_origin = ORIGIN_TOP_LEFT; + else + buffer->buffer_origin = ORIGIN_BOTTOM_LEFT; + + return true; +} +#endif + static void pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps) { @@ -928,6 +1133,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); @@ -991,80 +1211,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 && - attributes->modifier[i] != DRM_FORMAT_MOD_LINEAR) - 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 * @@ -1120,6 +1271,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) { @@ -1141,6 +1375,9 @@ pixman_renderer_init(struct weston_compositor *ec) renderer->base.destroy = pixman_renderer_destroy; renderer->base.surface_copy_content = pixman_renderer_surface_copy_content; +#ifdef ENABLE_EGL + renderer->base.fill_buffer_info = pixman_renderer_fill_buffer_info; +#endif ec->renderer = &renderer->base; ec->capabilities |= WESTON_CAP_ROTATION_ANY; ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK; @@ -1181,6 +1418,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