Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Common/TimeUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <cstdint>

#include "Common/TimeUtil.h"
#include "Common/Data/Random/Rng.h"
#include "Common/Log.h"

#ifdef HAVE_LIBNX
Expand Down Expand Up @@ -339,3 +340,11 @@ void GetCurrentTimeFormatted(char formattedTime[13]) {
// Now tack on the milliseconds
snprintf(formattedTime, 11, "%s:%03u", tmp, milliseconds % 1000);
}

// We don't even bother synchronizing this, it's fine if threads stomp a bit.
static GMRng g_sleepRandom;

void sleep_random(double minSeconds, double maxSeconds) {
const double waitSeconds = minSeconds + (maxSeconds - minSeconds) * g_sleepRandom.F();
sleep_precise(waitSeconds);
}
3 changes: 3 additions & 0 deletions Common/TimeUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ void sleep_ms(int ms, const char *reason);
// Precise sleep. Can consume a little bit of CPU on Windows at least.
void sleep_precise(double seconds);

// Random sleep, used for debugging.
void sleep_random(double minSeconds, double maxSeconds);

// Yield. Signals that this thread is busy-waiting but wants to allow other hyperthreads to run.
void yield();

Expand Down
5 changes: 3 additions & 2 deletions Core/HW/Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
#pragma once

#include <cstdint>
#include <functional>

class PointerWrap;

typedef void (*VblankCallback)();
// Listen for vblank events.
typedef std::function<void()> VblankCallback;
// Listen for vblank events. Callbacks are cleared in DisplayHWShutdown().
void __DisplayListenVblank(VblankCallback callback);
typedef void (*FlipCallback)(void *userdata);
void __DisplayListenFlip(FlipCallback callback, void *userdata);
Expand Down
143 changes: 62 additions & 81 deletions UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,6 @@ using namespace std::placeholders;
static AVIDump avi;
#endif

// TODO: Ugly!
static bool frameStep_;
static int lastNumFlips;
static bool startDumping;

extern bool g_TakeScreenshot;

