diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/egl/Makefile.am | 7 | ||||
-rw-r--r-- | src/egl/drivers/dri2/egl_dri2.c | 13 | ||||
-rw-r--r-- | src/egl/drivers/dri2/egl_dri2.h | 37 | ||||
-rw-r--r-- | src/egl/drivers/dri2/platform_tizen.c | 1543 | ||||
-rw-r--r-- | src/egl/main/eglapi.c | 16 | ||||
-rw-r--r-- | src/egl/main/egldisplay.c | 25 | ||||
-rw-r--r-- | src/egl/main/egldisplay.h | 11 |
7 files changed, 1650 insertions, 2 deletions
diff --git a/src/egl/Makefile.am b/src/egl/Makefile.am index de4a754a2db..0b79112e3a8 100644 --- a/src/egl/Makefile.am +++ b/src/egl/Makefile.am @@ -113,6 +113,13 @@ libEGL_common_la_LIBADD += $(ANDROID_LIBS) dri2_backend_FILES += drivers/dri2/platform_android.c endif +if HAVE_EGL_PLATFORM_TIZEN +AM_CFLAGS += -DHAVE_TIZEN_PLATFORM +AM_CFLAGS += $(TIZEN_CFLAGS) +libEGL_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/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index c98b9a5d18a..c6054b91aec 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -893,6 +893,12 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp) case _EGL_PLATFORM_ANDROID: ret = dri2_initialize_android(drv, disp); break; + +#ifdef HAVE_TIZEN_PLATFORM + case _EGL_PLATFORM_TIZEN: + ret = dri2_initialize_tizen(drv, disp); + break; +#endif default: unreachable("Callers ensure we cannot get here."); return EGL_FALSE; @@ -960,6 +966,13 @@ dri2_display_destroy(_EGLDisplay *disp) case _EGL_PLATFORM_WAYLAND: dri2_teardown_wayland(dri2_dpy); break; + +#ifdef HAVE_TIZEN_PLATFORM + case _EGL_PLATFORM_TIZEN: + if (dri2_dpy->tpl_display) + tpl_object_unreference((tpl_object_t *)(dri2_dpy->tpl_display)); + break; +#endif default: /* TODO: add teardown for other platforms */ break; diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index a9ddadf11b1..cd0d4a26d9e 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -69,6 +69,14 @@ struct zwp_linux_dmabuf_v1; #include <hardware/gralloc.h> #endif /* HAVE_ANDROID_PLATFORM */ +#ifdef HAVE_TIZEN_PLATFORM +#include <tpl.h> +#include <tbm_bufmgr.h> +#include <tbm_drm_helper.h> +#include <tbm_surface.h> +#include <tbm_surface_internal.h> +#endif /* HAVE_TIZEN_PLATFORM */ + #include "eglconfig.h" #include "eglcontext.h" #include "egldevice.h" @@ -241,8 +249,12 @@ struct dri2_egl_display const gralloc_module_t *gralloc; #endif - bool is_render_node; - bool is_different_gpu; +#ifdef HAVE_TIZEN_PLATFORM + tpl_display_t *tpl_display; +#endif + + int is_render_node; + int is_different_gpu; }; struct dri2_egl_context @@ -292,9 +304,27 @@ struct dri2_egl_surface struct gbm_dri_surface *gbm_surf; #endif +#ifdef HAVE_TIZEN_PLATFORM + void *native_win; + tpl_surface_t *tpl_surface; + tbm_surface_h tbm_surface; + tbm_format tbm_format; + __DRIimage *dri_image_back; + __DRIimage *dri_image_front; + /* EGL-owned buffers */ __DRIbuffer *local_buffers[__DRI_BUFFER_COUNT]; + /* Used to record all the tbm_surface created by tpl_surface and their ages. + * Usually Tizen uses at most triple buffers in tpl_surface (tbm_surface_queue) + * so hardcode the number of color_buffers to 3. + */ + struct { + tbm_surface_h tbm_surface; + int age; + } color_buffers[3], *back; +#endif + #if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM) struct { #ifdef HAVE_WAYLAND_PLATFORM @@ -492,6 +522,9 @@ dri2_initialize_surfaceless(_EGLDriver *drv, _EGLDisplay *disp) } #endif +EGLBoolean +dri2_initialize_tizen(_EGLDriver *drv, _EGLDisplay *disp); + void dri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw); diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c new file mode 100644 index 00000000000..39ec926fd5e --- /dev/null +++ b/src/egl/drivers/dri2/platform_tizen.c @@ -0,0 +1,1543 @@ +/* + * 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@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 <kk.moon@samsung.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 void tizen_free_local_buffers(struct dri2_egl_surface *dri2_surf); + +/* createImageFromFds requires fourcc format */ +static int get_fourcc(tbm_format format) +{ + switch (format) { + case TBM_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565; + case TBM_FORMAT_BGRA8888: return __DRI_IMAGE_FOURCC_ARGB8888; + case TBM_FORMAT_RGBA8888: return __DRI_IMAGE_FOURCC_ABGR8888; + case TBM_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888; + case TBM_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888; + case TBM_FORMAT_RGBX8888: return __DRI_IMAGE_FOURCC_XBGR8888; + case TBM_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888; + default: + _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", format); + } + return -1; +} + +static int get_fourcc_yuv(tbm_format format) +{ + switch (format) { + case TBM_FORMAT_NV12: return __DRI_IMAGE_FOURCC_NV12; + case TBM_FORMAT_NV21: return __DRI_IMAGE_FOURCC_NV12; + case TBM_FORMAT_YUV420: return __DRI_IMAGE_FOURCC_YUV420; + case TBM_FORMAT_YVU420: return __DRI_IMAGE_FOURCC_YVU420; + default: + _eglLog(_EGL_WARNING, "unsupported native yuv buffer format 0x%x", format); + } + return -1; +} + +static bool is_yuv_format(tbm_format format) +{ + if (get_fourcc_yuv(format) == -1) + return false; + else + return true; +} + +static int get_format(tbm_format format) +{ + switch (format) { + case TBM_FORMAT_RGB565: return __DRI_IMAGE_FORMAT_RGB565; + case TBM_FORMAT_BGRA8888: return __DRI_IMAGE_FORMAT_ARGB8888; + case TBM_FORMAT_RGBA8888: return __DRI_IMAGE_FORMAT_ABGR8888; + case TBM_FORMAT_ARGB8888: return __DRI_IMAGE_FORMAT_ARGB8888; + case TBM_FORMAT_ABGR8888: return __DRI_IMAGE_FORMAT_ABGR8888; + case TBM_FORMAT_RGBX8888: return __DRI_IMAGE_FORMAT_XBGR8888; + case TBM_FORMAT_XRGB8888: return __DRI_IMAGE_FORMAT_XRGB8888; + default: + _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", format); + } + return -1; +} + +static int get_format_bpp(tbm_format format) +{ + int bpp; + + switch (format) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" + case TBM_FORMAT_BGRA8888: + case TBM_FORMAT_RGBA8888: + case TBM_FORMAT_RGBX8888: + case TBM_FORMAT_ARGB8888: +#pragma GCC diagnostic pop + case TBM_FORMAT_XRGB8888: + bpp = 4; + break; + case TBM_FORMAT_RGB565: + bpp = 2; + break; + default: + bpp = 0; + break; + } + + return bpp; +} + +static int get_pitch(tbm_surface_h tbm_surface) +{ + tbm_surface_info_s surf_info; + + if (tbm_surface_get_info(tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) { + return 0; + } + + return surf_info.planes[0].stride; +} + +static int +get_native_buffer_fd(tbm_surface_h tbm_surface) +{ + tbm_bo_handle bo_handle; + bo_handle = tbm_bo_get_handle(tbm_surface_internal_get_bo(tbm_surface, 0), + TBM_DEVICE_3D); + + return (bo_handle.ptr != NULL) ? (int)bo_handle.u32 : -1; +} + +static int +get_native_buffer_name(tbm_surface_h tbm_surface) +{ + uint32_t bo_name; + + bo_name = tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0)); + + return (bo_name != 0 ) ? (int)bo_name : -1; +} + +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; + tizen_free_local_buffers(dri2_surf); + } + + /* Record all the buffers created by tpl_surface (tbm_surface_queue) + * and update back buffer * for updating buffer's age in swap_buffers. + */ + EGLBoolean updated = EGL_FALSE; + for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + if (!dri2_surf->color_buffers[i].tbm_surface) { + dri2_surf->color_buffers[i].tbm_surface = dri2_surf->tbm_surface; + dri2_surf->color_buffers[i].age = 0; + } + if (dri2_surf->color_buffers[i].tbm_surface == dri2_surf->tbm_surface) { + dri2_surf->back = &dri2_surf->color_buffers[i]; + updated = EGL_TRUE; + break; + } + } + + if (!updated) { + /* In case of all the buffers were recreated , reset the color_buffers */ + for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + dri2_surf->color_buffers[i].tbm_surface = NULL; + dri2_surf->color_buffers[i].age = 0; + } + dri2_surf->color_buffers[0].tbm_surface = dri2_surf->tbm_surface; + dri2_surf->back = &dri2_surf->color_buffers[0]; + } + + 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; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + /* 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__); + } + + tbm_surface_internal_unref(dri2_surf->tbm_surface); + dri2_surf->tbm_surface = NULL; + dri2_surf->back = NULL; + + mtx_lock(&disp->Mutex); + + if (dri2_surf->dri_image_back) { + dri2_dpy->image->destroyImage(dri2_surf->dri_image_back); + dri2_surf->dri_image_back = NULL; + } + + 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 __DRIbuffer * +tizen_alloc_local_buffer(struct dri2_egl_surface *dri2_surf, + unsigned int att, unsigned int format) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + if (att >= ARRAY_SIZE(dri2_surf->local_buffers)) + return NULL; + + if (!dri2_surf->local_buffers[att]) { + dri2_surf->local_buffers[att] = + dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format, + dri2_surf->base.Width, dri2_surf->base.Height); + } + + return dri2_surf->local_buffers[att]; +} + +static void +tizen_free_local_buffers(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int i; + + for (i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) { + if (dri2_surf->local_buffers[i]) { + dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, + dri2_surf->local_buffers[i]); + dri2_surf->local_buffers[i] = NULL; + } + } +} + +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; + + if (dri2_dpy->dri2) { + createNewDrawable = dri2_dpy->dri2->createNewDrawable; + } else { + createNewDrawable = dri2_dpy->swrast->createNewDrawable; + } + + dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen, config, + dri2_surf); + 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 _EGLSurface * +tizen_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, const EGLint *attrib_list) +{ + return tizen_create_surface(drv, disp, EGL_PBUFFER_BIT, conf, + NULL, 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); + + tizen_free_local_buffers(dri2_surf); + + if (dri2_surf->base.Type == EGL_WINDOW_BIT) { + if (dri2_surf->tbm_surface) + tizen_window_cancel_buffer(disp, dri2_surf); + } + + if (dri2_surf->dri_image_back) { + _eglLog(_EGL_DEBUG, "%s : %d : destroy dri_image_back", __func__, __LINE__); + dri2_dpy->image->destroyImage(dri2_surf->dri_image_back); + dri2_surf->dri_image_back = NULL; + } + + if (dri2_surf->dri_image_front) { + _eglLog(_EGL_DEBUG, "%s : %d : destroy dri_image_front", __func__, __LINE__); + dri2_dpy->image->destroyImage(dri2_surf->dri_image_front); + dri2_surf->dri_image_front = NULL; + } + + 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 int +get_front_bo(struct dri2_egl_surface *dri2_surf, unsigned int format) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + if (dri2_surf->dri_image_front) + return 0; + + if (dri2_surf->base.Type == EGL_WINDOW_BIT) { + /* According current EGL spec, front buffer rendering + * for window surface is not supported now. + * and mesa doesn't have the implementation of this case. + * Add warning message, but not treat it as error. + */ + _eglLog(_EGL_DEBUG, "DRI driver requested unsupported front buffer for window surface"); + } else if (dri2_surf->base.Type == EGL_PBUFFER_BIT) { + dri2_surf->dri_image_front = + dri2_dpy->image->createImage(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + format, + 0, + dri2_surf); + if (!dri2_surf->dri_image_front) { + _eglLog(_EGL_WARNING, "dri2_image_front allocation failed"); + return -1; + } + } + + return 0; +} + +static int +get_back_bo(struct dri2_egl_surface *dri2_surf, unsigned int format) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int fourcc, pitch; + int offset = 0, fd; + tbm_surface_info_s surf_info; + + if (dri2_surf->dri_image_back) + return 0; + + if (dri2_surf->base.Type == EGL_WINDOW_BIT) { + if (!dri2_surf->tbm_surface) { + _eglLog(_EGL_WARNING, "Could not get native buffer"); + return -1; + } + + fd = get_native_buffer_fd(dri2_surf->tbm_surface); + if (fd < 0) { + _eglLog(_EGL_WARNING, "Could not get native buffer FD"); + return -1; + } + + if (tbm_surface_get_info(dri2_surf->tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) { + _eglLog(_EGL_WARNING, "Could not get pitch"); + return -1; + } + + pitch = surf_info.planes[0].stride; + fourcc = get_fourcc(dri2_surf->tbm_format); + + if (fourcc == -1 || pitch == 0) { + _eglLog(_EGL_WARNING, "Invalid buffer fourcc(%x) or pitch(%d)", + fourcc, pitch); + return -1; + } + + dri2_surf->base.Width = surf_info.width; + dri2_surf->base.Height = surf_info.height; + + dri2_surf->dri_image_back = + dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + fourcc, + &fd, + 1, + &pitch, + &offset, + dri2_surf); + + if (!dri2_surf->dri_image_back) { + _eglLog(_EGL_WARNING, "failed to create DRI image from FD"); + return -1; + } + } else if (dri2_surf->base.Type == EGL_PBUFFER_BIT) { + /* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically, + * the spec states that they have a back buffer but no front buffer, in + * contrast to pixmaps, which have a front buffer but no back buffer. + * + * Single-buffered surfaces with no front buffer confuse Mesa; so we deviate + * from the spec, following the precedent of Mesa's EGL X11 platform. The + * X11 platform correctly assigns pbuffers to single-buffered configs, but + * assigns the pbuffer a front buffer instead of a back buffer. + * + * Pbuffers in the X11 platform mostly work today, so let's just copy its + * behavior instead of trying to fix (and hence potentially breaking) the + * world. + */ + _eglLog(_EGL_DEBUG, "DRI driver requested unsupported back buffer for pbuffer surface"); + } + + return 0; +} + +/* Some drivers will pass multiple bits in buffer_mask. + * For such case, will go through all the bits, and + * will not return error when unsupported buffer is requested, only + * return error when the allocation for supported buffer failed. + */ +static int +tizen_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format, + uint32_t *stamp, void *loaderPrivate, + uint32_t buffer_mask, struct __DRIimageList *images) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + + images->image_mask = 0; + images->front = NULL; + images->back = NULL; + + if (update_buffers(dri2_surf) < 0) + return 0; + + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { + if (get_front_bo(dri2_surf, format) < 0) + return 0; + + if (dri2_surf->dri_image_front) { + images->front = dri2_surf->dri_image_front; + images->image_mask |= __DRI_IMAGE_BUFFER_FRONT; + } + } + + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { + if (get_back_bo(dri2_surf, format) < 0) + return 0; + + if (dri2_surf->dri_image_back) { + images->back = dri2_surf->dri_image_back; + images->image_mask |= __DRI_IMAGE_BUFFER_BACK; + } + } + + return 1; +} + +static EGLint +tizen_query_buffer_age(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surface) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); + + if (update_buffers(dri2_surf) < 0) { + _eglError(EGL_BAD_ALLOC, "tizen_query_buffer_age"); + return 0; + } + + return dri2_surf->back->age; +} + +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; + + for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + if (dri2_surf->color_buffers[i].age > 0) + dri2_surf->color_buffers[i].age++; + } + + /* Make sure we have a back buffer in case we're swapping without + * ever rendering. */ + if (get_back_bo(dri2_surf, 0) < 0) { + _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); + return EGL_FALSE; + } + + dri2_surf->back->age = 1; + + if (dri2_surf->tbm_surface) + tizen_window_enqueue_buffer_with_damage(disp, dri2_surf, rects, n_rects); + + if (dri2_dpy->swrast) { + dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); + } else { + dri2_flush_drawable_for_swapbuffers(disp, draw); + dri2_dpy->flush->invalidate(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 _EGLImage * +tizen_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx, + tbm_surface_h tbm_surface) + +{ + tbm_surface_info_s surf_info; + tbm_fd bo_fd[TBM_SURF_PLANE_MAX]; + tbm_bo bo[TBM_SURF_PLANE_MAX]; + int num_planes; + int i; + int fourcc; + size_t offsets[3]; + size_t pitches[3]; + int fds[3]; + + if (tbm_surface_get_info(tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) { + _eglLog(_EGL_WARNING, "Could not get tbm_surface_info"); + return NULL; + } + + num_planes = surf_info.num_planes; + for (i = 0; i < num_planes; i++) { + tbm_bo_handle bo_handle; + int bo_idx = tbm_surface_internal_get_plane_bo_idx(tbm_surface, i); + bo[i] = tbm_surface_internal_get_bo (tbm_surface, bo_idx); + if (bo[i] == NULL) { + _eglLog(_EGL_WARNING, "Could not get tbm_surface_internal_bo"); + return NULL; + } + bo_handle = tbm_bo_get_handle(bo[i], TBM_DEVICE_3D); + bo_fd[i] = bo_handle.u32; + } + + fourcc = get_fourcc_yuv(tbm_surface_get_format(tbm_surface)); + if (fourcc == -1) { + _eglLog(_EGL_WARNING, "Unsupported native yuv format"); + return NULL; + } + + switch (fourcc) { + case __DRI_IMAGE_FOURCC_NV12: + fds[0] = bo_fd[0]; + fds[1] = bo_fd[1]; + offsets[0] = surf_info.planes[0].offset; + offsets[1] = surf_info.planes[1].offset; + pitches[0] = surf_info.planes[0].stride; + pitches[1] = surf_info.planes[1].stride; + break; + case __DRI_IMAGE_FOURCC_YUV420: + fds[0] = bo_fd[0]; + fds[1] = bo_fd[1]; + fds[2] = bo_fd[2]; + offsets[0] = surf_info.planes[0].offset; + offsets[1] = surf_info.planes[1].offset; + offsets[2] = surf_info.planes[2].offset; + pitches[0] = surf_info.planes[0].stride; + pitches[1] = surf_info.planes[1].stride; + pitches[2] = surf_info.planes[2].stride; + break; + case __DRI_IMAGE_FOURCC_YVU420: + fds[0] = bo_fd[0]; + fds[1] = bo_fd[2]; + fds[2] = bo_fd[1]; + offsets[0] = surf_info.planes[0].offset; + offsets[1] = surf_info.planes[2].offset; + offsets[2] = surf_info.planes[1].offset; + pitches[0] = surf_info.planes[0].stride; + pitches[1] = surf_info.planes[2].stride; + pitches[2] = surf_info.planes[1].stride; + break; + default: + _eglLog(_EGL_WARNING, "Unsupported native yuv format"); + return NULL; + } + + if (num_planes == 2) { + const EGLint attr_list_2plane[] = { + EGL_WIDTH, surf_info.width, + EGL_HEIGHT, surf_info.height, + EGL_LINUX_DRM_FOURCC_EXT, fourcc, + EGL_DMA_BUF_PLANE0_FD_EXT, fds[0], + EGL_DMA_BUF_PLANE0_PITCH_EXT, pitches[0], + EGL_DMA_BUF_PLANE0_OFFSET_EXT, offsets[0], + EGL_DMA_BUF_PLANE1_FD_EXT, fds[1], + EGL_DMA_BUF_PLANE1_PITCH_EXT, pitches[1], + EGL_DMA_BUF_PLANE1_OFFSET_EXT, offsets[1], + EGL_NONE, 0 + }; + return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list_2plane); + } else if (num_planes == 3) { + const EGLint attr_list_3plane[] = { + EGL_WIDTH, surf_info.width, + EGL_HEIGHT, surf_info.height, + EGL_LINUX_DRM_FOURCC_EXT, fourcc, + EGL_DMA_BUF_PLANE0_FD_EXT, fds[0], + EGL_DMA_BUF_PLANE0_PITCH_EXT, pitches[0], + EGL_DMA_BUF_PLANE0_OFFSET_EXT, offsets[0], + EGL_DMA_BUF_PLANE1_FD_EXT, fds[1], + EGL_DMA_BUF_PLANE1_PITCH_EXT, pitches[1], + EGL_DMA_BUF_PLANE1_OFFSET_EXT, offsets[1], + EGL_DMA_BUF_PLANE2_FD_EXT, fds[2], + EGL_DMA_BUF_PLANE2_PITCH_EXT, pitches[2], + EGL_DMA_BUF_PLANE2_OFFSET_EXT, offsets[2], + EGL_NONE, 0 + }; + return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list_3plane); + } else { + _eglLog(_EGL_WARNING, "Unsupported yuv planes"); + return NULL; + } +} + +static _EGLImage * +tizen_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx, + tbm_surface_h tbm_surface , int fd) +{ + unsigned int pitch; + tbm_surface_info_s surf_info; + + if (is_yuv_format(tbm_surface_get_format(tbm_surface))) + return tizen_create_image_from_prime_fd_yuv(disp, ctx, tbm_surface); + + const int fourcc = get_fourcc(tbm_surface_get_format(tbm_surface)); + if (fourcc == -1) { + _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); + return NULL; + } + + if (tbm_surface_get_info(tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) { + _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); + return NULL; + } + pitch = surf_info.planes[0].stride; + + if (pitch == 0) { + _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); + return NULL; + } + + const EGLint attr_list[] = { + EGL_WIDTH, surf_info.width, + EGL_HEIGHT, surf_info.height, + EGL_LINUX_DRM_FOURCC_EXT, fourcc, + EGL_DMA_BUF_PLANE0_FD_EXT, fd, + EGL_DMA_BUF_PLANE0_PITCH_EXT, pitch, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, + EGL_NONE, 0 + }; + + return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list); +} + +static _EGLImage * +tizen_create_image_from_name(_EGLDisplay *disp, _EGLContext *ctx, + tbm_surface_h tbm_surface) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img; + int name; + int format; + unsigned int pitch; + tbm_surface_info_s surf_info; + + name = get_native_buffer_name(tbm_surface); + if (!name) { + _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); + return NULL; + } + + format = get_format(tbm_surface_get_format(tbm_surface)); + if (format == -1) + return NULL; + + if (tbm_surface_get_info(tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) { + _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); + return NULL; + } + pitch = surf_info.planes[0].stride; + + if (pitch == 0) { + _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); + return NULL; + } + + dri2_img = calloc(1, sizeof(*dri2_img)); + if (!dri2_img) { + _eglError(EGL_BAD_ALLOC, "tizen_create_image_mesa_drm"); + return NULL; + } + + if (!_eglInitImage(&dri2_img->base, disp)) { + free(dri2_img); + return NULL; + } + + dri2_img->dri_image = + dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, + surf_info.width, + surf_info.height, + format, + name, + pitch, + dri2_img); + if (!dri2_img->dri_image) { + free(dri2_img); + _eglError(EGL_BAD_ALLOC, "tizen_create_image_mesa_drm"); + return NULL; + } + + return &dri2_img->base; +} + +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; + } + return _eglQuerySurface(drv, dpy, surf, attribute, value); +} + +static _EGLImage * +dri2_create_image_tizen_native_buffer(_EGLDisplay *disp, + _EGLContext *ctx, + tbm_surface_h tbm_surface) +{ + int fd; + + fd = get_native_buffer_fd(tbm_surface); + if (fd >= 0) + return tizen_create_image_from_prime_fd(disp, ctx, tbm_surface, fd); + + return tizen_create_image_from_name(disp, ctx, tbm_surface); +} + +static _EGLImage * +dri2_create_image_tizen_wl_buffer(_EGLDisplay *disp, + _EGLContext *ctx, + tpl_handle_t native_pixmap) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + int fd; + tbm_surface_h tbm_surface = NULL; + + tbm_surface = tpl_display_get_buffer_from_native_pixmap(dri2_dpy->tpl_display, + (tpl_handle_t)native_pixmap); + if (!tbm_surface) + return NULL; + + fd = get_native_buffer_fd(tbm_surface); + if (fd >= 0) + return tizen_create_image_from_prime_fd(disp, ctx, tbm_surface, fd); + + return tizen_create_image_from_name(disp, ctx, tbm_surface); +} + +static _EGLImage * +tizen_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, + _EGLContext *ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attr_list) +{ + switch (target) { + case EGL_NATIVE_SURFACE_TIZEN: + return dri2_create_image_tizen_native_buffer(disp, ctx, + (tbm_surface_h)buffer); + case EGL_WAYLAND_BUFFER_WL: + return dri2_create_image_tizen_wl_buffer(disp, ctx, (tpl_handle_t)buffer); + default: + return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list); + } +} + +static void +tizen_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) +{ +} + +static int +tizen_get_buffers_parse_attachments(struct dri2_egl_surface *dri2_surf, + unsigned int *attachments, int count) +{ + int num_buffers = 0, i; + + /* fill dri2_surf->buffers */ + for (i = 0; i < count * 2; i += 2) { + __DRIbuffer *buf, *local; + + assert(num_buffers < ARRAY_SIZE(dri2_surf->buffers)); + buf = &dri2_surf->buffers[num_buffers]; + + switch (attachments[i]) { + case __DRI_BUFFER_BACK_LEFT: + if (dri2_surf->base.Type == EGL_WINDOW_BIT) { + buf->attachment = attachments[i]; + buf->name = get_native_buffer_name(dri2_surf->tbm_surface); + buf->cpp = get_format_bpp(tbm_surface_get_format(dri2_surf->tbm_surface)); + buf->pitch = get_pitch(dri2_surf->tbm_surface); + buf->flags = 0; + + if (buf->name) + num_buffers++; + + break; + } + /* fall through for pbuffers */ + case __DRI_BUFFER_DEPTH: + case __DRI_BUFFER_STENCIL: + case __DRI_BUFFER_ACCUM: + case __DRI_BUFFER_DEPTH_STENCIL: + case __DRI_BUFFER_HIZ: + local = tizen_alloc_local_buffer(dri2_surf, attachments[i], attachments[i + 1]); + + if (local) { + *buf = *local; + num_buffers++; + } + break; + case __DRI_BUFFER_FRONT_LEFT: + case __DRI_BUFFER_FRONT_RIGHT: + case __DRI_BUFFER_FAKE_FRONT_LEFT: + case __DRI_BUFFER_FAKE_FRONT_RIGHT: + case __DRI_BUFFER_BACK_RIGHT: + default: + /* no front or right buffers */ + break; + } + } + + return num_buffers; +} + +static __DRIbuffer * +tizen_get_buffers_with_format(__DRIdrawable * driDrawable, + int *width, int *height, + unsigned int *attachments, int count, + int *out_count, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + + if (update_buffers(dri2_surf) < 0) + return NULL; + + dri2_surf->buffer_count = + tizen_get_buffers_parse_attachments(dri2_surf, attachments, count); + + if (width) + *width = dri2_surf->base.Width; + if (height) + *height = dri2_surf->base.Height; + + *out_count = dri2_surf->buffer_count; + + return dri2_surf->buffers; +} + +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; + } +} + +static void +tizen_swrast_get_drawable_info(__DRIdrawable * draw, + int *x, int *y, int *w, int *h, + void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + + if (!dri2_surf->tbm_surface) { + if (update_buffers(dri2_surf) < 0) + return; + } + + *x = 0; + *y = 0; + *w = dri2_surf->base.Width; + *h = dri2_surf->base.Height; +} + +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; + + for (i = 0; i < h; i++) { + memcpy(data + i * stride, + surf_info.planes[0].ptr + (x + i) * internal_stride + y, stride); + } + + 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); + } + + 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; + } + } + + 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 count, i; + + for (i = 0, count = 0; dri2_dpy->driver_configs[i]; i++) { + struct dri2_egl_config *dri2_cfg; + unsigned int red, blue, green, alpha, depth; + int surface_type = 0; + tpl_bool_t is_slow; + EGLint attr_list[] = { + 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); + + res = tpl_display_query_config(dri2_dpy->tpl_display, TPL_SURFACE_TYPE_WINDOW, + red, green, blue, alpha, depth, + &attr_list[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, + &attr_list[1], &is_slow); + if (res == TPL_ERROR_NONE) + surface_type |= EGL_PIXMAP_BIT; + + if (!surface_type) + continue; + + dri2_cfg = dri2_add_config(dpy, dri2_dpy->driver_configs[i], count + 1, + surface_type, &attr_list[0], NULL); + if (dri2_cfg) + count++; + } + + return (count != 0); +} + +static struct dri2_egl_display_vtbl tizen_display_vtbl = { + .authenticate = NULL, + .create_window_surface = tizen_create_window_surface, + .create_pixmap_surface = tizen_create_pixmap_surface, + .create_pbuffer_surface = tizen_create_pbuffer_surface, + .destroy_surface = tizen_destroy_surface, + .create_image = tizen_create_image_khr, + .swap_interval = dri2_fallback_swap_interval, + .swap_buffers = tizen_swap_buffers, + .swap_buffers_with_damage = tizen_swap_buffers_with_damage, + .swap_buffers_region = dri2_fallback_swap_buffers_region, + .post_sub_buffer = dri2_fallback_post_sub_buffer, + .copy_buffers = dri2_fallback_copy_buffers, + .query_buffer_age = tizen_query_buffer_age, + .query_surface = tizen_query_surface, + .create_wayland_buffer_from_image = NULL, + .get_sync_values = dri2_fallback_get_sync_values, + .get_dri_drawable = dri2_surface_get_dri_drawable, +}; + +static const __DRIdri2LoaderExtension tizen_dri2_loader_extension = { + .base = { __DRI_DRI2_LOADER, 3 }, + + .getBuffers = NULL, + .getBuffersWithFormat = tizen_get_buffers_with_format, + .flushFrontBuffer = tizen_flush_front_buffer, +}; + +static const __DRIimageLoaderExtension tizen_image_loader_extension = { + .base = { __DRI_IMAGE_LOADER, 1 }, + + .getBuffers = tizen_image_get_buffers, + .flushFrontBuffer = tizen_flush_front_buffer, +}; + +static const __DRIswrastLoaderExtension tizen_swrast_loader_extension = { + .base = { __DRI_SWRAST_LOADER, 2 }, + + .getDrawableInfo = tizen_swrast_get_drawable_info, + .putImage = tizen_swrast_put_image, + .getImage = tizen_swrast_get_image, + .putImage2 = tizen_swrast_put_image2, +}; + +static const __DRIextension *tizen_dri2_loader_extensions[] = { + &tizen_dri2_loader_extension.base, + &image_lookup_extension.base, + &use_invalidate.base, + NULL, +}; + +static const __DRIextension *tizen_image_loader_extensions[] = { + &tizen_image_loader_extension.base, + &image_lookup_extension.base, + &use_invalidate.base, + NULL, +}; + +static const __DRIextension *tizen_swrast_loader_extensions[] = { + &tizen_swrast_loader_extension.base, + NULL, +}; + +static EGLBoolean +tizen_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, + struct wl_display *wl_dpy) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + (void) drv; + (void) wl_dpy; + + if (!dri2_dpy->tpl_display) + return EGL_FALSE; + + if (!tpl_display_get_native_handle(dri2_dpy->tpl_display)) + return EGL_FALSE; + + return EGL_TRUE; +} + +static EGLBoolean +tizen_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, + struct wl_display *wl_dpy) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + (void) drv; + (void) wl_dpy; + + if (!dri2_dpy->tpl_display) + return EGL_FALSE; + + if (!tpl_display_get_native_handle(dri2_dpy->tpl_display)) + return EGL_FALSE; + + return EGL_TRUE; +} + +static EGLBoolean +tizen_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp, + struct wl_resource *buffer_resource, + EGLint attribute, EGLint *value) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + tbm_format tbm_format = 0; + int width = 0, height = 0; + tpl_result_t res; + + if (!dri2_dpy->tpl_display) + return EGL_FALSE; + + if (!tpl_display_get_native_handle(dri2_dpy->tpl_display)) + return EGL_FALSE; + + res = tpl_display_get_native_pixmap_info(dri2_dpy->tpl_display, + (tpl_handle_t)buffer_resource, + &width, &height, &tbm_format); + if (res != TPL_ERROR_NONE) + return EGL_FALSE; + + switch (attribute) { + case EGL_TEXTURE_FORMAT: + switch (tbm_format) { + case TBM_FORMAT_ARGB8888: + *value = EGL_TEXTURE_RGBA; + return EGL_TRUE; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" + case TBM_FORMAT_XRGB8888: + case TBM_FORMAT_RGB565: +#pragma GCC diagnostic pop + *value = EGL_TEXTURE_RGB; + return EGL_TRUE; + } + case EGL_WIDTH: + *value = width; + return EGL_TRUE; + case EGL_HEIGHT: + *value = height; + return EGL_TRUE; + } + + return EGL_FALSE; +} + +EGLBoolean +dri2_initialize_tizen(_EGLDriver *drv, _EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy; + tpl_display_t *tpl_display = NULL; + const char *err; + int tbm_bufmgr_fd = -1; + char *tbm_bufmgr_device_name = NULL; + int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL); + + loader_set_logger(_eglLog); + + dri2_dpy = calloc(1, sizeof *dri2_dpy); + if (!dri2_dpy) + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); + + disp->DriverData = (void *) dri2_dpy; + + /* TPL_BACKEND_UNKNOWN type make checking runtime type check */ + tpl_display = tpl_display_create(TPL_BACKEND_UNKNOWN, disp->PlatformDisplay); + if (!tpl_display) { + err = "DRI2: failed to create tpl_display"; + goto cleanup_display; + } + dri2_dpy->tpl_display = tpl_display; + + /* Get tbm_bufmgr's fd */ + tbm_bufmgr_fd = tbm_drm_helper_get_fd(); + + if (tbm_bufmgr_fd == -1) { + err = "DRI2: failed to get tbm_bufmgr fd"; + goto cleanup_device; + } + + if (hw_accel) { + int fd = -1; + + if (drmGetNodeTypeFromFd(tbm_bufmgr_fd) == DRM_NODE_RENDER) { + + tbm_bufmgr_device_name = loader_get_device_name_for_fd(tbm_bufmgr_fd); + if (tbm_bufmgr_device_name == NULL) { + err = "DRI2: failed to get tbm_bufmgr device name"; + goto cleanup_device; + } + fd = loader_open_device(tbm_bufmgr_device_name); + + } else { + if (!tbm_drm_helper_get_auth_info(&fd, NULL, NULL)) { + + /* FIXME: tbm_drm_helper_get_auth_info() does not support the case of + * display server for now. this code is fallback routine for + * that Enlightenment Server fails on tbm_drm_helper_get_auth_info. + * When tbm_drm_helper_get_auth_info() supports display server + * case, then remove below routine. + */ +#if 1 + tbm_bufmgr_device_name = loader_get_device_name_for_fd(tbm_bufmgr_fd); + if (tbm_bufmgr_device_name == NULL) { + err = "DRI2: failed to get tbm_bufmgr device name"; + goto cleanup_device; + } + fd = loader_open_device(tbm_bufmgr_device_name); +#else + err = "DRI2: failed to get fd from tbm_drm_helper_get_auth_info()"; + goto cleanup_device; +#endif + } + } + + if (fd == -1) { + err = "DRI2: failed to get fd"; + goto cleanup_device; + } + dri2_dpy->fd = fd; + + dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); + if (dri2_dpy->driver_name == NULL) { + err = "DRI2: failed to get driver name"; + goto cleanup_device; + } + if (!dri2_load_driver(disp)) { + err = "DRI2: failed to load driver"; + goto cleanup_driver_name; + } + + dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER; + /* render nodes cannot use Gem names, and thus do not support + * the __DRI_DRI2_LOADER extension */ + + if (!dri2_dpy->is_render_node) + dri2_dpy->loader_extensions = tizen_dri2_loader_extensions; + else + dri2_dpy->loader_extensions = tizen_image_loader_extensions; + + } else { + dri2_dpy->fd = tbm_bufmgr_fd; + dri2_dpy->driver_name = strdup("swrast"); + if (!dri2_load_driver_swrast(disp)) { + err = "DRI2: failed to load swrast driver"; + goto cleanup_device; + } + dri2_dpy->loader_extensions = tizen_swrast_loader_extensions; + } + + if (!dri2_create_screen(disp)) { + err = "DRI2: failed to create screen"; + goto cleanup_driver; + } + + if (!tizen_add_configs(drv, disp)) { + err = "DRI2: failed to add configs"; + goto cleanup_screen; + } + + /* Fill vtbl last to prevent accidentally calling virtual function during + * initialization. + */ + dri2_dpy->vtbl = &tizen_display_vtbl; + + disp->Extensions.EXT_buffer_age = EGL_TRUE; + disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE; + disp->Extensions.TIZEN_image_native_surface = EGL_TRUE; + disp->Extensions.WL_bind_wayland_display = EGL_TRUE; + disp->Extensions.WL_create_wayland_buffer_from_image = EGL_FALSE; + + drv->API.BindWaylandDisplayWL = tizen_bind_wayland_display_wl; + drv->API.UnbindWaylandDisplayWL = tizen_unbind_wayland_display_wl; + drv->API.QueryWaylandBufferWL = tizen_query_wayland_buffer_wl; + + return EGL_TRUE; + +cleanup_screen: + dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); +cleanup_driver: + dlclose(dri2_dpy->driver); +cleanup_driver_name: + if (hw_accel) + free(dri2_dpy->driver_name); +cleanup_device: + if (tbm_bufmgr_device_name) + free(tbm_bufmgr_device_name); + tpl_object_unreference((tpl_object_t *)tpl_display); +cleanup_display: + free(dri2_dpy); + disp->DriverData = NULL; + + return _eglError(EGL_NOT_INITIALIZED, err); +} diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index dd9b5b989cb..87ff0a7070b 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -406,6 +406,18 @@ _eglGetPlatformDisplayCommon(EGLenum platform, void *native_display, dpy = _eglGetSurfacelessDisplay(native_display, attrib_list); break; #endif +#ifdef HAVE_TIZEN_PLATFORM +#ifndef HAVE_DRM_PLATFORM + case EGL_PLATFORM_GBM_MESA: + dpy = _eglGetTizenDisplay(native_display, attrib_list); + break; +#endif +#ifndef HAVE_WAYLAND_PLATFORM + case EGL_PLATFORM_WAYLAND_EXT: + dpy = _eglGetTizenDisplay(native_display, attrib_list); + break; +#endif +#endif default: RETURN_EGL_ERROR(NULL, EGL_BAD_PARAMETER, NULL); } @@ -535,6 +547,10 @@ _eglCreateExtensionsString(_EGLDisplay *dpy) _EGL_CHECK_EXTENSION(NV_post_sub_buffer); +#ifdef HAVE_TIZEN_PLATFORM + _EGL_CHECK_EXTENSION(TIZEN_image_native_surface); +#endif + _EGL_CHECK_EXTENSION(WL_bind_wayland_display); _EGL_CHECK_EXTENSION(WL_create_wayland_buffer_from_image); diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c index 387df6a66d0..96c8072d03a 100644 --- a/src/egl/main/egldisplay.c +++ b/src/egl/main/egldisplay.c @@ -70,6 +70,7 @@ static const struct { { _EGL_PLATFORM_ANDROID, "android" }, { _EGL_PLATFORM_HAIKU, "haiku" }, { _EGL_PLATFORM_SURFACELESS, "surfaceless" }, + { _EGL_PLATFORM_TIZEN, "tizen" }, }; @@ -115,6 +116,10 @@ _eglNativePlatformDetectNativeDisplay(void *nativeDisplay) (void) first_pointer; /* silence unused var warning */ +#ifdef HAVE_TIZEN_PLATFORM + /* In Tizen Platform, _EGL_PLATFORM_TIZEN handles DRM(gbm) and wayland_egl platform together */ + return _EGL_PLATFORM_TIZEN; +#endif #ifdef HAVE_WAYLAND_PLATFORM /* wl_display is a wl_proxy, which is a wl_object. * wl_object's first element points to the interfacetype. */ @@ -157,6 +162,11 @@ _eglGetNativePlatform(void *nativeDisplay) detected_platform = _eglGetNativePlatformFromEnv(); detection_method = "environment overwrite"; +#ifdef HAVE_TIZEN_PLATFORM + if (native_platform != _EGL_INVALID_PLATFORM) + native_platform = _EGL_PLATFORM_TIZEN; +#endif + if (detected_platform == _EGL_INVALID_PLATFORM) { detected_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay); detection_method = "autodetected"; @@ -542,3 +552,18 @@ _eglGetSurfacelessDisplay(void *native_display, return _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, native_display); } #endif /* HAVE_SURFACELESS_PLATFORM */ + +#ifdef HAVE_TIZEN_PLATFORM +_EGLDisplay* +_eglGetTizenDisplay(void *native_display, + const EGLint *attrib_list) +{ + /* EGL_EXT_platform_wayland recognizes no attributes. */ + if (attrib_list != NULL && attrib_list[0] != EGL_NONE) { + _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay"); + return NULL; + } + + return _eglFindDisplay(_EGL_PLATFORM_TIZEN, native_display); +} +#endif /* HAVE_TIZEN_PLATFORM */ diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index 5cc503734bc..d97d8ccbc21 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -50,6 +50,7 @@ enum _egl_platform_type { _EGL_PLATFORM_ANDROID, _EGL_PLATFORM_HAIKU, _EGL_PLATFORM_SURFACELESS, + _EGL_PLATFORM_TIZEN, _EGL_NUM_PLATFORMS, _EGL_INVALID_PLATFORM = -1 @@ -145,6 +146,10 @@ struct _egl_extensions EGLBoolean NV_post_sub_buffer; +#ifdef HAVE_TIZEN_PLATFORM + EGLBoolean TIZEN_image_native_surface; +#endif + EGLBoolean WL_bind_wayland_display; EGLBoolean WL_create_wayland_buffer_from_image; }; @@ -301,6 +306,12 @@ _eglGetSurfacelessDisplay(void *native_display, const EGLAttrib *attrib_list); #endif +#ifdef HAVE_TIZEN_PLATFORM +_EGLDisplay* +_eglGetTizenDisplay(void *native_display, + const EGLint *attrib_list); +#endif + #ifdef __cplusplus } #endif |