mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-22 01:57:16 +00:00
SDL/DISPMANX: Updated rendering code for better buffers management.
This commit is contained in:
parent
bf68de9aa7
commit
6320a008ec
@ -34,180 +34,277 @@
|
||||
|
||||
#include <bcm_host.h>
|
||||
|
||||
#define NUMPAGES 2
|
||||
|
||||
struct dispvarsStruct {
|
||||
DISPMANX_DISPLAY_HANDLE_T display;
|
||||
DISPMANX_MODEINFO_T amode;
|
||||
DISPMANX_UPDATE_HANDLE_T update;
|
||||
DISPMANX_ELEMENT_HANDLE_T element;
|
||||
VC_IMAGE_TYPE_T pixFormat;
|
||||
VC_DISPMANX_ALPHA_T *alpha;
|
||||
VC_RECT_T srcRect;
|
||||
VC_RECT_T dstRect;
|
||||
VC_DISPMANX_ALPHA_T alpha;
|
||||
|
||||
VC_RECT_T bmpRect;
|
||||
uint vcImagePtr;
|
||||
uint screen;
|
||||
uint pitch;
|
||||
VC_RECT_T srcRect;
|
||||
VC_RECT_T dstRect;
|
||||
uint32_t vcImagePtr;
|
||||
int screen;
|
||||
int pitch;
|
||||
unsigned int dispmanxWidth;
|
||||
unsigned int dispmanxHeight;
|
||||
bool aspectRatioCorrection;
|
||||
void *pixmem;
|
||||
|
||||
|
||||
int numpages;
|
||||
struct dispmanxPage *pages;
|
||||
struct dispmanxPage *nextPage;
|
||||
bool pageflipPending;
|
||||
struct dispmanxPage *currentPage;
|
||||
int pageflipPending;
|
||||
|
||||
pthread_cond_t vsyncCondition;
|
||||
pthread_mutex_t vsyncCondMutex;
|
||||
pthread_mutex_t pendingMutex;
|
||||
|
||||
SDL_Surface *fscreen;
|
||||
};
|
||||
|
||||
struct dispmanxPage {
|
||||
DISPMANX_RESOURCE_HANDLE_T resource;
|
||||
DISPMANX_RESOURCE_HANDLE_T resource;
|
||||
bool used;
|
||||
// Each page has it's own mutex for
|
||||
// isolating the access to it's "used" flag.
|
||||
pthread_mutex_t pageUsedMutex;
|
||||
|
||||
// This field will allow us to access the
|
||||
// main dispvars struct, for the vsync cb.
|
||||
struct dispvarsStruct *dispvars;
|
||||
};
|
||||
|
||||
DispmanXSdlGraphicsManager::DispmanXSdlGraphicsManager(SdlEventSource *sdlEventSource)
|
||||
: SurfaceSdlGraphicsManager(sdlEventSource) {
|
||||
_dispvars = new dispvarsStruct;
|
||||
_dispvars = new(dispvarsStruct);
|
||||
DispmanXInit();
|
||||
}
|
||||
|
||||
DispmanXSdlGraphicsManager::~DispmanXSdlGraphicsManager() {
|
||||
DispmanXVideoQuit();
|
||||
delete _dispvars;
|
||||
delete(_dispvars);
|
||||
}
|
||||
|
||||
void DispmanXSdlGraphicsManager::DispmanXInit() {
|
||||
_dispvars->screen = 0;
|
||||
_dispvars->vcImagePtr = 0;
|
||||
_dispvars->pages = (struct dispmanxPage *)calloc(NUMPAGES, sizeof(struct dispmanxPage));
|
||||
_dispvars->numpages = 3;
|
||||
_dispvars->pages = (struct dispmanxPage *)calloc(_dispvars->numpages, sizeof(struct dispmanxPage));
|
||||
_dispvars->pageflipPending = 0;
|
||||
_dispvars->nextPage = &_dispvars->pages[0];
|
||||
_dispvars->currentPage = NULL;
|
||||
_dispvars->pixFormat = VC_IMAGE_RGB565;
|
||||
|
||||
/* Transparency disabled */
|
||||
_dispvars->alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
||||
_dispvars->alpha.opacity = 255;
|
||||
_dispvars->alpha.mask = 0;
|
||||
_dispvars->element = 0;
|
||||
|
||||
// Initialize mutex and condition variable objects
|
||||
pthread_mutex_init(&_dispvars->pendingMutex, NULL);
|
||||
// Init each page's variables
|
||||
for (int i = 0; i < _dispvars->numpages; i++) {
|
||||
_dispvars->pages[i].used = false;
|
||||
_dispvars->pages[i].dispvars = _dispvars;
|
||||
_dispvars->pages[i].resource = 0;
|
||||
pthread_mutex_init(&_dispvars->pages[i].pageUsedMutex, NULL);
|
||||
}
|
||||
|
||||
// Initialize the other mutex and condition variables
|
||||
pthread_cond_init(&_dispvars->vsyncCondition, NULL);
|
||||
pthread_mutex_init(&_dispvars->pendingMutex, NULL);
|
||||
pthread_mutex_init(&_dispvars->vsyncCondMutex, NULL);
|
||||
|
||||
// Before we call any vc_* function, we need to call this one.
|
||||
bcm_host_init();
|
||||
|
||||
_dispvars->display = vc_dispmanx_display_open(_dispvars->screen);
|
||||
graphics_get_display_size(_dispvars->display, &_dispvars->dispmanxWidth, &_dispvars->dispmanxHeight);
|
||||
|
||||
// We need this so SDL_SetVideoMode() is called once.
|
||||
_dispvars->fscreen = NULL;
|
||||
}
|
||||
|
||||
void DispmanXSdlGraphicsManager::DispmanXSetup(int width, int height, int bpp) {
|
||||
DispmanXFreeResources();
|
||||
vc_dispmanx_display_get_info(_dispvars->display, &_dispvars->amode);
|
||||
void DispmanXSdlGraphicsManager::DispmanXSetup(int srcWidth, int srcHeight) {
|
||||
unsigned int dstWidth, dstHeight, dstXpos, dstYpos;
|
||||
|
||||
_dispvars->pitch = width * (bpp / 8);
|
||||
_dispvars->pixFormat = VC_IMAGE_RGB565;
|
||||
|
||||
// Transparency disabled
|
||||
VC_DISPMANX_ALPHA_T layerAlpha;
|
||||
layerAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
||||
layerAlpha.opacity = 255;
|
||||
layerAlpha.mask = 0;
|
||||
_dispvars->alpha = &layerAlpha;
|
||||
|
||||
if (_dispvars->aspectRatioCorrection) {
|
||||
float orig_ratio = ((float)width / (float)height);
|
||||
int dst_width = _dispvars->amode.height * orig_ratio;
|
||||
|
||||
// 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->dstRect), dst_ypos, 0,
|
||||
dst_width, _dispvars->amode.height);
|
||||
} else {
|
||||
vc_dispmanx_rect_set(&(_dispvars->dstRect), 0, 0,
|
||||
_dispvars->amode.width, _dispvars->amode.height);
|
||||
// If we have an element, we have to free it along with it's resources.
|
||||
if (_dispvars->element) {
|
||||
DispmanXFreeResources();
|
||||
}
|
||||
|
||||
// We configure the rects now
|
||||
vc_dispmanx_rect_set(&(_dispvars->bmpRect), 0, 0, width, height);
|
||||
vc_dispmanx_rect_set(&(_dispvars->srcRect), 0, 0, width << 16, height << 16);
|
||||
// We do this for 2 bytes per pixel which is default on the Rpi.
|
||||
_dispvars->pitch = srcWidth * 2;
|
||||
if (_dispvars->aspectRatioCorrection) {
|
||||
float aspect = ((float)srcWidth / (float)srcHeight);
|
||||
dstWidth = _dispvars->dispmanxHeight * aspect;
|
||||
} else {
|
||||
dstWidth = _dispvars->dispmanxWidth;
|
||||
}
|
||||
dstHeight = _dispvars->dispmanxHeight;
|
||||
|
||||
// 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 (dstWidth > _dispvars->dispmanxWidth) {
|
||||
dstWidth = _dispvars->dispmanxWidth;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMPAGES; i++)
|
||||
_dispvars->pages[i].resource = vc_dispmanx_resource_create(_dispvars->pixFormat, width, height,
|
||||
&(_dispvars->vcImagePtr));
|
||||
|
||||
// Add element
|
||||
dstXpos = (_dispvars->dispmanxWidth - dstWidth) / 2;
|
||||
dstYpos = (_dispvars->dispmanxHeight - dstHeight) / 2;
|
||||
|
||||
// Remember we have to transfer the whole bitmap even if we would have
|
||||
// interest in a part of it! Blitting is done by the GPU.
|
||||
vc_dispmanx_rect_set(&_dispvars->dstRect, dstXpos, dstYpos, dstWidth, dstHeight);
|
||||
vc_dispmanx_rect_set(&_dispvars->bmpRect, 0, 0, srcWidth, srcHeight);
|
||||
vc_dispmanx_rect_set(&_dispvars->srcRect, 0, 0, srcWidth << 16, srcHeight << 16);
|
||||
|
||||
for (int i = 0; i < _dispvars->numpages; i++) {
|
||||
_dispvars->pages[i].resource = vc_dispmanx_resource_create(_dispvars->pixFormat,
|
||||
srcWidth, srcHeight, &(_dispvars->vcImagePtr));
|
||||
}
|
||||
|
||||
// Add the element. Has to be removed before getting here again.
|
||||
_dispvars->update = vc_dispmanx_update_start(0);
|
||||
|
||||
_dispvars->element = vc_dispmanx_element_add(_dispvars->update, _dispvars->display, 0,
|
||||
&(_dispvars->dstRect), _dispvars->pages[0].resource, &(_dispvars->srcRect),
|
||||
DISPMANX_PROTECTION_NONE, _dispvars->alpha, 0, (DISPMANX_TRANSFORM_T)0);
|
||||
|
||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
||||
|
||||
_dispvars->element = vc_dispmanx_element_add(
|
||||
_dispvars->update,_dispvars->display, 0,
|
||||
&_dispvars->dstRect, 0,
|
||||
&_dispvars->srcRect, DISPMANX_PROTECTION_NONE,
|
||||
&_dispvars->alpha, 0, (DISPMANX_TRANSFORM_T)0);
|
||||
|
||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
||||
}
|
||||
|
||||
void DispmanXVSyncCallback (DISPMANX_UPDATE_HANDLE_T u, void *arg) {
|
||||
struct dispvarsStruct *_dispvars = (struct dispvarsStruct*)arg;
|
||||
struct dispmanxPage *page = (struct dispmanxPage*)arg;
|
||||
struct dispvarsStruct *dispvars = page->dispvars;
|
||||
|
||||
// Changing the page to write must be done before the signaling
|
||||
// so we have the right page in nextPage when update_main continues
|
||||
if (_dispvars->nextPage == &_dispvars->pages[0])
|
||||
_dispvars->nextPage = &_dispvars->pages[1];
|
||||
else
|
||||
_dispvars->nextPage = &_dispvars->pages[0];
|
||||
// Marking the page as free must be done before the signaling
|
||||
// so when the update function continues (it won't continue until we signal)
|
||||
// we can chose this page as free.
|
||||
if (dispvars->currentPage) {
|
||||
pthread_mutex_lock(&dispvars->currentPage->pageUsedMutex);
|
||||
|
||||
// We mark as free the page that was visible until now.
|
||||
page->dispvars->currentPage->used = false;
|
||||
|
||||
pthread_mutex_unlock(&dispvars->currentPage->pageUsedMutex);
|
||||
}
|
||||
|
||||
// The page on which we issued the flip that
|
||||
// caused this callback becomes the visible one
|
||||
dispvars->currentPage = page;
|
||||
|
||||
// These two things must be isolated "atomically" to avoid getting
|
||||
// a false positive in the pending_mutex test in update_main.
|
||||
pthread_mutex_lock(&_dispvars->pendingMutex);
|
||||
|
||||
pthread_cond_signal(&_dispvars->vsyncCondition);
|
||||
_dispvars->pageflipPending = false;
|
||||
|
||||
pthread_mutex_unlock(&_dispvars->pendingMutex);
|
||||
|
||||
// a false positive in the pending_mutex test in update function.
|
||||
pthread_mutex_lock(&dispvars->pendingMutex);
|
||||
|
||||
dispvars->pageflipPending--;
|
||||
pthread_cond_signal(&dispvars->vsyncCondition);
|
||||
|
||||
pthread_mutex_unlock(&dispvars->pendingMutex);
|
||||
}
|
||||
|
||||
void DispmanXSdlGraphicsManager::DispmanXUpdate() {
|
||||
// Wait until last issued flip completes to get a free page. Also,
|
||||
// dispmanx doesn't support issuing more than one pageflip.
|
||||
pthread_mutex_lock(&_dispvars->pendingMutex);
|
||||
|
||||
if (_dispvars->pageflipPending) {
|
||||
if (_dispvars->pageflipPending > 0) {
|
||||
pthread_cond_wait(&_dispvars->vsyncCondition, &_dispvars->pendingMutex);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_dispvars->pendingMutex);
|
||||
|
||||
struct dispmanxPage *page = DispmanXGetFreePage();
|
||||
|
||||
// Frame blitting
|
||||
vc_dispmanx_resource_write_data(_dispvars->nextPage->resource, _dispvars->pixFormat,
|
||||
_dispvars->pitch, _dispvars->pixmem, &(_dispvars->bmpRect));
|
||||
vc_dispmanx_resource_write_data(page->resource, _dispvars->pixFormat,
|
||||
_dispvars->pitch, _dispvars->pixmem, &_dispvars->bmpRect);
|
||||
|
||||
// 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->nextPage->resource);
|
||||
vc_dispmanx_update_submit(_dispvars->update, &DispmanXVSyncCallback, _dispvars);
|
||||
page->resource);
|
||||
vc_dispmanx_update_submit(_dispvars->update, &DispmanXVSyncCallback, page);
|
||||
|
||||
pthread_mutex_lock(&_dispvars->pendingMutex);
|
||||
_dispvars->pageflipPending = true;
|
||||
_dispvars->pageflipPending++;
|
||||
pthread_mutex_unlock(&_dispvars->pendingMutex);
|
||||
}
|
||||
|
||||
struct dispmanxPage *DispmanXSdlGraphicsManager::DispmanXGetFreePage(void) {
|
||||
struct dispmanxPage *page = NULL;
|
||||
|
||||
while (!page)
|
||||
{
|
||||
// Try to find a free page
|
||||
for (int i = 0; i < _dispvars->numpages; ++i) {
|
||||
if (!_dispvars->pages[i].used)
|
||||
{
|
||||
page = (_dispvars->pages) + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no page is free at the moment,
|
||||
// wait until a free page is freed by vsync CB.
|
||||
if (!page) {
|
||||
pthread_mutex_lock(&_dispvars->vsyncCondMutex);
|
||||
pthread_cond_wait(&_dispvars->vsyncCondition, &_dispvars->vsyncCondMutex);
|
||||
pthread_mutex_unlock(&_dispvars->vsyncCondMutex);
|
||||
}
|
||||
}
|
||||
|
||||
// We mark the choosen page as used
|
||||
pthread_mutex_lock(&page->pageUsedMutex);
|
||||
page->used = true;
|
||||
pthread_mutex_unlock(&page->pageUsedMutex);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
void DispmanXSdlGraphicsManager::DispmanXFreeResources(void) {
|
||||
_dispvars->update = vc_dispmanx_update_start(0);
|
||||
|
||||
for (int i = 0; i < NUMPAGES; i++)
|
||||
// What if we run into the vsync cb code after freeing the resources?
|
||||
pthread_mutex_lock(&_dispvars->pendingMutex);
|
||||
if (_dispvars->pageflipPending > 0)
|
||||
{
|
||||
pthread_cond_wait(&_dispvars->vsyncCondition, &_dispvars->pendingMutex);
|
||||
}
|
||||
pthread_mutex_unlock(&_dispvars->pendingMutex);
|
||||
|
||||
for (int i = 0; i < _dispvars->numpages; i++) {
|
||||
vc_dispmanx_resource_delete(_dispvars->pages[i].resource);
|
||||
|
||||
_dispvars->pages[i].resource = 0;
|
||||
_dispvars->pages[i].used = false;
|
||||
}
|
||||
|
||||
_dispvars->update = vc_dispmanx_update_start(0);
|
||||
vc_dispmanx_element_remove(_dispvars->update, _dispvars->element);
|
||||
|
||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
||||
// We use this on the setup function to know if we have to free resources and element.
|
||||
_dispvars->element = 0;
|
||||
}
|
||||
|
||||
void DispmanXSdlGraphicsManager::DispmanXVideoQuit() {
|
||||
// This also waits for pending flips to complete, that's needed before
|
||||
// we destroy the mutexes and condition.
|
||||
DispmanXFreeResources();
|
||||
// Close display and deinit
|
||||
vc_dispmanx_display_close(_dispvars->display);
|
||||
bcm_host_deinit();
|
||||
|
||||
// Destroy mutexes and conditions
|
||||
|
||||
// Destroy the mutexes and conditions
|
||||
for (int i = 0; i < _dispvars->numpages; i++) {
|
||||
pthread_mutex_destroy(&_dispvars->pages[i].pageUsedMutex);
|
||||
}
|
||||
pthread_mutex_destroy(&_dispvars->pendingMutex);
|
||||
pthread_mutex_destroy(&_dispvars->vsyncCondMutex);
|
||||
pthread_cond_destroy(&_dispvars->vsyncCondition);
|
||||
|
||||
free(_dispvars->pages);
|
||||
|
||||
// Close display and deinit
|
||||
vc_dispmanx_display_close(_dispvars->display);
|
||||
bcm_host_deinit();
|
||||
}
|
||||
|
||||
bool DispmanXSdlGraphicsManager::loadGFXMode() {
|
||||
@ -216,10 +313,10 @@ bool DispmanXSdlGraphicsManager::loadGFXMode() {
|
||||
// In DispmanX, we manage aspect ratio correction, so for scummvm it's always disabled.
|
||||
_videoMode.aspectRatioCorrection = false;
|
||||
|
||||
_videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
|
||||
_videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
|
||||
_videoMode.hardwareWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
|
||||
_videoMode.hardwareHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
|
||||
_videoMode.overlayWidth = _videoMode.screenWidth;
|
||||
_videoMode.overlayHeight = _videoMode.screenHeight;
|
||||
_videoMode.hardwareWidth = _videoMode.screenWidth;
|
||||
_videoMode.hardwareHeight = _videoMode.screenHeight;
|
||||
|
||||
//
|
||||
// Create the surface that contains the 8 bit game data
|
||||
@ -236,59 +333,30 @@ bool DispmanXSdlGraphicsManager::loadGFXMode() {
|
||||
// Avoid having SDL_SRCALPHA set even if we supplied an alpha-channel in the format.
|
||||
SDL_SetAlpha(_screen, 0, 255);
|
||||
|
||||
// SDL 1.2 palettes default to all black,
|
||||
// SDL 1.3 palettes default to all white,
|
||||
// Thus set our own default palette to all black.
|
||||
// SDL_SetColors does nothing for non indexed surfaces.
|
||||
// We set our own default palette to all black.
|
||||
SDL_SetColors(_screen, _currentPalette, 0, 256);
|
||||
|
||||
//
|
||||
// Create the surface that contains the scaled graphics in 16 bit mode
|
||||
//
|
||||
|
||||
// We call DispmanXSetup() before SDL_SetVideoMode() because we use _hwscreen == null
|
||||
// to know inside DispmanXSetup() if we've been there before and need to free resources.
|
||||
DispmanXSetup(_videoMode.screenWidth, _videoMode.screenHeight, 16);
|
||||
// _hwscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 16, SDL_FULLSCREEN);
|
||||
DispmanXSetup(_videoMode.screenWidth, _videoMode.screenHeight);
|
||||
|
||||
_hwscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.hardwareWidth, _videoMode.hardwareHeight, 16,
|
||||
0, 0, 0, 0);
|
||||
|
||||
_dispvars->pixmem = _hwscreen->pixels;
|
||||
|
||||
// We draw on a RAM surface, but we make this call just to get SDL input initialized.
|
||||
// Even if we don't use the returned SDL_Surface *, we still need to use the right dimensions
|
||||
// for mouse pointer adjustment to work correctly.
|
||||
SDL_SetVideoMode(_videoMode.screenWidth, _videoMode.screenHeight, 16, SDL_FULLSCREEN);
|
||||
|
||||
detectSupportedFormats();
|
||||
|
||||
// This is just so SDL 1.x input is initialized. Only once!
|
||||
if (_dispvars->fscreen == NULL)
|
||||
_dispvars->fscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 16, SDL_FULLSCREEN);
|
||||
if (_hwscreen == NULL) {
|
||||
// DON'T use error(), as this tries to bring up the debug
|
||||
// console, which WON'T WORK now that _hwscreen is hosed.
|
||||
|
||||
if (!_oldVideoMode.setup) {
|
||||
warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
|
||||
g_system->quit();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// Don't use error here because we don't have access to the debug console
|
||||
warning("Allocating surface for DispmanX rendering _hwscreen failed");
|
||||
g_system->quit();
|
||||
}
|
||||
|
||||
//
|
||||
// Create the surface used for the graphics in 16 bit before scaling, and also the overlay
|
||||
//
|
||||
|
||||
// Need some extra bytes around when using 2xSaI
|
||||
_tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + 3, _videoMode.screenHeight + 3,
|
||||
16,
|
||||
_hwscreen->format->Rmask,
|
||||
_hwscreen->format->Gmask,
|
||||
_hwscreen->format->Bmask,
|
||||
_hwscreen->format->Amask);
|
||||
|
||||
if (_tmpscreen == NULL)
|
||||
error("allocating _tmpscreen failed");
|
||||
|
||||
// We render to dispmanx resources from _hwscreen pixels array
|
||||
_dispvars->pixmem = _hwscreen->pixels;
|
||||
|
||||
_overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight,
|
||||
16,
|
||||
_hwscreen->format->Rmask,
|
||||
@ -311,16 +379,6 @@ bool DispmanXSdlGraphicsManager::loadGFXMode() {
|
||||
_overlayFormat.bShift = _overlayscreen->format->Bshift;
|
||||
_overlayFormat.aShift = _overlayscreen->format->Ashift;
|
||||
|
||||
_tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3,
|
||||
16,
|
||||
_hwscreen->format->Rmask,
|
||||
_hwscreen->format->Gmask,
|
||||
_hwscreen->format->Bmask,
|
||||
_hwscreen->format->Amask);
|
||||
|
||||
if (_tmpscreen2 == NULL)
|
||||
error("allocating _tmpscreen2 failed");
|
||||
|
||||
#ifdef USE_OSD
|
||||
_osdSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
|
||||
_hwscreen->w,
|
||||
@ -336,29 +394,51 @@ bool DispmanXSdlGraphicsManager::loadGFXMode() {
|
||||
#endif
|
||||
|
||||
_eventSource->resetKeyboadEmulation(
|
||||
_videoMode.screenWidth * _videoMode.scaleFactor - 1,
|
||||
effectiveScreenHeight() - 1);
|
||||
|
||||
// Distinguish 555 and 565 mode
|
||||
if (_hwscreen->format->Rmask == 0x7C00)
|
||||
InitScalers(555);
|
||||
else
|
||||
InitScalers(565);
|
||||
_videoMode.screenWidth, effectiveScreenHeight());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DispmanXSdlGraphicsManager::clearOverlay() {
|
||||
//assert(_transactionMode == kTransactionNone);
|
||||
|
||||
Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
|
||||
|
||||
if (!_overlayVisible)
|
||||
return;
|
||||
|
||||
// Clear the overlay by making the game screen "look through" everywhere.
|
||||
SDL_Rect src, dst;
|
||||
src.x = src.y = 0;
|
||||
dst.x = dst.y = 0;
|
||||
src.w = dst.w = _videoMode.screenWidth;
|
||||
src.h = dst.h = _videoMode.screenHeight;
|
||||
if (SDL_BlitSurface(_screen, &src, _hwscreen, &dst) != 0)
|
||||
error("SDL_BlitSurface failed: %s", SDL_GetError());
|
||||
|
||||
SDL_LockSurface(_hwscreen);
|
||||
SDL_LockSurface(_overlayscreen);
|
||||
Normal1x((byte *)(_hwscreen->pixels), _hwscreen->pitch,
|
||||
(byte *)_overlayscreen->pixels, _overlayscreen->pitch, _videoMode.screenWidth, _videoMode.screenHeight);
|
||||
|
||||
SDL_UnlockSurface(_hwscreen);
|
||||
SDL_UnlockSurface(_overlayscreen);
|
||||
|
||||
_forceFull = true;
|
||||
}
|
||||
|
||||
void DispmanXSdlGraphicsManager::internUpdateScreen() {
|
||||
SDL_Surface *srcSurf, *origSurf;
|
||||
int height, width;
|
||||
ScalerProc *scalerProc;
|
||||
int scale1;
|
||||
|
||||
// If the shake position changed, fill the dirty area with blackness
|
||||
if (_currentShakePos != _newShakePos ||
|
||||
(_mouseNeedsRedraw && _mouseBackup.y <= _currentShakePos)) {
|
||||
SDL_Rect blackrect = {0, 0, (Uint16)(_videoMode.screenWidth * _videoMode.scaleFactor), (Uint16)(_newShakePos * _videoMode.scaleFactor)};
|
||||
|
||||
if (_videoMode.aspectRatioCorrection && !_overlayVisible)
|
||||
blackrect.h = real2Aspect(blackrect.h - 1) + 1;
|
||||
|
||||
SDL_FillRect(_hwscreen, &blackrect, 0);
|
||||
|
||||
_currentShakePos = _newShakePos;
|
||||
@ -400,19 +480,14 @@ void DispmanXSdlGraphicsManager::internUpdateScreen() {
|
||||
|
||||
if (!_overlayVisible) {
|
||||
origSurf = _screen;
|
||||
srcSurf = _tmpscreen;
|
||||
srcSurf = _hwscreen;
|
||||
width = _videoMode.screenWidth;
|
||||
height = _videoMode.screenHeight;
|
||||
scalerProc = _scalerProc;
|
||||
scale1 = _videoMode.scaleFactor;
|
||||
} else {
|
||||
origSurf = _overlayscreen;
|
||||
srcSurf = _tmpscreen2;
|
||||
srcSurf = _hwscreen;
|
||||
width = _videoMode.overlayWidth;
|
||||
height = _videoMode.overlayHeight;
|
||||
scalerProc = Normal1x;
|
||||
|
||||
scale1 = 1;
|
||||
}
|
||||
|
||||
// Add the area covered by the mouse cursor to the list of dirty rects if
|
||||
@ -433,50 +508,15 @@ void DispmanXSdlGraphicsManager::internUpdateScreen() {
|
||||
if (_numDirtyRects > 0 || _mouseNeedsRedraw) {
|
||||
SDL_Rect *r;
|
||||
SDL_Rect dst;
|
||||
uint32 srcPitch, dstPitch;
|
||||
SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects;
|
||||
|
||||
for (r = _dirtyRectList; r != lastRect; ++r) {
|
||||
dst = *r;
|
||||
dst.x++; // Shift rect by one since 2xSai needs to access the data around
|
||||
dst.y++; // any pixel to scale it, and we want to avoid mem access crashes.
|
||||
|
||||
if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
|
||||
error("SDL_BlitSurface failed: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
SDL_LockSurface(srcSurf);
|
||||
SDL_LockSurface(_hwscreen);
|
||||
|
||||
srcPitch = srcSurf->pitch;
|
||||
dstPitch = _hwscreen->pitch;
|
||||
|
||||
for (r = _dirtyRectList; r != lastRect; ++r) {
|
||||
register int dst_y = r->y + _currentShakePos;
|
||||
register int dst_h = 0;
|
||||
register int rx1 = r->x * scale1;
|
||||
|
||||
if (dst_y < height) {
|
||||
dst_h = r->h;
|
||||
if (dst_h > height - dst_y)
|
||||
dst_h = height - dst_y;
|
||||
|
||||
dst_y = dst_y * scale1;
|
||||
|
||||
assert(scalerProc != NULL);
|
||||
scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
|
||||
(byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h);
|
||||
}
|
||||
|
||||
r->x = rx1;
|
||||
r->y = dst_y;
|
||||
r->w = r->w * scale1;
|
||||
r->h = dst_h * scale1;
|
||||
|
||||
}
|
||||
SDL_UnlockSurface(srcSurf);
|
||||
SDL_UnlockSurface(_hwscreen);
|
||||
|
||||
// Readjust the dirty rect list in case we are doing a full update.
|
||||
// This is necessary if shaking is active.
|
||||
if (_forceFull) {
|
||||
@ -491,6 +531,7 @@ void DispmanXSdlGraphicsManager::internUpdateScreen() {
|
||||
SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Finally, blit all our changes to the screen
|
||||
if (!_displayDisabled) {
|
||||
SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
|
||||
@ -531,15 +572,13 @@ void DispmanXSdlGraphicsManager::setFullscreenMode(bool enable) {
|
||||
|
||||
void DispmanXSdlGraphicsManager::setAspectRatioCorrection(bool enable) {
|
||||
Common::StackLock lock(_graphicsMutex);
|
||||
// Ratio correction is managed externally by dispmanx, so we disable it at the SDL level but take note,
|
||||
// so it's effectively taken into account at the dispmanx level in DispmanXSetup().
|
||||
if (_oldVideoMode.setup && _dispvars->aspectRatioCorrection == enable)
|
||||
return;
|
||||
// We simply take note on what's the aspect ratio correction activation state.
|
||||
_dispvars->aspectRatioCorrection = enable;
|
||||
|
||||
if (_transactionMode == kTransactionActive) {
|
||||
_dispvars->aspectRatioCorrection = enable;
|
||||
_transactionDetails.needHotswap = false;
|
||||
DispmanXSetup(_videoMode.screenWidth, _videoMode.screenHeight, 16);
|
||||
// If we have a videomode setup already, call DispmanXSetup() again so aspect ratio
|
||||
// correction activation/deactivation works from the menu.
|
||||
if (_oldVideoMode.setup && _dispvars->aspectRatioCorrection == enable) {
|
||||
DispmanXSetup(_videoMode.screenWidth, _videoMode.screenHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,11 +37,13 @@ public:
|
||||
bool handleScalerHotkeys(Common::KeyCode key);
|
||||
void setFullscreenMode(bool enable);
|
||||
void setAspectRatioCorrection(bool enable);
|
||||
void clearOverlay();
|
||||
protected:
|
||||
// Raspberry Pi Dispmanx API
|
||||
void DispmanXSetup(int dwidth, int dheight, int dbpp);
|
||||
void DispmanXSetup(int width, int height);
|
||||
void DispmanXInit();
|
||||
void DispmanXUpdate();
|
||||
struct dispmanxPage *DispmanXGetFreePage();
|
||||
void DispmanXFreeResources();
|
||||
void DispmanXVideoQuit();
|
||||
struct dispvarsStruct *_dispvars;
|
||||
|
64
configure
vendored
64
configure
vendored
@ -124,6 +124,7 @@ _faad=auto
|
||||
_fluidsynth=auto
|
||||
_opengl=auto
|
||||
_opengles=auto
|
||||
_dispmanx=no
|
||||
_readline=auto
|
||||
_freetype2=auto
|
||||
_taskbar=auto
|
||||
@ -824,7 +825,7 @@ Configuration:
|
||||
-h, --help display this help and exit
|
||||
--backend=BACKEND backend to build (android, tizen, dc, dingux, ds, gcw0,
|
||||
gph, iphone, linuxmoto, maemo, n64, null, openpandora,
|
||||
ps2, psp, raspberrypi, samsungtv, sdl, webos, wii, wince) [sdl]
|
||||
ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl]
|
||||
|
||||
Installation directories:
|
||||
--prefix=PREFIX install architecture-independent files in PREFIX
|
||||
@ -945,6 +946,8 @@ Optional Libraries:
|
||||
--with-opengl-prefix=DIR Prefix where OpenGL (ES) is installed (optional)
|
||||
--disable-opengl disable OpenGL (ES) support [autodetect]
|
||||
|
||||
--with-dispmanx enable dispmanx (Raspberry Pi native 2D API) rendering
|
||||
|
||||
--with-jpeg-prefix=DIR Prefix where libjpeg is installed (optional)
|
||||
--disable-jpeg disable JPEG decoder [autodetect]
|
||||
|
||||
@ -1049,6 +1052,8 @@ for ac_option in $@; do
|
||||
--disable-libunity) _libunity=no ;;
|
||||
--enable-opengl) _opengl=yes ;;
|
||||
--disable-opengl) _opengl=no ;;
|
||||
--enable-dispmanx) _dispmanx=yes ;;
|
||||
--disable-dispmanx) _dispmanx=no ;;
|
||||
--enable-bink) _bink=yes ;;
|
||||
--disable-bink) _bink=no ;;
|
||||
--enable-verbose-build) _verbose_build=yes ;;
|
||||
@ -1299,6 +1304,7 @@ raspberrypi)
|
||||
_host_os=linux
|
||||
_host_cpu=arm
|
||||
_host_alias=arm-linux-gnueabihf
|
||||
_backend=raspberrypi
|
||||
;;
|
||||
caanoo)
|
||||
_host_os=gph-linux
|
||||
@ -2987,30 +2993,6 @@ case $_backend in
|
||||
LIBS="$LIBS -Wl,-Map,mapfile.txt"
|
||||
;;
|
||||
raspberrypi)
|
||||
echocheck "DispmanX graphics "
|
||||
_use_dispmanx=no
|
||||
DISPMANX_CXXFLAGS="-I$RPI_ROOTDIR/opt/vc/include -I$RPI_ROOTDIR/opt/vc/include/interface/vmcs_host/linux/ -I$RPI_ROOTDIR/opt/vc/include/interface/vcos/pthreads -mfpu=vfp -mfloat-abi=hard -I$RPI_ROOTDIR/opt/rpi_root/usr/include/SDL"
|
||||
DISPMANX_LIBS="--sysroot=$RPI_ROOTDIR -L$RPI_ROOTDIR/usr/lib -L$RPI_ROOTDIR/opt/vc/lib -lbcm_host -lvcos -lvchiq_arm"
|
||||
cat > $TMPC << EOF
|
||||
#include <bcm_host.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bcm_host_init();
|
||||
}
|
||||
EOF
|
||||
cc_check $DISPMANX_CXXFLAGS $DISPMANX_LIBS && _use_dispmanx=yes
|
||||
if test "$_use_dispmanx" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS $DISPMANX_CXXFLAGS"
|
||||
LIBS="$LIBS $DISPMANX_LIBS"
|
||||
MODULES="$MODULES backends/platform/sdl"
|
||||
DEFINES="$DEFINES -DRASPBERRYPI"
|
||||
add_line_to_config_mk 'RASPBERRYPI = 1'
|
||||
_build_scalers=no
|
||||
_build_hq_scalers=no
|
||||
_opengl=no
|
||||
_default_optimization_level=-O3
|
||||
echo $_use_dispmanx
|
||||
fi
|
||||
;;
|
||||
samsungtv)
|
||||
DEFINES="$DEFINES -DSAMSUNGTV"
|
||||
@ -3148,7 +3130,7 @@ case $_backend in
|
||||
esac
|
||||
|
||||
#
|
||||
# In raspberry Pi, we don't use find_sdlconfig since we could be crosscompiling, but still we use SDL
|
||||
# In raspberry Pi, we don't use find_sdlconfig since we could be crosscompiling, but still we use SDL
|
||||
#
|
||||
case $_backend in
|
||||
raspberrypi)
|
||||
@ -3159,8 +3141,11 @@ case $_backend in
|
||||
_16bit=yes
|
||||
_savegame_timestamp=no
|
||||
_eventrec=no
|
||||
_build_scalers=no
|
||||
_build_hq_scalers=no
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
#
|
||||
# Determine whether host is POSIX compliant, or at least POSIX
|
||||
# compatible enough to support our POSIX code (including dlsym(),
|
||||
@ -4094,6 +4079,31 @@ fi
|
||||
define_in_config_if_yes "$_opengl" "USE_OPENGL"
|
||||
define_in_config_if_yes "$_opengles" "USE_GLES"
|
||||
|
||||
# Check if Raspberry Pi dispmanx has been activated.
|
||||
if test "$_dispmanx" = "yes" ; then
|
||||
echocheck "DispmanX graphics"
|
||||
_use_dispmanx=no
|
||||
DISPMANX_CXXFLAGS="-I$RPI_ROOTDIR/opt/vc/include -I$RPI_ROOTDIR/opt/vc/include/interface/vmcs_host/linux/ -I$RPI_ROOTDIR/opt/vc/include/interface/vcos/pthreads -mfpu=vfp -mfloat-abi=hard -I$RPI_ROOTDIR/opt/rpi_root/usr/include/SDL"
|
||||
DISPMANX_LIBS="--sysroot=$RPI_ROOTDIR -L$RPI_ROOTDIR/usr/lib -L$RPI_ROOTDIR/opt/vc/lib -lbcm_host -lvcos -lvchiq_arm"
|
||||
cat > $TMPC << EOF
|
||||
#include <bcm_host.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bcm_host_init();
|
||||
}
|
||||
EOF
|
||||
cc_check $DISPMANX_CXXFLAGS $DISPMANX_LIBS && _use_dispmanx=yes
|
||||
if test "$_use_dispmanx" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS $DISPMANX_CXXFLAGS"
|
||||
LIBS="$LIBS $DISPMANX_LIBS"
|
||||
MODULES="$MODULES backends/platform/sdl"
|
||||
DEFINES="$DEFINES -DRASPBERRYPI"
|
||||
add_line_to_config_mk 'RASPBERRYPI = 1'
|
||||
_opengl=no
|
||||
_opengles=no
|
||||
echo $_use_dispmanx
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for nasm
|
||||
|
Loading…
x
Reference in New Issue
Block a user