From 0902c4c8df28d4ed1d4df68c28f1da0fceb85997 Mon Sep 17 00:00:00 2001 From: Daniel Rakos Date: Wed, 30 Oct 2019 15:25:54 +0100 Subject: [PATCH] Fix responsiveness of RGA GUI disassembly view The GUI becomes unresponsive for several seconds whenever the disassembly view gains or loses focus due to the code unnecessarily applying a stylesheet to the entire frame just to change border color, which seems to be a leftover functionality, considering that the color was only affected by the API used which is now chosen at application launch so the border color does not provide much value. According to the Qt documentation applications should not call setStylesheet() outside of the constructor because it's very costly and the current code calls it on focus change. This change fixes that by getting rid of all the code using setStylesheet() to change the disassembly view's border. Also, some missing header includes were added which most likely were uncovered by compiling against Qt 5.11.2 contrarily to Qt 5.9.2 recommended in the RGA documentation. --- .../Include/Qt/rgIsaDisassemblyView.h | 3 - .../Include/Qt/rgIsaDisassemblyViewOpenCL.h | 3 - .../Include/Qt/rgIsaDisassemblyViewVulkan.h | 4 - .../Include/rgStringConstants.h | 5 - .../Src/rgIsaDisassemblyView.cpp | 2403 ++++++++--------- .../Src/rgIsaDisassemblyViewOpenCL.cpp | 5 - .../Src/rgIsaDisassemblyViewVulkan.cpp | 5 - .../Src/rgSettingsButtonsView.cpp | 1 + 8 files changed, 1194 insertions(+), 1235 deletions(-) diff --git a/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyView.h b/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyView.h index da9bd175..adfd7eba 100755 --- a/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyView.h +++ b/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyView.h @@ -233,9 +233,6 @@ protected slots: // Set the cursor to pointing hand cursor for various widgets. void SetCursor(); - // Set the border stylesheet. - virtual void SetBorderStylesheet() = 0; - // Set the current target GPU to display disassembly for. void SetTargetGpu(const std::string& targetGpu); diff --git a/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyViewOpenCL.h b/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyViewOpenCL.h index 47521b61..99aa130c 100644 --- a/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyViewOpenCL.h +++ b/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyViewOpenCL.h @@ -16,9 +16,6 @@ class rgIsaDisassemblyViewOpenCL : public rgIsaDisassemblyView virtual bool PopulateBuildOutput(const std::shared_ptr pProjectClone, const rgBuildOutputsMap& buildOutputs) override; protected: - // Set the border stylesheet. - virtual void SetBorderStylesheet() override; - // Populate the disassembly view with the given CLI build output. bool PopulateDisassemblyView(const std::vector& sourceFiles, const rgBuildOutputsMap& buildOutput); }; \ No newline at end of file diff --git a/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyViewVulkan.h b/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyViewVulkan.h index 982ea5f7..d1f19e8c 100644 --- a/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyViewVulkan.h +++ b/RadeonGPUAnalyzerGUI/Include/Qt/rgIsaDisassemblyViewVulkan.h @@ -14,8 +14,4 @@ class rgIsaDisassemblyViewVulkan : public rgIsaDisassemblyViewGraphics public: rgIsaDisassemblyViewVulkan(QWidget* pParent); virtual ~rgIsaDisassemblyViewVulkan() = default; - -protected: - // Set the border stylesheet. - virtual void SetBorderStylesheet() override; }; \ No newline at end of file diff --git a/RadeonGPUAnalyzerGUI/Include/rgStringConstants.h b/RadeonGPUAnalyzerGUI/Include/rgStringConstants.h index 67067eb5..e402c351 100644 --- a/RadeonGPUAnalyzerGUI/Include/rgStringConstants.h +++ b/RadeonGPUAnalyzerGUI/Include/rgStringConstants.h @@ -526,11 +526,6 @@ static const char* STR_MAIN_WINDOW_STYLESHEET_FILE = "rgMainWindowStyle.q static const char* STR_MAIN_WINDOW_STYLESHEET_FILE_OPENCL = "OpenCL/rgMainWindowStyleOpenCL.qss"; static const char* STR_MAIN_WINDOW_STYLESHEET_FILE_VULKAN = "Vulkan/rgMainWindowStyleVulkan.qss"; -// Disassembly view frame border color. -static const char* STR_DISASSEMBLY_FRAME_BORDER_RED_STYLESHEET = "QFrame#frame {border: 1px solid rgb(224,30,55)}"; -static const char* STR_DISASSEMBLY_FRAME_BORDER_GREEN_STYLESHEET = "QFrame#frame {border: 1px solid rgb(18, 152, 0)}"; -static const char* STR_DISASSEMBLY_FRAME_BORDER_BLACK_STYLESHEET = "QFrame#frame {border: 1px solid black}"; - // The "current" property of file menu items. static const char* STR_FILE_MENU_PROPERTY_CURRENT = "current"; diff --git a/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyView.cpp b/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyView.cpp index a8db78db..6e909e2f 100644 --- a/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyView.cpp +++ b/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyView.cpp @@ -1,708 +1,709 @@ -#ifdef _WIN32 -// This warning relates to a compiler limitation that restricts the length of type names. -// The warning doesn't impose any risk to the code, so it's disabled for this file. -#pragma warning(disable : 4503) -#endif - -// C++. -#include -#include -#include -#include -#include - -// Qt. -#include -#include - -// Infra. -#include -#include -#include -#include -#include - -// Local. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Names of special widgets within the disassembly view. -static const char* STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST = "DisassemblyColumnVisibilityList"; -static const char* STR_DISASSEMBLY_COLUMN_LIST_ITEM_CHECKBOX = "ListWidgetCheckBox"; -static const char* STR_DISASSEMBLY_COLUMN_LIST_ITEM_ALL_CHECKBOX = "ListWidgetAllCheckBox"; - -// Object name associated with the target GPU dropdown list. -static const char* STR_DISASSEMBLY_TARGET_GPU_LIST = "TargetGpuList"; - -// Columns push button font size. -const int s_PUSH_BUTTON_FONT_SIZE = 11; - -rgIsaDisassemblyView::rgIsaDisassemblyView(QWidget* pParent) : - QWidget(pParent) -{ - ui.setupUi(this); - - ui.verticalSplitterWidget->setStretchFactor(0, 1); - ui.verticalSplitterWidget->setStretchFactor(1, 0); - ui.verticalSplitterWidget->handle(1)->setDisabled(true); - - // Create the widget used to control column visibility. - CreateColumnVisibilityControls(); - - // Fill the column visibility dropdown with all of the possible column names. - PopulateColumnVisibilityList(); - - // Create the dropdown list used to select the current target GPU. - CreateTargetGpuListControls(); - - // Connect the signals for the disassembly view. - ConnectSignals(); - - // Set mouse pointer to pointing hand cursor. - SetCursor(); - - // Block recursively repolishing child tables in the disassembly view. - ui.disassemblyTableHostWidget->setProperty(gs_IS_REPOLISHING_BLOCKED, true); - - // Set the push button font sizes. - SetFontSizes(); - - // Set the focus proxy of the view maximize button to be the title bar. - // This will cause the frame border to change to black when the maximize button loses focus. - // This is because the view title bar already handles its own loss of focus event. - ui.viewMaximizeButton->setFocusProxy(ui.viewTitlebar); -} - -rgIsaDisassemblyView::~rgIsaDisassemblyView() -{ - // Remove the column dropdown focus event filters if they exist. - if (m_pDisassemblyColumnsListWidget != nullptr && m_pDisassemblyColumnsListEventFilter != nullptr) - { - m_pDisassemblyColumnsListWidget->removeEventFilter(m_pDisassemblyColumnsListEventFilter); - qApp->removeEventFilter(m_pDisassemblyColumnsListEventFilter); - } - - // Remove the GPU dropdown event filter. - if (m_pTargetGpusListWidget != nullptr && m_pTargetGpusListEventFilter != nullptr) - { - m_pTargetGpusListWidget->removeEventFilter(m_pTargetGpusListEventFilter); - qApp->removeEventFilter(m_pTargetGpusListEventFilter); - } -} - -void rgIsaDisassemblyView::ClearBuildOutput() -{ - if (!m_gpuTabViews.empty()) - { - // Destroy all existing GPU tabs. - auto firstGpuTab = m_gpuTabViews.begin(); - auto lastGpuTab = m_gpuTabViews.end(); - for (auto gpuTabIter = firstGpuTab; gpuTabIter != lastGpuTab; ++gpuTabIter) - { - ui.disassemblyTableHostWidget->removeWidget(gpuTabIter->second); - } - } - - // Clear all state data in the view. - m_gpuTabViews.clear(); - m_gpuResourceUsageViews.clear(); - m_resourceUsageText.clear(); -} - -void rgIsaDisassemblyView::GetResourceUsageTextBounds(QRect& textBounds) const -{ - QFontMetrics fontMetrics(m_resourceUsageFont); - textBounds = fontMetrics.boundingRect(m_resourceUsageText.c_str()); -} - -bool rgIsaDisassemblyView::IsEmpty() const -{ - return m_gpuTabViews.empty(); -} - -void rgIsaDisassemblyView::RemoveInputFileEntries(const std::string& inputFilePath) -{ - // Clean up disassembly tables associated with the given file. - DestroyDisassemblyViewsForFile(inputFilePath); - - // Clean up resource usage views associated with the given file. - DestroyResourceUsageViewsForFile(inputFilePath); -} - -void rgIsaDisassemblyView::HandleInputFileSelectedLineChanged(const std::string& targetGpu, const std::string& inputFilePath, std::string& entryName, int lineIndex) -{ - // Get the currently active stacked view. - rgIsaDisassemblyTabView* pCurrentTabView = GetTargetGpuTabWidgetByTabName(targetGpu); - - if (pCurrentTabView != nullptr && pCurrentTabView->GetTableCount() > 0) - { - HandleSelectedEntrypointChanged(targetGpu, inputFilePath, entryName); - pCurrentTabView->UpdateCorrelatedSourceFileLine(inputFilePath, lineIndex, entryName); - } -} - -void rgIsaDisassemblyView::HandleSelectedEntrypointChanged(const std::string& targetGpu, const std::string& inputFilePath, const std::string& selectedEntrypointName) -{ - // Get the currently active stacked view. - rgIsaDisassemblyTabView* pTargetTabView = GetTargetGpuTabWidgetByTabName(targetGpu); - - // Switch the target GPU tab if necessary. - if (pTargetTabView != m_pCurrentTabView) - { - SetCurrentTargetGpuTabView(pTargetTabView); - } - - if (pTargetTabView != nullptr) - { - // Switch the table to show the disassembly for the given entrypoint. - pTargetTabView->SwitchToEntryPoint(inputFilePath, selectedEntrypointName); - } - - // Get a reference to the map of input file path to the entry point names map. - InputToEntrypointViews& inputFileToEntrypointMap = m_gpuResourceUsageViews[targetGpu]; - - // Use the input file path to get a reference to a map of entry point names to resource usage views. - EntrypointToResourcesView& entrypointMap = inputFileToEntrypointMap[inputFilePath]; - - // Search the map to find the resource usage view associated with the given entrypoint. - auto resourceViewIter = entrypointMap.find(selectedEntrypointName); - if (resourceViewIter != entrypointMap.end()) - { - // Display the resource usage view associated with the given entrypoint. - rgResourceUsageView* pResourceUsageView = resourceViewIter->second; - ui.resourceUsageHostStackedWidget->setCurrentWidget(pResourceUsageView); - } -} - -void rgIsaDisassemblyView::HandleColumnVisibilityButtonClicked(bool /*clicked*/) -{ - // Make the list widget appear and process user selection from the list widget. - bool visible = m_pDisassemblyColumnsListWidget->isVisible(); - if (visible == true) - { - m_pDisassemblyColumnsListWidget->hide(); - - // Change the up arrow to a down arrow. - ui.columnVisibilityArrowPushButton->SetDirection(ArrowIconWidget::Direction::DownArrow); - } - else - { - // Update the check box values in case they were changed in global settings. - rgConfigManager& configManager = rgConfigManager::Instance(); - std::shared_ptr pGlobalSettings = configManager.GetGlobalConfig(); - ListWidget::SetColumnVisibilityCheckboxes(m_pDisassemblyColumnsListWidget, pGlobalSettings->m_visibleDisassemblyViewColumns); - - // Compute where to place the combo box relative to where the arrow button is. - QWidget* pWidget = ui.columnVisibilityArrowPushButton; - m_pDisassemblyColumnsListWidget->show(); - m_pDisassemblyColumnsListWidget->setFocus(); - QRect rect = pWidget->geometry(); - QPoint pos(0, 0); - pos = pWidget->mapTo(this, pos); - pos.setY(pos.y() + rect.height()); - int height = QtCommon::QtUtil::GetListWidgetHeight(m_pDisassemblyColumnsListWidget); - int width = QtCommon::QtUtil::GetListWidgetWidth(m_pDisassemblyColumnsListWidget); - m_pDisassemblyColumnsListWidget->setGeometry(pos.x(), pos.y(), width + s_CHECK_BOX_WIDTH, height); - - // Change the down arrow to an up arrow. - ui.columnVisibilityArrowPushButton->SetDirection(ArrowIconWidget::Direction::UpArrow); - } -} - -void rgIsaDisassemblyView::HandleColumnVisibilityComboBoxItemClicked(const QString& text, const bool checked) -{ - rgConfigManager& configManager = rgConfigManager::Instance(); - std::shared_ptr pGlobalSettings = configManager.GetGlobalConfig(); - - const int firstColumn = rgIsaDisassemblyTableModel::GetTableColumnIndex(rgIsaDisassemblyTableColumns::Address); - const int lastColumn = rgIsaDisassemblyTableModel::GetTableColumnIndex(rgIsaDisassemblyTableColumns::Count); - - // Get the current checked state of the UI. - // This will include changes from the check/uncheck that triggered this callback. - std::vector columnVisibility = ListWidget::GetColumnVisibilityCheckboxes(m_pDisassemblyColumnsListWidget); - - // Make sure at least one check box is still checked. - bool isAtLeastOneChecked = std::any_of(columnVisibility.begin() + firstColumn, columnVisibility.begin() + lastColumn, [](bool b) { return b == true; }); - - if (checked || isAtLeastOneChecked) - { - // If the user checked the "All" option, Step through each column and set to visible. - if (text.compare(STR_DISASSEMBLY_TABLE_COLUMN_ALL) == 0 && (checked == true)) - { - for (int columnIndex = firstColumn; columnIndex < lastColumn; ++columnIndex) - { - columnVisibility[columnIndex] = checked; - } - - // Update the state of the dropdown check boxes to reflect that all options are checked. - ListWidget::SetColumnVisibilityCheckboxes(m_pDisassemblyColumnsListWidget, columnVisibility); - } - - // Save the changes. - configManager.Instance().SetDisassemblyColumnVisibility(columnVisibility); - configManager.SaveGlobalConfigFile(); - } - else - { - // The user tried to uncheck the last check box, but at least one box - // MUST be checked, so find that item in the ListWidget, and set it back to checked. - for (int row = 0; row < m_pDisassemblyColumnsListWidget->count(); row++) - { - QListWidgetItem* pItem = m_pDisassemblyColumnsListWidget->item(row); - QCheckBox* pCheckBox = (QCheckBox*)m_pDisassemblyColumnsListWidget->itemWidget(pItem); - QString checkBoxText = pCheckBox->text(); - if (checkBoxText.compare(text) == 0) - { - QCheckBox* pCheckBox = (QCheckBox*)m_pDisassemblyColumnsListWidget->itemWidget(pItem); - pCheckBox->setChecked(true); - } - } - } - - // See if the "All" box needs checking/unchecking. - ListWidget::UpdateAllCheckbox(m_pDisassemblyColumnsListWidget); - - // Update the "All" checkbox text color to grey or black. - UpdateAllCheckBoxText(); -} - -void rgIsaDisassemblyView::HandleColumnVisibilityFilterStateChanged(bool checked) -{ - // Figure out the sender and process appropriately. - QObject* pSender = QObject::sender(); - assert(pSender != nullptr); - - // Find out which entry caused the signal. - QWidget* pItem = qobject_cast(pSender); - assert(pItem != nullptr); - - QCheckBox* pCheckBox = qobject_cast(pSender); - assert(pCheckBox != nullptr); - - // Process the click. - HandleColumnVisibilityComboBoxItemClicked(pCheckBox->text(), checked); - - // Emit a signal to trigger a refresh of the disassembly table's filter. - emit DisassemblyColumnVisibilityUpdated(); -} - -void rgIsaDisassemblyView::HandleTargetGpuArrowClicked(bool clicked) -{ - // Make the list widget appear and process user selection from the list widget. - bool visible = m_pTargetGpusListWidget->isVisible(); - if (visible == true) - { - m_pTargetGpusListWidget->hide(); - - // Change the up arrow to a down arrow. - ui.targetGpuPushButton->SetDirection(ArrowIconWidget::Direction::DownArrow); - } - else - { - // Compute where to place the combo box relative to where the arrow button is. - QWidget* pWidget = ui.targetGpuPushButton; - m_pTargetGpusListWidget->show(); - m_pTargetGpusListWidget->setFocus(); - m_pTargetGpusListWidget->setCursor(Qt::PointingHandCursor); - QRect rect = pWidget->geometry(); - QPoint pos(0, 0); - pos = pWidget->mapTo(this, pos); - pos.setY(pos.y() + rect.height()); - int height = QtCommon::QtUtil::GetListWidgetHeight(m_pTargetGpusListWidget); - int width = QtCommon::QtUtil::GetListWidgetWidth(m_pTargetGpusListWidget); - m_pTargetGpusListWidget->setGeometry(pos.x(), pos.y(), width + s_CHECK_BOX_WIDTH, height); - - // Change the down arrow to an up arrow. - ui.targetGpuPushButton->SetDirection(ArrowIconWidget::Direction::UpArrow); - } -} - -void rgIsaDisassemblyView::HandleTargetGpuChanged(int currentIndex) -{ - assert(m_pTargetGpusListWidget != nullptr); - if (m_pTargetGpusListWidget != nullptr) - { - auto pTargetGpuItem = m_pTargetGpusListWidget->item(currentIndex); - assert(pTargetGpuItem != nullptr); - if (pTargetGpuItem != nullptr) - { - // Change the target GPU if it differs from the current target GPU. - std::string currentTargetGpu = ui.targetGpuPushButton->text().toStdString(); - std::string newTargetGpu = pTargetGpuItem->text().toStdString(); - if (currentTargetGpu.compare(newTargetGpu) != 0) - { - // Use the dropdown list's selection model to change the currently selected target GPU. - QItemSelectionModel* pSelectionModel = m_pTargetGpusListWidget->selectionModel(); - assert(pSelectionModel != nullptr); - if (pSelectionModel != nullptr) - { - // Select the new target GPU within the dropdown list widget. - QAbstractItemModel* pListModel = m_pTargetGpusListWidget->model(); - - assert(pListModel != nullptr); - if (pListModel != nullptr) - { - QModelIndex modelIndex = pListModel->index(currentIndex, 0); - pSelectionModel->setCurrentIndex(modelIndex, QItemSelectionModel::SelectionFlag::Select); - } - } - - // Change the target GPU to the newly selected item. - SetTargetGpu(newTargetGpu); - - // Strip the GPU name from the architecture if needed. - std::string strippedGpuName; - size_t bracketPos = newTargetGpu.find("("); - if (bracketPos != std::string::npos && newTargetGpu.size() > 2) - { - strippedGpuName = newTargetGpu.substr(0, bracketPos - 1); - } - else - { - strippedGpuName = newTargetGpu; - } - - // Strip gfx notation if needed. - size_t slashPos = strippedGpuName.find("/"); - if (slashPos != std::string::npos) - { - strippedGpuName = strippedGpuName.substr(slashPos + 1); - } - - // Emit a signal with the name of the target GPU to switch to. - emit SelectedTargetGpuChanged(strippedGpuName); - } - } - } - - // Set focus to disassembly view. - setFocus(); -} - -void rgIsaDisassemblyView::ClearListWidget(ListWidget* &pListWidget) -{ - assert(pListWidget != nullptr); - - // Disconnect slot/signal connection for each check box - for (int row = 0; row < pListWidget->count(); row++) - { - QListWidgetItem* pItem = pListWidget->item(row); - QCheckBox* pCheckBox = (QCheckBox*)pListWidget->itemWidget(pItem); - - if (pListWidget->objectName().compare(STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST) == 0) - { - bool isDisconnected = disconnect(pCheckBox, &QCheckBox::clicked, this, &rgIsaDisassemblyView::HandleColumnVisibilityFilterStateChanged); - assert(isDisconnected); - } - else - { - assert(false); - } - } - - // Clear the list widget. This also deletes each item. - pListWidget->clear(); -} - -void rgIsaDisassemblyView::ConnectDisassemblyTabViewSignals(rgIsaDisassemblyTabView* pEntryView) -{ - // Connect the new disassembly GPU tab's source input file highlight line changed signal. - bool isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::InputSourceHighlightedLineChanged, this, &rgIsaDisassemblyView::InputSourceHighlightedLineChanged); - assert(isConnected); - - // Connect the disassembly table's resized event handler. - isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::DisassemblyTableWidthResizeRequested, this, &rgIsaDisassemblyView::DisassemblyTableWidthResizeRequested); - assert(isConnected); - - // Connect the disassembly view's column visibility updated signal. - isConnected = connect(this, &rgIsaDisassemblyView::DisassemblyColumnVisibilityUpdated, pEntryView, &rgIsaDisassemblyTabView::HandleColumnVisibilityFilterStateChanged); - assert(isConnected); - - // Connect the disassembly view's set frame border red signal. - isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FrameFocusInSignal, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); - assert(isConnected); - - // Connect the disassembly view's set frame border black signal. - isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FrameFocusOutSignal, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewLostFocus); - assert(isConnected); - - // Connect the disassembly view's title bar's set frame border red signal. - isConnected = connect(ui.viewTitlebar, &rgIsaDisassemblyViewTitlebar::FrameFocusInSignal, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); - assert(isConnected); - - // Connect the disassembly view's enable scroll bar signal. - isConnected = connect(this, &rgIsaDisassemblyView::EnableScrollbarSignals, pEntryView, &rgIsaDisassemblyTabView::EnableScrollbarSignals); - assert(isConnected); - - // Connect the disassembly view's disable scroll bar signal. - isConnected = connect(this, &rgIsaDisassemblyView::DisableScrollbarSignals, pEntryView, &rgIsaDisassemblyTabView::DisableScrollbarSignals); - assert(isConnected); - - // Connect the disassembly table's target GPU push button focus in signal. - isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FocusTargetGpuPushButton, this, &rgIsaDisassemblyView::HandleFocusTargetGpuPushButton); - assert(isConnected); - - // Connect the disassembly table's switch disassembly view size signal. - isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::SwitchDisassemblyContainerSize, this, &rgIsaDisassemblyView::SwitchDisassemblyContainerSize); - assert(isConnected); - - // Connect the disassembly table's columns push button focus in signal. - isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FocusColumnPushButton, this, &rgIsaDisassemblyView::HandleFocusColumnsPushButton); - assert(isConnected); - - // Connect the disassembly table's cli output window focus in signal. - isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FocusSourceWindow, this, &rgIsaDisassemblyView::FocusSourceWindow); - assert(isConnected); - - // Connect the disassembly view's update current sub widget signal. - isConnected = connect(this, &rgIsaDisassemblyView::UpdateCurrentSubWidget, pEntryView, &rgIsaDisassemblyTabView::UpdateCurrentSubWidget); - assert(isConnected); -} - -void rgIsaDisassemblyView::ConnectSignals() -{ - // Connect the column visibility selector arrow button. - bool isConnected = connect(ui.columnVisibilityArrowPushButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleColumnVisibilityButtonClicked); - assert(isConnected); - - // Connect the handler to show/hide the target GPU list when the arrow button is clicked. - isConnected = connect(ui.targetGpuPushButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleTargetGpuArrowClicked); - assert(isConnected); - - // Connect the handler to give focus to frame on view maximize button click. - isConnected = connect(ui.viewMaximizeButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); - assert(isConnected); - - // Connect the handler to give focus to frame on disassembly column list widget's gain of focus. - isConnected = connect(m_pDisassemblyColumnsListWidget, &ListWidget::FocusInEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusInEvent); - assert(isConnected); - - // Connect the handler to remove focus from frame on disassembly column list widget's loss of focus. - isConnected = connect(m_pDisassemblyColumnsListWidget, &ListWidget::FocusOutEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusOutEvent); - assert(isConnected); - - // Connect the handler to give focus to frame on target GPUs list widget's gain of focus. - isConnected = connect(m_pTargetGpusListWidget, &ListWidget::FocusInEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusInEvent); - assert(isConnected); - - // Connect the handler to give focus to frame on target GPUs list widget's loss of focus. - isConnected = connect(m_pTargetGpusListWidget, &ListWidget::FocusOutEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusOutEvent); - assert(isConnected); - - // Connect the handler to give focus to frame on columns push button click. - isConnected = connect(ui.columnVisibilityArrowPushButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); - assert(isConnected); - - // Connect the handler to give focus to frame on target GPUs push button click. - isConnected = connect(ui.targetGpuPushButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); - assert(isConnected); - - // Connect the handler to remove focus from frame on columns push button loss of focus. - isConnected = connect(ui.columnVisibilityArrowPushButton, &ArrowIconWidget::FocusOutEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusOutEvent); - assert(isConnected); - - // Connect the handler to give focus to frame on target GPUs push button loss of focus. - isConnected = connect(ui.targetGpuPushButton, &ArrowIconWidget::FocusOutEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusOutEvent); - assert(isConnected); - - // Select next GPU device action. - m_pSelectNextGPUTarget = new QAction(this); - m_pSelectNextGPUTarget->setShortcutContext(Qt::ApplicationShortcut); - m_pSelectNextGPUTarget->setShortcut(QKeySequence(gs_DISASSEMBLY_VIEW_HOTKEY_GPU_SELECTION)); - addAction(m_pSelectNextGPUTarget); - - isConnected = connect(m_pSelectNextGPUTarget, &QAction::triggered, this, &rgIsaDisassemblyView::HandleSelectNextGPUTargetAction); - assert(isConnected); -} - -void rgIsaDisassemblyView::CreateColumnVisibilityControls() -{ - // Setup the list widget that opens when the user clicks the column visibility arrow. - rgUtils::SetupComboList(this, m_pDisassemblyColumnsListWidget, ui.columnVisibilityArrowPushButton, m_pDisassemblyColumnsListEventFilter, false); - m_pDisassemblyColumnsListWidget->setObjectName(STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST); - - // Handle the open gpu list widget signal and, - // the update current sub widget signal from the hide list widget event filter object. - if (m_pDisassemblyColumnsListEventFilter != nullptr) - { - rgHideListWidgetEventFilter* pEventFilter = static_cast(m_pDisassemblyColumnsListEventFilter); - if (pEventFilter != nullptr) - { - bool isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::OpenGpuListWidget, this, &rgIsaDisassemblyView::HandleOpenGpuListWidget); - assert(isConnected); - - isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::UpdateCurrentSubWidget, this, &rgIsaDisassemblyView::UpdateCurrentSubWidget); - assert(isConnected); - - isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::FocusCliOutputWindow, this, &rgIsaDisassemblyView::FocusCliOutputWindow); - assert(isConnected); - } - } - - // Update scale factor for widgets. - QFont font = ui.columnVisibilityArrowPushButton->font(); - double scaleFactor = ScalingManager::Get().GetScaleFactor(); - font.setPointSize(s_PUSH_BUTTON_FONT_SIZE * scaleFactor); - m_pDisassemblyColumnsListWidget->setStyleSheet(s_LIST_WIDGET_STYLE.arg(font.pointSize())); - - // Reset the current selection in the column visibility list. - m_pDisassemblyColumnsListWidget->setCurrentRow(0); -} - -void rgIsaDisassemblyView::HandleOpenColumnListWidget() -{ - if (m_pDisassemblyColumnsListWidget != nullptr) - { - ui.columnVisibilityArrowPushButton->clicked(); - } -} - -void rgIsaDisassemblyView::CreateTargetGpuListControls() -{ - // Setup the list widget used to select the current target GPU. - rgUtils::SetupComboList(this, m_pTargetGpusListWidget, ui.targetGpuPushButton, m_pTargetGpusListEventFilter, false); - m_pTargetGpusListWidget->setObjectName(STR_DISASSEMBLY_TARGET_GPU_LIST); - - if (m_pTargetGpusListEventFilter != nullptr) - { - rgHideListWidgetEventFilter* pEventFilter = static_cast(m_pTargetGpusListEventFilter); - if (pEventFilter != nullptr) - { - bool isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::OpenColumnListWidget, this, &rgIsaDisassemblyView::HandleOpenColumnListWidget); - assert(isConnected); - - isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::UpdateCurrentSubWidget, this, &rgIsaDisassemblyView::UpdateCurrentSubWidget); - assert(isConnected); - } - } - - // Update scale factor for widgets. - QFont font = ui.targetGpuPushButton->font(); - double scaleFactor = ScalingManager::Get().GetScaleFactor(); - font.setPointSize(s_PUSH_BUTTON_FONT_SIZE * scaleFactor); - m_pTargetGpusListWidget->setStyleSheet(s_LIST_WIDGET_STYLE.arg(font.pointSize())); - - // Reset the current selection in the target GPU dropdown list. - m_pTargetGpusListWidget->setCurrentRow(0); - - // Connect the signal used to handle a change in the selected target GPU. - bool isConnected = connect(m_pTargetGpusListWidget, &QListWidget::currentRowChanged, this, &rgIsaDisassemblyView::HandleTargetGpuChanged); - assert(isConnected); -} - -void rgIsaDisassemblyView::HandleOpenGpuListWidget() -{ - if (m_pTargetGpusListWidget != nullptr) - { - ui.targetGpuPushButton->clicked(); - } -} - -std::string rgIsaDisassemblyView::GetDisassemblyColumnName(rgIsaDisassemblyTableColumns column) const -{ - std::string result; - - static std::map kColumnNameMap = - { - { rgIsaDisassemblyTableColumns::Address, STR_DISASSEMBLY_TABLE_COLUMN_ADDRESS }, - { rgIsaDisassemblyTableColumns::Opcode, STR_DISASSEMBLY_TABLE_COLUMN_OPCODE }, - { rgIsaDisassemblyTableColumns::Operands, STR_DISASSEMBLY_TABLE_COLUMN_OPERANDS }, - { rgIsaDisassemblyTableColumns::FunctionalUnit, STR_DISASSEMBLY_TABLE_COLUMN_FUNCTIONAL_UNIT }, - { rgIsaDisassemblyTableColumns::Cycles, STR_DISASSEMBLY_TABLE_COLUMN_CYCLES }, - { rgIsaDisassemblyTableColumns::BinaryEncoding, STR_DISASSEMBLY_TABLE_COLUMN_BINARY_ENCODING }, - }; - - auto columnNameIter = kColumnNameMap.find(column); - if (columnNameIter != kColumnNameMap.end()) - { - result = columnNameIter->second; - } - else - { - // The incoming column doesn't have a name string mapped to it. - assert(false); - } - - return result; -} - -rgIsaDisassemblyTabView* rgIsaDisassemblyView::GetTargetGpuTabWidgetByTabName(const std::string& tabText) const -{ - rgIsaDisassemblyTabView* pResult = nullptr; - - // If a matching view exists return it. - auto gpuTabIter = m_gpuTabViews.find(tabText); - if (gpuTabIter != m_gpuTabViews.end()) - { - pResult = gpuTabIter->second; - } - - return pResult; -} - -void rgIsaDisassemblyView::PopulateTargetGpuList(const rgBuildOutputsMap& buildOutput) -{ - // Get a mapping of the compute capability to architecture. - std::map computeCapabilityToArch; - bool hasArchMapping = rgUtils::GetComputeCapabilityToArchMapping(computeCapabilityToArch); - - // Block signals to stop updates when each new GPU is added to the list. - m_pTargetGpusListWidget->blockSignals(true); - - m_pTargetGpusListWidget->clear(); - - std::vector targets; - - for (auto targetGpuIter = buildOutput.rbegin(); targetGpuIter != buildOutput.rend(); ++targetGpuIter) - { - if (targetGpuIter->second != nullptr) - { - // Add each target GPU from the build outputs to the dropdown list. - auto targetGpu = targetGpuIter->first; - - // Construct the presented name. - std::stringstream presentedName; - - // If applicable, prepend the gfx notation (for example, "gfx802/Tonga" for "Tonga"). - std::string gfxNotation; - bool hasGfxNotation = rgUtils::GetGfxNotation(targetGpu, gfxNotation); - if (hasGfxNotation && !gfxNotation.empty()) - { - presentedName << gfxNotation << "/"; - } - presentedName << targetGpu; - - // If we have a mapping, let's construct a name that includes - // the GPU architecture as well: (). - if (hasArchMapping) - { - auto iter = computeCapabilityToArch.find(targetGpu); - if (iter != computeCapabilityToArch.end()) - { - presentedName << " (" << iter->second << ")"; - } - } - - // Add the name to the list. - targets.push_back(presentedName.str()); - } - } - assert(!targets.empty()); - - // Sort and choose the latest target. +#ifdef _WIN32 +// This warning relates to a compiler limitation that restricts the length of type names. +// The warning doesn't impose any risk to the code, so it's disabled for this file. +#pragma warning(disable : 4503) +#endif + +// C++. +#include +#include +#include +#include +#include + +// Qt. +#include +#include +#include + +// Infra. +#include +#include +#include +#include +#include + +// Local. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Names of special widgets within the disassembly view. +static const char* STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST = "DisassemblyColumnVisibilityList"; +static const char* STR_DISASSEMBLY_COLUMN_LIST_ITEM_CHECKBOX = "ListWidgetCheckBox"; +static const char* STR_DISASSEMBLY_COLUMN_LIST_ITEM_ALL_CHECKBOX = "ListWidgetAllCheckBox"; + +// Object name associated with the target GPU dropdown list. +static const char* STR_DISASSEMBLY_TARGET_GPU_LIST = "TargetGpuList"; + +// Columns push button font size. +const int s_PUSH_BUTTON_FONT_SIZE = 11; + +rgIsaDisassemblyView::rgIsaDisassemblyView(QWidget* pParent) : + QWidget(pParent) +{ + ui.setupUi(this); + + ui.verticalSplitterWidget->setStretchFactor(0, 1); + ui.verticalSplitterWidget->setStretchFactor(1, 0); + ui.verticalSplitterWidget->handle(1)->setDisabled(true); + + // Create the widget used to control column visibility. + CreateColumnVisibilityControls(); + + // Fill the column visibility dropdown with all of the possible column names. + PopulateColumnVisibilityList(); + + // Create the dropdown list used to select the current target GPU. + CreateTargetGpuListControls(); + + // Connect the signals for the disassembly view. + ConnectSignals(); + + // Set mouse pointer to pointing hand cursor. + SetCursor(); + + // Block recursively repolishing child tables in the disassembly view. + ui.disassemblyTableHostWidget->setProperty(gs_IS_REPOLISHING_BLOCKED, true); + + // Set the push button font sizes. + SetFontSizes(); + + // Set the focus proxy of the view maximize button to be the title bar. + // This will cause the frame border to change to black when the maximize button loses focus. + // This is because the view title bar already handles its own loss of focus event. + ui.viewMaximizeButton->setFocusProxy(ui.viewTitlebar); +} + +rgIsaDisassemblyView::~rgIsaDisassemblyView() +{ + // Remove the column dropdown focus event filters if they exist. + if (m_pDisassemblyColumnsListWidget != nullptr && m_pDisassemblyColumnsListEventFilter != nullptr) + { + m_pDisassemblyColumnsListWidget->removeEventFilter(m_pDisassemblyColumnsListEventFilter); + qApp->removeEventFilter(m_pDisassemblyColumnsListEventFilter); + } + + // Remove the GPU dropdown event filter. + if (m_pTargetGpusListWidget != nullptr && m_pTargetGpusListEventFilter != nullptr) + { + m_pTargetGpusListWidget->removeEventFilter(m_pTargetGpusListEventFilter); + qApp->removeEventFilter(m_pTargetGpusListEventFilter); + } +} + +void rgIsaDisassemblyView::ClearBuildOutput() +{ + if (!m_gpuTabViews.empty()) + { + // Destroy all existing GPU tabs. + auto firstGpuTab = m_gpuTabViews.begin(); + auto lastGpuTab = m_gpuTabViews.end(); + for (auto gpuTabIter = firstGpuTab; gpuTabIter != lastGpuTab; ++gpuTabIter) + { + ui.disassemblyTableHostWidget->removeWidget(gpuTabIter->second); + } + } + + // Clear all state data in the view. + m_gpuTabViews.clear(); + m_gpuResourceUsageViews.clear(); + m_resourceUsageText.clear(); +} + +void rgIsaDisassemblyView::GetResourceUsageTextBounds(QRect& textBounds) const +{ + QFontMetrics fontMetrics(m_resourceUsageFont); + textBounds = fontMetrics.boundingRect(m_resourceUsageText.c_str()); +} + +bool rgIsaDisassemblyView::IsEmpty() const +{ + return m_gpuTabViews.empty(); +} + +void rgIsaDisassemblyView::RemoveInputFileEntries(const std::string& inputFilePath) +{ + // Clean up disassembly tables associated with the given file. + DestroyDisassemblyViewsForFile(inputFilePath); + + // Clean up resource usage views associated with the given file. + DestroyResourceUsageViewsForFile(inputFilePath); +} + +void rgIsaDisassemblyView::HandleInputFileSelectedLineChanged(const std::string& targetGpu, const std::string& inputFilePath, std::string& entryName, int lineIndex) +{ + // Get the currently active stacked view. + rgIsaDisassemblyTabView* pCurrentTabView = GetTargetGpuTabWidgetByTabName(targetGpu); + + if (pCurrentTabView != nullptr && pCurrentTabView->GetTableCount() > 0) + { + HandleSelectedEntrypointChanged(targetGpu, inputFilePath, entryName); + pCurrentTabView->UpdateCorrelatedSourceFileLine(inputFilePath, lineIndex, entryName); + } +} + +void rgIsaDisassemblyView::HandleSelectedEntrypointChanged(const std::string& targetGpu, const std::string& inputFilePath, const std::string& selectedEntrypointName) +{ + // Get the currently active stacked view. + rgIsaDisassemblyTabView* pTargetTabView = GetTargetGpuTabWidgetByTabName(targetGpu); + + // Switch the target GPU tab if necessary. + if (pTargetTabView != m_pCurrentTabView) + { + SetCurrentTargetGpuTabView(pTargetTabView); + } + + if (pTargetTabView != nullptr) + { + // Switch the table to show the disassembly for the given entrypoint. + pTargetTabView->SwitchToEntryPoint(inputFilePath, selectedEntrypointName); + } + + // Get a reference to the map of input file path to the entry point names map. + InputToEntrypointViews& inputFileToEntrypointMap = m_gpuResourceUsageViews[targetGpu]; + + // Use the input file path to get a reference to a map of entry point names to resource usage views. + EntrypointToResourcesView& entrypointMap = inputFileToEntrypointMap[inputFilePath]; + + // Search the map to find the resource usage view associated with the given entrypoint. + auto resourceViewIter = entrypointMap.find(selectedEntrypointName); + if (resourceViewIter != entrypointMap.end()) + { + // Display the resource usage view associated with the given entrypoint. + rgResourceUsageView* pResourceUsageView = resourceViewIter->second; + ui.resourceUsageHostStackedWidget->setCurrentWidget(pResourceUsageView); + } +} + +void rgIsaDisassemblyView::HandleColumnVisibilityButtonClicked(bool /*clicked*/) +{ + // Make the list widget appear and process user selection from the list widget. + bool visible = m_pDisassemblyColumnsListWidget->isVisible(); + if (visible == true) + { + m_pDisassemblyColumnsListWidget->hide(); + + // Change the up arrow to a down arrow. + ui.columnVisibilityArrowPushButton->SetDirection(ArrowIconWidget::Direction::DownArrow); + } + else + { + // Update the check box values in case they were changed in global settings. + rgConfigManager& configManager = rgConfigManager::Instance(); + std::shared_ptr pGlobalSettings = configManager.GetGlobalConfig(); + ListWidget::SetColumnVisibilityCheckboxes(m_pDisassemblyColumnsListWidget, pGlobalSettings->m_visibleDisassemblyViewColumns); + + // Compute where to place the combo box relative to where the arrow button is. + QWidget* pWidget = ui.columnVisibilityArrowPushButton; + m_pDisassemblyColumnsListWidget->show(); + m_pDisassemblyColumnsListWidget->setFocus(); + QRect rect = pWidget->geometry(); + QPoint pos(0, 0); + pos = pWidget->mapTo(this, pos); + pos.setY(pos.y() + rect.height()); + int height = QtCommon::QtUtil::GetListWidgetHeight(m_pDisassemblyColumnsListWidget); + int width = QtCommon::QtUtil::GetListWidgetWidth(m_pDisassemblyColumnsListWidget); + m_pDisassemblyColumnsListWidget->setGeometry(pos.x(), pos.y(), width + s_CHECK_BOX_WIDTH, height); + + // Change the down arrow to an up arrow. + ui.columnVisibilityArrowPushButton->SetDirection(ArrowIconWidget::Direction::UpArrow); + } +} + +void rgIsaDisassemblyView::HandleColumnVisibilityComboBoxItemClicked(const QString& text, const bool checked) +{ + rgConfigManager& configManager = rgConfigManager::Instance(); + std::shared_ptr pGlobalSettings = configManager.GetGlobalConfig(); + + const int firstColumn = rgIsaDisassemblyTableModel::GetTableColumnIndex(rgIsaDisassemblyTableColumns::Address); + const int lastColumn = rgIsaDisassemblyTableModel::GetTableColumnIndex(rgIsaDisassemblyTableColumns::Count); + + // Get the current checked state of the UI. + // This will include changes from the check/uncheck that triggered this callback. + std::vector columnVisibility = ListWidget::GetColumnVisibilityCheckboxes(m_pDisassemblyColumnsListWidget); + + // Make sure at least one check box is still checked. + bool isAtLeastOneChecked = std::any_of(columnVisibility.begin() + firstColumn, columnVisibility.begin() + lastColumn, [](bool b) { return b == true; }); + + if (checked || isAtLeastOneChecked) + { + // If the user checked the "All" option, Step through each column and set to visible. + if (text.compare(STR_DISASSEMBLY_TABLE_COLUMN_ALL) == 0 && (checked == true)) + { + for (int columnIndex = firstColumn; columnIndex < lastColumn; ++columnIndex) + { + columnVisibility[columnIndex] = checked; + } + + // Update the state of the dropdown check boxes to reflect that all options are checked. + ListWidget::SetColumnVisibilityCheckboxes(m_pDisassemblyColumnsListWidget, columnVisibility); + } + + // Save the changes. + configManager.Instance().SetDisassemblyColumnVisibility(columnVisibility); + configManager.SaveGlobalConfigFile(); + } + else + { + // The user tried to uncheck the last check box, but at least one box + // MUST be checked, so find that item in the ListWidget, and set it back to checked. + for (int row = 0; row < m_pDisassemblyColumnsListWidget->count(); row++) + { + QListWidgetItem* pItem = m_pDisassemblyColumnsListWidget->item(row); + QCheckBox* pCheckBox = (QCheckBox*)m_pDisassemblyColumnsListWidget->itemWidget(pItem); + QString checkBoxText = pCheckBox->text(); + if (checkBoxText.compare(text) == 0) + { + QCheckBox* pCheckBox = (QCheckBox*)m_pDisassemblyColumnsListWidget->itemWidget(pItem); + pCheckBox->setChecked(true); + } + } + } + + // See if the "All" box needs checking/unchecking. + ListWidget::UpdateAllCheckbox(m_pDisassemblyColumnsListWidget); + + // Update the "All" checkbox text color to grey or black. + UpdateAllCheckBoxText(); +} + +void rgIsaDisassemblyView::HandleColumnVisibilityFilterStateChanged(bool checked) +{ + // Figure out the sender and process appropriately. + QObject* pSender = QObject::sender(); + assert(pSender != nullptr); + + // Find out which entry caused the signal. + QWidget* pItem = qobject_cast(pSender); + assert(pItem != nullptr); + + QCheckBox* pCheckBox = qobject_cast(pSender); + assert(pCheckBox != nullptr); + + // Process the click. + HandleColumnVisibilityComboBoxItemClicked(pCheckBox->text(), checked); + + // Emit a signal to trigger a refresh of the disassembly table's filter. + emit DisassemblyColumnVisibilityUpdated(); +} + +void rgIsaDisassemblyView::HandleTargetGpuArrowClicked(bool clicked) +{ + // Make the list widget appear and process user selection from the list widget. + bool visible = m_pTargetGpusListWidget->isVisible(); + if (visible == true) + { + m_pTargetGpusListWidget->hide(); + + // Change the up arrow to a down arrow. + ui.targetGpuPushButton->SetDirection(ArrowIconWidget::Direction::DownArrow); + } + else + { + // Compute where to place the combo box relative to where the arrow button is. + QWidget* pWidget = ui.targetGpuPushButton; + m_pTargetGpusListWidget->show(); + m_pTargetGpusListWidget->setFocus(); + m_pTargetGpusListWidget->setCursor(Qt::PointingHandCursor); + QRect rect = pWidget->geometry(); + QPoint pos(0, 0); + pos = pWidget->mapTo(this, pos); + pos.setY(pos.y() + rect.height()); + int height = QtCommon::QtUtil::GetListWidgetHeight(m_pTargetGpusListWidget); + int width = QtCommon::QtUtil::GetListWidgetWidth(m_pTargetGpusListWidget); + m_pTargetGpusListWidget->setGeometry(pos.x(), pos.y(), width + s_CHECK_BOX_WIDTH, height); + + // Change the down arrow to an up arrow. + ui.targetGpuPushButton->SetDirection(ArrowIconWidget::Direction::UpArrow); + } +} + +void rgIsaDisassemblyView::HandleTargetGpuChanged(int currentIndex) +{ + assert(m_pTargetGpusListWidget != nullptr); + if (m_pTargetGpusListWidget != nullptr) + { + auto pTargetGpuItem = m_pTargetGpusListWidget->item(currentIndex); + assert(pTargetGpuItem != nullptr); + if (pTargetGpuItem != nullptr) + { + // Change the target GPU if it differs from the current target GPU. + std::string currentTargetGpu = ui.targetGpuPushButton->text().toStdString(); + std::string newTargetGpu = pTargetGpuItem->text().toStdString(); + if (currentTargetGpu.compare(newTargetGpu) != 0) + { + // Use the dropdown list's selection model to change the currently selected target GPU. + QItemSelectionModel* pSelectionModel = m_pTargetGpusListWidget->selectionModel(); + assert(pSelectionModel != nullptr); + if (pSelectionModel != nullptr) + { + // Select the new target GPU within the dropdown list widget. + QAbstractItemModel* pListModel = m_pTargetGpusListWidget->model(); + + assert(pListModel != nullptr); + if (pListModel != nullptr) + { + QModelIndex modelIndex = pListModel->index(currentIndex, 0); + pSelectionModel->setCurrentIndex(modelIndex, QItemSelectionModel::SelectionFlag::Select); + } + } + + // Change the target GPU to the newly selected item. + SetTargetGpu(newTargetGpu); + + // Strip the GPU name from the architecture if needed. + std::string strippedGpuName; + size_t bracketPos = newTargetGpu.find("("); + if (bracketPos != std::string::npos && newTargetGpu.size() > 2) + { + strippedGpuName = newTargetGpu.substr(0, bracketPos - 1); + } + else + { + strippedGpuName = newTargetGpu; + } + + // Strip gfx notation if needed. + size_t slashPos = strippedGpuName.find("/"); + if (slashPos != std::string::npos) + { + strippedGpuName = strippedGpuName.substr(slashPos + 1); + } + + // Emit a signal with the name of the target GPU to switch to. + emit SelectedTargetGpuChanged(strippedGpuName); + } + } + } + + // Set focus to disassembly view. + setFocus(); +} + +void rgIsaDisassemblyView::ClearListWidget(ListWidget* &pListWidget) +{ + assert(pListWidget != nullptr); + + // Disconnect slot/signal connection for each check box + for (int row = 0; row < pListWidget->count(); row++) + { + QListWidgetItem* pItem = pListWidget->item(row); + QCheckBox* pCheckBox = (QCheckBox*)pListWidget->itemWidget(pItem); + + if (pListWidget->objectName().compare(STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST) == 0) + { + bool isDisconnected = disconnect(pCheckBox, &QCheckBox::clicked, this, &rgIsaDisassemblyView::HandleColumnVisibilityFilterStateChanged); + assert(isDisconnected); + } + else + { + assert(false); + } + } + + // Clear the list widget. This also deletes each item. + pListWidget->clear(); +} + +void rgIsaDisassemblyView::ConnectDisassemblyTabViewSignals(rgIsaDisassemblyTabView* pEntryView) +{ + // Connect the new disassembly GPU tab's source input file highlight line changed signal. + bool isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::InputSourceHighlightedLineChanged, this, &rgIsaDisassemblyView::InputSourceHighlightedLineChanged); + assert(isConnected); + + // Connect the disassembly table's resized event handler. + isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::DisassemblyTableWidthResizeRequested, this, &rgIsaDisassemblyView::DisassemblyTableWidthResizeRequested); + assert(isConnected); + + // Connect the disassembly view's column visibility updated signal. + isConnected = connect(this, &rgIsaDisassemblyView::DisassemblyColumnVisibilityUpdated, pEntryView, &rgIsaDisassemblyTabView::HandleColumnVisibilityFilterStateChanged); + assert(isConnected); + + // Connect the disassembly view's set frame border red signal. + isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FrameFocusInSignal, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); + assert(isConnected); + + // Connect the disassembly view's set frame border black signal. + isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FrameFocusOutSignal, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewLostFocus); + assert(isConnected); + + // Connect the disassembly view's title bar's set frame border red signal. + isConnected = connect(ui.viewTitlebar, &rgIsaDisassemblyViewTitlebar::FrameFocusInSignal, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); + assert(isConnected); + + // Connect the disassembly view's enable scroll bar signal. + isConnected = connect(this, &rgIsaDisassemblyView::EnableScrollbarSignals, pEntryView, &rgIsaDisassemblyTabView::EnableScrollbarSignals); + assert(isConnected); + + // Connect the disassembly view's disable scroll bar signal. + isConnected = connect(this, &rgIsaDisassemblyView::DisableScrollbarSignals, pEntryView, &rgIsaDisassemblyTabView::DisableScrollbarSignals); + assert(isConnected); + + // Connect the disassembly table's target GPU push button focus in signal. + isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FocusTargetGpuPushButton, this, &rgIsaDisassemblyView::HandleFocusTargetGpuPushButton); + assert(isConnected); + + // Connect the disassembly table's switch disassembly view size signal. + isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::SwitchDisassemblyContainerSize, this, &rgIsaDisassemblyView::SwitchDisassemblyContainerSize); + assert(isConnected); + + // Connect the disassembly table's columns push button focus in signal. + isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FocusColumnPushButton, this, &rgIsaDisassemblyView::HandleFocusColumnsPushButton); + assert(isConnected); + + // Connect the disassembly table's cli output window focus in signal. + isConnected = connect(pEntryView, &rgIsaDisassemblyTabView::FocusSourceWindow, this, &rgIsaDisassemblyView::FocusSourceWindow); + assert(isConnected); + + // Connect the disassembly view's update current sub widget signal. + isConnected = connect(this, &rgIsaDisassemblyView::UpdateCurrentSubWidget, pEntryView, &rgIsaDisassemblyTabView::UpdateCurrentSubWidget); + assert(isConnected); +} + +void rgIsaDisassemblyView::ConnectSignals() +{ + // Connect the column visibility selector arrow button. + bool isConnected = connect(ui.columnVisibilityArrowPushButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleColumnVisibilityButtonClicked); + assert(isConnected); + + // Connect the handler to show/hide the target GPU list when the arrow button is clicked. + isConnected = connect(ui.targetGpuPushButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleTargetGpuArrowClicked); + assert(isConnected); + + // Connect the handler to give focus to frame on view maximize button click. + isConnected = connect(ui.viewMaximizeButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); + assert(isConnected); + + // Connect the handler to give focus to frame on disassembly column list widget's gain of focus. + isConnected = connect(m_pDisassemblyColumnsListWidget, &ListWidget::FocusInEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusInEvent); + assert(isConnected); + + // Connect the handler to remove focus from frame on disassembly column list widget's loss of focus. + isConnected = connect(m_pDisassemblyColumnsListWidget, &ListWidget::FocusOutEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusOutEvent); + assert(isConnected); + + // Connect the handler to give focus to frame on target GPUs list widget's gain of focus. + isConnected = connect(m_pTargetGpusListWidget, &ListWidget::FocusInEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusInEvent); + assert(isConnected); + + // Connect the handler to give focus to frame on target GPUs list widget's loss of focus. + isConnected = connect(m_pTargetGpusListWidget, &ListWidget::FocusOutEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusOutEvent); + assert(isConnected); + + // Connect the handler to give focus to frame on columns push button click. + isConnected = connect(ui.columnVisibilityArrowPushButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); + assert(isConnected); + + // Connect the handler to give focus to frame on target GPUs push button click. + isConnected = connect(ui.targetGpuPushButton, &QPushButton::clicked, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); + assert(isConnected); + + // Connect the handler to remove focus from frame on columns push button loss of focus. + isConnected = connect(ui.columnVisibilityArrowPushButton, &ArrowIconWidget::FocusOutEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusOutEvent); + assert(isConnected); + + // Connect the handler to give focus to frame on target GPUs push button loss of focus. + isConnected = connect(ui.targetGpuPushButton, &ArrowIconWidget::FocusOutEvent, this, &rgIsaDisassemblyView::HandleListWidgetFocusOutEvent); + assert(isConnected); + + // Select next GPU device action. + m_pSelectNextGPUTarget = new QAction(this); + m_pSelectNextGPUTarget->setShortcutContext(Qt::ApplicationShortcut); + m_pSelectNextGPUTarget->setShortcut(QKeySequence(gs_DISASSEMBLY_VIEW_HOTKEY_GPU_SELECTION)); + addAction(m_pSelectNextGPUTarget); + + isConnected = connect(m_pSelectNextGPUTarget, &QAction::triggered, this, &rgIsaDisassemblyView::HandleSelectNextGPUTargetAction); + assert(isConnected); +} + +void rgIsaDisassemblyView::CreateColumnVisibilityControls() +{ + // Setup the list widget that opens when the user clicks the column visibility arrow. + rgUtils::SetupComboList(this, m_pDisassemblyColumnsListWidget, ui.columnVisibilityArrowPushButton, m_pDisassemblyColumnsListEventFilter, false); + m_pDisassemblyColumnsListWidget->setObjectName(STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST); + + // Handle the open gpu list widget signal and, + // the update current sub widget signal from the hide list widget event filter object. + if (m_pDisassemblyColumnsListEventFilter != nullptr) + { + rgHideListWidgetEventFilter* pEventFilter = static_cast(m_pDisassemblyColumnsListEventFilter); + if (pEventFilter != nullptr) + { + bool isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::OpenGpuListWidget, this, &rgIsaDisassemblyView::HandleOpenGpuListWidget); + assert(isConnected); + + isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::UpdateCurrentSubWidget, this, &rgIsaDisassemblyView::UpdateCurrentSubWidget); + assert(isConnected); + + isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::FocusCliOutputWindow, this, &rgIsaDisassemblyView::FocusCliOutputWindow); + assert(isConnected); + } + } + + // Update scale factor for widgets. + QFont font = ui.columnVisibilityArrowPushButton->font(); + double scaleFactor = ScalingManager::Get().GetScaleFactor(); + font.setPointSize(s_PUSH_BUTTON_FONT_SIZE * scaleFactor); + m_pDisassemblyColumnsListWidget->setStyleSheet(s_LIST_WIDGET_STYLE.arg(font.pointSize())); + + // Reset the current selection in the column visibility list. + m_pDisassemblyColumnsListWidget->setCurrentRow(0); +} + +void rgIsaDisassemblyView::HandleOpenColumnListWidget() +{ + if (m_pDisassemblyColumnsListWidget != nullptr) + { + ui.columnVisibilityArrowPushButton->clicked(); + } +} + +void rgIsaDisassemblyView::CreateTargetGpuListControls() +{ + // Setup the list widget used to select the current target GPU. + rgUtils::SetupComboList(this, m_pTargetGpusListWidget, ui.targetGpuPushButton, m_pTargetGpusListEventFilter, false); + m_pTargetGpusListWidget->setObjectName(STR_DISASSEMBLY_TARGET_GPU_LIST); + + if (m_pTargetGpusListEventFilter != nullptr) + { + rgHideListWidgetEventFilter* pEventFilter = static_cast(m_pTargetGpusListEventFilter); + if (pEventFilter != nullptr) + { + bool isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::OpenColumnListWidget, this, &rgIsaDisassemblyView::HandleOpenColumnListWidget); + assert(isConnected); + + isConnected = connect(pEventFilter, &rgHideListWidgetEventFilter::UpdateCurrentSubWidget, this, &rgIsaDisassemblyView::UpdateCurrentSubWidget); + assert(isConnected); + } + } + + // Update scale factor for widgets. + QFont font = ui.targetGpuPushButton->font(); + double scaleFactor = ScalingManager::Get().GetScaleFactor(); + font.setPointSize(s_PUSH_BUTTON_FONT_SIZE * scaleFactor); + m_pTargetGpusListWidget->setStyleSheet(s_LIST_WIDGET_STYLE.arg(font.pointSize())); + + // Reset the current selection in the target GPU dropdown list. + m_pTargetGpusListWidget->setCurrentRow(0); + + // Connect the signal used to handle a change in the selected target GPU. + bool isConnected = connect(m_pTargetGpusListWidget, &QListWidget::currentRowChanged, this, &rgIsaDisassemblyView::HandleTargetGpuChanged); + assert(isConnected); +} + +void rgIsaDisassemblyView::HandleOpenGpuListWidget() +{ + if (m_pTargetGpusListWidget != nullptr) + { + ui.targetGpuPushButton->clicked(); + } +} + +std::string rgIsaDisassemblyView::GetDisassemblyColumnName(rgIsaDisassemblyTableColumns column) const +{ + std::string result; + + static std::map kColumnNameMap = + { + { rgIsaDisassemblyTableColumns::Address, STR_DISASSEMBLY_TABLE_COLUMN_ADDRESS }, + { rgIsaDisassemblyTableColumns::Opcode, STR_DISASSEMBLY_TABLE_COLUMN_OPCODE }, + { rgIsaDisassemblyTableColumns::Operands, STR_DISASSEMBLY_TABLE_COLUMN_OPERANDS }, + { rgIsaDisassemblyTableColumns::FunctionalUnit, STR_DISASSEMBLY_TABLE_COLUMN_FUNCTIONAL_UNIT }, + { rgIsaDisassemblyTableColumns::Cycles, STR_DISASSEMBLY_TABLE_COLUMN_CYCLES }, + { rgIsaDisassemblyTableColumns::BinaryEncoding, STR_DISASSEMBLY_TABLE_COLUMN_BINARY_ENCODING }, + }; + + auto columnNameIter = kColumnNameMap.find(column); + if (columnNameIter != kColumnNameMap.end()) + { + result = columnNameIter->second; + } + else + { + // The incoming column doesn't have a name string mapped to it. + assert(false); + } + + return result; +} + +rgIsaDisassemblyTabView* rgIsaDisassemblyView::GetTargetGpuTabWidgetByTabName(const std::string& tabText) const +{ + rgIsaDisassemblyTabView* pResult = nullptr; + + // If a matching view exists return it. + auto gpuTabIter = m_gpuTabViews.find(tabText); + if (gpuTabIter != m_gpuTabViews.end()) + { + pResult = gpuTabIter->second; + } + + return pResult; +} + +void rgIsaDisassemblyView::PopulateTargetGpuList(const rgBuildOutputsMap& buildOutput) +{ + // Get a mapping of the compute capability to architecture. + std::map computeCapabilityToArch; + bool hasArchMapping = rgUtils::GetComputeCapabilityToArchMapping(computeCapabilityToArch); + + // Block signals to stop updates when each new GPU is added to the list. + m_pTargetGpusListWidget->blockSignals(true); + + m_pTargetGpusListWidget->clear(); + + std::vector targets; + + for (auto targetGpuIter = buildOutput.rbegin(); targetGpuIter != buildOutput.rend(); ++targetGpuIter) + { + if (targetGpuIter->second != nullptr) + { + // Add each target GPU from the build outputs to the dropdown list. + auto targetGpu = targetGpuIter->first; + + // Construct the presented name. + std::stringstream presentedName; + + // If applicable, prepend the gfx notation (for example, "gfx802/Tonga" for "Tonga"). + std::string gfxNotation; + bool hasGfxNotation = rgUtils::GetGfxNotation(targetGpu, gfxNotation); + if (hasGfxNotation && !gfxNotation.empty()) + { + presentedName << gfxNotation << "/"; + } + presentedName << targetGpu; + + // If we have a mapping, let's construct a name that includes + // the GPU architecture as well: (). + if (hasArchMapping) + { + auto iter = computeCapabilityToArch.find(targetGpu); + if (iter != computeCapabilityToArch.end()) + { + presentedName << " (" << iter->second << ")"; + } + } + + // Add the name to the list. + targets.push_back(presentedName.str()); + } + } + assert(!targets.empty()); + + // Sort and choose the latest target. std::sort(targets.begin(), - targets.end(), [&](const std::string& a, const std::string& b) - { + targets.end(), [&](const std::string& a, const std::string& b) + { const char* GFX_NOTATION_TOKEN = "gfx"; bool ret = true; size_t szA = a.find(GFX_NOTATION_TOKEN); @@ -733,510 +734,492 @@ void rgIsaDisassemblyView::PopulateTargetGpuList(const rgBuildOutputsMap& buildO ret = ((numB - numA) > 0); } } - return !ret; - }); - - for (const std::string& str : targets) - { - m_pTargetGpusListWidget->addItem(str.c_str()); - } - - // Switch to the first target GPU. - HandleTargetGpuChanged(0); - - // Re-enable signals emitted from the target GPU list. - m_pTargetGpusListWidget->blockSignals(false); -} - -bool rgIsaDisassemblyView::PopulateDisassemblyEntries(const GpuToEntryVector& gpuToDisassemblyCsvEntries) -{ - bool ret = true; - - if (!gpuToDisassemblyCsvEntries.empty()) - { - // Step through each GPU and insert a new rgIsaDisassemblyTabView into a new tab. - for (auto gpuEntryIter = gpuToDisassemblyCsvEntries.begin(); gpuEntryIter != gpuToDisassemblyCsvEntries.end(); ++gpuEntryIter) - { - const std::string& gpuName = gpuEntryIter->first; - const std::vector& gpuEntries = gpuEntryIter->second; - - // Does a tab already exist for the target GPU we're loading results for? - rgIsaDisassemblyTabView* pEntryView = GetTargetGpuTabWidgetByTabName(gpuName); - - // Create a new tab for the target GPU, and add a new disassembly table viewer. - if (pEntryView == nullptr) - { - // Create a new entry view for each unique GPU. - pEntryView = new rgIsaDisassemblyTabView(); - - // Connect signals for the new tab. - ConnectDisassemblyTabViewSignals(pEntryView); - - // Add the new entry view to the map. - m_gpuTabViews[gpuName] = pEntryView; - - // Add the new disassembly table as a tab page in the array of GPU results. - ui.disassemblyTableHostWidget->addWidget(pEntryView); - } - - // Send the CSV file paths to the GPU-specific entry viewer. - bool isTablePopulated = pEntryView->PopulateEntries(gpuEntries); - - // Verify that the table was populated correctly. - assert(isTablePopulated); - if (!isTablePopulated) - { - ret = false; - } - } - } - - return ret; -} - -bool rgIsaDisassemblyView::PopulateResourceUsageEntries(const GpuToEntryVector& gpuToResourceUsageCsvEntries) -{ - bool isLoadFailed = false; - - if (!gpuToResourceUsageCsvEntries.empty()) - { - // Step through each GPU and insert a new rgResourceView underneath the disassembly table. - for (auto gpuEntryIter = gpuToResourceUsageCsvEntries.begin(); gpuEntryIter != gpuToResourceUsageCsvEntries.end(); ++gpuEntryIter) - { - const std::string& gpuName = gpuEntryIter->first; - const std::vector& gpuEntries = gpuEntryIter->second; - - // Create a resource usage disassembly table for each entry, and add it to the layout. - // Only a single entry point table will be visible at a time, and the user can switch between the current entry. - for (const rgEntryOutput& entry : gpuEntries) - { - OutputFileTypeFinder outputFileTypeSearcher(rgCliOutputFileType::HwResourceUsageFile); - auto csvFileIter = std::find_if(entry.m_outputs.begin(), entry.m_outputs.end(), outputFileTypeSearcher); - if (csvFileIter != entry.m_outputs.end()) - { - // Create a CSV parser to read the resource usage file. - rgResourceUsageCsvFileParser resourceUsageFileParser(csvFileIter->m_filePath); - - // Attempt to parse the file. - std::string parseErrorString; - bool parsedSuccessfully = resourceUsageFileParser.Parse(parseErrorString); - if (parsedSuccessfully) - { - // Extract the parsed data, and populate the resource usage view. - const rgResourceUsageData& resourceUsageData = resourceUsageFileParser.GetData(); - rgResourceUsageView* pResourceUsageView = new rgResourceUsageView(); - pResourceUsageView->PopulateView(resourceUsageData); - m_resourceUsageText = pResourceUsageView->GetResourceUsageText(); - m_resourceUsageFont = pResourceUsageView->GetResourceUsageFont(); - - // Register the resource usage view with the scaling manager. - ScalingManager::Get().RegisterObject(pResourceUsageView); - - // Connect resource usage view signals. - ConnectResourceUsageViewSignals(pResourceUsageView); - - // Add the new resource usage view to the host widget. - ui.resourceUsageHostStackedWidget->addWidget(pResourceUsageView); - ui.resourceUsageHostStackedWidget->setContentsMargins(0, 10, 0, 0); - - // Get a reference to the entry point views associated with the parsed device. - InputToEntrypointViews& inputFileToEntrypointMap = m_gpuResourceUsageViews[gpuName]; - - // Get a reference to the resource views map for the source file. - EntrypointToResourcesView& entrypointMap = inputFileToEntrypointMap[entry.m_inputFilePath]; - - // Associate the entrypoint's name with the new rgResourceView. - entrypointMap[entry.m_entrypointName] = pResourceUsageView; - } - else - { - isLoadFailed = true; - } - } - } - } - } - - return !isLoadFailed; -} - -void rgIsaDisassemblyView::ConnectResourceUsageViewSignals(rgResourceUsageView * pResourceUsageView) -{ - // Connect to the resource usage view's mouse press event. - bool isConnected = connect(pResourceUsageView, &rgResourceUsageView::ResourceUsageViewClickedSignal, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); - assert(isConnected); - - // Connect to the resource usage view's focus out event. - isConnected = connect(pResourceUsageView, &rgResourceUsageView::ResourceUsageViewFocusOutEventSignal, this, &rgIsaDisassemblyView::HandleResourceUsageViewFocusOutEvent); - assert(isConnected); -} - -void rgIsaDisassemblyView::PopulateColumnVisibilityList() -{ - // Set up the function pointer responsible for handling column visibility filter state change. - using std::placeholders::_1; - std::function slotFunctionPointer = std::bind(&rgIsaDisassemblyView::HandleColumnVisibilityFilterStateChanged, this, _1); - - // Remove the existing items first - ClearListWidget(m_pDisassemblyColumnsListWidget); - - // Add the "All" entry - ListWidget::AddListWidgetCheckboxItem(STR_DISASSEMBLY_TABLE_COLUMN_ALL, m_pDisassemblyColumnsListWidget, slotFunctionPointer, this, STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST, STR_DISASSEMBLY_COLUMN_LIST_ITEM_ALL_CHECKBOX); - - // Loop through each column enum member. - int startColumn = rgIsaDisassemblyTableModel::GetTableColumnIndex(rgIsaDisassemblyTableColumns::Address); - int endColumn = rgIsaDisassemblyTableModel::GetTableColumnIndex(rgIsaDisassemblyTableColumns::Count); - - // Add an item for each column in the table. - for (int columnIndex = startColumn; columnIndex < endColumn; ++columnIndex) - { - // Add an item for each possible column in the table. - std::string columnName = GetDisassemblyColumnName(static_cast(columnIndex)); - ListWidget::AddListWidgetCheckboxItem(columnName.c_str(), m_pDisassemblyColumnsListWidget, slotFunctionPointer, this, STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST, STR_DISASSEMBLY_COLUMN_LIST_ITEM_CHECKBOX); - } - - // Populate the check box items by reading the global settings. - rgConfigManager& configManager = rgConfigManager::Instance(); - std::shared_ptr pGlobalSettings = configManager.GetGlobalConfig(); - ListWidget::SetColumnVisibilityCheckboxes(m_pDisassemblyColumnsListWidget, pGlobalSettings->m_visibleDisassemblyViewColumns); - - // Update the "All" checkbox text color to grey or black. - UpdateAllCheckBoxText(); - - // Set list widget's check box's focus proxy to be the frame. - SetCheckBoxFocusProxies(m_pDisassemblyColumnsListWidget); -} - -void rgIsaDisassemblyView::SetCheckBoxFocusProxies(const ListWidget* pListWidget) const -{ - for (int i = 0; i < pListWidget->count(); i++) - { - QListWidgetItem* pItem = pListWidget->item(i); - assert(pItem != nullptr); - - QCheckBox* pCheckBox = qobject_cast(pListWidget->itemWidget(pItem)); - assert(pCheckBox != nullptr); - - pCheckBox->setFocusProxy(ui.frame); - } -} - -void rgIsaDisassemblyView::UpdateAllCheckBoxText() -{ - bool areAllItemsChecked = true; - - // Check to see if all of the boxes are checked. - for (int i = 1; i < m_pDisassemblyColumnsListWidget->count(); i++) - { - QListWidgetItem* pItem = m_pDisassemblyColumnsListWidget->item(i); - assert(pItem != nullptr); - - QCheckBox* pCheckBox = qobject_cast(m_pDisassemblyColumnsListWidget->itemWidget(pItem)); - assert(pCheckBox != nullptr); - - if (pCheckBox->checkState() == Qt::CheckState::Unchecked) - { - areAllItemsChecked = false; - break; - } - } - - // If all boxes are checked, update the text color of the All check box. - QListWidgetItem* pItem = m_pDisassemblyColumnsListWidget->item(0); - if (pItem != nullptr) - { - QCheckBox* pCheckBox = qobject_cast(m_pDisassemblyColumnsListWidget->itemWidget(pItem)); - if (pCheckBox != nullptr) - { - if (areAllItemsChecked) - { - pCheckBox->setStyleSheet("QCheckBox#ListWidgetAllCheckBox {color: grey;}"); - } - else - { - pCheckBox->setStyleSheet("QCheckBox#ListWidgetAllCheckBox {color: black;}"); - } - } - } -} - -void rgIsaDisassemblyView::DestroyDisassemblyViewsForFile(const std::string& inputFilePath) -{ - // Keep a list of tabs that should be destroyed after removing the input file. - std::vector gpuTabsToRemove; - - // Step through each GPU tab and try to remove the entries associated with the given input file. - auto startTab = m_gpuTabViews.begin(); - auto endTab = m_gpuTabViews.end(); - for (auto tabIter = startTab; tabIter != endTab; ++tabIter) - { - // Search the tab for entries to remove. - rgIsaDisassemblyTabView* pGpuTab = tabIter->second; - assert(pGpuTab != nullptr); - if (pGpuTab != nullptr) - { - // Attempt to remove entries associated with the input file from each GPU tab. - pGpuTab->RemoveInputFileEntries(inputFilePath); - - // Does the GPU tab have any tables left in it? If not, destroy the tab too. - int numTablesInTab = pGpuTab->GetTableCount(); - if (numTablesInTab == 0) - { - const std::string& gpuName = tabIter->first; - gpuTabsToRemove.push_back(gpuName); - } - } - } - - // Destroy all tabs that were marked for destruction. - for (auto pGpuTab : gpuTabsToRemove) - { - auto tabIter = m_gpuTabViews.find(pGpuTab); - if (tabIter != m_gpuTabViews.end()) - { - // Destroy the GPU tab. - rgIsaDisassemblyTabView* pGpuTabView = tabIter->second; - - // Remove the GPU tab from the view. - ui.disassemblyTableHostWidget->removeWidget(pGpuTabView); - - // Remove the GPU from the view. - m_gpuTabViews.erase(tabIter); - } - } -} - -void rgIsaDisassemblyView::DestroyResourceUsageViewsForFile(const std::string& inputFilePath) -{ - // Destroy resource views for all GPUs. - for (auto gpuIter = m_gpuResourceUsageViews.begin(); gpuIter != m_gpuResourceUsageViews.end(); ++gpuIter) - { - // Find all resource views related to the given input file. - InputToEntrypointViews& inputFileToViewsIter = gpuIter->second; - auto entrypointResourceUsageviewsIter = inputFileToViewsIter.find(inputFilePath); - if (entrypointResourceUsageviewsIter != inputFileToViewsIter.end()) - { - // Step through each entrypoint's resource usage view, and destroy it. - EntrypointToResourcesView& entrypointResourceViews = entrypointResourceUsageviewsIter->second; - for (auto entrypointIter = entrypointResourceViews.begin(); entrypointIter != entrypointResourceViews.end(); ++entrypointIter) - { - // Destroy the resource usage view. - rgResourceUsageView* pResourceUsageView = entrypointIter->second; - - // Remove the resource usage widget from the view. - ui.resourceUsageHostStackedWidget->removeWidget(pResourceUsageView); - } - - inputFileToViewsIter.erase(entrypointResourceUsageviewsIter); - } - } -} - -void rgIsaDisassemblyView::SetCurrentResourceUsageView(rgResourceUsageView* pResourceUsageView) -{ - // Set the current widget in the stack. - ui.resourceUsageHostStackedWidget->setCurrentWidget(pResourceUsageView); - - // Use the given resource usage view as the focus proxy for this view. - setFocusProxy(pResourceUsageView); -} - -void rgIsaDisassemblyView::SetCurrentTargetGpuTabView(rgIsaDisassemblyTabView* pTabView) -{ - // Set the current widget in the stack. - ui.disassemblyTableHostWidget->setCurrentWidget(pTabView); - - // Store the current target GPU tab being viewed. - m_pCurrentTabView = pTabView; - - // Use the current tab view as the focus proxy for this view. - setFocusProxy(pTabView); -} - -void rgIsaDisassemblyView::SetCursor() -{ - ui.columnVisibilityArrowPushButton->setCursor(Qt::PointingHandCursor); - ui.targetGpuPushButton->setCursor(Qt::PointingHandCursor); - ui.viewMaximizeButton->setCursor(Qt::PointingHandCursor); -} - -void rgIsaDisassemblyView::SetTargetGpu(const std::string& targetGpu) -{ - static const int g_ARROW_WIDGET_EXTRA_WIDTH = 30; - - // Update the button text. - ui.targetGpuPushButton->setText(targetGpu.c_str()); - - // Measure the width of the Target GPU text, and add extra space to account for the width of the arrow. - int scaledArrowWidth = static_cast(g_ARROW_WIDGET_EXTRA_WIDTH * ScalingManager::Get().GetScaleFactor()); - int textWidth = QtCommon::QtUtil::GetTextWidth(ui.targetGpuPushButton->font(), targetGpu.c_str()); - ui.targetGpuPushButton->setMinimumWidth(scaledArrowWidth + textWidth); -} - -void rgIsaDisassemblyView::SetFontSizes() -{ - // Set column visibility push button font. - ArrowIconWidget* pArrowWidget = dynamic_cast(ui.columnVisibilityArrowPushButton); - if (pArrowWidget != nullptr) - { - pArrowWidget->SetFontSize(s_PUSH_BUTTON_FONT_SIZE); - } - - // Set ISA list push button font. - pArrowWidget = dynamic_cast(ui.targetGpuPushButton); - if (pArrowWidget != nullptr) - { - pArrowWidget->SetFontSize(s_PUSH_BUTTON_FONT_SIZE); - } -} - -bool rgIsaDisassemblyView::IsLineCorrelatedInEntry(const std::string& inputFilePath, const std::string& targetGpu, const std::string& entrypoint, int srcLine) const -{ - bool ret = false; - - rgIsaDisassemblyTabView* pTargetGpuTab = GetTargetGpuTabWidgetByTabName(targetGpu.c_str()); - - assert(pTargetGpuTab != nullptr); - if (pTargetGpuTab != nullptr) - { - ret = pTargetGpuTab->IsSourceLineCorrelatedForEntry(inputFilePath, entrypoint, srcLine); - } - - return ret; -} - -void rgIsaDisassemblyView::HandleDisassemblyTabViewClicked() -{ - // Emit a signal to indicate that disassembly view was clicked. - emit DisassemblyViewClicked(); - - // Highlight the frame in the correct API color (give it focus). - SetBorderStylesheet(); - - // Remove the button focus in the file menu. - emit RemoveFileMenuButtonFocus(); -} - -void rgIsaDisassemblyView::HandleDisassemblyTabViewLostFocus() -{ - // Highlight the frame in black. - ui.frame->setStyleSheet(STR_DISASSEMBLY_FRAME_BORDER_BLACK_STYLESHEET); - - // Remove the button focus in the file menu. - emit RemoveFileMenuButtonFocus(); -} - -void rgIsaDisassemblyView::HandleResourceUsageViewFocusOutEvent() -{ - // Highlight the frame in black. - ui.frame->setStyleSheet(STR_DISASSEMBLY_FRAME_BORDER_BLACK_STYLESHEET); - - // Remove the button focus in the file menu. - emit RemoveFileMenuButtonFocus(); -} - -void rgIsaDisassemblyView::HandleTitlebarClickedEvent(QMouseEvent* pEvent) -{ - // Emit a signal to indicate that disassembly view was clicked. - emit DisassemblyViewClicked(); - - // Highlight the frame in the correct API color (give it focus). - SetBorderStylesheet(); - - // Remove the button focus in the file menu. - emit RemoveFileMenuButtonFocus(); -} - -void rgIsaDisassemblyView::HandleListWidgetFocusInEvent() -{ - // Emit a signal to indicate that disassembly view was clicked. - emit DisassemblyViewClicked(); - - // Highlight the frame in the correct API color (give it focus). - SetBorderStylesheet(); - - // Remove the button focus in the file menu. - emit RemoveFileMenuButtonFocus(); -} - -void rgIsaDisassemblyView::HandleListWidgetFocusOutEvent() -{ - ui.frame->setStyleSheet(STR_DISASSEMBLY_FRAME_BORDER_BLACK_STYLESHEET); -} - -void rgIsaDisassemblyView::HandleFocusOutEvent() -{ - ui.frame->setStyleSheet(STR_DISASSEMBLY_FRAME_BORDER_BLACK_STYLESHEET); - - // Remove the button focus in the file menu. - emit RemoveFileMenuButtonFocus(); -} - -void rgIsaDisassemblyView::HandleFocusTargetGpuPushButton() -{ - ui.targetGpuPushButton->clicked(false); -} - -void rgIsaDisassemblyView::HandleFocusColumnsPushButton() -{ - ui.columnVisibilityArrowPushButton->clicked(false); -} - -void rgIsaDisassemblyView::ConnectTitleBarDoubleClick(const rgViewContainer* pDisassemblyViewContainer) -{ - assert(pDisassemblyViewContainer != nullptr); - if (pDisassemblyViewContainer != nullptr) - { - bool isConnected = connect(ui.viewTitlebar, &rgIsaDisassemblyViewTitlebar::ViewTitleBarDoubleClickedSignal, pDisassemblyViewContainer, &rgViewContainer::MaximizeButtonClicked); - assert(isConnected); - } -} - -bool rgIsaDisassemblyView::ReplaceInputFilePath(const std::string& oldFilePath, const std::string& newFilePath) -{ - bool result = true; - - // Replace the file path in all disassembly tab views for all devices. - for (auto& gpuAndTabView : m_gpuTabViews) - { - rgIsaDisassemblyTabView* pTabView = gpuAndTabView.second; - if (!pTabView->ReplaceInputFilePath(oldFilePath, newFilePath)) - { - result = false; - break; - } - } - - // Replace the file path in the resource usage map. - if (result) - { - for (auto& gpuAndResourceUsage : m_gpuResourceUsageViews) - { - auto& fileAndResourceUsage = gpuAndResourceUsage.second; - auto it = fileAndResourceUsage.find(oldFilePath); - if ((result = (it != fileAndResourceUsage.end())) == true) - { - std::map resUsageView = it->second; - fileAndResourceUsage.erase(oldFilePath); - fileAndResourceUsage[newFilePath] = resUsageView; - } - } - } - - return result; -} - -void rgIsaDisassemblyView::HandleSelectNextGPUTargetAction() -{ - int currentRow = m_pTargetGpusListWidget->currentRow(); - - if (currentRow < m_pTargetGpusListWidget->count() - 1) - { - currentRow++; - } - else - { - currentRow = 0; - } - m_pTargetGpusListWidget->setCurrentRow(currentRow); + return !ret; + }); + + for (const std::string& str : targets) + { + m_pTargetGpusListWidget->addItem(str.c_str()); + } + + // Switch to the first target GPU. + HandleTargetGpuChanged(0); + + // Re-enable signals emitted from the target GPU list. + m_pTargetGpusListWidget->blockSignals(false); +} + +bool rgIsaDisassemblyView::PopulateDisassemblyEntries(const GpuToEntryVector& gpuToDisassemblyCsvEntries) +{ + bool ret = true; + + if (!gpuToDisassemblyCsvEntries.empty()) + { + // Step through each GPU and insert a new rgIsaDisassemblyTabView into a new tab. + for (auto gpuEntryIter = gpuToDisassemblyCsvEntries.begin(); gpuEntryIter != gpuToDisassemblyCsvEntries.end(); ++gpuEntryIter) + { + const std::string& gpuName = gpuEntryIter->first; + const std::vector& gpuEntries = gpuEntryIter->second; + + // Does a tab already exist for the target GPU we're loading results for? + rgIsaDisassemblyTabView* pEntryView = GetTargetGpuTabWidgetByTabName(gpuName); + + // Create a new tab for the target GPU, and add a new disassembly table viewer. + if (pEntryView == nullptr) + { + // Create a new entry view for each unique GPU. + pEntryView = new rgIsaDisassemblyTabView(); + + // Connect signals for the new tab. + ConnectDisassemblyTabViewSignals(pEntryView); + + // Add the new entry view to the map. + m_gpuTabViews[gpuName] = pEntryView; + + // Add the new disassembly table as a tab page in the array of GPU results. + ui.disassemblyTableHostWidget->addWidget(pEntryView); + } + + // Send the CSV file paths to the GPU-specific entry viewer. + bool isTablePopulated = pEntryView->PopulateEntries(gpuEntries); + + // Verify that the table was populated correctly. + assert(isTablePopulated); + if (!isTablePopulated) + { + ret = false; + } + } + } + + return ret; +} + +bool rgIsaDisassemblyView::PopulateResourceUsageEntries(const GpuToEntryVector& gpuToResourceUsageCsvEntries) +{ + bool isLoadFailed = false; + + if (!gpuToResourceUsageCsvEntries.empty()) + { + // Step through each GPU and insert a new rgResourceView underneath the disassembly table. + for (auto gpuEntryIter = gpuToResourceUsageCsvEntries.begin(); gpuEntryIter != gpuToResourceUsageCsvEntries.end(); ++gpuEntryIter) + { + const std::string& gpuName = gpuEntryIter->first; + const std::vector& gpuEntries = gpuEntryIter->second; + + // Create a resource usage disassembly table for each entry, and add it to the layout. + // Only a single entry point table will be visible at a time, and the user can switch between the current entry. + for (const rgEntryOutput& entry : gpuEntries) + { + OutputFileTypeFinder outputFileTypeSearcher(rgCliOutputFileType::HwResourceUsageFile); + auto csvFileIter = std::find_if(entry.m_outputs.begin(), entry.m_outputs.end(), outputFileTypeSearcher); + if (csvFileIter != entry.m_outputs.end()) + { + // Create a CSV parser to read the resource usage file. + rgResourceUsageCsvFileParser resourceUsageFileParser(csvFileIter->m_filePath); + + // Attempt to parse the file. + std::string parseErrorString; + bool parsedSuccessfully = resourceUsageFileParser.Parse(parseErrorString); + if (parsedSuccessfully) + { + // Extract the parsed data, and populate the resource usage view. + const rgResourceUsageData& resourceUsageData = resourceUsageFileParser.GetData(); + rgResourceUsageView* pResourceUsageView = new rgResourceUsageView(); + pResourceUsageView->PopulateView(resourceUsageData); + m_resourceUsageText = pResourceUsageView->GetResourceUsageText(); + m_resourceUsageFont = pResourceUsageView->GetResourceUsageFont(); + + // Register the resource usage view with the scaling manager. + ScalingManager::Get().RegisterObject(pResourceUsageView); + + // Connect resource usage view signals. + ConnectResourceUsageViewSignals(pResourceUsageView); + + // Add the new resource usage view to the host widget. + ui.resourceUsageHostStackedWidget->addWidget(pResourceUsageView); + ui.resourceUsageHostStackedWidget->setContentsMargins(0, 10, 0, 0); + + // Get a reference to the entry point views associated with the parsed device. + InputToEntrypointViews& inputFileToEntrypointMap = m_gpuResourceUsageViews[gpuName]; + + // Get a reference to the resource views map for the source file. + EntrypointToResourcesView& entrypointMap = inputFileToEntrypointMap[entry.m_inputFilePath]; + + // Associate the entrypoint's name with the new rgResourceView. + entrypointMap[entry.m_entrypointName] = pResourceUsageView; + } + else + { + isLoadFailed = true; + } + } + } + } + } + + return !isLoadFailed; +} + +void rgIsaDisassemblyView::ConnectResourceUsageViewSignals(rgResourceUsageView * pResourceUsageView) +{ + // Connect to the resource usage view's mouse press event. + bool isConnected = connect(pResourceUsageView, &rgResourceUsageView::ResourceUsageViewClickedSignal, this, &rgIsaDisassemblyView::HandleDisassemblyTabViewClicked); + assert(isConnected); + + // Connect to the resource usage view's focus out event. + isConnected = connect(pResourceUsageView, &rgResourceUsageView::ResourceUsageViewFocusOutEventSignal, this, &rgIsaDisassemblyView::HandleResourceUsageViewFocusOutEvent); + assert(isConnected); +} + +void rgIsaDisassemblyView::PopulateColumnVisibilityList() +{ + // Set up the function pointer responsible for handling column visibility filter state change. + using std::placeholders::_1; + std::function slotFunctionPointer = std::bind(&rgIsaDisassemblyView::HandleColumnVisibilityFilterStateChanged, this, _1); + + // Remove the existing items first + ClearListWidget(m_pDisassemblyColumnsListWidget); + + // Add the "All" entry + ListWidget::AddListWidgetCheckboxItem(STR_DISASSEMBLY_TABLE_COLUMN_ALL, m_pDisassemblyColumnsListWidget, slotFunctionPointer, this, STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST, STR_DISASSEMBLY_COLUMN_LIST_ITEM_ALL_CHECKBOX); + + // Loop through each column enum member. + int startColumn = rgIsaDisassemblyTableModel::GetTableColumnIndex(rgIsaDisassemblyTableColumns::Address); + int endColumn = rgIsaDisassemblyTableModel::GetTableColumnIndex(rgIsaDisassemblyTableColumns::Count); + + // Add an item for each column in the table. + for (int columnIndex = startColumn; columnIndex < endColumn; ++columnIndex) + { + // Add an item for each possible column in the table. + std::string columnName = GetDisassemblyColumnName(static_cast(columnIndex)); + ListWidget::AddListWidgetCheckboxItem(columnName.c_str(), m_pDisassemblyColumnsListWidget, slotFunctionPointer, this, STR_DISASSEMBLY_COLUMN_VISIBILITY_LIST, STR_DISASSEMBLY_COLUMN_LIST_ITEM_CHECKBOX); + } + + // Populate the check box items by reading the global settings. + rgConfigManager& configManager = rgConfigManager::Instance(); + std::shared_ptr pGlobalSettings = configManager.GetGlobalConfig(); + ListWidget::SetColumnVisibilityCheckboxes(m_pDisassemblyColumnsListWidget, pGlobalSettings->m_visibleDisassemblyViewColumns); + + // Update the "All" checkbox text color to grey or black. + UpdateAllCheckBoxText(); + + // Set list widget's check box's focus proxy to be the frame. + SetCheckBoxFocusProxies(m_pDisassemblyColumnsListWidget); +} + +void rgIsaDisassemblyView::SetCheckBoxFocusProxies(const ListWidget* pListWidget) const +{ + for (int i = 0; i < pListWidget->count(); i++) + { + QListWidgetItem* pItem = pListWidget->item(i); + assert(pItem != nullptr); + + QCheckBox* pCheckBox = qobject_cast(pListWidget->itemWidget(pItem)); + assert(pCheckBox != nullptr); + + pCheckBox->setFocusProxy(ui.frame); + } +} + +void rgIsaDisassemblyView::UpdateAllCheckBoxText() +{ + bool areAllItemsChecked = true; + + // Check to see if all of the boxes are checked. + for (int i = 1; i < m_pDisassemblyColumnsListWidget->count(); i++) + { + QListWidgetItem* pItem = m_pDisassemblyColumnsListWidget->item(i); + assert(pItem != nullptr); + + QCheckBox* pCheckBox = qobject_cast(m_pDisassemblyColumnsListWidget->itemWidget(pItem)); + assert(pCheckBox != nullptr); + + if (pCheckBox->checkState() == Qt::CheckState::Unchecked) + { + areAllItemsChecked = false; + break; + } + } + + // If all boxes are checked, update the text color of the All check box. + QListWidgetItem* pItem = m_pDisassemblyColumnsListWidget->item(0); + if (pItem != nullptr) + { + QCheckBox* pCheckBox = qobject_cast(m_pDisassemblyColumnsListWidget->itemWidget(pItem)); + if (pCheckBox != nullptr) + { + if (areAllItemsChecked) + { + pCheckBox->setStyleSheet("QCheckBox#ListWidgetAllCheckBox {color: grey;}"); + } + else + { + pCheckBox->setStyleSheet("QCheckBox#ListWidgetAllCheckBox {color: black;}"); + } + } + } +} + +void rgIsaDisassemblyView::DestroyDisassemblyViewsForFile(const std::string& inputFilePath) +{ + // Keep a list of tabs that should be destroyed after removing the input file. + std::vector gpuTabsToRemove; + + // Step through each GPU tab and try to remove the entries associated with the given input file. + auto startTab = m_gpuTabViews.begin(); + auto endTab = m_gpuTabViews.end(); + for (auto tabIter = startTab; tabIter != endTab; ++tabIter) + { + // Search the tab for entries to remove. + rgIsaDisassemblyTabView* pGpuTab = tabIter->second; + assert(pGpuTab != nullptr); + if (pGpuTab != nullptr) + { + // Attempt to remove entries associated with the input file from each GPU tab. + pGpuTab->RemoveInputFileEntries(inputFilePath); + + // Does the GPU tab have any tables left in it? If not, destroy the tab too. + int numTablesInTab = pGpuTab->GetTableCount(); + if (numTablesInTab == 0) + { + const std::string& gpuName = tabIter->first; + gpuTabsToRemove.push_back(gpuName); + } + } + } + + // Destroy all tabs that were marked for destruction. + for (auto pGpuTab : gpuTabsToRemove) + { + auto tabIter = m_gpuTabViews.find(pGpuTab); + if (tabIter != m_gpuTabViews.end()) + { + // Destroy the GPU tab. + rgIsaDisassemblyTabView* pGpuTabView = tabIter->second; + + // Remove the GPU tab from the view. + ui.disassemblyTableHostWidget->removeWidget(pGpuTabView); + + // Remove the GPU from the view. + m_gpuTabViews.erase(tabIter); + } + } +} + +void rgIsaDisassemblyView::DestroyResourceUsageViewsForFile(const std::string& inputFilePath) +{ + // Destroy resource views for all GPUs. + for (auto gpuIter = m_gpuResourceUsageViews.begin(); gpuIter != m_gpuResourceUsageViews.end(); ++gpuIter) + { + // Find all resource views related to the given input file. + InputToEntrypointViews& inputFileToViewsIter = gpuIter->second; + auto entrypointResourceUsageviewsIter = inputFileToViewsIter.find(inputFilePath); + if (entrypointResourceUsageviewsIter != inputFileToViewsIter.end()) + { + // Step through each entrypoint's resource usage view, and destroy it. + EntrypointToResourcesView& entrypointResourceViews = entrypointResourceUsageviewsIter->second; + for (auto entrypointIter = entrypointResourceViews.begin(); entrypointIter != entrypointResourceViews.end(); ++entrypointIter) + { + // Destroy the resource usage view. + rgResourceUsageView* pResourceUsageView = entrypointIter->second; + + // Remove the resource usage widget from the view. + ui.resourceUsageHostStackedWidget->removeWidget(pResourceUsageView); + } + + inputFileToViewsIter.erase(entrypointResourceUsageviewsIter); + } + } +} + +void rgIsaDisassemblyView::SetCurrentResourceUsageView(rgResourceUsageView* pResourceUsageView) +{ + // Set the current widget in the stack. + ui.resourceUsageHostStackedWidget->setCurrentWidget(pResourceUsageView); + + // Use the given resource usage view as the focus proxy for this view. + setFocusProxy(pResourceUsageView); +} + +void rgIsaDisassemblyView::SetCurrentTargetGpuTabView(rgIsaDisassemblyTabView* pTabView) +{ + // Set the current widget in the stack. + ui.disassemblyTableHostWidget->setCurrentWidget(pTabView); + + // Store the current target GPU tab being viewed. + m_pCurrentTabView = pTabView; + + // Use the current tab view as the focus proxy for this view. + setFocusProxy(pTabView); +} + +void rgIsaDisassemblyView::SetCursor() +{ + ui.columnVisibilityArrowPushButton->setCursor(Qt::PointingHandCursor); + ui.targetGpuPushButton->setCursor(Qt::PointingHandCursor); + ui.viewMaximizeButton->setCursor(Qt::PointingHandCursor); +} + +void rgIsaDisassemblyView::SetTargetGpu(const std::string& targetGpu) +{ + static const int g_ARROW_WIDGET_EXTRA_WIDTH = 30; + + // Update the button text. + ui.targetGpuPushButton->setText(targetGpu.c_str()); + + // Measure the width of the Target GPU text, and add extra space to account for the width of the arrow. + int scaledArrowWidth = static_cast(g_ARROW_WIDGET_EXTRA_WIDTH * ScalingManager::Get().GetScaleFactor()); + int textWidth = QtCommon::QtUtil::GetTextWidth(ui.targetGpuPushButton->font(), targetGpu.c_str()); + ui.targetGpuPushButton->setMinimumWidth(scaledArrowWidth + textWidth); +} + +void rgIsaDisassemblyView::SetFontSizes() +{ + // Set column visibility push button font. + ArrowIconWidget* pArrowWidget = dynamic_cast(ui.columnVisibilityArrowPushButton); + if (pArrowWidget != nullptr) + { + pArrowWidget->SetFontSize(s_PUSH_BUTTON_FONT_SIZE); + } + + // Set ISA list push button font. + pArrowWidget = dynamic_cast(ui.targetGpuPushButton); + if (pArrowWidget != nullptr) + { + pArrowWidget->SetFontSize(s_PUSH_BUTTON_FONT_SIZE); + } +} + +bool rgIsaDisassemblyView::IsLineCorrelatedInEntry(const std::string& inputFilePath, const std::string& targetGpu, const std::string& entrypoint, int srcLine) const +{ + bool ret = false; + + rgIsaDisassemblyTabView* pTargetGpuTab = GetTargetGpuTabWidgetByTabName(targetGpu.c_str()); + + assert(pTargetGpuTab != nullptr); + if (pTargetGpuTab != nullptr) + { + ret = pTargetGpuTab->IsSourceLineCorrelatedForEntry(inputFilePath, entrypoint, srcLine); + } + + return ret; +} + +void rgIsaDisassemblyView::HandleDisassemblyTabViewClicked() +{ + // Emit a signal to indicate that disassembly view was clicked. + emit DisassemblyViewClicked(); + + // Remove the button focus in the file menu. + emit RemoveFileMenuButtonFocus(); +} + +void rgIsaDisassemblyView::HandleDisassemblyTabViewLostFocus() +{ + // Remove the button focus in the file menu. + emit RemoveFileMenuButtonFocus(); +} + +void rgIsaDisassemblyView::HandleResourceUsageViewFocusOutEvent() +{ + // Remove the button focus in the file menu. + emit RemoveFileMenuButtonFocus(); +} + +void rgIsaDisassemblyView::HandleTitlebarClickedEvent(QMouseEvent* pEvent) +{ + // Emit a signal to indicate that disassembly view was clicked. + emit DisassemblyViewClicked(); + + // Remove the button focus in the file menu. + emit RemoveFileMenuButtonFocus(); +} + +void rgIsaDisassemblyView::HandleListWidgetFocusInEvent() +{ + // Emit a signal to indicate that disassembly view was clicked. + emit DisassemblyViewClicked(); + + // Remove the button focus in the file menu. + emit RemoveFileMenuButtonFocus(); +} + +void rgIsaDisassemblyView::HandleListWidgetFocusOutEvent() +{ +} + +void rgIsaDisassemblyView::HandleFocusOutEvent() +{ + // Remove the button focus in the file menu. + emit RemoveFileMenuButtonFocus(); +} + +void rgIsaDisassemblyView::HandleFocusTargetGpuPushButton() +{ + ui.targetGpuPushButton->clicked(false); +} + +void rgIsaDisassemblyView::HandleFocusColumnsPushButton() +{ + ui.columnVisibilityArrowPushButton->clicked(false); +} + +void rgIsaDisassemblyView::ConnectTitleBarDoubleClick(const rgViewContainer* pDisassemblyViewContainer) +{ + assert(pDisassemblyViewContainer != nullptr); + if (pDisassemblyViewContainer != nullptr) + { + bool isConnected = connect(ui.viewTitlebar, &rgIsaDisassemblyViewTitlebar::ViewTitleBarDoubleClickedSignal, pDisassemblyViewContainer, &rgViewContainer::MaximizeButtonClicked); + assert(isConnected); + } +} + +bool rgIsaDisassemblyView::ReplaceInputFilePath(const std::string& oldFilePath, const std::string& newFilePath) +{ + bool result = true; + + // Replace the file path in all disassembly tab views for all devices. + for (auto& gpuAndTabView : m_gpuTabViews) + { + rgIsaDisassemblyTabView* pTabView = gpuAndTabView.second; + if (!pTabView->ReplaceInputFilePath(oldFilePath, newFilePath)) + { + result = false; + break; + } + } + + // Replace the file path in the resource usage map. + if (result) + { + for (auto& gpuAndResourceUsage : m_gpuResourceUsageViews) + { + auto& fileAndResourceUsage = gpuAndResourceUsage.second; + auto it = fileAndResourceUsage.find(oldFilePath); + if ((result = (it != fileAndResourceUsage.end())) == true) + { + std::map resUsageView = it->second; + fileAndResourceUsage.erase(oldFilePath); + fileAndResourceUsage[newFilePath] = resUsageView; + } + } + } + + return result; +} + +void rgIsaDisassemblyView::HandleSelectNextGPUTargetAction() +{ + int currentRow = m_pTargetGpusListWidget->currentRow(); + + if (currentRow < m_pTargetGpusListWidget->count() - 1) + { + currentRow++; + } + else + { + currentRow = 0; + } + m_pTargetGpusListWidget->setCurrentRow(currentRow); } \ No newline at end of file diff --git a/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyViewOpenCL.cpp b/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyViewOpenCL.cpp index aa87a5d2..3268ab4c 100644 --- a/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyViewOpenCL.cpp +++ b/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyViewOpenCL.cpp @@ -27,11 +27,6 @@ bool rgIsaDisassemblyViewOpenCL::PopulateBuildOutput(const std::shared_ptrsetStyleSheet(STR_DISASSEMBLY_FRAME_BORDER_GREEN_STYLESHEET); -} - bool rgIsaDisassemblyViewOpenCL::PopulateDisassemblyView(const std::vector& sourceFiles, const rgBuildOutputsMap& buildOutput) { bool isProblemFound = false; diff --git a/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyViewVulkan.cpp b/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyViewVulkan.cpp index f03fc15b..9b78325f 100644 --- a/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyViewVulkan.cpp +++ b/RadeonGPUAnalyzerGUI/Src/rgIsaDisassemblyViewVulkan.cpp @@ -8,8 +8,3 @@ rgIsaDisassemblyViewVulkan::rgIsaDisassemblyViewVulkan(QWidget* pParent) : rgIsaDisassemblyViewGraphics(pParent) { } - -void rgIsaDisassemblyViewVulkan::SetBorderStylesheet() -{ - ui.frame->setStyleSheet(STR_DISASSEMBLY_FRAME_BORDER_RED_STYLESHEET); -} \ No newline at end of file diff --git a/RadeonGPUAnalyzerGUI/Src/rgSettingsButtonsView.cpp b/RadeonGPUAnalyzerGUI/Src/rgSettingsButtonsView.cpp index deb5fd71..ad3fe76d 100644 --- a/RadeonGPUAnalyzerGUI/Src/rgSettingsButtonsView.cpp +++ b/RadeonGPUAnalyzerGUI/Src/rgSettingsButtonsView.cpp @@ -8,6 +8,7 @@ #include #include #include +#include // Infra. #include