diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index 80edef422..ff51f2d59 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -44,6 +44,7 @@ #include "Windows/PipelineState/PipelineStateViewer.h" #include "Windows/PixelHistoryView.h" #include "Windows/PythonShell.h" +#include "Windows/ResourceInspector.h" #include "Windows/ShaderViewer.h" #include "Windows/StatisticsViewer.h" #include "Windows/TextureViewer.h" @@ -261,6 +262,10 @@ void CaptureContext::LoadLogfileThreaded(const QString &logFile, const QString & m_StructuredFile = &r->GetStructuredFile(); + m_ResourceList = r->GetResources(); + for(ResourceDescription &res : m_ResourceList) + m_Resources[res.ID] = &res; + m_BufferList = r->GetBuffers(); for(BufferDescription &b : m_BufferList) m_Buffers[b.ID] = &b; @@ -537,6 +542,8 @@ void CaptureContext::CloseLogfile() m_BufferList.clear(); m_Textures.clear(); m_TextureList.clear(); + m_Resources.clear(); + m_ResourceList.clear(); m_Drawcalls.clear(); m_FirstDrawcall = m_LastDrawcall = NULL; @@ -788,6 +795,18 @@ IPythonShell *CaptureContext::GetPythonShell() return m_PythonShell; } +IResourceInspector *CaptureContext::GetResourceInspector() +{ + if(m_ResourceInspector) + return m_ResourceInspector; + + m_ResourceInspector = new ResourceInspector(*this, m_MainWindow); + m_ResourceInspector->setObjectName(lit("resourceInspector")); + setupDockWindow(m_ResourceInspector); + + return m_ResourceInspector; +} + void CaptureContext::ShowEventBrowser() { m_MainWindow->showEventBrowser(); @@ -843,6 +862,11 @@ void CaptureContext::ShowPythonShell() m_MainWindow->showPythonShell(); } +void CaptureContext::ShowResourceInspector() +{ + m_MainWindow->showResourceInspector(); +} + IShaderViewer *CaptureContext::EditShader(bool customShader, const QString &entryPoint, const QStringMap &files, IShaderViewer::SaveCallback saveCallback, @@ -946,6 +970,10 @@ QWidget *CaptureContext::CreateBuiltinWindow(const QString &objectName) { return GetPythonShell()->Widget(); } + else if(objectName == lit("resourceInspector")) + { + return GetResourceInspector()->Widget(); + } else if(objectName == lit("performanceCounterViewer")) { return GetPerformanceCounterViewer()->Widget(); @@ -976,6 +1004,8 @@ void CaptureContext::BuiltinWindowClosed(QWidget *window) m_TimelineBar = NULL; else if(m_PythonShell && m_PythonShell->Widget() == window) m_PythonShell = NULL; + else if(m_ResourceInspector && m_ResourceInspector->Widget() == window) + m_ResourceInspector = NULL; else if(m_PerformanceCounterViewer && m_PerformanceCounterViewer->Widget() == window) m_PerformanceCounterViewer = NULL; else diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index bacde7097..e6d702e34 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -49,6 +49,7 @@ class PerformanceCounterViewer; class StatisticsViewer; class TimelineBar; class PythonShell; +class ResourceInspector; QString ConfigFilePath(const QString &filename); @@ -109,6 +110,8 @@ public: const DrawcallDescription *GetFirstDrawcall() override { return m_FirstDrawcall; }; const DrawcallDescription *GetLastDrawcall() override { return m_LastDrawcall; }; const rdcarray &CurDrawcalls() override { return m_Drawcalls; } + ResourceDescription *GetResource(ResourceId id) override { return m_Resources[id]; } + const rdcarray &GetResources() override { return m_ResourceList; } TextureDescription *GetTexture(ResourceId id) override { return m_Textures[id]; } const rdcarray &GetTextures() override { return m_TextureList; } BufferDescription *GetBuffer(ResourceId id) override { return m_Buffers[id]; } @@ -138,6 +141,7 @@ public: IStatisticsViewer *GetStatisticsViewer() override; ITimelineBar *GetTimelineBar() override; IPythonShell *GetPythonShell() override; + IResourceInspector *GetResourceInspector() override; bool HasEventBrowser() override { return m_EventBrowser != NULL; } bool HasAPIInspector() override { return m_APIInspector != NULL; } @@ -150,6 +154,7 @@ public: bool HasStatisticsViewer() override { return m_StatisticsViewer != NULL; } bool HasTimelineBar() override { return m_TimelineBar != NULL; } bool HasPythonShell() override { return m_PythonShell != NULL; } + bool HasResourceInspector() override { return m_ResourceInspector != NULL; } void ShowEventBrowser() override; void ShowAPIInspector() override; void ShowTextureViewer() override; @@ -161,6 +166,7 @@ public: void ShowStatisticsViewer() override; void ShowTimelineBar() override; void ShowPythonShell() override; + void ShowResourceInspector() override; IShaderViewer *EditShader(bool customShader, const QString &entryPoint, const QStringMap &files, IShaderViewer::SaveCallback saveCallback, @@ -265,6 +271,8 @@ private: rdcarray m_TextureList; QMap m_Buffers; rdcarray m_BufferList; + QMap m_Resources; + rdcarray m_ResourceList; const SDFile *m_StructuredFile; SDFile m_DummySDFile; @@ -293,4 +301,5 @@ private: StatisticsViewer *m_StatisticsViewer = NULL; TimelineBar *m_TimelineBar = NULL; PythonShell *m_PythonShell = NULL; + ResourceInspector *m_ResourceInspector = NULL; }; diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 6c5893b47..daff1282c 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -265,6 +265,35 @@ protected: DECLARE_REFLECTION_STRUCT(IBufferViewer); +DOCUMENT("The Resource inspector window."); +struct IResourceInspector +{ + DOCUMENT( + "Retrieves the QWidget for this :class:`ResourceInspector` if PySide2 is available, or " + "otherwise " + "unique opaque pointer that can be passed to RenderDoc functions expecting a QWidget."); + virtual QWidget *Widget() = 0; + + DOCUMENT(R"(Change the current resource being inspected. + +:param ~renderdoc.ResourceId id: The ID of the resource to inspect. +)"); + virtual void Inspect(ResourceId id) = 0; + + DOCUMENT(R"(Return which resource is currently being inspected. + +:return: The ID of the resource being inspected. +:rtype: renderdoc.ResourceId id +)"); + virtual ResourceId CurrentResource() = 0; + +protected: + IResourceInspector() = default; + ~IResourceInspector() = default; +}; + +DECLARE_REFLECTION_STRUCT(IResourceInspector); + DOCUMENT("The executable capture window."); struct ICaptureDialog { @@ -1014,6 +1043,21 @@ more information for how this differs. )"); virtual const rdcarray &CurDrawcalls() = 0; + DOCUMENT(R"(Retrieve the information about a particular resource. + +:param ~renderdoc.ResourceId id: The ID of the resource to query about. +:return: The information about a resource, or ``None`` if the ID does not correspond to a resource. +:rtype: ~renderdoc.ResourceDescription +)"); + virtual ResourceDescription *GetResource(ResourceId id) = 0; + + DOCUMENT(R"(Retrieve the list of resources in the current capture. + +:return: The list of resources. +:rtype: ``list`` of :class:`~renderdoc.ResourceDescription` +)"); + virtual const rdcarray &GetResources() = 0; + DOCUMENT(R"(Retrieve the information about a particular texture. :param ~renderdoc.ResourceId id: The ID of the texture to query about. @@ -1190,6 +1234,13 @@ as well as messages generated during replay and analysis. )"); virtual IPythonShell *GetPythonShell() = 0; + DOCUMENT(R"(Retrieve the current singleton :class:`ResourceInspector`. + +:return: The current window, which is created (but not shown) it there wasn't one open. +:rtype: ResourceInspector +)"); + virtual IResourceInspector *GetResourceInspector() = 0; + DOCUMENT(R"(Check if there is a current :class:`EventBrowser` open. :return: ``True`` if there is a window open. @@ -1267,6 +1318,13 @@ as well as messages generated during replay and analysis. )"); virtual bool HasPythonShell() = 0; + DOCUMENT(R"(Check if there is a current :class:`ResourceInspector` open. + +:return: ``True`` if there is a window open. +:rtype: ``bool`` +)"); + virtual bool HasResourceInspector() = 0; + DOCUMENT("Raise the current :class:`EventBrowser`, showing it in the default place if needed."); virtual void ShowEventBrowser() = 0; DOCUMENT("Raise the current :class:`APIInspector`, showing it in the default place if needed."); @@ -1293,6 +1351,9 @@ as well as messages generated during replay and analysis. virtual void ShowTimelineBar() = 0; DOCUMENT("Raise the current :class:`PythonShell`, showing it in the default place if needed."); virtual void ShowPythonShell() = 0; + DOCUMENT( + "Raise the current :class:`ResourceInspector`, showing it in the default place if needed."); + virtual void ShowResourceInspector() = 0; DOCUMENT(R"(Show a new :class:`ShaderViewer` window, showing an editable view of a given shader. diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index 01ff36a7a..8b5311d9c 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -1700,6 +1700,16 @@ void MainWindow::on_action_Counter_Viewer_triggered() ui->toolWindowManager->addToolWindow(performanceCounterViewer, mainToolArea()); } +void MainWindow::on_action_Resource_Inspector_triggered() +{ + QWidget *resourceInspector = m_Ctx.GetResourceInspector()->Widget(); + + if(ui->toolWindowManager->toolWindows().contains(resourceInspector)) + ToolWindowManager::raiseToolWindow(resourceInspector); + else + ui->toolWindowManager->addToolWindow(resourceInspector, mainToolArea()); +} + void MainWindow::saveLayout_triggered() { LoadSaveLayout(qobject_cast(QObject::sender()), true); diff --git a/qrenderdoc/Windows/MainWindow.h b/qrenderdoc/Windows/MainWindow.h index 985d6e457..40bbaab03 100644 --- a/qrenderdoc/Windows/MainWindow.h +++ b/qrenderdoc/Windows/MainWindow.h @@ -93,6 +93,7 @@ public: void showTimelineBar() { on_action_Timeline_triggered(); } void showPythonShell() { on_action_Python_Shell_triggered(); } void showPerformanceCounterViewer() { on_action_Counter_Viewer_triggered(); } + void showResourceInspector() { on_action_Resource_Inspector_triggered(); } void PopulateRecentFiles(); void PopulateRecentCaptures(); private slots: @@ -124,6 +125,7 @@ private slots: void on_action_Build_Release_Downloads_triggered(); void on_action_Show_Tips_triggered(); void on_action_Counter_Viewer_triggered(); + void on_action_Resource_Inspector_triggered(); // manual slots void saveLayout_triggered(); diff --git a/qrenderdoc/Windows/MainWindow.ui b/qrenderdoc/Windows/MainWindow.ui index ed0bc305f..fa0782db5 100644 --- a/qrenderdoc/Windows/MainWindow.ui +++ b/qrenderdoc/Windows/MainWindow.ui @@ -131,6 +131,7 @@ + @@ -385,7 +386,7 @@ - Statisti&cs Viewer + &Statistics Viewer @@ -405,7 +406,12 @@ - Performance Counter Viewer + Performance &Counter Viewer + + + + + &Resource Inspector diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index 9d009ee7b..f52792c36 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -77,6 +77,11 @@ struct CaptureContextInvoker : ICaptureContext { return m_Ctx.CurDrawcalls(); } + virtual ResourceDescription *GetResource(ResourceId id) override { return m_Ctx.GetResource(id); } + virtual const rdcarray &GetResources() override + { + return m_Ctx.GetResources(); + } virtual TextureDescription *GetTexture(ResourceId id) override { return m_Ctx.GetTexture(id); } virtual const rdcarray &GetTextures() override { return m_Ctx.GetTextures(); } virtual BufferDescription *GetBuffer(ResourceId id) override { return m_Ctx.GetBuffer(id); } @@ -214,6 +219,10 @@ struct CaptureContextInvoker : ICaptureContext { return InvokeRetFunction(&ICaptureContext::GetPythonShell); } + virtual IResourceInspector *GetResourceInspector() override + { + return InvokeRetFunction(&ICaptureContext::GetResourceInspector); + } virtual bool HasEventBrowser() override { return InvokeRetFunction(&ICaptureContext::HasEventBrowser); @@ -258,6 +267,10 @@ struct CaptureContextInvoker : ICaptureContext { return InvokeRetFunction(&ICaptureContext::HasPythonShell); } + virtual bool HasResourceInspector() override + { + return InvokeRetFunction(&ICaptureContext::HasResourceInspector); + } virtual void ShowEventBrowser() override { @@ -294,6 +307,10 @@ struct CaptureContextInvoker : ICaptureContext } virtual void ShowTimelineBar() override { InvokeVoidFunction(&ICaptureContext::ShowTimelineBar); } virtual void ShowPythonShell() override { InvokeVoidFunction(&ICaptureContext::ShowPythonShell); } + virtual void ShowResourceInspector() override + { + InvokeVoidFunction(&ICaptureContext::ShowResourceInspector); + } virtual IShaderViewer *EditShader(bool customShader, const QString &entryPoint, const QStringMap &files, IShaderViewer::SaveCallback saveCallback, IShaderViewer::CloseCallback closeCallback) override diff --git a/qrenderdoc/Windows/ResourceInspector.cpp b/qrenderdoc/Windows/ResourceInspector.cpp new file mode 100644 index 000000000..99b8cbeac --- /dev/null +++ b/qrenderdoc/Windows/ResourceInspector.cpp @@ -0,0 +1,380 @@ +/****************************************************************************** + * 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 "ResourceInspector.h" +#include +#include "Widgets/Extended/RDHeaderView.h" +#include "ui_ResourceInspector.h" + +static const int ResourceIdRole = Qt::UserRole; +static const int FilterRole = Qt::UserRole + 1; + +Q_DECLARE_METATYPE(ResourceId); + +class ResourceListItemModel : public QAbstractItemModel +{ +public: + ResourceListItemModel(QWidget *parent, ICaptureContext &ctx) + : QAbstractItemModel(parent), m_Ctx(ctx) + { + } + + void reset() + { + emit beginResetModel(); + emit endResetModel(); + } + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override + { + if(row < 0 || row >= rowCount()) + return QModelIndex(); + + return createIndex(row, 0); + } + + QModelIndex parent(const QModelIndex &index) const override { return QModelIndex(); } + int rowCount(const QModelIndex &parent = QModelIndex()) const override + { + return m_Ctx.GetResources().count(); + } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 1; } + Qt::ItemFlags flags(const QModelIndex &index) const override + { + if(!index.isValid()) + return 0; + + return QAbstractItemModel::flags(index); + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override + { + if(index.isValid()) + { + const rdcarray &resources = m_Ctx.GetResources(); + + if(index.row() < resources.count()) + { + const ResourceDescription &desc = resources[index.row()]; + + if(role == Qt::DisplayRole) + return desc.name; + + if(role == ResourceIdRole) + return QVariant::fromValue(desc.ID); + + if(role == FilterRole) + return ToQStr(desc.type) + lit(" ") + desc.name; + } + } + + return QVariant(); + } + +private: + ICaptureContext &m_Ctx; +}; + +ResourceInspector::ResourceInspector(ICaptureContext &ctx, QWidget *parent) + : QFrame(parent), ui(new Ui::ResourceInspector), m_Ctx(ctx) +{ + ui->setupUi(this); + + ui->resourceName->setText(tr("No Resource Selected")); + + ui->resetName->hide(); + ui->resourceNameEdit->hide(); + ui->renameResource->setEnabled(false); + + ui->viewContents->hide(); + + m_ResourceModel = new ResourceListItemModel(this, m_Ctx); + + m_FilterModel = new QSortFilterProxyModel(this); + m_FilterModel->setSourceModel(m_ResourceModel); + m_FilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_FilterModel->setFilterRole(FilterRole); + m_FilterModel->setSortCaseSensitivity(Qt::CaseInsensitive); + m_FilterModel->setSortRole(Qt::DisplayRole); + + ui->resourceList->setModel(m_FilterModel); + + ui->initChunks->setColumns({lit("Parameter"), tr("Value")}); + ui->initChunks->header()->resizeSection(0, 200); + + ui->initChunks->setFont(Formatter::PreferredFont()); + ui->relatedResources->setFont(Formatter::PreferredFont()); + ui->resourceUsage->setFont(Formatter::PreferredFont()); + + { + RDHeaderView *header = new RDHeaderView(Qt::Horizontal, this); + ui->relatedResources->setHeader(header); + + ui->relatedResources->setColumns({tr("Type"), tr("Resource")}); + header->setColumnStretchHints({-1, 1}); + + ui->relatedResources->setClearSelectionOnFocusLoss(true); + } + + ui->resourceUsage->setColumns({tr("EID"), tr("Usage")}); + + QObject::connect(ui->resourceList, &QListView::doubleClicked, this, + &ResourceInspector::resource_doubleClicked); + QObject::connect(ui->relatedResources, &QTreeView::doubleClicked, this, + &ResourceInspector::resource_doubleClicked); + + Inspect(ResourceId()); + + m_Ctx.AddLogViewer(this); +} + +ResourceInspector::~ResourceInspector() +{ + m_Ctx.BuiltinWindowClosed(this); + m_Ctx.RemoveLogViewer(this); + delete ui; +} + +void ResourceInspector::Inspect(ResourceId id) +{ + if(m_Resource == id) + return; + + m_Resource = id; + + ui->viewContents->setVisible(m_Ctx.GetTexture(id) || m_Ctx.GetBuffer(id)); + + m_ResourceModel->reset(); + m_FilterModel->sort(0); + + ui->initChunks->setUpdatesEnabled(false); + ui->initChunks->clear(); + ui->relatedResources->clear(); + ui->resourceUsage->clear(); + + const SDFile &file = m_Ctx.GetStructuredFile(); + const ResourceDescription *desc = m_Ctx.GetResource(id); + + m_Ctx.Replay().AsyncInvoke([this, id](IReplayController *r) { + rdcarray usage = r->GetUsage(id); + + GUIInvoke::call([this, id, usage] { + CombineUsageEvents( + m_Ctx, usage, [this, id](uint32_t startEID, uint32_t endEID, ResourceUsage use) { + QString text; + + if(startEID == endEID) + text = QFormatStr("EID %1").arg(startEID); + else + text = QFormatStr("EID %1-%2").arg(startEID).arg(endEID); + + RDTreeWidgetItem *item = + new RDTreeWidgetItem({text, ToQStr(use, m_Ctx.APIProps().pipelineType)}); + item->setData(0, ResourceIdRole, QVariant(endEID)); + + ui->resourceUsage->addTopLevelItem(item); + }); + }); + }); + + if(desc) + { + // TODO fetch global name + ui->resourceName->setText(desc->name); + + for(ResourceId parent : desc->parentResources) + { + // TODO fetch global name + RDTreeWidgetItem *item = new RDTreeWidgetItem({tr("Parent"), ToQStr(parent)}); + item->setData(0, ResourceIdRole, QVariant::fromValue(parent)); + item->setData(1, ResourceIdRole, QVariant::fromValue(parent)); + ui->relatedResources->addTopLevelItem(item); + } + + for(ResourceId derived : desc->derivedResources) + { + // TODO fetch global name + RDTreeWidgetItem *item = new RDTreeWidgetItem({tr("Derived"), ToQStr(derived)}); + item->setData(0, ResourceIdRole, QVariant::fromValue(derived)); + item->setData(1, ResourceIdRole, QVariant::fromValue(derived)); + ui->relatedResources->addTopLevelItem(item); + } + + for(uint32_t chunk : desc->initialisationChunks) + { + RDTreeWidgetItem *root = new RDTreeWidgetItem({QString(), QString()}); + + if(chunk < file.chunks.size()) + { + SDChunk *chunkObj = file.chunks[chunk]; + + root->setText(0, chunkObj->name); + + addStructuredObjects(root, chunkObj->data.children, false); + } + else + { + root->setText(1, tr("Invalid chunk index %1").arg(chunk)); + } + + ui->initChunks->addTopLevelItem(root); + + ui->initChunks->setSelectedItem(root); + } + } + else + { + m_Resource = ResourceId(); + ui->resourceName->setText(tr("No Resource Selected")); + } + + ui->initChunks->setUpdatesEnabled(true); +} + +void ResourceInspector::OnLogfileLoaded() +{ + ui->renameResource->setEnabled(true); + + m_ResourceModel->reset(); + m_FilterModel->sort(0); +} + +void ResourceInspector::OnLogfileClosed() +{ + ui->renameResource->setEnabled(false); + ui->resetName->hide(); + + ui->resourceName->setText(tr("No Resource Selected")); + + ui->viewContents->hide(); + + m_ResourceModel->reset(); + + ui->initChunks->clear(); + ui->relatedResources->clear(); + ui->resourceUsage->clear(); + + m_Resource = ResourceId(); +} + +void ResourceInspector::on_renameResource_clicked() +{ + if(!ui->resourceNameEdit->isVisible()) + { + ui->resourceNameEdit->setText(ui->resourceName->text()); + ui->resourceName->hide(); + ui->resourceNameEdit->show(); + ui->resourceNameEdit->setFocus(); + } + else + { + // apply the edit + ui->resourceName->setText(ui->resourceNameEdit->text()); + ui->resourceNameEdit->hide(); + ui->resourceName->show(); + + ui->resetName->show(); + + // TODO - set custom name globally + // m_Ctx.SetResourceCustomName(m_Resource, ui->resourceName->text()); + } +} + +void ResourceInspector::on_resourceNameEdit_keyPress(QKeyEvent *event) +{ + if(event->key() == Qt::Key_Escape) + { + // throw away the edit and show the name again + ui->resourceNameEdit->hide(); + ui->resourceName->show(); + } + else if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) + { + // apply the edit + on_renameResource_clicked(); + } +} + +void ResourceInspector::on_resetName_clicked() +{ + const ResourceDescription *desc = m_Ctx.GetResource(m_Resource); + // TODO fetch global name + ui->resourceName->setText(desc->name); + + ui->resetName->hide(); + + // TODO - unset custom name globally + // m_Ctx.RemoveCustomName(m_Resource); +} + +void ResourceInspector::on_cancelResourceListFilter_clicked() +{ + ui->resourceListFilter->setText(QString()); +} + +void ResourceInspector::on_resourceListFilter_textChanged(const QString &text) +{ + m_FilterModel->setFilterFixedString(text); +} + +void ResourceInspector::resource_doubleClicked(const QModelIndex &index) +{ + ResourceId id = index.model()->data(index, ResourceIdRole).value(); + Inspect(id); +} + +void ResourceInspector::on_viewContents_clicked() +{ + TextureDescription *tex = m_Ctx.GetTexture(m_Resource); + BufferDescription *buf = m_Ctx.GetBuffer(m_Resource); + + if(tex) + { + if(tex->resType == TextureDim::Buffer) + { + IBufferViewer *viewer = m_Ctx.ViewTextureAsBuffer(0, 0, tex->ID); + + m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); + } + else + { + if(!m_Ctx.HasTextureViewer()) + m_Ctx.ShowTextureViewer(); + ITextureViewer *viewer = m_Ctx.GetTextureViewer(); + viewer->ViewTexture(tex->ID, true); + } + } + else if(buf) + { + IBufferViewer *viewer = m_Ctx.ViewBuffer(0, buf->length, buf->ID); + + m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); + } +} + +void ResourceInspector::on_resourceUsage_doubleClicked(const QModelIndex &index) +{ + uint32_t eid = index.model()->data(index, ResourceIdRole).value(); + m_Ctx.SetEventID({}, eid, eid); +} diff --git a/qrenderdoc/Windows/ResourceInspector.h b/qrenderdoc/Windows/ResourceInspector.h new file mode 100644 index 000000000..1dadc6ed3 --- /dev/null +++ b/qrenderdoc/Windows/ResourceInspector.h @@ -0,0 +1,81 @@ +/****************************************************************************** + * 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. + ******************************************************************************/ + +#pragma once + +#include +#include "Code/CaptureContext.h" + +namespace Ui +{ +class ResourceInspector; +} + +class QSortFilterProxyModel; + +class RDTreeWidgetItem; +class ResourceListItemModel; + +class ResourceInspector : public QFrame, public IResourceInspector, public ILogViewer +{ + Q_OBJECT + +public: + explicit ResourceInspector(ICaptureContext &ctx, QWidget *parent = 0); + ~ResourceInspector(); + + // IResourceInspector + QWidget *Widget() override { return this; } + void Inspect(ResourceId id) override; + ResourceId CurrentResource() override { return m_Resource; } + // ILogViewerForm + void OnLogfileLoaded() override; + void OnLogfileClosed() override; + void OnSelectedEventChanged(uint32_t eventID) override {} + void OnEventChanged(uint32_t eventID) override {} +public slots: + // automatic slots + void on_renameResource_clicked(); + void on_resourceNameEdit_keyPress(QKeyEvent *event); + void on_resetName_clicked(); + + void on_cancelResourceListFilter_clicked(); + void on_resourceListFilter_textChanged(const QString &text); + + // manual slots + void resource_doubleClicked(const QModelIndex &index); + +private slots: + void on_viewContents_clicked(); + + void on_resourceUsage_doubleClicked(const QModelIndex &index); + +private: + Ui::ResourceInspector *ui; + ICaptureContext &m_Ctx; + + ResourceId m_Resource; + ResourceListItemModel *m_ResourceModel; + QSortFilterProxyModel *m_FilterModel; +}; diff --git a/qrenderdoc/Windows/ResourceInspector.ui b/qrenderdoc/Windows/ResourceInspector.ui new file mode 100644 index 000000000..1b75fad25 --- /dev/null +++ b/qrenderdoc/Windows/ResourceInspector.ui @@ -0,0 +1,340 @@ + + + ResourceInspector + + + + 0 + 0 + 815 + 596 + + + + Resource Inspector + + + + + + + + + 20 + + + + Resource Name Here + + + + + + + + 20 + + + + + + + + Rename resource + + + + :/page_white_edit.png:/page_white_edit.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Reset name + + + + :/arrow_undo.png:/arrow_undo.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + View Contents + + + + :/action_hover.png:/action_hover.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + + + 1 + 0 + + + + Resource List + + + + 6 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + 0 + + + + + + 0 + 0 + + + + + + + + + + + + :/cross.png:/cross.png + + + true + + + + + + + + + QFrame::Box + + + QFrame::Sunken + + + QAbstractItemView::NoEditTriggers + + + false + + + Qt::CopyAction + + + QAbstractItemView::SelectRows + + + QListView::ListMode + + + true + + + + + + + + + + + 0 + 3 + + + + Related Resources + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 1 + + + + QAbstractItemView::SelectRows + + + false + + + + + + + + + + + 0 + 3 + + + + Usage in Frame + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Qt::ScrollBarAlwaysOn + + + QAbstractItemView::SelectRows + + + false + + + + + + + + + + + 2 + 5 + + + + Resource Initialisation Parameters + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::ContiguousSelection + + + 20 + + + true + + + true + + + true + + + + + + + + + + + RDLineEdit + QLineEdit +
Widgets/Extended/RDLineEdit.h
+
+ + RDTreeWidget + QTreeView +
Widgets/Extended/RDTreeWidget.h
+
+ + RDListView + QListView +
Widgets/Extended/RDListView.h
+
+
+ + + + +
diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index 1f95f9cd9..e51a8dc6d 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -218,7 +218,8 @@ SOURCES += Code/qrenderdoc.cpp \ Windows/Dialogs/TipsDialog.cpp \ Windows/PythonShell.cpp \ Windows/Dialogs/PerformanceCounterSelection.cpp \ - Windows/PerformanceCounterViewer.cpp + Windows/PerformanceCounterViewer.cpp \ + Windows/ResourceInspector.cpp HEADERS += Code/CaptureContext.h \ Code/qprocessinfo.h \ Code/ReplayManager.h \ @@ -284,7 +285,8 @@ HEADERS += Code/CaptureContext.h \ Windows/Dialogs/TipsDialog.h \ Windows/PythonShell.h \ Windows/Dialogs/PerformanceCounterSelection.h \ - Windows/PerformanceCounterViewer.h + Windows/PerformanceCounterViewer.h \ + Windows/ResourceInspector.h FORMS += Windows/Dialogs/AboutDialog.ui \ Windows/MainWindow.ui \ Windows/EventBrowser.ui \ @@ -317,7 +319,8 @@ FORMS += Windows/Dialogs/AboutDialog.ui \ Windows/Dialogs/TipsDialog.ui \ Windows/PythonShell.ui \ Windows/Dialogs/PerformanceCounterSelection.ui \ - Windows/PerformanceCounterViewer.ui + Windows/PerformanceCounterViewer.ui \ + Windows/ResourceInspector.ui RESOURCES += Resources/resources.qrc diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index 09ff0a3bd..ca94b0f30 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -577,6 +577,7 @@ + @@ -677,6 +678,7 @@ + @@ -876,6 +878,7 @@ + @@ -1069,6 +1072,12 @@ 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" + 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" @@ -1285,6 +1294,12 @@ UIC %(Filename).ui $(IntDir)generated\ui_%(Filename).h + + %(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 + %(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs) "$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe" "%(Fullpath)" -o "$(IntDir)generated\ui_%(Filename).h" diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 465b317c1..9955a13f5 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -663,6 +663,12 @@ Generated Files + + Generated Files + + + Windows + @@ -998,6 +1004,9 @@ Code\pyrenderdoc + + Generated Files + @@ -1499,5 +1508,11 @@ Windows + + Windows + + + Windows + \ No newline at end of file