From 299aa1d1f289d8602a1d32957c2e06b5b79a563a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 13 Mar 2015 22:39:18 +0100 Subject: [PATCH] (Dispman Graphics driver) Cleanups --- gfx/drivers/dispmanx_gfx.c | 823 ++++++++++++++++++++----------------- 1 file changed, 456 insertions(+), 367 deletions(-) diff --git a/gfx/drivers/dispmanx_gfx.c b/gfx/drivers/dispmanx_gfx.c index 5dcc9d7efd..f64c76413d 100644 --- a/gfx/drivers/dispmanx_gfx.c +++ b/gfx/drivers/dispmanx_gfx.c @@ -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 = {