123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- From 5212f22050e6e92812b14b6cd1fe5029ceeb4225 Mon Sep 17 00:00:00 2001
- From: Luigi Santivetti <luigi.santivetti@imgtec.com>
- Date: Mon, 21 Oct 2019 09:21:52 +0100
- Subject: [PATCH] egl/null: add support for async flip with front buffer
- rendering
- This change enables the application to render into the buffer being
- scanned out if the display driver doesn't support
- DRM_CAP_ASYNC_PAGE_FLIP.
- The egl display now tracks the DRM async flip capabilities, allowing
- platform_null to always return the buffer on screen to the application
- when the swap interval is set to 0, but the DRM driver doesn't support
- async flip.
- platform_null can be in several alternative states by the time
- eglSwapInterval() is called, following is a summary of them.
- 1. platform_null was initialised and it has already flipped. In this
- case, return to the client API a reference to the buffer on screen
- 2. platform_null was initialised but no back buffer was requested yet
- from the client API. In this case, return a reference to the front
- buffer
- 3. platform_null was initialised and the client API has already got
- a back buffer, but no flip was scheduled. In this case, make sure
- to flip and return the buffer on the screen
- Note that this change also refactors the color buffers and front
- buffer code. Platform null after this change has a dedicated struct
- for storing front buffer DRI data and framebuffer id.
- Also be noted that min_swap_interval is no longer clamped to 1 when
- DRM_CAP_ASYNC_PAGE_FLIP isn't supported. This is because,
- if min_swap_interval is automatically promoted to 1, Mesa EGL will de
- facto prevent the application from requesting any swap interval less
- than 1.
- Change-Id: I3930cfcdb30bfb5358166911bcf84a78bdb4548d
- Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
- ---
- src/egl/drivers/dri2/egl_dri2.h | 8 +-
- src/egl/drivers/dri2/platform_null.c | 153 +++++++++++++++++++++------
- 2 files changed, 129 insertions(+), 32 deletions(-)
- diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
- index 32ad720..27beae5 100644
- --- a/src/egl/drivers/dri2/egl_dri2.h
- +++ b/src/egl/drivers/dri2/egl_dri2.h
- @@ -283,6 +283,7 @@ struct dri2_egl_display
- #ifdef HAVE_NULL_PLATFORM
- bool atomic_enabled;
- bool in_formats_enabled;
- + bool async_flip_enabled;
- struct display_output output;
- #endif
-
- @@ -439,8 +440,12 @@ struct dri2_egl_surface
- #endif
- bool locked;
- int age;
- +#ifdef HAVE_NULL_PLATFORM
- + } color_buffers[DRI2_SURFACE_NUM_COLOR_BUFFERS], *back, *current, front_buffer;
- +#else
- } color_buffers[DRI2_SURFACE_NUM_COLOR_BUFFERS], *back, *current;
- #endif
- +#endif
-
- #ifdef HAVE_ANDROID_PLATFORM
- struct ANativeWindow *window;
- @@ -469,12 +474,13 @@ struct dri2_egl_surface
- #endif
-
- #ifdef HAVE_NULL_PLATFORM
- - uint32_t front_fb_id;
- struct swap_queue_elem swap_queue[DRI2_SURFACE_NUM_COLOR_BUFFERS];
- struct swap_queue_elem *swap_data;
- int swap_state;
- bool mutex_init;
- bool cond_init;
- + bool front_render_enabled;
- + bool front_render_init;
- bool cond_init_unlock_buffer;
- #endif
-
- diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c
- index 2c79199..0ce7e60 100644
- --- a/src/egl/drivers/dri2/platform_null.c
- +++ b/src/egl/drivers/dri2/platform_null.c
- @@ -602,6 +602,15 @@ swap_dequeue_data_finish(struct dri2_egl_surface *dri2_surf)
- pthread_mutex_unlock(&dri2_surf->mutex);
- }
-
- +static void
- +swap_drain_queue_data(struct dri2_egl_surface *dri2_surf)
- +{
- + pthread_mutex_lock(&dri2_surf->mutex);
- + while (dri2_surf->swap_queue_idx_head != dri2_surf->swap_queue_idx_tail)
- + pthread_cond_wait(&dri2_surf->swap_unlock_buffer_cond, &dri2_surf->mutex);
- + pthread_mutex_unlock(&dri2_surf->mutex);
- +}
- +
- static void
- flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
- unsigned int tv_usec, void *flip_data)
- @@ -1146,15 +1155,15 @@ get_front_bo(struct dri2_egl_surface *dri2_surf)
- if (dri2_surf->base.Type == EGL_WINDOW_BIT)
- use |= __DRI_IMAGE_USE_SCANOUT;
-
- - dri2_surf->front = create_image(dri2_surf, use);
- - if (!dri2_surf->front)
- + dri2_surf->front_buffer.dri_image = create_image(dri2_surf, use);
- + if (!dri2_surf->front_buffer.dri_image)
- return false;
-
- if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
- - if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->front,
- - &dri2_surf->front_fb_id)) {
- - dri2_dpy->image->destroyImage(dri2_surf->front);
- - dri2_surf->front = NULL;
- + if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->front_buffer.dri_image,
- + &dri2_surf->front_buffer.fb_id)) {
- + dri2_dpy->image->destroyImage(dri2_surf->front_buffer.dri_image);
- + dri2_surf->front_buffer.dri_image = NULL;
- return false;
- }
- }
- @@ -1362,7 +1371,7 @@ dri2_null_create_window_surface(_EGLDisplay *disp, _EGLConfig *config,
- }
-
- err = display_output_modeset(dri2_dpy->fd, &dri2_dpy->output,
- - dri2_surf->front_fb_id);
- + dri2_surf->front_buffer.fb_id);
- if (err) {
- _eglError(EGL_BAD_NATIVE_WINDOW, "window set mode");
- goto err_destroy_surface;
- @@ -1392,6 +1401,60 @@ dri2_null_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *config,
- return create_surface(disp, config, EGL_PBUFFER_BIT, attrib_list);
- }
-
- +static void
- +dri2_null_init_front_buffer_render(_EGLSurface *draw)
- +{
- + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
- +
- + dri2_surf->front_render_init = true;
- +
- + /* Drain the queue. swap_buffer_unlock_cond signals for the last time
- + * when the last back buffer in the queue went on screen and it's being
- + * tracked as current by then.
- + */
- + swap_drain_queue_data(dri2_surf);
- +
- + /* If previously flipped, take a reference to the current buffer */
- + if (dri2_surf->current) {
- + assert(dri2_surf->current->dri_image);
- + dri2_surf->back = dri2_surf->current;
- +
- + for (unsigned i = 0; i < DRI2_SURFACE_NUM_COLOR_BUFFERS; i++)
- + dri2_surf->color_buffers[i].age = 0;
- +
- + return;
- + }
- +
- + /* If the application hasn't yet fetched a back buffer, then it's not too
- + * late to use front buffer's dri_image and fb_id.
- + */
- + if (!dri2_surf->back) {
- + assert(dri2_surf->front_buffer.dri_image);
- + dri2_surf->back = &dri2_surf->front_buffer;
- +
- + /* Don't need to reset buffer age since no flip was requested yet */
- +
- + return;
- + }
- +
- + /* In order to initialise one color buffer for front buffer rendering,
- + * one page flip must occur.
- + */
- + swap_enqueue_data(dri2_surf, get_back_buffer_id(dri2_surf), 1);
- +
- + return dri2_null_init_front_buffer_render(draw);
- +}
- +
- +static void
- +dri2_null_disable_front_buffer_render(_EGLSurface *draw)
- +{
- + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
- +
- + dri2_surf->front_render_enabled = false;
- + dri2_surf->front_render_init = false;
- + dri2_surf->back = NULL;
- +}
- +
- static EGLBoolean
- dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
- {
- @@ -1403,14 +1466,7 @@ dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
- * sure we process the flip event.
- */
- if (dri2_surf->swap_queue_processor) {
- - pthread_mutex_lock(&dri2_surf->mutex);
- -
- - /* Wait for any outstanding swaps to complete */
- - while (dri2_surf->swap_queue_idx_head != dri2_surf->swap_queue_idx_tail)
- - pthread_cond_wait(&dri2_surf->swap_unlock_buffer_cond,
- - &dri2_surf->mutex);
- -
- - pthread_mutex_unlock(&dri2_surf->mutex);
- + swap_drain_queue_data(dri2_surf);
- pthread_cancel(dri2_surf->swap_queue_processor);
- pthread_join(dri2_surf->swap_queue_processor, NULL);
- }
- @@ -1424,11 +1480,11 @@ dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
- if (dri2_surf->mutex_init)
- pthread_mutex_destroy(&dri2_surf->mutex);
-
- - if (dri2_surf->front)
- - dri2_dpy->image->destroyImage(dri2_surf->front);
- + if (dri2_surf->front_buffer.dri_image)
- + dri2_dpy->image->destroyImage(dri2_surf->front_buffer.dri_image);
-
- - if (dri2_surf->front_fb_id)
- - drmModeRmFB(dri2_dpy->fd, dri2_surf->front_fb_id);
- + if (dri2_surf->front_buffer.fb_id)
- + drmModeRmFB(dri2_dpy->fd, dri2_surf->front_buffer.fb_id);
-
- for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
- if (dri2_surf->color_buffers[i].fb_id)
- @@ -1455,6 +1511,16 @@ dri2_null_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
- if (dri2_surf->base.Type != EGL_WINDOW_BIT)
- return EGL_TRUE;
-
- + /* Flush and early return, no swap takes place */
- + if (dri2_surf->front_render_enabled) {
- + dri2_flush_drawable_for_swapbuffers(disp, draw);
- +
- + if (!dri2_surf->front_render_init)
- + dri2_null_init_front_buffer_render(draw);
- +
- + return EGL_TRUE;
- + }
- +
- for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
- if (dri2_surf->color_buffers[i].age > 0)
- dri2_surf->color_buffers[i].age++;
- @@ -1497,6 +1563,22 @@ dri2_null_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
- static EGLBoolean
- dri2_null_swap_interval(_EGLDisplay *dpy, _EGLSurface *draw, EGLint interval)
- {
- + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
- + struct dri2_egl_display *dri2_dpy =
- + dri2_egl_display(dri2_surf->base.Resource.Display);
- +
- + /* dri2_dpy tracks whether the display driver is async flip capable.
- + * If it isn't, enable front buffer rendering when swap interval
- + * 0 is passed in from the application.
- + */
- + if (!interval && !dri2_dpy->async_flip_enabled) {
- + if (!dri2_surf->front_render_enabled)
- + dri2_surf->front_render_enabled = true;
- + } else {
- + if (dri2_surf->front_render_enabled)
- + dri2_null_disable_front_buffer_render(draw);
- + }
- +
- _eglLog(_EGL_DEBUG, "DRI2: set swap interval to %d", interval);
- draw->SwapInterval = interval;
- return EGL_TRUE;
- @@ -1534,7 +1616,7 @@ dri2_null_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format,
-
- if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
- buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
- - buffers->front = dri2_surf->front;
- + buffers->front = dri2_surf->front_buffer.dri_image;
- }
-
- if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
- @@ -1672,18 +1754,27 @@ dri2_null_setup_swap_interval(_EGLDisplay *disp)
- dri2_setup_swap_interval(disp, swap_max_interval);
-
- err = drmGetCap(dri2_dpy->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value);
- - if (err || value == 0)
- - dri2_dpy->min_swap_interval = 1;
- + if (err || value == 0) {
-
- - /**
- - * drm/atomic: Reject FLIP_ASYNC unconditionally
- - * upstream f2cbda2dba11de868759cae9c0d2bab5b8411406
- - *
- - * Only allow swap interval 0 for legacy DRM/KMS and let
- - * the app be aware that swap interval is clamped to 1.
- - */
- - if (dri2_dpy->atomic_enabled)
- - dri2_dpy->min_swap_interval = 1;
- + /* DRM/KMS does not support async page flip. In order to support
- + * swap interval 0, use front buffer rendering.
- + */
- + _eglLog(_EGL_DEBUG,
- + "drm async flip not supported, use front buffer");
- + } else {
- +
- + /* drm/atomic: Reject FLIP_ASYNC unconditionally
- + * upstream f2cbda2dba11de868759cae9c0d2bab5b8411406
- + *
- + * Legacy DRM/KMS can use DRM_MODE_PAGE_FLIP_ASYNC, for atomic
- + * drivers fallback to front buffer rendering.
- + */
- + if (dri2_dpy->atomic_enabled)
- + _eglLog(_EGL_DEBUG,
- + "async flip not supported by atomic, use front buffer");
- + else
- + dri2_dpy->async_flip_enabled = true;
- + }
- }
-
- EGLBoolean
|