From a9b010b0cd514f3333b1033798ec1ed869168180 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 5 Jan 2015 01:23:03 +0100 Subject: [PATCH] Add a basic debug console UI to the devmenu that shows some log scrollback and has a little command line. Useful for debugging on non-Windows in the future. For now non-mobile only (although may lift that restriction later) --- Common/LogManager.cpp | 17 ++++++++ Common/LogManager.h | 26 ++++++++++++ GPU/Directx9/FramebufferDX9.cpp | 8 ++-- UI/DevScreens.cpp | 75 +++++++++++++++++++++++++++++++++ UI/DevScreens.h | 16 +++++++ native | 2 +- 6 files changed, 139 insertions(+), 5 deletions(-) diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index 685619263..e508850f8 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -103,6 +103,7 @@ LogManager::LogManager() { consoleLog_ = NULL; debuggerLog_ = NULL; #endif + ringLog_ = new RingbufferLogListener(); for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) { log_[i]->SetEnable(true); @@ -113,6 +114,7 @@ LogManager::LogManager() { if (IsDebuggerPresent() && debuggerLog_ != NULL && LOG_MSC_OUTPUTDEBUG) log_[i]->AddListener(debuggerLog_); #endif + log_[i]->AddListener(ringLog_); #endif } } @@ -285,3 +287,18 @@ void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) { OutputDebugStringUTF8(msg); #endif } + +void RingbufferLogListener::Log(LogTypes::LOG_LEVELS level, const char *msg) { + if (!enabled_) + return; + levels_[curMessage_] = (u8)level; + int len = (int)strlen(msg); + if (len >= sizeof(messages_[0])) + len = sizeof(messages_[0]) - 1; + memcpy(messages_[curMessage_], msg, len); + messages_[curMessage_][len] = 0; + curMessage_++; + if (curMessage_ >= MAX_LOGS) + curMessage_ -= MAX_LOGS; + count_++; +} diff --git a/Common/LogManager.h b/Common/LogManager.h index 501869402..d0e75a94f 100644 --- a/Common/LogManager.h +++ b/Common/LogManager.h @@ -61,6 +61,27 @@ public: void Log(LogTypes::LOG_LEVELS, const char *msg); }; +class RingbufferLogListener : public LogListener { +public: + RingbufferLogListener() : curMessage_(0), count_(0), enabled_(false) {} + void Log(LogTypes::LOG_LEVELS, const char *msg); + + bool IsEnabled() const { return enabled_; } + void SetEnable(bool enable) { enabled_ = enable; } + + int GetCount() const { return count_ < MAX_LOGS ? count_ : MAX_LOGS; } + const char *TextAt(int i) { return messages_[(curMessage_ - i - 1) & (MAX_LOGS - 1)]; } + LogTypes::LOG_LEVELS LevelAt(int i) { return (LogTypes::LOG_LEVELS)levels_[(curMessage_ - i - 1) & (MAX_LOGS - 1)]; } + +private: + enum { MAX_LOGS = 128 }; + char messages_[MAX_LOGS][1024]; + u8 levels_[MAX_LOGS]; + int curMessage_; + int count_; + bool enabled_; +}; + // TODO: A simple buffered log that can be used to display the log in-window // on Android etc. // class BufferedLogListener { ... } @@ -105,6 +126,7 @@ private: FileLogListener *fileLog_; ConsoleListener *consoleLog_; DebuggerLogListener *debuggerLog_; + RingbufferLogListener *ringLog_; static LogManager *logManager_; // Singleton. Ugh. std::mutex log_lock_; @@ -157,6 +179,10 @@ public: return debuggerLog_; } + RingbufferLogListener *GetRingbufferListener() const { + return ringLog_; + } + static LogManager* GetInstance() { return logManager_; } diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 6fea68208..d431f69aa 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -774,9 +774,9 @@ namespace DX9 { const u32 rh = PSP_CoreParameter().pixelHeight; const RECT srcRect = {(LONG)(u0 * vfb->renderWidth), (LONG)(v0 * vfb->renderHeight), (LONG)(u1 * vfb->renderWidth), (LONG)(v1 * vfb->renderHeight)}; const RECT dstRect = {x * rw / w, y * rh / h, (x + w) * rw / w, (y + h) * rh / h}; - HRESULT hr = fbo_blit_color(vfb->fbo, &srcRect, nullptr, &dstRect, g_Config.iBufFilter == SCALE_LINEAR ? D3DTEXF_LINEAR : D3DTEXF_POINT); - if (FAILED(hr)) { - ERROR_LOG_REPORT_ONCE(blit_fail, G3D, "fbo_blit_color failed on display: %08x", hr); + //HRESULT hr = fbo_blit_color(vfb->fbo, &srcRect, nullptr, &dstRect, g_Config.iBufFilter == SCALE_LINEAR ? D3DTEXF_LINEAR : D3DTEXF_POINT); + //if (FAILED(hr)) { + // ERROR_LOG_REPORT_ONCE(blit_fail, G3D, "fbo_blit_color failed on display: %08x", hr); dxstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); // These are in the output display coordinates if (g_Config.iBufFilter == SCALE_LINEAR) { @@ -789,7 +789,7 @@ namespace DX9 { dxstate.texMipFilter.set(D3DTEXF_NONE); dxstate.texMipLodBias.set(0); DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, false, u0, v0, u1, v1); - } + //} } /* else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) { diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 81ced3bae..03f880577 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -55,11 +55,25 @@ void DevMenu::CreatePopupContents(UI::ViewGroup *parent) { I18NCategory *de = GetI18NCategory("Developer"); I18NCategory *sy = GetI18NCategory("System"); +#if !defined(MOBILE_DEVICE) + parent->Add(new Choice(de->T("Log View")))->OnClick.Handle(this, &DevMenu::OnLogView); +#endif parent->Add(new Choice(de->T("Logging Channels")))->OnClick.Handle(this, &DevMenu::OnLogConfig); parent->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &DevMenu::OnDeveloperTools); parent->Add(new Choice(de->T("Jit Compare")))->OnClick.Handle(this, &DevMenu::OnJitCompare); parent->Add(new Choice(de->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenu::OnFreezeFrame); parent->Add(new Choice(de->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenu::OnDumpFrame); + + RingbufferLogListener *ring = LogManager::GetInstance()->GetRingbufferListener(); + if (ring) { + ring->SetEnable(true); + } +} + +UI::EventReturn DevMenu::OnLogView(UI::EventParams &e) { + UpdateUIState(UISTATE_PAUSEMENU); + screenManager()->push(new LogScreen()); + return UI::EVENT_DONE; } UI::EventReturn DevMenu::OnLogConfig(UI::EventParams &e) { @@ -100,6 +114,67 @@ void DevMenu::dialogFinished(const Screen *dialog, DialogResult result) { // screenManager()->finishDialog(this, DR_OK); } +void LogScreen::UpdateLog() { + using namespace UI; + RingbufferLogListener *ring = LogManager::GetInstance()->GetRingbufferListener(); + if (!ring) + return; + vert_->Clear(); + for (int i = ring->GetCount() - 1; i >= 0; i--) { + TextView *v = vert_->Add(new TextView(ring->TextAt(i), FLAG_DYNAMIC_ASCII, false)); + uint32_t color = 0xFFFFFF; + switch (ring->LevelAt(i)) { + case LogTypes::LDEBUG: color = 0xE0E0E0; break; + case LogTypes::LWARNING: color = 0x50FFFF; break; + case LogTypes::LERROR: color = 0x5050FF; break; + case LogTypes::LNOTICE: color = 0x30FF30; break; + case LogTypes::LINFO: color = 0xFFFFFF; break; + } + v->SetTextColor(0xFF000000 | color); + } + toBottom_ = true; +} + +void LogScreen::update(InputState &input) { + UIDialogScreenWithBackground::update(input); + if (toBottom_) { + toBottom_ = false; + scroll_->ScrollToBottom(); + } +} + +void LogScreen::CreateViews() { + using namespace UI; + I18NCategory *di = GetI18NCategory("Dialog"); + + LinearLayout *outer = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + root_ = outer; + + scroll_ = outer->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0))); + LinearLayout *bottom = outer->Add(new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); + bottom->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); + cmdLine_ = bottom->Add(new TextEdit("", "Command Line", new LinearLayoutParams(1.0))); + cmdLine_->OnEnter.Handle(this, &LogScreen::OnSubmit); + bottom->Add(new Button(di->T("Submit")))->OnClick.Handle(this, &LogScreen::OnSubmit); + + vert_ = scroll_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + vert_->SetSpacing(0); + + UpdateLog(); +} + +UI::EventReturn LogScreen::OnSubmit(UI::EventParams &e) { + std::string cmd = cmdLine_->GetText(); + + // TODO: Can add all sorts of fun stuff here that we can't be bothered writing proper UI for, like various memdumps etc. + + NOTICE_LOG(HLE, "Submitted: %s", cmd.c_str()); + + UpdateLog(); + cmdLine_->SetText(""); + cmdLine_->SetFocus(); + return UI::EVENT_DONE; +} void LogConfigScreen::CreateViews() { using namespace UI; diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 285f2fc34..d2bcc822c 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -36,6 +36,7 @@ public: virtual void dialogFinished(const Screen *dialog, DialogResult result); protected: + UI::EventReturn OnLogView(UI::EventParams &e); UI::EventReturn OnLogConfig(UI::EventParams &e); UI::EventReturn OnJitCompare(UI::EventParams &e); UI::EventReturn OnFreezeFrame(UI::EventParams &e); @@ -54,6 +55,21 @@ private: UI::EventReturn OnLogLevelChange(UI::EventParams &e); }; +class LogScreen : public UIDialogScreenWithBackground { +public: + LogScreen() : toBottom_(false) {} + void CreateViews() override; + void update(InputState &input) override; + +private: + void UpdateLog(); + UI::EventReturn OnSubmit(UI::EventParams &e); + UI::TextEdit *cmdLine_; + UI::LinearLayout *vert_; + UI::ScrollView *scroll_; + bool toBottom_; +}; + class LogLevelScreen : public ListPopupScreen { public: LogLevelScreen(const std::string &title); diff --git a/native b/native index 3ebd46750..40848ae4b 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 3ebd4675091e3d08e0da3ad8d3d66d1adff1697a +Subproject commit 40848ae4b64907fec31b2562fc977c043133a275