Merge pull request #21229 from hrydgard/more-ui-polish

More UI fixes, easy way to copy function hash
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-02-09 19:53:46 +01:00
commit c802162a1a
16 files changed
+79 -30

No files matched your search

+2
View File
@@ -1848,6 +1848,8 @@ std::map<u32, u32> SaveAndClearReplacements() {
Memory::Write_U32(instr, addr);
}
}
// TODO: Should we not also call replacedInstructions.clear(); ?
return saved;
}
+6 -1
View File
@@ -15,14 +15,19 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// Regular replacement funcs are just C functions. These take care of their
// own parameter parsing using the old school PARAM macros.
// The return value is the number of cycles to eat.
// Replacement functions are replaced by function hash, also checking the size to reduce
// collisions. This is not really super safe, and we probably should restrict them by
// game ID, really...
// JIT replacefuncs can be for inline or "outline" replacement.
// With inline replacement, we recognize the call to the functions
// at jal time already. With outline replacement, we just replace the
// implementation.
// implementation, which gets jumped to from other functions.
// In both cases the jit needs to know how much to subtract downcount.
//
+1 -1
View File
@@ -771,7 +771,7 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst) {
case IROp::Mult:
{
s64 result = (s64)(s32)mips->r[inst->src1] * (s64)(s32)mips->r[inst->src2];
memcpy(&mips->lo, &result, 8);
memcpy(&mips->lo, &result, 8); // note: lo is followed by hi, so this is ok (little-endian).
break;
}
case IROp::MultU:
+11 -7
View File
@@ -1261,6 +1261,17 @@ skip:
}
}
bool GetAnalyzedFunctionAt(u32 addr, AnalyzedFunction *out) {
std::lock_guard<std::recursive_mutex> guard(functions_lock);
for (auto iter = functions.begin(), end = functions.end(); iter != end; ++iter) {
if (iter->start <= addr && iter->end >= addr) {
*out = *iter;
return true;
}
}
return false;
}
void ReplaceFunctions() {
std::lock_guard<std::recursive_mutex> guard(functions_lock);
@@ -1299,13 +1310,6 @@ skip:
return 0;
}
void SetHashMapFilename(const std::string& filename) {
if (filename.empty())
hashmapFileName = GetSysDirectory(DIRECTORY_SYSTEM) / "knownfuncs.ini";
else
hashmapFileName = Path(filename);
}
void StoreHashMap(Path filename) {
if (filename.empty())
filename = hashmapFileName;
+2 -1
View File
@@ -108,7 +108,8 @@ namespace MIPSAnalyst {
void FinalizeScan(bool insertSymbols);
void ForgetFunctions(u32 startAddr, u32 endAddr);
void SetHashMapFilename(const std::string& filename = "");
bool GetAnalyzedFunctionAt(u32 addr, AnalyzedFunction *out);
void LoadBuiltinHashMap();
void LoadHashMap(const Path &filename);
void StoreHashMap(Path filename = Path());
+6 -2
View File
@@ -1596,11 +1596,12 @@ ScreenRenderFlags EmuScreen::PreRender(ScreenRenderMode mode) {
using namespace Draw;
skipBufferEffects_ = g_Config.bSkipBufferEffects;
if (!skipBufferEffects_) {
if (!skipBufferEffects_ && PSP_IsInited()) {
if (ShouldRunEmulation(mode)) {
// We need to run emulation here, and perform all the normal render passes.
return RunEmulation(false);
} else {
} else if (gpu) {
// Need to check for gpu here, we might be in reset.
const DeviceOrientation orientation = GetDeviceOrientation();
const DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(orientation);
// We run just the post shaders.
@@ -1666,6 +1667,9 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
gpu->CopyDisplayToOutput(displayLayoutConfig);
}
// Reset the viewport. Needed in case Cardboard or something similar was enabled.
draw->SetViewport(viewport);
runImDebugger();
Draw::BackendState state = draw->GetCurrentBackendState();
+7 -7
View File
@@ -206,14 +206,14 @@ void GameScreen::CreateContentViews(UI::ViewGroup *parent) {
std::vector<GameDBInfo> dbInfos;
const bool inGameDB = g_gameDB.GetGameInfos(info_->id_version, &dbInfos);
// Show the game ID title below the icon. The top title will be from the DB.
std::string title = info_->GetTitle();
if (knownFlags_ & GameInfoFlags::PARAM_SFO) {
std::string regionID = ReplaceAll(info_->id_version, "_", " v");
if (!regionID.empty()) {
regionID += ": ";
// Show the game ID title below the icon. The top title will be from the DB.
std::string title = info_->GetTitle();
TextView *tvTitle = mainGameInfo->Add(new TextView(title, ALIGN_LEFT | FLAG_WRAP_TEXT, false, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
tvTitle->SetShadow(true);
}
@@ -278,7 +278,7 @@ void GameScreen::CreateContentViews(UI::ViewGroup *parent) {
auto di = GetI18NCategory(I18NCat::DIALOG);
Choice *btnResetTime = timeHoriz->Add(new Choice(di->T("Reset"), new LinearLayoutParams(0.0f, Gravity::G_VCENTER)));
btnResetTime->OnClick.Add([this, ga, timeStr](UI::EventParams &) {
btnResetTime->OnClick.Add([this, ga, timeStr, title](UI::EventParams &) {
auto di = GetI18NCategory(I18NCat::DIALOG);
auto gta = GetI18NCategory(I18NCat::GAME);
std::string id = info_->id;
@@ -286,12 +286,12 @@ void GameScreen::CreateContentViews(UI::ViewGroup *parent) {
questionText += "\n";
questionText += timeStr;
screenManager()->push(
new PromptScreen(gamePath_, questionText, di->T("Reset"), di->T("Cancel"), [id](bool yes) {
if (yes) {
new UI::MessagePopupScreen(title, questionText, di->T("Reset"), di->T("Cancel"), [this, id](bool reset) {
if (reset) {
g_Config.TimeTracker().Reset(id);
RecreateViews();
}
}));
RecreateViews();
});
}
+11
View File
@@ -12,6 +12,7 @@
#include "Core/Debugger/Breakpoints.h"
#include "Core/MIPS/MIPSDebugInterface.h"
#include "Core/MIPS/MIPSTables.h"
#include "Core/MIPS/MIPSAnalyst.h"
#include "Core/Debugger/SymbolMap.h"
#include "Core/MemMap.h"
#include "Common/System/Request.h"
@@ -751,6 +752,16 @@ void ImDisasmView::PopupMenu(ImControl &control) {
if (ImGui::MenuItem("Copy instruction (hex)")) {
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::OPCODES);
}
if (ImGui::MenuItem("Copy function hash")) {
MIPSAnalyst::AnalyzedFunction func;
if (MIPSAnalyst::GetAnalyzedFunctionAt(curAddress_, &func)) {
if (func.hasHash) {
char temp[256];
snprintf(temp, sizeof(temp), "%016llx:%d = %s\n", func.hash, func.size, func.name);
System_CopyStringToClipboard(temp);
}
}
}
ImGui::Separator();
if (ImGui::MenuItem("Set PC to here")) {
+1 -1
View File
@@ -428,7 +428,7 @@ void ReportFinishScreen::CreateDialogViews(UI::ViewGroup *parent) {
parent->Add(new Spacer(20.0f));
parent->Add(new Choice(rp->T("View Feedback"), ImageID("I_LINK_OUT")))->OnClick.Handle(this, &ReportFinishScreen::HandleViewFeedback);
parent->Add(new Choice(rp->T("View Feedback"), ImageID("I_LINK_OUT"), new LayoutParams(WRAP_CONTENT, ITEM_HEIGHT)))->OnClick.Handle(this, &ReportFinishScreen::HandleViewFeedback);
}
void ReportFinishScreen::update() {
+20 -1
View File
@@ -891,10 +891,26 @@ void CtrlDisAsmView::CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructio
delete [] temp;
} else {
std::string disassembly = DisassembleRange(startAddr,endAddr-startAddr, displaySymbols, debugger);
W32Util::CopyTextToClipboard(wnd, disassembly.c_str());
W32Util::CopyTextToClipboard(wnd, disassembly);
}
}
void CtrlDisAsmView::CopyFunctionHash(u32 addr) {
MIPSAnalyst::AnalyzedFunction func;
if (MIPSAnalyst::GetAnalyzedFunctionAt(addr, &func)) {
if (func.hasHash) {
char temp[256];
snprintf(temp, sizeof(temp), "%016llx:%d = %s\n", func.hash, func.size, func.name);
W32Util::CopyTextToClipboard(wnd, temp);
} else {
MessageBox(wnd, L"No hash", L"", 0);
}
} else {
MessageBox(wnd, L"No function", L"", 0);
}
}
void CtrlDisAsmView::NopInstructions(u32 selectRangeStart, u32 selectRangeEnd) {
for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) {
Memory::Write_U32(0, addr);
@@ -945,6 +961,9 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
case ID_DISASM_COPYINSTRUCTIONHEX:
CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::OPCODES);
break;
case ID_DISASM_COPYFUNCTIONHASH:
CopyFunctionHash(curAddress);
break;
case ID_DISASM_NOPINSTRUCTION:
NopInstructions(selectRangeStart, selectRangeEnd);
redraw();
+1
View File
@@ -75,6 +75,7 @@ class CtrlDisAsmView {
void updateStatusBarText();
void drawBranchLine(HDC hdc, std::map<u32, int> &addressPositions, const BranchLine &line);
void CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructionsMode mode);
void CopyFunctionHash(u32 addr);
void NopInstructions(u32 startAddr, u32 endAddr);
std::set<std::string> getSelectedLineArguments();
void drawArguments(HDC hdc, const DisassemblyLineInfo &line, int x, int y, int textColor, const std::set<std::string> &currentArguments);
+5 -5
View File
@@ -596,7 +596,7 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) {
std::ostringstream stream;
stream << (Memory::IsValidAddress(curAddress_) ? Memory::Read_Float(curAddress_) : NAN);
auto temp_string = stream.str();
W32Util::CopyTextToClipboard(wnd, temp_string.c_str());
W32Util::CopyTextToClipboard(wnd, temp_string);
}
break;
@@ -814,7 +814,7 @@ void CtrlMemView::ScrollCursor(int bytes, GotoMode mode) {
redraw();
}
bool CtrlMemView::ParseSearchString(const std::string &query, bool asHex, std::vector<uint8_t> &data) {
bool CtrlMemView::ParseSearchString(std::string_view query, bool asHex, std::vector<uint8_t> &data) {
data.clear();
if (!asHex) {
for (size_t i = 0; i < query.length(); i++) {
@@ -847,7 +847,7 @@ bool CtrlMemView::ParseSearchString(const std::string &query, bool asHex, std::v
return true;
}
std::vector<u32> CtrlMemView::searchString(const std::string &searchQuery) {
std::vector<u32> CtrlMemView::searchString(std::string_view searchQuery) {
std::vector<u32> searchResAddrs;
auto memLock = Memory::Lock();
@@ -993,8 +993,8 @@ void CtrlMemView::setHighlightType(MemBlockFlags flags) {
}
}
uint32_t CtrlMemView::pickTagColor(const std::string &tag) {
uint32_t CtrlMemView::pickTagColor(std::string_view tag) {
int colors[6] = { 0xe0FFFF, 0xFFE0E0, 0xE8E8FF, 0xFFE0FF, 0xE0FFE0, 0xFFFFE0 };
int which = XXH3_64bits(tag.c_str(), tag.length()) % ARRAY_SIZE(colors);
int which = XXH3_64bits(tag.data(), tag.length()) % ARRAY_SIZE(colors);
return colors[which];
}
+3 -3
View File
@@ -41,7 +41,7 @@ public:
MIPSDebugInterface *getDebugger() {
return debugger_;
}
std::vector<u32> searchString(const std::string &searchQuery);
std::vector<u32> searchString(std::string_view query);
void onPaint(WPARAM wParam, LPARAM lParam);
void onVScroll(WPARAM wParam, LPARAM lParam);
void onKeyDown(WPARAM wParam, LPARAM lParam);
@@ -57,10 +57,10 @@ public:
void setHighlightType(MemBlockFlags flags);
private:
bool ParseSearchString(const std::string &query, bool asHex, std::vector<uint8_t> &data);
bool ParseSearchString(std::string_view query, bool asHex, std::vector<uint8_t> &data);
void updateStatusBarText();
void search(bool continueSearch);
uint32_t pickTagColor(const std::string &tag);
uint32_t pickTagColor(std::string_view tag);
enum class GotoMode {
RESET,
+1
View File
@@ -745,6 +745,7 @@ BEGIN
MENUITEM "Copy Address", ID_DISASM_COPYADDRESS
MENUITEM "Copy Instruction (Hex)", ID_DISASM_COPYINSTRUCTIONHEX
MENUITEM "Copy Instruction (Disasm)", ID_DISASM_COPYINSTRUCTIONDISASM
MENUITEM "Copy Function Hash", ID_DISASM_COPYFUNCTIONHASH
MENUITEM "Disassemble to File", ID_DISASM_DISASSEMBLETOFILE
MENUITEM SEPARATOR
MENUITEM "Assemble Opcode", ID_DISASM_ASSEMBLE
+1
View File
@@ -136,6 +136,7 @@
#define ID_MEMVIEW_COPYVALUE_8 40005
#define ID_DISASM_COPYINSTRUCTIONDISASM 40006
#define ID_DISASM_COPYINSTRUCTIONHEX 40007
#define ID_DISASM_COPYFUNCTIONHASH 40031
#define ID_EMULATION_SPEEDLIMIT 40008
#define ID_TOGGLE_BREAK 40009
#define ID_EMULATION_STOP 40010