mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-30 01:25:55 +00:00
Add UI support for GPU typed pointers in buffers
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ®Index,
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -414,6 +414,7 @@ struct VulkanCreationInfo
|
||||
|
||||
VkBufferUsageFlags usage;
|
||||
uint64_t size;
|
||||
uint64_t gpuAddress;
|
||||
};
|
||||
std::map<ResourceId, Buffer> m_Buffer;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user