You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/apps/openmw/mwgui/debugwindow.cpp

223 lines
7.8 KiB
C++

#include "debugwindow.hpp"
#include <MyGUI_TabControl.h>
#include <MyGUI_TabItem.h>
#include <MyGUI_EditBox.h>
#include <LinearMath/btQuickprof.h>
#include <components/debug/debugging.hpp>
#include <components/settings/settings.hpp>
#include <mutex>
#ifndef BT_NO_PROFILE
namespace
{
void bulletDumpRecursive(CProfileIterator* pit, int spacing, std::stringstream& os)
{
pit->First();
if (pit->Is_Done())
return;
float accumulated_time=0,parent_time = pit->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : pit->Get_Current_Parent_Total_Time();
int i,j;
int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset();
for (i=0;i<spacing;i++) os << ".";
os << "----------------------------------\n";
for (i=0;i<spacing;i++) os << ".";
std::string s = "Profiling: "+
std::string(pit->Get_Current_Parent_Name())+" (total running time: "+MyGUI::utility::toString(parent_time,3)+" ms) ---\n";
os << s;
//float totalTime = 0.f;
int numChildren = 0;
for (i = 0; !pit->Is_Done(); i++,pit->Next())
{
numChildren++;
float current_total_time = pit->Get_Current_Total_Time();
accumulated_time += current_total_time;
float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
for (j=0;j<spacing;j++) os << ".";
double ms = (current_total_time / (double)frames_since_reset);
s = MyGUI::utility::toString(i)+" -- "+pit->Get_Current_Name()+" ("+MyGUI::utility::toString(fraction,2)+" %) :: "+MyGUI::utility::toString(ms,3)+" ms / frame ("+MyGUI::utility::toString(pit->Get_Current_Total_Calls())+" calls)\n";
os << s;
//totalTime += current_total_time;
//recurse into children
}
if (parent_time < accumulated_time)
{
os << "what's wrong\n";
}
for (i=0;i<spacing;i++) os << ".";
double unaccounted= parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f;
s = "Unaccounted: ("+MyGUI::utility::toString(unaccounted,3)+" %) :: "+MyGUI::utility::toString(parent_time - accumulated_time,3)+" ms\n";
os << s;
for (i=0;i<numChildren;i++)
{
pit->Enter_Child(i);
bulletDumpRecursive(pit, spacing+3, os);
pit->Enter_Parent();
}
}
void bulletDumpAll(std::stringstream& os)
{
CProfileIterator* profileIterator = 0;
profileIterator = CProfileManager::Get_Iterator();
bulletDumpRecursive(profileIterator, 0, os);
CProfileManager::Release_Iterator(profileIterator);
}
}
#endif // BT_NO_PROFILE
namespace MWGui
{
DebugWindow::DebugWindow()
: WindowBase("openmw_debug_window.layout")
{
getWidget(mTabControl, "TabControl");
// Ideas for other tabs:
// - Texture / compositor texture viewer
// - Material editor
// - Shader editor
MyGUI::TabItem* itemLV = mTabControl->addItem("Log Viewer");
itemLV->setCaptionWithReplacing(" #{DebugMenu:LogViewer} ");
mLogView = itemLV->createWidgetReal<MyGUI::EditBox>
("LogEdit", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Stretch);
mLogView->setEditReadOnly(true);
#ifndef BT_NO_PROFILE
MyGUI::TabItem* item = mTabControl->addItem("Physics Profiler");
item->setCaptionWithReplacing(" #{DebugMenu:PhysicsProfiler} ");
mBulletProfilerEdit = item->createWidgetReal<MyGUI::EditBox>
("LogEdit", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Stretch);
#else
mBulletProfilerEdit = nullptr;
#endif
}
static std::vector<char> sLogCircularBuffer;
static std::mutex sBufferMutex;
static int64_t sLogStartIndex;
static int64_t sLogEndIndex;
void DebugWindow::startLogRecording()
{
sLogCircularBuffer.resize(std::max<int64_t>(0, Settings::Manager::getInt64("log buffer size", "General")));
Debug::setLogListener([](Debug::Level level, std::string_view prefix, std::string_view msg)
{
if (sLogCircularBuffer.empty())
return; // Log viewer is disabled.
std::string_view color;
switch (level)
{
case Debug::Error: color = "#FF0000"; break;
case Debug::Warning: color = "#FFFF00"; break;
case Debug::Info: color = "#FFFFFF"; break;
case Debug::Verbose:
case Debug::Debug: color = "#666666"; break;
default: color = "#FFFFFF";
}
bool bufferOverflow = false;
std::lock_guard lock(sBufferMutex);
const int64_t bufSize = sLogCircularBuffer.size();
auto addChar = [&](char c)
{
sLogCircularBuffer[sLogEndIndex++] = c;
if (sLogEndIndex == bufSize)
sLogEndIndex = 0;
bufferOverflow = bufferOverflow || sLogEndIndex == sLogStartIndex;
};
auto addShieldedStr = [&](std::string_view s)
{
for (char c : s)
{
addChar(c);
if (c == '#')
addChar(c);
}
};
for (char c : color)
addChar(c);
addShieldedStr(prefix);
addShieldedStr(msg);
if (bufferOverflow)
sLogStartIndex = (sLogEndIndex + 1) % bufSize;
});
}
void DebugWindow::updateLogView()
{
std::lock_guard lock(sBufferMutex);
if (!mLogView || sLogCircularBuffer.empty() || sLogStartIndex == sLogEndIndex)
return;
if (mLogView->isTextSelection())
return; // Don't change text while player is trying to copy something
std::string addition;
const int64_t bufSize = sLogCircularBuffer.size();
{
if (sLogStartIndex < sLogEndIndex)
addition = std::string(sLogCircularBuffer.data() + sLogStartIndex, sLogEndIndex - sLogStartIndex);
else
{
addition = std::string(sLogCircularBuffer.data() + sLogStartIndex, bufSize - sLogStartIndex);
addition.append(sLogCircularBuffer.data(), sLogEndIndex);
}
sLogStartIndex = sLogEndIndex;
}
size_t scrollPos = mLogView->getVScrollPosition();
bool scrolledToTheEnd = scrollPos+1 >= mLogView->getVScrollRange();
int64_t newSizeEstimation = mLogView->getTextLength() + addition.size();
if (newSizeEstimation > bufSize)
mLogView->eraseText(0, newSizeEstimation - bufSize);
mLogView->addText(addition);
if (scrolledToTheEnd && mLogView->getVScrollRange() > 0)
mLogView->setVScrollPosition(mLogView->getVScrollRange() - 1);
else
mLogView->setVScrollPosition(scrollPos);
}
void DebugWindow::updateBulletProfile()
{
#ifndef BT_NO_PROFILE
std::stringstream stream;
bulletDumpAll(stream);
if (mBulletProfilerEdit->isTextSelection()) // pause updating while user is trying to copy text
return;
size_t previousPos = mBulletProfilerEdit->getVScrollPosition();
mBulletProfilerEdit->setCaption(stream.str());
mBulletProfilerEdit->setVScrollPosition(std::min(previousPos, mBulletProfilerEdit->getVScrollRange()-1));
#endif
}
void DebugWindow::onFrame(float dt)
{
static float timer = 0;
timer -= dt;
if (timer > 0 || !isVisible())
return;
timer = 0.25;
if (mTabControl->getIndexSelected() == 0)
updateLogView();
else
updateBulletProfile();
}
}