static void AssertCancelCallback(const char *message, void *userdata) {
Expand All @@ -127,35 +122,6 @@ static void AssertCancelCallback(const char *message, void *userdata) {
emuScreen->SendImDebuggerCommand(ImCommand{ ImCmd::SHOW_IN_CPU_DISASM, currentMIPS->pc });
}

static void __EmuScreenVblank()
{
auto sy = GetI18NCategory(I18NCat::SYSTEM);

if (frameStep_ && lastNumFlips != gpuStats.numFlips) {
frameStep_ = false;
Core_Break(BreakReason::FrameAdvance, 0);
lastNumFlips = gpuStats.numFlips;
}
#ifndef MOBILE_DEVICE
if (g_Config.bDumpFrames && !startDumping)
{
avi.Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
g_OSD.Show(OSDType::MESSAGE_INFO, sy->T("AVI Dump started."), 1.0f);
startDumping = true;
}
if (g_Config.bDumpFrames && startDumping)
{
avi.AddFrame();
}
else if (!g_Config.bDumpFrames && startDumping)
{
avi.Stop();
g_OSD.Show(OSDType::MESSAGE_INFO, sy->T("AVI Dump stopped."), 1.0f);
startDumping = false;
}
#endif
}

// Handles control rotation due to internal screen rotation.
static void SetPSPAnalog(int stick, float x, float y) {
switch (g_Config.iInternalScreenRotation) {
Expand Down Expand Up @@ -189,10 +155,6 @@ static void SetPSPAnalog(int stick, float x, float y) {
EmuScreen::EmuScreen(const Path &filename)
: gamePath_(filename) {
saveStateSlot_ = SaveState::GetCurrentSlot();
__DisplayListenVblank(__EmuScreenVblank);
frameStep_ = false;
lastNumFlips = gpuStats.numFlips;
startDumping = false;
controlMapper_.SetCallbacks(
std::bind(&EmuScreen::onVKey, this, _1, _2),
std::bind(&EmuScreen::onVKeyAnalog, this, _1, _2),
Expand Down Expand Up @@ -366,6 +328,8 @@ void EmuScreen::ProcessGameBoot(const Path &filename) {

// Only call this on successful boot.
void EmuScreen::bootComplete() {
__DisplayListenVblank([this]() {HandleVBlank(); });

// Initialize retroachievements, now that we're on the right thread.
if (g_Config.bAchievementsEnable) {
std::string errorString;
Expand Down Expand Up @@ -440,8 +404,10 @@ void EmuScreen::bootComplete() {

saveStateSlot_ = SaveState::GetCurrentSlot();

loadingViewColor_->Divert(0x00FFFFFF, 0.2f);
loadingViewVisible_->Divert(UI::V_INVISIBLE, 0.2f);
if (loadingViewColor_)
loadingViewColor_->Divert(0x00FFFFFF, 0.2f);
if (loadingViewVisible_)
loadingViewVisible_->Divert(UI::V_INVISIBLE, 0.2f);

std::string gameID = g_paramSFO.GetValueString("DISC_ID");
g_Config.TimeTracker().Start(gameID);
Expand Down Expand Up @@ -475,11 +441,11 @@ EmuScreen::~EmuScreen() {
g_logManager.EnableOutput(LogOutput::RingBuffer);

#ifndef MOBILE_DEVICE
if (g_Config.bDumpFrames && startDumping)
if (g_Config.bDumpFrames && startDumping_)
{
avi.Stop();
g_OSD.Show(OSDType::MESSAGE_INFO, "AVI Dump stopped.", 2.0f);
startDumping = false;
startDumping_ = false;
}
#endif

Expand Down Expand Up @@ -801,14 +767,6 @@ void EmuScreen::onVKey(VirtKey virtualKeyCode, bool down) {
}
break;

case VIRTKEY_FRAME_ADVANCE:
// Can't do this reliably in an async fashion, so we just set a variable.
// Is this used by anyone? There's no good way to resume, other than PAUSE_NO_MENU or the debugger.
if (down && !NetworkWarnUserIfOnlineAndCantSpeed()) {
doFrameAdvance_.store(true);
}
break;

case VIRTKEY_RESET_EMULATION:
if (down) {
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
Expand Down Expand Up @@ -1007,6 +965,19 @@ void EmuScreen::ProcessVKey(VirtKey virtKey) {
break;
}

case VIRTKEY_FRAME_ADVANCE:
// Can't do this reliably in an async fashion, so we just set a variable.
// Is this used by anyone? There's no user-friendly way to resume, other than PAUSE_NO_MENU or the debugger.
if (!NetworkWarnUserIfOnlineAndCantSpeed()) {
if (Core_IsStepping()) {
Core_Resume();
frameStep_ = true;
} else {
Core_Break(BreakReason::FrameAdvance);
}
}
break;

default:
break;
}
Expand Down Expand Up @@ -1217,7 +1188,14 @@ void EmuScreen::CreateViews() {
root_->Add(buttons);

resumeButton_ = buttons->Add(new Button(dev->T("Resume")));
resumeButton_->OnClick.Handle(this, &EmuScreen::OnResume);
resumeButton_->OnClick.Add([this](UI::EventParams &) {
if (coreState == CoreState::CORE_RUNTIME_ERROR) {
// Force it!
Memory::MemFault_IgnoreLastCrash();
coreState = CoreState::CORE_RUNNING_CPU;
}
return UI::EVENT_DONE;
});
resumeButton_->SetVisibility(V_GONE);

resetButton_ = buttons->Add(new Button(dev->T("Reset")));
Expand All @@ -1237,7 +1215,10 @@ void EmuScreen::CreateViews() {
backButton_->SetVisibility(V_GONE);

cardboardDisableButton_ = root_->Add(new Button(sc->T("Cardboard VR OFF"), new AnchorLayoutParams(bounds.centerX(), NONE, NONE, 30, true)));
cardboardDisableButton_->OnClick.Handle(this, &EmuScreen::OnDisableCardboard);
cardboardDisableButton_->OnClick.Add([](UI::EventParams &) {
g_Config.bEnableCardboardVR = false;
return UI::EVENT_DONE;
});
cardboardDisableButton_->SetVisibility(V_GONE);
cardboardDisableButton_->SetScale(0.65f); // make it smaller - this button can be in the way otherwise.

Expand Down Expand Up @@ -1331,11 +1312,6 @@ UI::EventReturn EmuScreen::OnDevTools(UI::EventParams &params) {
return UI::EVENT_DONE;
}

UI::EventReturn EmuScreen::OnDisableCardboard(UI::EventParams &params) {
g_Config.bEnableCardboardVR = false;
return UI::EVENT_DONE;
}

UI::EventReturn EmuScreen::OnChat(UI::EventParams &params) {
if (chatButton_ != nullptr && chatButton_->GetVisibility() == UI::V_VISIBLE) {
chatButton_->SetVisibility(UI::V_GONE);
Expand All @@ -1357,15 +1333,6 @@ UI::EventReturn EmuScreen::OnChat(UI::EventParams &params) {
return UI::EVENT_DONE;
}

UI::EventReturn EmuScreen::OnResume(UI::EventParams &params) {
if (coreState == CoreState::CORE_RUNTIME_ERROR) {
// Force it!
Memory::MemFault_IgnoreLastCrash();
coreState = CoreState::CORE_RUNNING_CPU;
}
return UI::EVENT_DONE;
}

// To avoid including proAdhoc.h, which includes a lot of stuff.
int GetChatMessageCount();

Expand Down Expand Up @@ -1512,6 +1479,26 @@ void EmuScreen::darken() {
}
}

// TODO: We probably shouldn't even handle frame dumping at vblank, we can just as well handle it directly in EmuScreen.
void EmuScreen::HandleVBlank() {
#ifndef MOBILE_DEVICE
if (g_Config.bDumpFrames && !startDumping_) {
auto sy = GetI18NCategory(I18NCat::SYSTEM);
avi.Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
g_OSD.Show(OSDType::MESSAGE_INFO, sy->T("AVI Dump started."), 1.0f);
startDumping_ = true;
}
if (g_Config.bDumpFrames && startDumping_) {
avi.AddFrame();
} else if (!g_Config.bDumpFrames && startDumping_) {
auto sy = GetI18NCategory(I18NCat::SYSTEM);
avi.Stop();
g_OSD.Show(OSDType::MESSAGE_INFO, sy->T("AVI Dump stopped."), 1.0f);
startDumping_ = false;
}
#endif
}

ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
// Moved from update, because we want it to be possible for booting to happen even when the screen
// is in the background, like when choosing Reset from the pause menu.
Expand All @@ -1532,7 +1519,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {

ProcessQueuedVKeys();

bool skipBufferEffects = g_Config.bSkipBufferEffects;
const bool skipBufferEffects = g_Config.bSkipBufferEffects;

bool framebufferBound = false;

Expand Down Expand Up @@ -1631,19 +1618,6 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {

PSP_UpdateDebugStats((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS || g_Config.bLogFrameDrops);

if (doFrameAdvance_.exchange(false)) {
if (!Achievements::WarnUserIfHardcoreModeActive(false)) {
// If game is running, pause emulation immediately. Otherwise, advance a single frame.
if (Core_IsStepping()) {
frameStep_ = true;
Core_Resume();
} else if (!frameStep_) {
lastNumFlips = gpuStats.numFlips;
Core_Break(BreakReason::FrameAdvance, 0);
}
}
}

// Running it early allows things like direct readbacks of buffers, things we can't do
// when we have started the final render pass. Well, technically we probably could with some manipulation
// of pass order in the render managers..
Expand All @@ -1665,7 +1639,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
switch (coreState) {
case CORE_NEXTFRAME:
// Reached the end of the frame while running at full blast, all good. Set back to running for the next frame
coreState = CORE_RUNNING_CPU;
coreState = frameStep_ ? CORE_STEPPING_CPU : CORE_RUNNING_CPU;
flags |= ScreenRenderFlags::HANDLED_THROTTLING;
Achievements::FrameUpdate();
break;
Expand Down Expand Up @@ -1708,6 +1682,13 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
PSP_EndHostFrame();
}

if (frameStep_) {
frameStep_ = false;
if (coreState == CORE_RUNNING_CPU) {
Core_Break(BreakReason::FrameAdvance, 0);
}
}

if (gpu && gpu->PresentedThisFrame()) {
framebufferBound = true;
}
Expand Down
9 changes: 5 additions & 4 deletions UI/EmuScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,9 @@ class EmuScreen : public UIScreen {
private:
void CreateViews() override;
UI::EventReturn OnDevTools(UI::EventParams &params);
UI::EventReturn OnDisableCardboard(UI::EventParams &params);
UI::EventReturn OnChat(UI::EventParams &params);
UI::EventReturn OnResume(UI::EventParams &params);

void HandleVBlank();
void ProcessGameBoot(const Path &filename);
bool bootAllowStorage(const Path &filename);
void bootComplete();
Expand Down Expand Up @@ -132,8 +131,6 @@ class EmuScreen : public UIScreen {

std::string extraAssertInfoStr_;

std::atomic<bool> doFrameAdvance_{};

ControlMapper controlMapper_;

std::unique_ptr<ImDebugger> imDebugger_ = nullptr;
Expand All @@ -153,6 +150,10 @@ class EmuScreen : public UIScreen {
std::vector<VirtKey> queuedVirtKeys_;

ImGuiContext *ctx_ = nullptr;

// TODO: Ugly!
bool frameStep_ = false;
bool startDumping_ = false;
};

bool MustRunBehind();
Expand Down
5 changes: 2 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,8 @@ android {
} else {
println "(not using these:) Android Version Name, Code: " + androidGitVersion.name() + " " + androidGitVersion.code()
}

new File("versionname.txt").write(androidGitVersion.name())
new File("versioncode.txt").write(androidGitVersion.code().toString())
file("versionname.txt").text = androidGitVersion.name()
file("versioncode.txt").text = androidGitVersion.code().toString()

minSdk 9
targetSdk 35
Expand Down
2 changes: 1 addition & 1 deletion assets/lang/ru_RU.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,7 @@ Off = Выкл.
Oldest Save = Самое старое сохранение
Only JPG and PNG images are supported = Поддерживаются только изображения в формате JPG и PNG
Path does not exist! = Пути не существует!
Pause when not focused = &Пауза, когда окно не в фокусе
Pause when not focused = Пауза, когда окно не в фокусе
Plugins = Плагины
PSP Memory Stick = Карта памяти PSP
PSP Model = Модель PSP
Expand Down
Loading
Loading