add metadata support to annotationviewer for buffers

This commit is contained in:
Remi Palandri
2026-01-13 15:07:24 +01:00
committed by baldurk
parent ec24a6ca4b
commit aaf19a128c
2 changed files with 189 additions and 4 deletions
+162 -4
View File
@@ -27,14 +27,21 @@
#include <QHeaderView>
#include <QMenu>
#include <QVBoxLayout>
#include "Code/Interface/QRDInterface.h"
#include "Code/QRDUtils.h"
#include "Code/Resources.h"
#include "Extended/RDHeaderView.h"
AnnotationDisplay::AnnotationDisplay(ICaptureContext &ctx, bool standalone, QWidget *parent)
: QFrame(parent), m_Ctx(ctx), m_Standalone(standalone)
{
m_Tree = new RDTreeWidget(this);
m_Header = new RDHeaderView(Qt::Horizontal, this);
m_Tree->setHeader(m_Header);
m_Tree->setColumns({lit("Key"), tr("Value")});
m_Tree->header()->resizeSection(0, 150);
m_Header->setColumnStretchHints({1, 4});
m_Tree->setFont(Formatter::PreferredFont());
QVBoxLayout *layout = new QVBoxLayout(this);
@@ -53,6 +60,12 @@ AnnotationDisplay::AnnotationDisplay(ICaptureContext &ctx, bool standalone, QWid
QObject::connect(m_Tree, &RDTreeWidget::customContextMenu, this,
&AnnotationDisplay::customContextMenu);
QObject::connect(m_Tree, &RDTreeWidget::itemClicked, this, &AnnotationDisplay::itemClicked);
QObject::connect(m_Tree, &RDTreeWidget::hoverItemChanged, this,
&AnnotationDisplay::hoverItemChanged);
m_Tree->viewport()->setAttribute(Qt::WA_Hover);
m_Tree->setMouseTracking(true);
if(m_Standalone)
m_Ctx.AddCaptureViewer(this);
@@ -131,10 +144,52 @@ void AnnotationDisplay::addStructuredChildren(RDTreeWidgetItem *parent, const SD
else
name = obj->name;
RDTreeWidgetItem *item = new RDTreeWidgetItem({name, QString()});
RDTreeWidgetItem *item;
if(m_HasGoColumn)
item = new RDTreeWidgetItem({name, QString(), QString()});
else
item = new RDTreeWidgetItem({name, QString()});
m_Items[obj] = item;
item->setTag(QVariant::fromValue((void *)obj));
// Check if this is a viewable resource (buffer, texture, or shader)
if(obj->type.basetype == SDBasic::Resource)
{
ResourceId id = obj->data.basic.id;
const ResourceDescription *resDesc = m_Ctx.GetResource(id);
if(resDesc && (resDesc->type == ResourceType::Buffer ||
resDesc->type == ResourceType::Texture || resDesc->type == ResourceType::Shader))
{
AnnotationResourceTag tag;
tag.resourceId = id;
tag.resourceType = resDesc->type;
if(resDesc->type == ResourceType::Buffer)
{
// Look for special child annotations for buffer viewer parameters
const SDObject *offsetChild = obj->FindChildByKeyPath("__offset");
const SDObject *sizeChild = obj->FindChildByKeyPath("__size");
const SDObject *formatChild = obj->FindChildByKeyPath("__rd_format");
if(offsetChild && (offsetChild->type.basetype == SDBasic::UnsignedInteger ||
offsetChild->type.basetype == SDBasic::SignedInteger))
tag.bufferOffset = offsetChild->data.basic.u;
if(sizeChild && (sizeChild->type.basetype == SDBasic::UnsignedInteger ||
sizeChild->type.basetype == SDBasic::SignedInteger))
tag.bufferSize = sizeChild->data.basic.u;
if(formatChild && formatChild->type.basetype == SDBasic::String)
tag.bufferFormat = formatChild->data.str;
}
item->setTag(QVariant::fromValue(tag));
if(m_HasGoColumn)
item->setIcon(2, Icons::action());
}
}
if(obj->type.basetype == SDBasic::Chunk || obj->type.basetype == SDBasic::Struct ||
obj->type.basetype == SDBasic::Array)
@@ -146,6 +201,29 @@ void AnnotationDisplay::addStructuredChildren(RDTreeWidgetItem *parent, const SD
}
}
bool AnnotationDisplay::hasResourceAnnotations(const SDObject &obj)
{
if(obj.type.basetype == SDBasic::Resource)
{
const ResourceDescription *resDesc = m_Ctx.GetResource(obj.data.basic.id);
if(resDesc && (resDesc->type == ResourceType::Buffer ||
resDesc->type == ResourceType::Texture || resDesc->type == ResourceType::Shader))
return true;
}
for(const SDObject *child : obj)
{
if(child->type.flags & SDTypeFlags::Hidden)
continue;
if(child->name.beginsWith("__"))
continue;
if(hasResourceAnnotations(*child))
return true;
}
return false;
}
void AnnotationDisplay::setAnnotationObject(const SDObject *annotation)
{
m_Tree->updateExpansion(m_Expansion, 0);
@@ -153,8 +231,23 @@ void AnnotationDisplay::setAnnotationObject(const SDObject *annotation)
m_Annotation = annotation;
m_Items.clear();
m_HoveredItem = NULL;
m_Tree->invisibleRootItem()->clear();
// Check if we have any buffer annotations to determine columns
m_HasGoColumn = m_Annotation && hasResourceAnnotations(*m_Annotation);
if(m_HasGoColumn)
{
m_Tree->setColumns({lit("Key"), tr("Value"), tr("Go")});
m_Header->setColumnStretchHints({1, 4, -1});
}
else
{
m_Tree->setColumns({lit("Key"), tr("Value")});
m_Header->setColumnStretchHints({1, 4});
}
if(m_Annotation)
{
m_Tree->beginUpdate();
@@ -168,7 +261,10 @@ void AnnotationDisplay::setAnnotationObject(const SDObject *annotation)
void AnnotationDisplay::customContextMenu(QModelIndex index, QMenu *menu)
{
RDTreeWidgetItem *item = m_Tree->itemForIndex(index);
const SDObject *obj = (const SDObject *)item->tag().value<void *>();
const SDObject *obj = m_Items.key(item, NULL);
if(!obj)
return;
rdcstr path;
// don't include the root node, it's not part of the path, so only iterate over nodes that have
@@ -194,3 +290,65 @@ void AnnotationDisplay::customContextMenu(QModelIndex index, QMenu *menu)
menu->insertAction(sep, showInEventBrowser);
}
void AnnotationDisplay::itemClicked(RDTreeWidgetItem *item, int column)
{
if(!m_HasGoColumn || column != 2)
return;
QVariant tag = item->tag();
if(!tag.canConvert<AnnotationResourceTag>())
return;
AnnotationResourceTag resTag = tag.value<AnnotationResourceTag>();
if(resTag.resourceType == ResourceType::Buffer)
{
IBufferViewer *viewer = m_Ctx.ViewBuffer(resTag.bufferOffset, resTag.bufferSize,
resTag.resourceId, resTag.bufferFormat);
m_Ctx.AddDockWindow(viewer->Widget(), DockReference::MainToolArea, NULL);
}
else if(resTag.resourceType == ResourceType::Texture)
{
if(!m_Ctx.HasTextureViewer())
m_Ctx.ShowTextureViewer();
ITextureViewer *viewer = m_Ctx.GetTextureViewer();
viewer->ViewTexture(resTag.resourceId, CompType::Typeless, true);
}
else if(resTag.resourceType == ResourceType::Shader)
{
ResourceId id = resTag.resourceId;
ICaptureContext *ctx = &m_Ctx;
m_Ctx.Replay().AsyncInvoke([this, ctx, id](IReplayController *r) {
rdcarray<ShaderEntryPoint> entries = r->GetShaderEntryPoints(id);
if(entries.isEmpty())
return;
const ShaderReflection *refl = r->GetShader(ResourceId(), id, entries[0]);
if(!refl)
return;
GUIInvoke::call(this, [ctx, refl] {
IShaderViewer *viewer = ctx->ViewShader(refl, ResourceId());
ctx->AddDockWindow(viewer->Widget(), DockReference::MainToolArea, NULL);
});
});
}
}
void AnnotationDisplay::hoverItemChanged(RDTreeWidgetItem *item)
{
// Restore normal icon for previously hovered resource item with a Go button
if(m_HoveredItem)
{
m_HoveredItem->setIcon(2, Icons::action());
}
// Set hover icon for newly hovered resource item, if it has a valid tag
if(item && item->tag().canConvert<AnnotationResourceTag>() && m_HasGoColumn)
{
m_HoveredItem = item;
m_HoveredItem->setIcon(2, Icons::action_hover());
}
}
+27
View File
@@ -24,8 +24,24 @@
#pragma once
#include "Extended/RDHeaderView.h"
#include "Extended/RDTreeWidget.h"
struct AnnotationResourceTag
{
AnnotationResourceTag() = default;
ResourceId resourceId;
ResourceType resourceType = ResourceType::Unknown;
// Buffer-specific fields
uint64_t bufferOffset = 0;
uint64_t bufferSize = UINT64_MAX;
rdcstr bufferFormat;
};
Q_DECLARE_METATYPE(AnnotationResourceTag);
// can be used either as an embedded control in the resource inspector, or as a separate panel for
// monitoring API events
class AnnotationDisplay : public QFrame, public IAnnotationViewer, public ICaptureViewer
@@ -50,6 +66,8 @@ public:
private slots:
void customContextMenu(QModelIndex index, QMenu *menu);
void itemClicked(RDTreeWidgetItem *item, int column);
void hoverItemChanged(RDTreeWidgetItem *item);
protected:
@@ -58,15 +76,24 @@ private:
const SDObject *m_Annotation = NULL;
RDTreeWidget *m_Tree;
RDHeaderView *m_Header;
RDTreeViewExpansionState m_Expansion;
// if this is a standalone viewer or not
bool m_Standalone = false;
// whether the Go column is present
bool m_HasGoColumn = false;
// track hovered item for icon changes
RDTreeWidgetItem *m_HoveredItem = NULL;
QMap<const SDObject *, RDTreeWidgetItem *> m_Items;
void addStructuredChildren(RDTreeWidgetItem *parent, const SDObject &parentObj);
bool hasResourceAnnotations(const SDObject &obj);
// either is a non-empty node, or has at least one non-empty child
bool shouldBeDisplayed(const SDObject &obj);
};