From eadd3b3edbe94cff3a5f91b2e04c50096e7c6dcf Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Tue, 8 Mar 2005 01:39:32 +0000 Subject: [PATCH] separate "low res loaded on startup" and "low res loaded on demand" banner modes --- stepmania/src/BannerCache.cpp | 91 +++++++++++++++++++++++------ stepmania/src/BannerCache.h | 6 +- stepmania/src/PrefsManager.cpp | 2 +- stepmania/src/PrefsManager.h | 5 +- stepmania/src/ScreenSelectMusic.cpp | 33 ++++++++--- stepmania/src/Song.cpp | 2 +- stepmania/src/SongCacheIndex.cpp | 7 +++ stepmania/src/SongCacheIndex.h | 1 + stepmania/src/StepMania.cpp | 2 +- 9 files changed, 118 insertions(+), 31 deletions(-) diff --git a/stepmania/src/BannerCache.cpp b/stepmania/src/BannerCache.cpp index 1336bee7d8..53119795c8 100644 --- a/stepmania/src/BannerCache.cpp +++ b/stepmania/src/BannerCache.cpp @@ -1,11 +1,13 @@ #include "global.h" #include "arch/arch.h" +#include "Foreach.h" #include "RageDisplay.h" #include "RageUtil.h" #include "RageLog.h" #include "RageSurface_Load.h" #include "BannerCache.h" +#include "SongCacheIndex.h" #include "Sprite.h" #include "PrefsManager.h" #include "RageDisplay.h" @@ -46,17 +48,66 @@ BannerCache *BANNERCACHE; static map g_BannerPathToImage; +static int g_iDemandRefcount = 0; CString BannerCache::GetBannerCachePath( CString BannerPath ) { - /* Use GetHashForString, not ForFile, since we don't want to spend time - * checking the file size and date. */ - return ssprintf( CACHE_DIR "Banners/%u", GetHashForString(BannerPath) ); + return SongCacheIndex::GetCacheFilePath( "Banners", BannerPath ); } +/* If in on-demand mode, load all cached banners. This must be fast, so + * cache files will not be created if they don't exist; that should be done + * by CacheBanner or LoadBanner on startup. */ +void BannerCache::Demand() +{ + ++g_iDemandRefcount; + if( g_iDemandRefcount > 1 ) + return; + + if( PREFSMAN->m_iBannerCache != PrefsManager::BNCACHE_LOW_RES_LOAD_ON_DEMAND ) + return; + + FOREACH_Child( &BannerData, p ) + { + CString sBannerPath = p->m_sName; + + if( g_BannerPathToImage.find(sBannerPath) != g_BannerPathToImage.end() ) + continue; /* already loaded */ + + const CString CachePath = GetBannerCachePath(sBannerPath); + RageSurface *img = RageSurfaceUtils::LoadSurface( CachePath ); + if( img == NULL ) + { + continue; /* doesn't exist */ + } + + g_BannerPathToImage[sBannerPath] = img; + } +} + +/* Release banners loaded on demand. */ +void BannerCache::Undemand() +{ + --g_iDemandRefcount; + if( g_iDemandRefcount != 0 ) + return; + + if( PREFSMAN->m_iBannerCache != PrefsManager::BNCACHE_LOW_RES_LOAD_ON_DEMAND ) + return; + + UnloadAllBanners(); +} + +/* If in a low-res banner mode, load a low-res banner into memory, creating + * the cache file if necessary. Unlike CacheBanner(), the original file will + * not be examined unless the cached banner doesn't exist, so the banner will + * not be updated if the original file changes, for efficiency. */ void BannerCache::LoadBanner( CString BannerPath ) { - if( PREFSMAN->m_iBannerCache != PrefsManager::BNCACHE_LOW_RES || BannerPath == "" ) + if( BannerPath == "" ) + return; // nothing to do + if( PREFSMAN->m_iBannerCache != PrefsManager::BNCACHE_LOW_RES_PRELOAD && + PREFSMAN->m_iBannerCache != PrefsManager::BNCACHE_LOW_RES_LOAD_ON_DEMAND ) return; /* Load it. */ @@ -205,6 +256,7 @@ struct BannerTexture: public RageTexture } }; +/* If a banner is cached, get its ID for use. */ RageTextureID BannerCache::LoadCachedBanner( CString BannerPath ) { RageTextureID ID( GetBannerCachePath(BannerPath) ); @@ -272,11 +324,12 @@ static inline int closest( int num, int n1, int n2 ) return n1; } -/* We write the cache even if we won't use it, so we don't have to recache everything - * if the memory or settings change. */ +/* Create or update the banner cache file as necessary. If in preload mode, + * load the cache file, too. (This is done at startup.) */ void BannerCache::CacheBanner( CString BannerPath ) { - if( PREFSMAN->m_iBannerCache != PrefsManager::BNCACHE_LOW_RES ) + if( PREFSMAN->m_iBannerCache != PrefsManager::BNCACHE_LOW_RES_PRELOAD && + PREFSMAN->m_iBannerCache != PrefsManager::BNCACHE_LOW_RES_LOAD_ON_DEMAND ) return; CHECKPOINT_M( BannerPath ); @@ -293,12 +346,16 @@ void BannerCache::CacheBanner( CString BannerPath ) if( BannerData.GetValue( BannerPath, "FullHash", CurFullHash ) && CurFullHash == FullHash ) { - /* It's identical. Just load it. */ - LoadBanner( BannerPath ); + /* It's identical. Just load it, if in preload. */ + if( PREFSMAN->m_iBannerCache == PrefsManager::BNCACHE_LOW_RES_PRELOAD ) + LoadBanner( BannerPath ); + return; } } + /* The cache file doesn't exist, or is out of date. Cache it. This + * will also load the cache into memory if in PRELOAD. */ CacheBannerInternal( BannerPath ); } @@ -412,16 +469,16 @@ void BannerCache::CacheBannerInternal( CString BannerPath ) const CString CachePath = GetBannerCachePath(BannerPath); RageSurfaceUtils::SaveSurface( img, CachePath ); - if( PREFSMAN->m_iBannerCache == PrefsManager::BNCACHE_LOW_RES ) + /* If an old image is loaded, free it. */ + if( g_BannerPathToImage.find(BannerPath) != g_BannerPathToImage.end() ) { - /* If an old image is loaded, free it. */ - if( g_BannerPathToImage.find(BannerPath) != g_BannerPathToImage.end() ) - { - RageSurface *oldimg = g_BannerPathToImage[BannerPath]; - delete oldimg; - g_BannerPathToImage.erase(BannerPath); - } + RageSurface *oldimg = g_BannerPathToImage[BannerPath]; + delete oldimg; + g_BannerPathToImage.erase(BannerPath); + } + if( PREFSMAN->m_iBannerCache == PrefsManager::BNCACHE_LOW_RES_PRELOAD ) + { /* Keep it; we're just going to load it anyway. */ g_BannerPathToImage[BannerPath] = img; } diff --git a/stepmania/src/BannerCache.h b/stepmania/src/BannerCache.h index c75fefe3a5..8263e3c349 100644 --- a/stepmania/src/BannerCache.h +++ b/stepmania/src/BannerCache.h @@ -22,10 +22,12 @@ public: ~BannerCache(); RageTextureID LoadCachedBanner( CString BannerPath ); - void CacheBanner( CString BannerPath ); - void UncacheBanner( CString BannerPath ); void LoadBanner( CString BannerPath ); + + void Demand(); + void Undemand(); + void OutputStats() const; }; diff --git a/stepmania/src/PrefsManager.cpp b/stepmania/src/PrefsManager.cpp index 27ff6cc238..d769cfc472 100644 --- a/stepmania/src/PrefsManager.cpp +++ b/stepmania/src/PrefsManager.cpp @@ -88,7 +88,7 @@ PrefsManager::PrefsManager() : m_bTexturePreload ( Options, "TexturePreload", false ), m_bDelayedScreenLoad ( Options, "DelayedScreenLoad", false ), m_bDelayedModelDelete ( Options, "DelayedModelDelete", false ), - m_iBannerCache ( Options, "BannerCache", BNCACHE_LOW_RES ), + m_iBannerCache ( Options, "BannerCache", BNCACHE_LOW_RES_PRELOAD ), m_bPalettedBannerCache ( Options, "PalettedBannerCache", false ), m_bFastLoad ( Options, "FastLoad", true ), diff --git a/stepmania/src/PrefsManager.h b/stepmania/src/PrefsManager.h index ce7a4f546e..d9ff34065d 100644 --- a/stepmania/src/PrefsManager.h +++ b/stepmania/src/PrefsManager.h @@ -43,7 +43,10 @@ public: Preference m_bTexturePreload; Preference m_bDelayedScreenLoad; Preference m_bDelayedModelDelete; - enum { BNCACHE_OFF, BNCACHE_LOW_RES, BNCACHE_FULL }; + enum { BNCACHE_OFF, + BNCACHE_LOW_RES_PRELOAD, // preload low-res on start + BNCACHE_LOW_RES_LOAD_ON_DEMAND, // preload low-res on screen load + BNCACHE_FULL }; Preference m_iBannerCache; Preference m_bPalettedBannerCache; Preference m_bFastLoad; diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index e7e3ccad16..4809bab992 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -27,6 +27,7 @@ #include "PlayerState.h" #include "Command.h" #include "CommonMetrics.h" +#include "BannerCache.h" const int NUM_SCORE_DIGITS = 9; @@ -89,6 +90,9 @@ void ScreenSelectMusic::Init() if( GAMESTATE->m_PlayMode == PLAY_MODE_INVALID ) RageException::Throw( "The PlayMode has not been set. A theme must set the PlayMode before loading ScreenSelectMusic." ); + /* Load low-res banners, if needed. */ + BANNERCACHE->Demand(); + m_MusicWheel.Load(); // pop'n music has this under the songwheel... @@ -341,6 +345,7 @@ void ScreenSelectMusic::Init() ScreenSelectMusic::~ScreenSelectMusic() { LOG->Trace( "ScreenSelectMusic::~ScreenSelectMusic()" ); + BANNERCACHE->Undemand(); } @@ -681,18 +686,25 @@ void ScreenSelectMusic::CheckBackgroundRequests() if( g_bBannerWaiting ) { float HighQualTime = m_Banner.GetFadeSeconds(); + if( g_StartedLoadingAt.Ago() < HighQualTime ) + return; CString sPath; - if( g_StartedLoadingAt.Ago() >= HighQualTime && m_BackgroundLoader.IsCacheFileFinished(g_sBannerPath, sPath) ) + if( TEXTUREMAN->IsTextureRegistered( Sprite::SongBannerTexture(g_sBannerPath) ) ) { - g_bBannerWaiting = false; - RageTimer foo; - m_Banner.Load( sPath ); - - m_BackgroundLoader.FinishedWithCachedFile( g_sBannerPath ); + /* If the file is already loaded into a texture, it's finished, + * and we only do this to honor the HighQualTime value. */ + sPath = g_sBannerPath; } else - return; + { + if( !m_BackgroundLoader.IsCacheFileFinished( g_sBannerPath, sPath ) ) + return; + m_BackgroundLoader.FinishedWithCachedFile( g_sBannerPath ); + } + + g_bBannerWaiting = false; + m_Banner.Load( sPath ); } /* Nothing else is going. Start the music, if we havn't yet. */ @@ -1679,7 +1691,12 @@ void ScreenSelectMusic::AfterMusicChange() LOG->Trace("LoadFromCachedBanner(%s)",g_sBannerPath .c_str()); if( m_Banner.LoadFromCachedBanner( g_sBannerPath ) ) { - m_BackgroundLoader.CacheFile( g_sBannerPath ); + /* If the high-res banner is already loaded, just + * delay before loading it, so the low-res one has + * time to fade in. */ + if( !TEXTUREMAN->IsTextureRegistered( Sprite::SongBannerTexture(g_sBannerPath) ) ) + m_BackgroundLoader.CacheFile( g_sBannerPath ); + g_bBannerWaiting = true; } } diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index ae32378f3f..8106d5218e 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -147,7 +147,7 @@ CString Song::GetBackgroundAtBeat( float fBeat ) const CString Song::GetCacheFilePath() const { - return ssprintf( CACHE_DIR "Songs/%u", GetHashForString(m_sSongDir) ); + return SongCacheIndex::GetCacheFilePath( "Songs", m_sSongDir ); } /* Get a path to the SM containing data for this song. It might diff --git a/stepmania/src/SongCacheIndex.cpp b/stepmania/src/SongCacheIndex.cpp index a4fb1a839e..e2b7e5d924 100644 --- a/stepmania/src/SongCacheIndex.cpp +++ b/stepmania/src/SongCacheIndex.cpp @@ -29,6 +29,13 @@ SongCacheIndex *SONGINDEX; +CString SongCacheIndex::GetCacheFilePath( const CString &sGroup, const CString &sPath ) +{ + /* Use GetHashForString, not ForFile, since we don't want to spend time + * checking the file size and date. */ + return ssprintf( "%s/%s/%u", CACHE_DIR, sGroup.c_str(), GetHashForString(sPath) ); +} + SongCacheIndex::SongCacheIndex() { ReadCacheIndex(); diff --git a/stepmania/src/SongCacheIndex.h b/stepmania/src/SongCacheIndex.h index 63918753f0..1ef5e9d155 100644 --- a/stepmania/src/SongCacheIndex.h +++ b/stepmania/src/SongCacheIndex.h @@ -11,6 +11,7 @@ class SongCacheIndex public: SongCacheIndex(); ~SongCacheIndex(); + static CString GetCacheFilePath( const CString &sGroup, const CString &sPath ); void ReadCacheIndex(); void AddCacheIndex( const CString &path, unsigned hash ); diff --git a/stepmania/src/StepMania.cpp b/stepmania/src/StepMania.cpp index 84af633104..b1e4a9da2a 100644 --- a/stepmania/src/StepMania.cpp +++ b/stepmania/src/StepMania.cpp @@ -355,7 +355,7 @@ static void CheckSettings() /* Preloaded banners takes about 9k per song. Although it's smaller than the * actual song data, it still adds up with a lot of songs. Disable it for 64-meg * systems. */ - PREFSMAN->m_iBannerCache = LowMemory ? PrefsManager::BNCACHE_OFF:PrefsManager::BNCACHE_LOW_RES; + PREFSMAN->m_iBannerCache = LowMemory ? PrefsManager::BNCACHE_OFF:PrefsManager::BNCACHE_LOW_RES_PRELOAD; PREFSMAN->SaveGlobalPrefsToDisk(); #endif