(Dispman Graphics driver) Cleanups

This commit is contained in:
twinaphex 2015-03-13 22:39:18 +01:00
parent 0188c5105b
commit 299aa1d1f2

View File

@ -1,5 +1,4 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2015 - Manuel Alfayate
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
@ -42,302 +41,352 @@
#include "config.h"
#endif
#define numpages 2
#define NUMPAGES 2
struct dispmanx_video {
DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T amode;
DISPMANX_UPDATE_HANDLE_T update;
DISPMANX_RESOURCE_HANDLE_T resources[numpages];
DISPMANX_ELEMENT_HANDLE_T element;
VC_IMAGE_TYPE_T pixFormat;
VC_DISPMANX_ALPHA_T *alpha;
VC_RECT_T srcRect;
VC_RECT_T dstRect;
VC_RECT_T bmpRect;
unsigned int vcImagePtr;
unsigned int screen;
unsigned int pitch;
unsigned int flipPage;
struct dispmanx_video
{
DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T amode;
DISPMANX_UPDATE_HANDLE_T update;
DISPMANX_RESOURCE_HANDLE_T resources[NUMPAGES];
DISPMANX_ELEMENT_HANDLE_T element;
VC_IMAGE_TYPE_T pixFormat;
VC_DISPMANX_ALPHA_T *alpha;
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
unsigned int width;
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;
/* Internal frame dimensions */
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel;
/* Some cores render things we don't need between scanlines */
unsigned int visible_width;
struct dispmanx_page *pages;
struct dispmanx_page *currentPage;
unsigned int pageflip_pending;
bool aspectRatioCorrection;
void *pixmem;
// For console blanking
int fd;
char *fbp;
unsigned int screensize;
char *screen_bck;
struct dispmanx_page *pages;
struct dispmanx_page *currentPage;
unsigned int pageflip_pending;
// For threading
pthread_cond_t vsync_condition;
pthread_mutex_t pending_mutex;
/* For console blanking */
int fd;
char *fbp;
unsigned int screensize;
char *screen_bck;
// Mutex to isolate the vsync condition signaling
pthread_mutex_t vsync_cond_mutex;
/* For threading */
pthread_cond_t vsync_condition;
pthread_mutex_t pending_mutex;
// Menu
bool menu_active;
DISPMANX_ELEMENT_HANDLE_T menu_element;
DISPMANX_RESOURCE_HANDLE_T menu_resources[2];
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;
/* Mutex to isolate the vsync condition signaling */
pthread_mutex_t vsync_cond_mutex;
// External aspect ratio
float aspect;
/* Menu */
bool menu_active;
DISPMANX_ELEMENT_HANDLE_T menu_element;
DISPMANX_RESOURCE_HANDLE_T menu_resources[2];
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 */
float aspect;
};
struct dispmanx_page {
unsigned int numpage;
struct dispmanx_page *next;
// This field will allow me to access the main _dispvars struct from the vsync CB function
struct dispmanx_video *dispvars;
// Each page has it's own mutex for isolating it's used flag access.
pthread_mutex_t page_used_mutex;
bool used;
struct dispmanx_page
{
unsigned int numpage;
struct dispmanx_page *next;
/* This field will allow us to
* access the main _dispvars struct
* from the vsync CB function */
struct dispmanx_video *dispvars;
/* Each page has it's own mutex for
* isolating it's used flag access. */
pthread_mutex_t page_used_mutex;
bool used;
};
void dispmanx_blank_console(void *data) {
struct dispmanx_video *_dispvars = data;
void dispmanx_blank_console(void *data)
{
struct fb_var_screeninfo vinfo;
unsigned int fb_bytes_per_pixel;
struct dispmanx_video *_dispvars = data;
struct fb_var_screeninfo vinfo;
unsigned int fb_bytes_per_pixel;
_dispvars->fd = open("/dev/fb0", O_RDWR);
// We need this just to know the framebuffer 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;
if (!_dispvars)
return;
_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);
_dispvars->fd = open("/dev/fb0", O_RDWR);
// Disable cursor blinking
system("setterm -cursor off");
/* We need this just to know the framebuffer
* 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;
// Backup console screen contents
_dispvars->screen_bck = (char*)malloc(_dispvars->screensize * sizeof(char));
memcpy((char*)_dispvars->screen_bck, (char*)_dispvars->fbp, _dispvars->screensize);
_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);
// Blank console
memset((char*)(_dispvars->fbp), 0x00, _dispvars->screensize);
/* Disable cursor blinking */
system("setterm -cursor off");
// Unmap and close
munmap(&_dispvars->fd, _dispvars->screensize);
close (_dispvars->fd);
/* 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);
}
void dispmanx_unblank_console(void *data) {
struct dispmanx_video *_dispvars = data;
_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);
void dispmanx_unblank_console(void *data)
{
struct dispmanx_video *_dispvars = data;
// Unmap and close
munmap(&_dispvars->fd, _dispvars->screensize);
close (_dispvars->fd);
if (!_dispvars)
return;
// Restore cursor blinking
system("setterm -cursor on");
_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");
}
/* Find a free page, clear it if necessary, and return the page. If *
* no free page is available when called, wait for a page flip. */
/* Find a free page, clear it if necessary, and return the 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_video *_dispvars = data;
struct dispmanx_page *page = NULL;
unsigned i;
unsigned i;
struct dispmanx_video *_dispvars = data;
struct dispmanx_page *page = NULL;
while (page == NULL) {
// Try to find a free page
for (i = 0; i < numpages; ++i) {
if (!_dispvars->pages[i].used) {
page = (_dispvars->pages) + i;
break;
}
}
while (!page)
{
/* Try to find a free page */
for (i = 0; i < NUMPAGES; ++i)
{
if (!_dispvars->pages[i].used)
{
page = (_dispvars->pages) + i;
break;
}
}
// If no page is free ATM, wait until a free page is freed by vsync CB
if (page == NULL) {
pthread_mutex_lock (&_dispvars->vsync_cond_mutex);
pthread_cond_wait (&_dispvars->vsync_condition, &_dispvars->vsync_cond_mutex);
pthread_mutex_unlock (&_dispvars->vsync_cond_mutex);
}
}
/* If no page is free at the moment,
* wait until a free page is freed by vsync CB. */
if (!page)
{
pthread_mutex_lock (&_dispvars->vsync_cond_mutex);
pthread_cond_wait (&_dispvars->vsync_condition, &_dispvars->vsync_cond_mutex);
pthread_mutex_unlock (&_dispvars->vsync_cond_mutex);
}
}
pthread_mutex_lock (&page->page_used_mutex);
page->used = true;
pthread_mutex_unlock (&page->page_used_mutex);
return page;
pthread_mutex_lock (&page->page_used_mutex);
page->used = true;
pthread_mutex_unlock (&page->page_used_mutex);
return page;
}
void vsync_callback (DISPMANX_UPDATE_HANDLE_T u, void *data){
struct dispmanx_page *page = data;
void vsync_callback (DISPMANX_UPDATE_HANDLE_T u, void *data)
{
struct dispmanx_page *page = data;
// We signal the vsync condition, just in case we're waiting for it somewhere (no free pages, etc)
pthread_mutex_lock(&page->dispvars->vsync_cond_mutex);
pthread_cond_signal(&page->dispvars->vsync_condition);
pthread_mutex_unlock(&page->dispvars->vsync_cond_mutex);
if (!page)
return;
pthread_mutex_lock(&page->dispvars->pending_mutex);
page->dispvars->pageflip_pending--;
pthread_mutex_unlock(&page->dispvars->pending_mutex);
// We mark as free the page that was visible until now
if (page->dispvars->currentPage != NULL) {
pthread_mutex_lock (&page->page_used_mutex);
page->dispvars->currentPage->used = false;
pthread_mutex_unlock (&page->page_used_mutex);
}
// The page on which we just issued the flip that caused this callback becomes the visible one
page->dispvars->currentPage = page;
/* We signal the vsync condition, just in case
* we're waiting for it somewhere (no free pages, etc). */
pthread_mutex_lock(&page->dispvars->vsync_cond_mutex);
pthread_cond_signal(&page->dispvars->vsync_condition);
pthread_mutex_unlock(&page->dispvars->vsync_cond_mutex);
pthread_mutex_lock(&page->dispvars->pending_mutex);
page->dispvars->pageflip_pending--;
pthread_mutex_unlock(&page->dispvars->pending_mutex);
/* We mark as free the page that was visible until now */
if (page->dispvars->currentPage != NULL)
{
pthread_mutex_lock (&page->page_used_mutex);
page->dispvars->currentPage->used = false;
pthread_mutex_unlock (&page->page_used_mutex);
}
/* The page on which we just issued the flip that
* caused this callback becomes the visible one */
page->dispvars->currentPage = page;
}
void dispmanx_flip (struct dispmanx_page *page, void *data) {
void dispmanx_flip (struct dispmanx_page *page, void *data)
{
struct dispmanx_video *_dispvars = data;
if (!_dispvars)
return;
/* Dispmanx doesn't support issuing more than one pageflip.
* If we do, the second CB isn't called. */
if (_dispvars->pageflip_pending > 0)
{
pthread_mutex_lock(&_dispvars->vsync_cond_mutex);
pthread_cond_wait (&_dispvars->vsync_condition, &_dispvars->vsync_cond_mutex);
pthread_mutex_unlock(&_dispvars->vsync_cond_mutex);
}
/* Issue a page flip at the next vblank interval
* (will be done at vsync anyway). */
_dispvars->update = vc_dispmanx_update_start(0);
vc_dispmanx_element_change_source(_dispvars->update, _dispvars->element,
_dispvars->resources[page->numpage]);
vc_dispmanx_update_submit(_dispvars->update, vsync_callback, (void*)page);
pthread_mutex_lock(&_dispvars->pending_mutex);
_dispvars->pageflip_pending++;
pthread_mutex_unlock(&_dispvars->pending_mutex);
}
void dispmanx_free_main_resources(void *data)
{
int i;
struct dispmanx_video *_dispvars = data;
if (!_dispvars)
return;
_dispvars->update = vc_dispmanx_update_start(0);
for (i = 0; i < NUMPAGES; i++)
vc_dispmanx_resource_delete(_dispvars->resources[i]);
vc_dispmanx_element_remove(_dispvars->update, _dispvars->element);
vc_dispmanx_update_submit_sync(_dispvars->update);
}
bool dispmanx_setup_scale (void *data, unsigned width,
unsigned height, unsigned pitch)
{
int i, dst_ypos;
VC_DISPMANX_ALPHA_T layerAlpha;
struct dispmanx_video *_dispvars = data;
// Dispmanx doesn't support issuing more than one pageflip. If we do, the second CB isn't called.
if (_dispvars->pageflip_pending > 0) {
pthread_mutex_lock(&_dispvars->vsync_cond_mutex);
pthread_cond_wait (&_dispvars->vsync_condition, &_dispvars->vsync_cond_mutex);
pthread_mutex_unlock(&_dispvars->vsync_cond_mutex);
}
// Issue a page flip at the next vblank interval (will be done at vsync anyway).
_dispvars->update = vc_dispmanx_update_start(0);
if (!_dispvars)
return false;
vc_dispmanx_element_change_source(_dispvars->update, _dispvars->element,
_dispvars->resources[page->numpage]);
vc_dispmanx_update_submit(_dispvars->update, vsync_callback, (void*)page);
pthread_mutex_lock(&_dispvars->pending_mutex);
_dispvars->pageflip_pending++;
pthread_mutex_unlock(&_dispvars->pending_mutex);
}
void dispmanx_free_main_resources(void *data) {
struct dispmanx_video *_dispvars = data;
int i;
_dispvars->update = vc_dispmanx_update_start(0);
for (i = 0; i < numpages; i++)
vc_dispmanx_resource_delete(_dispvars->resources[i]);
vc_dispmanx_element_remove(_dispvars->update, _dispvars->element );
vc_dispmanx_update_submit_sync(_dispvars->update);
}
bool dispmanx_setup_scale (void *data, unsigned width, unsigned height, unsigned pitch) {
struct dispmanx_video *_dispvars = data;
int i;
// Since internal frame resoluton seems to have changed, We change the internal frame resolution
// in use, and call again dispmanx_setup_scale() to set the rects, etc
/* Since internal frame resolution seems to have changed, we change the
* internal frame resolution in use, and call dispmanx_setup_scale()
* again to set the rects, etc. */
_dispvars->width = width;
_dispvars->height = height;
// Total pitch, including things the cores render between "visible" scanlines
/* Total pitch, including things the cores
* render between "visible" scanlines. */
_dispvars->pitch = pitch;
// The "visible" width obtained from the core pitch
/* The "visible" width obtained from the core pitch. */
_dispvars->visible_width = pitch / _dispvars->bytes_per_pixel;
dispmanx_free_main_resources (_dispvars);
dispmanx_free_main_resources(_dispvars);
vc_dispmanx_display_get_info(_dispvars->display, &(_dispvars->amode));
// We chose 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
VC_DISPMANX_ALPHA_T layerAlpha;
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 (g_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;
}
switch (g_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 an scaled image width that is bigger than the physical screen width,
// then we keep the physical screen width as our maximun width.
//if (dst_width > _dispvars->amode.width)
// dst_width = _dispvars->amode.width;
int dst_ypos = (_dispvars->amode.width - dst_width) / 2;
/* 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->dstRect), dst_ypos, 0,
dst_width, _dispvars->amode.height);
/*} else {
vc_dispmanx_rect_set(&(_dispvars->dstRect), 0, 0,
_dispvars->amode.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(&(_dispvars->srcRect), 0, 0, _dispvars->width << 16, _dispvars->height << 16);
// We create as many resources as pages
for (i = 0; i < numpages; i++)
/* We create as many resources as pages */
for (i = 0; i < NUMPAGES; i++)
_dispvars->resources[i] = vc_dispmanx_resource_create(_dispvars->pixFormat,
_dispvars->visible_width, _dispvars->height, &(_dispvars->vcImagePtr));
// Add element
/* Add element. */
_dispvars->update = vc_dispmanx_update_start(0);
_dispvars->element = vc_dispmanx_element_add(_dispvars->update, _dispvars->display, 0,
@ -349,47 +398,61 @@ bool dispmanx_setup_scale (void *data, unsigned width, unsigned height, unsigned
return true;
}
void dispmanx_update_main (void *data, const void *frame) {
struct dispmanx_video *_dispvars = data;
void dispmanx_update_main (void *data, const void *frame)
{
struct dispmanx_page *page = NULL;
struct dispmanx_video *_dispvars = data;
struct dispmanx_page *page;
page = dispmanx_get_free_page(_dispvars);
if (!_dispvars)
return;
// Frame blitting
vc_dispmanx_resource_write_data(_dispvars->resources[page->numpage], _dispvars->pixFormat,
_dispvars->pitch, (void *)frame, &(_dispvars->bmpRect));
page = dispmanx_get_free_page(_dispvars);
// Issue flipping: we send the page to the dispmanx API internal flipping FIFO stack.
dispmanx_flip (page, _dispvars);
return;
if (!page)
return;
/* Frame blitting */
vc_dispmanx_resource_write_data(_dispvars->resources[page->numpage], _dispvars->pixFormat,
_dispvars->pitch, (void *)frame, &(_dispvars->bmpRect));
/* Issue flipping: we send the page
* to the dispmanx API internal flipping FIFO stack. */
dispmanx_flip (page, _dispvars);
}
static void *dispmanx_gfx_init(const video_info_t *video,
const input_driver_t **input, void **input_data)
{
int i;
struct dispmanx_video *_dispvars = calloc(1, sizeof(struct dispmanx_video));
struct dispmanx_video *_dispvars;
_dispvars = calloc(1, sizeof(struct dispmanx_video));
if (!_dispvars)
return NULL;
_dispvars->bytes_per_pixel = video->rgb32 ? 4 : 2;
_dispvars->screen = 0;
_dispvars->vcImagePtr = 0;
_dispvars->pages = calloc(numpages, sizeof(struct dispmanx_page));
_dispvars->bytes_per_pixel = video->rgb32 ? 4 : 2;
_dispvars->screen = 0;
_dispvars->vcImagePtr = 0;
_dispvars->pageflip_pending = 0;
_dispvars->currentPage = NULL;
_dispvars->currentPage = NULL;
_dispvars->pages = calloc(NUMPAGES, sizeof(struct dispmanx_page));
for (i = 0; i < numpages; i++) {
_dispvars->pages[i].numpage = i;
_dispvars->pages[i].used = false;
if (!_dispvars->pages)
{
free(_dispvars);
return NULL;
}
for (i = 0; i < NUMPAGES; i++)
{
_dispvars->pages[i].numpage = i;
_dispvars->pages[i].used = false;
_dispvars->pages[i].dispvars = _dispvars;
pthread_mutex_init(&_dispvars->pages[i].page_used_mutex, NULL);
}
// Initialize the rest of the mutexes and conditions
pthread_cond_init(&_dispvars->vsync_condition, NULL);
pthread_mutex_init(&_dispvars->pending_mutex, NULL);
/* Initialize the rest of the mutexes and conditions. */
pthread_cond_init(&_dispvars->vsync_condition, NULL);
pthread_mutex_init(&_dispvars->pending_mutex, NULL);
pthread_mutex_init(&_dispvars->vsync_cond_mutex, NULL);
bcm_host_init();
@ -402,17 +465,17 @@ static void *dispmanx_gfx_init(const video_info_t *video,
}
static bool dispmanx_gfx_frame(void *data, const void *frame, unsigned width,
unsigned height, unsigned pitch, const char *msg)
unsigned height, unsigned pitch, const char *msg)
{
struct dispmanx_video *_dispvars = data;
// Check if neither menu nor core framebuffer is to be displayed.
if (!_dispvars->menu_active && frame == NULL)
/* Check if neither menu nor core framebuffer is to be displayed. */
if (!_dispvars->menu_active && !frame)
return true;
if (width != _dispvars->width || height != _dispvars->height)
{
// Sanity check
/* Sanity check. */
if (width == 0 || height == 0)
return true;
@ -426,11 +489,12 @@ static bool dispmanx_gfx_frame(void *data, const void *frame, unsigned width,
dispmanx_blank_console (_dispvars);
}
if (_dispvars->menu_active) {
if (_dispvars->menu_active)
{
char buf[128];
video_monitor_get_fps(buf, sizeof(buf), NULL, 0);
// Synchronous flipping of the menu buffers
/* Synchronous flipping of the menu buffers. */
_dispvars->update = vc_dispmanx_update_start(0);
vc_dispmanx_element_change_source(_dispvars->update, _dispvars->menu_element,
_dispvars->menu_resources[_dispvars->menu_flip_page]);
@ -438,112 +502,132 @@ static bool dispmanx_gfx_frame(void *data, const void *frame, unsigned width,
return true;
}
// Update main game screen: locate free page, blit and flip
/* Update main game screen: locate free page, blit and flip. */
dispmanx_update_main(_dispvars, frame);
return true;
}
static void dispmanx_free_menu_resources (void *data) {
struct dispmanx_video *_dispvars = data;
_dispvars->update = vc_dispmanx_update_start(0);
vc_dispmanx_resource_delete(_dispvars->menu_resources[0]);
vc_dispmanx_resource_delete(_dispvars->menu_resources[1]);
static void dispmanx_free_menu_resources (void *data)
{
struct dispmanx_video *_dispvars = data;
vc_dispmanx_element_remove(_dispvars->update, _dispvars->menu_element );
vc_dispmanx_update_submit_sync(_dispvars->update);
if (!_dispvars)
return;
_dispvars->menu_width = 0;
_dispvars->menu_height = 0;
_dispvars->update = vc_dispmanx_update_start(0);
vc_dispmanx_resource_delete(_dispvars->menu_resources[0]);
vc_dispmanx_resource_delete(_dispvars->menu_resources[1]);
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)
{
struct dispmanx_video *_dispvars = data;
if (_dispvars)
_dispvars->menu_active = state;
if (!_dispvars->menu_active)
dispmanx_free_menu_resources(_dispvars);
struct dispmanx_video *_dispvars = data;
if (_dispvars)
_dispvars->menu_active = state;
if (!_dispvars->menu_active)
dispmanx_free_menu_resources(_dispvars);
}
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 we're entering the menu in this frame, we must setup rects, resources and menu element.
if (width != _dispvars->menu_width || height != _dispvars->menu_height) {
// Sanity check
if (width == 0 || height == 0)
return;
int i;
_dispvars->menu_width = width;
_dispvars->menu_height = height;
if (!_dispvars)
return;
_dispvars->menu_pitch = width * (rgb32 ? 4 : 2);
/* If we're entering the menu in this frame,
* we must setup rects, resources and menu element. */
if (width != _dispvars->menu_width || height != _dispvars->menu_height)
{
int i, dst_width, dst_ypos;
VC_DISPMANX_ALPHA_T layerAlpha;
_dispvars->menu_pixFormat = VC_IMAGE_RGBA16;
_dispvars->menu_flip_page = 0;
// Transparency disabled
VC_DISPMANX_ALPHA_T layerAlpha;
layerAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
//layerAlpha.opacity = (unsigned char)(255.0f * alpha);
layerAlpha.opacity = 210;
layerAlpha.mask = 0;
_dispvars->menu_alpha = &layerAlpha;
/* Sanity check */
if (width == 0 || height == 0)
return;
int dst_width = _dispvars->amode.height * _dispvars->aspect;
// If we obtain an scaled image width that is bigger than the physical screen width,
// then we keep the physical screen width as our maximun width.
//if (dst_width > _dispvars->amode.width)
// dst_width = _dispvars->amode.width;
int 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);
// We create two resources for the menu element
_dispvars->menu_resources[0] = vc_dispmanx_resource_create(_dispvars->menu_pixFormat,
_dispvars->menu_width, _dispvars->menu_height, &(_dispvars->vcImagePtr));
_dispvars->menu_resources[1] = 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_resources[0], &(_dispvars->menu_srcRect),
DISPMANX_PROTECTION_NONE, _dispvars->menu_alpha, 0, (DISPMANX_TRANSFORM_T)0);
vc_dispmanx_update_submit_sync(_dispvars->update);
}
_dispvars->menu_width = width;
_dispvars->menu_height = height;
// Flipping is done in every frame, in the gfx_frame fn. That's why why change flip page here instead.
_dispvars->menu_flip_page = !_dispvars->menu_flip_page;
// Frame blitting
vc_dispmanx_resource_write_data(_dispvars->menu_resources[_dispvars->menu_flip_page],
_dispvars->menu_pixFormat, _dispvars->menu_pitch, (void *)frame, &(_dispvars->menu_bmpRect));
_dispvars->menu_pitch = width * (rgb32 ? 4 : 2);
// We don't flip the menu buffers here: that's done in the gfx_frame function when menu is active.
_dispvars->menu_pixFormat = VC_IMAGE_RGBA16;
_dispvars->menu_flip_page = 0;
/* Transparency disabled */
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);
/* We create two resources for the menu element. */
_dispvars->menu_resources[0] = vc_dispmanx_resource_create(_dispvars->menu_pixFormat,
_dispvars->menu_width, _dispvars->menu_height, &(_dispvars->vcImagePtr));
_dispvars->menu_resources[1] = 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_resources[0], &(_dispvars->menu_srcRect),
DISPMANX_PROTECTION_NONE, _dispvars->menu_alpha, 0, (DISPMANX_TRANSFORM_T)0);
vc_dispmanx_update_submit_sync(_dispvars->update);
}
/* Flipping is done in every frame,
* in the gfx_frame function.
* That's why why change flip page here instead. */
_dispvars->menu_flip_page = !_dispvars->menu_flip_page;
/* Frame blitting. */
vc_dispmanx_resource_write_data(_dispvars->menu_resources[_dispvars->menu_flip_page],
_dispvars->menu_pixFormat, _dispvars->menu_pitch, (void *)frame, &(_dispvars->menu_bmpRect));
/* We don't flip the menu buffers here:
* that's done in the gfx_frame function when menu is active. */
}
static void dispmanx_gfx_set_nonblock_state(void *data, bool state)
{
struct dispmanx_video *vid = data;
struct dispmanx_video *vid = data;
if (!data)
return;
(void)data;
(void)vid;
/* TODO */
}
static bool dispmanx_gfx_alive(void *data)
@ -573,17 +657,17 @@ static void dispmanx_gfx_viewport_info(void *data, struct video_viewport *vp)
static bool dispmanx_gfx_suppress_screensaver(void *data, bool enable)
{
(void)data;
(void)enable;
(void)data;
(void)enable;
return false;
return false;
}
static bool dispmanx_gfx_has_windowed(void *data)
{
(void)data;
/* TODO - implement. */
return true;
(void)data;
return false;
}
static bool dispmanx_gfx_set_shader(void *data,
@ -633,29 +717,34 @@ static const video_poke_interface_t dispmanx_poke_interface = {
static void dispmanx_gfx_get_poke_interface(void *data,
const video_poke_interface_t **iface)
{
(void)data;
*iface = &dispmanx_poke_interface;
(void)data;
*iface = &dispmanx_poke_interface;
}
static void dispmanx_gfx_free(void *data) {
struct dispmanx_video *_dispvars = data;
int i;
static void dispmanx_gfx_free(void *data)
{
int i;
struct dispmanx_video *_dispvars = data;
dispmanx_free_main_resources(_dispvars);
// Close display and deinit
vc_dispmanx_display_close(_dispvars->display);
bcm_host_deinit();
// Destroy mutexes and conditions
pthread_mutex_destroy(&_dispvars->pending_mutex);
pthread_cond_destroy(&_dispvars->vsync_condition);
for (i = 0; i < numpages; i++)
pthread_mutex_destroy(&_dispvars->pages[i].page_used_mutex);
free (_dispvars->pages);
if (!_dispvars)
return;
dispmanx_unblank_console(_dispvars);
dispmanx_free_main_resources(_dispvars);
/* Close display and deinitialize. */
vc_dispmanx_display_close(_dispvars->display);
bcm_host_deinit();
/* Destroy mutexes and conditions. */
pthread_mutex_destroy(&_dispvars->pending_mutex);
pthread_cond_destroy(&_dispvars->vsync_condition);
for (i = 0; i < NUMPAGES; i++)
pthread_mutex_destroy(&_dispvars->pages[i].page_used_mutex);
free (_dispvars->pages);
dispmanx_unblank_console(_dispvars);
}
video_driver_t video_dispmanx = {