From 200f0799a45f87e9d3d26ee6ca79b0b963c53135 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 14 Nov 2017 18:44:56 +0000 Subject: [PATCH] Generate clickable links to resource inspector in RDTreeWidget --- qrenderdoc/Code/CaptureContext.cpp | 9 +- qrenderdoc/Code/CaptureContext.h | 2 + qrenderdoc/Code/Interface/QRDInterface.cpp | 13 + qrenderdoc/Code/Interface/QRDInterface.h | 28 ++ qrenderdoc/Code/QRDUtils.cpp | 14 +- qrenderdoc/Code/QRDUtils.h | 4 +- qrenderdoc/Widgets/Extended/RDTreeWidget.cpp | 441 +++++++++++++++++- qrenderdoc/Widgets/Extended/RDTreeWidget.h | 31 ++ qrenderdoc/Windows/APIInspector.cpp | 2 +- qrenderdoc/Windows/MainWindow.cpp | 2 + .../D3D11PipelineStateViewer.cpp | 57 +-- .../D3D12PipelineStateViewer.cpp | 39 +- .../PipelineState/GLPipelineStateViewer.cpp | 79 ++-- .../VulkanPipelineStateViewer.cpp | 54 +-- qrenderdoc/Windows/PythonShell.cpp | 1 + qrenderdoc/Windows/ResourceInspector.cpp | 6 +- 16 files changed, 611 insertions(+), 171 deletions(-) diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index 8c052e6f6..424ff4a4d 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -626,7 +626,7 @@ void CaptureContext::AddMessages(const rdcarray &msgs) QString CaptureContext::GetResourceName(ResourceId id) { if(id == ResourceId()) - return tr("{No Resource}"); + return tr("No Resource"); if(m_CustomNames.contains(id)) return m_CustomNames[id]; @@ -672,9 +672,16 @@ void CaptureContext::SetResourceCustomName(ResourceId id, const QString &name) m_CustomNames[id] = name; } + m_CustomNameCachedID++; + RefreshUIStatus({}, true, true); } +int CaptureContext::ResourceNameCacheID() +{ + return m_CustomNameCachedID; +} + void *CaptureContext::FillWindowingData(uintptr_t widget) { #if defined(WIN32) diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index 7f44c2eaa..89a2319c9 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -120,6 +120,7 @@ public: bool IsAutogeneratedName(ResourceId id) override; bool HasResourceCustomName(ResourceId id) override; void SetResourceCustomName(ResourceId id, const QString &name) override; + int ResourceNameCacheID() override; 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]; } @@ -283,6 +284,7 @@ private: rdcarray m_ResourceList; QMap m_CustomNames; + int m_CustomNameCachedID = 1; const SDFile *m_StructuredFile; SDFile m_DummySDFile; diff --git a/qrenderdoc/Code/Interface/QRDInterface.cpp b/qrenderdoc/Code/Interface/QRDInterface.cpp index a6cfbaecf..2faefc305 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.cpp +++ b/qrenderdoc/Code/Interface/QRDInterface.cpp @@ -131,3 +131,16 @@ QString ConfigFilePath(const QString &filename) return QDir::cleanPath(dir.absoluteFilePath(filename)); } + +ICaptureContext *getCaptureContext(QWidget *widget) +{ + void *ctxptr = NULL; + + while(widget && !ctxptr) + { + ctxptr = widget->property("ICaptureContext").value(); + widget = widget->parentWidget(); + } + + return (ICaptureContext *)ctxptr; +} diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 067f78ede..a35a1ef8a 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -1107,6 +1107,20 @@ name fetched from the capture. )"); virtual void SetResourceCustomName(ResourceId id, const QString &name) = 0; + DOCUMENT(R"(Returns an index that can be used to cache the results of resource naming. + +In some cases (e.g. formatting in widgets) there might be high frequency fetches to names without an +easy way to force a refresh on a rename. Instead, the index here can be cached and compared each +time to see if any names have changed. + +The index starts at 1, so initialising an internal cache to 0 will cause the first check to be +considered out of date + +:return: An incrementing index that can be used as a quick check if any names have changed. +:rtype: int +)"); + virtual int ResourceNameCacheID() = 0; + DOCUMENT(R"(Retrieve the information about a particular texture. :param ~renderdoc.ResourceId id: The ID of the texture to query about. @@ -1594,3 +1608,17 @@ protected: }; DECLARE_REFLECTION_STRUCT(ICaptureContext); + +DOCUMENT(R"(Attempt to retrieve the capture context for a particular widget. + +This will search up the widget heirarchy to find if a capture context is associated with this widget +or any of its parents. Mostly useful from within widget code where a capture context can't be +explicitly passed in. + +This may return ``None`` if no capture context can be found. + +:param QWidget widget: The widget to search from. +:return: The capture context associated with this widget, if one unambiguously exists. +:rtype: CaptureContext +)"); +ICaptureContext *getCaptureContext(QWidget *widget); \ No newline at end of file diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp index b33f1276f..48ad10d27 100644 --- a/qrenderdoc/Code/QRDUtils.cpp +++ b/qrenderdoc/Code/QRDUtils.cpp @@ -55,7 +55,9 @@ std::string DoStringise(const uint32_t &el) template <> std::string DoStringise(const ResourceId &el) { - return QString::number((const uint64_t &)el).toStdString(); + uint64_t num; + memcpy(&num, &el, sizeof(num)); + return lit("resourceid::%1").arg(num).toStdString(); } #include "renderdoc_tostr.inl" @@ -359,8 +361,8 @@ void CombineUsageEvents(ICaptureContext &ctx, const rdcarray &usage, callback(start, end, us); } -void addStructuredObjects(ICaptureContext &ctx, RDTreeWidgetItem *parent, - const StructuredObjectList &objs, bool parentIsArray) +void addStructuredObjects(RDTreeWidgetItem *parent, const StructuredObjectList &objs, + bool parentIsArray) { for(const SDObject *obj : objs) { @@ -388,7 +390,7 @@ void addStructuredObjects(ICaptureContext &ctx, RDTreeWidgetItem *parent, static_assert(sizeof(id) == sizeof(obj->data.basic.u), "ResourceId is no longer uint64_t!"); memcpy(&id, &obj->data.basic.u, sizeof(id)); - param = ctx.GetResourceName(id); + param = id; } else if(obj->type.flags & SDTypeFlags::NullString) { @@ -405,11 +407,11 @@ void addStructuredObjects(ICaptureContext &ctx, RDTreeWidgetItem *parent, case SDBasic::Chunk: case SDBasic::Struct: param = QFormatStr("%1()").arg(obj->type.name); - addStructuredObjects(ctx, item, obj->data.children, false); + addStructuredObjects(item, obj->data.children, false); break; case SDBasic::Array: param = QFormatStr("%1[]").arg(obj->type.name); - addStructuredObjects(ctx, item, obj->data.children, true); + addStructuredObjects(item, obj->data.children, true); break; case SDBasic::Null: param = lit("NULL"); break; case SDBasic::Buffer: param = lit("(%1 bytes)").arg(obj->type.byteSize); break; diff --git a/qrenderdoc/Code/QRDUtils.h b/qrenderdoc/Code/QRDUtils.h index 0fd45502b..899431b81 100644 --- a/qrenderdoc/Code/QRDUtils.h +++ b/qrenderdoc/Code/QRDUtils.h @@ -104,8 +104,8 @@ void CombineUsageEvents( class RDTreeWidgetItem; -void addStructuredObjects(ICaptureContext &ctx, RDTreeWidgetItem *parent, - const StructuredObjectList &objs, bool parentIsArray); +void addStructuredObjects(RDTreeWidgetItem *parent, const StructuredObjectList &objs, + bool parentIsArray); struct Formatter { diff --git a/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp b/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp index 4a72f3868..9b42f913b 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp +++ b/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "RDTreeWidget.h" +#include #include #include #include @@ -32,8 +33,115 @@ #include #include #include +#include +#include +#include #include #include "Code/Interface/QRDInterface.h" +#include "Code/Resources.h" + +// this is used often, so cache it +QRegularExpression &ResourceIdRegexp() +{ + static QRegularExpression re(lit("(resourceid::)([0-9]*)")); + return re; +} + +struct ResourceIdLinkedText +{ + QVector fragments; + + // cached formatted document. We use cacheId to check if it needs to be updated + QTextDocument doc; + int cacheId = 0; + + // a plain-text version of the document, suitable for e.g. copy-paste + QString text; + + void cacheDocument(QWidget *widget) + { + ICaptureContext *ctxptr = getCaptureContext(widget); + + if(!ctxptr) + return; + + ICaptureContext &ctx = *(ICaptureContext *)ctxptr; + + int refCache = ctx.ResourceNameCacheID(); + + if(cacheId == refCache) + return; + + cacheId = refCache; + + // use a table to ensure images don't screw up the baseline for text. DON'T JUDGE ME. + QString html = lit(""); + + int i = 0; + + QVector fragmentIndexFromBlockIndex; + + // there's an empty block at the start. + fragmentIndexFromBlockIndex.push_back(-1); + + for(const QVariant &v : fragments) + { + if(v.userType() == qMetaTypeId()) + { + html += lit("") + .arg(ctx.GetResourceName(v.value())); + + // these generate two blocks (one for each cell) + fragmentIndexFromBlockIndex.push_back(i); + fragmentIndexFromBlockIndex.push_back(i); + } + else + { + html += lit("").arg(v.toString()); + + // this only generates one block + fragmentIndexFromBlockIndex.push_back(i); + } + + i++; + } + + // there's another empty block at the end + fragmentIndexFromBlockIndex.push_back(-1); + + html += lit("
%1%1
"); + + doc.setDocumentMargin(0); + doc.setHtml(html); + + if(doc.blockCount() != fragmentIndexFromBlockIndex.count()) + { + qCritical() << "Block count is not what's expected!" << doc.blockCount() + << fragmentIndexFromBlockIndex.count(); + + for(i = 0; i < doc.blockCount(); i++) + doc.findBlockByNumber(i).setUserState(-1); + + return; + } + + for(i = 0; i < doc.blockCount(); i++) + doc.findBlockByNumber(i).setUserState(fragmentIndexFromBlockIndex[i]); + + text = doc.toPlainText(); + // "Embedded objects, such as images, are represented by a Unicode value U+FFFC (OBJECT + // REPLACEMENT CHARACTER)." + text.remove(QChar(0xfffc)); + text = text.trimmed(); + } +}; + +// using QSharedPointer here since the lifetime management of these objects would get quite +// complicated, and there is no obvious QObject parent to assign to. The alternative would be to +// have the RDTreeWidgetItem track pointers in and out of the QVariant text +typedef QSharedPointer ResourceIdLinkedTextPtr; + +Q_DECLARE_METATYPE(ResourceIdLinkedTextPtr); class RDTreeWidgetModel : public QAbstractItemModel { @@ -165,13 +273,12 @@ public: RDTreeWidgetItem *item = itemForIndex(index); // invisible root element has no data - if(!item->m_parent) + if(!item->m_parent || index.column() >= item->m_text.count()) return QVariant(); if(role == Qt::DisplayRole) { - if(index.column() < item->m_text.count()) - return item->m_text[index.column()]; + return item->m_text[index.column()]; } else if(role == Qt::DecorationRole) { @@ -183,8 +290,7 @@ public: return widget->m_normalHoverIcon; } - if(index.column() < item->m_icons.count()) - return item->m_icons[index.column()]; + return item->m_icons[index.column()]; } else if(role == Qt::BackgroundRole) { @@ -311,12 +417,63 @@ RDTreeWidgetItem::RDTreeWidgetItem(const QVariantList &values) for(const QVariant &v : values) m_text.push_back(v); m_icons.resize(m_text.size()); + + for(int i = 0; i < m_text.count(); i++) + checkForResourceId(i); } RDTreeWidgetItem::RDTreeWidgetItem(const std::initializer_list &values) { m_text = values; m_icons.resize(m_text.size()); + + for(int i = 0; i < m_text.count(); i++) + checkForResourceId(i); +} + +void RDTreeWidgetItem::checkForResourceId(int col) +{ + QRegularExpression &re = ResourceIdRegexp(); + + QVariant &v = m_text[col]; + + if(v.userType() == qMetaTypeId() || re.match(v.toString()).hasMatch()) + { + QString text; + if(v.userType() == qMetaTypeId()) + text = ToQStr(v.value()); + else + text = v.toString(); + + ResourceIdLinkedTextPtr linkedText(new ResourceIdLinkedText); + + // use regexp to split up into fragments of text and resourceid. The resourceid is then + // formatted on the fly in ResourceIdLinkedText::cacheDocument + QRegularExpressionMatch match = re.match(text); + while(match.hasMatch()) + { + qulonglong idnum = match.captured(2).toULongLong(); + ResourceId id; + memcpy(&id, &idnum, sizeof(id)); + + // push any text that preceeded the ResourceId. + if(match.capturedStart(1) > 0) + linkedText->fragments.push_back(text.left(match.capturedStart(1))); + + text.remove(0, match.capturedEnd(2)); + + linkedText->fragments.push_back(id); + + match = re.match(text); + } + + if(!text.isEmpty()) + linkedText->fragments.push_back(text); + + linkedText->doc.setHtml(text); + + v = QVariant::fromValue(linkedText); + } } RDTreeWidgetItem::~RDTreeWidgetItem() @@ -424,6 +581,10 @@ void RDTreeWidgetItem::setWidget(RDTreeWidget *widget) if(widget == m_widget) return; + QWidget *parent = widget; + while(parent) + parent = parent->parentWidget(); + // if the widget is different, we need to recurse to children m_widget = widget; for(RDTreeWidgetItem *item : m_children) @@ -525,11 +686,236 @@ RDTreeWidgetItemIterator &RDTreeWidgetItemIterator::operator++() return *this; } +RDTreeWidgetDelegate::RDTreeWidgetDelegate(RDTreeWidget *parent) + : m_widget(parent), ForwardingDelegate(parent) +{ +} + +RDTreeWidgetDelegate::~RDTreeWidgetDelegate() +{ +} + +void RDTreeWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + RDTreeWidgetModel *model = m_widget->m_model; + if(model == index.model()) + { + RDTreeWidgetItem *item = model->itemForIndex(index); + + if(item->m_text[index.column()].userType() == qMetaTypeId()) + { + { + // draw the item without text, so we get the proper background/selection/etc. + QStyleOptionViewItem opt = option; + opt.text.clear(); + + ForwardingDelegate::paint(painter, opt, index); + } + + ResourceIdLinkedTextPtr linkedText = + item->m_text[index.column()].value(); + + painter->save(); + + painter->translate(option.rect.left(), option.rect.top()); + + linkedText->cacheDocument(m_widget); + linkedText->doc.setTextWidth(option.rect.width()); + linkedText->doc.drawContents(painter); + + if(option.state & QStyle::State_MouseOver) + { + painter->setPen(QPen(option.palette.brush(QPalette::WindowText), 1.0)); + + QAbstractTextDocumentLayout *layout = linkedText->doc.documentLayout(); + + QPoint p = m_widget->viewport()->mapFromGlobal(QCursor::pos()); + p -= option.rect.topLeft(); + + int pos = layout->hitTest(p, Qt::FuzzyHit); + + if(pos >= 0) + { + QTextBlock block = linkedText->doc.findBlock(pos); + + int frag = block.userState(); + if(frag >= 0) + { + QVariant v = linkedText->fragments[frag]; + if(v.userType() == qMetaTypeId() && v.value() != ResourceId()) + { + layout->blockBoundingRect(block); + QRectF rect = layout->blockBoundingRect(block); + + if(block.previous().userState() == frag) + { + rect = rect.united(layout->blockBoundingRect(block.previous())); + } + + if(block.next().userState() == frag) + { + rect = rect.united(layout->blockBoundingRect(block.next())); + } + + rect.translate(0.0, -2.0); + + painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + } + } + } + } + + painter->restore(); + return; + } + } + else + { + qCritical() << "Unexpected model being passed to RDTreeWidgetDelegate!"; + } + + return ForwardingDelegate::paint(painter, option, index); +} + +QSize RDTreeWidgetDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if(index.isValid()) + { + RDTreeWidgetModel *model = m_widget->m_model; + if(model == index.model()) + { + RDTreeWidgetItem *item = model->itemForIndex(index); + + if(item->m_text[index.column()].userType() == qMetaTypeId()) + { + ResourceIdLinkedTextPtr linkedText = + item->m_text[index.column()].value(); + + linkedText->cacheDocument(m_widget); + return QSize(linkedText->doc.idealWidth(), option.fontMetrics.height()); + } + } + else + { + qCritical() << "Unexpected model being passed to RDTreeWidgetDelegate!"; + } + } + + return ForwardingDelegate::sizeHint(option, index); +} + +bool RDTreeWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, + const QStyleOptionViewItem &option, const QModelIndex &index) +{ + if(event->type() == QEvent::MouseButtonRelease && index.isValid()) + { + RDTreeWidgetModel *rdmodel = m_widget->m_model; + if(rdmodel == model) + { + RDTreeWidgetItem *item = rdmodel->itemForIndex(index); + + if(item->m_text[index.column()].userType() == qMetaTypeId()) + { + ResourceIdLinkedTextPtr linkedText = + item->m_text[index.column()].value(); + + linkedText->cacheDocument(m_widget); + + QAbstractTextDocumentLayout *layout = linkedText->doc.documentLayout(); + + QPoint p = ((QMouseEvent *)event)->pos(); + p -= option.rect.topLeft(); + + int pos = layout->hitTest(p, Qt::FuzzyHit); + + if(pos >= 0) + { + QTextBlock block = linkedText->doc.findBlock(pos); + + int frag = block.userState(); + if(frag >= 0) + { + QVariant v = linkedText->fragments[frag]; + if(v.userType() == qMetaTypeId() && v.value() != ResourceId()) + { + ICaptureContext *ctxptr = getCaptureContext(m_widget); + + if(ctxptr) + { + ICaptureContext &ctx = *(ICaptureContext *)ctxptr; + + if(!ctx.HasResourceInspector()) + ctx.ShowResourceInspector(); + + ctx.GetResourceInspector()->Inspect(v.value()); + + ctx.RaiseDockWindow(ctx.GetResourceInspector()->Widget()); + } + } + } + } + + return true; + } + } + else + { + qCritical() << "Unexpected model being passed to RDTreeWidgetDelegate!"; + } + } + + return ForwardingDelegate::editorEvent(event, model, option, index); +} + +bool RDTreeWidgetDelegate::linkHover(QMouseEvent *e, const QModelIndex &index) +{ + if(index.isValid()) + { + RDTreeWidgetItem *item = m_widget->m_model->itemForIndex(index); + + if(item->m_text[index.column()].userType() == qMetaTypeId()) + { + ResourceIdLinkedTextPtr linkedText = + item->m_text[index.column()].value(); + + linkedText->cacheDocument(m_widget); + + QAbstractTextDocumentLayout *layout = linkedText->doc.documentLayout(); + + QPoint p = e->pos(); + p -= m_widget->visualRect(index).topLeft(); + + int pos = layout->hitTest(p, Qt::FuzzyHit); + + if(pos >= 0) + { + QTextBlock block = linkedText->doc.findBlock(pos); + + int frag = block.userState(); + if(frag >= 0) + { + QVariant v = linkedText->fragments[frag]; + if(v.userType() == qMetaTypeId() && v.value() != ResourceId()) + { + return true; + } + } + } + } + } + + return false; +} + RDTreeWidget::RDTreeWidget(QWidget *parent) : RDTreeView(parent) { // we'll call this ourselves in drawBranches() RDTreeView::enableBranchRectFill(false); + m_delegate = new RDTreeWidgetDelegate(this); + RDTreeView::setItemDelegate(m_delegate); + header()->setSectionsMovable(false); m_root = new RDTreeWidgetItem; @@ -610,6 +996,17 @@ void RDTreeWidget::setColumnAlignment(int column, Qt::Alignment align) m_alignments[column] = align; } +void RDTreeWidget::setItemDelegate(QAbstractItemDelegate *delegate) +{ + m_userDelegate = delegate; + m_delegate->setForwardDelegate(m_userDelegate); +} + +QAbstractItemDelegate *RDTreeWidget::itemDelegate() const +{ + return m_userDelegate; +} + void RDTreeWidget::setColumns(const QStringList &columns) { m_headers = columns; @@ -710,9 +1107,18 @@ void RDTreeWidget::mouseMoveEvent(QMouseEvent *e) RDTreeWidgetItem *newHover = m_model->itemForIndex(m_currentHoverIndex); if(m_currentHoverIndex.column() == m_hoverColumn && m_hoverHandCursor) + { setCursor(QCursor(Qt::PointingHandCursor)); + } + else if(m_delegate->linkHover(e, m_currentHoverIndex)) + { + m_model->itemChanged(m_model->itemForIndex(m_currentHoverIndex), {Qt::DecorationRole}); + setCursor(QCursor(Qt::PointingHandCursor)); + } else + { unsetCursor(); + } if(oldHover == newHover) return; @@ -810,7 +1216,17 @@ void RDTreeWidget::keyPressEvent(QKeyEvent *e) RDTreeWidgetItem *item = m_model->itemForIndex(idx); for(int i = 0; i < qMin(colCount, item->m_text.count()); i++) - widths[i] = qMax(widths[i], item->m_text[i].toString().count()); + { + QString text = item->m_text[i].toString(); + if(item->m_text[i].userType() == qMetaTypeId()) + { + ResourceIdLinkedTextPtr linkedText = item->m_text[i].value(); + linkedText->cacheDocument(this); + text = linkedText->text; + } + + widths[i] = qMax(widths[i], text.count()); + } } // only align up to 50 characters so one really long item doesn't mess up the whole thing @@ -825,7 +1241,16 @@ void RDTreeWidget::keyPressEvent(QKeyEvent *e) for(int i = 0; i < qMin(colCount, item->m_text.count()); i++) { QString format = i == 0 ? QFormatStr("%1") : QFormatStr(" %1"); - clipData += format.arg(item->m_text[i].toString(), -widths[i]); + + QString text = item->m_text[i].toString(); + if(item->m_text[i].userType() == qMetaTypeId()) + { + ResourceIdLinkedTextPtr linkedText = item->m_text[i].value(); + linkedText->cacheDocument(this); + text = linkedText->text; + } + + clipData += format.arg(text, -widths[i]); } clipData += lit("\n"); @@ -1003,4 +1428,4 @@ void RDTreeWidget::endAddChild(RDTreeWidgetItem *item) // work is all done in beginAddChild if(!m_queueUpdates) m_model->endAddChild(item); -} +} \ No newline at end of file diff --git a/qrenderdoc/Widgets/Extended/RDTreeWidget.h b/qrenderdoc/Widgets/Extended/RDTreeWidget.h index 9c3707977..6e063fc4d 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeWidget.h +++ b/qrenderdoc/Widgets/Extended/RDTreeWidget.h @@ -103,6 +103,7 @@ public: } m_text[column] = value; + checkForResourceId(column); dataChanged(column, Qt::DisplayRole); } inline void setToolTip(const QString &value) @@ -122,8 +123,11 @@ public: } private: + void checkForResourceId(int column); + friend class RDTreeWidget; friend class RDTreeWidgetModel; + friend class RDTreeWidgetDelegate; void setWidget(RDTreeWidget *widget); RDTreeWidget *m_widget = NULL; @@ -190,6 +194,26 @@ private: RDTreeWidgetItem *m_Current; }; +class RDTreeWidgetDelegate : public ForwardingDelegate +{ + Q_OBJECT +public: + explicit RDTreeWidgetDelegate(RDTreeWidget *parent); + ~RDTreeWidgetDelegate(); + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + + bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, + const QModelIndex &index) override; + + bool linkHover(QMouseEvent *e, const QModelIndex &index); + +private: + RDTreeWidget *m_widget; +}; + class RDTreeWidget : public RDTreeView { Q_OBJECT @@ -225,6 +249,9 @@ public: void endUpdate(); void setColumnAlignment(int column, Qt::Alignment align); + void setItemDelegate(QAbstractItemDelegate *delegate); + QAbstractItemDelegate *itemDelegate() const; + void setColumns(const QStringList &columns); QString headerText(int column) const { return m_headers[column]; } void setHeaderText(int column, const QString &text); @@ -275,12 +302,16 @@ private: friend class RDTreeWidgetModel; friend class RDTreeWidgetItem; + friend class RDTreeWidgetDelegate; // invisible root item, used to simplify recursion by even top-level items having a parent RDTreeWidgetItem *m_root; RDTreeWidgetModel *m_model; + QAbstractItemDelegate *m_userDelegate = NULL; + RDTreeWidgetDelegate *m_delegate; + bool m_clearing = false; QStringList m_headers; diff --git a/qrenderdoc/Windows/APIInspector.cpp b/qrenderdoc/Windows/APIInspector.cpp index cac46b923..d9aa7cf9f 100644 --- a/qrenderdoc/Windows/APIInspector.cpp +++ b/qrenderdoc/Windows/APIInspector.cpp @@ -146,7 +146,7 @@ void APIInspector::fillAPIView() root->setText(1, chunk->name); - addStructuredObjects(m_Ctx, root, chunk->data.children, false); + addStructuredObjects(root, chunk->data.children, false); } else { diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index 172fcd5d0..9d5bae6a3 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -59,6 +59,8 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai { ui->setupUi(this); + setProperty("ICaptureContext", QVariant::fromValue((void *)&ctx)); + #if !defined(Q_OS_WIN32) // process injection is not supported on non-Windows, so remove the menu item rather than disable // it without a clear way to communicate that it is never supported diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index 398655f2c..bbb16adbd 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -606,12 +606,10 @@ void D3D11PipelineStateViewer::addResourceRow(const D3D11ViewTag &view, uint32_t w = 1, h = 1, d = 1; uint32_t a = 1; QString format = tr("Unknown"); - QString name = m_Ctx.GetResourceName(r.Resource); QString typeName = tr("Unknown"); if(!filledSlot) { - name = tr("Empty"); format = lit("-"); typeName = lit("-"); w = h = d = a = 0; @@ -689,6 +687,11 @@ void D3D11PipelineStateViewer::addResourceRow(const D3D11ViewTag &view, viewDetails = true; } + QVariant name = r.Resource; + + if(viewDetails) + name = tr("%1 viewed by %2").arg(ToQStr(r.Resource)).arg(ToQStr(r.Object)); + RDTreeWidgetItem *node = new RDTreeWidgetItem({slotname, name, typeName, w, h, d, a, format, QString()}); @@ -924,8 +927,6 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL if(shaderInput && !shaderInput->name.empty()) slotname += lit(": ") + shaderInput->name; - QString sampName = m_Ctx.GetResourceName(s.Samp); - QString borderColor = QFormatStr("%1, %2, %3, %4") .arg(s.BorderColor[0]) .arg(s.BorderColor[1]) @@ -974,7 +975,7 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL filter = QFormatStr(" (%1)").arg(ToQStr(s.Filter.func)); RDTreeWidgetItem *node = new RDTreeWidgetItem( - {slotname, sampName, addressing, filter, + {slotname, s.Samp, addressing, filter, QFormatStr("%1 - %2") .arg(s.MinLOD == -FLT_MAX ? lit("0") : QString::number(s.MinLOD)) .arg(s.MaxLOD == FLT_MAX ? lit("FLT_MAX") : QString::number(s.MaxLOD)), @@ -1025,17 +1026,10 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL if(showNode(usedSlot, filledSlot)) { - QString name = m_Ctx.GetResourceName(b.Buffer); - ulong length = 1; + ulong length = 0; int numvars = shaderCBuf ? shaderCBuf->variables.count() : 0; uint32_t bytesize = shaderCBuf ? shaderCBuf->byteSize : 0; - if(!filledSlot) - { - name = tr("Empty"); - length = 0; - } - BufferDescription *buf = m_Ctx.GetBuffer(b.Buffer); if(buf) @@ -1058,7 +1052,8 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL QString vecrange = QFormatStr("%1 - %2").arg(b.VecOffset).arg(b.VecOffset + b.VecCount); - RDTreeWidgetItem *node = new RDTreeWidgetItem({slotname, name, vecrange, sizestr, QString()}); + RDTreeWidgetItem *node = + new RDTreeWidgetItem({slotname, b.Buffer, vecrange, sizestr, QString()}); node->setTag(QVariant::fromValue(i)); @@ -1293,20 +1288,16 @@ void D3D11PipelineStateViewer::setState() { if(ibufferUsed || ui->showDisabled->isChecked()) { - QString name = m_Ctx.GetResourceName(state.m_IA.ibuffer.Buffer); - uint64_t length = 1; - - if(!ibufferUsed) - length = 0; + uint64_t length = 0; BufferDescription *buf = m_Ctx.GetBuffer(state.m_IA.ibuffer.Buffer); if(buf) length = buf->length; - RDTreeWidgetItem *node = - new RDTreeWidgetItem({tr("Index"), name, draw ? draw->indexByteWidth : 0, - state.m_IA.ibuffer.Offset, (qulonglong)length, QString()}); + RDTreeWidgetItem *node = new RDTreeWidgetItem( + {tr("Index"), state.m_IA.ibuffer.Buffer, draw ? draw->indexByteWidth : 0, + state.m_IA.ibuffer.Offset, (qulonglong)length, QString()}); node->setTag(QVariant::fromValue( D3D11VBIBTag(state.m_IA.ibuffer.Buffer, draw ? draw->indexOffset : 0))); @@ -1350,14 +1341,7 @@ void D3D11PipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - QString name = m_Ctx.GetResourceName(v.Buffer); - qulonglong length = 1; - - if(!filledSlot) - { - name = tr("Empty"); - length = 0; - } + qulonglong length = 0; BufferDescription *buf = m_Ctx.GetBuffer(v.Buffer); if(buf) @@ -1366,7 +1350,7 @@ void D3D11PipelineStateViewer::setState() RDTreeWidgetItem *node = NULL; if(filledSlot) - node = new RDTreeWidgetItem({i, name, v.Stride, v.Offset, length, QString()}); + node = new RDTreeWidgetItem({i, v.Buffer, v.Stride, v.Offset, length, QString()}); else node = new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); @@ -1447,20 +1431,13 @@ void D3D11PipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - QString name = m_Ctx.GetResourceName(s.Buffer); qulonglong length = 0; - - if(!filledSlot) - { - name = tr("Empty"); - } - BufferDescription *buf = m_Ctx.GetBuffer(s.Buffer); - if(buf && length == 0) + if(buf) length = buf->length; - RDTreeWidgetItem *node = new RDTreeWidgetItem({i, name, length, s.Offset, QString()}); + RDTreeWidgetItem *node = new RDTreeWidgetItem({i, s.Buffer, length, s.Offset, QString()}); node->setTag(QVariant::fromValue(s.Buffer)); diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 2c69853e4..b63066828 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -683,12 +683,10 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, uint32_t w = 1, h = 1, d = 1; uint32_t a = 1; QString format = tr("Unknown"); - QString name = m_Ctx.GetResourceName(r.Resource); QString typeName = tr("Unknown"); if(!filledSlot) { - name = tr("Empty"); format = lit("-"); typeName = lit("-"); w = h = d = a = 0; @@ -760,7 +758,7 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, } RDTreeWidgetItem *node = new RDTreeWidgetItem( - {rootel, view.space, regname, name, typeName, w, h, d, a, format, QString()}); + {rootel, view.space, regname, r.Resource, typeName, w, h, d, a, format, QString()}); node->setTag(QVariant::fromValue(view)); @@ -1140,7 +1138,6 @@ void D3D12PipelineStateViewer::setShaderState(const D3D12Pipe::Shader &stage, QL if(showNode(usedSlot, filledSlot)) { - QString name = m_Ctx.GetResourceName(b.Buffer); ulong length = b.ByteSize; uint64_t offset = b.Offset; int numvars = shaderCBuf ? shaderCBuf->variables.count() : 0; @@ -1149,9 +1146,6 @@ void D3D12PipelineStateViewer::setShaderState(const D3D12Pipe::Shader &stage, QL if(b.Immediate && !b.RootValues.empty()) bytesize = uint32_t(b.RootValues.count() * 4); - if(!filledSlot) - name = tr("Empty"); - QString regname = QString::number(reg); if(shaderCBuf && !shaderCBuf->name.empty()) @@ -1168,7 +1162,7 @@ void D3D12PipelineStateViewer::setShaderState(const D3D12Pipe::Shader &stage, QL filledSlot = false; RDTreeWidgetItem *node = new RDTreeWidgetItem( - {rootel, (qulonglong)space, regname, name, (qulonglong)offset, sizestr, QString()}); + {rootel, (qulonglong)space, regname, b.Buffer, (qulonglong)offset, sizestr, QString()}); node->setTag(tag); @@ -1292,11 +1286,7 @@ void D3D12PipelineStateViewer::setState() { if(ibufferUsed || ui->showDisabled->isChecked()) { - QString name = m_Ctx.GetResourceName(state.m_IA.ibuffer.Buffer); - uint64_t length = 1; - - if(!ibufferUsed) - length = 0; + uint64_t length = 0; BufferDescription *buf = m_Ctx.GetBuffer(state.m_IA.ibuffer.Buffer); @@ -1304,7 +1294,7 @@ void D3D12PipelineStateViewer::setState() length = buf->length; RDTreeWidgetItem *node = new RDTreeWidgetItem( - {tr("Index"), name, draw ? draw->indexByteWidth : 0, + {tr("Index"), state.m_IA.ibuffer.Buffer, draw ? draw->indexByteWidth : 0, (qulonglong)state.m_IA.ibuffer.Offset, (qulonglong)length, QString()}); node->setTag(QVariant::fromValue( @@ -1349,14 +1339,7 @@ void D3D12PipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - QString name = m_Ctx.GetResourceName(v.Buffer); - qulonglong length = 1; - - if(!filledSlot) - { - name = tr("Empty"); - length = 0; - } + qulonglong length = 0; BufferDescription *buf = m_Ctx.GetBuffer(v.Buffer); if(buf) @@ -1365,7 +1348,7 @@ void D3D12PipelineStateViewer::setState() RDTreeWidgetItem *node = NULL; if(filledSlot) - node = new RDTreeWidgetItem({i, name, v.Stride, (qulonglong)v.Offset, length, QString()}); + node = new RDTreeWidgetItem({i, v.Buffer, v.Stride, (qulonglong)v.Offset, length, QString()}); else node = new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); @@ -1413,21 +1396,15 @@ void D3D12PipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - QString name = m_Ctx.GetResourceName(s.Buffer); qulonglong length = 0; - if(!filledSlot) - { - name = tr("Empty"); - } - BufferDescription *buf = m_Ctx.GetBuffer(s.Buffer); - if(buf && length == 0) + if(buf) length = buf->length; RDTreeWidgetItem *node = - new RDTreeWidgetItem({i, name, length, (qulonglong)s.Offset, QString()}); + new RDTreeWidgetItem({i, s.Buffer, length, (qulonglong)s.Offset, QString()}); node->setTag(QVariant::fromValue(s.Buffer)); diff --git a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp index f7318d20d..55b5ddd37 100644 --- a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp @@ -652,12 +652,10 @@ void GLPipelineStateViewer::setShaderState(const GLPipe::Shader &stage, QLabel * uint32_t w = 1, h = 1, d = 1; uint32_t a = 1; QString format = lit("Unknown"); - QString name = m_Ctx.GetResourceName(r.Resource); QString typeName = lit("Unknown"); if(!filledSlot) { - name = tr("Empty"); format = lit("-"); typeName = lit("-"); w = h = d = a = 0; @@ -695,7 +693,7 @@ void GLPipelineStateViewer::setShaderState(const GLPipe::Shader &stage, QLabel * } RDTreeWidgetItem *node = - new RDTreeWidgetItem({slotname, name, typeName, w, h, d, a, format, QString()}); + new RDTreeWidgetItem({slotname, r.Resource, typeName, w, h, d, a, format, QString()}); node->setTag(QVariant::fromValue(r.Resource)); @@ -829,7 +827,6 @@ void GLPipelineStateViewer::setShaderState(const GLPipe::Shader &stage, QLabel * if(b) { slotname = QFormatStr("%1: %2").arg(bindPoint).arg(shaderCBuf.name); - name = m_Ctx.GetResourceName(b->Resource); offset = b->Offset; length = b->Size; @@ -852,7 +849,8 @@ void GLPipelineStateViewer::setShaderState(const GLPipe::Shader &stage, QLabel * byterange = QFormatStr("%1 - %2").arg(offset).arg(offset + length); } - RDTreeWidgetItem *node = new RDTreeWidgetItem({slotname, name, byterange, sizestr, QString()}); + RDTreeWidgetItem *node = + new RDTreeWidgetItem({slotname, b->Resource, byterange, sizestr, QString()}); node->setTag(QVariant::fromValue(i)); @@ -927,7 +925,6 @@ void GLPipelineStateViewer::setShaderState(const GLPipe::Shader &stage, QLabel * : readWriteType == GLReadWriteType::SSBO ? tr("SSBO") : tr("Unknown"); QString slotname = QFormatStr("%1: %2").arg(bindPoint).arg(res.name); - QString name = m_Ctx.GetResourceName(id); QString dimensions; QString format = lit("-"); QString access = tr("Read/Write"); @@ -990,13 +987,12 @@ void GLPipelineStateViewer::setShaderState(const GLPipe::Shader &stage, QLabel * if(!filledSlot) { - name = tr("Empty"); dimensions = lit("-"); access = lit("-"); } RDTreeWidgetItem *node = - new RDTreeWidgetItem({binding, slotname, name, dimensions, format, access, QString()}); + new RDTreeWidgetItem({binding, slotname, id, dimensions, format, access, QString()}); node->setTag(tag); @@ -1192,7 +1188,6 @@ void GLPipelineStateViewer::setState() { if(ibufferUsed || showDisabled) { - QString name = m_Ctx.GetResourceName(state.m_VtxIn.ibuffer); uint64_t length = 1; if(!ibufferUsed) @@ -1201,13 +1196,11 @@ void GLPipelineStateViewer::setState() BufferDescription *buf = m_Ctx.GetBuffer(state.m_VtxIn.ibuffer); if(buf) - { length = buf->length; - } - RDTreeWidgetItem *node = - new RDTreeWidgetItem({tr("Element"), name, draw ? draw->indexByteWidth : 0, 0, 0, - (qulonglong)length, QString()}); + RDTreeWidgetItem *node = new RDTreeWidgetItem({tr("Element"), state.m_VtxIn.ibuffer, + draw ? draw->indexByteWidth : 0, 0, 0, + (qulonglong)length, QString()}); node->setTag( QVariant::fromValue(GLVBIBTag(state.m_VtxIn.ibuffer, draw ? draw->indexOffset : 0))); @@ -1251,22 +1244,15 @@ void GLPipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - QString name = m_Ctx.GetResourceName(v.Buffer); - uint64_t length = 1; + uint64_t length = 0; uint64_t offset = v.Offset; - if(!filledSlot) - { - name = tr("Empty"); - length = 0; - } - BufferDescription *buf = m_Ctx.GetBuffer(v.Buffer); if(buf) length = buf->length; RDTreeWidgetItem *node = new RDTreeWidgetItem( - {i, name, v.Stride, (qulonglong)offset, v.Divisor, (qulonglong)length, QString()}); + {i, v.Buffer, v.Stride, (qulonglong)offset, v.Divisor, (qulonglong)length, QString()}); node->setTag(QVariant::fromValue(GLVBIBTag(v.Buffer, v.Offset))); @@ -1311,19 +1297,16 @@ void GLPipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - QString name = m_Ctx.GetResourceName(state.m_Feedback.BufferBinding[i]); qulonglong length = state.m_Feedback.Size[i]; - if(!filledSlot) - name = tr("Empty"); - BufferDescription *buf = m_Ctx.GetBuffer(state.m_Feedback.BufferBinding[i]); - if(buf && length == 0) + if(buf) length = buf->length; - RDTreeWidgetItem *node = new RDTreeWidgetItem( - {i, name, length, (qulonglong)state.m_Feedback.Offset[i], QString()}); + RDTreeWidgetItem *node = + new RDTreeWidgetItem({i, state.m_Feedback.BufferBinding[i], length, + (qulonglong)state.m_Feedback.Offset[i], QString()}); node->setTag(QVariant::fromValue(state.m_Feedback.BufferBinding[i])); @@ -1616,12 +1599,10 @@ void GLPipelineStateViewer::setState() uint32_t w = 1, h = 1, d = 1; uint32_t a = 1; QString format = tr("Unknown"); - QString name = m_Ctx.GetResourceName(p); QString typeName = tr("Unknown"); if(p == ResourceId()) { - name = tr("Empty"); format = lit("-"); typeName = lit("-"); w = h = d = a = 0; @@ -1637,19 +1618,6 @@ void GLPipelineStateViewer::setState() format = tex->format.Name(); typeName = ToQStr(tex->resType); - if(m_Ctx.IsAutogeneratedName(p) && state.m_FS.ShaderDetails) - { - for(int s = 0; s < state.m_FS.ShaderDetails->OutputSig.count(); s++) - { - if(state.m_FS.ShaderDetails->OutputSig[s].regIndex == (uint32_t)db && - (state.m_FS.ShaderDetails->OutputSig[s].systemValue == ShaderBuiltin::Undefined || - state.m_FS.ShaderDetails->OutputSig[s].systemValue == ShaderBuiltin::ColorOutput)) - { - name = QFormatStr("<%1>").arg(state.m_FS.ShaderDetails->OutputSig[s].varName); - } - } - } - if(tex->format.srgbCorrected && !state.m_FB.FramebufferSRGB) format += lit(" (GL_FRAMEBUFFER_SRGB = 0)"); } @@ -1664,8 +1632,23 @@ void GLPipelineStateViewer::setState() .arg(ToQStr(r->Swizzle[3])); } + QString slotname = QString::number(i); + + if(state.m_FS.ShaderDetails) + { + for(int s = 0; s < state.m_FS.ShaderDetails->OutputSig.count(); s++) + { + if(state.m_FS.ShaderDetails->OutputSig[s].regIndex == (uint32_t)db && + (state.m_FS.ShaderDetails->OutputSig[s].systemValue == ShaderBuiltin::Undefined || + state.m_FS.ShaderDetails->OutputSig[s].systemValue == ShaderBuiltin::ColorOutput)) + { + slotname += QFormatStr(": %1").arg(state.m_FS.ShaderDetails->OutputSig[s].varName); + } + } + } + RDTreeWidgetItem *node = - new RDTreeWidgetItem({i, name, typeName, w, h, d, a, format, QString()}); + new RDTreeWidgetItem({i, p, typeName, w, h, d, a, format, QString()}); if(tex) node->setTag(QVariant::fromValue(p)); @@ -1700,12 +1683,10 @@ void GLPipelineStateViewer::setState() uint32_t w = 1, h = 1, d = 1; uint32_t a = 1; QString format = tr("Unknown"); - QString name = m_Ctx.GetResourceName(ds); QString typeName = tr("Unknown"); if(ds == ResourceId()) { - name = tr("Empty"); format = lit("-"); typeName = lit("-"); w = h = d = a = 0; @@ -1736,7 +1717,7 @@ void GLPipelineStateViewer::setState() } RDTreeWidgetItem *node = - new RDTreeWidgetItem({slot, name, typeName, w, h, d, a, format, QString()}); + new RDTreeWidgetItem({slot, ds, typeName, w, h, d, a, format, QString()}); if(tex) node->setTag(QVariant::fromValue(ds)); diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 3bf3ff299..22cb2c0c5 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -653,7 +653,7 @@ QVariantList VulkanPipelineStateViewer::makeSampler(const QString &bindset, cons bindset, slotname, descriptor.immutableSampler ? tr("Immutable Sampler") : tr("Sampler"), - m_Ctx.GetResourceName(descriptor.res), + descriptor.res, addressing, filter + lit(", ") + lod}; } @@ -857,7 +857,6 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, uint32_t samples = 1; uint64_t len = 0; QString format = tr("Unknown"); - QString name = m_Ctx.GetResourceName(descriptorBind->res); TextureDim restype = TextureDim::Unknown; QVariant tag; @@ -906,7 +905,6 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, } else { - name = tr("Empty"); format = lit("-"); w = h = d = a = 0; } @@ -932,7 +930,8 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, range = QFormatStr("%1 - %2").arg(descriptorBind->offset).arg(descriptorLen); node = new RDTreeWidgetItem({ - QString(), bindset, slotname, ToQStr(bindType), name, tr("%1 bytes").arg(len), range, + QString(), bindset, slotname, ToQStr(bindType), descriptorBind->res, + tr("%1 bytes").arg(len), range, }); node->setTag(tag); @@ -1018,7 +1017,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, dim += QFormatStr(", %1x MSAA").arg(samples); node = new RDTreeWidgetItem({ - QString(), bindset, slotname, typeName, name, dim, format, + QString(), bindset, slotname, typeName, descriptorBind->res, dim, format, }); node->setTag(tag); @@ -1185,7 +1184,6 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta slotname = QFormatStr("%1[%2]").arg(bind).arg(idx); } - QString name = m_Ctx.GetResourceName(descriptorBind->res); uint64_t length = 0; int numvars = cblock != NULL ? cblock->variables.count() : 0; uint64_t byteSize = cblock != NULL ? cblock->byteSize : 0; @@ -1206,6 +1204,8 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta QString sizestr; + QVariant name = descriptorBind->res; + // push constants or specialization constants if(cblock != NULL && !cblock->bufferBacked) { @@ -1531,7 +1531,6 @@ void VulkanPipelineStateViewer::setState() { if(ibufferUsed || showDisabled) { - QString name = m_Ctx.GetResourceName(state.IA.ibuffer.buf); uint64_t length = 1; if(!ibufferUsed) @@ -1543,7 +1542,7 @@ void VulkanPipelineStateViewer::setState() length = buf->length; RDTreeWidgetItem *node = new RDTreeWidgetItem( - {tr("Index"), name, tr("Index"), (qulonglong)state.IA.ibuffer.offs, + {tr("Index"), state.IA.ibuffer.buf, tr("Index"), (qulonglong)state.IA.ibuffer.offs, draw != NULL ? draw->indexByteWidth : 0, (qulonglong)length, QString()}); node->setTag(QVariant::fromValue( @@ -1597,7 +1596,6 @@ void VulkanPipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - QString name = tr("No Buffer"); QString rate = lit("-"); uint64_t length = 1; uint64_t offset = 0; @@ -1605,7 +1603,6 @@ void VulkanPipelineStateViewer::setState() if(vbuff != NULL) { - name = m_Ctx.GetResourceName(vbuff->buffer); offset = vbuff->offset; BufferDescription *buf = m_Ctx.GetBuffer(vbuff->buffer); @@ -1620,14 +1617,14 @@ void VulkanPipelineStateViewer::setState() } else { - name += tr(", No Binding"); + rate += tr("No Binding"); } RDTreeWidgetItem *node = NULL; if(filledSlot) node = new RDTreeWidgetItem( - {i, name, rate, (qulonglong)offset, stride, (qulonglong)length, QString()}); + {i, vbuff->buffer, rate, (qulonglong)offset, stride, (qulonglong)length, QString()}); else node = new RDTreeWidgetItem( {i, tr("No Binding"), lit("-"), lit("-"), lit("-"), lit("-"), QString()}); @@ -1783,12 +1780,10 @@ void VulkanPipelineStateViewer::setState() uint32_t w = 1, h = 1, d = 1; uint32_t a = 1; QString format = p.viewfmt.Name(); - QString name = m_Ctx.GetResourceName(p.img); QString typeName = tr("Unknown"); if(p.img == ResourceId()) { - name = tr("Empty"); format = lit("-"); typeName = lit("-"); w = h = d = a = 0; @@ -1802,19 +1797,6 @@ void VulkanPipelineStateViewer::setState() d = tex->depth; a = tex->arraysize; typeName = ToQStr(tex->resType); - - if(m_Ctx.IsAutogeneratedName(p.img) && state.m_FS.ShaderDetails != NULL) - { - for(int s = 0; s < state.m_FS.ShaderDetails->OutputSig.count(); s++) - { - if(state.m_FS.ShaderDetails->OutputSig[s].regIndex == (uint32_t)colIdx && - (state.m_FS.ShaderDetails->OutputSig[s].systemValue == ShaderBuiltin::Undefined || - state.m_FS.ShaderDetails->OutputSig[s].systemValue == ShaderBuiltin::ColorOutput)) - { - name = QFormatStr("<%1>").arg(state.m_FS.ShaderDetails->OutputSig[s].varName); - } - } - } } if(p.swizzle[0] != TextureSwizzle::Red || p.swizzle[1] != TextureSwizzle::Green || @@ -1836,8 +1818,21 @@ void VulkanPipelineStateViewer::setState() else slotname = lit("Depth"); + if(state.m_FS.ShaderDetails != NULL) + { + for(int s = 0; s < state.m_FS.ShaderDetails->OutputSig.count(); s++) + { + if(state.m_FS.ShaderDetails->OutputSig[s].regIndex == (uint32_t)colIdx && + (state.m_FS.ShaderDetails->OutputSig[s].systemValue == ShaderBuiltin::Undefined || + state.m_FS.ShaderDetails->OutputSig[s].systemValue == ShaderBuiltin::ColorOutput)) + { + slotname += QFormatStr(": %1").arg(state.m_FS.ShaderDetails->OutputSig[s].varName); + } + } + } + RDTreeWidgetItem *node = - new RDTreeWidgetItem({slotname, name, typeName, w, h, d, a, format, QString()}); + new RDTreeWidgetItem({slotname, p.img, typeName, w, h, d, a, format, QString()}); if(tex) node->setTag(QVariant::fromValue(p.img)); @@ -2486,7 +2481,6 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe:: int i = 0; for(const VKPipe::VB &vb : vi.vbuffers) { - QString name = m_Ctx.GetResourceName(vb.buffer); uint64_t length = 0; if(vb.buffer == ResourceId()) @@ -2500,7 +2494,7 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe:: length = buf->length; } - rows.push_back({i, name, (qulonglong)vb.offset, (qulonglong)length}); + rows.push_back({i, vb.buffer, (qulonglong)vb.offset, (qulonglong)length}); i++; } diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index d31a463e6..94befc1c6 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -88,6 +88,7 @@ struct CaptureContextInvoker : ICaptureContext { return m_Ctx.HasResourceCustomName(id); } + virtual int ResourceNameCacheID() override { return m_Ctx.ResourceNameCacheID(); } 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); } diff --git a/qrenderdoc/Windows/ResourceInspector.cpp b/qrenderdoc/Windows/ResourceInspector.cpp index f4be4b8af..533979ad6 100644 --- a/qrenderdoc/Windows/ResourceInspector.cpp +++ b/qrenderdoc/Windows/ResourceInspector.cpp @@ -207,7 +207,7 @@ void ResourceInspector::Inspect(ResourceId id) for(ResourceId parent : desc->parentResources) { - RDTreeWidgetItem *item = new RDTreeWidgetItem({tr("Parent"), m_Ctx.GetResourceName(parent)}); + RDTreeWidgetItem *item = new RDTreeWidgetItem({tr("Parent"), parent}); item->setData(0, ResourceIdRole, QVariant::fromValue(parent)); item->setData(1, ResourceIdRole, QVariant::fromValue(parent)); ui->relatedResources->addTopLevelItem(item); @@ -215,7 +215,7 @@ void ResourceInspector::Inspect(ResourceId id) for(ResourceId derived : desc->derivedResources) { - RDTreeWidgetItem *item = new RDTreeWidgetItem({tr("Derived"), m_Ctx.GetResourceName(derived)}); + RDTreeWidgetItem *item = new RDTreeWidgetItem({tr("Derived"), derived}); item->setData(0, ResourceIdRole, QVariant::fromValue(derived)); item->setData(1, ResourceIdRole, QVariant::fromValue(derived)); ui->relatedResources->addTopLevelItem(item); @@ -231,7 +231,7 @@ void ResourceInspector::Inspect(ResourceId id) root->setText(0, chunkObj->name); - addStructuredObjects(m_Ctx, root, chunkObj->data.children, false); + addStructuredObjects(root, chunkObj->data.children, false); } else {