123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- From 6d364d64fb28069a0ce9bab65a6f12f873707eda 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] 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 eaa0bae..db993f8 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 a8bfe45..546bc0a 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 ad75c11..4946215 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;
-
|