diff --git a/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.cpp b/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.cpp new file mode 100644 index 000000000..7fd1c9eff --- /dev/null +++ b/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.cpp @@ -0,0 +1,175 @@ +/****************************************************************************** +* The MIT License (MIT) +* +* Copyright (c) 2016-2017 Baldur Karlsson +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +******************************************************************************/ + +#include "PerformanceCounterSelection.h" +#include "Code/CaptureContext.h" +#include "Code/Interface/QRDInterface.h" +#include "ui_PerformanceCounterSelection.h" + +#include + +namespace +{ +enum class CounterFamily +{ + Unknown, + Generic, + AMD, + Intel, + NVIDIA, +}; + +CounterFamily GetCounterFamily(GPUCounter counter) +{ + if(IsAMDCounter(counter)) + { + return CounterFamily::AMD; + } + else if(IsIntelCounter(counter)) + { + return CounterFamily::Intel; + } + else if(IsNvidiaCounter(counter)) + { + return CounterFamily::NVIDIA; + } + + return CounterFamily::Generic; +} + +const char *ToString(CounterFamily family) +{ + switch(family) + { + case CounterFamily::AMD: return "AMD"; + case CounterFamily::Generic: return "Generic"; + case CounterFamily::Intel: return "Intel"; + case CounterFamily::NVIDIA: return "NVIDIA"; + case CounterFamily::Unknown: return "Unknown"; + } + + return nullptr; +} +} + +PerformanceCounterSelection::PerformanceCounterSelection(ICaptureContext &ctx, QWidget *parent) + : QDialog(parent), ui(new Ui::PerformanceCounterSelection), m_Ctx(ctx) +{ + ui->setupUi(this); + + connect(ui->counterTree, &QTreeWidget::itemEntered, [&](QTreeWidgetItem *item, int) -> void { + const auto d = item->data(0, Qt::UserRole + 1); + + if(d.isValid()) + { + ui->counterDescription->setText( + QString(QLatin1String("%1
%2")).arg(item->text(0)).arg(d.toString())); + } + }); + + connect(ui->counterTree, &QTreeWidget::itemChanged, [&](QTreeWidgetItem *item, int) -> void { + const auto d = item->data(0, Qt::UserRole + 2); + + if(d.isValid()) + { + if(item->checkState(0) == Qt::Checked) + { + // Add + auto listItem = new QListWidgetItem(ui->enabledCounters); + listItem->setText(item->text(0)); + m_SelectedCounters.insert(d.toInt(), listItem); + } + else + { + // Remove + auto listItem = m_SelectedCounters.take(d.toInt()); + delete listItem; + } + } + }); + + ui->counterTree->setMouseTracking(true); + + auto showCounters = [&](const QVector &counters) -> void { + ui->counterTree->clear(); + ui->enabledCounters->clear(); + + QTreeWidgetItem *currentRoot = NULL; + CounterFamily currentFamily = CounterFamily::Unknown; + + std::unordered_map categories; + + for(const auto desc : counters) + { + const CounterFamily family = GetCounterFamily(desc.counterID); + if(family != currentFamily) + { + currentRoot = new QTreeWidgetItem(ui->counterTree); + currentRoot->setText(0, QLatin1String{ToString(family)}); + + categories.clear(); + + currentFamily = family; + } + + QTreeWidgetItem *categoryItem = nullptr; + + const auto category = std::string{desc.category}; + auto categoryIterator = categories.find(category); + + if(categoryIterator == categories.end()) + { + auto item = new QTreeWidgetItem{currentRoot}; + item->setText(0, desc.category); + categories[category] = item; + categoryItem = item; + } + else + { + categoryItem = categoryIterator->second; + } + + auto counterItem = new QTreeWidgetItem{categoryItem}; + counterItem->setText(0, desc.name); + counterItem->setData(0, Qt::UserRole + 1, desc.description); + counterItem->setData(0, Qt::UserRole + 2, (int32_t)desc.counterID); + counterItem->setCheckState(0, Qt::Unchecked); + } + }; + + ctx.Replay().AsyncInvoke([=](IReplayController *controller) -> void { + QVector desc; + for(const auto counter : controller->EnumerateCounters()) + { + desc.append(controller->DescribeCounter(counter)); + } + + GUIInvoke::call([=]() -> void { showCounters(desc); }); + }); +} + +PerformanceCounterSelection::~PerformanceCounterSelection() +{ + delete ui; +} diff --git a/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.h b/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.h new file mode 100644 index 000000000..20e5ebfb2 --- /dev/null +++ b/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.h @@ -0,0 +1,49 @@ +/****************************************************************************** +* The MIT License (MIT) +* +* Copyright (c) 2017 Baldur Karlsson +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +******************************************************************************/ + +#include +#include + +namespace Ui +{ +class PerformanceCounterSelection; +} + +struct ICaptureContext; +class QListWidgetItem; + +class PerformanceCounterSelection : public QDialog +{ + Q_OBJECT + +public: + explicit PerformanceCounterSelection(ICaptureContext &ctx, QWidget *parent = 0); + ~PerformanceCounterSelection(); + +private: + Ui::PerformanceCounterSelection *ui; + + ICaptureContext &m_Ctx; + QMap m_SelectedCounters; +}; diff --git a/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.ui b/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.ui new file mode 100644 index 000000000..50ebd8964 --- /dev/null +++ b/qrenderdoc/Windows/Dialogs/PerformanceCounterSelection.ui @@ -0,0 +1,129 @@ + + + PerformanceCounterSelection + + + + 0 + 0 + 640 + 480 + + + + Performance counter selection + + + + + + + + Counters + + + + + + + false + + + + 1 + + + + + + + + + + + + Counter description + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.875pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Cache miss</span></p> +<hr /> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lorem ipsum something something about cache misses and why you don't want those to happen all the time. Not sure what to write here, given some people seem to like a high number here.</p></body></html> + + + + + + + Enabled counters + + + + + + + true + + + + Counter 1 + + + + + Cache miss + + + + + Counter 2 + + + + + + + + + + Save + + + + + + + Load + + + + + + + Sample counters + + + + + + + Cancel + + + + + + + + + + + + diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index 283929688..40a9cde4e 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -41,6 +41,7 @@ #include "Windows/Dialogs/AboutDialog.h" #include "Windows/Dialogs/CaptureDialog.h" #include "Windows/Dialogs/LiveCapture.h" +#include "Windows/Dialogs/PerformanceCounterSelection.h" #include "Windows/Dialogs/RemoteManager.h" #include "Windows/Dialogs/SettingsDialog.h" #include "Windows/Dialogs/SuggestRemoteDialog.h" @@ -1644,6 +1645,12 @@ void MainWindow::on_actionShow_Tips_triggered() RDDialog::show(&tipsDialog); } +void MainWindow::on_action_Counter_Viewer_triggered() +{ + PerformanceCounterSelection pcs(m_Ctx, this); + RDDialog::show(&pcs); +} + void MainWindow::saveLayout_triggered() { LoadSaveLayout(qobject_cast(QObject::sender()), true); diff --git a/qrenderdoc/Windows/MainWindow.h b/qrenderdoc/Windows/MainWindow.h index a5b91a889..643f7288f 100644 --- a/qrenderdoc/Windows/MainWindow.h +++ b/qrenderdoc/Windows/MainWindow.h @@ -94,6 +94,7 @@ public: void showStatisticsViewer() { on_action_Statistics_Viewer_triggered(); } void showTimelineBar() { on_action_Timeline_triggered(); } void showPythonShell() { on_action_Python_Shell_triggered(); } + void showPerformanceCounterViewer() { on_action_Counter_Viewer_triggered(); } private slots: // automatic slots void on_action_Exit_triggered(); @@ -122,6 +123,7 @@ private slots: void on_action_Source_on_github_triggered(); void on_action_Build_Release_downloads_triggered(); void on_actionShow_Tips_triggered(); + void on_action_Counter_Viewer_triggered(); // manual slots void saveLayout_triggered(); diff --git a/qrenderdoc/Windows/MainWindow.ui b/qrenderdoc/Windows/MainWindow.ui index 20b564707..ef0a67b7f 100644 --- a/qrenderdoc/Windows/MainWindow.ui +++ b/qrenderdoc/Windows/MainWindow.ui @@ -130,6 +130,7 @@ + @@ -405,6 +406,11 @@ Start Replay &Loop + + + Counter selection + + diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index 018f254cf..a5a412317 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -216,7 +216,8 @@ SOURCES += Code/qrenderdoc.cpp \ Widgets/FindReplace.cpp \ Widgets/Extended/RDSplitter.cpp \ Windows/Dialogs/TipsDialog.cpp \ - Windows/PythonShell.cpp + Windows/PythonShell.cpp \ + Windows/Dialogs/PerformanceCounterSelection.cpp HEADERS += Code/CaptureContext.h \ Code/qprocessinfo.h \ Code/ReplayManager.h \ @@ -280,7 +281,8 @@ HEADERS += Code/CaptureContext.h \ Widgets/FindReplace.h \ Widgets/Extended/RDSplitter.h \ Windows/Dialogs/TipsDialog.h \ - Windows/PythonShell.h + Windows/PythonShell.h \ + Windows/Dialogs/PerformanceCounterSelection.h FORMS += Windows/Dialogs/AboutDialog.ui \ Windows/MainWindow.ui \ Windows/EventBrowser.ui \ @@ -311,7 +313,8 @@ FORMS += Windows/Dialogs/AboutDialog.ui \ Windows/Dialogs/EnvironmentEditor.ui \ Widgets/FindReplace.ui \ Windows/Dialogs/TipsDialog.ui \ - Windows/PythonShell.ui + Windows/PythonShell.ui \ + Windows/Dialogs/PerformanceCounterSelection.ui RESOURCES += Resources/resources.qrc diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index fe1f7e8ee..b1c95cc5c 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -592,6 +592,7 @@ + @@ -683,6 +684,7 @@ + @@ -763,6 +765,12 @@ + + %(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs) + $(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I$(ProjectDir) -I$(SolutionDir)\renderdoc\api\replay -I$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015 -I$(ProjectDir)3rdparty\qt\$(Platform)\include -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtWidgets -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtGui -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtCore %(Fullpath) -o $(IntDir)generated\moc_%(Filename).cpp + MOC %(Filename).h + $(IntDir)generated\moc_%(Filename).cpp + %(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs) "$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe" -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I"$(ProjectDir)." -I"$(SolutionDir)\renderdoc\api\replay" -I"$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtWidgets" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtGui" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtCore" "%(Fullpath)" -o "$(IntDir)generated\moc_%(Filename).cpp" @@ -876,6 +884,7 @@ + @@ -1501,6 +1510,13 @@ IF %ERRORLEVEL% NEQ 0 (echo ==================================================== + + %(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs) + $(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe %(Fullpath) -o $(IntDir)generated\ui_%(Filename).h + UIC %(Filename).ui + $(IntDir)generated\ui_%(Filename).h + Designer + diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 6751a50fc..df2e5b099 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -651,6 +651,9 @@ Styles + + Windows\Dialogs + @@ -965,6 +968,9 @@ Styles + + Windows\Dialogs + @@ -1147,6 +1153,9 @@ Code\pyrenderdoc + + Windows\Dialogs + diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index 302292b1d..241e02514 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -891,6 +891,9 @@ struct CounterDescription DOCUMENT("A short human-readable name for the counter."); rdctype::str name; + DOCUMENT("The counter category. Can be empty for uncategorized counters."); + rdctype::str category; + DOCUMENT("If available, a longer human-readable description of the value this counter measures."); rdctype::str description; diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index 14a60b2f5..36de6e88d 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -1593,8 +1593,9 @@ void Serialiser::Serialise(const char *name, CounterDescription &el) Serialise("", el.resultType); Serialise("", el.resultByteWidth); Serialise("", el.unit); + Serialise("", el.category); - SIZE_CHECK(56); + SIZE_CHECK(72); } template <> diff --git a/renderdoc/driver/d3d11/d3d11_counters.cpp b/renderdoc/driver/d3d11/d3d11_counters.cpp index bb9af5203..de59c441f 100644 --- a/renderdoc/driver/d3d11/d3d11_counters.cpp +++ b/renderdoc/driver/d3d11/d3d11_counters.cpp @@ -90,6 +90,8 @@ void D3D11DebugManager::DescribeCounter(GPUCounter counterID, CounterDescription } } + desc.category = "D3D11"; + switch(counterID) { case GPUCounter::EventGPUDuration: diff --git a/renderdoc/driver/ihv/amd/amd_counters.cpp b/renderdoc/driver/ihv/amd/amd_counters.cpp index d3d408068..567d169a7 100644 --- a/renderdoc/driver/ihv/amd/amd_counters.cpp +++ b/renderdoc/driver/ihv/amd/amd_counters.cpp @@ -219,7 +219,7 @@ vector AMDCounters::EnumerateCounters() internalDesc.desc = InternalGetCounterDescription(i); // We ignore any D3D11 counters, as those are handled elsewhere - if(strncmp(internalDesc.desc.description.c_str(), "#D3D11#", 7) == 0) + if(strncmp(internalDesc.desc.category.c_str(), "D3D11", 5) == 0) { continue; } @@ -249,7 +249,35 @@ CounterDescription AMDCounters::InternalGetCounterDescription(uint32_t internalI m_pGPUPerfAPI->getCounterName(internalIndex, &tmp); desc.name = tmp; m_pGPUPerfAPI->getCounterDescription(internalIndex, &tmp); - desc.description = tmp; + + std::vector descCopy; + int separator = -1; + int sharpFound = 0; + const char *c = tmp; + while(*c) + { + if(*c == '#') + { + ++sharpFound; + descCopy.push_back('\0'); + + if(sharpFound == 2) + { + separator = (int32_t)(c - tmp); + } + } + else + { + descCopy.push_back(*c); + } + + ++c; + } + + descCopy.push_back('\0'); + + desc.category = descCopy.data() + 1; + desc.description = descCopy.data() + separator + 1; GPA_Usage_Type usageType;