On 17 September 2017 at 19:01, Gwan-gyeong Mun <elong...@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 <elong...@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 <olva...@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 <elong...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev