Add UI support for GPU typed pointers in buffers

This commit is contained in:
baldurk
2019-11-29 13:53:44 +00:00
parent b3979262a5
commit e205054317
28 changed files with 722 additions and 249 deletions
+73 -21
View File
@@ -30,6 +30,7 @@
struct StructFormatData
{
ShaderConstant structDef;
uint32_t pointerTypeId = 0;
uint32_t offset = 0;
};
@@ -86,6 +87,7 @@ ShaderConstant BufferFormatter::ParseFormatString(const QString &formatString, u
QRegularExpression structUseRegex(
lit("^" // start of the line
"([A-Za-z_][A-Za-z0-9_]*)" // struct type name
"(\\*)?" // maybe a pointer
"\\s+([A-Za-z@_][A-Za-z0-9@_]*)" // variable name
"(\\s*\\[[0-9]+\\])?" // optional array dimension
"$"));
@@ -119,6 +121,8 @@ ShaderConstant BufferFormatter::ParseFormatString(const QString &formatString, u
if(!tightPacking)
cur->structDef.type.descriptor.arrayByteStride = (cur->offset + 0xFU) & (~0xFU);
cur->pointerTypeId = PointerTypeRegistry::GetTypeID(cur->structDef.type);
cur = &root;
continue;
}
@@ -140,6 +144,7 @@ ShaderConstant BufferFormatter::ParseFormatString(const QString &formatString, u
}
cur = &structelems[lastStruct];
cur->structDef.type.descriptor.name = lastStruct;
continue;
}
}
@@ -152,34 +157,55 @@ ShaderConstant BufferFormatter::ParseFormatString(const QString &formatString, u
{
StructFormatData &structContext = structelems[structMatch.captured(1)];
QString varName = structMatch.captured(2);
bool isPointer = !structMatch.captured(2).trimmed().isEmpty();
QString arrayDim = structMatch.captured(3).trimmed();
uint32_t arrayCount = 1;
if(!arrayDim.isEmpty())
QString varName = structMatch.captured(3);
if(isPointer)
{
arrayDim = arrayDim.mid(1, arrayDim.count() - 2);
bool ok = false;
arrayCount = arrayDim.toUInt(&ok);
if(!ok)
arrayCount = 1;
// if not tight packing, align up to pointer size
if(!tightPacking)
cur->offset = (cur->offset + 0x7) & (~0x7);
el.name = varName;
el.byteOffset = cur->offset;
el.type.descriptor.pointerTypeID = structContext.pointerTypeId;
el.type.descriptor.type = VarType::ULong;
el.type.descriptor.displayAsHex = true;
el.type.descriptor.arrayByteStride = 8;
cur->offset += 8;
cur->structDef.type.members.push_back(el);
}
else
{
QString arrayDim = structMatch.captured(4).trimmed();
uint32_t arrayCount = 1;
if(!arrayDim.isEmpty())
{
arrayDim = arrayDim.mid(1, arrayDim.count() - 2);
bool ok = false;
arrayCount = arrayDim.toUInt(&ok);
if(!ok)
arrayCount = 1;
}
// cbuffer packing rules, structs are always float4 base aligned
if(!tightPacking)
cur->offset = (cur->offset + 0xFU) & (~0xFU);
// cbuffer packing rules, structs are always float4 base aligned
if(!tightPacking)
cur->offset = (cur->offset + 0xFU) & (~0xFU);
el = structContext.structDef;
el.name = varName;
el.byteOffset = cur->offset;
el.type.descriptor.elements = arrayCount;
el = structContext.structDef;
el.name = varName;
el.byteOffset = cur->offset;
el.type.descriptor.elements = arrayCount;
cur->structDef.type.members.push_back(el);
cur->structDef.type.members.push_back(el);
// undo the padding after the last struct
uint32_t padding = el.type.descriptor.arrayByteStride - structContext.offset;
// undo the padding after the last struct
uint32_t padding = el.type.descriptor.arrayByteStride - structContext.offset;
cur->offset += el.type.descriptor.elements * el.type.descriptor.arrayByteStride - padding;
cur->offset += el.type.descriptor.elements * el.type.descriptor.arrayByteStride - padding;
}
continue;
}
@@ -760,7 +786,24 @@ QString BufferFormatter::DeclareStruct(QList<QString> &declaredStructs, const QS
QString varTypeName = members[i].type.descriptor.name;
if(!members[i].type.members.isEmpty())
if(members[i].type.descriptor.pointerTypeID != ~0U)
{
const ShaderVariableType &pointeeType =
PointerTypeRegistry::GetTypeDescriptor(members[i].type.descriptor.pointerTypeID);
varTypeName = pointeeType.descriptor.name;
if(!declaredStructs.contains(varTypeName))
{
declaredStructs.push_back(varTypeName);
ret = DeclareStruct(declaredStructs, varTypeName, pointeeType.members,
pointeeType.descriptor.arrayByteStride) +
lit("\n") + ret;
}
varTypeName += lit("*");
}
else if(!members[i].type.members.isEmpty())
{
// GL structs don't give us typenames (boo!) so give them unique names. This will mean some
// structs get duplicated if they're used in multiple places, but not much we can do about
@@ -1453,6 +1496,9 @@ QString TypeString(const ShaderVariable &v)
return QFormatStr("%1[%2]").arg(TypeString(v.members[0])).arg(v.members.count());
}
if(v.isPointer)
return PointerTypeRegistry::GetTypeDescriptor(v.GetPointer()).descriptor.name + "*";
QString typeStr = ToQStr(v.type);
if(v.displayAsHex)
@@ -1504,6 +1550,9 @@ QString RowString(const ShaderVariable &v, uint32_t row, VarType type)
if(type == VarType::Unknown)
type = v.type;
if(v.isPointer)
return ToQStr(v.GetPointer());
if(type == VarType::Double)
return RowValuesToString((int)v.columns, v.displayAsHex, v.value.dv[row * v.columns + 0],
v.value.dv[row * v.columns + 1], v.value.dv[row * v.columns + 2],
@@ -1562,6 +1611,9 @@ QString RowTypeString(const ShaderVariable &v)
if(v.rows == 0 && v.columns == 0)
return lit("-");
if(v.isPointer)
return PointerTypeRegistry::GetTypeDescriptor(v.GetPointer()).descriptor.name + "*";
QString typeStr = ToQStr(v.type);
if(v.displayAsHex)
+11
View File
@@ -686,6 +686,8 @@ void CaptureContext::LoadCapture(const rdcstr &captureFile, const ReplayOptions
{
CloseCapture();
PointerTypeRegistry::Init();
m_LoadInProgress = true;
if(local)
@@ -1450,6 +1452,15 @@ void CaptureContext::SetRemoteHost(int hostIdx)
void CaptureContext::RefreshUIStatus(const rdcarray<ICaptureViewer *> &exclude,
bool updateSelectedEvent, bool updateEvent)
{
// cache and assign pointer type IDs for any known pointer types in current shaders
for(ShaderStage stage : {ShaderStage::Vertex, ShaderStage::Hull, ShaderStage::Domain,
ShaderStage::Geometry, ShaderStage::Pixel, ShaderStage::Compute})
{
const ShaderReflection *refl = m_CurPipelineState->GetShaderReflection(stage);
if(refl)
PointerTypeRegistry::CacheShader(refl);
}
for(ICaptureViewer *viewer : m_CaptureViewers)
{
if(exclude.contains(viewer))
+294 -38
View File
@@ -60,13 +60,103 @@ rdcstr DoStringise(const uint32_t &el)
return QString::number(el).toStdString();
}
// this one we do by hand as it requires formatting
// these ones we do by hand as it requires formatting
template <>
rdcstr DoStringise(const ResourceId &el)
{
uint64_t num;
memcpy(&num, &el, sizeof(num));
return lit("ResourceId::%1").arg(num).toStdString();
return lit("ResourceId::%1").arg(num);
}
QMap<QPair<ResourceId, uint32_t>, uint32_t> PointerTypeRegistry::typeMapping;
rdcarray<ShaderVariableType> PointerTypeRegistry::typeDescriptions;
static const uint32_t TypeIDBit = 0x80000000;
void PointerTypeRegistry::Init()
{
typeMapping.clear();
// type ID 0 is reserved as a NULL/empty descriptor
typeDescriptions.resize(1);
typeDescriptions[0].descriptor.name = "<Unknown>";
}
uint32_t PointerTypeRegistry::GetTypeID(ResourceId shader, uint32_t pointerTypeId)
{
return typeMapping[qMakePair(shader, pointerTypeId)];
}
uint32_t PointerTypeRegistry::GetTypeID(const ShaderVariableType &structDef)
{
// see if the type is already registered, return its existing ID
for(uint32_t i = 1; i < typeDescriptions.size(); i++)
{
if(structDef == typeDescriptions[i])
return TypeIDBit | i;
}
uint32_t id = TypeIDBit | (uint32_t)typeDescriptions.size();
// otherwise register the new type
typeDescriptions.push_back(structDef);
typeMapping[qMakePair(ResourceId(), id)] = id;
return id;
}
const ShaderVariableType &PointerTypeRegistry::GetTypeDescriptor(uint32_t typeId)
{
return typeDescriptions[typeId & ~TypeIDBit];
}
void PointerTypeRegistry::CacheSubTypes(const ShaderReflection *reflection,
ShaderVariableType &structDef)
{
if((structDef.descriptor.pointerTypeID & TypeIDBit) == 0)
structDef.descriptor.pointerTypeID =
PointerTypeRegistry::GetTypeID(reflection->pointerTypes[structDef.descriptor.pointerTypeID]);
for(ShaderConstant &member : structDef.members)
CacheSubTypes(reflection, member.type);
}
void PointerTypeRegistry::CacheShader(const ShaderReflection *reflection)
{
// nothing to do if there are no pointer types
if(reflection->pointerTypes.isEmpty())
return;
// check if we've already cached this shader (we know there's at least one pointer type)
if(typeMapping.contains(qMakePair(reflection->resourceId, 0)))
return;
for(uint32_t i = 0; i < reflection->pointerTypes.size(); i++)
{
ShaderVariableType typeDesc = reflection->pointerTypes[i];
// first recursively cache all subtypes needed by the root struct types
CacheSubTypes(reflection, typeDesc);
// then look up the Type ID for this struct
typeMapping[qMakePair(reflection->resourceId, i)] = GetTypeID(typeDesc);
}
}
template <>
rdcstr DoStringise(const PointerVal &el)
{
if(el.pointerTypeID != ~0U)
{
uint32_t ptrTypeId = PointerTypeRegistry::GetTypeID(el.shader, el.pointerTypeID);
return QFormatStr("GPUAddress::%1::%2").arg(el.pointer).arg(ptrTypeId);
}
else
{
return QFormatStr("GPUAddress::%1").arg(el.pointer);
}
}
// this is an opaque struct that contains the data to render, hit-test, etc for some text that
@@ -183,6 +273,37 @@ typedef QSharedPointer<RichResourceText> RichResourceTextPtr;
Q_DECLARE_METATYPE(RichResourceTextPtr);
void GPUAddress::cacheAddress(const QWidget *widget)
{
if(!ctxptr)
ctxptr = getCaptureContext(widget);
// bail out if we don't have a context
if(!ctxptr)
return;
// bail if we're already cached
if(base != ResourceId())
return;
// find the first matching buffer
for(const BufferDescription &b : ctxptr->GetBuffers())
{
if(b.gpuAddress && b.gpuAddress <= val.pointer && b.gpuAddress + b.length > val.pointer)
{
base = b.resourceId;
offset = val.pointer - b.gpuAddress;
return;
}
}
}
// for the same reason as above we use a shared pointer for GPU addresses too. This ensures the
// cached data doesn't keep getting re-cached in copies.
typedef QSharedPointer<GPUAddress> GPUAddressPtr;
Q_DECLARE_METATYPE(GPUAddressPtr);
QString ResIdTextToString(RichResourceTextPtr ptr)
{
return ptr->text;
@@ -193,10 +314,19 @@ QString ResIdToString(ResourceId ptr)
return ToQStr(ptr);
}
QString GPUAddressToString(GPUAddressPtr addr)
{
if(addr->base != ResourceId())
return QFormatStr("%1+%2").arg(ToQStr(addr->base)).arg(addr->offset);
else
return QFormatStr("0x%1").arg(addr->val.pointer, 0, 16);
}
void RegisterMetatypeConversions()
{
QMetaType::registerConverter<RichResourceTextPtr, QString>(&ResIdTextToString);
QMetaType::registerConverter<ResourceId, QString>(&ResIdToString);
QMetaType::registerConverter<GPUAddressPtr, QString>(&GPUAddressToString);
}
void RichResourceTextInitialise(QVariant &var)
@@ -211,14 +341,40 @@ void RichResourceTextInitialise(QVariant &var)
QString text = var.toString().trimmed();
// do a simple string search first before using regular expressions
if(!text.contains(lit("ResourceId::")))
if(!text.contains(lit("ResourceId::")) && !text.contains(lit("GPUAddress::")))
return;
// two forms: GPUAddress::012345 - typeless
// GPUAddress::012345::991 - using type 991 from PointerTypeRegistry
static QRegularExpression addrRE(lit("GPUAddress::([0-9]*)(::([0-9]*))?"));
QRegularExpressionMatch match = addrRE.match(text);
if(match.hasMatch())
{
// don't support mixed text & addresses. Only do the replacement if we matched the whole string
if(match.capturedStart(0) == 0 && match.capturedLength(0) == text.length())
{
GPUAddressPtr addr(new GPUAddress);
addr->val.pointer = match.captured(1).toULongLong();
// we deliberately set this to ResourceId() to indicate that we're using an ID from the
// registry, not a shader-relative index
addr->val.shader = ResourceId();
addr->val.pointerTypeID = match.captured(3).toULong();
var = QVariant::fromValue(addr);
return;
}
return;
}
// use regexp to split up into fragments of text and resourceid. The resourceid is then
// formatted on the fly in RichResourceText::cacheDocument
static QRegularExpression re(lit("(ResourceId::)([0-9]*)"));
static QRegularExpression resRE(lit("(ResourceId::)([0-9]*)"));
QRegularExpressionMatch match = re.match(text);
match = resRE.match(text);
if(match.hasMatch())
{
@@ -250,7 +406,7 @@ void RichResourceTextInitialise(QVariant &var)
linkedText->fragments.push_back(id);
match = re.match(text);
match = resRE.match(text);
}
if(!text.isEmpty())
@@ -265,6 +421,7 @@ void RichResourceTextInitialise(QVariant &var)
bool RichResourceTextCheck(const QVariant &var)
{
return var.userType() == qMetaTypeId<RichResourceTextPtr>() ||
var.userType() == qMetaTypeId<GPUAddressPtr>() ||
var.userType() == qMetaTypeId<ResourceId>();
}
@@ -275,8 +432,8 @@ static const int RichResourceTextMargin = 2;
void RichResourceTextPaint(const QWidget *owner, QPainter *painter, QRect rect, QFont font,
QPalette palette, bool mouseOver, QPoint mousePos, const QVariant &var)
{
// special case handling for ResourceId
if(var.userType() == qMetaTypeId<ResourceId>())
// special case handling for ResourceId/GPUAddress on its own
if(var.userType() == qMetaTypeId<ResourceId>() || var.userType() == qMetaTypeId<GPUAddressPtr>())
{
painter->save();
@@ -290,14 +447,46 @@ void RichResourceTextPaint(const QWidget *owner, QPainter *painter, QRect rect,
QString name;
ICaptureContext *ctxptr = getCaptureContext(owner);
bool valid = false;
ResourceId id = var.value<ResourceId>();
if(var.userType() == qMetaTypeId<ResourceId>())
{
ICaptureContext *ctxptr = getCaptureContext(owner);
if(ctxptr)
name = ctxptr->GetResourceName(id);
ResourceId id = var.value<ResourceId>();
valid = (id != ResourceId());
if(ctxptr)
name = ctxptr->GetResourceName(id);
else
name = ToQStr(id);
}
else
name = ToQStr(id);
{
GPUAddressPtr ptr = var.value<GPUAddressPtr>();
ptr->cacheAddress(owner);
valid = (ptr->val.pointer != 0);
if(valid)
{
if(ptr->base != ResourceId())
{
name = QFormatStr("%1+%2").arg(ptr->ctxptr->GetResourceName(ptr->base)).arg(ptr->offset);
}
else
{
name = QFormatStr("Unknown 0x%1").arg(ptr->val.pointer, 16, 16);
valid = false;
}
}
else
{
name = lit("NULL");
}
}
painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, name);
@@ -318,7 +507,7 @@ void RichResourceTextPaint(const QWidget *owner, QPainter *painter, QRect rect,
painter->drawPixmap(pos, px, px.rect());
if(mouseOver && textRect.contains(mousePos) && id != ResourceId())
if(mouseOver && textRect.contains(mousePos) && valid)
{
int underline_y = textRect.bottom() + margin;
@@ -400,8 +589,8 @@ void RichResourceTextPaint(const QWidget *owner, QPainter *painter, QRect rect,
int RichResourceTextWidthHint(const QWidget *owner, const QFont &font, const QVariant &var)
{
// special case handling for ResourceId
if(var.userType() == qMetaTypeId<ResourceId>())
// special case handling for ResourceId/GPUAddress on its own
if(var.userType() == qMetaTypeId<ResourceId>() || var.userType() == qMetaTypeId<GPUAddressPtr>())
{
QFont f = font;
f.setBold(true);
@@ -412,12 +601,28 @@ int RichResourceTextWidthHint(const QWidget *owner, const QFont &font, const QVa
QString name;
ICaptureContext *ctxptr = getCaptureContext(owner);
if(var.userType() == qMetaTypeId<ResourceId>())
{
ICaptureContext *ctxptr = getCaptureContext(owner);
if(ctxptr)
name = ctxptr->GetResourceName(var.value<ResourceId>());
ResourceId id = var.value<ResourceId>();
if(ctxptr)
name = ctxptr->GetResourceName(id);
else
name = ToQStr(id);
}
else
name = ToQStr(var.value<ResourceId>());
{
GPUAddressPtr ptr = var.value<GPUAddressPtr>();
ptr->cacheAddress(owner);
if(ptr->val.pointer != 0)
name = QFormatStr("%1+%2").arg(ptr->ctxptr->GetResourceName(ptr->base)).arg(ptr->offset);
else
name = lit("NULL");
}
const QPixmap &px = Pixmaps::link(owner->devicePixelRatio());
@@ -439,14 +644,32 @@ bool RichResourceTextMouseEvent(const QWidget *owner, const QVariant &var, QRect
if(event->type() != QEvent::MouseButtonRelease && event->type() != QEvent::MouseMove)
return false;
// special case handling for ResourceId
if(var.userType() == qMetaTypeId<ResourceId>())
// special case handling for ResourceId/GPUAddress on its own
if(var.userType() == qMetaTypeId<ResourceId>() || var.userType() == qMetaTypeId<GPUAddressPtr>())
{
ResourceId id = var.value<ResourceId>();
ResourceId id;
GPUAddressPtr ptr;
ICaptureContext *ctxptr = NULL;
// empty resource ids are not clickable or hover-highlighted.
if(id == ResourceId())
return false;
if(var.userType() == qMetaTypeId<ResourceId>())
{
id = var.value<ResourceId>();
// empty resource ids are not clickable or hover-highlighted.
if(id == ResourceId())
return false;
}
if(var.userType() == qMetaTypeId<GPUAddressPtr>())
{
ptr = var.value<GPUAddressPtr>();
ptr->cacheAddress(owner);
// NULL or unknown addresses also are not clickable
if(ptr->val.pointer == 0 || ptr->base == ResourceId())
return false;
}
QFont f = font;
f.setBold(true);
@@ -457,12 +680,21 @@ bool RichResourceTextMouseEvent(const QWidget *owner, const QVariant &var, QRect
QString name;
ICaptureContext *ctxptr = getCaptureContext(owner);
if(var.userType() == qMetaTypeId<ResourceId>())
{
ctxptr = getCaptureContext(owner);
if(ctxptr)
name = ctxptr->GetResourceName(id);
if(ctxptr)
name = ctxptr->GetResourceName(id);
else
name = ToQStr(id);
}
else
name = ToQStr(id);
{
ctxptr = ptr->ctxptr;
name = QFormatStr("%1+%2").arg(ptr->ctxptr->GetResourceName(ptr->base)).arg(ptr->offset);
}
QRect textRect = QFontMetrics(f).boundingRect(rect, Qt::AlignLeft | Qt::AlignVCenter, name);
@@ -472,21 +704,45 @@ bool RichResourceTextMouseEvent(const QWidget *owner, const QVariant &var, QRect
rect.setWidth(textRect.width() + margin + px.width());
rect.setHeight(qMax(textRect.height(), px.height()));
if(rect.contains(event->pos()) && id != ResourceId())
if(rect.contains(event->pos()))
{
if(event->type() == QEvent::MouseButtonRelease && ctxptr)
if(var.userType() == qMetaTypeId<ResourceId>())
{
ICaptureContext &ctx = *(ICaptureContext *)ctxptr;
if(event->type() == QEvent::MouseButtonRelease && ctxptr)
{
ICaptureContext &ctx = *(ICaptureContext *)ctxptr;
if(!ctx.HasResourceInspector())
ctx.ShowResourceInspector();
if(!ctx.HasResourceInspector())
ctx.ShowResourceInspector();
ctx.GetResourceInspector()->Inspect(id);
ctx.GetResourceInspector()->Inspect(id);
ctx.RaiseDockWindow(ctx.GetResourceInspector()->Widget());
ctx.RaiseDockWindow(ctx.GetResourceInspector()->Widget());
}
return true;
}
else if(var.userType() == qMetaTypeId<GPUAddressPtr>())
{
if(event->type() == QEvent::MouseButtonRelease && ctxptr)
{
ICaptureContext &ctx = *(ICaptureContext *)ctxptr;
return true;
const ShaderVariableType &ptrType = PointerTypeRegistry::GetTypeDescriptor(ptr->val);
QString formatter;
if(!ptrType.members.isEmpty())
formatter = BufferFormatter::DeclareStruct(ptrType.descriptor.name, ptrType.members,
ptrType.descriptor.arrayByteStride);
IBufferViewer *view = ctx.ViewBuffer(ptr->offset, 0, ptr->base, formatter);
ctx.AddDockWindow(view->Widget(), DockReference::MainToolArea, NULL);
}
return true;
}
}
return false;
+44
View File
@@ -124,6 +124,50 @@ class RDTreeWidgetItem;
void addStructuredObjects(RDTreeWidgetItem *parent, const StructuredObjectList &objs,
bool parentIsArray);
struct PointerTypeRegistry
{
public:
static void Init();
static void CacheShader(const ShaderReflection *reflection);
static uint32_t GetTypeID(ResourceId shader, uint32_t pointerTypeId);
static uint32_t GetTypeID(PointerVal val) { return GetTypeID(val.shader, val.pointerTypeID); }
static uint32_t GetTypeID(const ShaderVariableType &structDef);
static const ShaderVariableType &GetTypeDescriptor(uint32_t typeId);
static const ShaderVariableType &GetTypeDescriptor(ResourceId shader, uint32_t pointerTypeId)
{
return GetTypeDescriptor(GetTypeID(shader, pointerTypeId));
}
static const ShaderVariableType &GetTypeDescriptor(PointerVal val)
{
return GetTypeDescriptor(GetTypeID(val));
}
private:
static void CacheSubTypes(const ShaderReflection *reflection, ShaderVariableType &structDef);
static QMap<QPair<ResourceId, uint32_t>, uint32_t> typeMapping;
static rdcarray<ShaderVariableType> typeDescriptions;
};
struct GPUAddress
{
GPUAddress() = default;
GPUAddress(const PointerVal &v) : val(v) {}
PointerVal val;
// cached data
ResourceId base;
uint64_t offset = 0;
// cache the context once we've obtained it.
ICaptureContext *ctxptr = NULL;
void cacheAddress(const QWidget *widget);
};
// this will check the variant, and if it contains a ResourceId directly or text with ResourceId
// identifiers then it will be converted into a RichResourceTextPtr or ResourceId in-place. The new
// QVariant will still convert to QString so it doesn't have to be special-cased. However it must be
+1
View File
@@ -319,6 +319,7 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, BoundResourceArray)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, FloatVector)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, GraphicsAPI)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, GPUDevice)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderVariableType)
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, Attachment)
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, BindingElement)
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, DescriptorBinding)
+8
View File
@@ -879,6 +879,14 @@ public:
else
v = list[comp * rowdim];
if(el.type.descriptor.pointerTypeID != ~0U)
{
PointerVal ptr;
ptr.pointer = v.toULongLong();
ptr.pointerTypeID = el.type.descriptor.pointerTypeID;
v = ToQStr(ptr);
}
RichResourceTextInitialise(v);
if(RichResourceTextCheck(v))
@@ -79,32 +79,6 @@ static uint32_t byteSize(const ResourceFormat &fmt)
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 == 4)
ret += lit("xint pad;");
else 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");
}
PipelineStateViewer::PipelineStateViewer(ICaptureContext &ctx, QWidget *parent)
: QFrame(parent), ui(new Ui::PipelineStateViewer), m_Ctx(ctx)
{
@@ -617,83 +591,6 @@ void PipelineStateViewer::setMeshViewPixmap(RDLabel *meshView)
});
}
QString PipelineStateViewer::declareStruct(QList<QString> &declaredStructs, const QString &name,
const rdcarray<ShaderConstant> &members,
uint32_t requiredByteStride)
{
QString ret;
ret = lit("struct %1\n{\n").arg(name);
for(int i = 0; i < members.count(); i++)
{
QString arraySize;
if(members[i].type.descriptor.elements > 1)
arraySize = QFormatStr("[%1]").arg(members[i].type.descriptor.elements);
QString varTypeName = members[i].type.descriptor.name;
if(!members[i].type.members.isEmpty())
{
// GL structs don't give us typenames (boo!) so give them unique names. This will mean some
// structs get duplicated if they're used in multiple places, but not much we can do about
// that.
if(varTypeName.isEmpty() || varTypeName == lit("struct"))
varTypeName = lit("anon%1").arg(declaredStructs.size());
if(!declaredStructs.contains(varTypeName))
{
declaredStructs.push_back(varTypeName);
ret = declareStruct(declaredStructs, varTypeName, members[i].type.members,
members[i].type.descriptor.arrayByteStride) +
lit("\n") + ret;
}
}
ret += QFormatStr(" %1 %2%3;\n").arg(varTypeName).arg(members[i].name).arg(arraySize);
}
if(requiredByteStride > 0)
{
uint32_t structStart = 0;
const ShaderConstant *lastChild = &members.back();
structStart += lastChild->byteOffset;
while(!lastChild->type.members.isEmpty())
{
lastChild = &lastChild->type.members.back();
structStart += lastChild->byteOffset;
}
uint32_t size = lastChild->type.descriptor.rows * lastChild->type.descriptor.columns;
if(lastChild->type.descriptor.type == VarType::Double ||
lastChild->type.descriptor.type == VarType::ULong ||
lastChild->type.descriptor.type == VarType::SLong)
size *= 8;
else if(lastChild->type.descriptor.type == VarType::Float ||
lastChild->type.descriptor.type == VarType::UInt ||
lastChild->type.descriptor.type == VarType::SInt)
size *= 4;
else if(lastChild->type.descriptor.type == VarType::Half ||
lastChild->type.descriptor.type == VarType::UShort ||
lastChild->type.descriptor.type == VarType::SShort)
size *= 2;
if(lastChild->type.descriptor.elements > 1)
size *= lastChild->type.descriptor.elements;
uint32_t padBytes = requiredByteStride - (lastChild->byteOffset + size);
if(padBytes > 0)
ret += lit(" ") + padding(padBytes);
}
ret += lit("}\n");
return ret;
}
void PipelineStateViewer::MakeShaderVariablesHLSL(bool cbufferContents,
const rdcarray<ShaderConstant> &vars,
QString &struct_contents, QString &struct_defs)
@@ -1181,7 +1078,7 @@ QString PipelineStateViewer::GetVBufferFormatString(uint32_t slot)
continue;
// declare any padding from previous element to this one
format += padding(attrs[i].byteOffset - offset);
format += BufferFormatter::DeclarePaddingBytes(attrs[i].byteOffset - offset);
const ResourceFormat &fmt = attrs[i].format;
@@ -1261,7 +1158,7 @@ QString PipelineStateViewer::GetVBufferFormatString(uint32_t slot)
}
if(stride > 0)
format += padding(stride - offset);
format += BufferFormatter::DeclarePaddingBytes(stride - offset);
return format;
}
@@ -91,9 +91,6 @@ private:
QMenu *editMenus[6] = {};
QString declareStruct(QList<QString> &declaredStructs, const QString &name,
const rdcarray<ShaderConstant> &members, uint32_t requiredByteStride);
QString GenerateHLSLStub(const ShaderBindpointMapping &bindpointMapping,
const ShaderReflection *shaderDetails, const QString &entryFunc);
IShaderViewer *EditShader(ResourceId id, ShaderStage shaderType, const rdcstr &entry,
+9 -3
View File
@@ -484,7 +484,8 @@ struct BufferDescription
bool operator==(const BufferDescription &o) const
{
return resourceId == o.resourceId && creationFlags == o.creationFlags && length == o.length;
return resourceId == o.resourceId && creationFlags == o.creationFlags &&
gpuAddress == o.gpuAddress && length == o.length;
}
bool operator<(const BufferDescription &o) const
{
@@ -492,6 +493,8 @@ struct BufferDescription
return resourceId < o.resourceId;
if(!(creationFlags == o.creationFlags))
return creationFlags < o.creationFlags;
if(!(gpuAddress == o.gpuAddress))
return gpuAddress < o.gpuAddress;
if(!(length == o.length))
return length < o.length;
return false;
@@ -500,10 +503,13 @@ struct BufferDescription
ResourceId resourceId;
DOCUMENT("The way this buffer will be used in the pipeline.");
BufferCategory creationFlags;
BufferCategory creationFlags = BufferCategory::NoFlags;
DOCUMENT("The known base GPU Address of this buffer. 0 if not applicable or available.");
uint64_t gpuAddress = 0;
DOCUMENT("The byte length of the buffer.");
uint64_t length;
uint64_t length = 0;
};
DECLARE_REFLECTION_STRUCT(BufferDescription);
+90 -17
View File
@@ -97,6 +97,25 @@ struct UIntVecVal
uint32_t w;
};
DOCUMENT("A 64-bit pointer value with optional type information.")
struct PointerVal
{
DOCUMENT("");
PointerVal() = default;
PointerVal(const PointerVal &) = default;
DOCUMENT("The actual pointer value itself.");
uint64_t pointer;
DOCUMENT("An optional :class:`ResourceId` identifying the shader containing the type info.");
ResourceId shader;
DOCUMENT("The index into :data:`ShaderReflection.pointerTypes` of the pointed type.");
uint32_t pointerTypeID;
};
DECLARE_STRINGISE_TYPE(PointerVal);
DOCUMENT("A C union that holds 16 values, with each different basic variable type.");
union ShaderValue
{
@@ -141,7 +160,7 @@ struct ShaderVariable
{
name = "";
rows = columns = 0;
displayAsHex = isStruct = rowMajor = false;
displayAsHex = isStruct = rowMajor = isPointer = false;
type = VarType::Float;
for(int i = 0; i < 16; i++)
value.uv[i] = 0;
@@ -152,7 +171,7 @@ struct ShaderVariable
name = n;
rows = 1;
columns = 4;
displayAsHex = isStruct = rowMajor = false;
displayAsHex = isStruct = rowMajor = isPointer = false;
for(int i = 0; i < 16; i++)
value.uv[i] = 0;
type = VarType::Float;
@@ -166,7 +185,7 @@ struct ShaderVariable
name = n;
rows = 1;
columns = 4;
displayAsHex = isStruct = rowMajor = false;
displayAsHex = isStruct = rowMajor = isPointer = false;
for(int i = 0; i < 16; i++)
value.uv[i] = 0;
type = VarType::SInt;
@@ -180,7 +199,7 @@ struct ShaderVariable
name = n;
rows = 1;
columns = 4;
displayAsHex = isStruct = rowMajor = false;
displayAsHex = isStruct = rowMajor = isPointer = false;
for(int i = 0; i < 16; i++)
value.uv[i] = 0;
type = VarType::UInt;
@@ -193,7 +212,8 @@ struct ShaderVariable
{
return rows == o.rows && columns == o.columns && name == o.name && type == o.type &&
displayAsHex == o.displayAsHex && !memcmp(&value, &o.value, sizeof(value)) &&
isStruct == o.isStruct && members == o.members;
isStruct == o.isStruct && rowMajor == o.rowMajor && isPointer == o.isPointer &&
members == o.members;
}
bool operator<(const ShaderVariable &o) const
{
@@ -211,6 +231,8 @@ struct ShaderVariable
return isStruct < o.isStruct;
if(!(rowMajor == o.rowMajor))
return rowMajor < o.rowMajor;
if(!(isPointer == o.isPointer))
return isPointer < o.isPointer;
if(memcmp(&value, &o.value, sizeof(value)) < 0)
return true;
if(!(members == o.members))
@@ -218,18 +240,16 @@ struct ShaderVariable
return false;
}
DOCUMENT("The number of rows in this matrix.");
uint32_t rows;
DOCUMENT("The number of columns in this matrix.");
uint32_t columns;
DOCUMENT("The name of this variable.");
rdcstr name;
DOCUMENT("The :class:`basic type <VarType>` of this variable.");
VarType type;
DOCUMENT("The number of rows in this matrix.");
uint8_t rows;
DOCUMENT("The number of columns in this matrix.");
uint8_t columns;
DOCUMENT("The :class:`contents <ShaderValue>` of this variable if it has no members.");
ShaderValue value;
DOCUMENT("``True`` if this variable is a pointer.");
bool isPointer;
DOCUMENT("``True`` if the contents of this variable should be displayed as hex.");
bool displayAsHex;
@@ -240,8 +260,56 @@ struct ShaderVariable
DOCUMENT("``True`` if this variable is stored in rows in memory. Only relevant for matrices.");
bool rowMajor;
DOCUMENT("The :class:`basic type <VarType>` of this variable.");
VarType type;
DOCUMENT("The :class:`contents <ShaderValue>` of this variable if it has no members.");
ShaderValue value;
DOCUMENT("The members of this variable as a list of :class:`ShaderVariable`.");
rdcarray<ShaderVariable> members;
DOCUMENT(R"(Utility function for setting a pointer value with no type information.
:param int pointer: The actual pointer value.
)");
inline void SetTypelessPointer(uint64_t pointer)
{
isPointer = true;
value.u64v[0] = pointer;
}
DOCUMENT(R"(Utility function for setting a pointer value with type information.
:param int pointer: The actual pointer value.
:param ResourceId shader: The shader containing the type information.
:param int pointerTypeID: The type's index in the shader's :data:`ShaderReflection.pointerTypes`
list.
)");
inline void SetTypedPointer(uint64_t pointer, ResourceId shader, uint32_t pointerTypeID)
{
isPointer = true;
value.u64v[0] = pointer;
value.u64v[1] = pointerTypeID;
pointerShader = shader;
}
DOCUMENT(R"(Utility function for getting a pointer value, with optional type information.
:return: A :class:`PointerVal` with the pointer value.
:rtype: PointerVal
)");
inline PointerVal GetPointer() const
{
return {value.u64v[0], pointerShader, uint32_t(value.u64v[1] & 0xFFFFFFFF)};
}
private:
DOCUMENT("");
ResourceId pointerShader;
// make DoSerialise a friend so it can serialise pointerShader
template <typename SerialiserType>
friend void DoSerialise(SerialiserType &ser, ShaderVariable &el);
};
DECLARE_REFLECTION_STRUCT(ShaderVariable);
@@ -613,7 +681,7 @@ struct ShaderVariableDescriptor
return type == o.type && rows == o.rows && columns == o.columns &&
rowMajorStorage == o.rowMajorStorage && elements == o.elements &&
arrayByteStride == o.arrayByteStride && matrixByteStride == o.matrixByteStride &&
name == o.name;
pointerTypeID == o.pointerTypeID && name == o.name;
}
bool operator<(const ShaderVariableDescriptor &o) const
{
@@ -637,6 +705,8 @@ struct ShaderVariableDescriptor
}
DOCUMENT("The name of the type of this constant, e.g. a ``struct`` name.");
rdcstr name;
DOCUMENT("The index in :data:`ShaderReflection.pointerTypes` of the pointee type.");
uint32_t pointerTypeID = ~0U;
DOCUMENT("The number of elements in the array, or 1 if it's not an array.");
uint32_t elements = 1;
DOCUMENT("The number of bytes between the start of one element in the array and the next.");
@@ -653,9 +723,9 @@ struct ShaderVariableDescriptor
bool rowMajorStorage = false;
DOCUMENT("``True`` if the contents of this variable should be displayed as hex.");
bool displayAsHex = false;
DOCUMENT(R"(``True`` if the contents of this variable should be displayed as RGB color (where
possible).
)");
DOCUMENT(R"(``True`` if the contents of this variable should be displayed as RGB color (where
possible).
)");
bool displayAsRGB = false;
};
@@ -1042,6 +1112,9 @@ struct ShaderReflection
// TODO expand this to encompass shader subroutines.
DOCUMENT("A list of strings with the shader's interfaces. Largely an unused API feature.");
rdcarray<rdcstr> interfaces;
DOCUMENT("A list of :class:`ShaderVariableType` with the shader's pointer types.");
rdcarray<ShaderVariableType> pointerTypes;
};
DECLARE_REFLECTION_STRUCT(ShaderReflection);
+20 -1
View File
@@ -62,7 +62,7 @@ void LogReplayOptions(const ReplayOptions &opts)
RDCLOG("Replay optimisation level: %s", ToStr(opts.optimisation).c_str());
}
// this one is done by hand as we format it
// these one is done by hand as we format it
template <>
rdcstr DoStringise(const ResourceId &el)
{
@@ -105,10 +105,29 @@ rdcstr DoStringise(const ResourceId &el)
for(size_t i = 0; i <= prefixlast; i++)
*(c--) = PREFIX[prefixlast - i];
#undef PREFIX
// the loop will have stepped us to the first NULL before our string, so return c+1
return c + 1;
}
template <>
rdcstr DoStringise(const PointerVal &el)
{
if(el.shader != ResourceId())
{
// we don't want to format as an ID, we need to encode the raw value
uint64_t num;
memcpy(&num, &el.shader, sizeof(num));
return StringFormat::Fmt("GPUAddress::%llu::%llu::%u", el.pointer, num, el.pointerTypeID);
}
else
{
return StringFormat::Fmt("GPUAddress::%llu", el.pointer);
}
}
BASIC_TYPE_SERIALISE_STRINGIFY(ResourceId, (uint64_t &)el, SDBasic::Resource, 8);
INSTANTIATE_SERIALISE_TYPE(ResourceId);
+2 -1
View File
@@ -2799,7 +2799,8 @@ void D3D11Replay::FillCBufferVariables(ResourceId pipeline, ResourceId shader,
return;
}
StandardFillCBufferVariables(refl.constantBlocks[cbufSlot].variables, outvars, data);
StandardFillCBufferVariables(refl.resourceId, refl.constantBlocks[cbufSlot].variables, outvars,
data);
}
uint32_t D3D11Replay::PickVertex(uint32_t eventId, int32_t width, int32_t height,
+2 -1
View File
@@ -2774,7 +2774,8 @@ void D3D12Replay::FillCBufferVariables(ResourceId pipeline, ResourceId shader,
}
}
StandardFillCBufferVariables(c.variables, outvars, rootData.empty() ? data : rootData);
StandardFillCBufferVariables(refl.resourceId, c.variables, outvars,
rootData.empty() ? data : rootData);
}
std::vector<DebugMessage> D3D12Replay::GetDebugMessages()
+15 -10
View File
@@ -1958,7 +1958,8 @@ void GLReplay::SavePipelineState(uint32_t eventId)
pipe.hints.polySmoothingEnabled = rs.Enabled[GLRenderState::eEnabled_PolySmooth];
}
void GLReplay::OpenGLFillCBufferVariables(GLuint prog, bool bufferBacked, std::string prefix,
void GLReplay::OpenGLFillCBufferVariables(ResourceId shader, GLuint prog, bool bufferBacked,
std::string prefix,
const rdcarray<ShaderConstant> &variables,
rdcarray<ShaderVariable> &outvars,
const bytebuf &bufferData)
@@ -1991,7 +1992,7 @@ void GLReplay::OpenGLFillCBufferVariables(GLuint prog, bool bufferBacked, std::s
{
if(desc.elements == 0)
{
OpenGLFillCBufferVariables(prog, bufferBacked, prefix + var.name.c_str() + ".",
OpenGLFillCBufferVariables(shader, prog, bufferBacked, prefix + var.name.c_str() + ".",
variables[i].type.members, var.members, data);
var.isStruct = true;
}
@@ -2008,7 +2009,7 @@ void GLReplay::OpenGLFillCBufferVariables(GLuint prog, bool bufferBacked, std::s
arrEl.isStruct = true;
arrEl.rowMajor = var.rowMajor;
OpenGLFillCBufferVariables(prog, bufferBacked, prefix + arrEl.name.c_str() + ".",
OpenGLFillCBufferVariables(shader, prog, bufferBacked, prefix + arrEl.name.c_str() + ".",
variables[i].type.members, arrEl.members, data);
}
var.isStruct = false;
@@ -2110,7 +2111,7 @@ void GLReplay::OpenGLFillCBufferVariables(GLuint prog, bool bufferBacked, std::s
}
}
StandardFillCBufferVariable(offset, data, var, matStride);
StandardFillCBufferVariable(shader, desc, offset, data, var, matStride);
}
else
{
@@ -2155,7 +2156,7 @@ void GLReplay::OpenGLFillCBufferVariables(GLuint prog, bool bufferBacked, std::s
}
}
StandardFillCBufferVariable(offset, data, el, matStride);
StandardFillCBufferVariable(shader, desc, offset, data, el, matStride);
if(bufferBacked)
offset += desc.arrayByteStride;
@@ -2221,8 +2222,9 @@ void GLReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, std:
if(shaderDetails.spirvWords.empty())
{
OpenGLFillCBufferVariables(curProg, cblock.bufferBacked ? true : false, "", cblock.variables,
outvars, data);
OpenGLFillCBufferVariables(shaderDetails.reflection.resourceId, curProg,
cblock.bufferBacked ? true : false, "", cblock.variables, outvars,
data);
}
else
{
@@ -2239,15 +2241,18 @@ void GLReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, std:
specconsts.push_back(spec);
}
FillSpecConstantVariables(cblock.variables, outvars, specconsts);
FillSpecConstantVariables(shaderDetails.reflection.resourceId, cblock.variables, outvars,
specconsts);
}
else if(!cblock.bufferBacked)
{
OpenGLFillCBufferVariables(curProg, false, "", cblock.variables, outvars, data);
OpenGLFillCBufferVariables(shaderDetails.reflection.resourceId, curProg, false, "",
cblock.variables, outvars, data);
}
else
{
StandardFillCBufferVariables(cblock.variables, outvars, data);
StandardFillCBufferVariables(shaderDetails.reflection.resourceId, cblock.variables, outvars,
data);
}
}
}
+2 -2
View File
@@ -238,8 +238,8 @@ public:
bool IsReplayContext(void *ctx) { return m_ReplayCtx.ctx == NULL || ctx == m_ReplayCtx.ctx; }
bool HasDebugContext() { return m_DebugCtx != NULL; }
private:
void OpenGLFillCBufferVariables(GLuint prog, bool bufferBacked, std::string prefix,
const rdcarray<ShaderConstant> &variables,
void OpenGLFillCBufferVariables(ResourceId shader, GLuint prog, bool bufferBacked,
std::string prefix, const rdcarray<ShaderConstant> &variables,
rdcarray<ShaderVariable> &outvars, const bytebuf &data);
bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, bool stencil,
+6 -2
View File
@@ -730,9 +730,11 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa
}
var.type.descriptor.rowMajorStorage = (values[6] > 0);
var.type.descriptor.arrayByteStride = values[7];
var.type.descriptor.matrixByteStride = (uint8_t)values[8];
RDCASSERTMSG("Stride is too large for uint16_t", values[7] <= 0xffff);
var.type.descriptor.arrayByteStride = RDCMIN((uint32_t)values[7], 0xffffu) & 0xffff;
bool bareUniform = false;
// for plain uniforms we won't get an array/matrix byte stride. Calculate tightly packed strides
@@ -870,9 +872,11 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa
parentVar.type.descriptor.type = var.type.descriptor.type;
parentVar.type.descriptor.elements =
isarray && !multiDimArray ? RDCMAX(1U, uint32_t(arrayIdx + 1)) : 0;
parentVar.type.descriptor.arrayByteStride = topLevelStride;
parentVar.type.descriptor.matrixByteStride = 0;
RDCASSERTMSG("Stride is too large for uint16_t", topLevelStride <= 0xffff);
parentVar.type.descriptor.arrayByteStride = RDCMIN((uint32_t)topLevelStride, 0xffffu) & 0xffff;
// consider all block-level SSBO structs to have infinite elements if they are an array at all
if(blockLevel && topLevelStride && isarray)
parentVar.type.descriptor.elements = ~0U;
+1 -1
View File
@@ -4185,7 +4185,7 @@ void CreateShaderDebugStateAndTrace(ShaderDebug::State &initialState, ShaderDebu
rdcarray<ShaderVariable> vars;
// Fetch cbuffers into vars, which will be 'natural': structs with members, non merged vectors
StandardFillCBufferVariables(refl.constantBlocks[i].variables, vars,
StandardFillCBufferVariables(refl.resourceId, refl.constantBlocks[i].variables, vars,
cbufData[dxbc->GetReflection()->CBuffers[i].reg]);
FlattenVariables(refl.constantBlocks[i].variables, vars, trace.constantBlocks[i].members);
@@ -64,7 +64,9 @@ static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type)
if(type.descriptor.varClass == DXBC::CLASS_STRUCT)
{
ret.descriptor.arrayByteStride = type.descriptor.bytesize / RDCMAX(1U, type.descriptor.elements);
uint32_t stride = type.descriptor.bytesize / RDCMAX(1U, type.descriptor.elements);
RDCASSERTMSG("Stride is too large for uint16_t", stride <= 0xffff);
ret.descriptor.arrayByteStride = RDCMIN(stride, 0xffffu) & 0xffff;
}
else
{
@@ -553,7 +553,7 @@ void Processor::RegisterOp(Iter it)
{
v.type = type.scalar().Type();
v.rows = 1;
v.columns = type.vector().count;
v.columns = type.vector().count & 0xf;
if(type.scalar().width == 32)
{
@@ -569,8 +569,8 @@ void Processor::RegisterOp(Iter it)
else if(type.type == DataType::MatrixType)
{
v.type = type.scalar().Type();
v.rows = type.vector().count;
v.columns = type.matrix().count;
v.rows = type.vector().count & 0xf;
v.columns = type.matrix().count & 0xf;
// always store constants row major
v.rowMajor = true;
@@ -29,11 +29,11 @@
#include "replay/replay_driver.h"
#include "spirv_editor.h"
void FillSpecConstantVariables(const rdcarray<ShaderConstant> &invars,
void FillSpecConstantVariables(ResourceId shader, const rdcarray<ShaderConstant> &invars,
rdcarray<ShaderVariable> &outvars,
const std::vector<SpecConstant> &specInfo)
{
StandardFillCBufferVariables(invars, outvars, bytebuf());
StandardFillCBufferVariables(shader, invars, outvars, bytebuf());
RDCASSERTEQUAL(invars.size(), outvars.size());
@@ -797,6 +797,9 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
rdcarray<cblockpair> cblocks;
rdcarray<shaderrespair> samplers, roresources, rwresources;
// for pointer types, mapping of inner type ID to index in list (assigned sequentially)
SparseIdMap<uint16_t> pointerTypes;
// $Globals gathering - for GL global values
ConstantBlock globalsblock;
@@ -1052,8 +1055,8 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
ShaderConstant constant;
MakeConstantBlockVariable(constant, *varType, strings[global.id], decorations[global.id],
specInfo);
MakeConstantBlockVariable(constant, pointerTypes, *varType, strings[global.id],
decorations[global.id], specInfo);
if(isArray)
constant.type.descriptor.elements = arraySize;
@@ -1090,7 +1093,8 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
res.variableType.descriptor.type = VarType::Float;
res.variableType.descriptor.name = varType->name;
MakeConstantBlockVariables(*varType, 0, 0, res.variableType.members, specInfo);
MakeConstantBlockVariables(*varType, 0, 0, res.variableType.members, pointerTypes,
specInfo);
rwresources.push_back(shaderrespair(bindmap, res));
}
@@ -1103,7 +1107,7 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
cblock.name = StringFormat::Fmt("uniforms%u", global.id);
cblock.bufferBacked = !pushConst;
MakeConstantBlockVariables(*varType, 0, 0, cblock.variables, specInfo);
MakeConstantBlockVariables(*varType, 0, 0, cblock.variables, pointerTypes, specInfo);
if(!varType->children.empty())
cblock.byteSize = CalculateMinimumByteSize(cblock.variables);
@@ -1137,7 +1141,8 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
name = StringFormat::Fmt("specID%u", decorations[c.id].specID);
ShaderConstant spec;
MakeConstantBlockVariable(spec, dataTypes[c.type], name, decorations[c.id], specInfo);
MakeConstantBlockVariable(spec, pointerTypes, dataTypes[c.type], name, decorations[c.id],
specInfo);
spec.byteOffset = decorations[c.id].specID;
spec.defaultValue = c.value.value.u64v[0];
specblock.variables.push_back(spec);
@@ -1353,6 +1358,21 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
reflection.readWriteResources[i] = rwresources[i].bindres;
reflection.readWriteResources[i].bindPoint = (int32_t)i;
}
// populate the pointer types
reflection.pointerTypes.reserve(pointerTypes.size());
for(auto it = pointerTypes.begin(); it != pointerTypes.end(); ++it)
{
ShaderConstant dummy;
MakeConstantBlockVariable(dummy, pointerTypes, dataTypes[it->first], rdcstr(), Decorations(),
specInfo);
if(it->second >= reflection.pointerTypes.size())
reflection.pointerTypes.resize(it->second + 1);
reflection.pointerTypes[it->second] = dummy.type;
}
}
ShaderVariable Reflector::EvaluateConstant(Id constID, const std::vector<SpecConstant> &specInfo) const
@@ -1568,7 +1588,7 @@ ShaderVariable Reflector::EvaluateConstant(Id constID, const std::vector<SpecCon
indices.push_back(specop.params[i].value());
ret = ShaderVariable("derived", 0, 0, 0, 0);
ret.columns = (uint32_t)indices.size();
ret.columns = (uint8_t)indices.size();
for(size_t i = 0; i < indices.size(); i++)
{
@@ -1661,7 +1681,7 @@ ShaderVariable Reflector::EvaluateConstant(Id constID, const std::vector<SpecCon
// all other operations are component-wise on vectors or scalars. Check that rows are all 1 and
// all cols are identical
uint32_t cols = params[0].columns;
uint8_t cols = params[0].columns;
for(size_t i = 0; i < params.size(); i++)
{
RDCASSERT(cols == params[i].columns, i, params[i].columns);
@@ -1872,6 +1892,7 @@ ShaderVariable Reflector::EvaluateConstant(Id constID, const std::vector<SpecCon
void Reflector::MakeConstantBlockVariables(const DataType &structType, uint32_t arraySize,
uint32_t arrayByteStride, rdcarray<ShaderConstant> &cblock,
SparseIdMap<uint16_t> &pointerTypes,
const std::vector<SpecConstant> &specInfo) const
{
// we get here for multi-dimensional arrays
@@ -1885,7 +1906,7 @@ void Reflector::MakeConstantBlockVariables(const DataType &structType, uint32_t
cblock.resize(arraySize);
for(uint32_t i = 0; i < arraySize; i++)
{
MakeConstantBlockVariable(cblock[i], structType, StringFormat::Fmt("[%u]", i),
MakeConstantBlockVariable(cblock[i], pointerTypes, structType, StringFormat::Fmt("[%u]", i),
decorations[structType.id], specInfo);
cblock[i].byteOffset = relativeOffset;
@@ -1901,12 +1922,13 @@ void Reflector::MakeConstantBlockVariables(const DataType &structType, uint32_t
cblock.resize(structType.children.size());
for(size_t i = 0; i < structType.children.size(); i++)
MakeConstantBlockVariable(cblock[i], dataTypes[structType.children[i].type],
MakeConstantBlockVariable(cblock[i], pointerTypes, dataTypes[structType.children[i].type],
structType.children[i].name, structType.children[i].decorations,
specInfo);
}
void Reflector::MakeConstantBlockVariable(ShaderConstant &outConst, const DataType &type,
void Reflector::MakeConstantBlockVariable(ShaderConstant &outConst,
SparseIdMap<uint16_t> &pointerTypes, const DataType &type,
const rdcstr &name, const Decorations &varDecorations,
const std::vector<SpecConstant> &specInfo) const
{
@@ -1925,9 +1947,17 @@ void Reflector::MakeConstantBlockVariable(ShaderConstant &outConst, const DataTy
curType->length != Id() ? EvaluateConstant(curType->length, specInfo).value.u.x : ~0U;
if(varDecorations.arrayStride != ~0U)
outConst.type.descriptor.arrayByteStride = varDecorations.arrayStride;
{
RDCASSERTMSG("Stride is too large for uint16_t", varDecorations.arrayStride <= 0xffff);
outConst.type.descriptor.arrayByteStride = RDCMIN(varDecorations.arrayStride, 0xffffu) & 0xffff;
}
else if(decorations[curType->id].arrayStride != ~0U)
outConst.type.descriptor.arrayByteStride = decorations[curType->id].arrayStride;
{
RDCASSERTMSG("Stride is too large for uint16_t",
decorations[curType->id].arrayStride <= 0xffff);
outConst.type.descriptor.arrayByteStride =
RDCMIN(decorations[curType->id].arrayStride, 0xffffu) & 0xffff;
}
if(varDecorations.matrixStride != ~0U)
outConst.type.descriptor.matrixByteStride = varDecorations.matrixStride & 0xff;
@@ -1968,6 +1998,23 @@ void Reflector::MakeConstantBlockVariable(ShaderConstant &outConst, const DataTy
}
else
{
if(curType->type == DataType::PointerType)
{
outConst.type.descriptor.type = VarType::ULong;
outConst.type.descriptor.rowMajorStorage = false;
outConst.type.descriptor.rows = 1;
outConst.type.descriptor.columns = 1;
outConst.type.descriptor.name = curType->name;
// try to insert the inner type ID into the map. If it succeeds, it gets the next available
// pointer type index (size of the map), if not then we just get the previously added index
auto it =
pointerTypes.insert(std::make_pair(curType->InnerType(), (uint16_t)pointerTypes.size()));
outConst.type.descriptor.pointerTypeID = it.first->second;
return;
}
RDCASSERT(curType->type == DataType::StructType || curType->type == DataType::ArrayType);
outConst.type.descriptor.type = VarType::Float;
@@ -1979,7 +2026,7 @@ void Reflector::MakeConstantBlockVariable(ShaderConstant &outConst, const DataTy
MakeConstantBlockVariables(*curType, outConst.type.descriptor.elements,
outConst.type.descriptor.arrayByteStride, outConst.type.members,
specInfo);
pointerTypes, specInfo);
if(curType->type == DataType::ArrayType)
{
@@ -113,9 +113,11 @@ private:
void MakeConstantBlockVariables(const DataType &structType, uint32_t arraySize,
uint32_t arrayByteStride, rdcarray<ShaderConstant> &cblock,
SparseIdMap<uint16_t> &pointerTypes,
const std::vector<SpecConstant> &specInfo) const;
void MakeConstantBlockVariable(ShaderConstant &outConst, const DataType &type, const rdcstr &name,
const Decorations &decorations,
void MakeConstantBlockVariable(ShaderConstant &outConst, SparseIdMap<uint16_t> &pointerTypes,
const DataType &type, const rdcstr &name,
const Decorations &varDecorations,
const std::vector<SpecConstant> &specInfo) const;
void AddSignatureParameter(const bool isInput, const ShaderStage stage, const Id id,
const Id structID, uint32_t &regIndex,
@@ -143,7 +145,7 @@ private:
static const uint32_t SpecializationConstantBindSet = 1234567;
static const uint32_t PushConstantBindSet = 1234568;
void FillSpecConstantVariables(const rdcarray<ShaderConstant> &invars,
void FillSpecConstantVariables(ResourceId shader, const rdcarray<ShaderConstant> &invars,
rdcarray<ShaderVariable> &outvars,
const std::vector<SpecConstant> &specInfo);
+1
View File
@@ -878,6 +878,7 @@ void VulkanCreationInfo::Buffer::Init(VulkanResourceManager *resourceMan, Vulkan
{
usage = pCreateInfo->usage;
size = pCreateInfo->size;
gpuAddress = 0;
}
void VulkanCreationInfo::BufferView::Init(VulkanResourceManager *resourceMan,
+1
View File
@@ -414,6 +414,7 @@ struct VulkanCreationInfo
VkBufferUsageFlags usage;
uint64_t size;
uint64_t gpuAddress;
};
std::map<ResourceId, Buffer> m_Buffer;
+4 -3
View File
@@ -392,6 +392,7 @@ BufferDescription VulkanReplay::GetBuffer(ResourceId id)
ret.resourceId = m_pDriver->GetResourceManager()->GetOriginalID(id);
ret.length = bufinfo.size;
ret.creationFlags = BufferCategory::NoFlags;
ret.gpuAddress = bufinfo.gpuAddress;
if(bufinfo.usage & (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT))
ret.creationFlags |= BufferCategory::ReadWrite;
@@ -1938,7 +1939,7 @@ void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader,
if(c.bufferBacked)
{
StandardFillCBufferVariables(c.variables, outvars, data);
StandardFillCBufferVariables(refl.resourceId, c.variables, outvars, data);
}
else
{
@@ -1952,7 +1953,7 @@ void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader,
auto specInfo =
pipeIt->second.shaders[it->second.GetReflection(entryPoint, pipeline).stageIndex].specialization;
FillSpecConstantVariables(c.variables, outvars, specInfo);
FillSpecConstantVariables(refl.resourceId, c.variables, outvars, specInfo);
}
}
else
@@ -1960,7 +1961,7 @@ void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader,
bytebuf pushdata;
pushdata.resize(sizeof(m_pDriver->m_RenderState.pushconsts));
memcpy(&pushdata[0], m_pDriver->m_RenderState.pushconsts, pushdata.size());
StandardFillCBufferVariables(c.variables, outvars, pushdata);
StandardFillCBufferVariables(refl.resourceId, c.variables, outvars, pushdata);
}
}
}
@@ -919,6 +919,21 @@ bool WrappedVulkan::Serialise_vkBindBufferMemory(SerialiserType &ser, VkDevice d
AddResourceCurChunk(memOrigId);
AddResourceCurChunk(resOrigId);
// for buffers created with device addresses, fetch it now as that's possible for both EXT and
// KHR variants now.
VulkanCreationInfo::Buffer &bufInfo = m_CreationInfo.m_Buffer[GetResID(buffer)];
if(bufInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR)
{
VkBufferDeviceAddressInfoKHR getInfo = {
VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR, NULL, Unwrap(buffer),
};
if(GetExtensions(GetRecord(device)).ext_KHR_buffer_device_address)
bufInfo.gpuAddress = ObjDisp(device)->GetBufferDeviceAddressKHR(Unwrap(device), &getInfo);
else if(GetExtensions(GetRecord(device)).ext_EXT_buffer_device_address)
bufInfo.gpuAddress = ObjDisp(device)->GetBufferDeviceAddressEXT(Unwrap(device), &getInfo);
}
}
return true;
@@ -2012,6 +2027,21 @@ bool WrappedVulkan::Serialise_vkBindBufferMemory2(SerialiserType &ser, VkDevice
AddResourceCurChunk(memOrigId);
AddResourceCurChunk(resOrigId);
// for buffers created with device addresses, fetch it now as that's possible for both EXT and
// KHR variants now.
VulkanCreationInfo::Buffer &bufInfo = m_CreationInfo.m_Buffer[GetResID(bindInfo.buffer)];
if(bufInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR)
{
VkBufferDeviceAddressInfoKHR getInfo = {
VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR, NULL, Unwrap(bindInfo.buffer),
};
if(GetExtensions(GetRecord(device)).ext_KHR_buffer_device_address)
bufInfo.gpuAddress = ObjDisp(device)->GetBufferDeviceAddressKHR(Unwrap(device), &getInfo);
else if(GetExtensions(GetRecord(device)).ext_EXT_buffer_device_address)
bufInfo.gpuAddress = ObjDisp(device)->GetBufferDeviceAddressEXT(Unwrap(device), &getInfo);
}
}
VkBindBufferMemoryInfo *unwrapped = UnwrapInfos(pBindInfos, bindInfoCount);
+14 -7
View File
@@ -183,8 +183,9 @@ void DoSerialise(SerialiserType &ser, ShaderVariableDescriptor &el)
SERIALISE_MEMBER(name);
SERIALISE_MEMBER(displayAsHex);
SERIALISE_MEMBER(displayAsRGB);
SERIALISE_MEMBER(pointerTypeID);
SIZE_CHECK(40);
SIZE_CHECK(48);
}
template <typename SerialiserType>
@@ -193,7 +194,7 @@ void DoSerialise(SerialiserType &ser, ShaderVariableType &el)
SERIALISE_MEMBER(descriptor);
SERIALISE_MEMBER(members);
SIZE_CHECK(64);
SIZE_CHECK(72);
}
template <typename SerialiserType>
@@ -204,7 +205,7 @@ void DoSerialise(SerialiserType &ser, ShaderConstant &el)
SERIALISE_MEMBER(defaultValue);
SERIALISE_MEMBER(type);
SIZE_CHECK(104);
SIZE_CHECK(112);
}
template <typename SerialiserType>
@@ -238,7 +239,7 @@ void DoSerialise(SerialiserType &ser, ShaderResource &el)
SERIALISE_MEMBER(isTexture);
SERIALISE_MEMBER(isReadOnly);
SIZE_CHECK(104);
SIZE_CHECK(112);
}
template <typename SerialiserType>
@@ -313,7 +314,9 @@ void DoSerialise(SerialiserType &ser, ShaderReflection &el)
SERIALISE_MEMBER(interfaces);
SIZE_CHECK(312);
SERIALISE_MEMBER(pointerTypes);
SIZE_CHECK(336);
}
template <typename SerialiserType>
@@ -324,6 +327,7 @@ void DoSerialise(SerialiserType &ser, ShaderVariable &el)
SERIALISE_MEMBER(name);
SERIALISE_MEMBER(type);
SERIALISE_MEMBER(isPointer);
SERIALISE_MEMBER(displayAsHex);
SERIALISE_MEMBER(isStruct);
SERIALISE_MEMBER(rowMajor);
@@ -332,7 +336,9 @@ void DoSerialise(SerialiserType &ser, ShaderVariable &el)
SERIALISE_MEMBER(members);
SIZE_CHECK(200);
SERIALISE_MEMBER(pointerShader);
SIZE_CHECK(192);
}
template <typename SerialiserType>
@@ -449,9 +455,10 @@ void DoSerialise(SerialiserType &ser, BufferDescription &el)
{
SERIALISE_MEMBER(resourceId);
SERIALISE_MEMBER(creationFlags);
SERIALISE_MEMBER(gpuAddress);
SERIALISE_MEMBER(length);
SIZE_CHECK(24);
SIZE_CHECK(32);
}
template <typename SerialiserType>
+16 -10
View File
@@ -338,7 +338,8 @@ void PatchTriangleFanRestartIndexBufer(std::vector<uint32_t> &patchedIndices, ui
newIndices.swap(patchedIndices);
}
void StandardFillCBufferVariable(uint32_t dataOffset, const bytebuf &data, ShaderVariable &outvar,
void StandardFillCBufferVariable(ResourceId shader, const ShaderVariableDescriptor &desc,
uint32_t dataOffset, const bytebuf &data, ShaderVariable &outvar,
uint32_t matStride)
{
const VarType type = outvar.type;
@@ -433,9 +434,12 @@ void StandardFillCBufferVariable(uint32_t dataOffset, const bytebuf &data, Shade
}
}
}
if(desc.pointerTypeID != ~0U)
outvar.SetTypedPointer(outvar.value.u64v[0], shader, desc.pointerTypeID);
}
static void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
static void StandardFillCBufferVariables(ResourceId shader, const rdcarray<ShaderConstant> &invars,
rdcarray<ShaderVariable> &outvars, const bytebuf &data,
uint32_t baseOffset)
{
@@ -443,8 +447,8 @@ static void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
{
std::string basename = invars[v].name;
uint32_t rows = invars[v].type.descriptor.rows;
uint32_t cols = invars[v].type.descriptor.columns;
uint8_t rows = invars[v].type.descriptor.rows;
uint8_t cols = invars[v].type.descriptor.columns;
uint32_t elems = RDCMAX(1U, invars[v].type.descriptor.elements);
const bool rowMajor = invars[v].type.descriptor.rowMajorStorage != 0;
const bool isArray = elems > 1;
@@ -474,7 +478,7 @@ static void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
vr.type = VarType::Float;
vr.rowMajor = rowMajor;
StandardFillCBufferVariables(invars[v].type.members, vr.members, data, dataOffset);
StandardFillCBufferVariables(shader, invars[v].type.members, vr.members, data, dataOffset);
dataOffset += invars[v].type.descriptor.arrayByteStride;
@@ -487,7 +491,7 @@ static void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
{
var.isStruct = true;
StandardFillCBufferVariables(invars[v].type.members, var.members, data, dataOffset);
StandardFillCBufferVariables(shader, invars[v].type.members, var.members, data, dataOffset);
}
outvars.push_back(var);
@@ -514,7 +518,8 @@ static void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
{
outvars[outIdx].rows = rows;
StandardFillCBufferVariable(dataOffset, data, outvars[outIdx], matStride);
StandardFillCBufferVariable(shader, invars[v].type.descriptor, dataOffset, data,
outvars[outIdx], matStride);
}
else
{
@@ -540,7 +545,8 @@ static void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
dataOffset += invars[v].type.descriptor.arrayByteStride;
StandardFillCBufferVariable(rowDataOffset, data, varmembers[e], matStride);
StandardFillCBufferVariable(shader, invars[v].type.descriptor, rowDataOffset, data,
varmembers[e], matStride);
}
{
@@ -552,11 +558,11 @@ static void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
}
}
void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
void StandardFillCBufferVariables(ResourceId shader, const rdcarray<ShaderConstant> &invars,
rdcarray<ShaderVariable> &outvars, const bytebuf &data)
{
// start with offset 0
StandardFillCBufferVariables(invars, outvars, data, 0);
StandardFillCBufferVariables(shader, invars, outvars, data, 0);
}
uint64_t CalcMeshOutputSize(uint64_t curSize, uint64_t requiredOutput)
+3 -2
View File
@@ -237,9 +237,10 @@ void PatchTriangleFanRestartIndexBufer(std::vector<uint32_t> &patchedIndices, ui
uint64_t CalcMeshOutputSize(uint64_t curSize, uint64_t requiredOutput);
void StandardFillCBufferVariable(uint32_t dataOffset, const bytebuf &data, ShaderVariable &outvar,
void StandardFillCBufferVariable(ResourceId shader, const ShaderVariableDescriptor &desc,
uint32_t dataOffset, const bytebuf &data, ShaderVariable &outvar,
uint32_t matStride);
void StandardFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
void StandardFillCBufferVariables(ResourceId shader, const rdcarray<ShaderConstant> &invars,
rdcarray<ShaderVariable> &outvars, const bytebuf &data);
// simple cache for when we need buffer data for highlighting