0022-egl-tizen-create-an-internal-_EGLImage-for-each-tbm-.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. From 6d364d64fb28069a0ce9bab65a6f12f873707eda Mon Sep 17 00:00:00 2001
  2. From: Frank Binns <frank.binns@imgtec.com>
  3. Date: Wed, 25 Oct 2017 18:15:00 +0100
  4. Subject: [PATCH] egl/tizen: create an internal _EGLImage for each tbm surface
  5. Create an internal _EGLImage the first time a tbm surface is seen
  6. by eglCreateImageKHR (with either the EGL_WAYLAND_BUFFER_WL or
  7. EGL_NATIVE_SURFACE_TIZEN target) and return a copy of it to the
  8. caller. This avoids some tbm surfaces being frequently mapped and
  9. then unmapped from the GPU.
  10. ---
  11. src/egl/drivers/dri2/egl_dri2.c | 236 +++++++++++++++++++++++++-
  12. src/egl/drivers/dri2/egl_dri2.h | 12 ++
  13. src/egl/drivers/dri2/platform_tizen.c | 6 +
  14. 3 files changed, 251 insertions(+), 3 deletions(-)
  15. diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
  16. index eaa0bae..db993f8 100644
  17. --- a/src/egl/drivers/dri2/egl_dri2.c
  18. +++ b/src/egl/drivers/dri2/egl_dri2.c
  19. @@ -1264,6 +1264,10 @@ dri2_display_destroy(_EGLDisplay *disp)
  20. break;
  21. #ifdef HAVE_TIZEN_PLATFORM
  22. case _EGL_PLATFORM_TIZEN:
  23. + if (dri2_dpy->image_list_mutex_initialized) {
  24. + pthread_mutex_destroy(&dri2_dpy->image_list_mutex);
  25. + dri2_dpy->image_list_mutex_initialized = false;
  26. + }
  27. if (dri2_dpy->tpl_dpy)
  28. tpl_object_unreference((tpl_object_t *) dri2_dpy->tpl_dpy);
  29. break;
  30. @@ -1320,6 +1324,60 @@ dri2_egl_surface_free_local_buffers(struct dri2_egl_surface *dri2_surf)
  31. }
  32. }
  33. +static void
  34. +dri2_display_release_resources_tizen(_EGLDisplay *disp)
  35. +{
  36. +#ifdef HAVE_TIZEN_PLATFORM
  37. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  38. + _EGLResource *image_elem;
  39. +
  40. + /* Destroy _EGLImages in the image_list */
  41. + pthread_mutex_lock(&dri2_dpy->image_list_mutex);
  42. + image_elem = dri2_dpy->image_list;
  43. + dri2_dpy->image_list = NULL;
  44. + pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
  45. +
  46. + while (image_elem) {
  47. + _EGLImage *img = (_EGLImage *) image_elem;
  48. + struct dri2_egl_image *dri2_img = dri2_egl_image(img);
  49. +
  50. + image_elem = image_elem->Next;
  51. +
  52. + /*
  53. + * Delete the tbm surface user data (_EGLImage), unless the tbm surface
  54. + * was destroyed since we started processing the image_list.
  55. + */
  56. + if (dri2_img->tbm_surf)
  57. + tbm_surface_internal_delete_user_data(dri2_img->tbm_surf,
  58. + (unsigned long) disp);
  59. +
  60. + /*
  61. + * dri2_orphan_tbm_surf_egl_image won't be able to transfer the
  62. + * _EGLImage to the orphan_image_list once we have started processing
  63. + * the image_list so we must destroy it ourselves.
  64. + */
  65. + dri2_dpy->image->destroyImage(dri2_img->dri_image);
  66. + free(dri2_img);
  67. + }
  68. +
  69. + /* Destroy _EGLimages in the orphan_image_list*/
  70. + pthread_mutex_lock(&dri2_dpy->image_list_mutex);
  71. + image_elem = dri2_dpy->orphan_image_list;
  72. + dri2_dpy->orphan_image_list = NULL;
  73. + pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
  74. +
  75. + while (image_elem) {
  76. + _EGLImage *img = (_EGLImage *) image_elem;
  77. + struct dri2_egl_image *dri2_img = dri2_egl_image(img);
  78. +
  79. + image_elem = image_elem->Next;
  80. +
  81. + dri2_dpy->image->destroyImage(dri2_img->dri_image);
  82. + free(dri2_img);
  83. + }
  84. +#endif
  85. +}
  86. +
  87. /**
  88. * Called via eglTerminate(), drv->Terminate().
  89. *
  90. @@ -1332,6 +1390,8 @@ dri2_terminate(_EGLDisplay *disp)
  91. /* Release all non-current Context/Surfaces. */
  92. _eglReleaseDisplayResources(disp);
  93. + dri2_display_release_resources_tizen(disp);
  94. +
  95. dri2_display_release(disp);
  96. return EGL_TRUE;
  97. @@ -2309,6 +2369,9 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
  98. }
  99. #ifdef HAVE_TIZEN_PLATFORM
  100. +static EGLBoolean
  101. +dri2_destroy_image_khr(_EGLDisplay *disp, _EGLImage *image);
  102. +
  103. int
  104. dri2_fourcc_from_tbm_format(tbm_format format)
  105. {
  106. @@ -2405,14 +2468,145 @@ fail_close:
  107. return NULL;
  108. }
  109. +static void
  110. +dri2_orphan_tbm_surf_egl_image(void *user_data)
  111. +{
  112. + _EGLImage *img = user_data;
  113. + struct dri2_egl_image *dri2_img = dri2_egl_image(img);
  114. + _EGLDisplay *disp = img->Resource.Display;
  115. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  116. +
  117. + /*
  118. + * Transfer the passed in _EGLImage from the image_list to the
  119. + * orphan_image_list so that it can be cleaned up at some later
  120. + * point. This is necessary as the disp->Mutex needs to be held
  121. + * in order destroy the _EGLImage and this could potentially cause
  122. + * a deadlock in the event that the tbm surface is destroyed.
  123. + */
  124. + pthread_mutex_lock(&dri2_dpy->image_list_mutex);
  125. + /*
  126. + * This may be NULL if called via dri2_terminate or if dri2_terminate is
  127. + * running in another thread.
  128. + */
  129. + if (dri2_dpy->image_list) {
  130. + _EGLResource *image_elem;
  131. +
  132. + /* Remove the _EGLImage from the image_list */
  133. + image_elem = dri2_dpy->image_list;
  134. + if (image_elem != &img->Resource) {
  135. + while (image_elem) {
  136. + if (image_elem->Next == &img->Resource)
  137. + break;
  138. + image_elem = image_elem->Next;
  139. + }
  140. + image_elem->Next = img->Resource.Next;
  141. + } else {
  142. + dri2_dpy->image_list = img->Resource.Next;
  143. + }
  144. +
  145. + /* Add the _EGLImage to the orphan_image_list */
  146. + img->Resource.Next = dri2_dpy->orphan_image_list;
  147. + dri2_dpy->orphan_image_list = &img->Resource;
  148. + }
  149. +
  150. + /*
  151. + * This function may have been called via tbm_surface_destroy so tbm_surf
  152. + * may be invalid after this function returns.
  153. + */
  154. + dri2_img->tbm_surf = NULL;
  155. + pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
  156. +}
  157. +
  158. +static _EGLImage *
  159. +dri2_get_tbm_surf_egl_image(_EGLDisplay *disp, _EGLContext *ctx,
  160. + tbm_surface_h tbm_surf)
  161. +{
  162. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  163. + struct dri2_egl_image *dri2_img;
  164. + _EGLImage *img;
  165. + int ret;
  166. +
  167. + ret = tbm_surface_internal_get_user_data(tbm_surf, (unsigned long) disp,
  168. + (void **) &img);
  169. + if (ret)
  170. + return img;
  171. +
  172. + img = dri2_create_image_tbm_surface(disp, ctx, tbm_surf);
  173. + if (!img) {
  174. + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tbm_surface failed");
  175. + goto fail_exit;
  176. + }
  177. + dri2_img = dri2_egl_image(img);
  178. +
  179. + /* Use 'disp' as the 'key' as the _EGLimage is tied to it */
  180. + ret = tbm_surface_internal_add_user_data(tbm_surf, (unsigned long) disp,
  181. + dri2_orphan_tbm_surf_egl_image);
  182. + if (!ret) {
  183. + _eglError(EGL_BAD_PARAMETER, "dri2_get_tbm_surf_egl_image");
  184. + goto fail_destroy_image;
  185. + }
  186. +
  187. + ret = tbm_surface_internal_set_user_data(tbm_surf, (unsigned long) disp, img);
  188. + if (!ret) {
  189. + _eglError(EGL_BAD_PARAMETER, "dri2_get_tbm_surf_egl_image");
  190. + goto fail_delete_user_data;
  191. + }
  192. +
  193. + /*
  194. + * Store the tbm surface so that the user data (_EGLImage) can be destroyed
  195. + * in dri2_terminate. We don't take a reference on the surface as this would
  196. + * prevent it from being destroyed until eglTerminate is called. This isn't
  197. + * an issue since it will be set to NULL, via dri2_orphan_tbm_surf_egl_image,
  198. + * once the surface is destroyed (although it's actually safe to call tbm
  199. + * surface functions with stale/NULL pointers).
  200. + */
  201. + dri2_img->tbm_surf = tbm_surf;
  202. +
  203. + /*
  204. + * Add to the list of _EGLImages that are associated with tbm surfaces.
  205. + * This allows the _EGLImage to be destroyed if the application calls
  206. + * eglTerminate before the tbm surface is destroyed.
  207. + */
  208. + pthread_mutex_lock(&dri2_dpy->image_list_mutex);
  209. + img->Resource.Next = dri2_dpy->image_list;
  210. + dri2_dpy->image_list = &img->Resource;
  211. + pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
  212. +
  213. + return img;
  214. +
  215. +fail_delete_user_data:
  216. + tbm_surface_internal_delete_user_data(tbm_surf, (unsigned long) disp);
  217. +fail_destroy_image:
  218. + dri2_destroy_image_khr(disp, img);
  219. +fail_exit:
  220. + return NULL;
  221. +}
  222. +
  223. static _EGLImage *
  224. dri2_create_image_tizen(_EGLDisplay *disp, _EGLContext *ctx,
  225. EGLClientBuffer _buffer,
  226. const EGLint *attr_list)
  227. {
  228. - tbm_surface_h tbm_surf = (tbm_surface_h)_buffer;
  229. + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  230. + tbm_surface_h tbm_surf = (tbm_surface_h) _buffer;
  231. + _EGLImage *img;
  232. + struct dri2_egl_image *dri2_img;
  233. + __DRIimage *dri_image;
  234. +
  235. + img = dri2_get_tbm_surf_egl_image(disp, ctx, tbm_surf);
  236. + if (!img) {
  237. + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tizen");
  238. + return NULL;
  239. + }
  240. + dri2_img = dri2_egl_image(img);
  241. +
  242. + dri_image = dri2_dpy->image->fromPlanar(dri2_img->dri_image, 0, NULL);
  243. + if (!dri_image) {
  244. + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tizen");
  245. + return NULL;
  246. + }
  247. - return dri2_create_image_tbm_surface(disp, ctx, tbm_surf);
  248. + return dri2_create_image_from_dri(disp, dri_image);
  249. }
  250. static _EGLImage *
  251. @@ -2424,6 +2618,9 @@ dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx,
  252. _EGLImageAttribs attrs;
  253. tbm_surface_h tbm_surf;
  254. tbm_surface_info_s info;
  255. + _EGLImage *img;
  256. + struct dri2_egl_image *dri2_img;
  257. + __DRIimage *dri_image;
  258. tbm_surf = tpl_display_get_buffer_from_native_pixmap(dri2_dpy->tpl_dpy,
  259. (tpl_handle_t) _buffer);
  260. @@ -2454,7 +2651,21 @@ dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx,
  261. return NULL;
  262. }
  263. - return dri2_create_image_tbm_surface(disp, ctx, tbm_surf);
  264. + img = dri2_get_tbm_surf_egl_image(disp, ctx, tbm_surf);
  265. + if (!img) {
  266. + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer_tizen");
  267. + return NULL;
  268. + }
  269. + dri2_img = dri2_egl_image(img);
  270. +
  271. + dri_image =
  272. + dri2_dpy->image->fromPlanar(dri2_img->dri_image, attrs.PlaneWL, NULL);
  273. + if (!dri_image) {
  274. + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer_tizen");
  275. + return NULL;
  276. + }
  277. +
  278. + return dri2_create_image_from_dri(disp, dri_image);
  279. }
  280. #endif
  281. @@ -3377,10 +3588,29 @@ dri2_destroy_image_khr(_EGLDisplay *disp, _EGLImage *image)
  282. {
  283. struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  284. struct dri2_egl_image *dri2_img = dri2_egl_image(image);
  285. +#ifdef HAVE_TIZEN_PLATFORM
  286. + _EGLResource *image_elem;
  287. +#endif
  288. dri2_dpy->image->destroyImage(dri2_img->dri_image);
  289. free(dri2_img);
  290. +#ifdef HAVE_TIZEN_PLATFORM
  291. + /* Take the opportunity to destroy orphaned tbm surface _EGLImages */
  292. + pthread_mutex_lock(&dri2_dpy->image_list_mutex);
  293. + image_elem = dri2_dpy->orphan_image_list;
  294. + dri2_dpy->orphan_image_list = NULL;
  295. + pthread_mutex_unlock(&dri2_dpy->image_list_mutex);
  296. +
  297. + while (image_elem) {
  298. + dri2_img = dri2_egl_image((_EGLImage *) image_elem);
  299. + image_elem = image_elem->Next;
  300. +
  301. + dri2_dpy->image->destroyImage(dri2_img->dri_image);
  302. + free(dri2_img);
  303. + }
  304. +#endif
  305. +
  306. return EGL_TRUE;
  307. }
  308. diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
  309. index a8bfe45..546bc0a 100644
  310. --- a/src/egl/drivers/dri2/egl_dri2.h
  311. +++ b/src/egl/drivers/dri2/egl_dri2.h
  312. @@ -268,6 +268,15 @@ struct dri2_egl_display
  313. #ifdef HAVE_TIZEN_PLATFORM
  314. tpl_display_t *tpl_dpy;
  315. + /*
  316. + * The image_list_mutex protects the image_list and orphan_image_list. It
  317. + * should never be held while calling a libtbm function as this may result
  318. + * in a deadlock.
  319. + */
  320. + pthread_mutex_t image_list_mutex;
  321. + bool image_list_mutex_initialized;
  322. + _EGLResource *image_list;
  323. + _EGLResource *orphan_image_list;
  324. #endif
  325. };
  326. @@ -413,6 +422,9 @@ struct dri2_egl_image
  327. {
  328. _EGLImage base;
  329. __DRIimage *dri_image;
  330. +#ifdef HAVE_TIZEN_PLATFORM
  331. + tbm_surface_h tbm_surf;
  332. +#endif
  333. };
  334. struct dri2_egl_sync {
  335. diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c
  336. index ad75c11..4946215 100644
  337. --- a/src/egl/drivers/dri2/platform_tizen.c
  338. +++ b/src/egl/drivers/dri2/platform_tizen.c
  339. @@ -891,6 +891,7 @@ dri2_initialize_tizen(_EGLDisplay *dpy)
  340. {
  341. struct dri2_egl_display *dri2_dpy;
  342. int i;
  343. + int err;
  344. dri2_dpy = calloc(1, sizeof(*dri2_dpy));
  345. if (!dri2_dpy)
  346. @@ -906,6 +907,11 @@ dri2_initialize_tizen(_EGLDisplay *dpy)
  347. goto cleanup;
  348. }
  349. + err = pthread_mutex_init(&dri2_dpy->image_list_mutex, NULL);
  350. + if (err)
  351. + goto cleanup;
  352. + dri2_dpy->image_list_mutex_initialized = true;
  353. +
  354. for (i = TIZEN_DRM_RENDER_MINOR_START; i <= TIZEN_DRM_RENDER_MINOR_MAX; i++) {
  355. char *render_path;