Self-rebuilding resource cache; init performance improvements

This commit is contained in:
Jack Andersen 2016-09-17 11:33:32 -10:00
parent 386e9445e5
commit cfb16f34f1
13 changed files with 175 additions and 127 deletions

View File

@ -8,6 +8,7 @@ namespace DataSpec
struct ITweakSlideShow : BigYAML
{
virtual const std::string& GetFont() const=0;
virtual const zeus::CColor& GetFontColor() const=0;
virtual const zeus::CColor& GetOutlineColor() const=0;
virtual float GetX54() const=0;

View File

@ -28,6 +28,7 @@
#include "Tweaks/CTweakGunRes.hpp"
#include "Tweaks/CTweakPlayer.hpp"
#include "Tweaks/CTweakCameraBob.hpp"
#include "Tweaks/CTweakSlideShow.hpp"
namespace DataSpec
{
@ -321,6 +322,8 @@ ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const PAK& pak, const PAK::En
return {ExtractTweak<CTweakPlayer>, nullptr, {_S(".yaml")}};
if (!name.compare("CameraBob"))
return {ExtractTweak<CTweakCameraBob>, nullptr, {_S(".yaml")}};
if (!name.compare("SlideShow"))
return {ExtractTweak<CTweakSlideShow>, nullptr, {_S(".yaml")}};
}
break;
}

View File

@ -33,6 +33,7 @@ struct CTweakSlideShow : ITweakSlideShow
CTweakSlideShow() = default;
CTweakSlideShow(athena::io::IStreamReader& in) { read(in); }
const std::string& GetFont() const { return x14_fontAssetName; }
const zeus::CColor& GetFontColor() const { return x24_fontColor; }
const zeus::CColor& GetOutlineColor() const { return x28_outlineColor; }
float GetX54() const { return x54_; }

View File

