From e205054317d9631e7ebd8b403582510fa9785ec3 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 15 Oct 2019 16:25:08 +0100 Subject: [PATCH] Add UI support for GPU typed pointers in buffers --- qrenderdoc/Code/BufferFormatter.cpp | 94 +++-- qrenderdoc/Code/CaptureContext.cpp | 11 + qrenderdoc/Code/QRDUtils.cpp | 332 ++++++++++++++++-- qrenderdoc/Code/QRDUtils.h | 44 +++ qrenderdoc/Code/pyrenderdoc/renderdoc.i | 1 + qrenderdoc/Windows/BufferViewer.cpp | 8 + .../PipelineState/PipelineStateViewer.cpp | 107 +----- .../PipelineState/PipelineStateViewer.h | 3 - renderdoc/api/replay/data_types.h | 12 +- renderdoc/api/replay/shader_types.h | 107 +++++- renderdoc/core/core.cpp | 21 +- renderdoc/driver/d3d11/d3d11_replay.cpp | 3 +- renderdoc/driver/d3d12/d3d12_replay.cpp | 3 +- renderdoc/driver/gl/gl_replay.cpp | 25 +- renderdoc/driver/gl/gl_replay.h | 4 +- renderdoc/driver/gl/gl_shader_refl.cpp | 8 +- renderdoc/driver/shaders/dxbc/dxbc_debug.cpp | 2 +- .../driver/shaders/dxbc/dxbc_reflect.cpp | 4 +- .../driver/shaders/spirv/spirv_processor.cpp | 6 +- .../driver/shaders/spirv/spirv_reflect.cpp | 77 +++- .../driver/shaders/spirv/spirv_reflect.h | 8 +- renderdoc/driver/vulkan/vk_info.cpp | 1 + renderdoc/driver/vulkan/vk_info.h | 1 + renderdoc/driver/vulkan/vk_replay.cpp | 7 +- .../vulkan/wrappers/vk_resource_funcs.cpp | 30 ++ renderdoc/replay/renderdoc_serialise.inl | 21 +- renderdoc/replay/replay_driver.cpp | 26 +- renderdoc/replay/replay_driver.h | 5 +- 28 files changed, 722 insertions(+), 249 deletions(-) diff --git a/qrenderdoc/Code/BufferFormatter.cpp b/qrenderdoc/Code/BufferFormatter.cpp index 62417c4c3..9f01fce04 100644 --- a/qrenderdoc/Code/BufferFormatter.cpp +++ b/qrenderdoc/Code/BufferFormatter.cpp @@ -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 &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) diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index f014dfdfe..6d0100fee 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -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 &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)) diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp index 672d88a4d..eb69aed77 100644 --- a/qrenderdoc/Code/QRDUtils.cpp +++ b/qrenderdoc/Code/QRDUtils.cpp @@ -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, uint32_t> PointerTypeRegistry::typeMapping; +rdcarray 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 = ""; +} + +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 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 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(&ResIdTextToString); QMetaType::registerConverter(&ResIdToString); + QMetaType::registerConverter(&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() || + var.userType() == qMetaTypeId() || var.userType() == qMetaTypeId(); } @@ -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()) + // special case handling for ResourceId/GPUAddress on its own + if(var.userType() == qMetaTypeId() || var.userType() == qMetaTypeId()) { 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(); + if(var.userType() == qMetaTypeId()) + { + ICaptureContext *ctxptr = getCaptureContext(owner); - if(ctxptr) - name = ctxptr->GetResourceName(id); + ResourceId id = var.value(); + + valid = (id != ResourceId()); + + if(ctxptr) + name = ctxptr->GetResourceName(id); + else + name = ToQStr(id); + } else - name = ToQStr(id); + { + GPUAddressPtr ptr = var.value(); + + 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()) + // special case handling for ResourceId/GPUAddress on its own + if(var.userType() == qMetaTypeId() || var.userType() == qMetaTypeId()) { 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()) + { + ICaptureContext *ctxptr = getCaptureContext(owner); - if(ctxptr) - name = ctxptr->GetResourceName(var.value()); + ResourceId id = var.value(); + + if(ctxptr) + name = ctxptr->GetResourceName(id); + else + name = ToQStr(id); + } else - name = ToQStr(var.value()); + { + GPUAddressPtr ptr = var.value(); + + 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()) + // special case handling for ResourceId/GPUAddress on its own + if(var.userType() == qMetaTypeId() || var.userType() == qMetaTypeId()) { - ResourceId id = var.value(); + 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()) + { + id = var.value(); + + // empty resource ids are not clickable or hover-highlighted. + if(id == ResourceId()) + return false; + } + + if(var.userType() == qMetaTypeId()) + { + ptr = var.value(); + + 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()) + { + 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()) { - 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()) + { + 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; diff --git a/qrenderdoc/Code/QRDUtils.h b/qrenderdoc/Code/QRDUtils.h index 95c0b803f..2cb5ea58c 100644 --- a/qrenderdoc/Code/QRDUtils.h +++ b/qrenderdoc/Code/QRDUtils.h @@ -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, uint32_t> typeMapping; + static rdcarray 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 diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index df5dec2e5..4fafb1fa7 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -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) diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index b767e515b..058aa96c3 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -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)) diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp index bb3447d8d..561a572b0 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp @@ -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 &declaredStructs, const QString &name, - const rdcarray &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 &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; } diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h index 343374c86..2f4acd776 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h @@ -91,9 +91,6 @@ private: QMenu *editMenus[6] = {}; - QString declareStruct(QList &declaredStructs, const QString &name, - const rdcarray &members, uint32_t requiredByteStride); - QString GenerateHLSLStub(const ShaderBindpointMapping &bindpointMapping, const ShaderReflection *shaderDetails, const QString &entryFunc); IShaderViewer *EditShader(ResourceId id, ShaderStage shaderType, const rdcstr &entry, diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index 895086439..ca709ac0f 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -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); diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 26c3a91b8..1f3d9be4f 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -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 ` 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 ` 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 ` of this variable."); + VarType type; + + DOCUMENT("The :class:`contents ` of this variable if it has no members."); + ShaderValue value; + DOCUMENT("The members of this variable as a list of :class:`ShaderVariable`."); rdcarray 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 + 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 interfaces; + + DOCUMENT("A list of :class:`ShaderVariableType` with the shader's pointer types."); + rdcarray pointerTypes; }; DECLARE_REFLECTION_STRUCT(ShaderReflection); diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index d5e7edeb0..cf0f0f353 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -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); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index c6274a0df..66caf69b2 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -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, diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 82aaf9ac3..9a9f7428c 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -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 D3D12Replay::GetDebugMessages() diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index a7adab9f7..542ef69e8 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -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 &variables, rdcarray &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); } } } diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index ee0d671b2..9b58b07f5 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -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 &variables, + void OpenGLFillCBufferVariables(ResourceId shader, GLuint prog, bool bufferBacked, + std::string prefix, const rdcarray &variables, rdcarray &outvars, const bytebuf &data); bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, bool stencil, diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 1a3f60832..e729194f4 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -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; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp index 1eb5407e3..0b687b60b 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp @@ -4185,7 +4185,7 @@ void CreateShaderDebugStateAndTrace(ShaderDebug::State &initialState, ShaderDebu rdcarray 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); diff --git a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp index c5063a73b..9fc960539 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp @@ -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 { diff --git a/renderdoc/driver/shaders/spirv/spirv_processor.cpp b/renderdoc/driver/shaders/spirv/spirv_processor.cpp index 66f87eb0f..aab418142 100644 --- a/renderdoc/driver/shaders/spirv/spirv_processor.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_processor.cpp @@ -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; diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index bd816a1c7..13a962335 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -29,11 +29,11 @@ #include "replay/replay_driver.h" #include "spirv_editor.h" -void FillSpecConstantVariables(const rdcarray &invars, +void FillSpecConstantVariables(ResourceId shader, const rdcarray &invars, rdcarray &outvars, const std::vector &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 cblocks; rdcarray samplers, roresources, rwresources; + // for pointer types, mapping of inner type ID to index in list (assigned sequentially) + SparseIdMap 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 &specInfo) const @@ -1568,7 +1588,7 @@ ShaderVariable Reflector::EvaluateConstant(Id constID, const std::vector &cblock, + SparseIdMap &pointerTypes, const std::vector &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 &pointerTypes, const DataType &type, const rdcstr &name, const Decorations &varDecorations, const std::vector &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) { diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.h b/renderdoc/driver/shaders/spirv/spirv_reflect.h index b7735cb6f..7e38172e1 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.h +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.h @@ -113,9 +113,11 @@ private: void MakeConstantBlockVariables(const DataType &structType, uint32_t arraySize, uint32_t arrayByteStride, rdcarray &cblock, + SparseIdMap &pointerTypes, const std::vector &specInfo) const; - void MakeConstantBlockVariable(ShaderConstant &outConst, const DataType &type, const rdcstr &name, - const Decorations &decorations, + void MakeConstantBlockVariable(ShaderConstant &outConst, SparseIdMap &pointerTypes, + const DataType &type, const rdcstr &name, + const Decorations &varDecorations, const std::vector &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 &invars, +void FillSpecConstantVariables(ResourceId shader, const rdcarray &invars, rdcarray &outvars, const std::vector &specInfo); diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 65ff352d9..6a1924aaa 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -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, diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 3de426d32..7c0c06b9b 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -414,6 +414,7 @@ struct VulkanCreationInfo VkBufferUsageFlags usage; uint64_t size; + uint64_t gpuAddress; }; std::map m_Buffer; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 583129e8b..6811fcb5d 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -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); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index e82106d10..21ffedcff 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -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); diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 482422ad5..e87015acc 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -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 @@ -193,7 +194,7 @@ void DoSerialise(SerialiserType &ser, ShaderVariableType &el) SERIALISE_MEMBER(descriptor); SERIALISE_MEMBER(members); - SIZE_CHECK(64); + SIZE_CHECK(72); } template @@ -204,7 +205,7 @@ void DoSerialise(SerialiserType &ser, ShaderConstant &el) SERIALISE_MEMBER(defaultValue); SERIALISE_MEMBER(type); - SIZE_CHECK(104); + SIZE_CHECK(112); } template @@ -238,7 +239,7 @@ void DoSerialise(SerialiserType &ser, ShaderResource &el) SERIALISE_MEMBER(isTexture); SERIALISE_MEMBER(isReadOnly); - SIZE_CHECK(104); + SIZE_CHECK(112); } template @@ -313,7 +314,9 @@ void DoSerialise(SerialiserType &ser, ShaderReflection &el) SERIALISE_MEMBER(interfaces); - SIZE_CHECK(312); + SERIALISE_MEMBER(pointerTypes); + + SIZE_CHECK(336); } template @@ -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 @@ -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 diff --git a/renderdoc/replay/replay_driver.cpp b/renderdoc/replay/replay_driver.cpp index 369fec019..0e83d42b9 100644 --- a/renderdoc/replay/replay_driver.cpp +++ b/renderdoc/replay/replay_driver.cpp @@ -338,7 +338,8 @@ void PatchTriangleFanRestartIndexBufer(std::vector &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 &invars, +static void StandardFillCBufferVariables(ResourceId shader, const rdcarray &invars, rdcarray &outvars, const bytebuf &data, uint32_t baseOffset) { @@ -443,8 +447,8 @@ static void StandardFillCBufferVariables(const rdcarray &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 &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 &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 &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 &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 &invars, } } -void StandardFillCBufferVariables(const rdcarray &invars, +void StandardFillCBufferVariables(ResourceId shader, const rdcarray &invars, rdcarray &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) diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index 301a2f959..985e5f334 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -237,9 +237,10 @@ void PatchTriangleFanRestartIndexBufer(std::vector &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 &invars, +void StandardFillCBufferVariables(ResourceId shader, const rdcarray &invars, rdcarray &outvars, const bytebuf &data); // simple cache for when we need buffer data for highlighting