[Mesa-dev] [PATCH v2 3/9] egl/tizen: add support of the swrast related features for tizen platform
Emil Velikov
emil.l.velikov at gmail.com
Thu Sep 28 13:51:54 UTC 2017
On 17 September 2017 at 19:01, Gwan-gyeong Mun <elongbug at gmail.com> wrote:
> It implements the egl swrast related features for tizen platform on platform_tizen.c
>
> It works with libtpl-egl (Tizen Porting Layer for egl) and libtbm (Tizen Buffer Manager)
> where back buffers of windows are backed by GEM objects. In Tizen a native window
> has a queue (tbm_surface_queue) of back buffers allocated by the WL_TBM
> (wayland client case, WL_TBM is abbreviation of wayland-tbm protocol) or gbm
> (tizen has implements gbm with tbm) or tbm through tbm_backend.
>
> For each frame, EGL needs to
>
> dequeue the next back buffer - tizen_window_dequeue_buffer()
> render to the buffer
> enqueue the buffer - tizen_window_enqueue_buffer()
>
> After enqueuing, the buffer is no longer valid to EGL.
>
> Referenced documents:
> [1] https://www.x.org/wiki/Events/XDC2016/Program/XDC2016_Tizen_Window_System_EGL_Vulkan.pdf
> [2] https://wiki.tizen.org/wiki/3.0_Porting_Guide/Graphics_and_UI/libtpl-egl
> [3] https://wiki.tizen.org/wiki/TBM
>
> Signed-off-by: Mun Gwan-gyeong <elongbug at gmail.com>
> ---
> src/egl/Makefile.am | 6 +
> src/egl/drivers/dri2/platform_tizen.c | 618 ++++++++++++++++++++++++++++++++++
> 2 files changed, 624 insertions(+)
> create mode 100644 src/egl/drivers/dri2/platform_tizen.c
>
> diff --git a/src/egl/Makefile.am b/src/egl/Makefile.am
> index 8ff1ffaba1..ef0c47ad76 100644
> --- a/src/egl/Makefile.am
> +++ b/src/egl/Makefile.am
> @@ -104,6 +104,12 @@ libEGL_common_la_LIBADD += $(ANDROID_LIBS)
> dri2_backend_FILES += drivers/dri2/platform_android.c
> endif
>
> +if HAVE_PLATFORM_TIZEN
> +AM_CFLAGS += $(TIZEN_CFLAGS)
> +libEGL_common_la_LIBADD += $(TIZEN_LIBS)
> +dri2_backend_FILES += drivers/dri2/platform_tizen.c
> +endif
> +
> AM_CFLAGS += \
> -I$(top_srcdir)/src/loader \
> -I$(top_builddir)/src/egl/drivers/dri2 \
> diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c
> new file mode 100644
> index 0000000000..efdf79682b
> --- /dev/null
> +++ b/src/egl/drivers/dri2/platform_tizen.c
> @@ -0,0 +1,618 @@
> +/*
> + * Mesa 3-D graphics library
> + *
> + * Copyright (C) 2017 Samsung Electronics co., Ltd. All Rights Reserved
> + *
> + * Based on platform_android, which has
> + *
> + * Copyright (C) 2010-2011 Chia-I Wu <olvaffe at gmail.com>
> + * Copyright (C) 2010-2011 LunarG Inc.
> + * Copyright © 2011 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + * Gwan-gyeong Mun <elongbug at gmail.com>
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <xf86drm.h>
> +#include <dlfcn.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +
> +#include "egl_dri2.h"
> +#include "egl_dri2_fallbacks.h"
> +#include "loader.h"
> +
> +static EGLBoolean
> +tizen_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf)
> +{
> + int width, height;
> +
> + dri2_surf->tbm_surface = tpl_surface_dequeue_buffer(dri2_surf->tpl_surface);
> +
> + if (!dri2_surf->tbm_surface)
> + return EGL_FALSE;
> +
> + tbm_surface_internal_ref(dri2_surf->tbm_surface);
> +
> + tpl_surface_get_size(dri2_surf->tpl_surface, &width, &height);
> + if (dri2_surf->base.Width != width || dri2_surf->base.Height != height) {
> + dri2_surf->base.Width = width;
> + dri2_surf->base.Height = height;
> + }
> +
> + return EGL_TRUE;
> +}
> +
> +static EGLBoolean
> +tizen_window_enqueue_buffer_with_damage(_EGLDisplay *disp,
> + struct dri2_egl_surface *dri2_surf,
> + const EGLint *rects,
> + EGLint n_rects)
> +{
> + tpl_result_t ret;
> +
> + /* To avoid blocking other EGL calls, release the display mutex before
> + * we enter tizen_window_enqueue_buffer() and re-acquire the mutex upon
> + * return.
> + */
> + mtx_unlock(&disp->Mutex);
> +
> + if (n_rects < 1 || rects == NULL) {
> + /* if there is no damage, call the normal API tpl_surface_enqueue_buffer */
> + ret = tpl_surface_enqueue_buffer(dri2_surf->tpl_surface,
> + dri2_surf->tbm_surface);
> + } else {
> + /* if there are rectangles of damage region,
> + call the API tpl_surface_enqueue_buffer_with_damage() */
> + ret = tpl_surface_enqueue_buffer_with_damage(dri2_surf->tpl_surface,
> + dri2_surf->tbm_surface,
> + n_rects, rects);
> + }
> +
> + if (ret != TPL_ERROR_NONE) {
> + _eglLog(_EGL_DEBUG, "%s : %d :tpl_surface_enqueue fail", __func__, __LINE__);
> + }
There's no need for brackets for a single line if statements.
Also: shouldn't we issue a _EGL_WARNING when the call fails and/or
return EGL_FALSE?
> +
> + tbm_surface_internal_unref(dri2_surf->tbm_surface);
> + dri2_surf->tbm_surface = NULL;
> +
> + mtx_lock(&disp->Mutex);
> +
> + return EGL_TRUE;
> +}
> +
> +static EGLBoolean
> +tizen_window_enqueue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf)
> +{
> + return tizen_window_enqueue_buffer_with_damage(disp, dri2_surf, NULL, 0);
> +}
> +
> +static void
> +tizen_window_cancel_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf)
> +{
> + tizen_window_enqueue_buffer(disp, dri2_surf);
> +}
> +
> +static _EGLSurface *
> +tizen_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
> + _EGLConfig *conf, void *native_window,
> + const EGLint *attrib_list)
> +{
> + __DRIcreateNewDrawableFunc createNewDrawable;
> + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> + struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
> + struct dri2_egl_surface *dri2_surf;
> + const __DRIconfig *config;
> + tpl_surface_type_t tpl_surf_type = TPL_SURFACE_ERROR;
> + tpl_result_t ret = TPL_ERROR_INVALID_PARAMETER;
> +
> + dri2_surf = calloc(1, sizeof *dri2_surf);
> + if (!dri2_surf) {
> + _eglError(EGL_BAD_ALLOC, "tizen_create_surface");
> + return NULL;
> + }
> +
> + if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
> + goto cleanup_surface;
> +
> + config = dri2_get_dri_config(dri2_conf, type,
> + dri2_surf->base.GLColorspace);
> + if (!config)
> + goto cleanup_surface;
> +
> + if (type == EGL_WINDOW_BIT) {
> + unsigned int alpha, depth;
> +
> + if (!native_window) {
> + _eglError(EGL_BAD_NATIVE_WINDOW, "tizen_create_surface needs vaild native window");
> + goto cleanup_surface;
> + }
> + dri2_surf->native_win = native_window;
> +
> + dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_DEPTH_SIZE, &depth);
> + dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_ALPHA_SIZE, &alpha);
> +
> + ret = tpl_display_get_native_window_info(dri2_dpy->tpl_display,
> + (tpl_handle_t)native_window,
> + &dri2_surf->base.Width,
> + &dri2_surf->base.Height,
> + &dri2_surf->tbm_format,
> + depth, alpha);
> +
> + if (ret != TPL_ERROR_NONE || dri2_surf->tbm_format == 0) {
> + _eglError(EGL_BAD_NATIVE_WINDOW, "tizen_create_surface fails on tpl_display_get_native_window_info()");
> + goto cleanup_surface;
> + }
> +
> + tpl_surf_type = TPL_SURFACE_TYPE_WINDOW;
> + } else if (type == EGL_PIXMAP_BIT) {
> +
> + if (!native_window) {
> + _eglError(EGL_BAD_NATIVE_PIXMAP, "tizen_create_surface needs valid native pixmap");
> + goto cleanup_surface;
> + }
> + ret = tpl_display_get_native_pixmap_info(dri2_dpy->tpl_display,
> + (tpl_handle_t)native_window,
> + &dri2_surf->base.Width,
> + &dri2_surf->base.Height,
> + &dri2_surf->tbm_format);
> +
> + if (ret != TPL_ERROR_NONE || dri2_surf->tbm_format == 0) {
> + _eglError(EGL_BAD_NATIVE_PIXMAP, "tizen_create_surface fails on tpl_display_get_native_pixmap_info");
> + goto cleanup_surface;
> + }
> +
> + tpl_surf_type = TPL_SURFACE_TYPE_PIXMAP;
> + } else {
> + _eglError(EGL_BAD_NATIVE_WINDOW, "tizen_create_surface does not support PBuffer");
> + goto cleanup_surface;
> + }
> +
> + dri2_surf->tpl_surface = tpl_surface_create(dri2_dpy->tpl_display,
> + (tpl_handle_t)native_window,
> + tpl_surf_type,
> + dri2_surf->tbm_format);
> + if (!dri2_surf->tpl_surface)
> + goto cleanup_surface;
> +
> + createNewDrawable = dri2_dpy->swrast->createNewDrawable;
> +
> + dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen, config,
> + dri2_surf);
This seems odd as-is. Assuming you're adding dri2/dri3 later on -
otherwise please drop the createNewDrawable variable.
> + if (dri2_surf->dri_drawable == NULL) {
> + _eglError(EGL_BAD_ALLOC, "createNewDrawable");
> + goto cleanup_tpl_surface;
> + }
> +
> + return &dri2_surf->base;
> +
> +cleanup_tpl_surface:
> + tpl_object_unreference((tpl_object_t *)dri2_surf->tpl_surface);
> +cleanup_surface:
> + free(dri2_surf);
> +
> + return NULL;
> +}
> +
> +static _EGLSurface *
> +tizen_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
> + _EGLConfig *conf, void *native_window,
> + const EGLint *attrib_list)
> +{
> + return tizen_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
> + native_window, attrib_list);
> +}
> +
> +static _EGLSurface *
> +tizen_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
> + _EGLConfig *conf, void *native_pixmap,
> + const EGLint *attrib_list)
> +{
> + return tizen_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
> + native_pixmap, attrib_list);
> +}
> +
> +static EGLBoolean
> +tizen_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
> +{
> + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
> +
> + if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
> + if (dri2_surf->tbm_surface)
Fold the two conditionals onto a single line. Same applies throughout
the patch/series.
> + tizen_window_cancel_buffer(disp, dri2_surf);
> + }
> +
> + dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
> +
> + tpl_object_unreference((tpl_object_t *)dri2_surf->tpl_surface);
> +
> + free(dri2_surf);
> +
> + return EGL_TRUE;
> +}
> +
> +static int
> +update_buffers(struct dri2_egl_surface *dri2_surf)
> +{
> + if (dri2_surf->base.Type != EGL_WINDOW_BIT)
> + return 0;
> +
> + /* try to dequeue the next back buffer */
> + if (!dri2_surf->tbm_surface && !tizen_window_dequeue_buffer(dri2_surf)) {
> + _eglLog(_EGL_WARNING, "Could not dequeue buffer from native window");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static EGLBoolean
> +tizen_swap_buffers_with_damage(_EGLDriver *drv, _EGLDisplay *disp,
> + _EGLSurface *draw, const EGLint *rects,
> + EGLint n_rects)
> +{
> + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
> +
> + if (dri2_surf->base.Type != EGL_WINDOW_BIT)
> + return EGL_TRUE;
> +
> + if (dri2_surf->tbm_surface)
> + tizen_window_enqueue_buffer_with_damage(disp, dri2_surf, rects, n_rects);
> +
> + dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
> +
> + return EGL_TRUE;
> +}
> +
> +static EGLBoolean
> +tizen_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
> +{
> + return tizen_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
> +}
> +
> +static EGLBoolean
> +tizen_query_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
> + EGLint attribute, EGLint *value)
> +{
> + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
> + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
> + int width = 0, height = 0;
> +
> + if (tpl_display_get_native_window_info(dri2_dpy->tpl_display,
> + dri2_surf->native_win,
> + &width, &height, NULL, 0, 0) != TPL_ERROR_NONE)
> + return EGL_FALSE;
> +
> + switch (attribute) {
> + case EGL_WIDTH:
> + if (dri2_surf->base.Type == EGL_WINDOW_BIT && dri2_surf->native_win) {
> + *value = width;
> + return EGL_TRUE;
> + }
> + break;
> + case EGL_HEIGHT:
> + if (dri2_surf->base.Type == EGL_WINDOW_BIT && dri2_surf->native_win) {
> + *value = height;
> + return EGL_TRUE;
> + }
> + break;
> + default:
> + break;
> + }
This seems strange - get the window dimensions, even if a) there's no
window and b) one does not ask for them?
Also indentation is off.
> + return _eglQuerySurface(drv, dpy, surf, attribute, value);
> +}
> +
> +static int
> +tizen_swrast_get_stride_for_format(tbm_format format, int w)
> +{
> + switch (format) {
> + case TBM_FORMAT_RGB565:
> + return 2 * w;
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wswitch"
> + case TBM_FORMAT_BGRA8888:
> + case TBM_FORMAT_RGBA8888:
> +#pragma GCC diagnostic pop
> + case TBM_FORMAT_RGBX8888:
> + default:
> + return 4 * w;
> + }
> +}
You want something like gbm_bo_get_bpp.
No pragma magic, with sane default.
> +static void
> +tizen_swrast_get_image(__DRIdrawable * read,
> + int x, int y, int w, int h,
> + char *data, void *loaderPrivate)
> +{
> + struct dri2_egl_surface *dri2_surf = loaderPrivate;
> + tbm_surface_info_s surf_info;
> + int ret = TBM_SURFACE_ERROR_NONE;
> + int internal_stride, stride, i;
> +
> + if (!dri2_surf->tbm_surface) {
> + if (update_buffers(dri2_surf) < 0)
> + return;
> + }
> +
> + ret = tbm_surface_map(dri2_surf->tbm_surface, TBM_SURF_OPTION_READ, &surf_info);
> +
> + if (ret != TBM_SURFACE_ERROR_NONE) {
> + _eglLog(_EGL_WARNING, "Could not tbm_surface_map");
> + return;
> + }
> +
> + internal_stride = surf_info.planes[0].stride;
> + stride = w * 4;
You created a helper yet, use it to get the correct stride.
> +
> + for (i = 0; i < h; i++) {
> + memcpy(data + i * stride,
> + surf_info.planes[0].ptr + (x + i) * internal_stride + y, stride);
Nit: use something like fe2a6281b3b299998fe7399e7dbcc2077d773824
> + }
> +
> + tbm_surface_unmap(dri2_surf->tbm_surface);
> +}
> +
> +static void
> +tizen_swrast_put_image2(__DRIdrawable * draw, int op,
> + int x, int y, int w, int h, int stride,
> + char *data, void *loaderPrivate)
> +{
> + struct dri2_egl_surface *dri2_surf = loaderPrivate;
> + tbm_surface_info_s surf_info;
> + int ret = TBM_SURFACE_ERROR_NONE;
> + int internal_stride, i;
> +
> + if (op != __DRI_SWRAST_IMAGE_OP_DRAW && op != __DRI_SWRAST_IMAGE_OP_SWAP)
> + return;
> +
> + if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
> + if (!dri2_surf->tbm_surface) {
> + if (update_buffers(dri2_surf) < 0) {
> + _eglLog(_EGL_WARNING, "Could not get native buffer");
> + return;
> + }
> + }
> +
> + ret = tbm_surface_map(dri2_surf->tbm_surface, TBM_SURF_OPTION_WRITE, &surf_info);
> + if (ret != TBM_SURFACE_ERROR_NONE) {
> + _eglLog(_EGL_WARNING, "Could not tbm_surface_map");
> + return;
> + }
> +
> + internal_stride = surf_info.planes[0].stride;
> +
> + for (i = 0; i < h; i++) {
> + memcpy(surf_info.planes[0].ptr + (x + i) * internal_stride + y,
> + data + i * stride, stride);
Alike 3a5e3aa5a53cff55a5e31766d713a41ffa5a93d7 ?
> + }
> +
> + tbm_surface_unmap(dri2_surf->tbm_surface);
> + }
> +}
> +
> +static void
> +tizen_swrast_put_image(__DRIdrawable * draw, int op,
> + int x, int y, int w, int h,
> + char *data, void *loaderPrivate)
> +{
> + struct dri2_egl_surface *dri2_surf = loaderPrivate;
> + int stride;
> +
> + if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
> + if (!dri2_surf->tbm_surface) {
> + if (update_buffers(dri2_surf) < 0) {
> + _eglLog(_EGL_WARNING, "Could not get native buffer");
> + return;
> + }
> + }
Indentation seems off.
> +
> + stride = tizen_swrast_get_stride_for_format(dri2_surf->tbm_format, w);
> + tizen_swrast_put_image2(draw, op, x, y, w, h, stride, data, loaderPrivate);
> + }
> +}
> +
> +static EGLBoolean
> +tizen_add_configs(_EGLDriver *drv, _EGLDisplay *dpy)
> +{
> + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
> + int config_count = 0;
> +
> + for (int i = 0; dri2_dpy->driver_configs[i]; i++) {
> + struct dri2_egl_config *dri2_conf;
> + unsigned int red, blue, green, alpha, depth;
> + int surface_type = 0;
> + tpl_bool_t is_slow;
> + EGLint config_attrs[] = {
> + EGL_NATIVE_VISUAL_ID, 0,
> + EGL_NONE,
> + };
> + tpl_result_t res;
> +
> + dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
> + __DRI_ATTRIB_RED_SIZE, &red);
> + dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
> + __DRI_ATTRIB_GREEN_SIZE, &green);
> + dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
> + __DRI_ATTRIB_BLUE_SIZE, &blue);
> + dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
> + __DRI_ATTRIB_ALPHA_SIZE, &alpha);
> + dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
> + __DRI_ATTRIB_DEPTH_SIZE, &depth);
> +
Would be great if we can avoid all there roundtrips. My Tizen
knowledge is non-existent to suggest alternatives :-\
> + res = tpl_display_query_config(dri2_dpy->tpl_display, TPL_SURFACE_TYPE_WINDOW,
> + red, green, blue, alpha, depth,
> + &config_attrs[1], &is_slow);
> + if (res == TPL_ERROR_NONE)
> + surface_type |= EGL_WINDOW_BIT;
> +
> + res = tpl_display_query_config(dri2_dpy->tpl_display, TPL_SURFACE_TYPE_PIXMAP,
> + red, green, blue, alpha, depth,
> + &config_attrs[1], &is_slow);
> + if (res == TPL_ERROR_NONE)
> + surface_type |= EGL_PIXMAP_BIT;
> +
This seems strange:
Can one have both pixmap and window bits set? If yes, what happens to
the visual ID - seems like it gets trashed.
-Emil
More information about the mesa-dev
mailing list