mirror of
https://github.com/libretro/RetroArch
synced 2025-04-09 21:45:45 +00:00
DISPMANX backend: implemented a faster triple buffering method and abstracted drawing surfaces for core and menu in their own class-like struct. Honor the aspect ratio setting changes without re-launching. Cleanups.
This commit is contained in:
parent
d2cd6a33cb
commit
26b0876376
@ -21,11 +21,6 @@
|
|||||||
#include "../video_context_driver.h"
|
#include "../video_context_driver.h"
|
||||||
#include "../font_renderer_driver.h"
|
#include "../font_renderer_driver.h"
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <linux/fb.h>
|
|
||||||
|
|
||||||
#include <bcm_host.h>
|
#include <bcm_host.h>
|
||||||
#include <rthreads/rthreads.h>
|
#include <rthreads/rthreads.h>
|
||||||
|
|
||||||
@ -33,342 +28,354 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NUMPAGES 2
|
/* We have two "drawing surfaces" (abstract), one for running
|
||||||
|
* core and other for menu, each one backed by a dispmanx
|
||||||
|
* element and a set of buffers (resources in dispmanx terms). */
|
||||||
|
enum dispmanx_surface_type {
|
||||||
|
MAIN_SURFACE,
|
||||||
|
MENU_SURFACE,
|
||||||
|
BACK_SURFACE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dispmanx_page
|
||||||
|
{
|
||||||
|
/* Each page contains it's own resource handler
|
||||||
|
* instead of pointing to in by page number */
|
||||||
|
DISPMANX_RESOURCE_HANDLE_T resource;
|
||||||
|
bool used;
|
||||||
|
/* Each page has it's own mutex for
|
||||||
|
* isolating it's used flag access. */
|
||||||
|
slock_t *page_used_mutex;
|
||||||
|
|
||||||
|
/* This field will allow us to access the
|
||||||
|
* main _dispvars struct from the vsync CB function */
|
||||||
|
struct dispmanx_video *dispvars;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dispmanx_surface
|
||||||
|
{
|
||||||
|
/* main surface has 3 pages, menu surface has 1 */
|
||||||
|
unsigned int numpages;
|
||||||
|
struct dispmanx_page *pages;
|
||||||
|
unsigned int bpp;
|
||||||
|
|
||||||
|
VC_RECT_T src_rect;
|
||||||
|
VC_RECT_T dst_rect;
|
||||||
|
VC_RECT_T bmp_rect;
|
||||||
|
|
||||||
|
/* Each surface has it's own element, and the resources are contained one in each page */
|
||||||
|
DISPMANX_ELEMENT_HANDLE_T element;
|
||||||
|
VC_DISPMANX_ALPHA_T alpha;
|
||||||
|
VC_IMAGE_TYPE_T pixformat;
|
||||||
|
|
||||||
|
/* Surfaces with a higher layer will be on top of the ones with lower. Default is 0. */
|
||||||
|
int layer;
|
||||||
|
|
||||||
|
/* Internal frame dimensions */
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int pitch;
|
||||||
|
|
||||||
|
/* External aspect for scaling */
|
||||||
|
float aspect;
|
||||||
|
};
|
||||||
|
|
||||||
struct dispmanx_video
|
struct dispmanx_video
|
||||||
{
|
{
|
||||||
uint64_t frame_count;
|
uint64_t frame_count;
|
||||||
DISPMANX_DISPLAY_HANDLE_T display;
|
DISPMANX_DISPLAY_HANDLE_T display;
|
||||||
DISPMANX_MODEINFO_T amode;
|
|
||||||
DISPMANX_UPDATE_HANDLE_T update;
|
DISPMANX_UPDATE_HANDLE_T update;
|
||||||
DISPMANX_ELEMENT_HANDLE_T element;
|
uint32_t vc_image_ptr;
|
||||||
VC_IMAGE_TYPE_T pixFormat;
|
|
||||||
VC_DISPMANX_ALPHA_T *alpha;
|
struct dispmanx_page *current_page;
|
||||||
VC_RECT_T srcRect;
|
|
||||||
VC_RECT_T dstRect;
|
|
||||||
VC_RECT_T bmpRect;
|
|
||||||
unsigned int vcImagePtr;
|
|
||||||
unsigned int screen;
|
|
||||||
unsigned int pitch;
|
|
||||||
unsigned int flipPage;
|
|
||||||
|
|
||||||
/* Internal frame dimensions */
|
/* We abstract three "surfaces": main surface, menu surface and black back surface. */
|
||||||
unsigned int width;
|
struct dispmanx_surface surfaces[3];
|
||||||
unsigned int height;
|
|
||||||
unsigned int bytes_per_pixel;
|
|
||||||
/* Some cores render things we don't need between scanlines */
|
|
||||||
unsigned int visible_width;
|
|
||||||
|
|
||||||
bool aspectRatioCorrection;
|
|
||||||
void *pixmem;
|
|
||||||
|
|
||||||
struct dispmanx_page *pages;
|
|
||||||
struct dispmanx_page *currentPage;
|
|
||||||
struct dispmanx_page *nextPage;
|
|
||||||
bool pageflip_pending;
|
|
||||||
|
|
||||||
/* For console blanking */
|
/* For console blanking */
|
||||||
int fd;
|
int fb_fd;
|
||||||
char *fbp;
|
uint8_t *fb_addr;
|
||||||
unsigned int screensize;
|
unsigned int screensize;
|
||||||
char *screen_bck;
|
uint8_t *screen_bck;
|
||||||
|
|
||||||
|
/* Total dispmanx video dimensions. Not counting overscan settings. */
|
||||||
|
unsigned int dispmanx_width;
|
||||||
|
unsigned int dispmanx_height;
|
||||||
|
|
||||||
/* For threading */
|
/* For threading */
|
||||||
scond_t *vsync_condition;
|
scond_t *vsync_condition;
|
||||||
|
slock_t *vsync_cond_mutex;
|
||||||
slock_t *pending_mutex;
|
slock_t *pending_mutex;
|
||||||
|
unsigned int pageflip_pending;
|
||||||
|
|
||||||
/* Menu */
|
/* Menu */
|
||||||
bool menu_active;
|
bool menu_active;
|
||||||
DISPMANX_ELEMENT_HANDLE_T menu_element;
|
|
||||||
DISPMANX_RESOURCE_HANDLE_T menu_resource;
|
|
||||||
VC_IMAGE_TYPE_T menu_pixFormat;
|
|
||||||
VC_DISPMANX_ALPHA_T *menu_alpha;
|
|
||||||
VC_RECT_T menu_srcRect;
|
|
||||||
VC_RECT_T menu_dstRect;
|
|
||||||
VC_RECT_T menu_bmpRect;
|
|
||||||
unsigned int menu_width;
|
|
||||||
unsigned int menu_height;
|
|
||||||
unsigned int menu_pitch;
|
|
||||||
unsigned int menu_flip_page;
|
|
||||||
|
|
||||||
/* External aspect ratio */
|
unsigned int numsurfaces;
|
||||||
float aspect;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dispmanx_page
|
/* 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) {
|
||||||
DISPMANX_RESOURCE_HANDLE_T resource;
|
unsigned i;
|
||||||
};
|
|
||||||
|
|
||||||
static void dispmanx_blank_console(void *data)
|
|
||||||
{
|
|
||||||
struct fb_var_screeninfo vinfo;
|
|
||||||
unsigned int fb_bytes_per_pixel;
|
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
struct dispmanx_page *page = NULL;
|
||||||
|
|
||||||
if (!_dispvars)
|
while (!page)
|
||||||
return;
|
{
|
||||||
|
/* Try to find a free page */
|
||||||
|
for (i = 0; i < surface->numpages; ++i) {
|
||||||
|
if (!surface->pages[i].used)
|
||||||
|
{
|
||||||
|
page = (surface->pages) + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_dispvars->fd = open("/dev/fb0", O_RDWR);
|
/* If no page is free at the moment,
|
||||||
|
* wait until a free page is freed by vsync CB. */
|
||||||
|
if (!page) {
|
||||||
|
slock_lock(_dispvars->vsync_cond_mutex);
|
||||||
|
scond_wait(_dispvars->vsync_condition, _dispvars->vsync_cond_mutex);
|
||||||
|
slock_unlock(_dispvars->vsync_cond_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We mark the choosen page as used */
|
||||||
|
slock_lock(page->page_used_mutex);
|
||||||
|
page->used = true;
|
||||||
|
slock_unlock(page->page_used_mutex);
|
||||||
|
|
||||||
/* We need this just to know the framebuffer
|
return page;
|
||||||
* color depth, which vc_get_display_info() doesn't provide. */
|
|
||||||
ioctl(_dispvars->fd, FBIOGET_VSCREENINFO, &vinfo);
|
|
||||||
fb_bytes_per_pixel = vinfo.bits_per_pixel / 8;
|
|
||||||
|
|
||||||
_dispvars->screensize = _dispvars->amode.width * _dispvars->amode.height * fb_bytes_per_pixel;
|
|
||||||
_dispvars->fbp = (char *)mmap(0, _dispvars->screensize, PROT_READ | PROT_WRITE, MAP_SHARED, _dispvars->fd, 0);
|
|
||||||
|
|
||||||
/* Disable cursor blinking */
|
|
||||||
system("setterm -cursor off");
|
|
||||||
|
|
||||||
/* Backup console screen contents */
|
|
||||||
_dispvars->screen_bck = (char*)malloc(_dispvars->screensize * sizeof(char));
|
|
||||||
|
|
||||||
if (!_dispvars->screen_bck)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
memcpy((char*)_dispvars->screen_bck, (char*)_dispvars->fbp, _dispvars->screensize);
|
|
||||||
|
|
||||||
/* Blank console */
|
|
||||||
memset((char*)(_dispvars->fbp), 0x00, _dispvars->screensize);
|
|
||||||
|
|
||||||
end:
|
|
||||||
/* Unmap and close */
|
|
||||||
munmap(&_dispvars->fd, _dispvars->screensize);
|
|
||||||
close (_dispvars->fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dispmanx_restore_console(void *data)
|
|
||||||
{
|
|
||||||
struct dispmanx_video *_dispvars = data;
|
|
||||||
|
|
||||||
if (!_dispvars)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_dispvars->fd = open("/dev/fb0", O_RDWR);
|
|
||||||
_dispvars->fbp = (char *)mmap(0, _dispvars->screensize, PROT_READ | PROT_WRITE, MAP_SHARED, _dispvars->fd, 0);
|
|
||||||
|
|
||||||
/* Restore console screen contents. */
|
|
||||||
memcpy((char*)_dispvars->fbp, (char*)_dispvars->screen_bck, _dispvars->screensize);
|
|
||||||
free(_dispvars->screen_bck);
|
|
||||||
|
|
||||||
/* Unmap and close. */
|
|
||||||
munmap(&_dispvars->fd, _dispvars->screensize);
|
|
||||||
close (_dispvars->fd);
|
|
||||||
|
|
||||||
/* Restore cursor blinking. */
|
|
||||||
system("setterm -cursor on");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
|
static void dispmanx_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
|
||||||
{
|
{
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_page *page = data;
|
||||||
|
|
||||||
/* Changing the page to write must be done before the signaling
|
/* Marking the page as free must be done before the signaling
|
||||||
* so we have the right page in nextPage when update_main continues */
|
* so when update_main continues (it won't continue until we signal)
|
||||||
|
* we can chose this page as free */
|
||||||
|
if (page->dispvars->current_page) {
|
||||||
|
slock_lock(page->dispvars->current_page->page_used_mutex);
|
||||||
|
|
||||||
if (_dispvars->nextPage == &_dispvars->pages[0])
|
/* We mark as free the page that was visible until now */
|
||||||
_dispvars->nextPage = &_dispvars->pages[1];
|
page->dispvars->current_page->used = false;
|
||||||
else
|
|
||||||
_dispvars->nextPage = &_dispvars->pages[0];
|
slock_unlock(page->dispvars->current_page->page_used_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The page on which we issued the flip that
|
||||||
|
* caused this callback becomes the visible one */
|
||||||
|
page->dispvars->current_page = page;
|
||||||
|
|
||||||
/* These two things must be isolated "atomically" to avoid getting
|
/* These two things must be isolated "atomically" to avoid getting
|
||||||
* a false positive in the pending_mutex test in update_main. */
|
* a false positive in the pending_mutex test in update_main. */
|
||||||
slock_lock(_dispvars->pending_mutex);
|
slock_lock(page->dispvars->pending_mutex);
|
||||||
|
|
||||||
_dispvars->pageflip_pending = false;
|
page->dispvars->pageflip_pending--;
|
||||||
scond_signal(_dispvars->vsync_condition);
|
scond_signal(page->dispvars->vsync_condition);
|
||||||
|
|
||||||
slock_unlock(_dispvars->pending_mutex);
|
slock_unlock(page->dispvars->pending_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_free_main_resources(void *data)
|
static void dispmanx_surface_free_resources(void *data, struct dispmanx_surface *surface)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
|
||||||
if (!_dispvars)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_dispvars->update = vc_dispmanx_update_start(0);
|
_dispvars->update = vc_dispmanx_update_start(0);
|
||||||
|
|
||||||
for (i = 0; i < NUMPAGES; i++)
|
for (i = 0; i < surface->numpages; i++) {
|
||||||
vc_dispmanx_resource_delete(_dispvars->pages[i].resource);
|
if (surface->pages[i].resource != 0){
|
||||||
|
vc_dispmanx_resource_delete(surface->pages[i].resource);
|
||||||
vc_dispmanx_element_remove(_dispvars->update, _dispvars->element);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vc_dispmanx_element_remove(_dispvars->update, surface->element);
|
||||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
vc_dispmanx_update_submit_sync(_dispvars->update);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool dispmanx_setup_scale(void *data, unsigned width,
|
static bool dispmanx_surface_setup(void *data, int width, int height, int pitch, float aspect,
|
||||||
unsigned height, unsigned pitch)
|
struct dispmanx_surface *surface)
|
||||||
{
|
{
|
||||||
int i, dst_ypos;
|
|
||||||
VC_DISPMANX_ALPHA_T layerAlpha;
|
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
settings_t *settings = config_get_ptr();
|
int i, dst_width, dst_height, dst_xpos, dst_ypos;
|
||||||
|
|
||||||
if (!_dispvars)
|
/* Internal frame dimensions. Pitch is total pitch including info
|
||||||
return false;
|
* between scanlines */
|
||||||
|
surface->width = width;
|
||||||
/* Since internal frame resolution seems to have changed, we change the
|
surface->height = height;
|
||||||
* internal frame resolution in use, and call dispmanx_setup_scale()
|
surface->pitch = pitch;
|
||||||
* again to set the rects, etc. */
|
surface->aspect = aspect;
|
||||||
_dispvars->width = width;
|
|
||||||
_dispvars->height = height;
|
/* The "visible" width obtained from the core pitch. We blit based on
|
||||||
|
* the "visible" width, for cores with things between scanlines. */
|
||||||
/* Total pitch, including things the cores
|
int visible_width = pitch / surface->bpp;
|
||||||
* render between "visible" scanlines. */
|
|
||||||
_dispvars->pitch = pitch;
|
dst_width = _dispvars->dispmanx_height * aspect;
|
||||||
|
dst_height = _dispvars->dispmanx_height;
|
||||||
/* The "visible" width obtained from the core pitch. */
|
|
||||||
_dispvars->visible_width = pitch / _dispvars->bytes_per_pixel;
|
|
||||||
|
|
||||||
dispmanx_free_main_resources(_dispvars);
|
|
||||||
vc_dispmanx_display_get_info(_dispvars->display, &(_dispvars->amode));
|
|
||||||
|
|
||||||
/* We choose the pixel format depending on the bpp of the frame. */
|
|
||||||
switch (_dispvars->bytes_per_pixel)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
_dispvars->pixFormat = VC_IMAGE_RGB565;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
_dispvars->pixFormat = VC_IMAGE_XRGB8888;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
RARCH_ERR("video_dispmanx: wrong pixel format\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Transparency disabled */
|
|
||||||
layerAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
|
||||||
layerAlpha.opacity = 255;
|
|
||||||
layerAlpha.mask = 0;
|
|
||||||
_dispvars->alpha = &layerAlpha;
|
|
||||||
|
|
||||||
switch (settings->video.aspect_ratio_idx)
|
|
||||||
{
|
|
||||||
case ASPECT_RATIO_4_3:
|
|
||||||
_dispvars->aspect = (float)4 / (float)3;
|
|
||||||
break;
|
|
||||||
case ASPECT_RATIO_16_9:
|
|
||||||
_dispvars->aspect = (float)16 / (float)9;
|
|
||||||
break;
|
|
||||||
case ASPECT_RATIO_16_10:
|
|
||||||
_dispvars->aspect = (float)16 / (float)10;
|
|
||||||
break;
|
|
||||||
case ASPECT_RATIO_16_15:
|
|
||||||
_dispvars->aspect = (float)16 / (float)15;
|
|
||||||
break;
|
|
||||||
case ASPECT_RATIO_CORE:
|
|
||||||
_dispvars->aspect = (float)_dispvars->width / (float)_dispvars->height;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_dispvars->aspect = (float)_dispvars->width / (float)_dispvars->height;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dst_width = _dispvars->amode.height * _dispvars->aspect;
|
|
||||||
|
|
||||||
/* If we obtain a scaled image width that is bigger than the physical screen width,
|
/* If we obtain a scaled image width that is bigger than the physical screen width,
|
||||||
* then we keep the physical screen width as our maximun width. */
|
* then we keep the physical screen width as our maximun width. */
|
||||||
#if 0
|
if (dst_width > _dispvars->dispmanx_width)
|
||||||
if (dst_width > _dispvars->amode.width)
|
dst_width = _dispvars->dispmanx_width;
|
||||||
dst_width = _dispvars->amode.width;
|
|
||||||
#endif
|
dst_xpos = (_dispvars->dispmanx_width - dst_width) / 2;
|
||||||
dst_ypos = (_dispvars->amode.width - dst_width) / 2;
|
dst_ypos = (_dispvars->dispmanx_height - dst_height) / 2;
|
||||||
|
|
||||||
vc_dispmanx_rect_set(&(_dispvars->dstRect), dst_ypos, 0,
|
|
||||||
dst_width, _dispvars->amode.height);
|
|
||||||
|
|
||||||
/* We configure the rects now. */
|
/* We configure the rects now. */
|
||||||
vc_dispmanx_rect_set(&(_dispvars->bmpRect), 0, 0, _dispvars->width, _dispvars->height);
|
vc_dispmanx_rect_set(&surface->dst_rect, dst_xpos, dst_ypos, dst_width, dst_height);
|
||||||
vc_dispmanx_rect_set(&(_dispvars->srcRect), 0, 0, _dispvars->width << 16, _dispvars->height << 16);
|
vc_dispmanx_rect_set(&surface->bmp_rect, 0, 0, width, height);
|
||||||
|
vc_dispmanx_rect_set(&surface->src_rect, 0, 0, width << 16, height << 16);
|
||||||
/* We create as many resources as pages */
|
|
||||||
for (i = 0; i < NUMPAGES; i++)
|
|
||||||
_dispvars->pages[i].resource = vc_dispmanx_resource_create(_dispvars->pixFormat,
|
|
||||||
_dispvars->visible_width, _dispvars->height, &(_dispvars->vcImagePtr));
|
|
||||||
|
|
||||||
|
for (i = 0; i < surface->numpages; i++) {
|
||||||
|
surface->pages[i].resource =
|
||||||
|
vc_dispmanx_resource_create(surface->pixformat,
|
||||||
|
visible_width, height, &(_dispvars->vc_image_ptr));
|
||||||
|
}
|
||||||
/* Add element. */
|
/* Add element. */
|
||||||
_dispvars->update = vc_dispmanx_update_start(0);
|
_dispvars->update = vc_dispmanx_update_start(0);
|
||||||
|
|
||||||
_dispvars->element = vc_dispmanx_element_add(_dispvars->update, _dispvars->display, 0,
|
surface->element = vc_dispmanx_element_add(
|
||||||
&(_dispvars->dstRect), _dispvars->pages[0].resource, &(_dispvars->srcRect),
|
_dispvars->update,_dispvars->display, surface->layer,
|
||||||
DISPMANX_PROTECTION_NONE, _dispvars->alpha, 0, (DISPMANX_TRANSFORM_T)0);
|
&surface->dst_rect, surface->pages[0].resource,
|
||||||
|
&surface->src_rect, DISPMANX_PROTECTION_NONE,
|
||||||
|
&surface->alpha, 0, (DISPMANX_TRANSFORM_T)0);
|
||||||
|
|
||||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
vc_dispmanx_update_submit_sync(_dispvars->update);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_update_main(void *data, const void *frame)
|
static void dispmanx_surface_init(void *data,
|
||||||
|
int bpp,
|
||||||
|
int pixformat,
|
||||||
|
int layer,
|
||||||
|
unsigned alpha,
|
||||||
|
int numpages,
|
||||||
|
struct dispmanx_surface *surface)
|
||||||
{
|
{
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Setup surface parameters */
|
||||||
|
surface->numpages = numpages;
|
||||||
|
surface->bpp = bpp;
|
||||||
|
surface->layer = layer;
|
||||||
|
surface->pixformat = pixformat;
|
||||||
|
|
||||||
/* Wait until last issued flip completes to get the free page
|
/* Internal frame dimensions. We leave them as 0 until we get
|
||||||
* that the vsync cb will put in nextPage. Also, dispmanx doesn't
|
* to the gfx_frame function where we get image width and height. */
|
||||||
* support issuing more than one pageflip.*/
|
surface->width = 0;
|
||||||
|
surface->height = 0;
|
||||||
|
surface->pitch = 0;
|
||||||
|
|
||||||
|
/* Transparency disabled */
|
||||||
|
surface->alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
||||||
|
surface->alpha.opacity = alpha;
|
||||||
|
surface->alpha.mask = 0;
|
||||||
|
|
||||||
|
/* Allocate memory for all the pages in each surface
|
||||||
|
* and initialize variables inside each page's struct. */
|
||||||
|
surface->pages = calloc(surface->numpages, sizeof(struct dispmanx_surface));
|
||||||
|
for (i = 0; i < surface->numpages; i++) {
|
||||||
|
surface->pages[i].used = false;
|
||||||
|
surface->pages[i].dispvars = _dispvars;
|
||||||
|
surface->pages[i].page_used_mutex = slock_new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dispmanx_surface_update(void *data, const void *frame, struct dispmanx_surface *surface)
|
||||||
|
{
|
||||||
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
struct dispmanx_page *page = NULL;
|
||||||
|
|
||||||
|
/* Wait until last issued flip completes to get a free page. Also,
|
||||||
|
dispmanx doesn't support issuing more than one pageflip.*/
|
||||||
slock_lock(_dispvars->pending_mutex);
|
slock_lock(_dispvars->pending_mutex);
|
||||||
if (_dispvars->pageflip_pending)
|
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 */
|
/* Frame blitting */
|
||||||
vc_dispmanx_resource_write_data(_dispvars->nextPage->resource, _dispvars->pixFormat,
|
vc_dispmanx_resource_write_data(page->resource, surface->pixformat,
|
||||||
_dispvars->pitch, (void *)frame, &(_dispvars->bmpRect));
|
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, _dispvars->element,
|
vc_dispmanx_element_change_source(_dispvars->update, surface->element,
|
||||||
_dispvars->nextPage->resource);
|
page->resource);
|
||||||
|
|
||||||
vc_dispmanx_update_submit(_dispvars->update, dispmanx_vsync_callback, (void*)_dispvars);
|
vc_dispmanx_update_submit(_dispvars->update, dispmanx_vsync_callback, (void*)page);
|
||||||
|
|
||||||
slock_lock(_dispvars->pending_mutex);
|
slock_lock(_dispvars->pending_mutex);
|
||||||
_dispvars->pageflip_pending = true;
|
_dispvars->pageflip_pending++;
|
||||||
slock_unlock(_dispvars->pending_mutex);
|
slock_unlock(_dispvars->pending_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dispmanx_blank_console (void *data)
|
||||||
|
{
|
||||||
|
/* Note that a 2-pixels array is needed to accomplish console blanking because with 1-pixel
|
||||||
|
* only the write data function doesn't work well, so when we do the only resource
|
||||||
|
* change in the surface update function, we will be seeing a distorted console. */
|
||||||
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
uint16_t image[2] = {0x0000, 0x0000};
|
||||||
|
float aspect = (float)_dispvars->dispmanx_width / (float)_dispvars->dispmanx_height;
|
||||||
|
|
||||||
|
dispmanx_surface_init(_dispvars,
|
||||||
|
1,
|
||||||
|
VC_IMAGE_RGB565,
|
||||||
|
-1,
|
||||||
|
255,
|
||||||
|
1,
|
||||||
|
&_dispvars->surfaces[BACK_SURFACE]);
|
||||||
|
dispmanx_surface_setup(_dispvars, 2, 2, 4, aspect, &_dispvars->surfaces[BACK_SURFACE]);
|
||||||
|
dispmanx_surface_update(_dispvars, &image, &_dispvars->surfaces[BACK_SURFACE]);
|
||||||
|
}
|
||||||
|
|
||||||
static void *dispmanx_gfx_init(const video_info_t *video,
|
static void *dispmanx_gfx_init(const video_info_t *video,
|
||||||
const input_driver_t **input, void **input_data)
|
const input_driver_t **input, void **input_data)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct dispmanx_video *_dispvars = calloc(1, sizeof(struct dispmanx_video));
|
struct dispmanx_video *_dispvars = calloc(1, sizeof(struct dispmanx_video));
|
||||||
|
|
||||||
if (!_dispvars)
|
bcm_host_init();
|
||||||
return NULL;
|
_dispvars->display = vc_dispmanx_display_open(0 /* LCD */);
|
||||||
|
/* If the console framebuffer has active overscan settings,
|
||||||
|
* the user must have overscan_scale=1 in config.txt to have
|
||||||
|
* the same size for both fb console and dispmanx. */
|
||||||
|
graphics_get_display_size(_dispvars->display, &_dispvars->dispmanx_width, &_dispvars->dispmanx_height);
|
||||||
|
|
||||||
_dispvars->bytes_per_pixel = video->rgb32 ? 4 : 2;
|
/* Setup surface parameters */
|
||||||
_dispvars->screen = 0;
|
_dispvars->numsurfaces = 3;
|
||||||
_dispvars->vcImagePtr = 0;
|
|
||||||
_dispvars->pageflip_pending = false;
|
_dispvars->vc_image_ptr = 0;
|
||||||
_dispvars->currentPage = NULL;
|
_dispvars->pageflip_pending = 0;
|
||||||
_dispvars->pages = calloc(NUMPAGES, sizeof(struct dispmanx_page));
|
_dispvars->current_page = NULL;
|
||||||
_dispvars->menu_active = false;
|
_dispvars->menu_active = false;
|
||||||
_dispvars->nextPage = &_dispvars->pages[0];
|
|
||||||
|
|
||||||
if (!_dispvars->pages)
|
|
||||||
{
|
|
||||||
free(_dispvars);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the rest of the mutexes and conditions. */
|
/* Initialize the rest of the mutexes and conditions. */
|
||||||
_dispvars->vsync_condition = scond_new();
|
_dispvars->vsync_condition = scond_new();
|
||||||
|
_dispvars->vsync_cond_mutex = slock_new();
|
||||||
_dispvars->pending_mutex = slock_new();
|
_dispvars->pending_mutex = slock_new();
|
||||||
|
|
||||||
bcm_host_init();
|
dispmanx_surface_init(_dispvars,
|
||||||
|
video->rgb32 ? 4 : 2,
|
||||||
_dispvars->display = vc_dispmanx_display_open(_dispvars->screen);
|
video->rgb32 ? VC_IMAGE_XRGB8888 : VC_IMAGE_RGB565,
|
||||||
|
0 /* layer */,
|
||||||
|
255 /* alpha */,
|
||||||
|
3, /* numpages */
|
||||||
|
&_dispvars->surfaces[MAIN_SURFACE]);
|
||||||
|
|
||||||
if (input && input_data)
|
if (input && input_data)
|
||||||
*input = NULL;
|
*input = NULL;
|
||||||
|
|
||||||
|
dispmanx_blank_console(_dispvars);
|
||||||
|
|
||||||
return _dispvars;
|
return _dispvars;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,142 +384,72 @@ static bool dispmanx_gfx_frame(void *data, const void *frame, unsigned width,
|
|||||||
{
|
{
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
|
||||||
/* Check if neither menu nor core framebuffer is to be displayed. */
|
if (width != _dispvars->surfaces[MAIN_SURFACE].width || height != _dispvars->surfaces[MAIN_SURFACE].height)
|
||||||
if (!_dispvars->menu_active && !frame)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (width != _dispvars->width || height != _dispvars->height)
|
|
||||||
{
|
{
|
||||||
/* Sanity check. */
|
/* Sanity check. */
|
||||||
if (width == 0 || height == 0)
|
if (width == 0 || height == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
RARCH_LOG("video_dispmanx: internal frame resolution changed by core\n");
|
dispmanx_surface_free_resources(_dispvars, &_dispvars->surfaces[MAIN_SURFACE]);
|
||||||
|
float aspect = video_driver_get_aspect_ratio();
|
||||||
if (!dispmanx_setup_scale(_dispvars, width, height, pitch))
|
/* Reconfiguring internal dimensions of the main surface is needed. */
|
||||||
{
|
dispmanx_surface_setup(_dispvars, width, height, pitch, aspect, &_dispvars->surfaces[MAIN_SURFACE]);
|
||||||
RARCH_ERR("video_dispmanx: frame resolution set failed\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispmanx_blank_console (_dispvars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dispvars->menu_active)
|
if (_dispvars->menu_active)
|
||||||
{
|
{
|
||||||
char buf[128] = {0};
|
char buf[128];
|
||||||
video_monitor_get_fps(buf, sizeof(buf), NULL, 0);
|
video_monitor_get_fps(buf, sizeof(buf), NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update main game screen: locate free page, blit and flip. */
|
/* Update main surface: locate free page, blit and flip. */
|
||||||
dispmanx_update_main(_dispvars, frame);
|
dispmanx_surface_update(_dispvars, frame, &_dispvars->surfaces[MAIN_SURFACE]);
|
||||||
|
|
||||||
_dispvars->frame_count++;
|
_dispvars->frame_count++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_free_menu_resources (void *data)
|
|
||||||
{
|
|
||||||
struct dispmanx_video *_dispvars = data;
|
|
||||||
|
|
||||||
if (!_dispvars)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_dispvars->update = vc_dispmanx_update_start(0);
|
|
||||||
|
|
||||||
vc_dispmanx_resource_delete(_dispvars->menu_resource);
|
|
||||||
vc_dispmanx_element_remove(_dispvars->update, _dispvars->menu_element);
|
|
||||||
|
|
||||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
|
||||||
|
|
||||||
_dispvars->menu_width = 0;
|
|
||||||
_dispvars->menu_height = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dispmanx_set_texture_enable(void *data, bool state, bool full_screen)
|
static void dispmanx_set_texture_enable(void *data, bool state, bool full_screen)
|
||||||
{
|
{
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
|
||||||
if (_dispvars)
|
/* If it was active but it's not anymore... */
|
||||||
_dispvars->menu_active = state;
|
if (!state && _dispvars->menu_active) {
|
||||||
if (!_dispvars->menu_active)
|
dispmanx_surface_free_resources(_dispvars, &_dispvars->surfaces[MENU_SURFACE]);
|
||||||
dispmanx_free_menu_resources(_dispvars);
|
/* This is needed so we enter thru surface_setup on
|
||||||
|
* set_texture_frame() next time menu is active. */
|
||||||
|
_dispvars->surfaces[MENU_SURFACE].width = 0;
|
||||||
|
_dispvars->surfaces[MENU_SURFACE].height = 0;
|
||||||
|
}
|
||||||
|
_dispvars->menu_active = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_set_texture_frame(void *data, const void *frame, bool rgb32,
|
static void dispmanx_set_texture_frame(void *data, const void *frame, bool rgb32,
|
||||||
unsigned width, unsigned height, float alpha)
|
unsigned width, unsigned height, float alpha)
|
||||||
{
|
{
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
|
||||||
if (!_dispvars)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* If we're entering the menu in this frame,
|
/* If we're entering the menu in this frame,
|
||||||
* we must setup rects, resources and menu element. */
|
* we must setup rects, resources and menu element. */
|
||||||
if (width != _dispvars->menu_width || height != _dispvars->menu_height)
|
if (width != _dispvars->surfaces[MENU_SURFACE].width || height != _dispvars->surfaces[MENU_SURFACE].height)
|
||||||
{
|
{
|
||||||
int i, dst_width, dst_ypos;
|
|
||||||
VC_DISPMANX_ALPHA_T layerAlpha;
|
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if (width == 0 || height == 0)
|
if (width == 0 || height == 0)
|
||||||
return;
|
return;
|
||||||
|
int pitch = width * (rgb32 ? 4 : 2);
|
||||||
|
|
||||||
|
dispmanx_surface_init(_dispvars,
|
||||||
|
rgb32 ? 4 : 2,
|
||||||
|
VC_IMAGE_RGBA16,
|
||||||
|
0 /* layer */,
|
||||||
|
210 /* alpha, hardcoded */,
|
||||||
|
3, /* numpages */
|
||||||
|
&_dispvars->surfaces[MENU_SURFACE]);
|
||||||
|
|
||||||
_dispvars->menu_width = width;
|
dispmanx_surface_setup(_dispvars, width, height, pitch,
|
||||||
_dispvars->menu_height = height;
|
_dispvars->surfaces[MAIN_SURFACE].aspect,
|
||||||
|
&_dispvars->surfaces[MENU_SURFACE]);
|
||||||
_dispvars->menu_pitch = width * (rgb32 ? 4 : 2);
|
|
||||||
|
|
||||||
_dispvars->menu_pixFormat = VC_IMAGE_RGBA16;
|
|
||||||
_dispvars->menu_flip_page = 0;
|
|
||||||
|
|
||||||
/* Menu transparency has a fixed value for now. */
|
|
||||||
layerAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
|
||||||
#if 0
|
|
||||||
layerAlpha.opacity = (unsigned char)(255.0f * alpha);
|
|
||||||
#endif
|
|
||||||
layerAlpha.opacity = 210;
|
|
||||||
layerAlpha.mask = 0;
|
|
||||||
_dispvars->menu_alpha = &layerAlpha;
|
|
||||||
|
|
||||||
dst_width = _dispvars->amode.height * _dispvars->aspect;
|
|
||||||
|
|
||||||
/* If we obtain a scaled image width that is
|
|
||||||
* bigger than the physical screen width,
|
|
||||||
* then we keep the physical screen width as our maximun width. */
|
|
||||||
#if 0
|
|
||||||
if (dst_width > _dispvars->amode.width)
|
|
||||||
dst_width = _dispvars->amode.width;
|
|
||||||
#endif
|
|
||||||
dst_ypos = (_dispvars->amode.width - dst_width) / 2;
|
|
||||||
vc_dispmanx_rect_set(&(_dispvars->menu_dstRect), dst_ypos, 0,
|
|
||||||
dst_width, _dispvars->amode.height);
|
|
||||||
|
|
||||||
/* We configure the rects now. */
|
|
||||||
vc_dispmanx_rect_set(&(_dispvars->menu_bmpRect), 0, 0, _dispvars->menu_width, _dispvars->menu_height);
|
|
||||||
vc_dispmanx_rect_set(&(_dispvars->menu_srcRect), 0, 0, _dispvars->menu_width << 16, _dispvars->menu_height << 16);
|
|
||||||
|
|
||||||
/* Create resource for the menu element. */
|
|
||||||
_dispvars->menu_resource = vc_dispmanx_resource_create(_dispvars->menu_pixFormat,
|
|
||||||
_dispvars->menu_width, _dispvars->menu_height, &(_dispvars->vcImagePtr));
|
|
||||||
|
|
||||||
/* Add the menu element. */
|
|
||||||
_dispvars->update = vc_dispmanx_update_start(0);
|
|
||||||
|
|
||||||
_dispvars->menu_element = vc_dispmanx_element_add(_dispvars->update, _dispvars->display, 0,
|
|
||||||
&(_dispvars->menu_dstRect), _dispvars->menu_resource, &(_dispvars->menu_srcRect),
|
|
||||||
DISPMANX_PROTECTION_NONE, _dispvars->menu_alpha, 0, (DISPMANX_TRANSFORM_T)0);
|
|
||||||
|
|
||||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
|
||||||
}
|
}
|
||||||
|
dispmanx_surface_update(_dispvars, frame, &_dispvars->surfaces[MENU_SURFACE]);
|
||||||
/* Frame blitting. */
|
|
||||||
vc_dispmanx_resource_write_data(_dispvars->menu_resource,
|
|
||||||
_dispvars->menu_pixFormat, _dispvars->menu_pitch, (void *)frame, &(_dispvars->menu_bmpRect));
|
|
||||||
|
|
||||||
/* We don't need to flip buffers: one is enough for menu. We sync in gfx_frame, on the
|
|
||||||
* dispmanx_update_main() call, that is called with menu active, too. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_gfx_set_nonblock_state(void *data, bool state)
|
static void dispmanx_gfx_set_nonblock_state(void *data, bool state)
|
||||||
@ -546,8 +483,8 @@ static void dispmanx_gfx_viewport_info(void *data, struct video_viewport *vp)
|
|||||||
|
|
||||||
vp->x = vp->y = 0;
|
vp->x = vp->y = 0;
|
||||||
|
|
||||||
vp->width = vp->full_width = vid->width;
|
vp->width = vp->full_width = vid->surfaces[MAIN_SURFACE].width;
|
||||||
vp->height = vp->full_height = vid->height;
|
vp->height = vp->full_height = vid->surfaces[MAIN_SURFACE].height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool dispmanx_gfx_suppress_screensaver(void *data, bool enable)
|
static bool dispmanx_gfx_suppress_screensaver(void *data, bool enable)
|
||||||
@ -592,11 +529,26 @@ static bool dispmanx_gfx_read_viewport(void *data, uint8_t *buffer)
|
|||||||
static uint64_t dispmanx_gfx_get_frame_count(void *data)
|
static uint64_t dispmanx_gfx_get_frame_count(void *data)
|
||||||
{
|
{
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
if (!_dispvars)
|
|
||||||
return 0;
|
|
||||||
return _dispvars->frame_count;
|
return _dispvars->frame_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dispmanx_set_aspect_ratio (void *data, unsigned aspect_ratio_idx)
|
||||||
|
{
|
||||||
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
struct dispmanx_surface *surface;
|
||||||
|
/* Here we obtain the new aspect ratio. */
|
||||||
|
|
||||||
|
float aspect = aspectratio_lut[aspect_ratio_idx].value;
|
||||||
|
|
||||||
|
surface = &_dispvars->surfaces[MAIN_SURFACE];
|
||||||
|
dispmanx_surface_free_resources(_dispvars, surface);
|
||||||
|
dispmanx_surface_setup(_dispvars, surface->width, surface->height, surface->pitch, aspect, surface);
|
||||||
|
|
||||||
|
surface = &_dispvars->surfaces[MENU_SURFACE];
|
||||||
|
dispmanx_surface_free_resources(_dispvars, surface);
|
||||||
|
dispmanx_surface_setup(_dispvars, surface->width, surface->height, surface->pitch, aspect, surface);
|
||||||
|
}
|
||||||
|
|
||||||
static const video_poke_interface_t dispmanx_poke_interface = {
|
static const video_poke_interface_t dispmanx_poke_interface = {
|
||||||
dispmanx_gfx_get_frame_count,
|
dispmanx_gfx_get_frame_count,
|
||||||
NULL, /* set_video_mode */
|
NULL, /* set_video_mode */
|
||||||
@ -606,7 +558,7 @@ static const video_poke_interface_t dispmanx_poke_interface = {
|
|||||||
NULL, /* get_video_output_next */
|
NULL, /* get_video_output_next */
|
||||||
NULL, /* get_current_framebuffer */
|
NULL, /* get_current_framebuffer */
|
||||||
NULL, /* get_proc_address */
|
NULL, /* get_proc_address */
|
||||||
NULL, /* dispmanx_set_aspect_ratio */
|
dispmanx_set_aspect_ratio,
|
||||||
NULL, /* dispmanx_apply_state_changes */
|
NULL, /* dispmanx_apply_state_changes */
|
||||||
#ifdef HAVE_MENU
|
#ifdef HAVE_MENU
|
||||||
dispmanx_set_texture_frame,
|
dispmanx_set_texture_frame,
|
||||||
@ -623,19 +575,27 @@ static void dispmanx_gfx_get_poke_interface(void *data,
|
|||||||
*iface = &dispmanx_poke_interface;
|
*iface = &dispmanx_poke_interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispmanx_gfx_free(void *data)
|
static void dispmanx_surface_free_pages (struct dispmanx_surface *surface)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
for (i = 0; i < surface->numpages; i++) {
|
||||||
|
surface->pages[i].used = false;
|
||||||
|
slock_free(surface->pages[i].page_used_mutex);
|
||||||
|
}
|
||||||
|
free(surface->pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dispmanx_gfx_free(void *data)
|
||||||
|
{
|
||||||
struct dispmanx_video *_dispvars = data;
|
struct dispmanx_video *_dispvars = data;
|
||||||
|
|
||||||
if (!_dispvars)
|
dispmanx_surface_free_resources(_dispvars, &_dispvars->surfaces[MENU_SURFACE]);
|
||||||
return;
|
dispmanx_surface_free_resources(_dispvars, &_dispvars->surfaces[MAIN_SURFACE]);
|
||||||
|
dispmanx_surface_free_resources(_dispvars, &_dispvars->surfaces[BACK_SURFACE]);
|
||||||
|
|
||||||
/* Free menu resurces if we are in menu when exiting. */
|
dispmanx_surface_free_pages(&_dispvars->surfaces[MAIN_SURFACE]);
|
||||||
if (_dispvars->menu_active)
|
dispmanx_surface_free_pages(&_dispvars->surfaces[MENU_SURFACE]);
|
||||||
dispmanx_free_menu_resources(_dispvars);
|
dispmanx_surface_free_pages(&_dispvars->surfaces[BACK_SURFACE]);
|
||||||
|
|
||||||
dispmanx_free_main_resources(_dispvars);
|
|
||||||
|
|
||||||
/* Close display and deinitialize. */
|
/* Close display and deinitialize. */
|
||||||
vc_dispmanx_display_close(_dispvars->display);
|
vc_dispmanx_display_close(_dispvars->display);
|
||||||
@ -643,34 +603,31 @@ static void dispmanx_gfx_free(void *data)
|
|||||||
|
|
||||||
/* Destroy mutexes and conditions. */
|
/* Destroy mutexes and conditions. */
|
||||||
slock_free(_dispvars->pending_mutex);
|
slock_free(_dispvars->pending_mutex);
|
||||||
|
slock_free(_dispvars->vsync_cond_mutex);
|
||||||
scond_free(_dispvars->vsync_condition);
|
scond_free(_dispvars->vsync_condition);
|
||||||
|
|
||||||
if (_dispvars->pages)
|
free(_dispvars);
|
||||||
free (_dispvars->pages);
|
|
||||||
_dispvars->pages = NULL;
|
|
||||||
|
|
||||||
dispmanx_restore_console(_dispvars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
video_driver_t video_dispmanx = {
|
video_driver_t video_dispmanx = {
|
||||||
dispmanx_gfx_init,
|
dispmanx_gfx_init,
|
||||||
dispmanx_gfx_frame,
|
dispmanx_gfx_frame,
|
||||||
dispmanx_gfx_set_nonblock_state,
|
dispmanx_gfx_set_nonblock_state,
|
||||||
dispmanx_gfx_alive,
|
dispmanx_gfx_alive,
|
||||||
dispmanx_gfx_focus,
|
dispmanx_gfx_focus,
|
||||||
dispmanx_gfx_suppress_screensaver,
|
dispmanx_gfx_suppress_screensaver,
|
||||||
dispmanx_gfx_has_windowed,
|
dispmanx_gfx_has_windowed,
|
||||||
dispmanx_gfx_set_shader,
|
dispmanx_gfx_set_shader,
|
||||||
dispmanx_gfx_free,
|
dispmanx_gfx_free,
|
||||||
"dispmanx",
|
"dispmanx",
|
||||||
NULL, /* set_viewport */
|
NULL, /* set_viewport */
|
||||||
dispmanx_gfx_set_rotation,
|
dispmanx_gfx_set_rotation,
|
||||||
dispmanx_gfx_viewport_info,
|
dispmanx_gfx_viewport_info,
|
||||||
dispmanx_gfx_read_viewport,
|
dispmanx_gfx_read_viewport,
|
||||||
NULL, /* read_frame_raw */
|
NULL, /* read_frame_raw */
|
||||||
|
|
||||||
#ifdef HAVE_OVERLAY
|
#ifdef HAVE_OVERLAY
|
||||||
NULL, /* overlay_interface */
|
NULL, /* overlay_interface */
|
||||||
#endif
|
#endif
|
||||||
dispmanx_gfx_get_poke_interface
|
dispmanx_gfx_get_poke_interface
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user