Show visible offsets and (optionally) padding in buffers. Closes #1664

This commit is contained in:
baldurk
2022-05-11 13:48:37 +01:00
parent 5ac9de0a20
commit 4bb54d00dd
11 changed files with 494 additions and 109 deletions
+40 -49
View File
@@ -412,8 +412,8 @@ bool BufferFormatter::CheckInvalidUnbounded(const ShaderConstant &structDef, QSt
return true;
}
rdcpair<ShaderConstant, ShaderConstant> BufferFormatter::ParseFormatString(
const QString &formatString, uint64_t maxLen, bool cbuffer, QString &errors)
ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uint64_t maxLen,
bool cbuffer, QString &errors)
{
StructFormatData root;
StructFormatData *cur = &root;
@@ -1615,21 +1615,7 @@ rdcpair<ShaderConstant, ShaderConstant> BufferFormatter::ParseFormatString(
// if we're bitfield packing don't advance offset, otherwise advance to the end of this element
if(bitfieldCurPos == ~0U)
{
// advance by the struct including any trailing padding
cur->offset += GetVarSize(el);
// if we allow trailing overlap in arrays/matrices, remove the padding. This is only possible
// with non-tight arrays
if(pack.trailing_overlap && !pack.tight_arrays &&
(el.type.descriptor.type == VarType::Struct || el.type.descriptor.elements > 1 ||
el.type.descriptor.rows > 1))
{
// the padding is the stride (which is rounded up to 16 for non-tight arrays) minus the size
// of the last vector (whether or not this is an array of scalars, vectors or matrices
cur->offset -= 16 - elSize;
}
}
cur->offset += GetVarAdvance(pack, el);
}
if(bitfieldCurPos != ~0U)
@@ -1834,7 +1820,7 @@ rdcpair<ShaderConstant, ShaderConstant> BufferFormatter::ParseFormatString(
}
}
return {root.structDef, repeat};
return {root.structDef, repeat, pack};
}
QString BufferFormatter::GetTextureFormatString(const TextureDescription &tex)
@@ -2097,7 +2083,7 @@ uint32_t BufferFormatter::GetVarStraddleSize(const ShaderConstant &var)
return VarTypeByteSize(var.type.descriptor.type) * var.type.descriptor.columns;
}
uint32_t BufferFormatter::GetVarSize(const ShaderConstant &var)
uint32_t BufferFormatter::GetVarSizeAndTrail(const ShaderConstant &var)
{
if(var.type.descriptor.elements > 1 && var.type.descriptor.elements != ~0U)
return var.type.descriptor.arrayByteStride * var.type.descriptor.elements;
@@ -2119,6 +2105,37 @@ uint32_t BufferFormatter::GetVarSize(const ShaderConstant &var)
return VarTypeByteSize(var.type.descriptor.type) * var.type.descriptor.columns;
}
uint32_t BufferFormatter::GetVarAdvance(Packing::Rules pack, const ShaderConstant &var)
{
uint32_t ret = GetVarSizeAndTrail(var);
// if we allow trailing overlap, remove the padding at the end of the struct/array
if(pack.trailing_overlap)
{
if(var.type.descriptor.type == VarType::Struct)
{
ret -= (var.type.descriptor.arrayByteStride - GetUnpaddedStructAdvance(pack, var.type.members));
}
else if((var.type.descriptor.elements > 1 || var.type.descriptor.rows > 1) && !pack.tight_arrays)
{
uint8_t vecSize = var.type.descriptor.columns;
if(var.type.descriptor.rows > 1 && var.type.descriptor.ColMajor())
vecSize = var.type.descriptor.rows;
uint32_t elSize = GetAlignment(pack, var);
if(pack.vector_align_component)
elSize *= vecSize;
// the padding is the stride (which is rounded up to 16 for non-tight arrays) minus the size
// of the last vector (whether or not this is an array of scalars, vectors or matrices
ret -= 16 - elSize;
}
}
return ret;
}
uint32_t BufferFormatter::GetAlignment(Packing::Rules pack, const ShaderConstant &c)
{
uint32_t ret = 1;
@@ -2162,7 +2179,8 @@ uint32_t BufferFormatter::GetAlignment(Packing::Rules pack, const ShaderConstant
return ret;
}
uint32_t BufferFormatter::GetUnpaddedStructSize(const rdcarray<ShaderConstant> &members)
uint32_t BufferFormatter::GetUnpaddedStructAdvance(Packing::Rules pack,
const rdcarray<ShaderConstant> &members)
{
uint32_t lastMemberStart = 0;
@@ -2181,7 +2199,7 @@ uint32_t BufferFormatter::GetUnpaddedStructSize(const rdcarray<ShaderConstant> &
lastMemberStart += lastChild->byteOffset;
}
return lastMemberStart + GetVarSize(*lastChild);
return lastMemberStart + GetVarAdvance(pack, *lastChild);
}
QString BufferFormatter::DeclareStruct(Packing::Rules pack, QList<QString> &declaredStructs,
@@ -2204,7 +2222,6 @@ QString BufferFormatter::DeclareStruct(Packing::Rules pack, QList<QString> &decl
{
const uint32_t alignment = GetAlignment(pack, members[i]);
const uint32_t vecsize = GetVarStraddleSize(members[i]);
const uint32_t size = GetVarSize(members[i]);
structAlignment = std::max(structAlignment, alignment);
offset = AlignUp(offset, alignment);
@@ -2233,33 +2250,7 @@ QString BufferFormatter::DeclareStruct(Packing::Rules pack, QList<QString> &decl
offset = members[i].byteOffset;
offset += size;
// if we allow trailing overlap, remove the padding at the end of the struct/array
if(pack.trailing_overlap)
{
if(members[i].type.descriptor.type == VarType::Struct)
{
offset -= (members[i].type.descriptor.arrayByteStride -
GetUnpaddedStructSize(members[i].type.members));
}
else if((members[i].type.descriptor.elements > 1 || members[i].type.descriptor.rows > 1) &&
!pack.tight_arrays)
{
uint8_t vecSize = members[i].type.descriptor.columns;
if(members[i].type.descriptor.rows > 1 && members[i].type.descriptor.ColMajor())
vecSize = members[i].type.descriptor.rows;
uint32_t elSize = GetAlignment(pack, members[i]);
if(pack.vector_align_component)
elSize *= vecSize;
// the padding is the stride (which is rounded up to 16 for non-tight arrays) minus the size
// of the last vector (whether or not this is an array of scalars, vectors or matrices
offset -= 16 - elSize;
}
}
offset += GetVarAdvance(pack, members[i]);
QString arraySize;
if(members[i].type.descriptor.elements > 1)
+12 -5
View File
@@ -175,6 +175,12 @@ struct Rules
}; // namespace Packing
struct ParsedFormat
{
ShaderConstant fixed, repeating;
Packing::Rules packing;
};
struct BufferFormatter
{
private:
@@ -190,8 +196,10 @@ private:
uint32_t requiredByteStride, QString innerSkippedPrefixString);
static uint32_t GetAlignment(Packing::Rules pack, const ShaderConstant &constant);
static uint32_t GetUnpaddedStructSize(const rdcarray<ShaderConstant> &members);
static uint32_t GetUnpaddedStructAdvance(Packing::Rules pack,
const rdcarray<ShaderConstant> &members);
static uint32_t GetVarStraddleSize(const ShaderConstant &var);
static uint32_t GetVarSizeAndTrail(const ShaderConstant &var);
static void EstimatePackingRules(Packing::Rules &pack, const ShaderConstant &constant);
static QString DeclarePacking(Packing::Rules pack);
@@ -200,10 +208,9 @@ public:
BufferFormatter() = default;
static void Init(GraphicsAPI api) { m_API = api; }
static rdcpair<ShaderConstant, ShaderConstant> ParseFormatString(const QString &formatString,
uint64_t maxLen, bool cbuffer,
QString &errors);
static uint32_t GetVarSize(const ShaderConstant &var);
static ParsedFormat ParseFormatString(const QString &formatString, uint64_t maxLen, bool cbuffer,
QString &errors);
static uint32_t GetVarAdvance(Packing::Rules pack, const ShaderConstant &var);
static Packing::Rules EstimatePackingRules(const rdcarray<ShaderConstant> &members);
+1
View File
@@ -30,6 +30,7 @@
#define RESOURCE_LIST() \
RESOURCE_DEF(add, "add.png") \
RESOURCE_DEF(align, "align.png") \
RESOURCE_DEF(arrow_in, "arrow_in.png") \
RESOURCE_DEF(arrow_join, "arrow_join.png") \
RESOURCE_DEF(arrow_left, "arrow_left.png") \
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+2
View File
@@ -17,6 +17,8 @@
<file>action_hover@2x.png</file>
<file>add.png</file>
<file>add@2x.png</file>
<file>align.png</file>
<file>align@2x.png</file>
<file>arrow_in.png</file>
<file>arrow_in@2x.png</file>
<file>arrow_join.png</file>
+395 -48
View File
@@ -34,6 +34,7 @@
#include <QScrollBar>
#include <QSplitter>
#include <QTimer>
#include <QToolTip>
#include <QtMath>
#include "Code/QRDUtils.h"
#include "Code/Resources.h"
@@ -43,6 +44,28 @@
#include "Windows/Dialogs/AxisMappingDialog.h"
#include "ui_BufferViewer.h"
struct FixedVarTag
{
FixedVarTag() = default;
FixedVarTag(uint32_t size) : valid(true), padding(true), byteSize(size) {}
FixedVarTag(rdcstr varName, uint32_t offset)
: valid(true), padding(false), name(varName), byteOffset(offset)
{
}
bool valid = false;
bool padding = false;
bool matrix = false;
bool rowmajor = false;
rdcstr name;
union
{
uint32_t byteOffset;
uint32_t byteSize;
};
};
Q_DECLARE_METATYPE(FixedVarTag);
static const uint32_t MaxVisibleRows = 10000;
namespace NativeScanCode
@@ -470,6 +493,7 @@ struct BufferConfiguration
uint32_t numRows = 0, unclampedNumRows = 0;
uint32_t pagingOffset = 0;
Packing::Rules packing;
ShaderConstant fixedVars;
rdcarray<ShaderVariable> evalVars;
uint32_t repeatStride = 1;
@@ -508,6 +532,7 @@ struct BufferConfiguration
unclampedNumRows = o.unclampedNumRows;
pagingOffset = o.pagingOffset;
packing = o.packing;
fixedVars = o.fixedVars;
evalVars = o.evalVars;
repeatStride = o.repeatStride;
@@ -2288,6 +2313,10 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)
QObject::connect(ui->render, &CustomPaintWidget::mouseWheel, this,
&BufferViewer::render_mouseWheel);
// event filter to pick up tooltip events
ui->fixedVars->setTooltipElidedItems(false);
ui->fixedVars->installEventFilter(this);
Reset();
m_Ctx.AddCaptureViewer(this);
@@ -2329,7 +2358,7 @@ void BufferViewer::SetupRawView()
processFormat(format);
});
ui->fixedVars->setColumns({tr("Name"), tr("Value"), tr("Type")});
ui->fixedVars->setColumns({tr("Name"), tr("Value"), tr("Byte Offset"), tr("Type")});
{
ui->fixedVars->header()->setSectionResizeMode(0, QHeaderView::Interactive);
ui->fixedVars->header()->setSectionResizeMode(1, QHeaderView::Interactive);
@@ -2412,6 +2441,7 @@ void BufferViewer::SetupMeshView()
byteRangeLength->setVisible(false);
ui->fixedVars->setVisible(false);
ui->showPadding->setVisible(false);
ui->resourceDetails->setVisible(false);
ui->formatSpecifier->setVisible(false);
@@ -2564,25 +2594,33 @@ void BufferViewer::fixedVars_contextMenu(const QPoint &pos)
QMenu contextMenu(this);
QAction expandAll(tr("&Expand All"), this);
QAction collapseAll(tr("&Collapse All"), this);
QAction collapseAll(tr("C&ollapse All"), this);
QAction copy(tr("&Copy"), this);
QAction showPadding(tr("&Show Padding"), this);
expandAll.setIcon(Icons::arrow_out());
collapseAll.setIcon(Icons::arrow_in());
copy.setIcon(Icons::copy());
showPadding.setIcon(Icons::align());
showPadding.setCheckable(true);
showPadding.setChecked(ui->showPadding->isChecked());
expandAll.setEnabled(item && item->childCount() > 0);
collapseAll.setEnabled(expandAll.isEnabled());
contextMenu.addAction(m_ExportCSV);
contextMenu.addAction(m_ExportBytes);
contextMenu.addSeparator();
contextMenu.addAction(&expandAll);
contextMenu.addAction(&collapseAll);
contextMenu.addAction(&copy);
contextMenu.addSeparator();
contextMenu.addAction(&showPadding);
contextMenu.addSeparator();
contextMenu.addAction(m_ExportCSV);
contextMenu.addAction(m_ExportBytes);
QObject::connect(&expandAll, &QAction::triggered,
[this, item]() { ui->fixedVars->expandAllItems(item); });
@@ -2590,6 +2628,8 @@ void BufferViewer::fixedVars_contextMenu(const QPoint &pos)
[this, item]() { ui->fixedVars->collapseAllItems(item); });
QObject::connect(&copy, &QAction::triggered,
[this, item, pos]() { ui->fixedVars->copyItem(pos, item); });
QObject::connect(&showPadding, &QAction::triggered,
[this]() { ui->showPadding->setChecked(!ui->showPadding->isChecked()); });
RDDialog::show(&contextMenu, ui->fixedVars->viewport()->mapToGlobal(pos));
}
@@ -2855,16 +2895,36 @@ void BufferViewer::OnEventChanged(uint32_t eventId)
}
QString errors;
ShaderConstant repeating;
rdctie(bufdata->vsinConfig.fixedVars, repeating) =
ParsedFormat parsed =
BufferFormatter::ParseFormatString(m_Format, m_ByteSize, IsCBufferView(), errors);
if(repeating.type.descriptor.type != VarType::Unknown)
{
bufdata->vsinConfig.repeatStride = repeating.type.descriptor.arrayByteStride;
bufdata->vsinConfig.repeatOffset = repeating.byteOffset;
bufdata->vsinConfig.fixedVars = parsed.fixed;
bufdata->vsinConfig.packing = parsed.packing;
UnrollConstant(repeating, bufdata->vsinConfig.columns, bufdata->vsinConfig.props);
if(parsed.repeating.type.descriptor.type != VarType::Unknown)
{
bufdata->vsinConfig.repeatStride = parsed.repeating.type.descriptor.arrayByteStride;
bufdata->vsinConfig.repeatOffset = parsed.repeating.byteOffset;
UnrollConstant(parsed.repeating, bufdata->vsinConfig.columns, bufdata->vsinConfig.props);
}
if((m_Format.isEmpty() || !bufdata->cb.bufferBacked) && IsCBufferView())
{
if(bufdata->cb.valid)
{
const ShaderReflection *reflection =
m_Ctx.CurPipelineState().GetShaderReflection(m_CBufferSlot.stage);
bufdata->vsinConfig.fixedVars.type.members =
reflection->constantBlocks[m_CBufferSlot.slot].variables;
if(IsD3D(m_Ctx.APIProps().pipelineType))
bufdata->vsinConfig.packing = Packing::D3DCB;
else
bufdata->vsinConfig.packing =
BufferFormatter::EstimatePackingRules(bufdata->vsinConfig.fixedVars.type.members);
}
}
ClearModels();
@@ -3132,7 +3192,13 @@ void BufferViewer::OnEventChanged(uint32_t eventId)
ui->fixedVars->clear();
if(!vars.isEmpty())
UI_AddFixedVariables(ui->fixedVars->invisibleRootItem(), vars);
{
UI_AddFixedVariables(ui->fixedVars->invisibleRootItem(), 0,
bufdata->vsinConfig.fixedVars.type.members, vars);
if(!bufdata->cb.bufferBacked)
UI_RemoveOffsets(ui->fixedVars->invisibleRootItem());
}
ui->fixedVars->endUpdate();
@@ -3286,23 +3352,168 @@ void BufferViewer::setPersistData(const QVariant &persistData)
}
}
void BufferViewer::UI_AddFixedVariables(RDTreeWidgetItem *root, const rdcarray<ShaderVariable> &vars)
void BufferViewer::UI_FixedAddMatrixRows(RDTreeWidgetItem *n, const ShaderConstant &c,
const ShaderVariable &v)
{
for(const ShaderVariable &v : vars)
const bool showPadding = ui->showPadding->isChecked() && m_CurCBuffer.bufferBacked;
if(v.rows > 1)
{
RDTreeWidgetItem *n = new RDTreeWidgetItem({v.name, VarString(v), TypeString(v)});
uint32_t vecSize = VarTypeByteSize(v.type) * v.columns;
FixedVarTag tag = n->tag().value<FixedVarTag>();
tag.matrix = true;
tag.rowmajor = v.RowMajor();
n->setTag(QVariant::fromValue(tag));
if(v.ColMajor())
vecSize = VarTypeByteSize(v.type) * v.rows;
for(uint32_t r = 0; r < v.rows; r++)
{
n->addChild(new RDTreeWidgetItem({QFormatStr("%1.row%2").arg(v.name).arg(r), RowString(v, r),
QString(), RowTypeString(v)}));
if(showPadding && v.RowMajor() && c.type.descriptor.matrixByteStride > vecSize)
{
uint32_t size = c.type.descriptor.matrixByteStride - vecSize;
RDTreeWidgetItem *pad = new RDTreeWidgetItem(
{tr(""), QFormatStr("%1 bytes").arg(size), QString(), tr("Padding")});
pad->setItalic(true);
pad->setTag(QVariant::fromValue(FixedVarTag(size)));
n->addChild(pad);
}
}
if(showPadding && v.ColMajor() && c.type.descriptor.matrixByteStride > vecSize)
{
uint32_t size = c.type.descriptor.matrixByteStride - vecSize;
RDTreeWidgetItem *pad = new RDTreeWidgetItem(
{tr(""), QFormatStr("%1 bytes each column").arg(size), QString(), tr("Padding")});
pad->setItalic(true);
pad->setTag(QVariant::fromValue(FixedVarTag(size)));
n->addChild(pad);
}
}
}
void BufferViewer::UI_AddFixedVariables(RDTreeWidgetItem *root, uint32_t baseOffset,
const rdcarray<ShaderConstant> &consts,
const rdcarray<ShaderVariable> &vars)
{
const bool showPadding = ui->showPadding->isChecked() && m_CurCBuffer.bufferBacked;
if(consts.size() != vars.size())
qCritical() << "Shader variable mismatch";
uint32_t offset = 0;
for(size_t idx = 0; idx < consts.size() && idx < vars.size(); idx++)
{
const ShaderConstant &c = consts[idx];
const ShaderVariable &v = vars[idx];
if(showPadding && c.byteOffset > offset)
{
uint32_t size = c.byteOffset - offset;
RDTreeWidgetItem *pad = new RDTreeWidgetItem(
{QString(), QFormatStr("%1 bytes").arg(size), QString(), tr("Padding")});
pad->setItalic(true);
pad->setTag(QVariant::fromValue(FixedVarTag(size)));
root->addChild(pad);
offset = c.byteOffset;
}
RDTreeWidgetItem *n =
new RDTreeWidgetItem({v.name, VarString(v), baseOffset + c.byteOffset, TypeString(v)});
n->setTag(QVariant::fromValue(FixedVarTag(v.name, baseOffset + c.byteOffset)));
root->addChild(n);
if(v.rows > 1)
UI_FixedAddMatrixRows(n, c, v);
// if it's an array the value (v) will be expanded with one element in each of v.members, but
// the constant (c) will just have the type with a number of elements
if(c.type.descriptor.elements > 1)
{
for(uint32_t i = 0; i < v.rows; i++)
n->addChild(new RDTreeWidgetItem(
{QFormatStr("%1.row%2").arg(v.name).arg(i), RowString(v, i), RowTypeString(v)}));
ShaderConstant noarray = c;
noarray.type.descriptor.elements = 1;
// calculate the tight scalar-packed advance, so we can detect padding
uint32_t elSize = BufferFormatter::GetVarAdvance(Packing::Scalar, noarray);
for(uint32_t e = 0; e < v.members.size(); e++)
{
const uint32_t elOffset = baseOffset + c.byteOffset + c.type.descriptor.arrayByteStride * e;
RDTreeWidgetItem *el = new RDTreeWidgetItem(
{v.members[e].name, VarString(v.members[e]), elOffset, TypeString(v.members[e])});
el->setTag(QVariant::fromValue(FixedVarTag(v.members[e].name, elOffset)));
// if it's an array of structs we can recurse, just need to do the outer iteration here
// because v.members[...].members will be the actual struct members because of the expansion
if(c.type.descriptor.type == VarType::Struct)
{
UI_AddFixedVariables(el, elOffset, c.type.members, v.members[e].members);
}
else
{
// otherwise just expand by hand since there will be no more members in c.type.members for
// us to recurse with
UI_FixedAddMatrixRows(el, c, v.members[e]);
}
n->addChild(el);
// don't count the padding in the last struct in an array of structs, it will be handled as
// padding after the array
if(c.type.descriptor.type == VarType::Struct && e + 1 == v.members.size())
break;
if(showPadding && c.type.descriptor.arrayByteStride > elSize)
{
uint32_t size = c.type.descriptor.arrayByteStride - elSize;
RDTreeWidgetItem *pad = new RDTreeWidgetItem(
{QString(), QFormatStr("%1 bytes").arg(size), QString(), tr("Padding")});
pad->setItalic(true);
pad->setTag(QVariant::fromValue(FixedVarTag(size)));
n->addChild(pad);
}
}
}
// for single structs, recurse
else if(v.type == VarType::Struct)
{
UI_AddFixedVariables(n, c.byteOffset, c.type.members, v.members);
}
if(!v.members.isEmpty())
UI_AddFixedVariables(n, v.members);
// advance by the tight scalar-packed advance, so we can detect padding
offset += BufferFormatter::GetVarAdvance(Packing::Scalar, c);
}
}
void BufferViewer::UI_RemoveOffsets(RDTreeWidgetItem *root)
{
for(int i = 0; i < root->childCount(); i++)
{
RDTreeWidgetItem *item = root->child(i);
item->setText(2, QVariant());
UI_RemoveOffsets(item);
}
}
@@ -4055,19 +4266,143 @@ void BufferViewer::ScrollToColumn(int32_t column, MeshDataStage stage)
bool BufferViewer::eventFilter(QObject *watched, QEvent *event)
{
if(!m_MeshView && watched == ui->vsinData->viewport() && event->type() == QEvent::MouseMove)
if(event->type() == QEvent::ToolTip)
{
bool ret = QObject::eventFilter(watched, event);
RDTreeWidget *tree = qobject_cast<RDTreeWidget *>(watched);
if(tree)
{
RDTreeWidgetItem *item = tree->itemAt(tree->viewport()->mapFromGlobal(QCursor::pos()));
if(item)
{
FixedVarTag tag = item->tag().value<FixedVarTag>();
QMouseEvent *mouseEvent = (QMouseEvent *)event;
QString tooltip;
if(m_delegate->linkHover(mouseEvent, font(),
ui->vsinData->indexAt(mouseEvent->localPos().toPoint())))
ui->vsinData->setCursor(QCursor(Qt::PointingHandCursor));
else
ui->vsinData->unsetCursor();
Packing::Rules pack = m_ModelVSIn->getConfig().packing;
return ret;
if(tag.valid && tag.padding)
{
tooltip = tr("%1 bytes of padding. Packing rules in effect:\n\n").arg(tag.byteSize);
if(pack == Packing::D3DCB)
tooltip += tr("Standard D3D constant buffer packing.\n\n");
else if(pack == Packing::std140)
tooltip += tr("Standard std140 buffer packing.\n\n");
else if(pack == Packing::std430)
tooltip += tr("Standard std430 buffer packing.\n\n");
else if(pack == Packing::C)
tooltip += tr("Standard C / D3D UAV packing.\n\n");
else if(pack == Packing::Scalar)
tooltip += tr("Scalar packing.\n\n");
if(pack.vector_align_component)
tooltip +=
tr("- Vectors are only aligned to their component (float4 to 4-byte boundary)\n");
else
tooltip +=
tr("- 3- and 4-wide vectors must be aligned to a 4-wide boundary\n"
" (vec3 and vec4 to 16-byte boundary)\n");
if(pack.tight_arrays)
tooltip += tr("- Arrays are tightly packed to each element\n");
else
tooltip += tr("- Arrays have a stride of a 16 bytes\n");
if(pack.trailing_overlap)
tooltip += tr("- Variables can overlap the trailing padding in arrays or structs.\n");
else
tooltip +=
tr("- Variables must not overlap the trailing padding in arrays or structs.\n");
if(pack.vector_straddle_16b)
tooltip += tr("- Vectors can straddle 16-byte boundaries.\n");
else
tooltip += tr("- Vectors must not straddle 16-byte boundaries.\n");
}
else if(tag.valid && !tag.padding)
{
tooltip = tr("Variable %1 is at byte offset %2").arg(tag.name).arg(tag.byteOffset);
if(!IsCBufferView())
tooltip += tr(", not including overall base byte offset %1 in buffer").arg(m_ByteOffset);
tooltip += lit(".");
if(tag.matrix)
{
tooltip += tr("\n\nMatrix stored ");
if(tag.rowmajor)
tooltip += tr("row-major.");
else
tooltip += tr("column-major.");
}
}
if(!tooltip.isEmpty())
{
QPoint pos = QCursor::pos();
pos.setX(pos.x() + 10);
pos.setY(pos.y() + 10);
QToolTip::showText(pos, tooltip.trimmed());
return true;
}
}
}
else if(!m_MeshView && watched == ui->vsinData->viewport())
{
QModelIndex index =
ui->vsinData->indexAt(ui->vsinData->viewport()->mapFromGlobal(QCursor::pos()));
if(index.isValid())
{
const ShaderConstant &c = m_ModelVSIn->elementForColumn(index.column());
QModelIndex rowidx = m_ModelVSIn->index(index.row(), 0, index.parent());
int row = m_ModelVSIn->data(rowidx).toInt();
size_t stride = m_ModelVSIn->getConfig().buffers[0]->stride;
QString tooltip;
tooltip = tr("%1 at overall byte offset %2").arg(c.name).arg(stride * row + c.byteOffset);
tooltip += tr(", not including overall base byte offset %1 in buffer").arg(m_ByteOffset);
tooltip += lit(".\n\n");
tooltip +=
tr("Row %1 begins at offset %2 (stride of %3 bytes)\n%4 is at offset %5 in each row.")
.arg(row)
.arg(stride * row)
.arg(stride)
.arg(c.name)
.arg(c.byteOffset);
QPoint pos = QCursor::pos();
pos.setX(pos.x() + 10);
pos.setY(pos.y() + 10);
QToolTip::showText(pos, tooltip.trimmed());
return true;
}
}
}
else if(!m_MeshView && watched == ui->vsinData->viewport())
{
if(event->type() == QEvent::MouseMove)
{
bool ret = QObject::eventFilter(watched, event);
QMouseEvent *mouseEvent = (QMouseEvent *)event;
if(m_delegate->linkHover(mouseEvent, font(),
ui->vsinData->indexAt(mouseEvent->localPos().toPoint())))
ui->vsinData->setCursor(QCursor(Qt::PointingHandCursor));
else
ui->vsinData->unsetCursor();
return ret;
}
}
return QObject::eventFilter(watched, event);
@@ -4619,22 +4954,21 @@ void BufferViewer::processFormat(const QString &format)
BufferConfiguration bufconfig;
ShaderConstant fixed, repeating;
ParsedFormat parsed;
if(IsCBufferView() && format.isEmpty())
{
// insert a dummy member so we get identified as plain fixed vars - we will automatically
// evaluate ignoring the format
fixed.type.members.push_back(ShaderConstant());
parsed.fixed.type.members.push_back(ShaderConstant());
}
else
{
rdctie(fixed, repeating) =
BufferFormatter::ParseFormatString(format, m_ByteSize, IsCBufferView(), errors);
parsed = BufferFormatter::ParseFormatString(format, m_ByteSize, IsCBufferView(), errors);
}
const bool repeatedVars = repeating.type.descriptor.type != VarType::Unknown;
const bool fixedVars = !fixed.type.members.empty();
const bool repeatedVars = parsed.repeating.type.descriptor.type != VarType::Unknown;
const bool fixedVars = !parsed.fixed.type.members.empty();
if(fixedVars && repeatedVars)
{
@@ -4657,6 +4991,8 @@ void BufferViewer::processFormat(const QString &format)
ui->fixedVars->setVisible(true);
ui->vsinData->setVisible(true);
ui->showPadding->setVisible(true);
m_InnerSplitter->setVisible(true);
if(m_CurView == NULL && !m_CurFixed)
@@ -4675,6 +5011,8 @@ void BufferViewer::processFormat(const QString &format)
ui->fixedVars->setVisible(true);
ui->vsinData->setVisible(false);
ui->showPadding->setVisible(true);
m_InnerSplitter->setVisible(false);
m_CurView = NULL;
@@ -4711,13 +5049,15 @@ void BufferViewer::processFormat(const QString &format)
ui->fixedVars->setVisible(false);
ui->vsinData->setVisible(true);
ui->showPadding->setVisible(false);
m_InnerSplitter->setVisible(false);
m_CurView = ui->vsinData;
m_CurFixed = false;
}
CalcColumnWidth(MaxNumRows(repeating));
CalcColumnWidth(MaxNumRows(parsed.repeating));
ClearModels();
@@ -4739,7 +5079,7 @@ void BufferViewer::processFormat(const QString &format)
}
else
{
qulonglong stride = qMax(1U, repeating.type.descriptor.arrayByteStride);
qulonglong stride = qMax(1U, parsed.repeating.type.descriptor.arrayByteStride);
byteRangeStart->setSingleStep(stride);
byteRangeLength->setSingleStep(stride);
@@ -4833,11 +5173,15 @@ void BufferViewer::exportCSV(QTextStream &ts, const QString &prefix, RDTreeWidge
{
if(item->childCount() == 0)
{
ts << QFormatStr("%1,\"%2\",%3\n").arg(item->text(0)).arg(item->text(1)).arg(item->text(2));
ts << QFormatStr("%1,\"%2\",%3,%4\n")
.arg(item->text(0))
.arg(item->text(1))
.arg(item->text(2))
.arg(item->text(3));
}
else
{
ts << QFormatStr("%1,,%2\n").arg(item->text(0)).arg(item->text(2));
ts << QFormatStr("%1,,%2,%3\n").arg(item->text(0)).arg(item->text(2)).arg(item->text(3));
for(int i = 0; i < item->childCount(); i++)
exportCSV(ts, item->text(0) + lit("."), item->child(i));
}
@@ -5114,12 +5458,10 @@ void BufferViewer::exportData(const BufferExport &params)
BufferItemModel *model = (BufferItemModel *)ui->vsinData->model();
const BufferConfiguration &config = model->getConfig();
const ShaderConstant &fixedVars = config.fixedVars;
size_t byteSize = 0;
if(!fixedVars.type.members.empty())
byteSize = BufferFormatter::GetVarSize(fixedVars.type.members.back());
if(!config.fixedVars.type.members.empty())
byteSize = BufferFormatter::GetVarAdvance(config.packing, config.fixedVars);
const bytebuf &bufdata = config.buffers[0]->storage;
@@ -5137,7 +5479,7 @@ void BufferViewer::exportData(const BufferExport &params)
{
QTextStream ts(f);
ts << tr("Name,Value,Type\n");
ts << tr("Name,Value,Byte Offset,Type\n");
for(int i = 0; i < ui->fixedVars->topLevelItemCount(); i++)
exportCSV(ts, QString(), ui->fixedVars->topLevelItem(i));
@@ -5361,6 +5703,11 @@ void BufferViewer::on_syncViews_toggled(bool checked)
SyncViews(NULL, true, true);
}
void BufferViewer::on_showPadding_toggled(bool checked)
{
OnEventChanged(m_Ctx.CurEvent());
}
void BufferViewer::on_highlightVerts_toggled(bool checked)
{
UpdateHighlightVerts();
+7 -1
View File
@@ -124,6 +124,7 @@ private slots:
void on_autofitCamera_clicked();
void on_toggleControls_toggled(bool checked);
void on_syncViews_toggled(bool checked);
void on_showPadding_toggled(bool checked);
void on_resourceDetails_clicked();
void on_highlightVerts_toggled(bool checked);
void on_wireframeRender_toggled(bool checked);
@@ -196,7 +197,12 @@ private:
void UI_UpdateBoundingBox(const CalcBoundingBoxData &bbox);
void UI_UpdateBoundingBoxLabels(int compCount = 0);
void UI_AddFixedVariables(RDTreeWidgetItem *root, const rdcarray<ShaderVariable> &vars);
void UI_AddFixedVariables(RDTreeWidgetItem *root, uint32_t baseOffset,
const rdcarray<ShaderConstant> &consts,
const rdcarray<ShaderVariable> &vars);
void UI_RemoveOffsets(RDTreeWidgetItem *root);
void UI_FixedAddMatrixRows(RDTreeWidgetItem *n, const ShaderConstant &c, const ShaderVariable &v);
void exportCSV(QTextStream &ts, const QString &prefix, RDTreeWidgetItem *item);
void FillScrolls(PopulateBufferData *bufdata);
+23
View File
@@ -846,6 +846,29 @@ Enter 0.0 to use automatic/guessed value derived from data.</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="showPadding">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Show visible padding</string>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/align.png</normaloff>:/align.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="syncViews">
<property name="enabled">
+2
View File
@@ -1914,6 +1914,8 @@
<Image Include="Resources\action_hover.png" />
<Image Include="Resources\add%402x.png" />
<Image Include="Resources\add.png" />
<Image Include="Resources\align%402x.png" />
<Image Include="Resources\align.png" />
<Image Include="Resources\arrow_in%402x.png" />
<Image Include="Resources\arrow_in.png" />
<Image Include="Resources\arrow_join%402x.png" />
+12 -6
View File
@@ -411,9 +411,9 @@
<ClCompile Include="$(IntDir)generated\moc_CaptureDialog.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)generated\moc_ComputeDebugSelector.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)generated\moc_ComputeDebugSelector.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)generated\moc_CustomPaintWidget.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
@@ -974,9 +974,9 @@
<ClInclude Include="$(IntDir)generated\ui_CaptureDialog.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="$(IntDir)generated\ui_ComputeDebugSelector.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="$(IntDir)generated\ui_ComputeDebugSelector.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="$(IntDir)generated\ui_D3D11PipelineStateViewer.h">
<Filter>Generated Files</Filter>
</ClInclude>
@@ -1957,6 +1957,12 @@
<Image Include="Resources\filter%402x.png">
<Filter>Resources\Files</Filter>
</Image>
<Image Include="Resources\align.png">
<Filter>Resources\Files</Filter>
</Image>
<Image Include="Resources\align%402x.png">
<Filter>Resources\Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<Natvis Include="python36.natvis" />