mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 04:02:42 +01:00
kernel_explorer: keep existing trees expanded
This commit is contained in:
parent
b75af69cf9
commit
66f1cbfb34
@ -1,5 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QHeaderView>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
@ -23,10 +30,106 @@
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
|
||||
#include "kernel_explorer.h"
|
||||
#include "qt_utils.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QHeaderView>
|
||||
constexpr auto qstr = QString::fromStdString;
|
||||
|
||||
enum kernel_item_role
|
||||
{
|
||||
name_role = Qt::UserRole + 0,
|
||||
expanded_role = Qt::UserRole + 1,
|
||||
type_role = Qt::UserRole + 2,
|
||||
id_role = Qt::UserRole + 3,
|
||||
};
|
||||
|
||||
enum kernel_item_type : int
|
||||
{
|
||||
root,
|
||||
node,
|
||||
volatile_node,
|
||||
leaf
|
||||
};
|
||||
|
||||
static QTreeWidgetItem* add_child(QTreeWidgetItem *parent, const QString& text, int column, kernel_item_type type)
|
||||
{
|
||||
if (parent)
|
||||
{
|
||||
for (int i = 0; i < parent->childCount(); i++)
|
||||
{
|
||||
if (parent->child(i)->data(0, kernel_item_role::name_role).toString() == text)
|
||||
{
|
||||
return parent->child(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
QTreeWidgetItem* item = gui::utils::add_child(parent, text, column);
|
||||
if (item)
|
||||
{
|
||||
item->setData(0, kernel_item_role::name_role, text);
|
||||
item->setData(0, kernel_item_role::type_role, type);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static QTreeWidgetItem* add_leaf(QTreeWidgetItem *parent, const QString& text, int column = 0)
|
||||
{
|
||||
return add_child(parent, text, column, kernel_item_type::leaf);
|
||||
}
|
||||
|
||||
static QTreeWidgetItem* add_node(u32 id, QTreeWidgetItem *parent, const QString& text, int column = 0)
|
||||
{
|
||||
QTreeWidgetItem* node = add_child(parent, text, column, kernel_item_type::node);
|
||||
if (node)
|
||||
{
|
||||
node->setData(0, kernel_item_role::id_role, id);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static QTreeWidgetItem* find_first_node(QTreeWidget* tree, QTreeWidgetItem *parent, const QString& regexp)
|
||||
{
|
||||
if (tree && parent)
|
||||
{
|
||||
for (auto item : tree->findItems(regexp, Qt::MatchFlag::MatchRegExp | Qt::MatchFlag::MatchRecursive))
|
||||
{
|
||||
if (item->parent() == parent && item->data(0, kernel_item_role::type_role).toInt() != kernel_item_type::leaf)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static QTreeWidgetItem* find_node(QTreeWidget* tree, u32 id)
|
||||
{
|
||||
if (tree)
|
||||
{
|
||||
for (auto item : tree->findItems(".*", Qt::MatchFlag::MatchRegExp | Qt::MatchFlag::MatchRecursive))
|
||||
{
|
||||
if (item->data(0, kernel_item_role::type_role).toInt() == kernel_item_type::node &&
|
||||
item->data(0, kernel_item_role::id_role).toUInt() == id)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static QTreeWidgetItem* add_volatile_node(QTreeWidget* tree, QTreeWidgetItem *parent, const QString& base_text, const QString& text = "", int column = 0)
|
||||
{
|
||||
QTreeWidgetItem* node = find_first_node(tree, parent, base_text + ".*");
|
||||
if (!node)
|
||||
{
|
||||
node = add_child(parent, base_text, column, kernel_item_type::volatile_node);
|
||||
}
|
||||
if (node)
|
||||
{
|
||||
node->setText(0, text.isEmpty() ? base_text : text);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
kernel_explorer::kernel_explorer(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
@ -60,12 +163,8 @@ kernel_explorer::kernel_explorer(QWidget* parent) : QDialog(parent)
|
||||
Update();
|
||||
}
|
||||
|
||||
constexpr auto qstr = QString::fromStdString;
|
||||
|
||||
void kernel_explorer::Update()
|
||||
{
|
||||
m_tree->clear();
|
||||
|
||||
const auto dct = g_fxo->get<lv2_memory_container>();
|
||||
|
||||
if (!dct)
|
||||
@ -73,122 +172,171 @@ void kernel_explorer::Update()
|
||||
return;
|
||||
}
|
||||
|
||||
static const size_t additional_size = 6;
|
||||
|
||||
const std::unordered_map<u32, QString> tree_item_names =
|
||||
{
|
||||
{ SYS_MEM_OBJECT , tr("Memory")},
|
||||
{ SYS_MUTEX_OBJECT , tr("Mutexes")},
|
||||
{ SYS_COND_OBJECT , tr("Condition Variables")},
|
||||
{ SYS_RWLOCK_OBJECT , tr("Reader Writer Locks")},
|
||||
{ SYS_INTR_TAG_OBJECT , tr("Interrupt Tags")},
|
||||
{ SYS_INTR_SERVICE_HANDLE_OBJECT , tr("Interrupt Service Handles")},
|
||||
{ SYS_EVENT_QUEUE_OBJECT , tr("Event Queues")},
|
||||
{ SYS_EVENT_PORT_OBJECT , tr("Event Ports")},
|
||||
{ SYS_TRACE_OBJECT , tr("Traces")},
|
||||
{ SYS_SPUIMAGE_OBJECT , tr("SPU Images")},
|
||||
{ SYS_PRX_OBJECT , tr("PRX Modules")},
|
||||
{ SYS_SPUPORT_OBJECT , tr("SPU Ports")},
|
||||
{ SYS_OVERLAY_OBJECT , tr("Overlay Modules")},
|
||||
{ SYS_LWMUTEX_OBJECT , tr("Light Weight Mutexes")},
|
||||
{ SYS_TIMER_OBJECT , tr("Timers")},
|
||||
{ SYS_SEMAPHORE_OBJECT , tr("Semaphores")},
|
||||
{ SYS_FS_FD_OBJECT , tr("File Descriptors ?")},
|
||||
{ SYS_LWCOND_OBJECT , tr("Light Weight Condition Variables")},
|
||||
{ SYS_EVENT_FLAG_OBJECT , tr("Event Flags")},
|
||||
|
||||
{ memory_containers , tr("Memory Containers")},
|
||||
{ ppu_threads , tr("PPU Threads")},
|
||||
{ spu_threads , tr("SPU Threads")},
|
||||
{ spu_thread_groups , tr("SPU Thread Groups")},
|
||||
{ rsx_contexts , tr("RSX Contexts")},
|
||||
{ file_descriptors , tr("File Descriptors")},
|
||||
};
|
||||
|
||||
QTreeWidgetItem* root = m_tree->topLevelItem(0);
|
||||
if (!root)
|
||||
{
|
||||
root = new QTreeWidgetItem();
|
||||
root->setData(0, kernel_item_role::type_role, kernel_item_type::root);
|
||||
m_tree->addTopLevelItem(root);
|
||||
|
||||
for (const auto& [key, name] : tree_item_names)
|
||||
{
|
||||
add_node(key, root, name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::function<void(QTreeWidgetItem*)> clean_up_tree;
|
||||
clean_up_tree = [&clean_up_tree](QTreeWidgetItem* item)
|
||||
{
|
||||
if (item && item->data(0, kernel_item_role::type_role).toInt() != kernel_item_type::leaf)
|
||||
{
|
||||
item->setText(0, item->data(0, kernel_item_role::name_role).toString());
|
||||
item->setData(0, kernel_item_role::expanded_role, item->isExpanded());
|
||||
|
||||
for (int i = item->childCount() - 1; i >= 0; i--)
|
||||
{
|
||||
switch (item->child(i)->data(0, kernel_item_role::type_role).toInt())
|
||||
{
|
||||
case kernel_item_type::leaf:
|
||||
{
|
||||
delete item->takeChild(i);
|
||||
break;
|
||||
}
|
||||
case kernel_item_type::volatile_node:
|
||||
{
|
||||
if (item->child(i)->childCount() <= 0)
|
||||
{
|
||||
// Cleanup volatile node if it has no children
|
||||
delete item->takeChild(i);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case kernel_item_type::node:
|
||||
case kernel_item_type::root:
|
||||
default:
|
||||
{
|
||||
clean_up_tree(item->child(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
clean_up_tree(root);
|
||||
}
|
||||
|
||||
const u32 total_memory_usage = dct->used;
|
||||
|
||||
QTreeWidgetItem* root = new QTreeWidgetItem();
|
||||
root->setText(0, qstr(fmt::format("Process 0x%08x: Total Memory Usage: 0x%x/0x%x (%0.2f/%0.2f MB)", process_getpid(), total_memory_usage, dct->size, 1. * total_memory_usage / (1024 * 1024)
|
||||
, 1. * dct->size / (1024 * 1024))));
|
||||
m_tree->addTopLevelItem(root);
|
||||
|
||||
// TODO: FileSystem
|
||||
|
||||
struct lv2_obj_rec
|
||||
{
|
||||
QTreeWidgetItem* node;
|
||||
u32 count{ 0 };
|
||||
|
||||
lv2_obj_rec() = default;
|
||||
lv2_obj_rec(QTreeWidgetItem* node)
|
||||
: node(node)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
auto l_addTreeChild = [this](QTreeWidgetItem *parent, QString text)
|
||||
{
|
||||
QTreeWidgetItem *treeItem = new QTreeWidgetItem();
|
||||
treeItem->setText(0, text);
|
||||
parent->addChild(treeItem);
|
||||
return treeItem;
|
||||
};
|
||||
|
||||
std::vector<lv2_obj_rec> lv2_types(256);
|
||||
lv2_types[SYS_MEM_OBJECT] = l_addTreeChild(root, "Memory");
|
||||
lv2_types[SYS_MUTEX_OBJECT] = l_addTreeChild(root, "Mutexes");
|
||||
lv2_types[SYS_COND_OBJECT] = l_addTreeChild(root, "Condition Variables");
|
||||
lv2_types[SYS_RWLOCK_OBJECT] = l_addTreeChild(root, "Reader Writer Locks");
|
||||
lv2_types[SYS_INTR_TAG_OBJECT] = l_addTreeChild(root, "Interrupt Tags");
|
||||
lv2_types[SYS_INTR_SERVICE_HANDLE_OBJECT] = l_addTreeChild(root, "Interrupt Service Handles");
|
||||
lv2_types[SYS_EVENT_QUEUE_OBJECT] = l_addTreeChild(root, "Event Queues");
|
||||
lv2_types[SYS_EVENT_PORT_OBJECT] = l_addTreeChild(root, "Event Ports");
|
||||
lv2_types[SYS_TRACE_OBJECT] = l_addTreeChild(root, "Traces");
|
||||
lv2_types[SYS_SPUIMAGE_OBJECT] = l_addTreeChild(root, "SPU Images");
|
||||
lv2_types[SYS_PRX_OBJECT] = l_addTreeChild(root, "PRX Modules");
|
||||
lv2_types[SYS_SPUPORT_OBJECT] = l_addTreeChild(root, "SPU Ports");
|
||||
lv2_types[SYS_OVERLAY_OBJECT] = l_addTreeChild(root, "Overlay Modules");
|
||||
lv2_types[SYS_LWMUTEX_OBJECT] = l_addTreeChild(root, "Light Weight Mutexes");
|
||||
lv2_types[SYS_TIMER_OBJECT] = l_addTreeChild(root, "Timers");
|
||||
lv2_types[SYS_SEMAPHORE_OBJECT] = l_addTreeChild(root, "Semaphores");
|
||||
lv2_types[SYS_LWCOND_OBJECT] = l_addTreeChild(root, "Light Weight Condition Variables");
|
||||
lv2_types[SYS_EVENT_FLAG_OBJECT] = l_addTreeChild(root, "Event Flags");
|
||||
|
||||
idm::select<lv2_obj>([&](u32 id, lv2_obj& obj)
|
||||
{
|
||||
lv2_types[id >> 24].count++;
|
||||
auto node = find_node(m_tree, id >> 24);
|
||||
if (!node)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto& node = lv2_types[id >> 24].node) switch (id >> 24)
|
||||
switch (id >> 24)
|
||||
{
|
||||
case SYS_MEM_OBJECT:
|
||||
{
|
||||
auto& mem = static_cast<lv2_memory&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Memory 0x%08x: Size: 0x%x (%0.2f MB), Granularity: %s, Mappings: %u", id, mem.size, mem.size * 1. / (1024 * 1024), mem.align == 0x10000u ? "64K" : "1MB", +mem.counter)));
|
||||
add_leaf(node, qstr(fmt::format("Memory 0x%08x: Size: 0x%x (%0.2f MB), Granularity: %s, Mappings: %u", id, mem.size, mem.size * 1. / (1024 * 1024), mem.align == 0x10000u ? "64K" : "1MB", +mem.counter)));
|
||||
break;
|
||||
}
|
||||
case SYS_MUTEX_OBJECT:
|
||||
{
|
||||
auto& mutex = static_cast<lv2_mutex&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"Mutex 0x%08x: “%s”,%s Owner: %#x, Locks: %u, Key: %#llx, Conds: %u, Wq: %zu", id, lv2_obj::name64(mutex.name),
|
||||
add_leaf(node, qstr(fmt::format(u8"Mutex 0x%08x: “%s”,%s Owner: %#x, Locks: %u, Key: %#llx, Conds: %u, Wq: %zu", id, lv2_obj::name64(mutex.name),
|
||||
mutex.recursive == SYS_SYNC_RECURSIVE ? " Recursive," : "", mutex.owner >> 1, +mutex.lock_count, mutex.key, +mutex.cond_count, mutex.sq.size())));
|
||||
break;
|
||||
}
|
||||
case SYS_COND_OBJECT:
|
||||
{
|
||||
auto& cond = static_cast<lv2_cond&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"Cond 0x%08x: “%s”, Key: %#llx, Wq: %u", id, lv2_obj::name64(cond.name), cond.key, +cond.waiters)));
|
||||
add_leaf(node, qstr(fmt::format(u8"Cond 0x%08x: “%s”, Key: %#llx, Wq: %u", id, lv2_obj::name64(cond.name), cond.key, +cond.waiters)));
|
||||
break;
|
||||
}
|
||||
case SYS_RWLOCK_OBJECT:
|
||||
{
|
||||
auto& rw = static_cast<lv2_rwlock&>(obj);
|
||||
const s64 val = rw.owner;
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"RW Lock 0x%08x: “%s”, Owner: %#x(%d), Key: %#llx, Rq: %zu, Wq: %zu", id, lv2_obj::name64(rw.name),
|
||||
add_leaf(node, qstr(fmt::format(u8"RW Lock 0x%08x: “%s”, Owner: %#x(%d), Key: %#llx, Rq: %zu, Wq: %zu", id, lv2_obj::name64(rw.name),
|
||||
std::max<s64>(0, val >> 1), -std::min<s64>(0, val >> 1), rw.key, rw.rq.size(), rw.wq.size())));
|
||||
break;
|
||||
}
|
||||
case SYS_INTR_TAG_OBJECT:
|
||||
{
|
||||
// auto& tag = static_cast<lv2_int_tag&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Intr Tag 0x%08x", id)));
|
||||
add_leaf(node, qstr(fmt::format("Intr Tag 0x%08x", id)));
|
||||
break;
|
||||
}
|
||||
case SYS_INTR_SERVICE_HANDLE_OBJECT:
|
||||
{
|
||||
// auto& serv = static_cast<lv2_int_serv&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Intr Svc 0x%08x", id)));
|
||||
add_leaf(node, qstr(fmt::format("Intr Svc 0x%08x", id)));
|
||||
break;
|
||||
}
|
||||
case SYS_EVENT_QUEUE_OBJECT:
|
||||
{
|
||||
auto& eq = static_cast<lv2_event_queue&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"Event Queue 0x%08x: “%s”, %s, Key: %#llx, Events: %zu/%d, Wq: %zu", id, lv2_obj::name64(eq.name),
|
||||
add_leaf(node, qstr(fmt::format(u8"Event Queue 0x%08x: “%s”, %s, Key: %#llx, Events: %zu/%d, Wq: %zu", id, lv2_obj::name64(eq.name),
|
||||
eq.type == SYS_SPU_QUEUE ? "SPU" : "PPU", eq.key, eq.events.size(), eq.size, eq.sq.size())));
|
||||
break;
|
||||
}
|
||||
case SYS_EVENT_PORT_OBJECT:
|
||||
{
|
||||
auto& ep = static_cast<lv2_event_port&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Event Port 0x%08x: Name: %#llx, Bound: %s", id, ep.name, lv2_event_queue::check(ep.queue))));
|
||||
add_leaf(node, qstr(fmt::format("Event Port 0x%08x: Name: %#llx, Bound: %s", id, ep.name, lv2_event_queue::check(ep.queue))));
|
||||
break;
|
||||
}
|
||||
case SYS_TRACE_OBJECT:
|
||||
{
|
||||
l_addTreeChild(node, qstr(fmt::format("Trace 0x%08x", id)));
|
||||
add_leaf(node, qstr(fmt::format("Trace 0x%08x", id)));
|
||||
break;
|
||||
}
|
||||
case SYS_SPUIMAGE_OBJECT:
|
||||
{
|
||||
auto& spi = static_cast<lv2_spu_image&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("SPU Image 0x%08x, Entry: 0x%x, Segs: *0x%x, Num Segs: %d", id, spi.e_entry, spi.segs, spi.nsegs)));
|
||||
add_leaf(node, qstr(fmt::format("SPU Image 0x%08x, Entry: 0x%x, Segs: *0x%x, Num Segs: %d", id, spi.e_entry, spi.segs, spi.nsegs)));
|
||||
break;
|
||||
}
|
||||
case SYS_PRX_OBJECT:
|
||||
@ -198,23 +346,23 @@ void kernel_explorer::Update()
|
||||
|
||||
if (!addr0)
|
||||
{
|
||||
l_addTreeChild(node, qstr(fmt::format("PRX 0x%08x: '%s' (HLE)", id, prx.name)));
|
||||
add_leaf(node, qstr(fmt::format("PRX 0x%08x: '%s' (HLE)", id, prx.name)));
|
||||
break;
|
||||
}
|
||||
|
||||
const u32 end0 = addr0 + prx.segs[0].size - 1;
|
||||
l_addTreeChild(node, qstr(fmt::format("PRX 0x%08x: '%s', Seg0: (0x%x...0x%x)", id, prx.name, addr0, end0)));
|
||||
add_leaf(node, qstr(fmt::format("PRX 0x%08x: '%s', Seg0: (0x%x...0x%x)", id, prx.name, addr0, end0)));
|
||||
break;
|
||||
}
|
||||
case SYS_SPUPORT_OBJECT:
|
||||
{
|
||||
l_addTreeChild(node, qstr(fmt::format("SPU Port 0x%08x", id)));
|
||||
add_leaf(node, qstr(fmt::format("SPU Port 0x%08x", id)));
|
||||
break;
|
||||
}
|
||||
case SYS_OVERLAY_OBJECT:
|
||||
{
|
||||
auto& ovl = static_cast<lv2_overlay&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("OVL 0x%08x: '%s', Seg0: (0x%x...0x%x)", id, ovl.name, ovl.segs[0].addr, ovl.segs[0].addr + ovl.segs[0].size - 1)));
|
||||
add_leaf(node, qstr(fmt::format("OVL 0x%08x: '%s', Seg0: (0x%x...0x%x)", id, ovl.name, ovl.segs[0].addr, ovl.segs[0].addr + ovl.segs[0].size - 1)));
|
||||
break;
|
||||
}
|
||||
case SYS_LWMUTEX_OBJECT:
|
||||
@ -243,74 +391,63 @@ void kernel_explorer::Update()
|
||||
}
|
||||
else
|
||||
{
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"LWMutex 0x%08x: “%s”, Wq: %zu (Couldn't extract control data)", id, lv2_obj::name64(lwm.name), lwm.sq.size())));
|
||||
add_leaf(node, qstr(fmt::format(u8"LWMutex 0x%08x: “%s”, Wq: %zu (Couldn't extract control data)", id, lv2_obj::name64(lwm.name), lwm.sq.size())));
|
||||
break;
|
||||
}
|
||||
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"LWMutex 0x%08x: “%s”,%s Owner: %s, Locks: %u, Wq: %zu", id, lv2_obj::name64(lwm.name),
|
||||
add_leaf(node, qstr(fmt::format(u8"LWMutex 0x%08x: “%s”,%s Owner: %s, Locks: %u, Wq: %zu", id, lv2_obj::name64(lwm.name),
|
||||
(lwm_data.attribute & SYS_SYNC_RECURSIVE) ? " Recursive," : "", owner_str, lwm_data.recursive_count, lwm.sq.size())));
|
||||
break;
|
||||
}
|
||||
case SYS_TIMER_OBJECT:
|
||||
{
|
||||
// auto& timer = static_cast<lv2_timer&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Timer 0x%08x", id)));
|
||||
add_leaf(node, qstr(fmt::format("Timer 0x%08x", id)));
|
||||
break;
|
||||
}
|
||||
case SYS_SEMAPHORE_OBJECT:
|
||||
{
|
||||
auto& sema = static_cast<lv2_sema&>(obj);
|
||||
const auto val = +sema.val;
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"Sema 0x%08x: “%s”, Count: %d/%d, Wq: %zu", id, lv2_obj::name64(sema.name),
|
||||
add_leaf(node, qstr(fmt::format(u8"Sema 0x%08x: “%s”, Count: %d/%d, Wq: %zu", id, lv2_obj::name64(sema.name),
|
||||
std::max<s32>(val, 0), sema.max, -std::min<s32>(val, 0))));
|
||||
break;
|
||||
}
|
||||
case SYS_LWCOND_OBJECT:
|
||||
{
|
||||
auto& lwc = static_cast<lv2_lwcond&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"LWCond 0x%08x: “%s”, Wq: %zu", id, lv2_obj::name64(lwc.name), +lwc.waiters)));
|
||||
add_leaf(node, qstr(fmt::format(u8"LWCond 0x%08x: “%s”, Wq: %zu", id, lv2_obj::name64(lwc.name), +lwc.waiters)));
|
||||
break;
|
||||
}
|
||||
case SYS_EVENT_FLAG_OBJECT:
|
||||
{
|
||||
auto& ef = static_cast<lv2_event_flag&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format(u8"Event Flag 0x%08x: “%s”, Type: 0x%x, Key: %#llx, Pattern: 0x%llx, Wq: %zu", id, lv2_obj::name64(ef.name),
|
||||
add_leaf(node, qstr(fmt::format(u8"Event Flag 0x%08x: “%s”, Type: 0x%x, Key: %#llx, Pattern: 0x%llx, Wq: %zu", id, lv2_obj::name64(ef.name),
|
||||
ef.type, ef.key, ef.pattern.load(), +ef.waiters)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
l_addTreeChild(node, qstr(fmt::format("Unknown object 0x%08x", id)));
|
||||
add_leaf(node, qstr(fmt::format("Unknown object 0x%08x", id)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "Memory Containers"));
|
||||
|
||||
idm::select<lv2_memory_container>([&](u32 id, lv2_memory_container& container)
|
||||
{
|
||||
lv2_types.back().count++;
|
||||
const u32 used = container.used;
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format("Memory Container 0x%08x: Used: 0x%x/0x%x (%0.2f/%0.2f MB)", id, used, container.size, used * 1. / (1024 * 1024), container.size * 1. / (1024 * 1024))));
|
||||
add_leaf(find_node(m_tree, additional_nodes::memory_containers), qstr(fmt::format("Memory Container 0x%08x: Used: 0x%x/0x%x (%0.2f/%0.2f MB)", id, used, container.size, used * 1. / (1024 * 1024), container.size * 1. / (1024 * 1024))));
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "PPU Threads"));
|
||||
|
||||
idm::select<named_thread<ppu_thread>>([&](u32 id, ppu_thread& ppu)
|
||||
{
|
||||
lv2_types.back().count++;
|
||||
|
||||
const auto func = ppu.last_function;
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, State: %s, %s func: “%s”", id, *ppu.ppu_tname.load(), +ppu.prio, ppu.joiner.load(), ppu.state.load()
|
||||
add_leaf(find_node(m_tree, additional_nodes::ppu_threads), qstr(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, State: %s, %s func: “%s”", id, *ppu.ppu_tname.load(), +ppu.prio, ppu.joiner.load(), ppu.state.load()
|
||||
, ppu.current_function ? "In" : "Last", func ? func : "")));
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "SPU Threads"));
|
||||
|
||||
idm::select<named_thread<spu_thread>>([&](u32 /*id*/, spu_thread& spu)
|
||||
{
|
||||
lv2_types.back().count++;
|
||||
|
||||
std::string_view type = "threaded";
|
||||
|
||||
if (spu.is_isolated)
|
||||
@ -322,18 +459,15 @@ void kernel_explorer::Update()
|
||||
type = "raw";
|
||||
}
|
||||
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"SPU 0x%07x: “%s”, State: %s, Type: %s", spu.lv2_id, *spu.spu_tname.load(), spu.state.load(), type)));
|
||||
add_leaf(find_node(m_tree, additional_nodes::spu_threads), qstr(fmt::format(u8"SPU 0x%07x: “%s”, State: %s, Type: %s", spu.lv2_id, *spu.spu_tname.load(), spu.state.load(), type)));
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "SPU Thread Groups"));
|
||||
|
||||
idm::select<lv2_spu_group>([&](u32 id, lv2_spu_group& tg)
|
||||
{
|
||||
lv2_types.back().count++;
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"SPU Group 0x%07x: “%s”, Status = %s, Priority = %d, Type = 0x%x", id, tg.name, tg.run_state.load(), +tg.prio, tg.type)));
|
||||
add_leaf(find_node(m_tree, additional_nodes::spu_thread_groups), qstr(fmt::format(u8"SPU Group 0x%07x: “%s”, Status = %s, Priority = %d, Type = 0x%x", id, tg.name, tg.run_state.load(), +tg.prio, tg.type)));
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "RSX Contexts"));
|
||||
QTreeWidgetItem* rsx_context_node = find_node(m_tree, additional_nodes::rsx_contexts);
|
||||
|
||||
do
|
||||
{
|
||||
@ -353,12 +487,13 @@ void kernel_explorer::Update()
|
||||
break;
|
||||
}
|
||||
|
||||
lv2_types.back().count++;
|
||||
const auto tree = l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"RSX Context 0x55555555, Local Size: %u MB, Base Addr: 0x%x, Device Addr: 0x%x", context_info->memory_size >> 20, base, context_info->device_addr)));
|
||||
const QString branch_name = "RSX Context 0x55555555";
|
||||
QTreeWidgetItem* rsx_tree = add_volatile_node(m_tree, rsx_context_node, branch_name,
|
||||
branch_name + qstr(fmt::format(u8", Local Size: %u MB, Base Addr: 0x%x, Device Addr: 0x%x", context_info->memory_size >> 20, base, context_info->device_addr)));
|
||||
|
||||
lv2_obj_rec io_tree = l_addTreeChild(tree, "IO-EA Table");
|
||||
lv2_obj_rec zc_tree = l_addTreeChild(tree, "Zcull Bindings");
|
||||
lv2_obj_rec db_tree = l_addTreeChild(tree, "Display Buffers");
|
||||
QTreeWidgetItem* io_tree = add_volatile_node(m_tree, rsx_tree, tr("IO-EA Table"));
|
||||
QTreeWidgetItem* zc_tree = add_volatile_node(m_tree, rsx_tree, tr("Zcull Bindings"));
|
||||
QTreeWidgetItem* db_tree = add_volatile_node(m_tree, rsx_tree, tr("Display Buffers"));
|
||||
|
||||
decltype(rsx->iomap_table) table;
|
||||
decltype(rsx->display_buffers) dbs;
|
||||
@ -379,8 +514,7 @@ void kernel_explorer::Update()
|
||||
if (size_block)
|
||||
{
|
||||
// Print block
|
||||
l_addTreeChild(io_tree.node, qstr(fmt::format("IO: %08x, EA: %08x, Size: %uMB", first_io, first_ea, size_block)));
|
||||
io_tree.count++;
|
||||
add_leaf(io_tree, qstr(fmt::format("IO: %08x, EA: %08x, Size: %uMB", first_io, first_ea, size_block)));
|
||||
}
|
||||
|
||||
if (i >= 512u)
|
||||
@ -406,11 +540,10 @@ void kernel_explorer::Update()
|
||||
else
|
||||
{
|
||||
// Print last block before we continue to a new one
|
||||
l_addTreeChild(io_tree.node, qstr(fmt::format("IO: %08x, EA: %08x, Size: %uMB", first_io, first_ea, old_block_size)));
|
||||
add_leaf(io_tree, qstr(fmt::format("IO: %08x, EA: %08x, Size: %uMB", first_io, first_ea, old_block_size)));
|
||||
size_block = 1;
|
||||
first_ea = addr;
|
||||
first_io = (i - 1) << 20;
|
||||
io_tree.count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -425,9 +558,8 @@ void kernel_explorer::Update()
|
||||
{
|
||||
if (zc.bound)
|
||||
{
|
||||
l_addTreeChild(zc_tree.node, qstr(fmt::format("O: %07x, W: %u, H: %u, Zformat: 0x%x, AAformat: 0x%x, Dir: 0x%x, sFunc: 0x%x, sRef: %02x, sMask: %02x"
|
||||
add_leaf(zc_tree, qstr(fmt::format("O: %07x, W: %u, H: %u, Zformat: 0x%x, AAformat: 0x%x, Dir: 0x%x, sFunc: 0x%x, sRef: %02x, sMask: %02x"
|
||||
, zc.offset, zc.height, zc.width, zc.zFormat, zc.aaFormat, zc.zcullDir, zc.sFunc, zc.sRef, zc.sMask)));
|
||||
zc_tree.count++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,57 +567,74 @@ void kernel_explorer::Update()
|
||||
{
|
||||
if (db.valid())
|
||||
{
|
||||
l_addTreeChild(db_tree.node, qstr(fmt::format("Offset: %07x, Width: %u, Height: %u, Pitch: %u"
|
||||
add_leaf(db_tree, qstr(fmt::format("Offset: %07x, Width: %u, Height: %u, Pitch: %u"
|
||||
, db.offset, db.height, db.width, db.pitch)));
|
||||
db_tree.count++;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto&& entry : {&io_tree, &zc_tree, &db_tree})
|
||||
{
|
||||
if (entry->node)
|
||||
{
|
||||
if (entry->count)
|
||||
{
|
||||
// Append object count
|
||||
entry->node->setText(0, entry->node->text(0) + qstr(fmt::format(" (%zu)", entry->count)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Delete node otherwise
|
||||
delete entry->node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (0);
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "File Descriptors"));
|
||||
|
||||
idm::select<lv2_fs_object>([&](u32 id, lv2_fs_object& fo)
|
||||
{
|
||||
lv2_types.back().count++;
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"FD %u: “%s”", id, fo.name.data())));
|
||||
add_leaf(find_node(m_tree, additional_nodes::file_descriptors), qstr(fmt::format(u8"FD %u: “%s”", id, fo.name.data())));
|
||||
});
|
||||
|
||||
for (auto&& entry : lv2_types)
|
||||
{
|
||||
if (entry.node)
|
||||
{
|
||||
if (entry.count)
|
||||
{
|
||||
// Append object count
|
||||
entry.node->setText(0, entry.node->text(0) + qstr(fmt::format(" (%zu)", entry.count)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Delete node otherwise
|
||||
delete entry.node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RawSPU Threads (TODO)
|
||||
|
||||
std::function<int(QTreeWidgetItem*)> final_touches;
|
||||
final_touches = [&final_touches](QTreeWidgetItem* item) -> int
|
||||
{
|
||||
int visible_children = 0;
|
||||
|
||||
for (int i = 0; i < item->childCount(); i++)
|
||||
{
|
||||
auto node = item->child(i);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (node->data(0, kernel_item_role::type_role).toInt())
|
||||
{
|
||||
case kernel_item_type::leaf:
|
||||
{
|
||||
node->setHidden(false);
|
||||
break;
|
||||
}
|
||||
case kernel_item_type::node:
|
||||
case kernel_item_type::volatile_node:
|
||||
{
|
||||
const int count = final_touches(node);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
// Append count
|
||||
node->setText(0, node->text(0) + qstr(fmt::format(" (%zu)", count)));
|
||||
|
||||
// Expand if necessary
|
||||
node->setExpanded(node->data(0, kernel_item_role::expanded_role).toBool());
|
||||
}
|
||||
|
||||
// Hide node if it has no children
|
||||
node->setHidden(count <= 0);
|
||||
break;
|
||||
}
|
||||
case kernel_item_type::root:
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!node->isHidden())
|
||||
{
|
||||
visible_children++;
|
||||
}
|
||||
}
|
||||
|
||||
return visible_children;
|
||||
};
|
||||
final_touches(root);
|
||||
root->setExpanded(true);
|
||||
}
|
||||
|
@ -3,14 +3,30 @@
|
||||
#include <QDialog>
|
||||
#include <QTreeWidget>
|
||||
|
||||
#include "Utilities/types.h"
|
||||
|
||||
class kernel_explorer : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QTreeWidget* m_tree;
|
||||
static const size_t sys_size = 256;
|
||||
|
||||
enum additional_nodes
|
||||
{
|
||||
memory_containers = sys_size + 0,
|
||||
ppu_threads = sys_size + 1,
|
||||
spu_threads = sys_size + 2,
|
||||
spu_thread_groups = sys_size + 3,
|
||||
rsx_contexts = sys_size + 4,
|
||||
file_descriptors = sys_size + 5,
|
||||
};
|
||||
|
||||
public:
|
||||
kernel_explorer(QWidget* parent);
|
||||
|
||||
private:
|
||||
QTreeWidget* m_tree;
|
||||
|
||||
private Q_SLOTS:
|
||||
void Update();
|
||||
};
|
||||
|
@ -313,5 +313,28 @@ namespace gui
|
||||
{
|
||||
open_dir(sstr(path));
|
||||
}
|
||||
|
||||
QTreeWidgetItem* add_child(QTreeWidgetItem *parent, const QString& text, int column)
|
||||
{
|
||||
if (parent)
|
||||
{
|
||||
QTreeWidgetItem *tree_item = new QTreeWidgetItem();
|
||||
tree_item->setText(0, text);
|
||||
parent->addChild(tree_item);
|
||||
return tree_item;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
void remove_children(QTreeWidgetItem* parent)
|
||||
{
|
||||
if (parent)
|
||||
{
|
||||
for (int i = 0; i < parent->childCount(); i++)
|
||||
{
|
||||
parent->removeChild(parent->child(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // utils
|
||||
} // gui
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <QLabel>
|
||||
#include <QTableWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
@ -65,5 +66,11 @@ namespace gui
|
||||
|
||||
// Open a path in the explorer and mark the file
|
||||
void open_dir(const QString& path);
|
||||
|
||||
// Constructs and adds a child to a QTreeWidgetItem
|
||||
QTreeWidgetItem* add_child(QTreeWidgetItem* parent, const QString& text, int column = 0);
|
||||
|
||||
// Removes all children of a QTreeWidgetItem
|
||||
void remove_children(QTreeWidgetItem* parent);
|
||||
} // utils
|
||||
} // gui
|
||||
|
Loading…
Reference in New Issue
Block a user