Revamp texture caching system

This commit is contained in:
Chris Danford
2003-04-18 23:55:20 +00:00
parent 0fcd675396
commit 74d7bcd2bf
11 changed files with 216 additions and 63 deletions
+123 -1
View File
@@ -6,7 +6,7 @@
<body>
<p><font face="Courier New" size="2">StepMania 3.0 final<br>
<p><font face="Courier New" size="2">StepMania X.X<br>
&copy;2001-2003, StepMania team, All rights reserved.<br>
<a href="http://www.stepmania.com">http://www.stepmania.com</a></font></p>
<p>
@@ -35,11 +35,14 @@ and Help</a> <br>
<a href="#Creating an Announcer">Creating an Announcer</a><br>
<a href="#Creating a Note Skin">Creating a Note Skin</a><br>
<a href="#Creating a Theme">Creating a Theme</a><br>
<a href="#Actor Commands">Actor Commands</a><br>
<a href="#ScreenSelect">ScreenSelect</a><br>
<a href="#How StepMania Loads Textures">How StepMania Loads Textures</a><br>
<a href="#Building StepMania from CVS source">Building StepMania from CVS Source</a><br>
<a href="#Thanks">Thanks</a><br>
<br>
See the file <a href="NEWS">NEWS</a> for version history.<br>
See the file <a href="COPYING.txt">COPYING.txt</a> for license information.<br>
<br>
</font>
<hr>
@@ -923,6 +926,125 @@ Graphics folder &quot;Themes\MySuperTheme\Graphics&quot;. <br>
<br>
</font>
<hr>
<p><font face="Courier New" size="2"><a name="Actor Commands">Actor Commands</a> (<a href="#Table of Contents">top</a>)</font></p>
<hr>
<p>
<font face="Courier New" size="2">
<br>
In the old paradigm, you would define the position of an Actor with two
different metrics - one for the X position, and one for the Y. For example:<br>
ObjectX=100<br>
ObjectY=220<br>
<br>
This system is being replaced by more powerful &quot;commands strings&quot;. A command
string can set positions, colors, effects, and also script animations over time.
Positioning an Actor with command string would look like this:<br>
ObjectOnCommand=x,100;y,220<br>
<br>
A command string contains one or more commands separated by semicolons. This
command string contains two commands: &quot;x,100&quot; and &quot;y,220&quot;. A command is made up
of a command name and a list of parameters. The command name and any parameters
are separated by commas. In the example above, both the commands &quot;x&quot; and &quot;y&quot;
both take exactly one parameter. Other commands like &quot;diffuse&quot; take 4 parameters
(R, G, B, and A). For example, the command &quot;diffuse,1,0,1,1&quot; would turn an
Actor's color to opaque purple.<br>
<br>
Typically, the metrics file will have two commands per Actor - the &quot;OnCommand&quot;
(which is where you command an Actor to tween onto the screen), and the &quot;OffCommand&quot;
(for tweening the Actor off the screen).<br>
<br>
Below is a list of actor commands and their equivalent C++ equivalents. I'll
have an explanation of animations and more examples in the full documentation.<br>
<br>
<br>
sleep BeginTweening( fParam(0), TWEEN_LINEAR );<br>
linear BeginTweening( fParam(0), TWEEN_LINEAR );<br>
accelerate BeginTweening( fParam(0), TWEEN_ACCELERATE );<br>
decelerate BeginTweening( fParam(0), TWEEN_DECELERATE );<br>
bouncebegin BeginTweening( fParam(0), TWEEN_BOUNCE_BEGIN );<br>
bounceend BeginTweening( fParam(0), TWEEN_BOUNCE_END );<br>
spring BeginTweening( fParam(0), TWEEN_SPRING );<br>
stoptweening { StopTweening(); BeginTweening( 0.0001f, TWEEN_LINEAR ); }<br>
x SetX( fParam(0) );<br>
y SetY( fParam(0) );<br>
xoffset SetX( GetX()+fParam(0) );<br>
yoffset SetY( GetY()+fParam(0) );<br>
zoom SetZoom( fParam(0) );<br>
zoomx SetZoomY( fParam(0) );<br>
zoomy SetZoomY( fParam(0) );<br>
diffuse SetDiffuse( RageColor(fParam(0),fParam(1),fParam(2),fParam(3)) );<br>
glow SetGlow( RageColor(fParam(0),fParam(1),fParam(2),fParam(3)) );<br>
rotationx SetRotationX( fParam(0) );<br>
rotationy SetRotationY( fParam(0) );<br>
rotationz SetRotationZ( fParam(0) );<br>
shadowlength SetShadowLength( fParam(0) );<br>
horizalign SetHorizAlign( sParam(0) );<br>
vertalign SetVertAlign( sParam(0) );<br>
diffuseblink SetEffectDiffuseBlink();<br>
diffuseshift SetEffectDiffuseShift();<br>
glowblink SetEffectGlowBlink();<br>
glowshift SetEffectGlowShift();<br>
wag SetEffectWag();<br>
bounce SetEffectBounce();<br>
bob SetEffectBob();<br>
spin SetEffectSpin();<br>
vibrate SetEffectVibrate();<br>
stopeffect SetEffectNone();<br>
effectcolor1 SetEffectColor1( RageColor(fParam(0),fParam(1),fParam(2),fParam(3))
);<br>
effectcolor2 SetEffectColor2( RageColor(fParam(0),fParam(1),fParam(2),fParam(3))
);<br>
effectperiod SetEffectPeriod( fParam(0) );<br>
effectmagnitude SetEffectMagnitude( RageVector3(fParam(0),fParam(1),fParam(2))
);<br>
additiveblend EnableAdditiveBlend( iParam(0)!=0 );<br>
<br>
<br>
&nbsp;</font></p>
<hr>
<p><font face="Courier New" size="2"><a name="ScreenSelect">ScreenSelect</a> (<a href="#Table of Contents">top</a>)</font></p>
<hr>
<p>
<font face="Courier New" size="2">
<br>
ScreenSelect is a type of screen that presents the user with a list of choices.
The choices shown on these screens can be Styles, Difficulties, PlayModes, or
any combination thereof. Each ScreenSelect screen has two metrics that define
what choices are shown (examples below). Currently, there are only two different
screens that support the ScreenSelect framework.<br>
- ScreenSelectMaxType1<br>
- ScreenSelectMaxType2<br>
- (more will be converted over in the next couple days)<br>
<br>
<br>
// Example 1: Show all Styles for the current game type the DDR MAX Select Style
template<br>
<br>
[ScreenSelectMaxType1]<br>
ChoicesType=0 // 0=styles, 1=difficulties, 2=modes, 3=games<br>
Choices=<br>
<br>
<br>
// Example 2: Show specific Difficulty and PlayMode choices using a DDR MAX
Select Difficulty template<br>
<br>
[ScreenSelectMaxType2]<br>
ChoicesType=1 // 0=styles, 1=difficulties, 2=modes, 3=games<br>
Choices=Beginner,Easy,Medium,Hard,Nonstop,Oni,Endless<br>
<br>
<br>
// Example 3: Show specific Style-PlayMode-Difficulty combinations using a DDR
MAX Select Style template<br>
<br>
ChoicesType=2 // 0=styles, 1=difficulties, 2=modes, 3=games<br>
Choices=versus-arcade-medium,couple-arcade-medium,double-arcade-medium,single-arcade-medium,single-battle-medium,double-battle-medium,couple-battle-medium,versus-battle-medium<br>
<br>
<br>
<br>
<br>
<br>
&nbsp;</font></p>
<hr>
<font face="Courier New" size="2">
<a name="How StepMania Loads Textures">How StepMania Loads Textures</a> (<a href="#Table of Contents">top</a>)</font><hr>
<font face="Courier New" size="2">
+4 -4
View File
@@ -71,8 +71,8 @@ PrefsManager::PrefsManager()
m_bShowSelectGroup = true;
m_bShowTranslations = true;
m_bArcadeOptionsNavigation = false;
m_bSoloSingle = false; // OFF!!!!
m_iUnloadTextureDelaySeconds = 0; // disabled 60*30; // 30 mins
m_bSoloSingle = false;
m_bDelayedTextureDelete = true;
m_MusicWheelUsesSections = ALWAYS;
m_iMusicWheelSwitchSpeed = 10;
m_bChangeBannersWhenFast = false;
@@ -163,7 +163,7 @@ void PrefsManager::ReadGlobalPrefsFromDisk( bool bSwitchToLastPlayedGame )
ini.GetValueB( "Options", "ShowTranslations", m_bShowTranslations );
ini.GetValueB( "Options", "ArcadeOptionsNavigation", m_bArcadeOptionsNavigation );
ini.GetValue ( "Options", "DWIPath", m_DWIPath );
ini.GetValueI( "Options", "UnloadTextureDelaySeconds", m_iUnloadTextureDelaySeconds );
ini.GetValueB( "Options", "DelayedTextureDelete", m_bDelayedTextureDelete );
ini.GetValueI( "Options", "MusicWheelUsesSections", (int&)m_MusicWheelUsesSections );
ini.GetValueI( "Options", "MusicWheelSwitchSpeed", m_iMusicWheelSwitchSpeed );
ini.GetValueB( "Options", "ChangeBannersWhenFast", m_bChangeBannersWhenFast );
@@ -245,7 +245,7 @@ void PrefsManager::SaveGlobalPrefsToDisk()
ini.SetValueB( "Options", "ShowTranslations", m_bShowTranslations );
ini.SetValueB( "Options", "ArcadeOptionsNavigation", m_bArcadeOptionsNavigation );
ini.SetValue ( "Options", "DWIPath", m_DWIPath );
ini.SetValueI( "Options", "UnloadTextureDelaySeconds", m_iUnloadTextureDelaySeconds );
ini.SetValueB( "Options", "DelayedTextureDelete", m_bDelayedTextureDelete );
ini.SetValueI( "Options", "MusicWheelUsesSections", m_MusicWheelUsesSections );
ini.SetValueI( "Options", "MusicWheelSwitchSpeed", m_iMusicWheelSwitchSpeed );
ini.SetValueB( "Options", "ChangeBannersWhenFast", m_bChangeBannersWhenFast );
+1 -1
View File
@@ -33,7 +33,7 @@ public:
bool m_bUseBGIfNoBanner;
bool m_bHiddenSongs;
bool m_bVsync;
int m_iUnloadTextureDelaySeconds;
bool m_bDelayedTextureDelete;
bool m_bIgnoreJoyAxes;
bool m_bOnlyDedicatedMenuButtons;
+1 -1
View File
@@ -86,7 +86,7 @@ public:
const CString &GetFilePath() const { return GetID().filename; }
int m_iRefCount;
int m_iTimeOfLastUnload;
bool m_bCacheThis;
/* The ID that we were asked to load: */
const RageTextureID &GetID() const { return m_ID; }
+58 -45
View File
@@ -27,9 +27,8 @@ RageTextureManager* TEXTUREMAN = NULL;
//-----------------------------------------------------------------------------
// constructor/destructor
//-----------------------------------------------------------------------------
RageTextureManager::RageTextureManager( int iTextureColorDepth, int iSecondsBeforeUnload, int iMaxTextureResolution )
RageTextureManager::RageTextureManager()
{
SetPrefs( iTextureColorDepth, iSecondsBeforeUnload, iMaxTextureResolution );
}
RageTextureManager::~RageTextureManager()
@@ -103,21 +102,49 @@ RageTexture* RageTextureManager::LoadTexture( RageTextureID ID )
return pTexture;
}
void RageTextureManager::GCTextures()
void RageTextureManager::CacheTexture( RageTextureID ID )
{
/* If m_iSecondsBeforeUnload is 0, then we'll unload textures immediately when
* they're no longer needed, to use as little extra memory as possible, so don't
* bother checking for expired textures here. */
if(!m_iSecondsBeforeUnload) return;
RageTexture* pTexture = LoadTexture( ID );
pTexture->m_bCacheThis |= true;
UnloadTexture( pTexture );
}
static int timeLastGarbageCollect = time(NULL);
if( timeLastGarbageCollect+m_iSecondsBeforeUnload/2 > time(NULL) )
return;
void RageTextureManager::UnloadTexture( RageTexture *t )
{
t->m_iRefCount--;
ASSERT( t->m_iRefCount >= 0 );
/* Always unload movies, so we don't waste time decoding.
*
* Actually, multiple refs to a movie won't work; they should play independently,
* but they'll actually share settings. Not worth fixing, since we don't currently
* using movies for anything except BGAs (though we could).
*/
if( t->m_iRefCount==0 )
{
bool bDeleteThis = false;
if( t->IsAMovie() )
bDeleteThis = true;
if( !m_bDelayedDelete || !t->m_bCacheThis )
bDeleteThis = true;
if( bDeleteThis )
DeleteTexture( t );
}
}
void RageTextureManager::DeleteTexture( RageTexture *t )
{
ASSERT( t->m_iRefCount==0 );
LOG->Trace( "RageTextureManager: deleting '%s'.", t->GetID().filename.GetString() );
m_mapPathToTexture.erase( t->GetID() ); // remove map entry
SAFE_DELETE( t ); // free the texture
}
void RageTextureManager::GarbageCollect( GCType type )
{
// Search for old textures with refcount==0 to unload
LOG->Trace("Performing texture garbage collection");
timeLastGarbageCollect = time(NULL);
LOG->Trace("Performing texture garbage collection.");
for( std::map<RageTextureID, RageTexture*>::iterator i = m_mapPathToTexture.begin();
i != m_mapPathToTexture.end(); )
@@ -126,16 +153,25 @@ void RageTextureManager::GCTextures()
i++;
CString sPath = j->first.filename;
RageTexture* pTexture = j->second;
if( pTexture->m_iRefCount==0 &&
pTexture->m_iTimeOfLastUnload+m_iSecondsBeforeUnload < time(NULL) )
RageTexture* t = j->second;
if( t->m_iRefCount==0 )
{
SAFE_DELETE( pTexture ); // free the texture
m_mapPathToTexture.erase(j); // and remove the key in the map
bool bDeleteThis = false;
if( type==cached_textures && !m_bDelayedDelete )
bDeleteThis = true;
if( type==delayed_delete )
bDeleteThis = true;
if( bDeleteThis )
DeleteTexture( t );
}
}
}
/*
Redundant. -Chris
void RageTextureManager::UnloadTexture( RageTextureID ID )
{
@@ -155,31 +191,8 @@ void RageTextureManager::UnloadTexture( RageTextureID ID )
UnloadTexture(p->second);
//LOG->Trace( "RageTextureManager: '%s' will not be deleted. It still has %d references.", sTexturePath.GetString(), pTexture->m_iRefCount );
}
*/
void RageTextureManager::UnloadTexture( RageTexture *t )
{
t->m_iRefCount--;
t->m_iTimeOfLastUnload = time(NULL);
ASSERT( t->m_iRefCount >= 0 );
/* Always unload movies, so we don't waste time decoding.
*
* Actually, multiple refs to a movie won't work; they should play independently,
* but they'll actually share settings. Not worth fixing, since we don't currently
* using movies for anything except BGAs (though we could).
*
* Also, if texture caching is off, just remove it now instead of doing
* garbage collection. */
if( t->m_iRefCount == 0 &&
(t->IsAMovie() || !m_iSecondsBeforeUnload ))
{
// LOG->Trace( "RageTextureManager: '%s' will be deleted. It has %d references.", sTexturePath.GetString(), pTexture->m_iRefCount );
m_mapPathToTexture.erase(t->GetID()); // and remove the key in the map
SAFE_DELETE( t ); // free the texture
}
GCTextures();
}
void RageTextureManager::ReloadAll()
{
@@ -228,15 +241,15 @@ void RageTextureManager::InvalidateTextures()
}
}
bool RageTextureManager::SetPrefs( int iTextureColorDepth, int iSecondsBeforeUnload, int iMaxTextureResolution )
bool RageTextureManager::SetPrefs( int iTextureColorDepth, bool bDelayedDelete, int iMaxTextureResolution )
{
bool need_reload = false;
if(m_iSecondsBeforeUnload != iSecondsBeforeUnload ||
if( m_bDelayedDelete != bDelayedDelete ||
m_iTextureColorDepth != iTextureColorDepth ||
m_iMaxTextureResolution != iMaxTextureResolution )
need_reload = true;
m_iSecondsBeforeUnload = iSecondsBeforeUnload;
m_bDelayedDelete = bDelayedDelete;
m_iTextureColorDepth = iTextureColorDepth;
m_iMaxTextureResolution = iMaxTextureResolution;
+14 -6
View File
@@ -21,27 +21,35 @@
class RageTextureManager
{
public:
RageTextureManager( int iTextureColorDepth, int iSecsBeforeUnload, int iMaxTextureResolution );
RageTextureManager();
void Update( float fDeltaTime );
~RageTextureManager();
RageTexture* LoadTexture( RageTextureID ID );
void UnloadTexture( RageTextureID ID );
void CacheTexture( RageTextureID ID );
void UnloadTexture( RageTexture *t );
void ReloadAll();
bool SetPrefs( int iTextureColorDepth, int iSecsBeforeUnload, int iMaxTextureResolution );
bool SetPrefs( int iTextureColorDepth, bool bDelayedDelete, int iMaxTextureResolution );
int GetTextureColorDepth() { return m_iTextureColorDepth; };
bool GetDelayedDelete() { return m_bDelayedDelete; };
int GetMaxTextureResolution() { return m_iMaxTextureResolution; };
int GetSecsBeforeUnload() { return m_iSecondsBeforeUnload; };
// call this between Screens
void DeleteCachedTextures() { GarbageCollect(cached_textures); }
// call this on switch theme
void DoDelayedDelete() { GarbageCollect(delayed_delete); }
void InvalidateTextures();
protected:
void GCTextures();
void DeleteTexture( RageTexture *t );
enum GCType { cached_textures, delayed_delete };
void GarbageCollect( GCType type );
int m_iTextureColorDepth;
int m_iSecondsBeforeUnload;
bool m_bDelayedDelete;
int m_iMaxTextureResolution;
std::map<RageTextureID, RageTexture*> m_mapPathToTexture;
@@ -157,6 +157,7 @@ void ScreenAppearanceOptions::ExportOptions()
int iSelectedTheme = m_iSelectedOption[0][AO_THEME];
CString sNewTheme = m_OptionRow[AO_THEME].choices[iSelectedTheme];
THEME->SwitchTheme( sNewTheme );
TEXTUREMAN->DoDelayedDelete(); // delete all textures that don't have references
int iSelectedSkin = m_iSelectedOption[0][AO_SKIN];
CString sNewSkin = m_OptionRow[AO_SKIN].choices[iSelectedSkin];
+2 -2
View File
@@ -109,7 +109,7 @@ void ScreenGraphicOptions::ImportOptions()
case 32: m_iSelectedOption[0][GO_TEXTURE_COLOR_DEPTH] = 1; break;
}
m_iSelectedOption[0][GO_KEEP_TEXTURES_IN_MEM] = PREFSMAN->m_iUnloadTextureDelaySeconds>0 ? 1:0;
m_iSelectedOption[0][GO_KEEP_TEXTURES_IN_MEM] = PREFSMAN->m_bDelayedTextureDelete ? 1:0;
switch(PREFSMAN->m_iRefreshRate)
{
@@ -153,7 +153,7 @@ void ScreenGraphicOptions::ExportOptions()
default: ASSERT(0); PREFSMAN->m_iTextureColorDepth = 16; break;
}
PREFSMAN->m_iUnloadTextureDelaySeconds = (m_iSelectedOption[0][GO_KEEP_TEXTURES_IN_MEM] == 1) ? 1200 : 0; // 20 mins
PREFSMAN->m_bDelayedTextureDelete = (m_iSelectedOption[0][GO_KEEP_TEXTURES_IN_MEM] == 1);
if(m_iSelectedOption[0][GO_REFRESH_RATE] == 0)
PREFSMAN->m_iRefreshRate = REFRESH_DEFAULT;
+3 -1
View File
@@ -24,9 +24,9 @@
#include "RageDisplay.h"
#include "Screen.h"
#include "SongManager.h"
#include "BitmapText.h"
#include "Quad.h"
#include "RageTextureManager.h"
ScreenManager* SCREENMAN = NULL; // global and accessable from anywhere in our program
@@ -370,6 +370,8 @@ void ScreenManager::Input( const DeviceInput& DeviceI, const InputEventType type
Screen* ScreenManager::MakeNewScreen( CString sClassName )
{
TEXTUREMAN->DeleteCachedTextures();
Screen *ret = Screen::Create( sClassName );
/* Loading probably took a little while. Let's reset stats. This prevents us
+2
View File
@@ -27,6 +27,7 @@
#include "SDL_utils.h"
#include "RageSoundManager.h"
#include "CodeDetector.h"
#include "RageTextureManager.h"
#define LOGO_ON_COMMAND THEME->GetMetric("ScreenTitleMenu","LogoOnCommand")
@@ -240,6 +241,7 @@ void ScreenTitleMenu::Input( const DeviceInput& DeviceI, const InputEventType ty
THEME->NextTheme();
SCREENMAN->SystemMessage( "Theme: "+THEME->GetCurThemeName() );
SCREENMAN->SetNewScreen( "ScreenTitleMenu" );
TEXTUREMAN->DoDelayedDelete();
}
if( CodeDetector::EnteredCode(GameI.controller,CodeDetector::CODE_NEXT_ANNOUNCER) )
{
+7 -2
View File
@@ -98,7 +98,7 @@ void ApplyGraphicOptions()
bNeedReload |= TEXTUREMAN->SetPrefs(
PREFSMAN->m_iTextureColorDepth,
PREFSMAN->m_iUnloadTextureDelaySeconds,
PREFSMAN->m_bDelayedTextureDelete,
PREFSMAN->m_iMaxTextureResolution );
if( bNeedReload )
@@ -133,6 +133,7 @@ void ResetGame()
THEME->SwitchTheme( sGameName );
else
THEME->SwitchTheme( "default" );
TEXTUREMAN->DoDelayedDelete();
}
PREFSMAN->SaveGamePrefsToDisk();
@@ -297,7 +298,11 @@ int main(int argc, char* argv[])
PREFSMAN->m_iDisplayColorDepth,
PREFSMAN->m_iRefreshRate,
PREFSMAN->m_bVsync );
TEXTUREMAN = new RageTextureManager( PREFSMAN->m_iTextureColorDepth, PREFSMAN->m_iUnloadTextureDelaySeconds, PREFSMAN->m_iMaxTextureResolution );
TEXTUREMAN = new RageTextureManager();
TEXTUREMAN->SetPrefs(
PREFSMAN->m_iTextureColorDepth,
PREFSMAN->m_bDelayedTextureDelete,
PREFSMAN->m_iMaxTextureResolution );
/* Now that we've started DISPLAY, we can set up event masks. */
SDL_EventState(SDL_QUIT, SDL_ENABLE);