Files
fml13v01-buildroot/package/mesa3d/0022-egl-tizen-create-an-internal-_EGLImage-for-each-tbm-.patch
T
2022-08-16 17:38:05 +08:00

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