Merge pull request #4485 from vanfanel/master

DISPMANX: now waiting for free pages after issuing flip, instead of b…
This commit is contained in:
Twinaphex 2017-01-23 15:20:19 +01:00 committed by GitHub
commit 400d4f1684

View File

@ -59,6 +59,10 @@ struct dispmanx_surface
struct dispmanx_page *pages; struct dispmanx_page *pages;
/* the page that's currently on screen */ /* the page that's currently on screen */
struct dispmanx_page *current_page; struct dispmanx_page *current_page;
/*The page to wich we will dump the render. We need to know this
* already when we enter the surface update function. No time to wait
* for free pages before blitting and showing the just rendered frame! */
struct dispmanx_page *next_page;
unsigned int bpp; unsigned int bpp;
VC_RECT_T src_rect; VC_RECT_T src_rect;
@ -145,7 +149,7 @@ static struct dispmanx_page *dispmanx_get_free_page(void *data, struct dispmanx_
break; break;
} }
} }
/* If no page is free at the moment, /* If no page is free at the moment,
* wait until a free page is freed by vsync CB. */ * wait until a free page is freed by vsync CB. */
if (!page) if (!page)
@ -178,10 +182,9 @@ static void dispmanx_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
/* We mark as free the page that was visible until now */ /* We mark as free the page that was visible until now */
surface->current_page->used = false; surface->current_page->used = false;
slock_unlock(surface->current_page->page_used_mutex); slock_unlock(surface->current_page->page_used_mutex);
} }
/* The page on which we issued the flip that /* The page on which we issued the flip that
* caused this callback becomes the visible one */ * caused this callback becomes the visible one */
surface->current_page = page; surface->current_page = page;
@ -265,6 +268,11 @@ static void dispmanx_surface_setup(void *data, int src_width, int src_height,
surface->pages[i].page_used_mutex = slock_new(); surface->pages[i].page_used_mutex = slock_new();
} }
/* No need to mutex this access to the "used" member because
* the flipping/callbacks are not still running */
surface->next_page = &(surface->pages[0]);
surface->next_page->used = true;
/* The "visible" width obtained from the core pitch. We blit based on /* The "visible" width obtained from the core pitch. We blit based on
* the "visible" width, for cores with things between scanlines. */ * the "visible" width, for cores with things between scanlines. */
int visible_width = visible_pitch / (bpp / 8); int visible_width = visible_pitch / (bpp / 8);
@ -307,7 +315,7 @@ static void dispmanx_surface_update_async(void *data, const void *frame,
{ {
struct dispmanx_video *_dispvars = data; struct dispmanx_video *_dispvars = data;
struct dispmanx_page *page = NULL; struct dispmanx_page *page = NULL;
/* Since it's an async update, there's no need for multiple pages */ /* Since it's an async update, there's no need for multiple pages */
page = &(surface->pages[0]); page = &(surface->pages[0]);
@ -319,33 +327,42 @@ static void dispmanx_surface_update_async(void *data, const void *frame,
static void dispmanx_surface_update(void *data, const void *frame, static void dispmanx_surface_update(void *data, const void *frame,
struct dispmanx_surface *surface) struct dispmanx_surface *surface)
{ {
/* Updating is very delicate: we REALLY want to show the just rendered frame ASAP,
* so we dump and issue flip, and then we can wait for free pages, but we don't
* want to wait for free pages at the beggining of the update or we will be
* adding lag! */
struct dispmanx_video *_dispvars = data; struct dispmanx_video *_dispvars = data;
struct dispmanx_page *page = NULL;
settings_t *settings = config_get_ptr();
/* Dispmanx doesn't support more than one pending pageflip. /* Frame blitting */
* It causes lockups. */ vc_dispmanx_resource_write_data(surface->next_page->resource, surface->pixformat,
surface->pitch, (void*)frame, &(surface->bmp_rect));
/* Dispmanx doesn't support more than one pending pageflip. Doing so would overwrite
* the page in the callback function, so we would be always freeing the same page. */
slock_lock(_dispvars->pending_mutex); slock_lock(_dispvars->pending_mutex);
if (_dispvars->pageflip_pending > 0) if (_dispvars->pageflip_pending > 0)
scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex); scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex);
slock_unlock(_dispvars->pending_mutex); slock_unlock(_dispvars->pending_mutex);
page = dispmanx_get_free_page(_dispvars, surface);
/* Frame blitting */
vc_dispmanx_resource_write_data(page->resource, surface->pixformat,
surface->pitch, (void*)frame, &(surface->bmp_rect));
/* Issue a page flip that will be done at the next vsync. */ /* Issue a page flip that will be done at the next vsync. */
_dispvars->update = vc_dispmanx_update_start(0); _dispvars->update = vc_dispmanx_update_start(0);
vc_dispmanx_element_change_source(_dispvars->update, surface->element, vc_dispmanx_element_change_source(_dispvars->update, surface->element,
page->resource); surface->next_page->resource);
vc_dispmanx_update_submit(_dispvars->update, dispmanx_vsync_callback, (void*)page); vc_dispmanx_update_submit(_dispvars->update,
dispmanx_vsync_callback, (void*)(surface->next_page));
slock_lock(_dispvars->pending_mutex); slock_lock(_dispvars->pending_mutex);
_dispvars->pageflip_pending++; _dispvars->pageflip_pending++;
slock_unlock(_dispvars->pending_mutex); slock_unlock(_dispvars->pending_mutex);
/* Get the next page ready for our next surface_update re-entry.
* It's OK to wait now that we've issued the flip to the last produced frame! */
surface->next_page = dispmanx_get_free_page(_dispvars, surface);
} }
/* Enable/disable bilinear filtering. */ /* Enable/disable bilinear filtering. */
@ -376,8 +393,10 @@ static void dispmanx_blank_console (void *data)
1, 1,
-1, -1,
&_dispvars->back_surface); &_dispvars->back_surface);
dispmanx_surface_update(_dispvars, image, _dispvars->back_surface); /* Updating 1-page surface synchronously asks for truble, since the 1st CB will
* signal but not free because the only page is on screen, so get_free will wait forever. */
dispmanx_surface_update_async(_dispvars, image, _dispvars->back_surface);
} }
static void *dispmanx_gfx_init(const video_info_t *video, static void *dispmanx_gfx_init(const video_info_t *video,