Permalink
Browse files

Merge pull request #10496 from unknownbrackets/cpu-bgstart

Core: Asynchronously load the main ELF
  • Loading branch information...
hrydgard committed Jan 2, 2018
2 parents 3b9d001 + 9952d4b commit 690a409dac6ee31ed08d7b2496017282543caed8
Showing with 103 additions and 20 deletions.
  1. +38 −3 Core/PSPLoaders.cpp
  2. +4 −3 Core/System.cpp
  3. +55 −9 UI/EmuScreen.cpp
  4. +1 −1 UI/EmuScreen.h
  5. +4 −3 UI/ReportScreen.cpp
  6. +1 −1 ext/native/ui/view.cpp
View
@@ -15,6 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <thread>
#include "file/file_util.h"
#include "util/text/utf8.h"
@@ -250,7 +251,20 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) {
g_Config.loadGameConfig(id);
host->SendUIMessage("config_loaded", "");
INFO_LOG(LOADER,"Loading %s...", bootpath.c_str());
return __KernelLoadExec(bootpath.c_str(), 0, error_string);
std::thread th([bootpath] {
// TODO: We can't use the initial error_string pointer.
bool success = __KernelLoadExec(bootpath.c_str(), 0, &PSP_CoreParameter().errorString);
if (success && coreState == CORE_POWERUP) {
coreState = PSP_CoreParameter().startPaused ? CORE_STEPPING : CORE_RUNNING;
} else {
coreState = CORE_ERROR;
// TODO: This is a crummy way to communicate the error...
PSP_CoreParameter().fileToStart = "";
}
});
th.detach();
return true;
}
static std::string NormalizePath(const std::string &path) {
@@ -354,13 +368,34 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) {
}
// End of temporary code
return __KernelLoadExec(finalName.c_str(), 0, error_string);
std::thread th([finalName] {
bool success = __KernelLoadExec(finalName.c_str(), 0, &PSP_CoreParameter().errorString);
if (success && coreState == CORE_POWERUP) {
coreState = PSP_CoreParameter().startPaused ? CORE_STEPPING : CORE_RUNNING;
} else {
coreState = CORE_ERROR;
// TODO: This is a crummy way to communicate the error...
PSP_CoreParameter().fileToStart = "";
}
});
th.detach();
return true;
}
bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) {
BlobFileSystem *umd = new BlobFileSystem(&pspFileSystem, fileLoader, "data.ppdmp");
pspFileSystem.Mount("disc0:", umd);
__KernelLoadGEDump("disc0:/data.ppdmp", error_string);
std::thread th([] {
bool success = __KernelLoadGEDump("disc0:/data.ppdmp", &PSP_CoreParameter().errorString);
if (success && coreState == CORE_POWERUP) {
coreState = PSP_CoreParameter().startPaused ? CORE_STEPPING : CORE_RUNNING;
} else {
coreState = CORE_ERROR;
// TODO: This is a crummy way to communicate the error...
PSP_CoreParameter().fileToStart = "";
}
});
th.detach();
return true;
}
View
@@ -181,6 +181,8 @@ bool CPU_NextStateNot(CPUThreadState from, CPUThreadState to) {
}
bool CPU_IsReady() {
if (coreState == CORE_POWERUP)
return false;
return cpuThreadState == CPU_THREAD_RUNNING || cpuThreadState == CPU_THREAD_NOT_RUNNING;
}
@@ -270,7 +272,8 @@ void CPU_Init() {
// TODO: Check Game INI here for settings, patches and cheats, and modify coreParameter accordingly
// Why did we check for CORE_POWERDOWN here?
// If they shut down early, we'll catch it when load completes.
// Note: this may return before init is complete, which is checked if CPU_IsReady().
if (!LoadFile(&loadedFile, &coreParameter.errorString)) {
CPU_Shutdown();
coreParameter.fileToStart = "";
@@ -282,8 +285,6 @@ void CPU_Init() {
if (coreParameter.updateRecent) {
g_Config.AddRecent(filename);
}
coreState = coreParameter.startPaused ? CORE_STEPPING : CORE_RUNNING;
}
void CPU_Shutdown() {
View
@@ -231,17 +231,15 @@ void EmuScreen::bootGame(const std::string &filename) {
host->NotifyUserMessage(gr->T("DefaultCPUClockRequired", "Warning: This game requires the CPU clock to be set to default."), 15.0f);
}
loadingViewColor_->Divert(0xFFFFFFFF, 0.15f);
loadingViewVisible_->Divert(UI::V_VISIBLE, 0.15f);
loadingViewColor_->Divert(0xFFFFFFFF, 0.75f);
loadingViewVisible_->Divert(UI::V_VISIBLE, 0.75f);
}
void EmuScreen::bootComplete() {
UpdateUIState(UISTATE_INGAME);
host->BootDone();
host->UpdateDisassembly();
g_gameInfoCache->FlushBGs();
NOTICE_LOG(BOOT, "Loading %s...", PSP_CoreParameter().fileToStart.c_str());
autoLoad();
@@ -811,6 +809,37 @@ void EmuScreen::processAxis(const AxisInput &axis, int direction) {
}
}
class GameInfoBGView : public UI::InertView {
public:
GameInfoBGView(const std::string &gamePath, UI::LayoutParams *layoutParams) : InertView(layoutParams), gamePath_(gamePath) {
}
void Draw(UIContext &dc) {
// Should only be called when visible.
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(dc.GetDrawContext(), gamePath_, GAMEINFO_WANTBG);
dc.Flush();
// PIC1 is the loading image, so let's only draw if it's available.
if (ginfo && ginfo->pic1.texture) {
dc.GetDrawContext()->BindTexture(0, ginfo->pic1.texture->GetTexture());
double loadTime = ginfo->pic1.timeLoaded;
uint32_t color = alphaMul(color_, ease((time_now_d() - loadTime) * 3));
dc.Draw()->DrawTexRect(dc.GetBounds(), 0, 0, 1, 1, color);
dc.Flush();
dc.RebindTexture();
}
}
void SetColor(uint32_t c) {
color_ = c;
}
protected:
std::string gamePath_;
uint32_t color_ = 0xFFC0C0C0;
};
void EmuScreen::CreateViews() {
using namespace UI;
@@ -831,14 +860,31 @@ void EmuScreen::CreateViews() {
root_->Add(saveStatePreview_);
root_->Add(new OnScreenMessagesView(new AnchorLayoutParams((Size)bounds.w, (Size)bounds.h)));
loadingView_ = new TextView(sc->T("Loading game..."), new AnchorLayoutParams(bounds.centerX(), bounds.centerY(), NONE, NONE, true));
root_->Add(loadingView_);
GameInfoBGView *loadingBG = root_->Add(new GameInfoBGView(gamePath_, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT)));
TextView *loadingTextView = root_->Add(new TextView(sc->T("Loading game..."), new AnchorLayoutParams(bounds.centerX(), bounds.centerY(), NONE, NONE, true)));
loadingTextView->SetShadow(true);
loadingView_ = loadingTextView;
// We start invisible here, in case of recreated views.
loadingViewColor_ = loadingView_->AddTween(new TextColorTween(0x00FFFFFF, 0x00FFFFFF, 0.2f, &bezierEaseInOut));
loadingViewColor_ = loadingTextView->AddTween(new CallbackColorTween(0x00FFFFFF, 0x00FFFFFF, 0.2f, &bezierEaseInOut));
loadingViewColor_->SetCallback([loadingBG, loadingTextView](View *v, uint32_t c) {
loadingBG->SetColor(c & 0xFFC0C0C0);
loadingTextView->SetTextColor(c);
});
loadingViewColor_->Persist();
loadingViewVisible_ = loadingView_->AddTween(new VisibilityTween(UI::V_INVISIBLE, UI::V_INVISIBLE, 0.2f, &bezierEaseInOut));
// We start invisible here, in case of recreated views.
loadingViewVisible_ = loadingTextView->AddTween(new VisibilityTween(UI::V_INVISIBLE, UI::V_INVISIBLE, 0.2f, &bezierEaseInOut));
loadingViewVisible_->Persist();
loadingViewVisible_->Finish.Add([loadingBG](EventParams &p) {
loadingBG->SetVisibility(p.v->GetVisibility());
// If we just became invisible, flush BGs since we don't need them anymore.
// Saves some VRAM for the game, but don't do it before we fade out...
if (p.v->GetVisibility() == V_INVISIBLE) {
g_gameInfoCache->FlushBGs();
}
return EVENT_DONE;
});
}
UI::EventReturn EmuScreen::OnDevTools(UI::EventParams &params) {
View
@@ -99,6 +99,6 @@ class EmuScreen : public UIScreen {
int saveStateSlot_;
UI::View *loadingView_ = nullptr;
UI::TextColorTween *loadingViewColor_ = nullptr;
UI::CallbackColorTween *loadingViewColor_ = nullptr;
UI::VisibilityTween *loadingViewVisible_ = nullptr;
};
View
@@ -62,11 +62,11 @@ class RatingChoice : public LinearLayout {
RatingChoice::RatingChoice(const char *captionKey, int *value, LayoutParams *layoutParams)
: LinearLayout(ORIENT_VERTICAL, layoutParams), value_(value) {
SetSpacing(-8.0f);
SetSpacing(0.0f);
I18NCategory *rp = GetI18NCategory("Reporting");
group_ = new LinearLayout(ORIENT_HORIZONTAL);
Add(new InfoItem(rp->T(captionKey), ""));
Add(new TextView(rp->T(captionKey)))->SetShadow(true);
Add(group_);
group_->SetSpacing(0.0f);
@@ -223,7 +223,7 @@ void ReportScreen::CreateViews() {
ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins));
LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL);
leftColumnItems->Add(new TextView(rp->T("FeedbackDesc", "How's the emulation? Let us and the community know!"), new LinearLayoutParams(Margins(12, 5, 0, 5))));
leftColumnItems->Add(new TextView(rp->T("FeedbackDesc", "How's the emulation? Let us and the community know!"), new LinearLayoutParams(Margins(12, 5, 0, 5))))->SetShadow(true);
if (!Reporting::IsEnabled()) {
reportingNotice_ = leftColumnItems->Add(new TextView(rp->T("FeedbackDisabled", "Compatibility server reports must be enabled."), new LinearLayoutParams(Margins(12, 5, 0, 5))));
reportingNotice_->SetShadow(true);
@@ -258,6 +258,7 @@ void ReportScreen::CreateViews() {
leftColumnItems->Add(new CompatRatingChoice("Overall", (int *)&overall_))->SetEnabledPtr(&enableReporting_)->OnChoice.Handle(this, &ReportScreen::HandleChoice);
overallDescription_ = leftColumnItems->Add(new TextView("", new LinearLayoutParams(Margins(10, 0))));
overallDescription_->SetShadow(true);
leftColumnItems->Add(new RatingChoice("Graphics", &graphics_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice);
leftColumnItems->Add(new RatingChoice("Speed", &speed_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice);
leftColumnItems->Add(new RatingChoice("Gameplay", &gameplay_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice);
View
@@ -837,7 +837,7 @@ void TextView::Draw(UIContext &dc) {
dc.SetFontStyle(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont);
if (shadow_) {
uint32_t shadowColor = 0x80000000;
dc.DrawTextRect(text_.c_str(), bounds_, shadowColor, textAlign_);
dc.DrawTextRect(text_.c_str(), bounds_.Offset(1.0f, 1.0f), shadowColor, textAlign_);
}
uint32_t textColor = hasTextColor_ ? textColor_ : dc.theme->infoStyle.fgColor;
dc.DrawTextRect(text_.c_str(), bounds_, textColor, textAlign_);

0 comments on commit 690a409

Please sign in to comment.