Generate better buffer format strings when opening VB or IB buffer views

This commit is contained in:
baldurk
2018-10-09 15:41:21 +01:00
parent 5472319025
commit b91d19e316
6 changed files with 366 additions and 34 deletions
@@ -37,14 +37,16 @@
struct D3D11VBIBTag
{
D3D11VBIBTag() { offset = 0; }
D3D11VBIBTag(ResourceId i, uint64_t offs)
D3D11VBIBTag(ResourceId i, uint64_t offs, QString f = QString())
{
id = i;
offset = offs;
format = f;
}
ResourceId id;
uint64_t offset;
QString format;
};
Q_DECLARE_METATYPE(D3D11VBIBTag);
@@ -1348,10 +1350,24 @@ void D3D11PipelineStateViewer::setState()
{tr("Index"), state.inputAssembly.indexBuffer.resourceId, draw ? draw->indexByteWidth : 0,
state.inputAssembly.indexBuffer.byteOffset, (qulonglong)length, QString()});
node->setTag(QVariant::fromValue(
D3D11VBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0))));
QString iformat;
if(draw)
{
if(draw->indexByteWidth == 1)
iformat = lit("ubyte");
else if(draw->indexByteWidth == 2)
iformat = lit("ushort");
else if(draw->indexByteWidth == 4)
iformat = lit("uint");
iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology));
}
node->setTag(
QVariant::fromValue(D3D11VBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0),
iformat)));
if(!ibufferUsed)
setInactiveRow(node);
@@ -1372,10 +1388,24 @@ void D3D11PipelineStateViewer::setState()
RDTreeWidgetItem *node = new RDTreeWidgetItem(
{tr("Index"), tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()});
node->setTag(QVariant::fromValue(
D3D11VBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0))));
QString iformat;
if(draw)
{
if(draw->indexByteWidth == 1)
iformat = lit("ubyte");
else if(draw->indexByteWidth == 2)
iformat = lit("ushort");
else if(draw->indexByteWidth == 4)
iformat = lit("uint");
iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology));
}
node->setTag(
QVariant::fromValue(D3D11VBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0),
iformat)));
setEmptyRow(node);
m_EmptyNodes.push_back(node);
@@ -1410,7 +1440,8 @@ void D3D11PipelineStateViewer::setState()
node =
new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()});
node->setTag(QVariant::fromValue(D3D11VBIBTag(v.resourceId, v.byteOffset)));
node->setTag(QVariant::fromValue(
D3D11VBIBTag(v.resourceId, v.byteOffset, m_Common.GetVBufferFormatString(i))));
if(!filledSlot)
{
@@ -2174,7 +2205,7 @@ void D3D11PipelineStateViewer::on_iaBuffers_itemActivated(RDTreeWidgetItem *item
if(buf.id != ResourceId())
{
IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id);
IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id, buf.format);
m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this);
}
@@ -37,14 +37,16 @@
struct D3D12VBIBTag
{
D3D12VBIBTag() { offset = 0; }
D3D12VBIBTag(ResourceId i, uint64_t offs)
D3D12VBIBTag(ResourceId i, uint64_t offs, QString f = QString())
{
id = i;
offset = offs;
format = f;
}
ResourceId id;
uint64_t offset;
QString format;
};
Q_DECLARE_METATYPE(D3D12VBIBTag);
@@ -1366,10 +1368,24 @@ void D3D12PipelineStateViewer::setState()
{tr("Index"), state.inputAssembly.indexBuffer.resourceId, draw ? draw->indexByteWidth : 0,
(qulonglong)state.inputAssembly.indexBuffer.byteOffset, (qulonglong)length, QString()});
node->setTag(QVariant::fromValue(
D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0))));
QString iformat;
if(draw)
{
if(draw->indexByteWidth == 1)
iformat = lit("ubyte");
else if(draw->indexByteWidth == 2)
iformat = lit("ushort");
else if(draw->indexByteWidth == 4)
iformat = lit("uint");
iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology));
}
node->setTag(
QVariant::fromValue(D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0),
iformat)));
if(!ibufferUsed)
setInactiveRow(node);
@@ -1390,10 +1406,24 @@ void D3D12PipelineStateViewer::setState()
RDTreeWidgetItem *node = new RDTreeWidgetItem(
{tr("Index"), tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()});
node->setTag(QVariant::fromValue(
D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0))));
QString iformat;
if(draw)
{
if(draw->indexByteWidth == 1)
iformat = lit("ubyte");
else if(draw->indexByteWidth == 2)
iformat = lit("ushort");
else if(draw->indexByteWidth == 4)
iformat = lit("uint");
iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology));
}
node->setTag(
QVariant::fromValue(D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0),
iformat)));
setEmptyRow(node);
m_EmptyNodes.push_back(node);
@@ -1449,7 +1479,8 @@ void D3D12PipelineStateViewer::setState()
node =
new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()});
node->setTag(QVariant::fromValue(D3D12VBIBTag(v.resourceId, v.byteOffset)));
node->setTag(QVariant::fromValue(
D3D12VBIBTag(v.resourceId, v.byteOffset, m_Common.GetVBufferFormatString(i))));
if(!filledSlot)
{
@@ -2033,7 +2064,7 @@ void D3D12PipelineStateViewer::on_iaBuffers_itemActivated(RDTreeWidgetItem *item
if(buf.id != ResourceId())
{
IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id);
IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id, buf.format);
m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this);
}
@@ -36,14 +36,16 @@
struct GLVBIBTag
{
GLVBIBTag() { offset = 0; }
GLVBIBTag(ResourceId i, uint64_t offs)
GLVBIBTag(ResourceId i, uint64_t offs, QString f = QString())
{
id = i;
offset = offs;
format = f;
}
ResourceId id;
uint64_t offset;
QString format;
};
Q_DECLARE_METATYPE(GLVBIBTag);
@@ -1293,8 +1295,22 @@ void GLPipelineStateViewer::setState()
draw ? draw->indexByteWidth : 0, 0, 0,
(qulonglong)length, QString()});
node->setTag(QVariant::fromValue(GLVBIBTag(
state.vertexInput.indexBuffer, draw ? draw->indexOffset * draw->indexByteWidth : 0)));
QString iformat;
if(draw)
{
if(draw->indexByteWidth == 1)
iformat = lit("ubyte");
else if(draw->indexByteWidth == 2)
iformat = lit("ushort");
else if(draw->indexByteWidth == 4)
iformat = lit("uint");
iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology));
}
node->setTag(QVariant::fromValue(GLVBIBTag(state.vertexInput.indexBuffer,
draw ? draw->indexOffset * draw->indexByteWidth : 0,
iformat)));
if(!ibufferUsed)
setInactiveRow(node);
@@ -1315,8 +1331,22 @@ void GLPipelineStateViewer::setState()
RDTreeWidgetItem *node = new RDTreeWidgetItem(
{tr("Element"), tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), lit("-"), QString()});
node->setTag(QVariant::fromValue(GLVBIBTag(
state.vertexInput.indexBuffer, draw ? draw->indexOffset * draw->indexByteWidth : 0)));
QString iformat;
if(draw)
{
if(draw->indexByteWidth == 1)
iformat = lit("ubyte");
else if(draw->indexByteWidth == 2)
iformat = lit("ushort");
else if(draw->indexByteWidth == 4)
iformat = lit("uint");
iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology));
}
node->setTag(QVariant::fromValue(GLVBIBTag(state.vertexInput.indexBuffer,
draw ? draw->indexOffset * draw->indexByteWidth : 0,
iformat)));
setEmptyRow(node);
m_EmptyNodes.push_back(node);
@@ -1348,7 +1378,8 @@ void GLPipelineStateViewer::setState()
new RDTreeWidgetItem({i, v.resourceId, v.byteStride, (qulonglong)offset,
v.instanceDivisor, (qulonglong)length, QString()});
node->setTag(QVariant::fromValue(GLVBIBTag(v.resourceId, v.byteOffset)));
node->setTag(QVariant::fromValue(
GLVBIBTag(v.resourceId, v.byteOffset, m_Common.GetVBufferFormatString(i))));
if(!filledSlot)
{
@@ -2185,7 +2216,7 @@ void GLPipelineStateViewer::on_viBuffers_itemActivated(RDTreeWidgetItem *item, i
if(buf.id != ResourceId())
{
IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id);
IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id, buf.format);
m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this);
}
@@ -912,6 +912,211 @@ void PipelineStateViewer::SetupShaderEditButton(QToolButton *button, ResourceId
button->setMenu(menu);
}
static uint32_t byteSize(const ResourceFormat &fmt)
{
if(fmt.Special())
{
switch(fmt.type)
{
case ResourceFormatType::R9G9B9E5:
case ResourceFormatType::R5G6B5:
case ResourceFormatType::R5G5B5A1:
case ResourceFormatType::R4G4B4A4:
case ResourceFormatType::R4G4:
case ResourceFormatType::BC1:
case ResourceFormatType::BC2:
case ResourceFormatType::BC3:
case ResourceFormatType::BC4:
case ResourceFormatType::BC5:
case ResourceFormatType::BC6:
case ResourceFormatType::BC7:
case ResourceFormatType::ETC2:
case ResourceFormatType::EAC:
case ResourceFormatType::ASTC:
case ResourceFormatType::D16S8:
case ResourceFormatType::D24S8:
case ResourceFormatType::D32S8:
case ResourceFormatType::S8:
case ResourceFormatType::YUV:
case ResourceFormatType::PVRTC: return ~0U;
case ResourceFormatType::R10G10B10A2:
case ResourceFormatType::R11G11B10: return 4;
}
}
return fmt.compByteWidth * fmt.compCount;
}
static QString padding(uint32_t bytes)
{
if(bytes == 0)
return QString();
QString ret;
if(bytes > 4)
{
ret += lit("xint pad[%1];").arg(bytes / 4);
bytes = bytes % 4;
}
if(bytes == 3)
ret += lit("xshort pad; xbyte pad;");
else if(bytes == 2)
ret += lit("xshort pad;");
else if(bytes == 1)
ret += lit("xbyte pad;");
return ret + lit("\n");
}
QString PipelineStateViewer::GetVBufferFormatString(uint32_t slot)
{
rdcarray<BoundVBuffer> vbs = m_Ctx.CurPipelineState().GetVBuffers();
rdcarray<VertexInputAttribute> attrs = m_Ctx.CurPipelineState().GetVertexInputs();
if(slot >= vbs.size())
return tr("// Unbound vertex buffer slot %1").arg(slot);
uint32_t stride = vbs[slot].byteStride;
// filter attributes to only the ones enabled and using this slot
for(size_t i = 0; i < attrs.size();)
{
if(!attrs[i].used || attrs[i].vertexBuffer != (int)slot)
{
attrs.erase(i);
// continue with same i
}
else
{
// move to next i
i++;
}
}
// we now have all attributes in this buffer. Sort by offset
std::sort(attrs.begin(), attrs.end(),
[](const VertexInputAttribute &a, const VertexInputAttribute &b) {
return a.byteOffset < b.byteOffset;
});
// ensure we don't have any overlap between attributes or with the stride
for(size_t i = 0; i < attrs.size(); i++)
{
uint32_t cursz = byteSize(attrs[i].format);
if(cursz == 0)
return tr("// Unhandled vertex attribute type '%1'").arg(ToQStr(attrs[i].format.type));
// for all but the first attribute, ensure no overlaps with previous. We allow identical
// elements
if(i > 0)
{
uint32_t prevsz = byteSize(attrs[i - 1].format);
if((attrs[i - 1].byteOffset != attrs[i].byteOffset || cursz != prevsz) &&
attrs[i - 1].byteOffset + prevsz > attrs[i].byteOffset)
return tr("// vertex attributes overlapping, no automatic format available");
}
if(i + 1 == attrs.size())
{
// for the last attribute, ensure the total size doesn't overlap stride
if(attrs[i].byteOffset + cursz > stride && stride > 0)
return tr("// vertex stride %1 less than total data fetched %1")
.arg(stride)
.arg(attrs[i].byteOffset + cursz);
}
}
QString format;
uint32_t offset = 0;
for(size_t i = 0; i < attrs.size(); i++)
{
// we disallowed overlaps above, but we do allow *duplicates*. So if our offset has already
// passed, silently skip this element.
if(attrs[i].byteOffset < offset)
continue;
// declare any padding from previous element to this one
format += padding(attrs[i].byteOffset - offset);
const ResourceFormat &fmt = attrs[i].format;
offset += byteSize(fmt);
if(fmt.Special())
{
switch(fmt.type)
{
case ResourceFormatType::R10G10B10A2:
if(fmt.compType == CompType::UInt)
format += lit("uintten");
if(fmt.compType == CompType::UNorm)
format += lit("unormten");
break;
case ResourceFormatType::R11G11B10: format += lit("floateleven"); break;
default: format += tr("// unknown type "); break;
}
}
else
{
QChar widthchar[] = {
QLatin1Char('?'), QLatin1Char('b'), QLatin1Char('h'), QLatin1Char('?'), QLatin1Char('f'),
};
if(fmt.compType == CompType::UNorm)
{
format += lit("unorm%1").arg(widthchar[fmt.compByteWidth]);
}
else if(fmt.compType == CompType::SNorm)
{
format += lit("snorm%1").arg(widthchar[fmt.compByteWidth]);
}
else
{
if(fmt.compType == CompType::UInt)
format += lit("u");
if(fmt.compByteWidth == 1)
{
format += lit("byte");
}
else if(fmt.compByteWidth == 2)
{
if(fmt.compType == CompType::Float)
format += lit("half");
else
format += lit("short");
}
else if(fmt.compByteWidth == 4)
{
if(fmt.compType == CompType::Float)
format += lit("float");
else
format += lit("int");
}
else if(fmt.compByteWidth == 8)
{
format += lit("double");
}
}
format += QString::number(fmt.compCount);
}
format += QFormatStr(" %1;\n").arg(QString(attrs[i].name));
}
if(stride > 0)
format += padding(stride - offset);
return format;
}
bool PipelineStateViewer::SaveShaderFile(const ShaderReflection *shader)
{
if(!shader)
@@ -70,6 +70,8 @@ public:
void SetupShaderEditButton(QToolButton *button, ResourceId pipelineId, ResourceId shaderId,
const ShaderReflection *shaderDetails);
QString GetVBufferFormatString(uint32_t slot);
void setTopologyDiagram(QLabel *diagram, Topology topo);
void setMeshViewPixmap(RDLabel *meshView);
@@ -38,14 +38,16 @@ Q_DECLARE_METATYPE(SamplerData);
struct VulkanVBIBTag
{
VulkanVBIBTag() { offset = 0; }
VulkanVBIBTag(ResourceId i, uint64_t offs)
VulkanVBIBTag(ResourceId i, uint64_t offs, QString f = QString())
{
id = i;
offset = offs;
format = f;
}
ResourceId id;
uint64_t offset;
QString format;
};
Q_DECLARE_METATYPE(VulkanVBIBTag);
@@ -1615,10 +1617,24 @@ void VulkanPipelineStateViewer::setState()
(qulonglong)state.inputAssembly.indexBuffer.byteOffset,
draw != NULL ? draw->indexByteWidth : 0, (qulonglong)length, QString()});
QString iformat;
if(draw)
{
if(draw->indexByteWidth == 1)
iformat = lit("ubyte");
else if(draw->indexByteWidth == 2)
iformat = lit("ushort");
else if(draw->indexByteWidth == 4)
iformat = lit("uint");
iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology));
}
node->setTag(QVariant::fromValue(
VulkanVBIBTag(state.inputAssembly.indexBuffer.resourceId,
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0))));
(draw ? draw->indexOffset * draw->indexByteWidth : 0),
iformat)));
if(!ibufferUsed)
setInactiveRow(node);
@@ -1639,9 +1655,24 @@ void VulkanPipelineStateViewer::setState()
RDTreeWidgetItem *node = new RDTreeWidgetItem({tr("Index"), ResourceId(), tr("Index"), lit("-"),
lit("-"), lit("-"), lit("-"), QString()});
QString iformat;
if(draw)
{
if(draw->indexByteWidth == 1)
iformat = lit("ubyte");
else if(draw->indexByteWidth == 2)
iformat = lit("ushort");
else if(draw->indexByteWidth == 4)
iformat = lit("uint");
iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology));
}
node->setTag(QVariant::fromValue(
VulkanVBIBTag(state.inputAssembly.indexBuffer.resourceId,
draw != NULL ? draw->indexOffset * draw->indexByteWidth : 0)));
state.inputAssembly.indexBuffer.byteOffset +
(draw ? draw->indexOffset * draw->indexByteWidth : 0),
iformat)));
setEmptyRow(node);
m_EmptyNodes.push_back(node);
@@ -1709,7 +1740,8 @@ void VulkanPipelineStateViewer::setState()
{i, tr("No Binding"), lit("-"), lit("-"), lit("-"), lit("-"), lit("-"), QString()});
node->setTag(QVariant::fromValue(VulkanVBIBTag(
vbuff != NULL ? vbuff->resourceId : ResourceId(), vbuff != NULL ? vbuff->byteOffset : 0)));
vbuff != NULL ? vbuff->resourceId : ResourceId(), vbuff != NULL ? vbuff->byteOffset : 0,
m_Common.GetVBufferFormatString(i))));
if(!filledSlot || bind == NULL || vbuff == NULL)
{
@@ -2280,7 +2312,7 @@ void VulkanPipelineStateViewer::on_viBuffers_itemActivated(RDTreeWidgetItem *ite
if(buf.id != ResourceId())
{
IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id);
IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id, buf.format);
m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this);
}