diff options
author | vanfanel | 2015-07-07 11:36:56 +0200 |
---|---|---|
committer | vanfanel | 2015-07-20 17:15:04 +0200 |
commit | 6320a008ec27499b3174cd2ea8b3926a59f2e117 (patch) | |
tree | 0debf70e934e0e2159f48bd5da9b4f893ed19688 /backends/graphics/dispmanxsdl | |
parent | bf68de9aa7c3131ffac65b15d5e971788c7fe9c9 (diff) | |
download | scummvm-rg350-6320a008ec27499b3174cd2ea8b3926a59f2e117.tar.gz scummvm-rg350-6320a008ec27499b3174cd2ea8b3926a59f2e117.tar.bz2 scummvm-rg350-6320a008ec27499b3174cd2ea8b3926a59f2e117.zip |
SDL/DISPMANX: Updated rendering code for better buffers management.
Diffstat (limited to 'backends/graphics/dispmanxsdl')
-rw-r--r-- | backends/graphics/dispmanxsdl/dispmanxsdl-graphics.cpp | 445 | ||||
-rw-r--r-- | backends/graphics/dispmanxsdl/dispmanxsdl-graphics.h | 4 |
2 files changed, 245 insertions, 204 deletions
diff --git a/backends/graphics/dispmanxsdl/dispmanxsdl-graphics.cpp b/backends/graphics/dispmanxsdl/dispmanxsdl-graphics.cpp index f2df0e0086..af48fce935 100644 --- a/backends/graphics/dispmanxsdl/dispmanxsdl-graphics.cpp +++ b/backends/graphics/dispmanxsdl/dispmanxsdl-graphics.cpp @@ -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; + + // 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 mutex and condition variable objects - pthread_mutex_init(&_dispvars->pendingMutex, 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); -void DispmanXSdlGraphicsManager::DispmanXSetup(int width, int height, int bpp) { - DispmanXFreeResources(); - vc_dispmanx_display_get_info(_dispvars->display, &_dispvars->amode); + // We need this so SDL_SetVideoMode() is called once. + _dispvars->fscreen = NULL; +} - _dispvars->pitch = width * (bpp / 8); - _dispvars->pixFormat = VC_IMAGE_RGB565; +void DispmanXSdlGraphicsManager::DispmanXSetup(int srcWidth, int srcHeight) { + unsigned int dstWidth, dstHeight, dstXpos, dstYpos; - // 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 we have an element, we have to free it along with it's resources. + if (_dispvars->element) { + DispmanXFreeResources(); + } + // We do this for 2 bytes per pixel which is default on the Rpi. + _dispvars->pitch = srcWidth * 2; 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); + float aspect = ((float)srcWidth / (float)srcHeight); + dstWidth = _dispvars->dispmanxHeight * aspect; } else { - vc_dispmanx_rect_set(&(_dispvars->dstRect), 0, 0, - _dispvars->amode.width, _dispvars->amode.height); + 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; } - // 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); + dstXpos = (_dispvars->dispmanxWidth - dstWidth) / 2; + dstYpos = (_dispvars->dispmanxHeight - dstHeight) / 2; - for (int i = 0; i < NUMPAGES; i++) - _dispvars->pages[i].resource = vc_dispmanx_resource_create(_dispvars->pixFormat, width, height, - &(_dispvars->vcImagePtr)); - - // Add element + // 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; + + // 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); + } - // 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]; + // 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); } } diff --git a/backends/graphics/dispmanxsdl/dispmanxsdl-graphics.h b/backends/graphics/dispmanxsdl/dispmanxsdl-graphics.h index a5abb8618a..c41f84ef7a 100644 --- a/backends/graphics/dispmanxsdl/dispmanxsdl-graphics.h +++ b/backends/graphics/dispmanxsdl/dispmanxsdl-graphics.h @@ -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; |