mirror of
https://github.com/libretro/RetroArch
synced 2025-04-16 08:43:10 +00:00
Fix max_swapchain_images and do some additional cleanup
When max_swapchain_images was originally added it worked properly, but was subsequently broken by using the value to specify the number of buffers allocated. Due to how the dispmanx driver works, only 2 buffers are ever actually used, so the 3rd buffer in the "swapchain" ended up doing nothing. Fix this by restoring it to the original intent, that is, if max_swapchain_images <= 2 wait for vsync after the flip (reducing lag), otherwise wait at the last possible moment (increasing lag). Additionally, fix up some unnecessary void* usage where type safety could be maintained.
This commit is contained in:
parent
c34b4dd787
commit
01e25bd5c7
@ -129,10 +129,10 @@ struct dispmanx_video
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* If no free page is available when called, wait for a page flip. */
|
/* If no free page is available when called, wait for a page flip. */
|
||||||
static struct dispmanx_page *dispmanx_get_free_page(void *data, struct dispmanx_surface *surface)
|
static struct dispmanx_page *dispmanx_get_free_page(struct dispmanx_video *_dispvars,
|
||||||
|
struct dispmanx_surface *surface)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct dispmanx_video *_dispvars = data;
|
|
||||||
struct dispmanx_page *page = NULL;
|
struct dispmanx_page *page = NULL;
|
||||||
|
|
||||||
while (!page)
|
while (!page)
|
||||||
@ -197,10 +197,10 @@ static void dispmanx_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
|
|||||||
slock_unlock(page->dispvars->pending_mutex);
|
slock_unlock(page->dispvars->pending_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_surface_free(void *data, struct dispmanx_surface **sp)
|
static void dispmanx_surface_free(struct dispmanx_video *_dispvars,
|
||||||
|
struct dispmanx_surface **sp)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct dispmanx_video *_dispvars = data;
|
|
||||||
struct dispmanx_surface *surface = *sp;
|
struct dispmanx_surface *surface = *sp;
|
||||||
|
|
||||||
/* What if we run into the vsync cb code after freeing the surface?
|
/* What if we run into the vsync cb code after freeing the surface?
|
||||||
@ -229,16 +229,16 @@ static void dispmanx_surface_free(void *data, struct dispmanx_surface **sp)
|
|||||||
*sp = NULL;
|
*sp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_surface_setup(void *data, int src_width, int src_height,
|
static void dispmanx_surface_setup(struct dispmanx_video *_dispvars,
|
||||||
|
int src_width, int src_height,
|
||||||
int visible_pitch, int bpp, VC_IMAGE_TYPE_T pixformat,
|
int visible_pitch, int bpp, VC_IMAGE_TYPE_T pixformat,
|
||||||
int alpha, float aspect, int numpages, int layer,
|
int alpha, float aspect, int numpages, int layer,
|
||||||
struct dispmanx_surface **sp)
|
struct dispmanx_surface **sp)
|
||||||
{
|
{
|
||||||
struct dispmanx_video *_dispvars = data;
|
|
||||||
int i, dst_width, dst_height, dst_xpos, dst_ypos, visible_width;
|
int i, dst_width, dst_height, dst_xpos, dst_ypos, visible_width;
|
||||||
struct dispmanx_surface *surface = NULL;
|
struct dispmanx_surface *surface = NULL;
|
||||||
|
|
||||||
*sp = calloc (1, sizeof(struct dispmanx_surface));
|
*sp = calloc(1, sizeof(struct dispmanx_surface));
|
||||||
|
|
||||||
surface = *sp;
|
surface = *sp;
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ static void dispmanx_surface_setup(void *data, int src_width, int src_height,
|
|||||||
/* We receive the pitch for what we consider "useful info",
|
/* We receive the pitch for what we consider "useful info",
|
||||||
* excluding things that are between scanlines.
|
* excluding things that are between scanlines.
|
||||||
* Then we align it to 16 pixels (not bytes) for performance reasons. */
|
* Then we align it to 16 pixels (not bytes) for performance reasons. */
|
||||||
surface->pitch = ALIGN_UP(visible_pitch, (pixformat == VC_IMAGE_XRGB8888 ? 64 : 32));
|
surface->pitch = ALIGN_UP(visible_pitch, (pixformat == VC_IMAGE_XRGB8888 ? 64 : 32));
|
||||||
|
|
||||||
/* Transparency disabled */
|
/* Transparency disabled */
|
||||||
surface->alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
surface->alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
||||||
@ -308,10 +308,8 @@ static void dispmanx_surface_setup(void *data, int src_width, int src_height,
|
|||||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
vc_dispmanx_update_submit_sync(_dispvars->update);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_surface_update_async(void *data, const void *frame,
|
static void dispmanx_surface_update_async(const void *frame, struct dispmanx_surface *surface)
|
||||||
struct dispmanx_surface *surface)
|
|
||||||
{
|
{
|
||||||
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 */
|
||||||
@ -322,26 +320,22 @@ static void dispmanx_surface_update_async(void *data, const void *frame,
|
|||||||
surface->pitch, (void*)frame, &(surface->bmp_rect));
|
surface->pitch, (void*)frame, &(surface->bmp_rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_surface_update(void *data, const void *frame,
|
static void dispmanx_surface_update(struct dispmanx_video *_dispvars, const void *frame,
|
||||||
struct dispmanx_surface *surface)
|
struct dispmanx_surface *surface, video_frame_info_t *video_info)
|
||||||
{
|
{
|
||||||
/* 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;
|
|
||||||
|
|
||||||
/* Frame blitting */
|
/* Frame blitting */
|
||||||
vc_dispmanx_resource_write_data(surface->next_page->resource, surface->pixformat,
|
vc_dispmanx_resource_write_data(surface->next_page->resource, surface->pixformat,
|
||||||
surface->pitch, (void*)frame, &(surface->bmp_rect));
|
surface->pitch, (void*)frame, &(surface->bmp_rect));
|
||||||
|
|
||||||
/* Dispmanx doesn't support more than one pending pageflip. Doing so would overwrite
|
/* Dispmanx doesn't support more than 1 pending frame flip, if we're "triple" buffering,
|
||||||
* the page in the callback function, so we would be always freeing the same page. */
|
* then wait at the last possible moment for any outstanding vsync to finish. */
|
||||||
slock_lock(_dispvars->pending_mutex);
|
if (video_info->max_swapchain_images >= 3)
|
||||||
if (_dispvars->pageflip_pending > 0)
|
{
|
||||||
scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex);
|
slock_lock(_dispvars->pending_mutex);
|
||||||
slock_unlock(_dispvars->pending_mutex);
|
if (_dispvars->pageflip_pending > 0)
|
||||||
|
scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex);
|
||||||
|
slock_unlock(_dispvars->pending_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
/* 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);
|
||||||
@ -356,8 +350,17 @@ static void dispmanx_surface_update(void *data, const void *frame,
|
|||||||
vc_dispmanx_update_submit(_dispvars->update,
|
vc_dispmanx_update_submit(_dispvars->update,
|
||||||
dispmanx_vsync_callback, (void*)(surface->next_page));
|
dispmanx_vsync_callback, (void*)(surface->next_page));
|
||||||
|
|
||||||
/* Get the next page ready for our next surface_update re-entry.
|
/* If we are "double" buffering, wait immediately after the flip for the vsync
|
||||||
* It's OK to wait now that we've issued the flip to the last produced frame! */
|
* before continuing */
|
||||||
|
if (video_info->max_swapchain_images <= 2)
|
||||||
|
{
|
||||||
|
slock_lock(_dispvars->pending_mutex);
|
||||||
|
if (_dispvars->pageflip_pending > 0)
|
||||||
|
scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex);
|
||||||
|
slock_unlock(_dispvars->pending_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point, there will always be a free page available */
|
||||||
surface->next_page = dispmanx_get_free_page(_dispvars, surface);
|
surface->next_page = dispmanx_get_free_page(_dispvars, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,11 +373,10 @@ static void dispmanx_set_scaling (bool bilinear_filter)
|
|||||||
vc_gencmd_send("%s", "scaling_kernel 0 0 0 0 0 0 0 0 1 1 1 1 255 255 255 255 255 255 255 255 1 1 1 1 0 0 0 0 0 0 0 0 1");
|
vc_gencmd_send("%s", "scaling_kernel 0 0 0 0 0 0 0 0 1 1 1 1 255 255 255 255 255 255 255 255 1 1 1 1 0 0 0 0 0 0 0 0 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_blank_console (void *data)
|
static void dispmanx_blank_console (struct dispmanx_video *_dispvars)
|
||||||
{
|
{
|
||||||
/* Since pitch will be aligned to 16 pixels (not bytes) we use a
|
/* Since pitch will be aligned to 16 pixels (not bytes) we use a
|
||||||
* 16 pixels image to save the alignment */
|
* 16 pixels image to save the alignment */
|
||||||
struct dispmanx_video *_dispvars = data;
|
|
||||||
uint16_t image[16] = {0x0000};
|
uint16_t image[16] = {0x0000};
|
||||||
float aspect = (float)_dispvars->dispmanx_width / (float)_dispvars->dispmanx_height;
|
float aspect = (float)_dispvars->dispmanx_width / (float)_dispvars->dispmanx_height;
|
||||||
|
|
||||||
@ -392,7 +394,7 @@ static void dispmanx_blank_console (void *data)
|
|||||||
|
|
||||||
/* Updating 1-page surface synchronously asks for truble, since the 1st CB will
|
/* 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. */
|
* 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);
|
dispmanx_surface_update_async(image, _dispvars->back_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *dispmanx_gfx_init(const video_info_t *video,
|
static void *dispmanx_gfx_init(const video_info_t *video,
|
||||||
@ -481,7 +483,7 @@ static bool dispmanx_gfx_frame(void *data, const void *frame, unsigned width,
|
|||||||
_dispvars->rgb32 ? VC_IMAGE_XRGB8888 : VC_IMAGE_RGB565,
|
_dispvars->rgb32 ? VC_IMAGE_XRGB8888 : VC_IMAGE_RGB565,
|
||||||
255,
|
255,
|
||||||
_dispvars->aspect_ratio,
|
_dispvars->aspect_ratio,
|
||||||
video_info->max_swapchain_images,
|
2,
|
||||||
0,
|
0,
|
||||||
&_dispvars->main_surface);
|
&_dispvars->main_surface);
|
||||||
|
|
||||||
@ -496,7 +498,7 @@ static bool dispmanx_gfx_frame(void *data, const void *frame, unsigned width,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Update main surface: locate free page, blit and flip. */
|
/* Update main surface: locate free page, blit and flip. */
|
||||||
dispmanx_surface_update(_dispvars, frame, _dispvars->main_surface);
|
dispmanx_surface_update(_dispvars, frame, _dispvars->main_surface, video_info);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,7 +545,7 @@ static void dispmanx_set_texture_frame(void *data, const void *frame, bool rgb32
|
|||||||
/* We update the menu surface if menu is active.
|
/* We update the menu surface if menu is active.
|
||||||
* This update is asynchronous, yet menu screen update
|
* This update is asynchronous, yet menu screen update
|
||||||
* will be synced because main surface updating is synchronous */
|
* will be synced because main surface updating is synchronous */
|
||||||
dispmanx_surface_update_async(_dispvars, frame, _dispvars->menu_surface);
|
dispmanx_surface_update_async(frame, _dispvars->menu_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_gfx_set_nonblock_state(void *data, bool state)
|
static void dispmanx_gfx_set_nonblock_state(void *data, bool state)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user