From f4d579ffaa68b61a065b405c16f0553b0cc63185 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 29 Oct 2024 13:34:44 +0000 Subject: [PATCH] Allow specifying tighter alignment than natural for odd buffer cases --- docs/how/how_buffer_format.rst | 1 + qrenderdoc/Code/BufferFormatter.cpp | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/how/how_buffer_format.rst b/docs/how/how_buffer_format.rst index e4cbec73a..d9bc59688 100644 --- a/docs/how/how_buffer_format.rst +++ b/docs/how/how_buffer_format.rst @@ -173,6 +173,7 @@ The buffer format supports annotations on declarations to specify special proper Struct definitions support the following annotations: * ``[[size(number)]]`` or ``[[byte_size(number)]]`` - Forces the struct to be padded up to a given size even if the contents don't require it. +* ``[[align(number)]]`` or ``[[alignment(number)]]`` - Overrides a struct's natural alignment (the largest alignment of any member). Can be used in edge cases where buffer definitions are tightly packed and misaligned, e.g. with D3D12 indirect arguments. * ``[[single]]`` or ``[[fixed]]`` - Forces the struct to be considered as a fixed SoA definition, even if in context the buffer viewer may default to AoS. See :ref:`the below section ` for more details. Structs with this annotation **may not** be declared as a variable, and should instead be the implicit final struct in a definition. Variable declarations support the following annotations: diff --git a/qrenderdoc/Code/BufferFormatter.cpp b/qrenderdoc/Code/BufferFormatter.cpp index 40a3b2f82..786814e17 100644 --- a/qrenderdoc/Code/BufferFormatter.cpp +++ b/qrenderdoc/Code/BufferFormatter.cpp @@ -880,7 +880,8 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin { cur->structDef.type.arrayByteStride = cur->offset; - cur->alignment = GetAlignment(pack, cur->structDef); + if(cur->alignment == 0) + cur->alignment = GetAlignment(pack, cur->structDef); // if we don't have tight arrays, struct byte strides are always 16-byte aligned if(!pack.tight_arrays) @@ -900,9 +901,11 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin else { reportError(tr("Struct %1 declared size %2 bytes is less than derived structure " - "size %3 bytes.") + "size:\n%3 bytes with alignment %4 meaning %5 bytes total size.") .arg(cur->structDef.type.name) .arg(cur->paddedStride) + .arg(cur->offset) + .arg(cur->alignment) .arg(cur->structDef.type.arrayByteStride)); success = false; break; @@ -956,6 +959,18 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin } cur->paddedStride = annot.param.toUInt(); } + else if(annot.name == lit("align") || annot.name == lit("alignment")) + { + if(annot.param.isEmpty()) + { + reportError(tr("Annotation '%1' requires a parameter with the size in bytes.\n\n" + "e.g. [[%1(128)]]") + .arg(annot.name)); + success = false; + break; + } + cur->alignment = annot.param.toUInt(); + } else if(annot.name == lit("single") || annot.name == lit("fixed")) { cur->singleDef = true; @@ -2129,7 +2144,10 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin end = qMax( end, fixed.type.members.back().byteOffset + GetVarSizeAndTrail(fixed.type.members.back())); - fixed.type.arrayByteStride = AlignUp(end, GetAlignment(pack, fixed)); + if(root.alignment != 0) + fixed.type.arrayByteStride = AlignUp(end, root.alignment); + else + fixed.type.arrayByteStride = AlignUp(end, GetAlignment(pack, fixed)); if(!fixed.type.members.isEmpty() && fixed.type.members.back().type.elements == ~0U) {