mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-17 06:00:48 +01:00
335 lines
7.9 KiB
C++
335 lines
7.9 KiB
C++
#include "stdafx.h"
|
|
|
|
#include "Gui/ConLog.h"
|
|
#include <wx/listctrl.h>
|
|
#include "Ini.h"
|
|
#include <fstream>
|
|
#include <vector>
|
|
|
|
LogWriter ConLog;
|
|
LogFrame* ConLogFrame;
|
|
|
|
enum LogIDs
|
|
{
|
|
id_log_level = 0x888,
|
|
};
|
|
|
|
std::mutex g_cs_conlog;
|
|
|
|
static const uint max_item_count = 500;
|
|
static const uint buffer_size = 1024 * 64;
|
|
|
|
static const std::string g_log_colors[] =
|
|
{
|
|
"Black", "Green", "White", "Yellow", "Red",
|
|
};
|
|
|
|
struct LogPacket
|
|
{
|
|
const std::string m_prefix;
|
|
const std::string m_text;
|
|
const std::string m_colour;
|
|
|
|
LogPacket(const std::string& prefix, const std::string& text, const std::string& colour)
|
|
: m_prefix(prefix)
|
|
, m_text(text)
|
|
, m_colour(colour)
|
|
{
|
|
|
|
}
|
|
};
|
|
|
|
struct _LogBuffer : public MTPacketBuffer<LogPacket>
|
|
{
|
|
_LogBuffer() : MTPacketBuffer<LogPacket>(buffer_size)
|
|
{
|
|
}
|
|
|
|
void _push(const LogPacket& data)
|
|
{
|
|
const u32 sprefix = data.m_prefix.length();
|
|
const u32 stext = data.m_text.length();
|
|
const u32 scolour = data.m_colour.length();
|
|
|
|
m_buffer.resize( m_buffer.size() +
|
|
sizeof(u32) + sprefix +
|
|
sizeof(u32) + stext +
|
|
sizeof(u32) + scolour);
|
|
|
|
u32 c_put = m_put;
|
|
|
|
memcpy(&m_buffer[c_put], &sprefix, sizeof(u32));
|
|
c_put += sizeof(u32);
|
|
memcpy(&m_buffer[c_put], data.m_prefix.c_str(), sprefix);
|
|
c_put += sprefix;
|
|
|
|
memcpy(&m_buffer[c_put], &stext, sizeof(u32));
|
|
c_put += sizeof(u32);
|
|
memcpy(&m_buffer[c_put], data.m_text.c_str(), stext);
|
|
c_put += stext;
|
|
|
|
memcpy(&m_buffer[c_put], &scolour, sizeof(u32));
|
|
c_put += sizeof(u32);
|
|
memcpy(&m_buffer[c_put], data.m_colour.c_str(), scolour);
|
|
c_put += scolour;
|
|
|
|
m_put = c_put;
|
|
CheckBusy();
|
|
}
|
|
|
|
LogPacket _pop()
|
|
{
|
|
u32 c_get = m_get;
|
|
|
|
const u32& sprefix = *(u32*)&m_buffer[c_get];
|
|
c_get += sizeof(u32);
|
|
const std::string prefix( (const char*) &m_buffer[c_get], sprefix);
|
|
c_get += sprefix;
|
|
|
|
const u32& stext = *(u32*)&m_buffer[c_get];
|
|
c_get += sizeof(u32);
|
|
const std::string text( (const char*) &m_buffer[c_get], stext);
|
|
c_get += stext;
|
|
|
|
const u32& scolour = *(u32*)&m_buffer[c_get];
|
|
c_get += sizeof(u32);
|
|
const std::string colour( (const char*) &m_buffer[c_get], scolour);
|
|
c_get += scolour;
|
|
|
|
m_get = c_get;
|
|
if(!HasNewPacket()) Flush();
|
|
|
|
return LogPacket(prefix, text, colour);
|
|
}
|
|
} LogBuffer;
|
|
|
|
LogWriter::LogWriter()
|
|
{
|
|
if(!m_logfile.Open(_PRGNAME_ ".log", wxFile::write))
|
|
{
|
|
#ifndef QT_UI
|
|
wxMessageBox("Can't create log file! (" _PRGNAME_ ".log)", wxMessageBoxCaptionStr, wxICON_ERROR);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void LogWriter::WriteToLog(const std::string& prefix, const std::string& value, u8 lvl/*, wxColour bgcolour*/)
|
|
{
|
|
std::string new_prefix = prefix;
|
|
if(!prefix.empty())
|
|
{
|
|
if(NamedThreadBase* thr = GetCurrentNamedThread())
|
|
{
|
|
new_prefix += " : " + thr->GetThreadName();
|
|
}
|
|
}
|
|
|
|
if(m_logfile.IsOpened() && !new_prefix.empty())
|
|
m_logfile.Write(fmt::FromUTF8("[" + new_prefix + "]: " + value + "\n"));
|
|
|
|
|
|
if(!ConLogFrame)
|
|
return;
|
|
|
|
std::lock_guard<std::mutex> lock(g_cs_conlog);
|
|
|
|
#ifdef QT_UI
|
|
// TODO: Use ThreadBase instead, track main thread id
|
|
if(QThread::currentThread() == qApp->thread())
|
|
#else
|
|
if(wxThread::IsMain())
|
|
#endif
|
|
{
|
|
while(LogBuffer.IsBusy())
|
|
{
|
|
// need extra break condition?
|
|
wxYieldIfNeeded();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (LogBuffer.IsBusy())
|
|
{
|
|
if (Emu.IsStopped())
|
|
{
|
|
break;
|
|
}
|
|
Sleep(1);
|
|
}
|
|
}
|
|
|
|
//if(LogBuffer.put == LogBuffer.get) LogBuffer.Flush();
|
|
|
|
LogBuffer.Push(LogPacket(new_prefix, value, g_log_colors[lvl]));
|
|
}
|
|
|
|
|
|
void LogWriter::SkipLn()
|
|
{
|
|
WriteToLog("", "", 0);
|
|
}
|
|
|
|
BEGIN_EVENT_TABLE(LogFrame, FrameBase)
|
|
EVT_CLOSE(LogFrame::OnQuit)
|
|
END_EVENT_TABLE()
|
|
|
|
LogFrame::LogFrame(wxWindow *parent)
|
|
: FrameBase(nullptr, wxID_ANY, "Log Frame", "LogFrame", wxSize(600, 500),
|
|
wxPoint(parent->GetPosition().x + parent->GetSize().x, parent->GetPosition().y))
|
|
, ThreadBase("LogThread")
|
|
, m_log(*new wxListView(this))
|
|
{
|
|
wxMenuBar* menubar = new wxMenuBar();
|
|
|
|
wxMenu* menu_log_settings = new wxMenu();
|
|
menubar->Append(menu_log_settings, "Settings");
|
|
menu_log_settings->Append(id_log_level, "Log Level");
|
|
|
|
SetMenuBar(menubar);
|
|
|
|
//events
|
|
Bind(wxEVT_MENU, &LogFrame::Settings, this, id_log_level);
|
|
Bind(wxEVT_SIZE, &LogFrame::UpdateListSize, this);
|
|
|
|
m_log.InsertColumn(0, wxEmptyString);
|
|
m_log.InsertColumn(1, "Log");
|
|
m_log.SetBackgroundColour(wxColour("Black"));
|
|
|
|
wxBoxSizer* s_main = new wxBoxSizer(wxVERTICAL);
|
|
s_main->Add(&m_log, 1, wxEXPAND);
|
|
SetSizer(s_main);
|
|
Layout();
|
|
|
|
Show();
|
|
ThreadBase::Start();
|
|
}
|
|
|
|
LogFrame::~LogFrame()
|
|
{
|
|
}
|
|
|
|
bool LogFrame::Close(bool force)
|
|
{
|
|
Stop(false);
|
|
ConLogFrame = nullptr;
|
|
return wxWindowBase::Close(force);
|
|
}
|
|
|
|
void LogFrame::Task()
|
|
{
|
|
while(!TestDestroy())
|
|
{
|
|
if(!LogBuffer.HasNewPacket())
|
|
{
|
|
Sleep(1);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
wxThread::Yield();
|
|
}
|
|
|
|
const LogPacket item = LogBuffer.Pop();
|
|
|
|
wxListView& m_log = this->m_log; //makes m_log capturable by the lambda
|
|
//queue adding the log message to the gui element in the main thread
|
|
wxTheApp->GetTopWindow()->GetEventHandler()->CallAfter([item, &m_log]()
|
|
{
|
|
while (m_log.GetItemCount() > max_item_count)
|
|
{
|
|
m_log.DeleteItem(0);
|
|
wxThread::Yield();
|
|
}
|
|
|
|
const int cur_item = m_log.GetItemCount();
|
|
|
|
m_log.InsertItem(cur_item, fmt::FromUTF8(item.m_prefix));
|
|
m_log.SetItem(cur_item, 1, fmt::FromUTF8(item.m_text));
|
|
m_log.SetItemTextColour(cur_item, fmt::FromUTF8(item.m_colour));
|
|
m_log.SetColumnWidth(0, -1);
|
|
m_log.SetColumnWidth(1, -1);
|
|
});
|
|
|
|
#ifdef _WIN32
|
|
::SendMessage((HWND)m_log.GetHWND(), WM_VSCROLL, SB_BOTTOM, 0);
|
|
#endif
|
|
}
|
|
|
|
LogBuffer.Flush();
|
|
}
|
|
|
|
void LogFrame::OnQuit(wxCloseEvent& event)
|
|
{
|
|
Stop(false);
|
|
ConLogFrame = nullptr;
|
|
event.Skip();
|
|
}
|
|
|
|
void LogFrame::Settings(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
bool paused = false;
|
|
|
|
if (Emu.IsRunning())
|
|
{
|
|
Emu.Pause();
|
|
paused = true;
|
|
}
|
|
|
|
wxDialog diag(this, wxID_ANY, "Settings", wxDefaultPosition);
|
|
|
|
wxStaticBoxSizer* s_round_log_level = new wxStaticBoxSizer(wxVERTICAL, &diag, _("Log Level"));
|
|
wxBoxSizer* s_panel = new wxBoxSizer(wxVERTICAL);
|
|
wxBoxSizer* s_subpanel_loglvl = new wxBoxSizer(wxVERTICAL);
|
|
|
|
wxCheckBox* chbox_log_write = new wxCheckBox(&diag, wxID_ANY, "Write");
|
|
wxCheckBox* chbox_log_error = new wxCheckBox(&diag, wxID_ANY, "Error");
|
|
wxCheckBox* chbox_log_warning = new wxCheckBox(&diag, wxID_ANY, "Warning");
|
|
wxCheckBox* chbox_log_success = new wxCheckBox(&diag, wxID_ANY, "Success");
|
|
wxCheckBox* chbox_hle_logging = new wxCheckBox(&diag, wxID_ANY, "Log all SysCalls");
|
|
|
|
s_round_log_level->Add(chbox_log_write, wxSizerFlags().Border(wxALL, 5).Expand());
|
|
s_round_log_level->Add(chbox_log_error, wxSizerFlags().Border(wxALL, 5).Expand());
|
|
s_round_log_level->Add(chbox_log_warning, wxSizerFlags().Border(wxALL, 5).Expand());
|
|
s_round_log_level->Add(chbox_log_success, wxSizerFlags().Border(wxALL, 5).Expand());
|
|
s_round_log_level->AddSpacer(20);
|
|
s_round_log_level->Add(chbox_hle_logging, wxSizerFlags().Border(wxALL, 5).Expand());
|
|
|
|
// get values from .ini
|
|
chbox_log_write->SetValue(Ini.LogWrite.GetValue());
|
|
chbox_log_warning->SetValue(Ini.LogWarning.GetValue());
|
|
chbox_log_error->SetValue(Ini.LogError.GetValue());
|
|
chbox_log_success->SetValue(Ini.LogSuccess.GetValue());
|
|
chbox_hle_logging->SetValue(Ini.LogAllSysCalls.GetValue());
|
|
|
|
s_subpanel_loglvl->Add(s_round_log_level, wxSizerFlags().Border(wxALL, 5).Expand());
|
|
|
|
wxBoxSizer* s_b_panel(new wxBoxSizer(wxHORIZONTAL));
|
|
s_b_panel->Add(new wxButton(&diag, wxID_OK), wxSizerFlags().Border(wxALL, 5).Bottom());
|
|
s_b_panel->Add(new wxButton(&diag, wxID_CANCEL), wxSizerFlags().Border(wxALL, 5).Bottom());
|
|
|
|
s_panel->Add(s_subpanel_loglvl);
|
|
s_panel->Add(s_b_panel);
|
|
|
|
diag.SetSizerAndFit(s_panel);
|
|
|
|
if (diag.ShowModal() == wxID_OK)
|
|
{
|
|
Ini.LogWrite.SetValue(chbox_log_write->GetValue());
|
|
Ini.LogWarning.SetValue(chbox_log_warning->GetValue());
|
|
Ini.LogError.SetValue(chbox_log_error->GetValue());
|
|
Ini.LogSuccess.SetValue(chbox_log_success->GetValue());
|
|
Ini.LogAllSysCalls.SetValue(chbox_hle_logging->GetValue());
|
|
|
|
Ini.Save();
|
|
}
|
|
|
|
if (paused) Emu.Resume();
|
|
}
|
|
|
|
void LogFrame::UpdateListSize(wxSizeEvent& event)
|
|
{
|
|
int width, height;
|
|
this->DoGetSize(&width, &height);
|
|
m_log.SetSize(wxSize(width-15, height-55));
|
|
event.Skip();
|
|
} |