Merge pull request #14923 from unknownbrackets/ui-savedata

Reduce IO in savedata screen sorting, move to async
This commit is contained in:
Henrik Rydgård
2021-09-24 09:09:07 +02:00
committed by GitHub
2 changed files with 89 additions and 42 deletions
+86 -41
View File
@@ -138,32 +138,49 @@ private:
class SortedLinearLayout : public UI::LinearLayoutList {
public:
typedef std::function<void(View *)> PrepFunc;
typedef std::function<bool(const View *, const View *)> CompareFunc;
typedef std::function<bool()> DoneFunc;
SortedLinearLayout(UI::Orientation orientation, UI::LayoutParams *layoutParams = nullptr)
: UI::LinearLayoutList(orientation, layoutParams) {
}
void SetCompare(CompareFunc lessFunc, DoneFunc doneFunc) {
void SetCompare(const PrepFunc &prepFunc, const CompareFunc &lessFunc) {
prepIndex_ = 0;
prepFunc_ = prepFunc;
lessFunc_ = lessFunc;
doneFunc_ = doneFunc;
}
void Update() override;
private:
size_t prepIndex_ = 0;
PrepFunc prepFunc_;
CompareFunc lessFunc_;
DoneFunc doneFunc_;
};
void SortedLinearLayout::Update() {
if (prepFunc_) {
// Try to avoid dropping more than a frame, prefer items shift.
constexpr double ALLOWED_TIME = 0.95 / 60.0;
double start_time = time_now_d();
for (; prepIndex_ < views_.size(); ++prepIndex_) {
prepFunc_(views_[prepIndex_]);
if (time_now_d() > start_time + ALLOWED_TIME) {
break;
}
}
}
if (lessFunc_) {
// We may sort several times while calculating.
std::stable_sort(views_.begin(), views_.end(), lessFunc_);
}
if (doneFunc_ && doneFunc_()) {
// We're done if we got through all items.
if (prepIndex_ >= views_.size()) {
prepFunc_ = PrepFunc();
lessFunc_ = CompareFunc();
}
UI::LinearLayout::Update();
}
@@ -184,14 +201,57 @@ public:
const Path &GamePath() const { return savePath_; }
uint64_t GetTotalSize() const {
return totalSize_;
}
int64_t GetDateSeconds() const {
return dateSeconds_;
}
void UpdateTotalSize();
void UpdateDateSeconds();
private:
void UpdateText(const std::shared_ptr<GameInfo> &ginfo);
Path savePath_;
std::string title_;
std::string subtitle_;
uint64_t totalSize_ = 0;
int64_t dateSeconds_ = 0;
bool hasTotalSize_ = false;
bool hasDateSeconds_ = false;
};
void SavedataButton::UpdateTotalSize() {
if (hasTotalSize_)
return;
File::FileInfo info;
if (File::GetFileInfo(savePath_, &info)) {
totalSize_ = info.size;
if (info.isDirectory)
totalSize_ = File::ComputeRecursiveDirectorySize(savePath_);
}
hasTotalSize_ = true;
}
void SavedataButton::UpdateDateSeconds() {
if (hasDateSeconds_)
return;
File::FileInfo info;
if (File::GetFileInfo(savePath_, &info)) {
dateSeconds_ = info.mtime;
if (info.isDirectory && File::GetFileInfo(savePath_ / "PARAM.SFO", &info)) {
dateSeconds_ = info.mtime;
}
}
hasDateSeconds_ = true;
}
UI::EventReturn SavedataPopupScreen::OnDeleteButtonClick(UI::EventParams &e) {
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(nullptr, savePath_, GAMEINFO_WANTSIZE);
ginfo->Delete();
@@ -408,15 +468,19 @@ void SavedataBrowser::SetSortOption(SavedataSortOption opt) {
if (gameList_) {
SortedLinearLayout *gl = static_cast<SortedLinearLayout *>(gameList_);
if (sortOption_ == SavedataSortOption::FILENAME) {
gl->SetCompare(&ByFilename, &SortDone);
gl->SetCompare(&PrepFilename, &ByFilename);
} else if (sortOption_ == SavedataSortOption::SIZE) {
gl->SetCompare(&BySize, &SortDone);
gl->SetCompare(&PrepSize, &BySize);
} else if (sortOption_ == SavedataSortOption::DATE) {
gl->SetCompare(&ByDate, &SortDone);
gl->SetCompare(&PrepDate, &ByDate);
}
}
}
void SavedataBrowser::PrepFilename(UI::View *v) {
// Nothing needed.
}
bool SavedataBrowser::ByFilename(const UI::View *v1, const UI::View *v2) {
const SavedataButton *b1 = static_cast<const SavedataButton *>(v1);
const SavedataButton *b2 = static_cast<const SavedataButton *>(v2);
@@ -424,61 +488,42 @@ bool SavedataBrowser::ByFilename(const UI::View *v1, const UI::View *v2) {
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
}
static time_t GetTotalSize(const SavedataButton *b) {
auto fileLoader = std::unique_ptr<FileLoader>(ConstructFileLoader(b->GamePath()));
std::string errorString;
switch (Identify_File(fileLoader.get(), &errorString)) {
case IdentifiedFileType::PSP_PBP_DIRECTORY:
case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY:
return File::ComputeRecursiveDirectorySize(ResolvePBPDirectory(b->GamePath()));
default:
return fileLoader->FileSize();
}
void SavedataBrowser::PrepSize(UI::View *v) {
SavedataButton *b = static_cast<SavedataButton *>(v);
b->UpdateTotalSize();
}
bool SavedataBrowser::BySize(const UI::View *v1, const UI::View *v2) {
const SavedataButton *b1 = static_cast<const SavedataButton *>(v1);
const SavedataButton *b2 = static_cast<const SavedataButton *>(v2);
const uint64_t size1 = b1->GetTotalSize();
const uint64_t size2 = b2->GetTotalSize();
if (GetTotalSize(b1) > GetTotalSize(b2))
if (size1 > size2)
return true;
else if (GetTotalSize(b1) < GetTotalSize(b2))
else if (size1 < size2)
return false;
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
}
static time_t GetDateSeconds(const SavedataButton *b) {
auto fileLoader = std::unique_ptr<FileLoader>(ConstructFileLoader(b->GamePath()));
tm datetm;
bool success;
std::string errorString;
if (Identify_File(fileLoader.get(), &errorString) == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) {
success = File::GetModifTime(b->GamePath() / "PARAM.SFO", datetm);
} else {
success = File::GetModifTime(b->GamePath(), datetm);
}
if (success) {
return mktime(&datetm);
}
return (time_t)0;
void SavedataBrowser::PrepDate(UI::View *v) {
SavedataButton *b = static_cast<SavedataButton *>(v);
b->UpdateDateSeconds();
}
bool SavedataBrowser::ByDate(const UI::View *v1, const UI::View *v2) {
const SavedataButton *b1 = static_cast<const SavedataButton *>(v1);
const SavedataButton *b2 = static_cast<const SavedataButton *>(v2);
const int64_t time1 = b1->GetDateSeconds();
const int64_t time2 = b2->GetDateSeconds();
if (GetDateSeconds(b1) > GetDateSeconds(b2))
if (time1 > time2)
return true;
if (GetDateSeconds(b1) < GetDateSeconds(b2))
if (time1 < time2)
return false;
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
}
bool SavedataBrowser::SortDone() {
return true;
}
void SavedataBrowser::Refresh() {
using namespace UI;
+3 -1
View File
@@ -46,10 +46,12 @@ public:
UI::Event OnChoice;
private:
static void PrepFilename(UI::View *);
static void PrepSize(UI::View *);
static void PrepDate(UI::View *);
static bool ByFilename(const UI::View *, const UI::View *);
static bool BySize(const UI::View *, const UI::View *);
static bool ByDate(const UI::View *, const UI::View *);
static bool SortDone();
void Refresh();
UI::EventReturn SavedataButtonClick(UI::EventParams &e);