381 lines
12 KiB
Diff
381 lines
12 KiB
Diff
From 404c0e915de381c2337c79657f80b0aa95c1c995 Mon Sep 17 00:00:00 2001
|
|
From: Frank Binns <frank.binns@imgtec.com>
|
|
Date: Wed, 25 Oct 2017 18:15:00 +0100
|
|
Subject: [PATCH 22/67] egl/tizen: create an internal _EGLImage for each tbm
|
|
surface
|
|
|
|
Create an internal _EGLImage the first time a tbm surface is seen
|
|
by eglCreateImageKHR (with either the EGL_WAYLAND_BUFFER_WL or
|
|
EGL_NATIVE_SURFACE_TIZEN target) and return a copy of it to the
|
|
caller. This avoids some tbm surfaces being frequently mapped and
|
|
then unmapped from the GPU.
|
|
---
|
|
src/egl/drivers/dri2/egl_dri2.c | 236 +++++++++++++++++++++++++-
|
|
src/egl/drivers/dri2/egl_dri2.h | 12 ++
|
|
src/egl/drivers/dri2/platform_tizen.c | 6 +
|
|
3 files changed, 251 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
|
|
index eaa0baed066..db993f8f059 100644
|
|
--- a/src/egl/drivers/dri2/egl_dri2.c
|
|
+++ b/src/egl/drivers/dri2/egl_dri2.c
|
|
@@ -1264,6 +1264,10 @@ dri2_display_destroy(_EGLDisplay *disp)
|
|
break;
|
|
#ifdef HAVE_TIZEN_PLATFORM
|
|
case _EGL_PLATFORM_TIZEN:
|
|
+ if (dri2_dpy->image_list_mutex_initialized) {
|
|
+ pthread_mutex_destroy(&dri2_dpy->image_list_mutex);
|
|
+ dri2_dpy->image_list_mutex_initialized = false;
|
|
+ }
|
|
if (dri2_dpy->tpl_dpy)
|
|
tpl_object_unreference((tpl_object_t *) dri2_dpy->tpl_dpy);
|
|
break;
|
|
@@ -1320,6 +1324,60 @@ dri2_egl_surface_free_local_buffers(struct dri2_egl_surface *dri2_surf)
|
|
}
|
|
}
|
|
|
|
+static void
|
|
+dri2_display_release_resources_tizen(_EGLDisplay *disp)
|
|
+{
|
|
+#ifdef HAVE_TIZEN_PLATFORM
|
|
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
+ _EGLResource *image_elem;
|
|
+
|
|
+ /* Destroy _EGLImages in the image_list */
|
|
+ pthread_mutex_lock(&dri2_dpy->image_list_mutex);
|
|
+ image_elem = dri2_dpy->image_list;
|
|
+ dri2_dpy->image_list = NULL;
|
|
+ pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
|
|
+
|
|
+ while (image_elem) {
|
|
+ _EGLImage *img = (_EGLImage *) image_elem;
|
|
+ struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
+
|
|
+ image_elem = image_elem->Next;
|
|
+
|
|
+ /*
|
|
+ * Delete the tbm surface user data (_EGLImage), unless the tbm surface
|
|
+ * was destroyed since we started processing the image_list.
|
|
+ */
|
|
+ if (dri2_img->tbm_surf)
|
|
+ tbm_surface_internal_delete_user_data(dri2_img->tbm_surf,
|
|
+ (unsigned long) disp);
|
|
+
|
|
+ /*
|
|
+ * dri2_orphan_tbm_surf_egl_image won't be able to transfer the
|
|
+ * _EGLImage to the orphan_image_list once we have started processing
|
|
+ * the image_list so we must destroy it ourselves.
|
|
+ */
|
|
+ dri2_dpy->image->destroyImage(dri2_img->dri_image);
|
|
+ free(dri2_img);
|
|
+ }
|
|
+
|
|
+ /* Destroy _EGLimages in the orphan_image_list*/
|
|
+ pthread_mutex_lock(&dri2_dpy->image_list_mutex);
|
|
+ image_elem = dri2_dpy->orphan_image_list;
|
|
+ dri2_dpy->orphan_image_list = NULL;
|
|
+ pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
|
|
+
|
|
+ while (image_elem) {
|
|
+ _EGLImage *img = (_EGLImage *) image_elem;
|
|
+ struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
+
|
|
+ image_elem = image_elem->Next;
|
|
+
|
|
+ dri2_dpy->image->destroyImage(dri2_img->dri_image);
|
|
+ free(dri2_img);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
/**
|
|
* Called via eglTerminate(), drv->Terminate().
|
|
*
|
|
@@ -1332,6 +1390,8 @@ dri2_terminate(_EGLDisplay *disp)
|
|
/* Release all non-current Context/Surfaces. */
|
|
_eglReleaseDisplayResources(disp);
|
|
|
|
+ dri2_display_release_resources_tizen(disp);
|
|
+
|
|
dri2_display_release(disp);
|
|
|
|
return EGL_TRUE;
|
|
@@ -2309,6 +2369,9 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
|
|
}
|
|
|
|
#ifdef HAVE_TIZEN_PLATFORM
|
|
+static EGLBoolean
|
|
+dri2_destroy_image_khr(_EGLDisplay *disp, _EGLImage *image);
|
|
+
|
|
int
|
|
dri2_fourcc_from_tbm_format(tbm_format format)
|
|
{
|
|
@@ -2405,14 +2468,145 @@ fail_close:
|
|
return NULL;
|
|
}
|
|
|
|
+static void
|
|
+dri2_orphan_tbm_surf_egl_image(void *user_data)
|
|
+{
|
|
+ _EGLImage *img = user_data;
|
|
+ struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
+ _EGLDisplay *disp = img->Resource.Display;
|
|
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
+
|
|
+ /*
|
|
+ * Transfer the passed in _EGLImage from the image_list to the
|
|
+ * orphan_image_list so that it can be cleaned up at some later
|
|
+ * point. This is necessary as the disp->Mutex needs to be held
|
|
+ * in order destroy the _EGLImage and this could potentially cause
|
|
+ * a deadlock in the event that the tbm surface is destroyed.
|
|
+ */
|
|
+ pthread_mutex_lock(&dri2_dpy->image_list_mutex);
|
|
+ /*
|
|
+ * This may be NULL if called via dri2_terminate or if dri2_terminate is
|
|
+ * running in another thread.
|
|
+ */
|
|
+ if (dri2_dpy->image_list) {
|
|
+ _EGLResource *image_elem;
|
|
+
|
|
+ /* Remove the _EGLImage from the image_list */
|
|
+ image_elem = dri2_dpy->image_list;
|
|
+ if (image_elem != &img->Resource) {
|
|
+ while (image_elem) {
|
|
+ if (image_elem->Next == &img->Resource)
|
|
+ break;
|
|
+ image_elem = image_elem->Next;
|
|
+ }
|
|
+ image_elem->Next = img->Resource.Next;
|
|
+ } else {
|
|
+ dri2_dpy->image_list = img->Resource.Next;
|
|
+ }
|
|
+
|
|
+ /* Add the _EGLImage to the orphan_image_list */
|
|
+ img->Resource.Next = dri2_dpy->orphan_image_list;
|
|
+ dri2_dpy->orphan_image_list = &img->Resource;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * This function may have been called via tbm_surface_destroy so tbm_surf
|
|
+ * may be invalid after this function returns.
|
|
+ */
|
|
+ dri2_img->tbm_surf = NULL;
|
|
+ pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
|
|
+}
|
|
+
|
|
+static _EGLImage *
|
|
+dri2_get_tbm_surf_egl_image(_EGLDisplay *disp, _EGLContext *ctx,
|
|
+ tbm_surface_h tbm_surf)
|
|
+{
|
|
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
+ struct dri2_egl_image *dri2_img;
|
|
+ _EGLImage *img;
|
|
+ int ret;
|
|
+
|
|
+ ret = tbm_surface_internal_get_user_data(tbm_surf, (unsigned long) disp,
|
|
+ (void **) &img);
|
|
+ if (ret)
|
|
+ return img;
|
|
+
|
|
+ img = dri2_create_image_tbm_surface(disp, ctx, tbm_surf);
|
|
+ if (!img) {
|
|
+ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tbm_surface failed");
|
|
+ goto fail_exit;
|
|
+ }
|
|
+ dri2_img = dri2_egl_image(img);
|
|
+
|
|
+ /* Use 'disp' as the 'key' as the _EGLimage is tied to it */
|
|
+ ret = tbm_surface_internal_add_user_data(tbm_surf, (unsigned long) disp,
|
|
+ dri2_orphan_tbm_surf_egl_image);
|
|
+ if (!ret) {
|
|
+ _eglError(EGL_BAD_PARAMETER, "dri2_get_tbm_surf_egl_image");
|
|
+ goto fail_destroy_image;
|
|
+ }
|
|
+
|
|
+ ret = tbm_surface_internal_set_user_data(tbm_surf, (unsigned long) disp, img);
|
|
+ if (!ret) {
|
|
+ _eglError(EGL_BAD_PARAMETER, "dri2_get_tbm_surf_egl_image");
|
|
+ goto fail_delete_user_data;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Store the tbm surface so that the user data (_EGLImage) can be destroyed
|
|
+ * in dri2_terminate. We don't take a reference on the surface as this would
|
|
+ * prevent it from being destroyed until eglTerminate is called. This isn't
|
|
+ * an issue since it will be set to NULL, via dri2_orphan_tbm_surf_egl_image,
|
|
+ * once the surface is destroyed (although it's actually safe to call tbm
|
|
+ * surface functions with stale/NULL pointers).
|
|
+ */
|
|
+ dri2_img->tbm_surf = tbm_surf;
|
|
+
|
|
+ /*
|
|
+ * Add to the list of _EGLImages that are associated with tbm surfaces.
|
|
+ * This allows the _EGLImage to be destroyed if the application calls
|
|
+ * eglTerminate before the tbm surface is destroyed.
|
|
+ */
|
|
+ pthread_mutex_lock(&dri2_dpy->image_list_mutex);
|
|
+ img->Resource.Next = dri2_dpy->image_list;
|
|
+ dri2_dpy->image_list = &img->Resource;
|
|
+ pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
|
|
+
|
|
+ return img;
|
|
+
|
|
+fail_delete_user_data:
|
|
+ tbm_surface_internal_delete_user_data(tbm_surf, (unsigned long) disp);
|
|
+fail_destroy_image:
|
|
+ dri2_destroy_image_khr(disp, img);
|
|
+fail_exit:
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static _EGLImage *
|
|
dri2_create_image_tizen(_EGLDisplay *disp, _EGLContext *ctx,
|
|
EGLClientBuffer _buffer,
|
|
const EGLint *attr_list)
|
|
{
|
|
- tbm_surface_h tbm_surf = (tbm_surface_h)_buffer;
|
|
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
+ tbm_surface_h tbm_surf = (tbm_surface_h) _buffer;
|
|
+ _EGLImage *img;
|
|
+ struct dri2_egl_image *dri2_img;
|
|
+ __DRIimage *dri_image;
|
|
+
|
|
+ img = dri2_get_tbm_surf_egl_image(disp, ctx, tbm_surf);
|
|
+ if (!img) {
|
|
+ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tizen");
|
|
+ return NULL;
|
|
+ }
|
|
+ dri2_img = dri2_egl_image(img);
|
|
+
|
|
+ dri_image = dri2_dpy->image->fromPlanar(dri2_img->dri_image, 0, NULL);
|
|
+ if (!dri_image) {
|
|
+ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tizen");
|
|
+ return NULL;
|
|
+ }
|
|
|
|
- return dri2_create_image_tbm_surface(disp, ctx, tbm_surf);
|
|
+ return dri2_create_image_from_dri(disp, dri_image);
|
|
}
|
|
|
|
static _EGLImage *
|
|
@@ -2424,6 +2618,9 @@ dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx,
|
|
_EGLImageAttribs attrs;
|
|
tbm_surface_h tbm_surf;
|
|
tbm_surface_info_s info;
|
|
+ _EGLImage *img;
|
|
+ struct dri2_egl_image *dri2_img;
|
|
+ __DRIimage *dri_image;
|
|
|
|
tbm_surf = tpl_display_get_buffer_from_native_pixmap(dri2_dpy->tpl_dpy,
|
|
(tpl_handle_t) _buffer);
|
|
@@ -2454,7 +2651,21 @@ dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx,
|
|
return NULL;
|
|
}
|
|
|
|
- return dri2_create_image_tbm_surface(disp, ctx, tbm_surf);
|
|
+ img = dri2_get_tbm_surf_egl_image(disp, ctx, tbm_surf);
|
|
+ if (!img) {
|
|
+ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer_tizen");
|
|
+ return NULL;
|
|
+ }
|
|
+ dri2_img = dri2_egl_image(img);
|
|
+
|
|
+ dri_image =
|
|
+ dri2_dpy->image->fromPlanar(dri2_img->dri_image, attrs.PlaneWL, NULL);
|
|
+ if (!dri_image) {
|
|
+ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer_tizen");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return dri2_create_image_from_dri(disp, dri_image);
|
|
}
|
|
#endif
|
|
|
|
@@ -3377,10 +3588,29 @@ dri2_destroy_image_khr(_EGLDisplay *disp, _EGLImage *image)
|
|
{
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
struct dri2_egl_image *dri2_img = dri2_egl_image(image);
|
|
+#ifdef HAVE_TIZEN_PLATFORM
|
|
+ _EGLResource *image_elem;
|
|
+#endif
|
|
|
|
dri2_dpy->image->destroyImage(dri2_img->dri_image);
|
|
free(dri2_img);
|
|
|
|
+#ifdef HAVE_TIZEN_PLATFORM
|
|
+ /* Take the opportunity to destroy orphaned tbm surface _EGLImages */
|
|
+ pthread_mutex_lock(&dri2_dpy->image_list_mutex);
|
|
+ image_elem = dri2_dpy->orphan_image_list;
|
|
+ dri2_dpy->orphan_image_list = NULL;
|
|
+ pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
|
|
+
|
|
+ while (image_elem) {
|
|
+ dri2_img = dri2_egl_image((_EGLImage *) image_elem);
|
|
+ image_elem = image_elem->Next;
|
|
+
|
|
+ dri2_dpy->image->destroyImage(dri2_img->dri_image);
|
|
+ free(dri2_img);
|
|
+ }
|
|
+#endif
|
|
+
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
|
|
index a8bfe45b1f5..546bc0a0dbc 100644
|
|
--- a/src/egl/drivers/dri2/egl_dri2.h
|
|
+++ b/src/egl/drivers/dri2/egl_dri2.h
|
|
@@ -268,6 +268,15 @@ struct dri2_egl_display
|
|
|
|
#ifdef HAVE_TIZEN_PLATFORM
|
|
tpl_display_t *tpl_dpy;
|
|
+ /*
|
|
+ * The image_list_mutex protects the image_list and orphan_image_list. It
|
|
+ * should never be held while calling a libtbm function as this may result
|
|
+ * in a deadlock.
|
|
+ */
|
|
+ pthread_mutex_t image_list_mutex;
|
|
+ bool image_list_mutex_initialized;
|
|
+ _EGLResource *image_list;
|
|
+ _EGLResource *orphan_image_list;
|
|
#endif
|
|
};
|
|
|
|
@@ -413,6 +422,9 @@ struct dri2_egl_image
|
|
{
|
|
_EGLImage base;
|
|
__DRIimage *dri_image;
|
|
+#ifdef HAVE_TIZEN_PLATFORM
|
|
+ tbm_surface_h tbm_surf;
|
|
+#endif
|
|
};
|
|
|
|
struct dri2_egl_sync {
|
|
diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c
|
|
index ad75c115d7e..49462152beb 100644
|
|
--- a/src/egl/drivers/dri2/platform_tizen.c
|
|
+++ b/src/egl/drivers/dri2/platform_tizen.c
|
|
@@ -891,6 +891,7 @@ dri2_initialize_tizen(_EGLDisplay *dpy)
|
|
{
|
|
struct dri2_egl_display *dri2_dpy;
|
|
int i;
|
|
+ int err;
|
|
|
|
dri2_dpy = calloc(1, sizeof(*dri2_dpy));
|
|
if (!dri2_dpy)
|
|
@@ -906,6 +907,11 @@ dri2_initialize_tizen(_EGLDisplay *dpy)
|
|
goto cleanup;
|
|
}
|
|
|
|
+ err = pthread_mutex_init(&dri2_dpy->image_list_mutex, NULL);
|
|
+ if (err)
|
|
+ goto cleanup;
|
|
+ dri2_dpy->image_list_mutex_initialized = true;
|
|
+
|
|
for (i = TIZEN_DRM_RENDER_MINOR_START; i <= TIZEN_DRM_RENDER_MINOR_MAX; i++) {
|
|
char *render_path;
|
|
|
|
--
|
|
2.25.1
|
|
|