Merge pull request #20072 from hrydgard/debugger-threading-improvements

UI threading improvements
This commit is contained in:
Henrik Rydgård 2025-03-03 15:19:43 +01:00 committed by GitHub
commit ec16aa64d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 141 additions and 146 deletions

View file

@ -100,6 +100,9 @@ enum class SystemRequestType {
RUN_CALLBACK_IN_WNDPROC,
};
// Run a closure on the main thread. Used to safely implement UI that runs on another thread.
void System_RunOnMainThread(std::function<void()> func);
// Implementations are supposed to process the request, and post the response to the g_RequestManager (see Message.h).
// This is not to be used directly by applications, instead use the g_RequestManager to make the requests.
// This can return false if it's known that the platform doesn't support the request, the app is supposed to handle

View file

@ -2015,7 +2015,7 @@ void Config::ResetControlLayout() {
g_Config.fRightStickHeadScale = 1.0f;
}
void Config::GetReportingInfo(UrlEncoder &data) {
void Config::GetReportingInfo(UrlEncoder &data) const {
for (size_t i = 0; i < numSections; ++i) {
const std::string prefix = std::string("config.") + sections[i].section;
for (size_t j = 0; j < sections[i].settingsCount; j++) {

View file

@ -632,7 +632,7 @@ public:
void ResetControlLayout();
void GetReportingInfo(UrlEncoder &data);
void GetReportingInfo(UrlEncoder &data) const;
bool IsPortrait() const;
int NextValidBackend();

View file

@ -108,7 +108,6 @@ const char *BreakReasonToString(BreakReason reason) {
case BreakReason::SavestateCrash: return "savestate.crash";
case BreakReason::MemoryBreakpoint: return "memory.breakpoint";
case BreakReason::CpuBreakpoint: return "cpu.breakpoint";
case BreakReason::BreakpointUpdate: return "cpu.breakpoint.update";
case BreakReason::MemoryAccess: return "memory.access"; // ???
case BreakReason::JitBranchDebug: return "jit.branchdebug";
case BreakReason::RABreak: return "ra.break";

View file

@ -61,7 +61,6 @@ enum class BreakReason {
SavestateCrash,
MemoryBreakpoint,
CpuBreakpoint,
BreakpointUpdate,
MemoryAccess, // ???
JitBranchDebug,
BreakOnBoot,

View file

@ -32,7 +32,7 @@
BreakpointManager g_breakpoints;
void MemCheck::Log(u32 addr, bool write, int size, u32 pc, const char *reason) {
void MemCheck::Log(u32 addr, bool write, int size, u32 pc, const char *reason) const {
if (result & BREAK_ACTION_LOG) {
const char *type = write ? "Write" : "Read";
if (logFormat.empty()) {
@ -71,11 +71,9 @@ BreakAction MemCheck::Action(u32 addr, bool write, int size, u32 pc, const char
}
// Note: must lock while calling this.
size_t BreakpointManager::FindBreakpoint(u32 addr, bool matchTemp, bool temp)
{
size_t BreakpointManager::FindBreakpoint(u32 addr, bool matchTemp, bool temp) {
size_t found = INVALID_BREAKPOINT;
for (size_t i = 0; i < breakPoints_.size(); ++i)
{
for (size_t i = 0; i < breakPoints_.size(); ++i) {
const auto &bp = breakPoints_[i];
if (bp.addr == addr && (!matchTemp || bp.temporary == temp))
{
@ -90,10 +88,8 @@ size_t BreakpointManager::FindBreakpoint(u32 addr, bool matchTemp, bool temp)
return found;
}
size_t BreakpointManager::FindMemCheck(u32 start, u32 end)
{
for (size_t i = 0; i < memChecks_.size(); ++i)
{
size_t BreakpointManager::FindMemCheck(u32 start, u32 end) {
for (size_t i = 0; i < memChecks_.size(); ++i) {
if (memChecks_[i].start == start && memChecks_[i].end == end)
return i;
}
@ -155,14 +151,11 @@ int BreakpointManager::AddBreakPoint(u32 addr, bool temp) {
breakPoints_.push_back(pt);
anyBreakPoints_ = true;
guard.unlock();
Update(addr);
return (int)breakPoints_.size() - 1;
} else if (!breakPoints_[bp].IsEnabled()) {
breakPoints_[bp].result |= BREAK_ACTION_PAUSE;
breakPoints_[bp].hasCond = false;
guard.unlock();
Update(addr);
return (int)bp;
} else {
@ -183,7 +176,6 @@ void BreakpointManager::RemoveBreakPoint(u32 addr) {
breakPoints_.erase(breakPoints_.begin() + bp);
anyBreakPoints_ = !breakPoints_.empty();
guard.unlock();
Update(addr);
}
}
@ -196,8 +188,6 @@ void BreakpointManager::ChangeBreakPoint(u32 addr, bool status) {
breakPoints_[bp].result |= BREAK_ACTION_PAUSE;
else
breakPoints_[bp].result = BreakAction(breakPoints_[bp].result & ~BREAK_ACTION_PAUSE);
guard.unlock();
Update(addr);
}
}
@ -207,7 +197,6 @@ void BreakpointManager::ChangeBreakPoint(u32 addr, BreakAction result) {
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT) {
breakPoints_[bp].result = result;
guard.unlock();
Update(addr);
}
}
@ -220,7 +209,6 @@ void BreakpointManager::ClearAllBreakPoints()
if (!breakPoints_.empty())
{
breakPoints_.clear();
guard.unlock();
Update();
}
}
@ -230,20 +218,14 @@ void BreakpointManager::ClearTemporaryBreakPoints()
if (!anyBreakPoints_)
return;
std::unique_lock<std::mutex> guard(breakPointsMutex_);
bool update = false;
for (int i = (int)breakPoints_.size()-1; i >= 0; --i)
{
if (breakPoints_[i].temporary)
{
breakPoints_.erase(breakPoints_.begin() + i);
update = true;
Update();
}
}
guard.unlock();
if (update)
Update();
}
void BreakpointManager::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond)
@ -254,30 +236,25 @@ void BreakpointManager::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &
{
breakPoints_[bp].hasCond = true;
breakPoints_[bp].cond = cond;
guard.unlock();
Update(addr);
}
}
void BreakpointManager::ChangeBreakPointRemoveCond(u32 addr)
{
void BreakpointManager::ChangeBreakPointRemoveCond(u32 addr) {
std::unique_lock<std::mutex> guard(breakPointsMutex_);
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
{
if (bp != INVALID_BREAKPOINT) {
breakPoints_[bp].hasCond = false;
guard.unlock();
Update(addr);
}
}
BreakPointCond *BreakpointManager::GetBreakPointCondition(u32 addr)
{
BreakPointCond *BreakpointManager::GetBreakPointCondition(u32 addr) {
std::lock_guard<std::mutex> guard(breakPointsMutex_);
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT && breakPoints_[bp].hasCond)
return &breakPoints_[bp].cond;
return NULL;
return nullptr;
}
void BreakpointManager::ChangeBreakPointLogFormat(u32 addr, const std::string &fmt) {
@ -285,7 +262,6 @@ void BreakpointManager::ChangeBreakPointLogFormat(u32 addr, const std::string &f
size_t bp = FindBreakpoint(addr, true, false);
if (bp != INVALID_BREAKPOINT) {
breakPoints_[bp].logFormat = fmt;
guard.unlock();
Update(addr);
}
}
@ -338,18 +314,18 @@ int BreakpointManager::AddMemCheck(u32 start, u32 end, MemCheckCondition cond, B
memChecks_.push_back(check);
bool hadAny = anyMemChecks_.exchange(true);
if (!hadAny)
if (!hadAny) {
MemBlockOverrideDetailed();
guard.unlock();
}
Update();
return (int)memChecks_.size() - 1;
} else {
memChecks_[mc].cond = (MemCheckCondition)(memChecks_[mc].cond | cond);
memChecks_[mc].result = (BreakAction)(memChecks_[mc].result | result);
bool hadAny = anyMemChecks_.exchange(true);
if (!hadAny)
if (!hadAny) {
MemBlockOverrideDetailed();
guard.unlock();
}
Update();
return (int)mc;
}
@ -366,7 +342,6 @@ void BreakpointManager::RemoveMemCheck(u32 start, u32 end)
bool hadAny = anyMemChecks_.exchange(!memChecks_.empty());
if (hadAny)
MemBlockReleaseDetailed();
guard.unlock();
Update();
}
}
@ -379,7 +354,6 @@ void BreakpointManager::ChangeMemCheck(u32 start, u32 end, MemCheckCondition con
{
memChecks_[mc].cond = cond;
memChecks_[mc].result = result;
guard.unlock();
Update();
}
}
@ -394,7 +368,6 @@ void BreakpointManager::ClearAllMemChecks()
bool hadAny = anyMemChecks_.exchange(false);
if (hadAny)
MemBlockReleaseDetailed();
guard.unlock();
Update();
}
}
@ -406,7 +379,6 @@ void BreakpointManager::ChangeMemCheckAddCond(u32 start, u32 end, const BreakPoi
if (mc != INVALID_MEMCHECK) {
memChecks_[mc].hasCondition = true;
memChecks_[mc].condition = cond;
guard.unlock();
// No need to update jit for a condition add/remove, they're not baked in.
Update(-1);
}
@ -417,7 +389,6 @@ void BreakpointManager::ChangeMemCheckRemoveCond(u32 start, u32 end) {
size_t mc = FindMemCheck(start, end);
if (mc != INVALID_MEMCHECK) {
memChecks_[mc].hasCondition = false;
guard.unlock();
// No need to update jit for a condition add/remove, they're not baked in.
Update(-1);
}
@ -436,7 +407,6 @@ void BreakpointManager::ChangeMemCheckLogFormat(u32 start, u32 end, const std::s
size_t mc = FindMemCheck(start, end);
if (mc != INVALID_MEMCHECK) {
memChecks_[mc].logFormat = fmt;
guard.unlock();
Update();
}
}
@ -620,30 +590,27 @@ std::vector<BreakPoint> BreakpointManager::GetBreakpoints() {
return breakPoints_;
}
void BreakpointManager::Update(u32 addr) {
if (MIPSComp::jit && addr != -1) {
bool resume = false;
if (Core_IsStepping() == false) {
Core_Break(BreakReason::BreakpointUpdate, addr);
Core_WaitInactive();
resume = true;
}
// In case this is a delay slot, clear the previous instruction too.
if (addr != 0)
mipsr4k.InvalidateICache(addr - 4, 8);
else
mipsr4k.ClearJitCache();
if (resume)
Core_Resume();
void BreakpointManager::Frame() {
// outside the lock here, should be ok.
if (!needsUpdate_) {
return;
}
if (anyMemChecks_ && addr != -1)
std::lock_guard<std::mutex> guard(breakPointsMutex_);
if (MIPSComp::jit && updateAddr_ != -1) {
// In case this is a delay slot, clear the previous instruction too.
if (updateAddr_ != 0)
mipsr4k.InvalidateICache(updateAddr_ - 4, 8);
else
mipsr4k.ClearJitCache();
}
if (anyMemChecks_ && updateAddr_ != -1)
UpdateCachedMemCheckRanges();
// Redraw in order to show the breakpoint.
System_Notify(SystemNotification::DISASSEMBLY);
needsUpdate_ = false;
}
bool BreakpointManager::ValidateLogFormat(MIPSDebugInterface *cpu, const std::string &fmt) {

View file

@ -103,7 +103,7 @@ struct MemCheck {
// Called on a copy.
BreakAction Action(u32 addr, bool write, int size, u32 pc, const char *reason);
void Log(u32 addr, bool write, int size, u32 pc, const char *reason);
void Log(u32 addr, bool write, int size, u32 pc, const char *reason) const;
bool IsEnabled() const {
return (result & BREAK_ACTION_PAUSE) != 0;
@ -183,12 +183,17 @@ public:
return anyMemChecks_;
}
void Update(u32 addr = 0);
void Frame();
bool ValidateLogFormat(MIPSDebugInterface *cpu, const std::string &fmt);
bool EvaluateLogFormat(MIPSDebugInterface *cpu, const std::string &fmt, std::string &result);
private:
// Should be called under lock.
void Update(u32 addr = 0) {
needsUpdate_ = true;
updateAddr_ = addr;
}
size_t FindBreakpoint(u32 addr, bool matchTemp = false, bool temp = false);
// Finds exactly, not using a range check.
size_t FindMemCheck(u32 start, u32 end);
@ -208,6 +213,9 @@ private:
std::vector<MemCheck> memChecks_;
std::vector<MemCheck> memCheckRangesRead_;
std::vector<MemCheck> memCheckRangesWrite_;
bool needsUpdate_ = true;
u32 updateAddr_ = 0;
};
extern BreakpointManager g_breakpoints;

View file

@ -205,7 +205,7 @@ struct GPUDebugVertex {
class GPUDebugInterface {
public:
virtual ~GPUDebugInterface() {}
virtual ~GPUDebugInterface() = default;
virtual bool GetCurrentDisplayList(DisplayList &list) = 0;
virtual int GetCurrentPrimCount() = 0;
virtual std::vector<DisplayList> ActiveDisplayLists() = 0;

View file

@ -42,7 +42,7 @@ const static u8 textureRelatedCmds[] = {
GE_CMD_TEXFLUSH, GE_CMD_TEXSYNC,
};
void GPUBreakpoints::Init() {
GPUBreakpoints::GPUBreakpoints() {
ClearAllBreakpoints();
nonTextureCmds.clear();
@ -268,20 +268,20 @@ bool GPUBreakpoints::IsRenderTargetBreakpoint(u32 addr) {
return breakRenderTargets.find(addr) != breakRenderTargets.end();
}
bool GPUBreakpoints::IsOpBreakpoint(u32 op, bool &temp) {
bool GPUBreakpoints::IsOpBreakpoint(u32 op, bool &temp) const {
return IsCmdBreakpoint(op >> 24, temp);
}
bool GPUBreakpoints::IsOpBreakpoint(u32 op) {
bool GPUBreakpoints::IsOpBreakpoint(u32 op) const {
return IsCmdBreakpoint(op >> 24);
}
bool GPUBreakpoints::IsCmdBreakpoint(u8 cmd, bool &temp) {
bool GPUBreakpoints::IsCmdBreakpoint(u8 cmd, bool &temp) const {
temp = breakCmdsTemp[cmd];
return breakCmds[cmd];
}
bool GPUBreakpoints::IsCmdBreakpoint(u8 cmd) {
bool GPUBreakpoints::IsCmdBreakpoint(u8 cmd) const {
return breakCmds[cmd];
}

View file

@ -29,17 +29,16 @@ struct GECmdInfo;
class GPUBreakpoints {
public:
GPUBreakpoints() {
Init();
}
void Init();
GPUBreakpoints();
bool IsBreakpoint(u32 pc, u32 op);
bool IsAddressBreakpoint(u32 addr, bool &temp);
bool IsAddressBreakpoint(u32 addr);
bool IsCmdBreakpoint(u8 cmd, bool &temp);
bool IsCmdBreakpoint(u8 cmd);
bool IsCmdBreakpoint(u8 cmd, bool &temp) const;
bool IsCmdBreakpoint(u8 cmd) const;
bool IsOpBreakpoint(u32 op, bool &temp) const;
bool IsOpBreakpoint(u32 op) const;
bool IsTextureBreakpoint(u32 addr, bool &temp);
bool IsTextureBreakpoint(u32 addr);
bool IsRenderTargetBreakpoint(u32 addr, bool &temp);
@ -69,10 +68,6 @@ public:
void ClearAllBreakpoints();
void ClearTempBreakpoints();
bool IsOpBreakpoint(u32 op, bool &temp);
bool IsOpBreakpoint(u32 op);
bool HasBreakpoints() const {
return hasBreakpoints_;
}

View file

@ -623,32 +623,31 @@ bool GPUCommon::SlowRunLoop(DisplayList &list) {
const bool dumpThisFrame = dumpThisFrame_;
while (downcount > 0) {
GPUDebug::NotifyResult result = NotifyCommand(list.pc, &breakpoints_);
if (result == GPUDebug::NotifyResult::Execute) {
recorder_.NotifyCommand(list.pc);
u32 op = Memory::ReadUnchecked_U32(list.pc);
u32 cmd = op >> 24;
u32 diff = op ^ gstate.cmdmem[cmd];
PreExecuteOp(op, diff);
if (dumpThisFrame) {
char temp[256];
u32 prev;
if (Memory::IsValidAddress(list.pc - 4)) {
prev = Memory::ReadUnchecked_U32(list.pc - 4);
} else {
prev = 0;
}
GeDisassembleOp(list.pc, op, prev, temp, 256);
NOTICE_LOG(Log::G3D, "%08x: %s", op, temp);
}
gstate.cmdmem[cmd] = op;
ExecuteOp(op, diff);
} else if (result == GPUDebug::NotifyResult::Break) {
if (result == GPUDebug::NotifyResult::Break) {
return false;
}
recorder_.NotifyCommand(list.pc);
u32 op = Memory::ReadUnchecked_U32(list.pc);
u32 cmd = op >> 24;
u32 diff = op ^ gstate.cmdmem[cmd];
PreExecuteOp(op, diff);
if (dumpThisFrame) {
char temp[256];
u32 prev;
if (Memory::IsValidAddress(list.pc - 4)) {
prev = Memory::ReadUnchecked_U32(list.pc - 4);
} else {
prev = 0;
}
GeDisassembleOp(list.pc, op, prev, temp, 256);
NOTICE_LOG(Log::G3D, "%08x: %s", op, temp);
}
gstate.cmdmem[cmd] = op;
ExecuteOp(op, diff);
list.pc += 4;
--downcount;
}
@ -2141,6 +2140,10 @@ void GPUCommon::NotifyFlush() {
if (primAfterDraw_) {
NOTICE_LOG(Log::GeDebugger, "Flush detected, breaking at next PRIM");
primAfterDraw_ = false;
// We've got one to rewind.
primsThisFrame_--;
// Switch to PRIM mode.
SetBreakNext(BreakNext::PRIM);
}

View file

@ -370,7 +370,7 @@ public:
return -1;
}
virtual void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) {
virtual void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) const {
primaryInfo = reportingPrimaryInfo_;
fullInfo = reportingFullInfo_;
}

View file

@ -156,7 +156,7 @@ public:
void CheckDisplayResized() override;
void CheckConfigChanged() override;
void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override {
void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) const override {
primaryInfo = "Software";
fullInfo = "Software";
}

View file

@ -1691,7 +1691,7 @@ void UmdReplaceScreen::CreateViews() {
if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) {
rightColumnItems->Add(new Choice(mm->T("Load", "Load...")))->OnClick.Add([&](UI::EventParams &e) {
auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_BrowseForFile(GetRequesterToken(), mm->T("Load"), BrowseFileType::BOOTABLE, [&](const std::string &value, int) {
System_BrowseForFile(GetRequesterToken(), mm->T("Load"), BrowseFileType::BOOTABLE, [this](const std::string &value, int) {
__UmdReplace(Path(value));
TriggerFinish(DR_OK);
});

View file

@ -89,6 +89,7 @@
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/Core.h"
#include "Core/Debugger/Breakpoints.h"
#include "Core/FileLoaders/DiskCachingFileLoader.h"
#include "Core/FrameTiming.h"
#include "Core/KeyMap.h"
@ -177,7 +178,7 @@ struct PendingMessage {
std::string value;
};
static std::mutex pendingMutex;
static std::mutex g_pendingMutex;
static std::vector<PendingMessage> pendingMessages;
static Draw::DrawContext *g_draw;
static Draw::Pipeline *colorPipeline;
@ -185,6 +186,7 @@ static Draw::Pipeline *texColorPipeline;
static UIContext *uiContext;
static int g_restartGraphics;
static bool g_windowHidden = false;
std::vector<std::function<void()>> g_pendingClosures;
#ifdef _WIN32
WindowsAudioBackend *winAudioBackend;
@ -345,6 +347,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
setlocale( LC_ALL, "C" );
std::string user_data_path = savegame_dir;
pendingMessages.clear();
g_pendingClosures.clear();
g_requestManager.Clear();
// external_dir has all kinds of meanings depending on platform.
@ -1047,23 +1050,34 @@ void NativeFrame(GraphicsContext *graphicsContext) {
g_screenManager->update();
// Do this after g_screenManager.update() so we can receive setting changes before rendering.
std::vector<PendingMessage> toProcess;
{
std::lock_guard<std::mutex> lock(pendingMutex);
toProcess = std::move(pendingMessages);
pendingMessages.clear();
}
for (const auto &item : toProcess) {
if (HandleGlobalMessage(item.message, item.value)) {
// TODO: Add a to-string thingy.
INFO_LOG(Log::System, "Handled global message: %d / %s", (int)item.message, item.value.c_str());
std::vector<PendingMessage> toProcess;
std::vector<std::function<void()>> toRun;
{
std::lock_guard<std::mutex> lock(g_pendingMutex);
toProcess = std::move(pendingMessages);
toRun = std::move(g_pendingClosures);
pendingMessages.clear();
g_pendingClosures.clear();
}
for (auto &item : toRun) {
item();
}
for (const auto &item : toProcess) {
if (HandleGlobalMessage(item.message, item.value)) {
// TODO: Add a to-string thingy.
INFO_LOG(Log::System, "Handled global message: %d / %s", (int)item.message, item.value.c_str());
}
g_screenManager->sendMessage(item.message, item.value.c_str());
}
g_screenManager->sendMessage(item.message, item.value.c_str());
}
g_requestManager.ProcessRequests();
g_breakpoints.Frame();
// Apply the UIContext bounds as a 2D transformation matrix.
Matrix4x4 ortho = ComputeOrthoMatrix(g_display.dp_xres, g_display.dp_yres, graphicsContext->GetDrawContext()->GetDeviceCaps().coordConvention);
@ -1404,13 +1418,18 @@ void NativeAccelerometer(float tiltX, float tiltY, float tiltZ) {
}
void System_PostUIMessage(UIMessage message, const std::string &value) {
std::lock_guard<std::mutex> lock(pendingMutex);
std::lock_guard<std::mutex> lock(g_pendingMutex);
PendingMessage pendingMessage;
pendingMessage.message = message;
pendingMessage.value = value;
pendingMessages.push_back(pendingMessage);
}
void System_RunOnMainThread(std::function<void()> func) {
std::lock_guard<std::mutex> lock(g_pendingMutex);
g_pendingClosures.push_back(std::move(func));
}
void NativeResized() {
// NativeResized can come from any thread so we just set a flag, then process it later.
VERBOSE_LOG(Log::G3D, "NativeResized - setting flag");

View file

@ -370,6 +370,7 @@ namespace MainWindow {
static void UmdSwitchAction(RequesterToken token) {
auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_BrowseForFile(token, mm->T("Switch UMD"), BrowseFileType::BOOTABLE, [](const std::string &value, int) {
// This is safe because the callback runs on the emu thread.
__UmdReplace(Path(value));
});
}
@ -383,17 +384,24 @@ namespace MainWindow {
// not static
void setTexScalingMultiplier(int level) {
g_Config.iTexScalingLevel = level;
System_RunOnMainThread([level]() {
g_Config.iTexScalingLevel = level;
});
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
}
static void setTexScalingType(int type) {
g_Config.iTexScalingType = type;
System_RunOnMainThread([type]() {
g_Config.iTexScalingType = type;
});
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
}
static void setSkipBufferEffects(bool skip) {
g_Config.bSkipBufferEffects = skip;
System_RunOnMainThread([skip]() {
g_Config.bSkipBufferEffects = skip;
});
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
}
@ -497,23 +505,15 @@ namespace MainWindow {
break;
case ID_EMULATION_PAUSE:
if (!NetworkWarnUserIfOnlineAndCantSpeed()) {
System_PostUIMessage(UIMessage::REQUEST_GAME_PAUSE);
}
System_PostUIMessage(UIMessage::REQUEST_GAME_PAUSE);
break;
case ID_EMULATION_STOP:
if (Core_IsStepping())
Core_Resume();
Core_Stop();
System_PostUIMessage(UIMessage::REQUEST_GAME_STOP);
Core_WaitInactive();
break;
case ID_EMULATION_RESET:
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
Core_Resume();
break;
case ID_EMULATION_SWITCH_UMD:
@ -662,14 +662,13 @@ namespace MainWindow {
case ID_OPTIONS_VSYNC:
g_Config.bVSync = !g_Config.bVSync;
NativeResized();
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
break;
case ID_OPTIONS_FRAMESKIP_AUTO:
g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip;
if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) {
g_Config.bSkipBufferEffects = false;
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
setSkipBufferEffects(false);
}
break;
@ -714,8 +713,7 @@ namespace MainWindow {
break;
case ID_OPTIONS_SKIP_BUFFER_EFFECTS:
g_Config.bSkipBufferEffects = !g_Config.bSkipBufferEffects;
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
setSkipBufferEffects(!g_Config.bSkipBufferEffects);
g_OSD.ShowOnOff(gr->T("Skip Buffer Effects"), g_Config.bSkipBufferEffects);
break;
@ -731,9 +729,12 @@ namespace MainWindow {
break;
case ID_OPTIONS_HARDWARETRANSFORM:
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
g_OSD.ShowOnOff(gr->T("Hardware Transform"), g_Config.bHardwareTransform);
System_RunOnMainThread([]() {
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
g_OSD.ShowOnOff(gr->T("Hardware Transform"), g_Config.bHardwareTransform);
});
break;
case ID_OPTIONS_DISPLAY_LAYOUT:

View file

@ -93,6 +93,7 @@ bool System_GetPropertyBool(SystemProperty prop) {
}
void System_Notify(SystemNotification notification) {}
void System_PostUIMessage(UIMessage message, const std::string &param) {}
void System_RunOnMainThread(std::function<void()>) {}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2, int64_t param3, int64_t param4) {
switch (type) {
case SystemRequestType::SEND_DEBUG_OUTPUT:

View file

@ -1913,6 +1913,7 @@ void System_Notify(SystemNotification notification) {
}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2, int64_t param3, int64_t param4) { return false; }
void System_PostUIMessage(UIMessage message, const std::string &param) {}
void System_RunOnMainThread(std::function<void()>) {}
void NativeFrame(GraphicsContext *graphicsContext) {}
void NativeResized() {}

View file

@ -112,6 +112,7 @@ bool System_GetPropertyBool(SystemProperty prop) {
}
void System_Notify(SystemNotification notification) {}
void System_PostUIMessage(UIMessage message, const std::string &param) {}
void System_RunOnMainThread(std::function<void()>) {}
void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; }
void System_AudioClear() {}
void System_AudioPushSamples(const s32 *audio, int numSamples, float volume) {}
@ -119,9 +120,7 @@ void System_AudioPushSamples(const s32 *audio, int numSamples, float volume) {}
// TODO: To avoid having to define these here, these should probably be turned into system "requests".
// To clear the secret entirely, just save an empty string.
bool NativeSaveSecret(std::string_view nameOfSecret, std::string_view data) { return false; }
std::string NativeLoadSecret(std::string_view nameOfSecret) {
return "";
}
std::string NativeLoadSecret(std::string_view nameOfSecret) { return ""; }
#if PPSSPP_PLATFORM(ANDROID)
JNIEnv *getEnv() {