From 1e77fc6a3c6cce5c62a91c867ff3c5a42b463abe Mon Sep 17 00:00:00 2001 From: Grant Date: Tue, 23 Sep 2025 16:15:44 +0000 Subject: [PATCH 1/6] Correlates gpu timing tab with command hierarchy --- ui/gpu_timing_tab_view.cpp | 36 +++++++++++++++++++++++++++++ ui/gpu_timing_tab_view.h | 7 ++++++ ui/main_window.cpp | 46 ++++++++++++++++++++++++++++++++++++++ ui/main_window.h | 1 + 4 files changed, 90 insertions(+) diff --git a/ui/gpu_timing_tab_view.cpp b/ui/gpu_timing_tab_view.cpp index 9297154b6..d8b7c3404 100644 --- a/ui/gpu_timing_tab_view.cpp +++ b/ui/gpu_timing_tab_view.cpp @@ -37,6 +37,11 @@ GpuTimingTabView::GpuTimingTabView(GpuTimingModel &gpu_timing_mode &QAbstractItemModel::modelReset, this, &GpuTimingTabView::OnModelReset); + + QObject::connect(m_table_view->selectionModel(), + &QItemSelectionModel::currentChanged, + this, + &GpuTimingTabView::OnSelectionChanged); } //-------------------------------------------------------------------------------------------------- @@ -153,4 +158,35 @@ void GpuTimingTabView::OnEventSelectionChanged(const QModelIndex &model_index) return; } m_table_view->selectRow(row); +} + +//-------------------------------------------------------------------------------------------------- +void GpuTimingTabView::OnSelectionChanged(const QModelIndex &index) +{ + // Resize columns to fit the content + uint32_t column_count = (uint32_t)m_model.columnCount(QModelIndex()); + for (uint32_t column = 0; column < column_count; ++column) + { + m_table_view->resizeColumnToContents(column); + } + int selected_row = index.row(); + if (static_cast(selected_row) < m_timed_event_indices.size()) + { + emit GpuTimingDataSelected(m_timed_event_indices.at(selected_row)); + m_ignore_selection_changes = true; + } +} + +//-------------------------------------------------------------------------------------------------- +void GpuTimingTabView::ClearSelection() +{ + if (!m_ignore_selection_changes) + { + QItemSelectionModel *selection_model = m_table_view->selectionModel(); + if (selection_model) + { + selection_model->clear(); + } + } + m_ignore_selection_changes = false; } \ No newline at end of file diff --git a/ui/gpu_timing_tab_view.h b/ui/gpu_timing_tab_view.h index 34690fc75..3db8bc890 100644 --- a/ui/gpu_timing_tab_view.h +++ b/ui/gpu_timing_tab_view.h @@ -40,6 +40,11 @@ class GpuTimingTabView : public QWidget public slots: void OnModelReset(); void OnEventSelectionChanged(const QModelIndex &model_index); + void OnSelectionChanged(const QModelIndex &index); + void ClearSelection(); + +signals: + void GpuTimingDataSelected(uint64_t); private: void ResizeColumns(); @@ -64,4 +69,6 @@ public slots: // // The Qt index of all events for which there is GPU timing data std::vector m_timed_event_indices = {}; + + bool m_ignore_selection_changes = false; }; diff --git a/ui/main_window.cpp b/ui/main_window.cpp index e7abed484..bab76d938 100644 --- a/ui/main_window.cpp +++ b/ui/main_window.cpp @@ -721,6 +721,7 @@ void MainWindow::OnFilterModeChange(const QString &filter_mode) ClearViewModelSelection(*m_command_hierarchy_view, true); ClearViewModelSelection(*m_pm4_command_hierarchy_view, false); m_perf_counter_tab_view->ClearSelection(); + m_gpu_timing_tab_view->ClearSelection(); ExpandResizeHierarchyView(*m_pm4_command_hierarchy_view, *m_filter_model); } else @@ -739,6 +740,7 @@ void MainWindow::OnGfxrFilterModeChange() { ClearViewModelSelection(*m_pm4_command_hierarchy_view, false); m_perf_counter_tab_view->ClearSelection(); + m_gpu_timing_tab_view->ClearSelection(); } } @@ -2394,6 +2396,11 @@ void MainWindow::DisconnectAllTabs() this, &MainWindow::OnCounterSelected); + QObject::disconnect(m_gpu_timing_tab_view, + &GpuTimingTabView::GpuTimingDataSelected, + this, + &MainWindow::OnGpuTimingDataSelected); + QObject::disconnect(m_command_hierarchy_view, SIGNAL(sourceCurrentChanged(const QModelIndex &, const QModelIndex &)), m_gpu_timing_tab_view, @@ -2611,6 +2618,11 @@ void MainWindow::ConnectDiveFileTabs() this, &MainWindow::OnCounterSelected); + QObject::connect(m_gpu_timing_tab_view, + &GpuTimingTabView::GpuTimingDataSelected, + this, + &MainWindow::OnGpuTimingDataSelected); + QObject::connect(m_command_hierarchy_view, SIGNAL(sourceCurrentChanged(const QModelIndex &, const QModelIndex &)), m_gpu_timing_tab_view, @@ -2783,6 +2795,11 @@ void MainWindow::ConnectGfxrFileTabs() this, &MainWindow::OnCounterSelected); + QObject::connect(m_gpu_timing_tab_view, + &GpuTimingTabView::GpuTimingDataSelected, + this, + &MainWindow::OnGpuTimingDataSelected); + QObject::connect(m_command_hierarchy_view, SIGNAL(sourceCurrentChanged(const QModelIndex &, const QModelIndex &)), m_gpu_timing_tab_view, @@ -3193,6 +3210,7 @@ void MainWindow::OnCorrelatePm4DrawCall(const QModelIndex &index) m_pm4_filter_mode_combo_box->currentIndex() != Dive::kFirstTilePassOnly) { ClearViewModelSelection(*m_command_hierarchy_view, false); + m_gpu_timing_tab_view->ClearSelection(); return; } @@ -3211,6 +3229,7 @@ void MainWindow::OnCorrelatePm4DrawCall(const QModelIndex &index) if (!found_pm4_draw_call_index.has_value()) { ClearViewModelSelection(*m_command_hierarchy_view, false); + m_gpu_timing_tab_view->ClearSelection(); return; } @@ -3334,6 +3353,7 @@ void MainWindow::OnCounterSelected(uint64_t row_index) void MainWindow::OnCorrelateCounter(const QModelIndex &index) { m_perf_counter_tab_view->ClearSelection(); + m_gpu_timing_tab_view->ClearSelection(); QObject *sender_object = sender(); std::optional found_draw_call_index = 0; @@ -3385,3 +3405,29 @@ void MainWindow::OnCorrelateCounter(const QModelIndex &index) m_perf_counter_tab_view->OnCorrelateCounter(found_draw_call_index.value()); } } + +//-------------------------------------------------------------------------------------------------- +void MainWindow::OnGpuTimingDataSelected(uint64_t node_index) +{ + ClearViewModelSelection(*m_command_hierarchy_view, true); + ClearViewModelSelection(*m_pm4_command_hierarchy_view, true); + + QAbstractItemModel *gfxr_source_model = m_gfxr_vulkan_commands_filter_proxy_model + ->sourceModel(); + QModelIndex gfxr_draw_call_index_from_source = FindSourceIndexFromNode(gfxr_source_model, + node_index); + QItemSelectionModel::SelectionFlags flags; + QModelIndex proxy_index = m_gfxr_vulkan_commands_filter_proxy_model->mapFromSource( + gfxr_draw_call_index_from_source); + if (proxy_index.isValid()) + { + QItemSelectionModel *selection_model = m_command_hierarchy_view->selectionModel(); + + flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; + + selection_model->setCurrentIndex(proxy_index, flags); + + m_command_hierarchy_view->scrollTo(proxy_index, QAbstractItemView::PositionAtCenter); + m_command_hierarchy_view->expand(proxy_index); + } +} diff --git a/ui/main_window.h b/ui/main_window.h index aeb9716b0..bc3db15d4 100644 --- a/ui/main_window.h +++ b/ui/main_window.h @@ -130,6 +130,7 @@ public slots: void OnCorrelatePm4DrawCall(const QModelIndex &); void OnCorrelateCounter(const QModelIndex &); void OnCounterSelected(uint64_t); + void OnGpuTimingDataSelected(uint64_t); void OnCorrelationFilterApplied(uint64_t, int, const QModelIndex &); private slots: From 72695e754292721e66e4f1f90429be29b714262d Mon Sep 17 00:00:00 2001 From: Grant Date: Wed, 24 Sep 2025 00:23:24 +0000 Subject: [PATCH 2/6] Correlation debugging --- ui/main_window.cpp | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/ui/main_window.cpp b/ui/main_window.cpp index bab76d938..3fbcc75f8 100644 --- a/ui/main_window.cpp +++ b/ui/main_window.cpp @@ -3136,8 +3136,6 @@ CorrelationTarget target) //-------------------------------------------------------------------------------------------------- void MainWindow::OnCorrelateVulkanDrawCall(const QModelIndex &index) { - m_perf_counter_tab_view->ClearSelection(); - if (m_pm4_filter_mode_combo_box->currentIndex() != Dive::kBinningPassOnly && m_pm4_filter_mode_combo_box->currentIndex() != Dive::kFirstTilePassOnly) { @@ -3145,6 +3143,10 @@ void MainWindow::OnCorrelateVulkanDrawCall(const QModelIndex &index) ClearViewModelSelection(*m_pm4_command_hierarchy_view, false); return; } + else + { + m_gpu_timing_tab_view->ClearSelection(); + } m_gfxr_vulkan_commands_filter_proxy_model->CollectGfxrDrawCallIndices(); std::vector @@ -3204,13 +3206,13 @@ void MainWindow::OnCorrelateVulkanDrawCall(const QModelIndex &index) //-------------------------------------------------------------------------------------------------- void MainWindow::OnCorrelatePm4DrawCall(const QModelIndex &index) { + m_gpu_timing_tab_view->ClearSelection(); m_perf_counter_tab_view->ClearSelection(); if (m_pm4_filter_mode_combo_box->currentIndex() != Dive::kBinningPassOnly && m_pm4_filter_mode_combo_box->currentIndex() != Dive::kFirstTilePassOnly) { ClearViewModelSelection(*m_command_hierarchy_view, false); - m_gpu_timing_tab_view->ClearSelection(); return; } @@ -3229,7 +3231,6 @@ void MainWindow::OnCorrelatePm4DrawCall(const QModelIndex &index) if (!found_pm4_draw_call_index.has_value()) { ClearViewModelSelection(*m_command_hierarchy_view, false); - m_gpu_timing_tab_view->ClearSelection(); return; } @@ -3353,7 +3354,6 @@ void MainWindow::OnCounterSelected(uint64_t row_index) void MainWindow::OnCorrelateCounter(const QModelIndex &index) { m_perf_counter_tab_view->ClearSelection(); - m_gpu_timing_tab_view->ClearSelection(); QObject *sender_object = sender(); std::optional found_draw_call_index = 0; @@ -3361,6 +3361,8 @@ void MainWindow::OnCorrelateCounter(const QModelIndex &index) if (sender_object == m_pm4_command_hierarchy_view->selectionModel()) { + m_gpu_timing_tab_view->ClearSelection(); + if (m_pm4_filter_mode_combo_box->currentIndex() == Dive::kBinningPassOnly || m_pm4_filter_mode_combo_box->currentIndex() == Dive::kFirstTilePassOnly) { @@ -3398,6 +3400,28 @@ void MainWindow::OnCorrelateCounter(const QModelIndex &index) { found = true; } + else + { + uint64_t source_node_index = (uint64_t)m_gfxr_vulkan_commands_filter_proxy_model + ->mapToSource(index) + .internalPointer(); + Dive::NodeType node_type = m_data_core->GetCommandHierarchy().GetNodeType( + source_node_index); + bool is_gpu_timing_node = (node_type == Dive::NodeType::kGfxrRootFrameNode) || + (node_type == + Dive::NodeType::kGfxrVulkanBeginRenderPassCommandNode) || + (node_type == + Dive::NodeType::kGfxrVulkanBeginCommandBufferNode); + + if (is_gpu_timing_node) + { + return; + } + else + { + m_gpu_timing_tab_view->ClearSelection(); + } + } } if (found) From 15091d354d2dcfd029c2cc89fbbff6ccd720e944 Mon Sep 17 00:00:00 2001 From: Grant Date: Wed, 24 Sep 2025 21:58:28 +0000 Subject: [PATCH 3/6] Updates selection logic, resolves comments --- ui/gpu_timing_tab_view.cpp | 19 ++++-------- ui/gpu_timing_tab_view.h | 2 -- ui/main_window.cpp | 60 +++++++++++++++++++++++--------------- ui/main_window.h | 1 + 4 files changed, 43 insertions(+), 39 deletions(-) diff --git a/ui/gpu_timing_tab_view.cpp b/ui/gpu_timing_tab_view.cpp index d8b7c3404..40b128a79 100644 --- a/ui/gpu_timing_tab_view.cpp +++ b/ui/gpu_timing_tab_view.cpp @@ -154,7 +154,7 @@ void GpuTimingTabView::OnEventSelectionChanged(const QModelIndex &model_index) int row = EventIndexToRow(model_index); if (row < 0) { - m_table_view->clearSelection(); + ClearSelection(); return; } m_table_view->selectRow(row); @@ -164,29 +164,20 @@ void GpuTimingTabView::OnEventSelectionChanged(const QModelIndex &model_index) void GpuTimingTabView::OnSelectionChanged(const QModelIndex &index) { // Resize columns to fit the content - uint32_t column_count = (uint32_t)m_model.columnCount(QModelIndex()); - for (uint32_t column = 0; column < column_count; ++column) - { - m_table_view->resizeColumnToContents(column); - } + ResizeColumns(); int selected_row = index.row(); if (static_cast(selected_row) < m_timed_event_indices.size()) { emit GpuTimingDataSelected(m_timed_event_indices.at(selected_row)); - m_ignore_selection_changes = true; } } //-------------------------------------------------------------------------------------------------- void GpuTimingTabView::ClearSelection() { - if (!m_ignore_selection_changes) + QItemSelectionModel *selection_model = m_table_view->selectionModel(); + if (selection_model) { - QItemSelectionModel *selection_model = m_table_view->selectionModel(); - if (selection_model) - { - selection_model->clear(); - } + selection_model->clear(); } - m_ignore_selection_changes = false; } \ No newline at end of file diff --git a/ui/gpu_timing_tab_view.h b/ui/gpu_timing_tab_view.h index 3db8bc890..bcb6e20b7 100644 --- a/ui/gpu_timing_tab_view.h +++ b/ui/gpu_timing_tab_view.h @@ -69,6 +69,4 @@ public slots: // // The Qt index of all events for which there is GPU timing data std::vector m_timed_event_indices = {}; - - bool m_ignore_selection_changes = false; }; diff --git a/ui/main_window.cpp b/ui/main_window.cpp index 3fbcc75f8..f4adf7aac 100644 --- a/ui/main_window.cpp +++ b/ui/main_window.cpp @@ -2401,11 +2401,6 @@ void MainWindow::DisconnectAllTabs() this, &MainWindow::OnGpuTimingDataSelected); - QObject::disconnect(m_command_hierarchy_view, - SIGNAL(sourceCurrentChanged(const QModelIndex &, const QModelIndex &)), - m_gpu_timing_tab_view, - SLOT(OnEventSelectionChanged(const QModelIndex &))); - QObject::disconnect(m_filter_mode_combo_box, SIGNAL(currentTextChanged(const QString &)), this, @@ -2623,11 +2618,6 @@ void MainWindow::ConnectDiveFileTabs() this, &MainWindow::OnGpuTimingDataSelected); - QObject::connect(m_command_hierarchy_view, - SIGNAL(sourceCurrentChanged(const QModelIndex &, const QModelIndex &)), - m_gpu_timing_tab_view, - SLOT(OnEventSelectionChanged(const QModelIndex &))); - // Correlate between two calls QObject::connect(m_pm4_command_hierarchy_view, SIGNAL(clicked(const QModelIndex &)), @@ -2800,11 +2790,6 @@ void MainWindow::ConnectGfxrFileTabs() this, &MainWindow::OnGpuTimingDataSelected); - QObject::connect(m_command_hierarchy_view, - SIGNAL(sourceCurrentChanged(const QModelIndex &, const QModelIndex &)), - m_gpu_timing_tab_view, - SLOT(OnEventSelectionChanged(const QModelIndex &))); - // Combo Boxes QObject::connect(m_filter_gfxr_commands_combo_box, SIGNAL(FilterChanged()), @@ -3136,6 +3121,26 @@ CorrelationTarget target) //-------------------------------------------------------------------------------------------------- void MainWindow::OnCorrelateVulkanDrawCall(const QModelIndex &index) { + m_gpu_timing_tab_view->ClearSelection(); + QModelIndex source_index = m_gfxr_vulkan_commands_filter_proxy_model->mapToSource(index); + + // Check if the selected node is a GPU timing node. If so, do not correlate with the PM4 view + // and performance counters. Only correlate with GPU timing view. + uint64_t source_node_index = (uint64_t)source_index.internalPointer(); + Dive::NodeType node_type = m_data_core->GetCommandHierarchy().GetNodeType(source_node_index); + bool is_gpu_timing_node = (node_type == Dive::NodeType::kGfxrRootFrameNode) || + (node_type == + Dive::NodeType::kGfxrVulkanBeginRenderPassCommandNode) || + (node_type == Dive::NodeType::kGfxrVulkanBeginCommandBufferNode); + + if (is_gpu_timing_node) + { + m_gpu_time_correlation_from_command_hierarchy = true; + m_gpu_timing_tab_view->OnEventSelectionChanged(source_index); + m_gpu_time_correlation_from_command_hierarchy = false; + return; + } + if (m_pm4_filter_mode_combo_box->currentIndex() != Dive::kBinningPassOnly && m_pm4_filter_mode_combo_box->currentIndex() != Dive::kFirstTilePassOnly) { @@ -3143,10 +3148,6 @@ void MainWindow::OnCorrelateVulkanDrawCall(const QModelIndex &index) ClearViewModelSelection(*m_pm4_command_hierarchy_view, false); return; } - else - { - m_gpu_timing_tab_view->ClearSelection(); - } m_gfxr_vulkan_commands_filter_proxy_model->CollectGfxrDrawCallIndices(); std::vector @@ -3417,10 +3418,8 @@ void MainWindow::OnCorrelateCounter(const QModelIndex &index) { return; } - else - { - m_gpu_timing_tab_view->ClearSelection(); - } + + m_gpu_timing_tab_view->ClearSelection(); } } @@ -3447,11 +3446,26 @@ void MainWindow::OnGpuTimingDataSelected(uint64_t node_index) { QItemSelectionModel *selection_model = m_command_hierarchy_view->selectionModel(); + // Only block signals if + // the selection was initiated by the user clicking a node in the command hierarchy, + // triggering correlation. This prevents the selection of the node here from trigger + // correlation again. + bool old_state = false; + if (m_gpu_time_correlation_from_command_hierarchy) + { + old_state = selection_model->blockSignals(true); + } + flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; selection_model->setCurrentIndex(proxy_index, flags); m_command_hierarchy_view->scrollTo(proxy_index, QAbstractItemView::PositionAtCenter); m_command_hierarchy_view->expand(proxy_index); + + if (m_gpu_time_correlation_from_command_hierarchy) + { + selection_model->blockSignals(old_state); + } } } diff --git a/ui/main_window.h b/ui/main_window.h index bc3db15d4..a74bd2092 100644 --- a/ui/main_window.h +++ b/ui/main_window.h @@ -314,6 +314,7 @@ private slots: int m_previous_tab_index = -1; bool m_gfxr_capture_loaded = false; bool m_correlated_capture_loaded = false; + bool m_gpu_time_correlation_from_command_hierarchy = true; EventSelection *m_event_selection; From 0aca4124cc84723267196a477a4a24659ded4a6c Mon Sep 17 00:00:00 2001 From: Grant Date: Wed, 24 Sep 2025 22:52:58 +0000 Subject: [PATCH 4/6] solo-gfxr use --- ui/main_window.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/main_window.cpp b/ui/main_window.cpp index f4adf7aac..2141fa5af 100644 --- a/ui/main_window.cpp +++ b/ui/main_window.cpp @@ -2832,12 +2832,17 @@ void MainWindow::ConnectGfxrFileTabs() m_gpu_timing_model, &GpuTimingModel::OnGpuTimingResultsGenerated); - // Correlate counter + // Correlate calls QObject::connect(m_command_hierarchy_view->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(OnCorrelateCounter(const QModelIndex &))); + QObject::connect(m_command_hierarchy_view->selectionModel(), + SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), + this, + SLOT(OnCorrelateVulkanDrawCall(const QModelIndex &))); + // Menus QObject::connect(m_command_hierarchy_view, &QTreeView::customContextMenuRequested, From d3b4f13b88e63f919259e82374da30f6e9c6ccb0 Mon Sep 17 00:00:00 2001 From: Grant Date: Thu, 25 Sep 2025 17:52:07 +0000 Subject: [PATCH 5/6] Utilizes QSignalBlocker, refactors selection logic --- ui/gpu_timing_tab_view.cpp | 6 +- ui/main_window.cpp | 169 ++++++++++++++++++++--------------- ui/main_window.h | 5 +- ui/perf_counter_tab_view.cpp | 12 +-- ui/perf_counter_tab_view.h | 2 +- 5 files changed, 110 insertions(+), 84 deletions(-) diff --git a/ui/gpu_timing_tab_view.cpp b/ui/gpu_timing_tab_view.cpp index 40b128a79..fbac9735f 100644 --- a/ui/gpu_timing_tab_view.cpp +++ b/ui/gpu_timing_tab_view.cpp @@ -141,6 +141,8 @@ int GpuTimingTabView::EventIndexToRow(const QModelIndex &model_index) //-------------------------------------------------------------------------------------------------- void GpuTimingTabView::OnEventSelectionChanged(const QModelIndex &model_index) { + QItemSelectionModel *selection_model = m_table_view->selectionModel(); + QSignalBlocker blocker(selection_model); // Verify that the number of rows in the model is consistent with the rows of // m_timed_event_indices if (m_model.rowCount() != static_cast(m_timed_event_indices.size())) @@ -158,6 +160,8 @@ void GpuTimingTabView::OnEventSelectionChanged(const QModelIndex &model_index) return; } m_table_view->selectRow(row); + m_table_view->update(); + m_table_view->viewport()->update(); } //-------------------------------------------------------------------------------------------------- @@ -166,7 +170,7 @@ void GpuTimingTabView::OnSelectionChanged(const QModelIndex &index) // Resize columns to fit the content ResizeColumns(); int selected_row = index.row(); - if (static_cast(selected_row) < m_timed_event_indices.size()) + if (static_cast(selected_row) < m_timed_event_indices.size() && selected_row >= 0) { emit GpuTimingDataSelected(m_timed_event_indices.at(selected_row)); } diff --git a/ui/main_window.cpp b/ui/main_window.cpp index 2141fa5af..d61621533 100644 --- a/ui/main_window.cpp +++ b/ui/main_window.cpp @@ -713,15 +713,17 @@ void MainWindow::OnFilterModeChange(const QString &filter_mode) if (m_command_hierarchy_view) { + ResetVerticalScroll(*m_command_hierarchy_view); m_command_hierarchy_view->scrollToTop(); } + m_perf_counter_tab_view->ClearSelection(); + m_gpu_timing_tab_view->ClearSelection(); + if (m_correlated_capture_loaded) { ClearViewModelSelection(*m_command_hierarchy_view, true); ClearViewModelSelection(*m_pm4_command_hierarchy_view, false); - m_perf_counter_tab_view->ClearSelection(); - m_gpu_timing_tab_view->ClearSelection(); ExpandResizeHierarchyView(*m_pm4_command_hierarchy_view, *m_filter_model); } else @@ -734,13 +736,18 @@ void MainWindow::OnFilterModeChange(const QString &filter_mode) //-------------------------------------------------------------------------------------------------- void MainWindow::OnGfxrFilterModeChange() { - ClearViewModelSelection(*m_command_hierarchy_view, true); + ClearViewModelSelection(*m_command_hierarchy_view, false); + m_perf_counter_tab_view->ClearSelection(); + m_gpu_timing_tab_view->ClearSelection(); + + ResetVerticalScroll(*m_command_hierarchy_view); + m_command_hierarchy_view->scrollToTop(); if (m_correlated_capture_loaded) { + m_pm4_command_hierarchy_view->scrollToTop(); ClearViewModelSelection(*m_pm4_command_hierarchy_view, false); - m_perf_counter_tab_view->ClearSelection(); - m_gpu_timing_tab_view->ClearSelection(); + ExpandResizeHierarchyView(*m_pm4_command_hierarchy_view, *m_filter_model); } } @@ -1527,6 +1534,16 @@ void MainWindow::ResetHorizontalScroll(const DiveTreeView &tree_view) } } +void MainWindow::ResetVerticalScroll(const DiveTreeView &tree_view) +{ + QScrollBar *v_scroll_bar = tree_view.verticalScrollBar(); + if (v_scroll_bar) + { + v_scroll_bar->triggerAction(QAbstractSlider::SliderToMinimum); + QApplication::processEvents(); + } +} + //-------------------------------------------------------------------------------------------------- void MainWindow::OnSearchTrigger() { @@ -2330,11 +2347,6 @@ void MainWindow::DisconnectAllTabs() this, SLOT(OnSelectionChanged(const QModelIndex &))); - QObject::disconnect(m_pm4_command_hierarchy_view->selectionModel(), - SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), - this, - SLOT(OnCorrelateCounter(const QModelIndex &))); - QObject::disconnect(m_pm4_command_hierarchy_view->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, @@ -2371,11 +2383,6 @@ void MainWindow::DisconnectAllTabs() m_gfxr_vulkan_command_arguments_tab_view, SLOT(OnSelectionChanged(const QModelIndex &))); - QObject::disconnect(m_command_hierarchy_view->selectionModel(), - SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), - this, - SLOT(OnCorrelateCounter(const QModelIndex &))); - QObject::disconnect(m_command_hierarchy_view->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, @@ -2619,21 +2626,10 @@ void MainWindow::ConnectDiveFileTabs() &MainWindow::OnGpuTimingDataSelected); // Correlate between two calls - QObject::connect(m_pm4_command_hierarchy_view, - SIGNAL(clicked(const QModelIndex &)), - this, - SLOT(OnCorrelatePm4DrawCall(const QModelIndex &))); - - // Correlate counter - QObject::connect(m_command_hierarchy_view->selectionModel(), - SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), - this, - SLOT(OnCorrelateCounter(const QModelIndex &))); - QObject::connect(m_pm4_command_hierarchy_view->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, - SLOT(OnCorrelateCounter(const QModelIndex &))); + SLOT(OnCorrelatePm4DrawCall(const QModelIndex &))); // Dialogs QObject::connect(m_analyze_dig, @@ -2836,12 +2832,7 @@ void MainWindow::ConnectGfxrFileTabs() QObject::connect(m_command_hierarchy_view->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, - SLOT(OnCorrelateCounter(const QModelIndex &))); - - QObject::connect(m_command_hierarchy_view->selectionModel(), - SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), - this, - SLOT(OnCorrelateVulkanDrawCall(const QModelIndex &))); + SLOT(OnCorrelateVulkanDrawCall(const QModelIndex &))); // Menus QObject::connect(m_command_hierarchy_view, @@ -2947,7 +2938,6 @@ void MainWindow::OnOpenVulkanDrawCallMenu(const QPoint &pos) if (selected_action_data == Dive::kPerfCounterData) { m_tab_widget->setCurrentIndex(m_perf_counter_view_tab_index); - emit CorrelateCounter(found_gfxr_draw_call_index); } else if (selected_action_data == Dive::kArguments) { @@ -2985,31 +2975,42 @@ void MainWindow::OnCorrelationFilterApplied(uint64_t gfxr_draw_call_in if (proxy_index.isValid()) { QItemSelectionModel *selection_model = m_pm4_command_hierarchy_view->selectionModel(); - bool old_state = selection_model->blockSignals(true); + QSignalBlocker pm4_view_blocker(selection_model); QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; selection_model->setCurrentIndex(proxy_index, flags); + m_command_tab_view->OnSelectionChanged(proxy_index); m_pm4_command_hierarchy_view->scrollTo(proxy_index, QAbstractItemView::PositionAtCenter); m_pm4_command_hierarchy_view->expand(proxy_index); - selection_model->blockSignals(old_state); + m_pm4_command_hierarchy_view->viewport()->update(); + QApplication::processEvents(); } } QItemSelectionModel *gfxr_selection_model = m_command_hierarchy_view->selectionModel(); - bool gfxr_old_state = gfxr_selection_model->blockSignals(true); + QSignalBlocker gfxr_view_blocker(gfxr_selection_model); QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; gfxr_selection_model->setCurrentIndex(vulkan_draw_call_model_index, flags); - gfxr_selection_model->blockSignals(gfxr_old_state); - OnCorrelateCounter(vulkan_draw_call_model_index); + ResetVerticalScroll(*m_command_hierarchy_view); + m_command_hierarchy_view->scrollTo(vulkan_draw_call_model_index, + QAbstractItemView::PositionAtCenter); + m_command_hierarchy_view->expand(vulkan_draw_call_model_index); + + m_command_hierarchy_view->viewport()->update(); + QApplication::processEvents(); + + CorrelateCounter(vulkan_draw_call_model_index, true); + + ResetHorizontalScroll(*m_pm4_command_hierarchy_view); } //-------------------------------------------------------------------------------------------------- @@ -3066,12 +3067,11 @@ void MainWindow::ClearViewModelSelection(DiveTreeView &tree_view, bool should_cl QItemSelectionModel *selection_model = tree_view.selectionModel(); if (selection_model) { - bool old_state = selection_model->blockSignals(true); + QSignalBlocker blocker(selection_model); selection_model->clear(); QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; selection_model->setCurrentIndex(QModelIndex(), flags); - selection_model->blockSignals(old_state); } if (should_clear_tab && (m_correlated_capture_loaded || m_gfxr_capture_loaded)) @@ -3080,6 +3080,7 @@ void MainWindow::ClearViewModelSelection(DiveTreeView &tree_view, bool should_cl } tree_view.viewport()->update(); + QApplication::processEvents(); } //-------------------------------------------------------------------------------------------------- @@ -3127,6 +3128,7 @@ CorrelationTarget target) void MainWindow::OnCorrelateVulkanDrawCall(const QModelIndex &index) { m_gpu_timing_tab_view->ClearSelection(); + m_perf_counter_tab_view->ClearSelection(); QModelIndex source_index = m_gfxr_vulkan_commands_filter_proxy_model->mapToSource(index); // Check if the selected node is a GPU timing node. If so, do not correlate with the PM4 view @@ -3140,19 +3142,24 @@ void MainWindow::OnCorrelateVulkanDrawCall(const QModelIndex &index) if (is_gpu_timing_node) { - m_gpu_time_correlation_from_command_hierarchy = true; + ClearViewModelSelection(*m_pm4_command_hierarchy_view, false); m_gpu_timing_tab_view->OnEventSelectionChanged(source_index); - m_gpu_time_correlation_from_command_hierarchy = false; return; } - if (m_pm4_filter_mode_combo_box->currentIndex() != Dive::kBinningPassOnly && - m_pm4_filter_mode_combo_box->currentIndex() != Dive::kFirstTilePassOnly) + if (m_correlated_capture_loaded && + (m_pm4_filter_mode_combo_box->currentIndex() != Dive::kBinningPassOnly && + m_pm4_filter_mode_combo_box->currentIndex() != Dive::kFirstTilePassOnly)) { - OnCorrelateCounter(index); + CorrelateCounter(index, true); ClearViewModelSelection(*m_pm4_command_hierarchy_view, false); return; } + else if (m_gfxr_capture_loaded) + { + CorrelateCounter(index, true); + return; + } m_gfxr_vulkan_commands_filter_proxy_model->CollectGfxrDrawCallIndices(); std::vector @@ -3192,16 +3199,21 @@ void MainWindow::OnCorrelateVulkanDrawCall(const QModelIndex &index) if (proxy_index.isValid()) { QItemSelectionModel *selection_model = m_pm4_command_hierarchy_view->selectionModel(); - + QSignalBlocker blocker(selection_model); QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; selection_model->setCurrentIndex(proxy_index, flags); + m_command_tab_view->OnSelectionChanged(proxy_index); m_pm4_command_hierarchy_view->scrollTo(proxy_index, QAbstractItemView::PositionAtCenter); m_pm4_command_hierarchy_view->expand(proxy_index); - emit CorrelateCounter(found_gfxr_draw_call_index.value()); + + m_pm4_command_hierarchy_view->viewport()->update(); + QApplication::processEvents(); + + CorrelateCounter(index, true); } } @@ -3215,9 +3227,13 @@ void MainWindow::OnCorrelatePm4DrawCall(const QModelIndex &index) m_gpu_timing_tab_view->ClearSelection(); m_perf_counter_tab_view->ClearSelection(); + QItemSelectionModel *gfxr_selection_model = m_command_hierarchy_view->selectionModel(); + QSignalBlocker blocker(gfxr_selection_model); + if (m_pm4_filter_mode_combo_box->currentIndex() != Dive::kBinningPassOnly && m_pm4_filter_mode_combo_box->currentIndex() != Dive::kFirstTilePassOnly) { + ResetHorizontalScroll(*m_pm4_command_hierarchy_view); ClearViewModelSelection(*m_command_hierarchy_view, false); return; } @@ -3259,16 +3275,19 @@ void MainWindow::OnCorrelatePm4DrawCall(const QModelIndex &index) gfxr_draw_call_index_from_source); if (proxy_index.isValid()) { - QItemSelectionModel *selection_model = m_command_hierarchy_view->selectionModel(); - QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; - selection_model->setCurrentIndex(proxy_index, flags); + gfxr_selection_model->setCurrentIndex(proxy_index, flags); + ResetVerticalScroll(*m_command_hierarchy_view); m_command_hierarchy_view->scrollTo(proxy_index, QAbstractItemView::PositionAtCenter); m_command_hierarchy_view->expand(proxy_index); - emit CorrelateCounter(found_pm4_draw_call_index.value()); + + m_command_hierarchy_view->viewport()->update(); + QApplication::processEvents(); + + CorrelateCounter(index, false); } } @@ -3279,6 +3298,7 @@ void MainWindow::OnCorrelatePm4DrawCall(const QModelIndex &index) //-------------------------------------------------------------------------------------------------- void MainWindow::OnCounterSelected(uint64_t row_index) { + m_gpu_timing_tab_view->ClearSelection(); m_gfxr_vulkan_commands_filter_proxy_model->CollectGfxrDrawCallIndices(); std::vector gfxr_draw_call_indices = qobject_cast( @@ -3310,13 +3330,17 @@ void MainWindow::OnCounterSelected(uint64_t row_index) if (proxy_index.isValid()) { selection_model = m_command_hierarchy_view->selectionModel(); - + QSignalBlocker main_view_blocker(selection_model); flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; selection_model->setCurrentIndex(proxy_index, flags); + ResetVerticalScroll(*m_command_hierarchy_view); m_command_hierarchy_view->scrollTo(proxy_index, QAbstractItemView::PositionAtCenter); m_command_hierarchy_view->expand(proxy_index); + + m_command_hierarchy_view->viewport()->update(); + QApplication::processEvents(); } } @@ -3337,7 +3361,7 @@ void MainWindow::OnCounterSelected(uint64_t row_index) if (proxy_index.isValid()) { selection_model = m_pm4_command_hierarchy_view->selectionModel(); - + QSignalBlocker main_view_blocker(selection_model); flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; selection_model->setCurrentIndex(proxy_index, flags); @@ -3345,6 +3369,9 @@ void MainWindow::OnCounterSelected(uint64_t row_index) m_pm4_command_hierarchy_view->scrollTo(proxy_index, QAbstractItemView::PositionAtCenter); m_pm4_command_hierarchy_view->expand(proxy_index); + + m_pm4_command_hierarchy_view->viewport()->update(); + QApplication::processEvents(); } } } @@ -3357,15 +3384,14 @@ void MainWindow::OnCounterSelected(uint64_t row_index) } //-------------------------------------------------------------------------------------------------- -void MainWindow::OnCorrelateCounter(const QModelIndex &index) +void MainWindow::CorrelateCounter(const QModelIndex &index, bool called_from_gfxr_view) { m_perf_counter_tab_view->ClearSelection(); - QObject *sender_object = sender(); std::optional found_draw_call_index = 0; bool found = false; - if (sender_object == m_pm4_command_hierarchy_view->selectionModel()) + if (!called_from_gfxr_view) { m_gpu_timing_tab_view->ClearSelection(); @@ -3430,15 +3456,23 @@ void MainWindow::OnCorrelateCounter(const QModelIndex &index) if (found) { - m_perf_counter_tab_view->OnCorrelateCounter(found_draw_call_index.value()); + m_perf_counter_tab_view->CorrelateCounter(found_draw_call_index.value()); } } //-------------------------------------------------------------------------------------------------- void MainWindow::OnGpuTimingDataSelected(uint64_t node_index) { + if (m_correlated_capture_loaded) + { + QItemSelectionModel *pm4_selection_model = m_pm4_command_hierarchy_view->selectionModel(); + QSignalBlocker pm4_blocker(pm4_selection_model); + ClearViewModelSelection(*m_pm4_command_hierarchy_view, true); + } + + QItemSelectionModel *gfxr_selection_model = m_command_hierarchy_view->selectionModel(); + QSignalBlocker gfxr_blocker(gfxr_selection_model); ClearViewModelSelection(*m_command_hierarchy_view, true); - ClearViewModelSelection(*m_pm4_command_hierarchy_view, true); QAbstractItemModel *gfxr_source_model = m_gfxr_vulkan_commands_filter_proxy_model ->sourceModel(); @@ -3451,26 +3485,15 @@ void MainWindow::OnGpuTimingDataSelected(uint64_t node_index) { QItemSelectionModel *selection_model = m_command_hierarchy_view->selectionModel(); - // Only block signals if - // the selection was initiated by the user clicking a node in the command hierarchy, - // triggering correlation. This prevents the selection of the node here from trigger - // correlation again. - bool old_state = false; - if (m_gpu_time_correlation_from_command_hierarchy) - { - old_state = selection_model->blockSignals(true); - } - flags = QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; selection_model->setCurrentIndex(proxy_index, flags); + ResetVerticalScroll(*m_command_hierarchy_view); m_command_hierarchy_view->scrollTo(proxy_index, QAbstractItemView::PositionAtCenter); m_command_hierarchy_view->expand(proxy_index); - if (m_gpu_time_correlation_from_command_hierarchy) - { - selection_model->blockSignals(old_state); - } + m_command_hierarchy_view->viewport()->update(); + QApplication::processEvents(); } } diff --git a/ui/main_window.h b/ui/main_window.h index a74bd2092..f1a1717e6 100644 --- a/ui/main_window.h +++ b/ui/main_window.h @@ -117,7 +117,6 @@ class MainWindow : public QMainWindow void SetSaveMenuStatus(bool); void SetSaveAsMenuStatus(bool); void FileLoaded(); - void CorrelateCounter(uint64_t); public slots: void OnCapture(bool is_capture_delayed = false, bool is_gfxr_capture = false); @@ -128,7 +127,6 @@ public slots: void OnOpenVulkanCallMenu(const QPoint &pos); void OnCorrelateVulkanDrawCall(const QModelIndex &); void OnCorrelatePm4DrawCall(const QModelIndex &); - void OnCorrelateCounter(const QModelIndex &); void OnCounterSelected(uint64_t); void OnGpuTimingDataSelected(uint64_t); void OnCorrelationFilterApplied(uint64_t, int, const QModelIndex &); @@ -192,7 +190,9 @@ private slots: void ResetEventSearchBar(); void ResetPm4EventSearchBar(); void ResetHorizontalScroll(const DiveTreeView &tree_view); + void ResetVerticalScroll(const DiveTreeView &tree_view); void ClearViewModelSelection(DiveTreeView &tree_view, bool should_clear_tab); + void CorrelateCounter(const QModelIndex &index, bool called_from_gfxr_view); std::optional GetDrawCallIndexFromProxyIndex( const QModelIndex &proxy_index, const QAbstractProxyModel &proxy_model, @@ -314,7 +314,6 @@ private slots: int m_previous_tab_index = -1; bool m_gfxr_capture_loaded = false; bool m_correlated_capture_loaded = false; - bool m_gpu_time_correlation_from_command_hierarchy = true; EventSelection *m_event_selection; diff --git a/ui/perf_counter_tab_view.cpp b/ui/perf_counter_tab_view.cpp index 3047aa3c7..2f05f289c 100644 --- a/ui/perf_counter_tab_view.cpp +++ b/ui/perf_counter_tab_view.cpp @@ -27,6 +27,7 @@ PerfCounterTabView::PerfCounterTabView(PerfCounterModel &perf_counter_model, QWi m_perf_counter_view = new QTableView(); m_perf_counter_view->setModel(&m_perf_counter_model); m_perf_counter_view->setContextMenuPolicy(Qt::CustomContextMenu); + m_perf_counter_view->setSelectionBehavior(QAbstractItemView::SelectRows); m_search_trigger_button = new QPushButton; m_search_trigger_button->setObjectName(kPerfCounterSearchButtonName); @@ -53,11 +54,6 @@ PerfCounterTabView::PerfCounterTabView(PerfCounterModel &perf_counter_model, QWi this, SLOT(OnSearchBarVisibilityChange(bool))); - QObject::connect(parent, - SIGNAL(CorrelateCounter(uint64_t)), - this, - SLOT(OnCorrelateCounter(uint64_t))); - connect(m_perf_counter_view->selectionModel(), &QItemSelectionModel::currentChanged, this, @@ -230,7 +226,11 @@ void PerfCounterTabView::DisconnectSearchBar() } //-------------------------------------------------------------------------------------------------- -void PerfCounterTabView::OnCorrelateCounter(uint64_t index) +void PerfCounterTabView::CorrelateCounter(uint64_t index) { + QItemSelectionModel *selection_model = m_perf_counter_view->selectionModel(); + QSignalBlocker blocker(selection_model); m_perf_counter_view->selectRow(index); + m_perf_counter_view->update(); + m_perf_counter_view->viewport()->update(); } diff --git a/ui/perf_counter_tab_view.h b/ui/perf_counter_tab_view.h index 4eb9e58c5..c2ad6bd4b 100644 --- a/ui/perf_counter_tab_view.h +++ b/ui/perf_counter_tab_view.h @@ -27,6 +27,7 @@ class PerfCounterTabView : public QWidget public: explicit PerfCounterTabView(PerfCounterModel &perf_counter_model, QWidget *parent = nullptr); void ClearSelection(); + void CorrelateCounter(uint64_t index); public slots: void OnSearchBarVisibilityChange(bool isHidden); @@ -35,7 +36,6 @@ public slots: void OnSearch(const QString &text); void OnNextMatch(); void OnPrevMatch(); - void OnCorrelateCounter(uint64_t); signals: void UpdateSearchInfo(uint64_t curr_item_pos, uint64_t total_search_results); From c7a6e12c901d149b687660e7ebbdc5f109812099 Mon Sep 17 00:00:00 2001 From: Grant Date: Mon, 29 Sep 2025 08:16:18 +0000 Subject: [PATCH 6/6] Moves function, adds log --- ui/gpu_timing_tab_view.cpp | 6 ++++++ ui/gpu_timing_tab_view.h | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ui/gpu_timing_tab_view.cpp b/ui/gpu_timing_tab_view.cpp index fbac9735f..90b05b294 100644 --- a/ui/gpu_timing_tab_view.cpp +++ b/ui/gpu_timing_tab_view.cpp @@ -174,6 +174,12 @@ void GpuTimingTabView::OnSelectionChanged(const QModelIndex &index) { emit GpuTimingDataSelected(m_timed_event_indices.at(selected_row)); } + else + { + qDebug() << "GpuTimingTabView::OnSelectionChanged() ERROR: selected row (" << selected_row + << ") is out of range of collected indices of timed Vulkan events: " + << m_timed_event_indices.size() << ". Non-gpu timed event selected."; + } } //-------------------------------------------------------------------------------------------------- diff --git a/ui/gpu_timing_tab_view.h b/ui/gpu_timing_tab_view.h index bcb6e20b7..f5fcf27a1 100644 --- a/ui/gpu_timing_tab_view.h +++ b/ui/gpu_timing_tab_view.h @@ -37,11 +37,12 @@ class GpuTimingTabView : public QWidget void CollectIndicesFromModel(const QAbstractItemModel &command_hierarchy_model, const QModelIndex &parent_index); + void ClearSelection(); + public slots: void OnModelReset(); void OnEventSelectionChanged(const QModelIndex &model_index); void OnSelectionChanged(const QModelIndex &index); - void ClearSelection(); signals: void GpuTimingDataSelected(uint64_t);