diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 83fc55d..f97f07f 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -32,6 +32,7 @@ PerfViewer.Sort="Sort" PerfViewer.None="None" # show mode PerfViewer.Scene="Scene" +PerfViewer.SceneNested="Scene Nested" PerfViewer.Source="Source" PerfViewer.Filter="Filter" PerfViewer.Transition="Transition" diff --git a/source-profiler.cpp b/source-profiler.cpp index 43f9116..46498cf 100644 --- a/source-profiler.cpp +++ b/source-profiler.cpp @@ -97,6 +97,7 @@ OBSPerfViewer::OBSPerfViewer(QWidget *parent) : QDialog(parent) auto searchBarLayout = new QHBoxLayout(); auto groupByBox = new QComboBox(); groupByBox->addItem(QString::fromUtf8(obs_module_text("PerfViewer.Scene"))); + groupByBox->addItem(QString::fromUtf8(obs_module_text("PerfViewer.SceneNested"))); groupByBox->addItem(QString::fromUtf8(obs_module_text("PerfViewer.Source"))); groupByBox->addItem(QString::fromUtf8(obs_module_text("PerfViewer.Filter"))); groupByBox->addItem(QString::fromUtf8(obs_module_text("PerfViewer.Transition"))); @@ -115,8 +116,9 @@ OBSPerfViewer::OBSPerfViewer(QWidget *parent) : QDialog(parent) auto buttonLayout = new QHBoxLayout(); buttonLayout->setContentsMargins(10, 0, 10, 0); - auto versionLabel = new QLabel(QString::fromUtf8("Source profiler (" PROJECT_VERSION - ") by Exeldro")); + auto versionLabel = new QLabel( + QString::fromUtf8("Source profiler (" PROJECT_VERSION + ") by Exeldro")); versionLabel->setOpenExternalLinks(true); buttonLayout->addWidget(versionLabel); @@ -393,6 +395,8 @@ PerfTreeModel::PerfTreeModel(QObject *parent) : QAbstractItemModel(parent) updater.reset(new QuickThread([this] { while (true) { + obs_queue_task( + OBS_TASK_UI, [](void *) {}, nullptr, true); QThread::msleep(refreshInterval); updateData(); } @@ -446,8 +450,17 @@ bool PerfTreeModel::EnumSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *da auto treeItem = new PerfTreeItem(item, parent, parent->model()); parent->prependChild(treeItem); - + auto show_transition = obs_sceneitem_get_transition(item, true); + if (show_transition) { + EnumAllSource(treeItem, show_transition); + } + auto hide_transition = obs_sceneitem_get_transition(item, false); + if (hide_transition) { + EnumAllSource(treeItem, hide_transition); + } if (obs_source_is_scene(source)) { + if (parent->model()->showMode != SCENE_NESTED) + return true; obs_scene_t *scene = obs_scene_from_source(source); obs_scene_enum_items(scene, EnumSceneItem, treeItem); } else if (obs_sceneitem_is_group(item)) { @@ -457,14 +470,6 @@ bool PerfTreeModel::EnumSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *da if (obs_source_filter_count(source) > 0) { obs_source_enum_filters(source, EnumFilter, treeItem); } - auto show_transition = obs_sceneitem_get_transition(item, true); - if (show_transition) { - EnumAllSource(treeItem, show_transition); - } - auto hide_transition = obs_sceneitem_get_transition(item, false); - if (hide_transition) { - EnumAllSource(treeItem, hide_transition); - } return true; } @@ -490,6 +495,16 @@ bool PerfTreeModel::EnumAllSource(void *data, obs_source_t *source) return true; } +bool PerfTreeModel::ExistsChild(PerfTreeItem* parent, obs_source_t* source) { + for (auto it = parent->m_childItems.begin(); it != parent->m_childItems.end(); it++) { + if ((*it)->m_source && obs_weak_source_references_source((*it)->m_source, source)) + return true; + if (ExistsChild(*it, source)) + return true; + } + return false; +} + bool PerfTreeModel::EnumScene(void *data, obs_source_t *source) { if (obs_source_is_group(source)) @@ -498,6 +513,18 @@ bool PerfTreeModel::EnumScene(void *data, obs_source_t *source) return EnumAllSource(data, source); } +bool PerfTreeModel::EnumSceneNested(void *data, obs_source_t *source) +{ + if (obs_source_is_group(source)) + return true; + + auto parent = static_cast(data); + if (ExistsChild(parent, source)) + return true; + + return EnumAllSource(data, source); +} + bool PerfTreeModel::EnumNotPrivateSource(void *data, obs_source_t *source) { if (obs_obj_is_private(source)) @@ -549,6 +576,8 @@ void PerfTreeModel::refreshSources() obs_enum_all_sources(EnumNotPrivateSource, rootItem); } else if (showMode == ShowMode::SCENE) { obs_enum_scenes(EnumScene, rootItem); + } else if (showMode == ShowMode::SCENE_NESTED) { + obs_enum_scenes(EnumSceneNested, rootItem); } else if (showMode == ShowMode::FILTER) { obs_enum_all_sources(EnumFilterSource, rootItem); } else if (showMode == ShowMode::TRANSITION) { @@ -908,6 +937,7 @@ PerfTreeItem::PerfTreeItem(obs_sceneitem_t *sceneitem, PerfTreeItem *parentItem, { m_sceneitem = sceneitem; + enabled = obs_sceneitem_visible(sceneitem); } PerfTreeItem::PerfTreeItem(obs_source_t *source, PerfTreeItem *parent, PerfTreeModel *model) @@ -917,18 +947,21 @@ PerfTreeItem::PerfTreeItem(obs_source_t *source, PerfTreeItem *parent, PerfTreeM { name = QString::fromUtf8(source ? obs_source_get_name(source) : ""); sourceType = QString::fromUtf8(source ? obs_source_get_display_name(obs_source_get_unversioned_id(source)) : ""); - is_filter = obs_source_get_type(source) == OBS_SOURCE_TYPE_FILTER; + is_filter = source && (obs_source_get_type(source) == OBS_SOURCE_TYPE_FILTER); + if (is_filter) + enabled = obs_source_enabled(source); if (!is_filter && source) { auto sh = obs_source_get_signal_handler(source); signal_handler_connect(sh, "filter_add", filter_add, this); signal_handler_connect(sh, "filter_remove", filter_remove, this); } - if (source && obs_source_get_type(source) == OBS_SOURCE_TYPE_SCENE) { + if (source && (obs_source_get_type(source) == OBS_SOURCE_TYPE_SCENE)) { auto sh = obs_source_get_signal_handler(source); signal_handler_connect(sh, "item_add", sceneitem_add, this); signal_handler_connect(sh, "item_remove", sceneitem_remove, this); } - async = (!is_filter && (obs_source_get_output_flags(source) & OBS_SOURCE_ASYNC_VIDEO) == OBS_SOURCE_ASYNC_VIDEO); + async = (!is_filter && source && + ((obs_source_get_output_flags(source) & OBS_SOURCE_ASYNC_VIDEO) == OBS_SOURCE_ASYNC_VIDEO)); icon = getIcon(source); m_perf = new profiler_result_t; memset(m_perf, 0, sizeof(profiler_result_t)); @@ -1003,7 +1036,12 @@ PerfTreeItem *PerfTreeItem::parentItem() void PerfTreeItem::update() { + profiler_result_t old; + memcpy(&old, m_perf, sizeof(profiler_result_t)); + bool old_rendered = rendered; + bool old_enabled = enabled; obs_source_t *source = obs_weak_source_get_source(m_source); + bool cleared = false; if (source) { if (obs_source_get_type(source) == OBS_SOURCE_TYPE_FILTER) rendered = m_parentItem->isRendered(); @@ -1014,8 +1052,6 @@ void PerfTreeItem::update() source_profiler_fill_result(source, m_perf); - if (m_model) - m_model->itemChanged(this); obs_source_release(source); } else if (m_source) { enabled = false; @@ -1024,9 +1060,7 @@ void PerfTreeItem::update() obs_weak_source_release(m_source); m_source = nullptr; - - if (m_model) - m_model->itemChanged(this); + cleared = true; } if (!m_childItems.empty()) { @@ -1050,6 +1084,12 @@ void PerfTreeItem::update() } } } + if (m_model && (m_source || cleared)) { + if (cleared || old_rendered != rendered || old_enabled != enabled || + memcmp(&old, m_perf, sizeof(profiler_result_t)) != 0) { + m_model->itemChanged(this); + } + } } QIcon PerfTreeItem::getIcon(obs_source_t *source) const diff --git a/source-profiler.hpp b/source-profiler.hpp index 6c9de35..740cacc 100644 --- a/source-profiler.hpp +++ b/source-profiler.hpp @@ -68,7 +68,7 @@ class PerfTreeModel : public QAbstractItemModel { void itemChanged(PerfTreeItem *item); - enum ShowMode { SCENE, SOURCE, FILTER, TRANSITION, ALL }; + enum ShowMode { SCENE, SCENE_NESTED, SOURCE, FILTER, TRANSITION, ALL }; void setShowMode(enum ShowMode s = ShowMode::SCENE) { @@ -103,12 +103,14 @@ private slots: static bool EnumAll(void *data, obs_source_t *source); static bool EnumNotPrivateSource(void *data, obs_source_t *source); static bool EnumScene(void *data, obs_source_t *source); + static bool EnumSceneNested(void *data, obs_source_t *source); static bool EnumFilterSource(void *data, obs_source_t *source); static bool EnumTransition(void *data, obs_source_t *source); static bool EnumAllSource(void *data, obs_source_t *source); static bool EnumSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *data); static void EnumFilter(obs_source_t *, obs_source_t *child, void *data); static void EnumTree(obs_source_t *, obs_source_t *child, void *data); + static bool ExistsChild(PerfTreeItem *parent, obs_source_t *source); static void source_add(void *data, calldata_t *cd); static void source_remove(void *data, calldata_t *cd); static void frontend_event(enum obs_frontend_event event, void *private_data);