0047-egl-null-add-support-for-async-flip-with-front-buffe.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. From 5212f22050e6e92812b14b6cd1fe5029ceeb4225 Mon Sep 17 00:00:00 2001
  2. From: Luigi Santivetti <luigi.santivetti@imgtec.com>
  3. Date: Mon, 21 Oct 2019 09:21:52 +0100
  4. Subject: [PATCH] egl/null: add support for async flip with front buffer
  5. rendering
  6. This change enables the application to render into the buffer being
  7. scanned out if the display driver doesn't support
  8. DRM_CAP_ASYNC_PAGE_FLIP.
  9. The egl display now tracks the DRM async flip capabilities, allowing
  10. platform_null to always return the buffer on screen to the application
  11. when the swap interval is set to 0, but the DRM driver doesn't support
  12. async flip.
  13. platform_null can be in several alternative states by the time
  14. eglSwapInterval() is called, following is a summary of them.
  15. 1. platform_null was initialised and it has already flipped. In this
  16. case, return to the client API a reference to the buffer on screen
  17. 2. platform_null was initialised but no back buffer was requested yet
  18. from the client API. In this case, return a reference to the front
  19. buffer
  20. 3. platform_null was initialised and the client API has already got
  21. a back buffer, but no flip was scheduled. In this case, make sure
  22. to flip and return the buffer on the screen
  23. Note that this change also refactors the color buffers and front
  24. buffer code. Platform null after this change has a dedicated struct
  25. for storing front buffer DRI data and framebuffer id.
  26. Also be noted that min_swap_interval is no longer clamped to 1 when
  27. DRM_CAP_ASYNC_PAGE_FLIP isn't supported. This is because,
  28. if min_swap_interval is automatically promoted to 1, Mesa EGL will de
  29. facto prevent the application from requesting any swap interval less
  30. than 1.
  31. Change-Id: I3930cfcdb30bfb5358166911bcf84a78bdb4548d
  32. Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
  33. ---
  34. src/egl/drivers/dri2/egl_dri2.h | 8 +-
  35. src/egl/drivers/dri2/platform_null.c | 153 +++++++++++++++++++++------
  36. 2 files changed, 129 insertions(+), 32 deletions(-)
  37. diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
  38. index 32ad720..27beae5 100644
  39. --- a/src/egl/drivers/dri2/egl_dri2.h
  40. +++ b/src/egl/drivers/dri2/egl_dri2.h
  41. @@ -283,6 +283,7 @@ struct dri2_egl_display
  42. #ifdef HAVE_NULL_PLATFORM
  43. bool atomic_enabled;
  44. bool in_formats_enabled;
  45. + bool async_flip_enabled;
  46. struct display_output output;
  47. #endif
  48. @@ -439,8 +440,12 @@ struct dri2_egl_surface
  49. #endif
  50. bool locked;
  51. int age;
  52. +#ifdef HAVE_NULL_PLATFORM
  53. + } color_buffers[DRI2_SURFACE_NUM_COLOR_BUFFERS], *back, *current, front_buffer;
  54. +#else
  55. } color_buffers[DRI2_SURFACE_NUM_COLOR_BUFFERS], *back, *current;
  56. #endif
  57. +#endif
  58. #ifdef HAVE_ANDROID_PLATFORM
  59. struct ANativeWindow *window;
  60. @@ -469,12 +474,13 @@ struct dri2_egl_surface
  61. #endif
  62. #ifdef HAVE_NULL_PLATFORM
  63. - uint32_t front_fb_id;
  64. struct swap_queue_elem swap_queue[DRI2_SURFACE_NUM_COLOR_BUFFERS];
  65. struct swap_queue_elem *swap_data;
  66. int swap_state;
  67. bool mutex_init;
  68. bool cond_init;
  69. + bool front_render_enabled;
  70. + bool front_render_init;
  71. bool cond_init_unlock_buffer;
  72. #endif
  73. diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c
  74. index 2c79199..0ce7e60 100644
  75. --- a/src/egl/drivers/dri2/platform_null.c
  76. +++ b/src/egl/drivers/dri2/platform_null.c
  77. @@ -602,6 +602,15 @@ swap_dequeue_data_finish(struct dri2_egl_surface *dri2_surf)
  78. pthread_mutex_unlock(&dri2_surf->mutex);
  79. }
  80. +static void
  81. +swap_drain_queue_data(struct dri2_egl_surface *dri2_surf)
  82. +{
  83. + pthread_mutex_lock(&dri2_surf->mutex);
  84. + while (dri2_surf->swap_queue_idx_head != dri2_surf->swap_queue_idx_tail)
  85. + pthread_cond_wait(&dri2_surf->swap_unlock_buffer_cond, &dri2_surf->mutex);
  86. + pthread_mutex_unlock(&dri2_surf->mutex);
  87. +}
  88. +
  89. static void
  90. flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
  91. unsigned int tv_usec, void *flip_data)
  92. @@ -1146,15 +1155,15 @@ get_front_bo(struct dri2_egl_surface *dri2_surf)
  93. if (dri2_surf->base.Type == EGL_WINDOW_BIT)
  94. use |= __DRI_IMAGE_USE_SCANOUT;
  95. - dri2_surf->front = create_image(dri2_surf, use);
  96. - if (!dri2_surf->front)
  97. + dri2_surf->front_buffer.dri_image = create_image(dri2_surf, use);
  98. + if (!dri2_surf->front_buffer.dri_image)
  99. return false;
  100. if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
  101. - if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->front,
  102. - &dri2_surf->front_fb_id)) {
  103. - dri2_dpy->image->destroyImage(dri2_surf->front);
  104. - dri2_surf->front = NULL;
  105. + if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->front_buffer.dri_image,
  106. + &dri2_surf->front_buffer.fb_id)) {
  107. + dri2_dpy->image->destroyImage(dri2_surf->front_buffer.dri_image);
  108. + dri2_surf->front_buffer.dri_image = NULL;
  109. return false;
  110. }
  111. }
  112. @@ -1362,7 +1371,7 @@ dri2_null_create_window_surface(_EGLDisplay *disp, _EGLConfig *config,
  113. }
  114. err = display_output_modeset(dri2_dpy->fd, &dri2_dpy->output,
  115. - dri2_surf->front_fb_id);
  116. + dri2_surf->front_buffer.fb_id);
  117. if (err) {
  118. _eglError(EGL_BAD_NATIVE_WINDOW, "window set mode");
  119. goto err_destroy_surface;
  120. @@ -1392,6 +1401,60 @@ dri2_null_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *config,
  121. return create_surface(disp, config, EGL_PBUFFER_BIT, attrib_list);
  122. }
  123. +static void
  124. +dri2_null_init_front_buffer_render(_EGLSurface *draw)
  125. +{
  126. + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
  127. +
  128. + dri2_surf->front_render_init = true;
  129. +
  130. + /* Drain the queue. swap_buffer_unlock_cond signals for the last time
  131. + * when the last back buffer in the queue went on screen and it's being
  132. + * tracked as current by then.
  133. + */
  134. + swap_drain_queue_data(dri2_surf);
  135. +
  136. + /* If previously flipped, take a reference to the current buffer */
  137. + if (dri2_surf->current) {
  138. + assert(dri2_surf->current->dri_image);
  139. + dri2_surf->back = dri2_surf->current;
  140. +
  141. + for (unsigned i = 0; i < DRI2_SURFACE_NUM_COLOR_BUFFERS; i++)
  142. + dri2_surf->color_buffers[i].age = 0;
  143. +
  144. + return;
  145. + }
  146. +
  147. + /* If the application hasn't yet fetched a back buffer, then it's not too
  148. + * late to use front buffer's dri_image and fb_id.
  149. + */
  150. + if (!dri2_surf->back) {
  151. + assert(dri2_surf->front_buffer.dri_image);
  152. + dri2_surf->back = &dri2_surf->front_buffer;
  153. +
  154. + /* Don't need to reset buffer age since no flip was requested yet */
  155. +
  156. + return;
  157. + }
  158. +
  159. + /* In order to initialise one color buffer for front buffer rendering,
  160. + * one page flip must occur.
  161. + */
  162. + swap_enqueue_data(dri2_surf, get_back_buffer_id(dri2_surf), 1);
  163. +
  164. + return dri2_null_init_front_buffer_render(draw);
  165. +}
  166. +
  167. +static void
  168. +dri2_null_disable_front_buffer_render(_EGLSurface *draw)
  169. +{
  170. + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
  171. +
  172. + dri2_surf->front_render_enabled = false;
  173. + dri2_surf->front_render_init = false;
  174. + dri2_surf->back = NULL;
  175. +}
  176. +
  177. static EGLBoolean
  178. dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
  179. {
  180. @@ -1403,14 +1466,7 @@ dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
  181. * sure we process the flip event.
  182. */
  183. if (dri2_surf->swap_queue_processor) {
  184. - pthread_mutex_lock(&dri2_surf->mutex);
  185. -
  186. - /* Wait for any outstanding swaps to complete */
  187. - while (dri2_surf->swap_queue_idx_head != dri2_surf->swap_queue_idx_tail)
  188. - pthread_cond_wait(&dri2_surf->swap_unlock_buffer_cond,
  189. - &dri2_surf->mutex);
  190. -
  191. - pthread_mutex_unlock(&dri2_surf->mutex);
  192. + swap_drain_queue_data(dri2_surf);
  193. pthread_cancel(dri2_surf->swap_queue_processor);
  194. pthread_join(dri2_surf->swap_queue_processor, NULL);
  195. }
  196. @@ -1424,11 +1480,11 @@ dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
  197. if (dri2_surf->mutex_init)
  198. pthread_mutex_destroy(&dri2_surf->mutex);
  199. - if (dri2_surf->front)
  200. - dri2_dpy->image->destroyImage(dri2_surf->front);
  201. + if (dri2_surf->front_buffer.dri_image)
  202. + dri2_dpy->image->destroyImage(dri2_surf->front_buffer.dri_image);
  203. - if (dri2_surf->front_fb_id)
  204. - drmModeRmFB(dri2_dpy->fd, dri2_surf->front_fb_id);
  205. + if (dri2_surf->front_buffer.fb_id)
  206. + drmModeRmFB(dri2_dpy->fd, dri2_surf->front_buffer.fb_id);
  207. for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  208. if (dri2_surf->color_buffers[i].fb_id)
  209. @@ -1455,6 +1511,16 @@ dri2_null_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
  210. if (dri2_surf->base.Type != EGL_WINDOW_BIT)
  211. return EGL_TRUE;
  212. + /* Flush and early return, no swap takes place */
  213. + if (dri2_surf->front_render_enabled) {
  214. + dri2_flush_drawable_for_swapbuffers(disp, draw);
  215. +
  216. + if (!dri2_surf->front_render_init)
  217. + dri2_null_init_front_buffer_render(draw);
  218. +
  219. + return EGL_TRUE;
  220. + }
  221. +
  222. for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
  223. if (dri2_surf->color_buffers[i].age > 0)
  224. dri2_surf->color_buffers[i].age++;
  225. @@ -1497,6 +1563,22 @@ dri2_null_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
  226. static EGLBoolean
  227. dri2_null_swap_interval(_EGLDisplay *dpy, _EGLSurface *draw, EGLint interval)
  228. {
  229. + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
  230. + struct dri2_egl_display *dri2_dpy =
  231. + dri2_egl_display(dri2_surf->base.Resource.Display);
  232. +
  233. + /* dri2_dpy tracks whether the display driver is async flip capable.
  234. + * If it isn't, enable front buffer rendering when swap interval
  235. + * 0 is passed in from the application.
  236. + */
  237. + if (!interval && !dri2_dpy->async_flip_enabled) {
  238. + if (!dri2_surf->front_render_enabled)
  239. + dri2_surf->front_render_enabled = true;
  240. + } else {
  241. + if (dri2_surf->front_render_enabled)
  242. + dri2_null_disable_front_buffer_render(draw);
  243. + }
  244. +
  245. _eglLog(_EGL_DEBUG, "DRI2: set swap interval to %d", interval);
  246. draw->SwapInterval = interval;
  247. return EGL_TRUE;
  248. @@ -1534,7 +1616,7 @@ dri2_null_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format,
  249. if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
  250. buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
  251. - buffers->front = dri2_surf->front;
  252. + buffers->front = dri2_surf->front_buffer.dri_image;
  253. }
  254. if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
  255. @@ -1672,18 +1754,27 @@ dri2_null_setup_swap_interval(_EGLDisplay *disp)
  256. dri2_setup_swap_interval(disp, swap_max_interval);
  257. err = drmGetCap(dri2_dpy->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value);
  258. - if (err || value == 0)
  259. - dri2_dpy->min_swap_interval = 1;
  260. + if (err || value == 0) {
  261. - /**
  262. - * drm/atomic: Reject FLIP_ASYNC unconditionally
  263. - * upstream f2cbda2dba11de868759cae9c0d2bab5b8411406
  264. - *
  265. - * Only allow swap interval 0 for legacy DRM/KMS and let
  266. - * the app be aware that swap interval is clamped to 1.
  267. - */
  268. - if (dri2_dpy->atomic_enabled)
  269. - dri2_dpy->min_swap_interval = 1;
  270. + /* DRM/KMS does not support async page flip. In order to support
  271. + * swap interval 0, use front buffer rendering.
  272. + */
  273. + _eglLog(_EGL_DEBUG,
  274. + "drm async flip not supported, use front buffer");
  275. + } else {
  276. +
  277. + /* drm/atomic: Reject FLIP_ASYNC unconditionally
  278. + * upstream f2cbda2dba11de868759cae9c0d2bab5b8411406
  279. + *
  280. + * Legacy DRM/KMS can use DRM_MODE_PAGE_FLIP_ASYNC, for atomic
  281. + * drivers fallback to front buffer rendering.
  282. + */
  283. + if (dri2_dpy->atomic_enabled)
  284. + _eglLog(_EGL_DEBUG,
  285. + "async flip not supported by atomic, use front buffer");
  286. + else
  287. + dri2_dpy->async_flip_enabled = true;
  288. + }
  289. }
  290. EGLBoolean