@ -7,12 +7,44 @@ namespace urde
{
static logvisor::Module Log("urde::ProjectResourceFactoryBase");
static void WriteTag(athena::io::YAMLDocWriter& cacheWriter,
const SObjectTag& pathTag, const hecl::ProjectPath& path)
{
char idStr[9];
snprintf(idStr, 9, "%08X", uint32_t(pathTag.id));
cacheWriter.enterSubVector(idStr);
cacheWriter.writeString(nullptr, pathTag.type.toString().c_str());
cacheWriter.writeString(nullptr, path.getRelativePathUTF8().c_str());
if (path.getAuxInfo().size())
cacheWriter.writeString(nullptr, path.getAuxInfoUTF8().c_str());
cacheWriter.leaveSubVector();
}
static void WriteNameTag(athena::io::YAMLDocWriter& nameWriter,
const SObjectTag& pathTag,
const std::string& name)
{
char idStr[9];
snprintf(idStr, 9, "%08X", uint32_t(pathTag.id));
nameWriter.writeString(name.c_str(), idStr);
}
void ProjectResourceFactoryBase::Clear()
{
m_tagToPath.clear();
m_pathToTag.clear();
m_catalogNameToTag.clear();
}
SObjectTag ProjectResourceFactoryBase::TagFromPath(const hecl::ProjectPath& path,
hecl::BlenderToken& btok) const
{
auto search = m_pathToTag.find(path.hash());
if (search != m_pathToTag.cend())
return search->second;
return BuildTagFromPath(path, btok);
}
void ProjectResourceFactoryBase::ReadCatalog(const hecl::ProjectPath& catalogPath,
athena::io::YAMLDocWriter& nameWriter)
{
@ -28,18 +60,19 @@ void ProjectResourceFactoryBase::ReadCatalog(const hecl::ProjectPath& catalogPat
const athena::io::YAMLNode* root = reader.getRootNode();
for (const auto& p : root->m_mapChildren)
{
/* Avoid redundant filesystem access for re-caches */
if (m_catalogNameToTag.find(p.first) != m_catalogNameToTag.cend())
continue;
hecl::ProjectPath path(m_proj->getProjectWorkingPath(), p.second->m_scalarString);
if (path.getPathType() != hecl::ProjectPath::Type::File)
continue;
SObjectTag pathTag = TagFromPath(path, m_backgroundBlender);
if (pathTag)
{
{
std::unique_lock<std::mutex> lk(m_backgroundIndexMutex);
m_catalogNameToTag[p.first] = pathTag;
char idStr[9];
snprintf(idStr, 9, "%08X", uint32_t(pathTag.id));
nameWriter.writeString(p.first.c_str(), idStr);
WriteNameTag(nameWriter, pathTag, p.first);
#if 0
fprintf(stderr, "%s %s %08X\n",
p.first.c_str(),
@ -82,19 +115,6 @@ void ProjectResourceFactoryBase::BackgroundIndexRecursiveCatalogs(const hecl::Pr
}
}
static void WriteTag(athena::io::YAMLDocWriter& cacheWriter,
const SObjectTag& pathTag, const hecl::ProjectPath& path)
{
char idStr[9];
snprintf(idStr, 9, "%08X", uint32_t(pathTag.id));
cacheWriter.enterSubVector(idStr);
cacheWriter.writeString(nullptr, pathTag.type.toString().c_str());
cacheWriter.writeString(nullptr, path.getRelativePathUTF8().c_str());
if (path.getAuxInfo().size())
cacheWriter.writeString(nullptr, path.getAuxInfoUTF8().c_str());
cacheWriter.leaveSubVector();
}
#if DUMP_CACHE_FILL
static void DumpCacheAdd(const SObjectTag& pathTag, const hecl::ProjectPath& path)
{
@ -104,6 +124,81 @@ static void DumpCacheAdd(const SObjectTag& pathTag, const hecl::ProjectPath& pat
}
#endif
bool ProjectResourceFactoryBase::AddFileToIndex(const hecl::ProjectPath& path,
athena::io::YAMLDocWriter& cacheWriter)
{
/* Avoid redundant filesystem access for re-caches */
if (m_pathToTag.find(path.hash()) != m_pathToTag.cend())
return true;
/* Classify intermediate into tag */
SObjectTag pathTag = BuildTagFromPath(path, m_backgroundBlender);
if (pathTag)
{
std::unique_lock<std::mutex> lk(m_backgroundIndexMutex);
m_tagToPath[pathTag] = path;
m_pathToTag[path.hash()] = pathTag;
WriteTag(cacheWriter, pathTag, path);
#if DUMP_CACHE_FILL
DumpCacheAdd(pathTag, path);
#endif
/* Special multi-resource intermediates */
if (pathTag.type == SBIG('ANCS'))
{
hecl::BlenderConnection& conn = m_backgroundBlender.getBlenderConnection();
if (!conn.openBlend(path) || conn.getBlendType() != hecl::BlenderConnection::BlendType::Actor)
return false;
hecl::BlenderConnection::DataStream ds = conn.beginData();
std::vector<std::string> armatureNames = ds.getArmatureNames();
std::vector<std::string> subtypeNames = ds.getSubtypeNames();
std::vector<std::string> actionNames = ds.getActionNames();
for (const std::string& arm : armatureNames)
{
hecl::SystemStringView sysStr(arm);
hecl::ProjectPath subPath = path.ensureAuxInfo(sysStr.sys_str() + _S(".CINF"));
SObjectTag pathTag = BuildTagFromPath(subPath, m_backgroundBlender);
m_tagToPath[pathTag] = subPath;
m_pathToTag[subPath.hash()] = pathTag;
WriteTag(cacheWriter, pathTag, subPath);
#if DUMP_CACHE_FILL
DumpCacheAdd(pathTag, subPath);
#endif
}
for (const std::string& sub : subtypeNames)
{
hecl::SystemStringView sysStr(sub);
hecl::ProjectPath subPath = path.ensureAuxInfo(sysStr.sys_str() + _S(".CSKR"));
SObjectTag pathTag = BuildTagFromPath(subPath, m_backgroundBlender);
m_tagToPath[pathTag] = subPath;
m_pathToTag[subPath.hash()] = pathTag;
WriteTag(cacheWriter, pathTag, subPath);
#if DUMP_CACHE_FILL
DumpCacheAdd(pathTag, subPath);
#endif
}
for (const std::string& act : actionNames)
{
hecl::SystemStringView sysStr(act);
hecl::ProjectPath subPath = path.ensureAuxInfo(sysStr.sys_str() + _S(".ANIM"));
SObjectTag pathTag = BuildTagFromPath(subPath, m_backgroundBlender);
m_tagToPath[pathTag] = subPath;
m_pathToTag[subPath.hash()] = pathTag;
WriteTag(cacheWriter, pathTag, subPath);
#if DUMP_CACHE_FILL
DumpCacheAdd(pathTag, subPath);
#endif
}
}
}
return true;
}
void ProjectResourceFactoryBase::BackgroundIndexRecursiveProc(const hecl::ProjectPath& dir,
athena::io::YAMLDocWriter& cacheWriter,
athena::io::YAMLDocWriter& nameWriter,
@ -131,66 +226,7 @@ void ProjectResourceFactoryBase::BackgroundIndexRecursiveProc(const hecl::Projec
continue;
}
/* Classify intermediate into tag */
SObjectTag pathTag = TagFromPath(path, m_backgroundBlender);
if (pathTag)
{
std::unique_lock<std::mutex> lk(m_backgroundIndexMutex);
m_tagToPath[pathTag] = path;
WriteTag(cacheWriter, pathTag, path);
#if DUMP_CACHE_FILL
DumpCacheAdd(pathTag, path);
#endif
/* Special multi-resource intermediates */
if (pathTag.type == SBIG('ANCS'))
{
hecl::BlenderConnection& conn = m_backgroundBlender.getBlenderConnection();
if (!conn.openBlend(path) || conn.getBlendType() != hecl::BlenderConnection::BlendType::Actor)
continue;
hecl::BlenderConnection::DataStream ds = conn.beginData();
std::vector<std::string> armatureNames = ds.getArmatureNames();
std::vector<std::string> subtypeNames = ds.getSubtypeNames();
std::vector<std::string> actionNames = ds.getActionNames();
for (const std::string& arm : armatureNames)
{
hecl::SystemStringView sysStr(arm);
hecl::ProjectPath subPath = path.ensureAuxInfo(sysStr.sys_str() + _S(".CINF"));
SObjectTag pathTag = TagFromPath(subPath, m_backgroundBlender);
m_tagToPath[pathTag] = subPath;
WriteTag(cacheWriter, pathTag, subPath);
#if DUMP_CACHE_FILL
DumpCacheAdd(pathTag, subPath);
#endif
}
for (const std::string& sub : subtypeNames)
{
hecl::SystemStringView sysStr(sub);
hecl::ProjectPath subPath = path.ensureAuxInfo(sysStr.sys_str() + _S(".CSKR"));
SObjectTag pathTag = TagFromPath(subPath, m_backgroundBlender);
m_tagToPath[pathTag] = subPath;
WriteTag(cacheWriter, pathTag, subPath);
#if DUMP_CACHE_FILL
DumpCacheAdd(pathTag, subPath);
#endif
}
for (const std::string& act : actionNames)
{
hecl::SystemStringView sysStr(act);
hecl::ProjectPath subPath = path.ensureAuxInfo(sysStr.sys_str() + _S(".ANIM"));
SObjectTag pathTag = TagFromPath(subPath, m_backgroundBlender);
m_tagToPath[pathTag] = subPath;
WriteTag(cacheWriter, pathTag, subPath);
#if DUMP_CACHE_FILL
DumpCacheAdd(pathTag, subPath);
#endif
}
}
}
AddFileToIndex(path, cacheWriter);
}
/* bail if cancelled by client */
@ -205,6 +241,10 @@ void ProjectResourceFactoryBase::BackgroundIndexProc()
hecl::ProjectPath nameCachePath(m_proj->getProjectCookedPath(*m_origSpec), _S("name_cache.yaml"));
hecl::ProjectPath specRoot(m_proj->getProjectWorkingPath(), m_origSpec->m_name);
/* Cache will be overwritten with validated entries afterwards */
athena::io::YAMLDocWriter cacheWriter(nullptr);
athena::io::YAMLDocWriter nameWriter(nullptr);
/* Read in tag cache */
if (tagCachePath.getPathType() == hecl::ProjectPath::Type::File)
{
@ -216,7 +256,9 @@ void ProjectResourceFactoryBase::BackgroundIndexProc()
if (cacheReader.parse(&reader))
{
std::unique_lock<std::mutex> lk(m_backgroundIndexMutex);
m_tagToPath.reserve(cacheReader.getRootNode()->m_mapChildren.size());
size_t tagCount = cacheReader.getRootNode()->m_mapChildren.size();
m_tagToPath.reserve(tagCount);
m_pathToTag.reserve(tagCount);
size_t loadIdx = 0;
for (const auto& child : cacheReader.getRootNode()->m_mapChildren)
{
@ -230,7 +272,14 @@ void ProjectResourceFactoryBase::BackgroundIndexProc()
hecl::SystemStringView sys(node.m_seqChildren[2]->m_scalarString);
path = path.ensureAuxInfo(sys.sys_str());
}
m_tagToPath[SObjectTag(type, id)] = path;
if (path.getPathType() == hecl::ProjectPath::Type::File)
{
SObjectTag pathTag(type, id);
m_tagToPath[pathTag] = path;
m_pathToTag[path.hash()] = pathTag;
WriteTag(cacheWriter, pathTag, path);
}
fprintf(stderr, "\r %" PRISize " / %" PRISize, ++loadIdx,
cacheReader.getRootNode()->m_mapChildren.size());
}
@ -254,31 +303,19 @@ void ProjectResourceFactoryBase::BackgroundIndexProc()
unsigned long id = strtoul(child.second->m_scalarString.c_str(), nullptr, 16);
auto search = m_tagToPath.find(SObjectTag(FourCC(), uint32_t(id)));
if (search != m_tagToPath.cend())
{
m_catalogNameToTag[child.first] = search->first;
WriteNameTag(nameWriter, search->first, child.first);
}
}
}
Log.report(logvisor::Info, _S("Name index of '%s' loaded; %d names"),
m_origSpec->m_name, m_catalogNameToTag.size());
}
else
{
/* Build name cache */
Log.report(logvisor::Info, _S("Name index of '%s' started"), m_origSpec->m_name);
athena::io::YAMLDocWriter nameWriter(nullptr);
BackgroundIndexRecursiveCatalogs(specRoot, nameWriter, 0);
athena::io::FileWriter nwriter(nameCachePath.getAbsolutePath());
nameWriter.finish(&nwriter);
Log.report(logvisor::Info, _S("Name index of '%s' complete; %d names"),
m_origSpec->m_name, m_catalogNameToTag.size());
}
m_backgroundRunning = false;
return;
}
}
Log.report(logvisor::Info, _S("Background index of '%s' started"), m_origSpec->m_name);
athena::io::YAMLDocWriter cacheWriter(nullptr);
athena::io::YAMLDocWriter nameWriter(nullptr);
BackgroundIndexRecursiveProc(specRoot, cacheWriter, nameWriter, 0);
tagCachePath.makeDirChain(false);

View File

@ -62,6 +62,7 @@ public:
protected:
std::unordered_map<urde::SObjectTag, hecl::ProjectPath> m_tagToPath;
std::unordered_map<hecl::Hash, urde::SObjectTag> m_pathToTag;
std::unordered_map<std::string, urde::SObjectTag> m_catalogNameToTag;
void Clear();
@ -85,10 +86,13 @@ protected:
const hecl::ProjectPath& path,
std::experimental::optional<athena::io::FileReader>& fr);
virtual SObjectTag TagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const=0;
SObjectTag TagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const;
virtual SObjectTag BuildTagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const=0;
void ReadCatalog(const hecl::ProjectPath& catalogPath,
athena::io::YAMLDocWriter& nameWriter);
bool AddFileToIndex(const hecl::ProjectPath& path,
athena::io::YAMLDocWriter& cacheWriter);
void BackgroundIndexRecursiveProc(const hecl::ProjectPath& path,
athena::io::YAMLDocWriter& cacheWriter,
athena::io::YAMLDocWriter& nameWriter,

View File

@ -55,7 +55,7 @@ void ProjectResourceFactoryMP1::IndexMP1Resources(hecl::Database::Project& proj)
BeginBackgroundIndex(proj, DataSpec::SpecEntMP1, DataSpec::SpecEntMP1PC);
}
SObjectTag ProjectResourceFactoryMP1::TagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const
SObjectTag ProjectResourceFactoryMP1::BuildTagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const
{
if (hecl::StringUtils::EndsWith(path.getAuxInfo(), _S(".CINF")))
return SObjectTag(SBIG('CINF'), path.hash().val32());

View File

@ -11,7 +11,7 @@ class ProjectResourceFactoryMP1 : public ProjectResourceFactoryBase
public:
ProjectResourceFactoryMP1(hecl::ClientProcess& clientProc);
void IndexMP1Resources(hecl::Database::Project& proj);
SObjectTag TagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const;
SObjectTag BuildTagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const;
};
}

View File

@ -9,9 +9,9 @@ namespace urde
static const char* SplashTextures[]
{
"MP1/NoARAM/TXTR_NintendoLogo.png",
"MP1/NoARAM/TXTR_RetroLogo.png",
"MP1/NoARAM/TXTR_DolbyLogo.png"
"TXTR_NintendoLogo",
"TXTR_RetroLogo",
"TXTR_DolbyLogo"
};
CSplashScreen::CSplashScreen(ESplashScreen which)

View File

@ -13,21 +13,23 @@ CSlideShow::CSlideShow()
x134_30_ = true;
x135_24_ = true;
const SObjectTag* font = g_ResFactory->GetResourceIdByName(g_tweakSlideShow->GetFont().c_str());
if (font)
{
CGuiTextProperties propsA(false, true, EJustification::Center, EVerticalJustification::Bottom);
xc4_textA = std::make_unique<CGuiTextSupport>(font->id, propsA,
g_tweakSlideShow->GetFontColor(),
g_tweakSlideShow->GetOutlineColor(),
zeus::CColor::skWhite, 640, 480, g_SimplePool);
/* Originally came from SlideShow tweak */
SObjectTag font = ProjectManager::g_SharedManager->TagFromPath(_S("MP1/NoARAM/FONT_Deface14B.yaml"));
CGuiTextProperties propsB(false, true, EJustification::Right, EVerticalJustification::Bottom);
xc8_textB = std::make_unique<CGuiTextSupport>(font->id, propsB,
g_tweakSlideShow->GetFontColor(),
g_tweakSlideShow->GetOutlineColor(),
zeus::CColor::skWhite, 640, 480, g_SimplePool);
}
CGuiTextProperties propsA(false, true, EJustification::Center, EVerticalJustification::Bottom);
xc4_textA = std::make_unique<CGuiTextSupport>(font.id, propsA,
g_tweakSlideShow->GetFontColor(),
g_tweakSlideShow->GetOutlineColor(),
zeus::CColor::skWhite, 640, 480, g_SimplePool);
CGuiTextProperties propsB(false, true, EJustification::Right, EVerticalJustification::Bottom);
xc8_textB = std::make_unique<CGuiTextSupport>(font.id, propsB,
g_tweakSlideShow->GetFontColor(),
g_tweakSlideShow->GetOutlineColor(),
zeus::CColor::skWhite, 640, 480, g_SimplePool);
xf8_.reserve(18);
}
CIOWin::EMessageReturn CSlideShow::OnMessage(const CArchitectureMessage& msg, CArchitectureQueue& queue)

View File

@ -34,16 +34,16 @@ void CTweaks::RegisterTweaks()
ProjectResourceFactoryMP1& factory = ProjectManager::g_SharedManager->resourceFactoryMP1();
std::experimental::optional<CMemoryInStream> strm;
SObjectTag tag = factory.ProjectResourceFactoryBase::TagFromPath(_S("MP1/Tweaks/SlideShow.yaml"));
strm.emplace(factory.LoadResourceSync(tag).release(), factory.ResourceSize(tag));
const SObjectTag* tag = factory.GetResourceIdByName("SlideShow");
strm.emplace(factory.LoadResourceSync(*tag).release(), factory.ResourceSize(*tag));
g_tweakSlideShow = new DataSpec::DNAMP1::CTweakSlideShow(*strm);
tag = factory.ProjectResourceFactoryBase::TagFromPath(_S("MP1/Tweaks/Player.yaml"));
strm.emplace(factory.LoadResourceSync(tag).release(), factory.ResourceSize(tag));
tag = factory.GetResourceIdByName("Player");
strm.emplace(factory.LoadResourceSync(*tag).release(), factory.ResourceSize(*tag));
g_tweakPlayer = new DataSpec::DNAMP1::CTweakPlayer(*strm);
tag = factory.ProjectResourceFactoryBase::TagFromPath(_S("MP1/Tweaks/CameraBob.yaml"));
strm.emplace(factory.LoadResourceSync(tag).release(), factory.ResourceSize(tag));
tag = factory.GetResourceIdByName("CameraBob");
strm.emplace(factory.LoadResourceSync(*tag).release(), factory.ResourceSize(*tag));
CPlayerCameraBob::ReadTweaks(*strm);
}
@ -52,12 +52,12 @@ void CTweaks::RegisterResourceTweaks()
ProjectResourceFactoryMP1& factory = ProjectManager::g_SharedManager->resourceFactoryMP1();
std::experimental::optional<CMemoryInStream> strm;
SObjectTag tag = factory.ProjectResourceFactoryBase::TagFromPath(_S("MP1/Tweaks/GunRes.yaml"));
strm.emplace(factory.LoadResourceSync(tag).release(), factory.ResourceSize(tag));
const SObjectTag* tag = factory.GetResourceIdByName("GunRes");
strm.emplace(factory.LoadResourceSync(*tag).release(), factory.ResourceSize(*tag));
g_tweakGunRes = new DataSpec::DNAMP1::CTweakGunRes(*strm);
tag = factory.ProjectResourceFactoryBase::TagFromPath(_S("MP1/Tweaks/PlayerRes.yaml"));
strm.emplace(factory.LoadResourceSync(tag).release(), factory.ResourceSize(tag));
tag = factory.GetResourceIdByName("PlayerRes");
strm.emplace(factory.LoadResourceSync(*tag).release(), factory.ResourceSize(*tag));
g_tweakPlayerRes = new DataSpec::DNAMP1::CTweakPlayerRes(*strm);
}

View File

@ -339,7 +339,7 @@ void CWorldTransManager::EnableTransition(const CAnimRes& samusRes,
const std::string& modelName = g_tweakPlayerRes->GetBeamCineModel(
DataSpec::ITweakPlayerRes::EBeamId(g_GameState->GetPlayerState()->GetCurrentBeam()));
x4_modelData->x14c_beamModel = g_SimplePool->GetObj(("MP1/TestAnim/" + modelName + ".blend").c_str());
x4_modelData->x14c_beamModel = g_SimplePool->GetObj(modelName.c_str());
TToken<CCharacterFactory> fac = g_CharFactoryBuilder->GetFactory(samusRes);
const CCharacterInfo& info = fac.GetObj()->GetCharInfo(GetSuitCharIdx());

2
hecl

@ -1 +1 @@
Subproject commit 83dee4423b5d4c5906357d63e90bb70c8230e8bd
Subproject commit 41c2107a921e238660b63f5042a13588d68ef7a3

2
nod

@ -1 +1 @@
Subproject commit 4a265986098adc10d5505dc3f39acbc30fa35853
Subproject commit 9d6b6ceb718a403da594d37480c3a941e045a1f2