diff --git a/docs/how/how_buffer_format.rst b/docs/how/how_buffer_format.rst index f09da6c00..4898155bd 100644 --- a/docs/how/how_buffer_format.rst +++ b/docs/how/how_buffer_format.rst @@ -1,3 +1,5 @@ +.. _how_buffer_format: + How do I specify a buffer format? ================================= diff --git a/docs/python_api/qrenderdoc/main.rst b/docs/python_api/qrenderdoc/main.rst index 61749c7e2..1df4cf1e3 100644 --- a/docs/python_api/qrenderdoc/main.rst +++ b/docs/python_api/qrenderdoc/main.rst @@ -33,6 +33,21 @@ CaptureViewer Interface .. autoclass:: qrenderdoc.CaptureViewer :members: +Helpers +------- + +.. autoclass:: qrenderdoc.BufferInterpreter + :members: + +.. autoclass:: qrenderdoc.PackingRules + :members: + +.. autoclass:: qrenderdoc.ParsedBufferFormat + :members: + +.. autoclass:: qrenderdoc.ParseError + :members: + Utilities --------- diff --git a/docs/spelling_general.txt b/docs/spelling_general.txt index 9be5b2bf7..0c5612667 100644 --- a/docs/spelling_general.txt +++ b/docs/spelling_general.txt @@ -133,6 +133,7 @@ uncheck unchecking unitless unix +unparse unprocessable unregister Unregister diff --git a/qrenderdoc/Code/BufferFormatter.cpp b/qrenderdoc/Code/BufferFormatter.cpp index f8c2f9157..42766f89d 100644 --- a/qrenderdoc/Code/BufferFormatter.cpp +++ b/qrenderdoc/Code/BufferFormatter.cpp @@ -271,7 +271,7 @@ QList GatherPointerRecursiveMembers( return ret; } -void BufferFormatter::EstimatePackingRules(Packing::Rules &pack, ResourceId shader, +void BufferFormatter::EstimatePackingRules(PackingRules &pack, ResourceId shader, const ShaderConstant &constant, QSet &pointerTypesProcessed, uint32_t knownVecAlignment) @@ -282,7 +282,7 @@ void BufferFormatter::EstimatePackingRules(Packing::Rules &pack, ResourceId shad // scalar packing was used but it was only three float4 vectors then it will look like the most // conservative std140/scalar. - if(!pack.vector_align_component || !pack.vector_straddle_16b) + if(!pack.vectorAlignComponent || !pack.vectorStraddle16b) { // column major matrices have vectors that are 'rows' long. Everything else is vectors of // 'columns' long @@ -304,29 +304,29 @@ void BufferFormatter::EstimatePackingRules(Packing::Rules &pack, ResourceId shad // if it's a vec3 or vec4 and its offset is not purely aligned, it's only component aligned if(vecSize >= 3 && offsModVec != 0) - pack.vector_align_component = true; + pack.vectorAlignComponent = true; // if it's a vec2 and its offset is not either 0 or half the total size, it's also only // component aligned. vec2s without this allowance must be aligned to the vec2 size if(vecSize == 2 && offsModVec != 0 && offsModVec != vec4Size / 2) - pack.vector_align_component = true; + pack.vectorAlignComponent = true; if(constant.type.elements > 1) { // with arrays we can check the stride as well. If the stride isn't vector-aligned then // that's the same as vectors being aligned to components (even if we don't see it) if(vecSize >= 3 && constant.type.arrayByteStride < vec4Size) - pack.vector_align_component = true; + pack.vectorAlignComponent = true; if(vecSize == 2 && constant.type.arrayByteStride < vec4Size / 2) - pack.vector_align_component = true; + pack.vectorAlignComponent = true; } if(matSize > 1) { if(vecSize >= 3 && constant.type.matrixByteStride < vec4Size) - pack.vector_align_component = true; + pack.vectorAlignComponent = true; if(vecSize == 2 && constant.type.matrixByteStride < vec4Size / 2) - pack.vector_align_component = true; + pack.vectorAlignComponent = true; } // while we're here, check if the vector straddles a 16-byte boundary @@ -337,35 +337,35 @@ void BufferFormatter::EstimatePackingRules(Packing::Rules &pack, ResourceId shad // if the vector crosses a 16-byte boundary, vectors can straddle them if(low16b != high16b) - pack.vector_straddle_16b = true; + pack.vectorStraddle16b = true; // if we have determined earlier that a struct array may misalign the vector's base alignment, we are straddling if(vecSize >= 3 && knownVecAlignment < 16) - pack.vector_straddle_16b = true; + pack.vectorStraddle16b = true; else if(vecSize == 2 && knownVecAlignment < 8) - pack.vector_straddle_16b = true; + pack.vectorStraddle16b = true; } - if(!pack.tight_arrays && matSize > 1) + if(!pack.tightArrays && matSize > 1) { // if the array has a byte stride less than 16, it must be non-tight packed if(constant.type.matrixByteStride < 16) - pack.tight_arrays = true; + pack.tightArrays = true; } } - if(!pack.tight_arrays && constant.type.elements > 1) + if(!pack.tightArrays && constant.type.elements > 1) { // if the array has a byte stride less than 16, it must be non-tight packed if(constant.type.arrayByteStride < 16) - pack.tight_arrays = true; + pack.tightArrays = true; } - if(!pack.tight_arrays && constant.type.baseType == VarType::Struct) + if(!pack.tightArrays && constant.type.baseType == VarType::Struct) { // if a struct isn't padded to 16-byte alignment, assume non-tight arrays if((constant.type.arrayByteStride % 16) != 0) - pack.tight_arrays = true; + pack.tightArrays = true; } // handle the case where a structs array stride may need to pessimise its members' alignments. @@ -389,7 +389,7 @@ void BufferFormatter::EstimatePackingRules(Packing::Rules &pack, ResourceId shad EstimatePackingRules(pack, shader, constant.type.members, pointerTypesProcessed, knownVecAlignment); } -void BufferFormatter::EstimatePackingRules(Packing::Rules &pack, ResourceId shader, +void BufferFormatter::EstimatePackingRules(PackingRules &pack, ResourceId shader, const rdcarray &members, QSet &pointerTypesProcessed, uint32_t knownVecAlignment) @@ -413,11 +413,11 @@ void BufferFormatter::EstimatePackingRules(Packing::Rules &pack, ResourceId shad // check for trailing array/struct use if(i > 0) { - Packing::Rules unpadded = pack; - Packing::Rules padded = pack; - unpadded.trailing_overlap = true; - unpadded.vector_align_component = true; - padded.trailing_overlap = false; + PackingRules unpadded = pack; + PackingRules padded = pack; + unpadded.trailingOverlap = true; + unpadded.vectorAlignComponent = true; + padded.trailingOverlap = false; const uint32_t unpaddedAdvance = GetVarAdvance(unpadded, members[i - 1]); const uint32_t paddedAdvance = GetVarAdvance(padded, members[i - 1]); @@ -427,18 +427,18 @@ void BufferFormatter::EstimatePackingRules(Packing::Rules &pack, ResourceId shad if(paddedAdvance > unpaddedAdvance && members[i].byteOffset < (members[i - 1].byteOffset + paddedAdvance)) { - pack.trailing_overlap = true; + pack.trailingOverlap = true; } } // if we've degenerated to scalar we can't get any more lenient, stop checking rules - if(pack == Packing::Scalar) + if(pack == PackingRules::Scalar()) break; } } -Packing::Rules BufferFormatter::EstimatePackingRules(ResourceId shader, - const rdcarray &members) +PackingRules BufferFormatter::EstimatePackingRules(ResourceId shader, + const rdcarray &members) { ShaderConstantType base; base.members = members; @@ -446,10 +446,10 @@ Packing::Rules BufferFormatter::EstimatePackingRules(ResourceId shader, return EstimatePackingRules(shader, base); } -Packing::Rules BufferFormatter::EstimatePackingRules(ResourceId shader, - const ShaderConstantType &baseType) +PackingRules BufferFormatter::EstimatePackingRules(ResourceId shader, + const ShaderConstantType &baseType) { - Packing::Rules pack; + PackingRules pack; // start from the most conservative ruleset. We will iteratively turn off any rules which are // violated to end up with the most conservative ruleset which is still valid for the described @@ -458,9 +458,9 @@ Packing::Rules BufferFormatter::EstimatePackingRules(ResourceId shader, // D3D shouldn't really need to be estimating, because it's implicit from how this is bound // (cbuffer or structured resource) if(IsD3D(m_API)) - pack = Packing::D3DCB; + pack = PackingRules::D3DCB(); else - pack = Packing::std140; + pack = PackingRules::STD140(); // without more information we must assume all vectors are naturally aligned QSet pointerTypesProcessed; @@ -477,35 +477,37 @@ Packing::Rules BufferFormatter::EstimatePackingRules(ResourceId shader, { // scalar is technically more lenient than anything D3D allows, as D3DUAV requires padding after // structs (it's closer to C packing) - if(pack == Packing::D3DCB || pack == Packing::D3DUAV || pack == Packing::Scalar) + if(pack == PackingRules::D3DCB() || pack == PackingRules::D3DUAV() || + pack == PackingRules::Scalar()) return pack; // shouldn't end up with these as we started at D3DCB, but just for safety - if(pack == Packing::std140) - return Packing::D3DCB; + if(pack == PackingRules::STD140()) + return PackingRules::D3DCB(); - if(pack == Packing::std430) - return Packing::D3DUAV; + if(pack == PackingRules::STD430()) + return PackingRules::D3DUAV(); } else { - if(pack == Packing::std140 || pack == Packing::std430 || pack == Packing::Scalar) + if(pack == PackingRules::STD140() || pack == PackingRules::STD430() || + pack == PackingRules::Scalar()) return pack; if(m_API == GraphicsAPI::Vulkan) { - if(pack == Packing::D3DCB || pack == Packing::D3DUAV) + if(pack == PackingRules::D3DCB() || pack == PackingRules::D3DUAV()) return pack; // on vulkan HLSL shaders may use relaxed block layout, which is not wholly represented here. // it doesn't actually allow trailing overlap but this lets us check if we're 'almost' cbuffer // rules, at which point any instances where trailing overlap would be used will look just // like manual padding/offsetting - Packing::Rules mod = pack; - mod.trailing_overlap = true; + PackingRules mod = pack; + mod.trailingOverlap = true; - if(mod == Packing::D3DCB) - return Packing::D3DCB; + if(mod == PackingRules::D3DCB()) + return PackingRules::D3DCB(); } } @@ -515,8 +517,8 @@ Packing::Rules BufferFormatter::EstimatePackingRules(ResourceId shader, // // note, D3DUAV is treated the same as C but we checked for it above so we'd only get here on // non-D3D - if(pack == Packing::C) - return Packing::Scalar; + if(pack == PackingRules::C()) + return PackingRules::Scalar(); // our ruleset doesn't match exactly to a premade one. Check the rules to see which properties we // have. @@ -527,60 +529,60 @@ Packing::Rules BufferFormatter::EstimatePackingRules(ResourceId shader, // straddling 16 bytes but e.g. not have tight arrays or component-aligned vectors. Possibly no // arrays were seen so tight arrays couldn't be explicitly determined. So regardless of what else // we found return scalar - if(pack.vector_straddle_16b) - return Packing::Scalar; + if(pack.vectorStraddle16b) + return PackingRules::Scalar(); // trailing overlap is allowed in any D3D layout, but for non-D3D only in scalar layout. // Since we know from above that either we're not using D3D or we aren't an exact match for D3DCB, // assume we're in scalar one way or another. // This could be e.g. D3DUAV with tight arrays but vector straddling wasn't seen explicitly - if(pack.trailing_overlap) - return Packing::Scalar; + if(pack.trailingOverlap) + return PackingRules::Scalar(); // the exact same logic as above applies to component-aligned vectors. Allowed in any D3D layout, // but for non-D3D only in scalar layout. - if(pack.vector_align_component) - return Packing::Scalar; + if(pack.vectorAlignComponent) + return PackingRules::Scalar(); // For non-D3D: if we have tight arrays, this is possible in std430 - however since we didn't // match std430 above there must be some other allowance. That means we must devolve to scalar // For D3D this is possible only in D3DUAV (which is equivalent to scalar) - if(pack.tight_arrays) - return Packing::Scalar; + if(pack.tightArrays) + return PackingRules::Scalar(); // shouldn't get here, but just for safety return the ruleset we derived return pack; } -QString BufferFormatter::DeclarePacking(Packing::Rules pack) +QString BufferFormatter::DeclarePacking(PackingRules pack) { - if(pack == Packing::D3DCB) + if(pack == PackingRules::D3DCB()) return lit("#pack(cbuffer)"); - else if(pack == Packing::std140) + else if(pack == PackingRules::STD140()) return lit("#pack(std140)"); - else if(pack == Packing::std430) + else if(pack == PackingRules::STD430()) return lit("#pack(std430)"); - else if(pack == Packing::D3DUAV) // this is also C but we call it 'structured' for D3D + else if(pack == PackingRules::D3DUAV()) // this is also C but we call it 'structured' for D3D return lit("#pack(structured)"); - else if(pack == Packing::Scalar) + else if(pack == PackingRules::Scalar()) return lit("#pack(scalar)"); // packing doesn't match a premade ruleset. Emit individual specifiers QString ret; - if(pack.vector_align_component) + if(pack.vectorAlignComponent) ret += lit("#pack(vector_align_component) // vectors are aligned to their component\n"); else ret += lit("#pack(no_vector_align_component) // vectors are aligned evenly (float3 as float4)\n"); - if(pack.tight_arrays) + if(pack.tightArrays) ret += lit("#pack(tight_arrays) // arrays are packed tightly\n"); else ret += lit("#pack(no_tight_arrays) // arrays are padded to 16-byte boundaries\n"); - if(pack.vector_straddle_16b) + if(pack.vectorStraddle16b) ret += lit("#pack(vector_straddle_16b) // vectors can straddle 16-byte boundaries\n"); else ret += lit("#pack(no_vector_straddle_16b) // vectors cannot straddle 16-byte boundaries\n"); - if(pack.trailing_overlap) + if(pack.trailingOverlap) ret += lit("#pack(trailing_overlap) // variables can overlap trailing padding after " "arrays/structs\n"); @@ -770,24 +772,24 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin // default to scalar (tight packing) if nothing else is specified at all. The expectation is // anything that needs a better default will insert that into the format string for the user, // or be picked up below - Packing::Rules &pack = ret.packing; - pack = Packing::Scalar; + PackingRules &pack = ret.packing; + pack = PackingRules::Scalar(); // for D3D and GL we default to the only valid packing for cbuffers and UAVs. The user can still // override this if they really wish with a #pack, but this makes sense as a sensible default if(cbuffer) { if(IsD3D(m_API)) - pack = Packing::D3DCB; + pack = PackingRules::D3DCB(); else if(m_API == GraphicsAPI::OpenGL) - pack = Packing::std140; + pack = PackingRules::STD140(); } else { if(IsD3D(m_API)) - pack = Packing::D3DUAV; + pack = PackingRules::D3DUAV(); else if(m_API == GraphicsAPI::OpenGL) - pack = Packing::std430; + pack = PackingRules::STD430(); } // vulkan allows scalar packing in any buffer, so don't wrest control away from the user @@ -940,41 +942,41 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin // try to pick up common aliases that people might use if(packrule == lit("d3dcbuffer") || packrule == lit("cbuffer") || packrule == lit("cb")) - pack = Packing::D3DCB; + pack = PackingRules::D3DCB(); else if(packrule == lit("d3duav") || packrule == lit("uav") || packrule == lit("structured")) - pack = Packing::D3DUAV; + pack = PackingRules::D3DUAV(); else if(packrule == lit("std140") || packrule == lit("ubo") || packrule == lit("gl") || packrule == lit("gles") || packrule == lit("opengl") || packrule == lit("glsl")) - pack = Packing::std140; + pack = PackingRules::STD140(); else if(packrule == lit("std430") || packrule == lit("ssbo")) - pack = Packing::std430; + pack = PackingRules::STD430(); else if(packrule == lit("scalar")) - pack = Packing::Scalar; + pack = PackingRules::Scalar(); else if(packrule == lit("c")) - pack = Packing::C; + pack = PackingRules::C(); // we also allow toggling the individual rules else if(packrule == lit("vector_align_component")) - pack.vector_align_component = true; + pack.vectorAlignComponent = true; else if(packrule == lit("no_vector_align_component")) - pack.vector_align_component = false; + pack.vectorAlignComponent = false; else if(packrule == lit("tight_arrays")) - pack.tight_arrays = true; + pack.tightArrays = true; else if(packrule == lit("no_tight_arrays")) - pack.tight_arrays = false; + pack.tightArrays = false; else if(packrule == lit("vector_straddle_16b")) - pack.vector_straddle_16b = true; + pack.vectorStraddle16b = true; else if(packrule == lit("no_vector_straddle_16b")) - pack.vector_straddle_16b = false; + pack.vectorStraddle16b = false; else if(packrule == lit("trailing_overlap")) - pack.trailing_overlap = true; + pack.trailingOverlap = true; else if(packrule == lit("no_trailing_overlap")) - pack.trailing_overlap = false; + pack.trailingOverlap = false; else if(packrule == lit("tight_bitfield_packing")) - pack.tight_bitfield_packing = true; + pack.tightBitfieldPacking = true; else if(packrule == lit("no_tight_bitfield_packing")) - pack.tight_bitfield_packing = false; + pack.tightBitfieldPacking = false; else packrule = QString(); @@ -1038,7 +1040,7 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin 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) + if(!pack.tightArrays) { cur->alignment = 16; } @@ -1697,7 +1699,7 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin cur->offset += el.type.elements * el.type.arrayByteStride; // if we allow trailing overlap, remove the padding - if(pack.trailing_overlap) + if(pack.trailingOverlap) cur->offset -= el.type.arrayByteStride - structContext.offset; continue; @@ -2188,16 +2190,16 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin const uint8_t vecSize = (el.type.rows > 1 && el.type.ColMajor()) ? el.type.rows : el.type.columns; - const uint32_t elSize = - packed32bit ? sizeof(uint32_t) - : (pack.vector_align_component ? elAlignment * vecSize : elAlignment); + const uint32_t elSize = packed32bit + ? sizeof(uint32_t) + : (pack.vectorAlignComponent ? elAlignment * vecSize : elAlignment); // if we aren't using tight arrays the stride is at least 16 bytes el.type.arrayByteStride = elAlignment; if(el.type.rows > 1 || el.type.columns > 1) el.type.arrayByteStride = elSize; - if(!pack.tight_arrays) + if(!pack.tightArrays) el.type.arrayByteStride = std::max(16U, el.type.arrayByteStride); // matrices are always aligned like arrays of vectors @@ -2231,7 +2233,7 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin el.type.baseType = VarType::GPUPointer; el.type.flags = ShaderVariableFlags::HexDisplay; el.type.arrayByteStride = elAlignment = 8; - if(!pack.tight_arrays) + if(!pack.tightArrays) el.type.arrayByteStride = std::max(16U, el.type.arrayByteStride); el.type.matrixByteStride = el.type.arrayByteStride; } @@ -2285,7 +2287,7 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin // unsigned int c : 4; if(start + el.bitFieldSize > elemScalarBitSize) { - if(pack.tight_bitfield_packing) + if(pack.tightBitfieldPacking) { while(bitfieldCurPos >= 8) { @@ -2335,11 +2337,11 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin cur->offset = AlignUp(cur->offset, elAlignment); // if we have non-tight arrays, arrays (and matrices) always start on a 16-byte boundary - if(!pack.tight_arrays && (el.type.elements > 1 || el.type.rows > 1)) + if(!pack.tightArrays && (el.type.elements > 1 || el.type.rows > 1)) cur->offset = AlignUp(cur->offset, 16U); // if vectors can't straddle 16-byte alignment, check to see if we're going to do that - if(!pack.vector_straddle_16b) + if(!pack.vectorStraddle16b) { if(cur->offset / 16 != (cur->offset + elSize - 1) / 16) { @@ -2518,7 +2520,7 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin fixed = root.structDef; uint32_t end = root.offset; if(!fixed.type.members.isEmpty() && - (!pack.tight_bitfield_packing || fixed.type.members.back().bitFieldSize == 0)) + (!pack.tightBitfieldPacking || fixed.type.members.back().bitFieldSize == 0)) end = qMax( end, fixed.type.members.back().byteOffset + GetVarSizeAndTrail(fixed.type.members.back())); @@ -2651,6 +2653,7 @@ ParsedFormat BufferFormatter::ParseFormatString(const QString &formatString, uin ShaderConstant el; el.byteOffset = 0; + el.type.name = fixed.type.name; el.type.baseType = VarType::Struct; el.type.elements = ~0U; el.type.arrayByteStride = fixed.type.arrayByteStride; @@ -2851,7 +2854,7 @@ QString BufferFormatter::GetTextureFormatString(const TextureDescription &tex) .arg(w); } -QString BufferFormatter::GetBufferFormatString(Packing::Rules pack, ResourceId shader, +QString BufferFormatter::GetBufferFormatString(PackingRules pack, ResourceId shader, const ShaderResource &res, const ResourceFormat &viewFormat) { @@ -3016,18 +3019,18 @@ uint32_t BufferFormatter::GetVarSizeAndTrail(const ShaderConstant &var) return VarTypeByteSize(var.type.baseType) * var.type.columns; } -uint32_t BufferFormatter::GetVarAdvance(const Packing::Rules &pack, const ShaderConstant &var) +uint32_t BufferFormatter::GetVarAdvance(PackingRules pack, const ShaderConstant &var) { uint32_t ret = GetVarSizeAndTrail(var); // if we allow trailing overlap, remove the padding at the end of the struct/array - if(pack.trailing_overlap) + if(pack.trailingOverlap) { if(var.type.baseType == VarType::Struct) { ret -= (var.type.arrayByteStride - GetUnpaddedStructAdvance(pack, var.type.members)); } - else if((var.type.elements > 1 || var.type.rows > 1) && !pack.tight_arrays) + else if((var.type.elements > 1 || var.type.rows > 1) && !pack.tightArrays) { uint8_t vecSize = var.type.columns; @@ -3035,7 +3038,7 @@ uint32_t BufferFormatter::GetVarAdvance(const Packing::Rules &pack, const Shader vecSize = var.type.rows; uint32_t elSize = GetAlignment(pack, var); - if(pack.vector_align_component) + if(pack.vectorAlignComponent) elSize *= vecSize; // the padding is the stride (which is rounded up to 16 for non-tight arrays) minus the size @@ -3047,7 +3050,7 @@ uint32_t BufferFormatter::GetVarAdvance(const Packing::Rules &pack, const Shader return ret; } -uint32_t BufferFormatter::GetAlignment(Packing::Rules pack, const ShaderConstant &c) +uint32_t BufferFormatter::GetAlignment(PackingRules pack, const ShaderConstant &c) { uint32_t ret = 1; @@ -3066,7 +3069,7 @@ uint32_t BufferFormatter::GetAlignment(Packing::Rules pack, const ShaderConstant // if vectors aren't component aligned we need to calculate the alignment based on the size of // the vectors - if(!pack.vector_align_component) + if(!pack.vectorAlignComponent) { // column major matrices have vectors that are 'rows' long. Everything else is vectors of // 'columns' long @@ -3090,7 +3093,7 @@ uint32_t BufferFormatter::GetAlignment(Packing::Rules pack, const ShaderConstant return ret; } -uint32_t BufferFormatter::GetUnpaddedStructAdvance(Packing::Rules pack, +uint32_t BufferFormatter::GetUnpaddedStructAdvance(PackingRules pack, const rdcarray &members) { uint32_t lastMemberStart = 0; @@ -3112,7 +3115,7 @@ uint32_t BufferFormatter::GetUnpaddedStructAdvance(Packing::Rules pack, return lastMemberStart + GetVarAdvance(pack, *lastChild); } -QString BufferFormatter::DeclareStruct(Packing::Rules pack, ResourceId shader, +QString BufferFormatter::DeclareStruct(PackingRules pack, ResourceId shader, QMap &declaredStructs, QMap &anonStructs, const QString &name, const rdcarray &members, @@ -3164,15 +3167,15 @@ QString BufferFormatter::DeclareStruct(Packing::Rules pack, ResourceId shader, offset = AlignUp(offset, alignment); // if things can't straddle 16-byte boundaries, check that and enforce - if(!pack.vector_straddle_16b) + if(!pack.vectorStraddle16b) { if(offset / 16 != (offset + vecsize - 1) / 16) offset = AlignUp(offset, 16U); } // if we don't have tight arrays, arrays and structs begin at 16-byte boundaries - if(!pack.tight_arrays && (members[i].type.baseType == VarType::Struct || - members[i].type.elements > 1 || members[i].type.rows > 1)) + if(!pack.tightArrays && (members[i].type.baseType == VarType::Struct || + members[i].type.elements > 1 || members[i].type.rows > 1)) { offset = AlignUp(offset, 16U); } @@ -3339,7 +3342,7 @@ QString BufferFormatter::DeclareStruct(Packing::Rules pack, ResourceId shader, uint32_t stride = GetAlignment(pack, members[i]); - if(pack.vector_align_component) + if(pack.vectorAlignComponent) { if(members[i].type.RowMajor()) stride *= members[i].type.columns; @@ -3347,7 +3350,7 @@ QString BufferFormatter::DeclareStruct(Packing::Rules pack, ResourceId shader, stride *= members[i].type.rows; } - if(!pack.tight_arrays) + if(!pack.tightArrays) stride = 16; if(stride != members[i].type.matrixByteStride) @@ -3366,7 +3369,7 @@ QString BufferFormatter::DeclareStruct(Packing::Rules pack, ResourceId shader, } // if we don't have tight arrays, struct byte strides are always 16-byte aligned - if(!pack.tight_arrays) + if(!pack.tightArrays) { structAlignment = 16; } @@ -3422,7 +3425,7 @@ QString BufferFormatter::DeclareEnum(const QString &name, const rdcarray &members, uint32_t requiredByteStride) { @@ -4626,13 +4629,13 @@ outer_struct2 a[4]; ResourceFormat fmt; ParsedFormat parsed; - Packing::Rules pack; + PackingRules pack; SECTION("No changes") { // we generated the members with std140 packing so it should stay std140 pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::std140)); + CHECK((pack == PackingRules::STD140())); } SECTION("std140 compatible offsets") @@ -4648,7 +4651,7 @@ outer_struct2 a[4]; } pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::std140)); + CHECK((pack == PackingRules::STD140())); } // no other changes we can make that are std140 compatible, alignments and strides are already at @@ -4662,25 +4665,25 @@ outer_struct2 a[4]; { members[4].type.arrayByteStride = 4; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::std430)); + CHECK((pack == PackingRules::STD430())); } SECTION("float2[4] tight array") { members[5].type.arrayByteStride = 8; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::std430)); + CHECK((pack == PackingRules::STD430())); } SECTION("[[col_major]] float2x4 tight array") { members[8].type.matrixByteStride = 8; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::std430)); + CHECK((pack == PackingRules::STD430())); } SECTION("[[row_major]] float4x2 tight array") { members[11].type.matrixByteStride = 8; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::std430)); + CHECK((pack == PackingRules::STD430())); } } @@ -4692,13 +4695,13 @@ outer_struct2 a[4]; { members[1].byteOffset += 4; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::D3DCB)); + CHECK((pack == PackingRules::D3DCB())); } SECTION("float3 4-byte offset") { members[2].byteOffset += 4; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::D3DCB)); + CHECK((pack == PackingRules::D3DCB())); } } @@ -4709,13 +4712,13 @@ outer_struct2 a[4]; { members[1].byteOffset += 12; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } SECTION("float3 8-byte offset") { members[2].byteOffset += 8; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } } @@ -4724,7 +4727,7 @@ outer_struct2 a[4]; // float3[4] is the only stride of a pure array that actually changes members[6].type.arrayByteStride = 12; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } SECTION("scalar matrix strides") @@ -4733,13 +4736,13 @@ outer_struct2 a[4]; { members[12].type.matrixByteStride = 12; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } SECTION("[[row_major]] float4x3 tight matrix") { members[15].type.matrixByteStride = 12; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } } @@ -4747,35 +4750,35 @@ outer_struct2 a[4]; { members[21].byteOffset = members[20].byteOffset + 64 - 4; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } SECTION("trailing array overlap") { members[23].byteOffset = members[22].byteOffset + 64 - 4; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } SECTION("trailing matrix overlap") { members[25].byteOffset = members[24].byteOffset + 64 - 4; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } SECTION("struct vector member misaligned by array stride") { members[26].type.arrayByteStride = 20; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } SECTION("nested struct vector member misaligned by array stride") { members[27].type.arrayByteStride = 52; pack = BufferFormatter::EstimatePackingRules(ResourceId(), members); - CHECK((pack == Packing::Scalar)); + CHECK((pack == PackingRules::Scalar())); } } @@ -6889,70 +6892,70 @@ struct s { BufferFormatter::Init(GraphicsAPI::D3D11); parsed = BufferFormatter::ParseFormatString(lit("float a;"), 0, true); - CHECK((parsed.packing == Packing::D3DCB)); + CHECK((parsed.packing == PackingRules::D3DCB())); BufferFormatter::Init(GraphicsAPI::D3D11); parsed = BufferFormatter::ParseFormatString(lit("float a;"), 0, false); - CHECK((parsed.packing == Packing::D3DUAV)); + CHECK((parsed.packing == PackingRules::D3DUAV())); BufferFormatter::Init(GraphicsAPI::D3D12); parsed = BufferFormatter::ParseFormatString(lit("float a;"), 0, true); - CHECK((parsed.packing == Packing::D3DCB)); + CHECK((parsed.packing == PackingRules::D3DCB())); BufferFormatter::Init(GraphicsAPI::D3D12); parsed = BufferFormatter::ParseFormatString(lit("float a;"), 0, false); - CHECK((parsed.packing == Packing::D3DUAV)); + CHECK((parsed.packing == PackingRules::D3DUAV())); BufferFormatter::Init(GraphicsAPI::OpenGL); parsed = BufferFormatter::ParseFormatString(lit("float a;"), 0, true); - CHECK((parsed.packing == Packing::std140)); + CHECK((parsed.packing == PackingRules::STD140())); BufferFormatter::Init(GraphicsAPI::OpenGL); parsed = BufferFormatter::ParseFormatString(lit("float a;"), 0, false); - CHECK((parsed.packing == Packing::std430)); + CHECK((parsed.packing == PackingRules::STD430())); }; SECTION("Overriding API defaults") { BufferFormatter::Init(GraphicsAPI::D3D11); parsed = BufferFormatter::ParseFormatString(lit("#pack(c)\nfloat a;"), 0, true); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); BufferFormatter::Init(GraphicsAPI::D3D11); parsed = BufferFormatter::ParseFormatString(lit("#pack(c)\nfloat a;"), 0, false); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); BufferFormatter::Init(GraphicsAPI::D3D12); parsed = BufferFormatter::ParseFormatString(lit("#pack(c)\nfloat a;"), 0, true); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); BufferFormatter::Init(GraphicsAPI::D3D12); parsed = BufferFormatter::ParseFormatString(lit("#pack(c)\nfloat a;"), 0, false); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); BufferFormatter::Init(GraphicsAPI::OpenGL); parsed = BufferFormatter::ParseFormatString(lit("#pack(c)\nfloat a;"), 0, true); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); BufferFormatter::Init(GraphicsAPI::OpenGL); parsed = BufferFormatter::ParseFormatString(lit("#pack(c)\nfloat a;"), 0, false); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); }; SECTION("Parsing") { BufferFormatter::Init(GraphicsAPI::OpenGL); parsed = BufferFormatter::ParseFormatString(lit("#pack (c)\nfloat a;"), 0, false); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); BufferFormatter::Init(GraphicsAPI::OpenGL); parsed = BufferFormatter::ParseFormatString(lit("# pack (c)\nfloat a;"), 0, false); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); BufferFormatter::Init(GraphicsAPI::OpenGL); parsed = BufferFormatter::ParseFormatString( lit("# /*comm*/ pack /* comments */ (c)\nfloat a;"), 0, false); - CHECK((parsed.packing == Packing::C)); + CHECK((parsed.packing == PackingRules::C())); }; SECTION("Selecting packing rules") diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index f0f80c1f7..2a5c5fd36 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -929,6 +929,8 @@ void CaptureContext::LoadCapture(const rdcstr &captureFile, const ReplayOptions PointerTypeRegistry::Init(); + BufferInterpreter::context = this; + m_LoadInProgress = true; if(local) @@ -1569,6 +1571,8 @@ void CaptureContext::CloseCapture() m_CaptureLoaded = false; + BufferInterpreter::context = NULL; + m_Replay.CloseThread(); } diff --git a/qrenderdoc/Code/Interface/Helpers.cpp b/qrenderdoc/Code/Interface/Helpers.cpp new file mode 100644 index 000000000..9550e93bd --- /dev/null +++ b/qrenderdoc/Code/Interface/Helpers.cpp @@ -0,0 +1,111 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2026 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "Code/Interface/QRDInterface.h" + +#include "Code/QRDUtils.h" +#include "Helpers.h" + +ICaptureContext *BufferInterpreter::context = NULL; + +ParsedBufferFormat BufferInterpreter::Parse(rdcstr format) +{ + ParsedBufferFormat ret; + + ParsedFormat tmp = BufferFormatter::ParseFormatString(format, 0, false); + + ret.fixedHeader = tmp.fixed; + ret.structure = tmp.repeating; + ret.packing = tmp.packing; + + for(auto err = tmp.errors.begin(); err != tmp.errors.end(); ++err) + ret.errors.push_back({err.key(), rdcstr(err.value())}); + + return ret; +} + +rdcstr BufferInterpreter::Unparse(ShaderConstantType structType, PackingRules pack, ResourceId shader) +{ + return BufferFormatter::DeclareStruct(pack, shader, structType.name, structType.members, + structType.arrayByteStride); +} + +PackingRules BufferInterpreter::EstimatePackingRules(ShaderConstantType baseType, ResourceId shader) +{ + return BufferFormatter::EstimatePackingRules(shader, baseType.members); +} + +ShaderConstantType BufferInterpreter::GetPointerValType(PointerVal val) +{ + return PointerTypeRegistry::GetTypeDescriptor(val); +} + +ShaderConstantType BufferInterpreter::GetPointerType(uint32_t pointerTypeId, ResourceId shader) +{ + return PointerTypeRegistry::GetTypeDescriptor(shader, pointerTypeId); +} + +rdcpair BufferInterpreter::LookupPointer(uint64_t pointerAddress, + uint64_t minSize) +{ + if(context) + { + for(const BufferDescription &b : context->GetBuffers()) + { + if(b.gpuAddress && b.gpuAddress <= pointerAddress && + b.gpuAddress + b.length > pointerAddress + minSize) + { + return {b.resourceId, pointerAddress - b.gpuAddress}; + } + } + } + + return {ResourceId(), 0}; +} + +uint32_t BufferInterpreter::GetVariableAdvance(PackingRules pack, const ShaderConstant &var) +{ + return BufferFormatter::GetVarAdvance(pack, var); +} + +rdcarray BufferInterpreter::GetShaderVariables(const ShaderConstant &elem, + const bytebuf &data, + int32_t maxVariables) +{ + rdcarray ret; + const byte *cur = data.begin(); + const byte *end = data.end(); + + for(int i = 0; cur < end && (i < maxVariables || maxVariables == -1); i++) + { + ret.push_back(InterpretShaderVar(elem, cur, end)); + + if(elem.type.arrayByteStride == 0) + break; + + cur += elem.type.arrayByteStride; + } + + return ret; +} diff --git a/qrenderdoc/Code/Interface/Helpers.h b/qrenderdoc/Code/Interface/Helpers.h new file mode 100644 index 000000000..62643750b --- /dev/null +++ b/qrenderdoc/Code/Interface/Helpers.h @@ -0,0 +1,420 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2026 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +// NOTE: If any of these rules or the standard packings change, make sure to update +// BufferFormatter::EstimatePackingRules +DOCUMENT(R"( +PackingRules() +PackingRules(other: PackingRules) + +A description of individual rules for how data is packed in GPU-side structures and +buffers. + +Each individual member rule is such that ``False`` is more restrictive on packing, and ``True`` +is less restrictive. + +Several helpers are available for the common formats, see :meth:`PackingRules.STD140`, +:meth:`PackingRules.STD430`, :meth:`PackingRules.D3DCB`, :meth:`PackingRules.C` which provide +a quick way to fetch a known set of packing rules. +)"); +struct PackingRules +{ + DOCUMENT(""); + PackingRules() = default; + PackingRules(bool vectorAlignComponent, bool vectorStraddle16b, bool tightArrays, + bool trailingOverlap, bool tightBitfieldPacking) + : vectorAlignComponent(vectorAlignComponent), + vectorStraddle16b(vectorStraddle16b), + tightArrays(tightArrays), + trailingOverlap(trailingOverlap), + tightBitfieldPacking(tightBitfieldPacking) + { + } + + bool operator==(PackingRules o) const + { + return vectorAlignComponent == o.vectorAlignComponent && + vectorStraddle16b == o.vectorStraddle16b && tightArrays == o.tightArrays && + trailingOverlap == o.trailingOverlap && tightBitfieldPacking == o.tightBitfieldPacking; + } + bool operator!=(PackingRules o) const { return !(*this == o); } + + // property | vector_align_component | vector_straddle_16b | tight_arrays | trailing_overlap + // | false | false | false | false + DOCUMENT(R"( +:return: The GLSL std140 rules, used on OpenGL and Vulkan. +:rtype: PackingRules +)"); + inline static const PackingRules STD140() + { + return PackingRules(false, false, false, false, false); + } + + // | false | false | true | false + DOCUMENT(R"( +:return: The GLSL std430 rules, used on OpenGL and Vulkan. +:rtype: PackingRules +)"); + inline static const PackingRules STD430() + { + return PackingRules(false, false, true, false, false); + } + + // | true | false | false | true + DOCUMENT(R"( +:return: The D3D11 and D3D12 Constant Buffer rules. +:rtype: PackingRules +)"); + inline static const PackingRules D3DCB() { return PackingRules(true, false, false, true, false); } + + // | true | true | true | false + DOCUMENT(R"( +.. note:: + This is the standard C ABI with no special packing directives such as ``#pragma pack()``. + +:return: The standard C packing rules. +:rtype: PackingRules +)"); + inline static const PackingRules C() { return PackingRules(true, true, true, false, false); } + + // | true | true | true | true + DOCUMENT(R"( +:return: Vulkan scalar block layout rules, which are almost the same as C but in some cases + allow more tight packing than C by default. +:rtype: PackingRules +)"); + inline static const PackingRules Scalar() { return PackingRules(true, true, true, true, false); } + + // D3D UAVs are assumed to be the same as C packing + DOCUMENT(R"( +:return: The D3D Structured UAV buffer rules. This is considered to be the same as standard + C packing rules. +:rtype: PackingRules +)"); + inline static const PackingRules D3DUAV() { return C(); } + + DOCUMENT(R"(Flag indicating if a vector's alignment is only equal to its component alignment. + +If ``True`` this means vectors have no special alignment, and a 3-component float vector is +aligned to 4-byte the same as a scalar float. + +If ``False``, 2-wide vectors are aligned to their size, and 3-wide and 4-wide vectors are aligned +to a 4-wide vector's size. E.g. ``float2`` has 8 byte alignment, ``float3`` and ``float4`` have +16-byte alignment. + +:type: bool +)"); + bool vectorAlignComponent = false; + + DOCUMENT(R"(Flag indicating if vectors can straddle a 16-byte boundary with their components. + +If ``True`` this means vectors have no special restrictions and can be at any aligned byte offset. + +If ``False``, vectors must be at an offset such that the whole vector sits within the same +16-byte aligned region. + +:type: bool +)"); + bool vectorStraddle16b = false; + + DOCUMENT(R"(Flag indicating if arrays are tightly packed with the stride being their natural +alignment. + +If ``True`` this means each array element is at a suitably aligned offset after the previous. + +If ``False``, each array element is at a 16-byte aligned offset after the previous regardless +of the element size and alignment. + +:type: bool +)"); + bool tightArrays = false; + + DOCUMENT(R"(Flag indicating if the trailing alignment padding space after a struct member can +be used by the next member. + +If ``True`` then a struct that contains e.g. 2 bytes of padding at its end to align it to a 4-byte +alignment can be followed by a 2-byte member which can have an offset inside that padding region. + +If ``False`` then a struct consumes its padding space and the next member starts after the struct +even if it would otherwise fit and be aligned. + +.. warning:: + This is not supported by standard C layouts, but is supported by some GPU layouts. + +:type: bool +)"); + bool trailingOverlap = false; + + // whether bitfields will allow themselves to straddle their base type, or be aligned to stay + // within it. Equivalent to #pragma pack(1) in C++ + DOCUMENT(R"(tight_bitfield_packing desc + +:type: bool +)"); + DOCUMENT(R"(Flag indicating if bitfields allow bit-packed regions to straddle the base type. + +If ``True`` this means bit regions are tightly packed even if one region would cross two +base elements. E.g. if the base type is uint then three 20-bit regions would only +consume two uints as that is 60 bits total. + +If ``False`` this means each bit region ensures it only exists in one base element with +padding/unused bits in elements as necessary. E.g. if the base type is uint then three 20-bit +regions would consume three uints as each region would be padded into its own element. + +.. note:: + Bitfield packing is compiler defined on CPU but this mostly matches what happens with + ``#pragma pack(1)``. + +:type: bool +)"); + bool tightBitfieldPacking = false; +}; + +DECLARE_REFLECTION_STRUCT(PackingRules); + +DOCUMENT(R"( +ParseError() +ParseError(other: ParseError) + +An error that occurred while parsing a buffer format string. +)"); +struct ParseError +{ + DOCUMENT(""); + ParseError() = default; + + bool operator==(const ParseError &o) const { return line == o.line && error == o.error; } + bool operator<(const ParseError &o) const + { + if(line != o.line) + return line < o.line; + return error < o.error; + } + + DOCUMENT(R"(The 0-based line number in the input string where the error occurred. + +:type: int +)"); + int line; + + DOCUMENT(R"(The text of the format parsing error. + +:type: str +)"); + rdcstr error; +}; + +DECLARE_REFLECTION_STRUCT(ParseError); + +DOCUMENT(R"( +ParsedBufferFormat() +ParsedBufferFormat(other: ParsedBufferFormat) + +The result of parsing a buffer format string. +)"); +struct ParsedBufferFormat +{ + DOCUMENT(""); + ParsedBufferFormat() = default; + + DOCUMENT(R"(The fixed SoA variables before any repeating structure, if present. + +On some APIs it is possible to declare a fixed size amount of SoA data before then +an unbounded/runtime array of AoS data. If the format string is interpreted this +way then the initial fixed data structure will be returned in this member + +:type: renderdoc.ShaderConstant +)"); + ShaderConstant fixedHeader; + + DOCUMENT(R"(The main structure of data described by the input buffer string. + +:type: renderdoc.ShaderConstant +)"); + ShaderConstant structure; + + DOCUMENT(R"(The packing rules specified in the buffer format string. If not explicitly +stated then the estimated rules will be given here, as the most conservative packing that +would work for the current API. + +:type: PackingRules +)"); + PackingRules packing; + + DOCUMENT(R"(The list of errors encountered while processing the format string. + +:type: List[ParseError] +)"); + rdcarray errors; +}; + +DECLARE_REFLECTION_STRUCT(ParsedBufferFormat); + +DOCUMENT(R"( +BufferInterpreter() +BufferInterpreter(other: BufferInterpreter) + +A helper class with static methods to assist with interpreting buffer data +according to a given format or parsing format strings into format structures. +)"); +struct BufferInterpreter +{ +public: + BufferInterpreter() = default; + ~BufferInterpreter() = default; + +#ifndef SWIG + // for static lookups + static ICaptureContext *context; +#endif + + DOCUMENT(R"(Parse a buffer format string and return the format in a structure that can be +inspected or used to interpret data. + +For more information see :ref:`how_buffer_format`. + +.. warning:: + For format strings that specify pointers, care should be taken that + :data:`~renderdoc.ShaderConstantType.pointerTypeID` is an opaque identifier as there is no + shader reflection to look up. You should use :meth:`GetPointerType` to obtain the type + description of pointer types. + +:param str format: The format string to interpret +:return: The result of parsing the format string. +:rtype: ParsedBufferFormat +)"); + static ParsedBufferFormat Parse(rdcstr format); + + DOCUMENT(R"(Generate a buffer format string from a known structure type. + +This may not generate exactly, depending on the exact structure type. It may also not roundtrip +exactly when used with :meth:`Parse`. + +:param renderdoc.ShaderConstantType structType: The structure type to unparse. +:param PackingRules pack: The packing rules to use when generating the string. +:param renderdoc.ResourceId shader=ResourceId(): **Optional parameter**. The shader this struct + came from, used for determining the types of any pointer variables. Can be omitted if the struct + type did not come from a shader. +:return: The generated format string, or an empty string if an error happened. +:rtype: str +)"); + static rdcstr Unparse(ShaderConstantType structType, PackingRules pack, + ResourceId shader = ResourceId()); + + DOCUMENT(R"(Estimate the packing rules that apply to a given structure type. + +This is not exact, as less strict packing rules will apply equally to structures that use more strict +packing rules. This function returns only the most-strict set of rules that would be valid. + +:param renderdoc.ShaderConstantType baseType: The structure type to analyse. +:param renderdoc.ResourceId shader=ResourceId(): **Optional parameter**. The shader this struct + came from, used for determining the types of any pointer variables. Can be omitted if the struct + type did not come from a shader. +:return: The most conservative packing rules that satisfy the given type +:rtype: PackingRules +)"); + static PackingRules EstimatePackingRules(ShaderConstantType baseType, + ResourceId shader = ResourceId()); + + DOCUMENT(R"(Return the type description of a given pointer. + +Returns an empty type if the value is invalid. + +:param renderdoc.PointerVal val: The pointer value to inspect. +:return: The type description. +:rtype: renderdoc.ShaderConstantType +)"); + static ShaderConstantType GetPointerValType(PointerVal val); + + DOCUMENT(R"(Return the type description of a pointer ID. If this is from shader reflection +the ID is an index into :data:`~renderdoc.ShaderReflection.pointerTypes`. If the pointer type +was generated by parsing a buffer string it will be an arbitrary index. + +Returns an empty type if the type ID is invalid or if a shader is not provided for a shader-based +type ID. + +:param int pointerTypeId: The ID of the pointer type. +:param renderdoc.ResourceId shader=ResourceId(): **Optional parameter**. The shader this struct + came from, used for determining the types of any pointer variables. Can be omitted if the struct + type did not come from a shader. +:return: The type description. +:rtype: renderdoc.ShaderConstantType +)"); + static ShaderConstantType GetPointerType(uint32_t pointerTypeId, ResourceId shader = ResourceId()); + + DOCUMENT(R"(Look up a pointer address and return the :data:`~renderdoc.ResourceId` and offset of +the containing buffer. + +Due to buffer aliasing, it is possible a different overlapping buffer will be returned since there is +no way to differentiate based on purely an address. The :paramref:`LookupPointer.minSize` parameter can +be used to ensure that a range sits in the same buffer. + +If no matching buffer is found then the result is default initialised. + +This looks through the buffers available in :meth:`~CaptureContext.GetBuffers` and compares against +:data:`~renderdoc.BufferDescription.gpuAddress` and :data:`~renderdoc.BufferDescription.length`. + +:param int pointerAddress: The address of the pointer to look up. +:param int minSize=0: **Optional parameter**. The minimum number of bytes that must be available + after the address in the same buffer. +:return: The buffer ID and offset within that buffer. +:rtype: Tuple[renderdoc.ResourceId,int] +)"); + static rdcpair LookupPointer(uint64_t pointerAddress, uint64_t minSize = 0); + + DOCUMENT(R"(Return the number of bytes between the start and end of a variable type. + +.. note:: + Depending on the packing rules specified, this may not include the necessary padding or alignment + needed for the given type and may calculate only the offset to the end of the variable. If you + are calculating the offsets of elements of an array you should use + :data:`~renderdoc.ShaderConstantType.arrayByteStride`. + +:param PackingRules pack: The packing rules to use when calculating the advance. +:param renderdoc.ShaderConstant var: The variable to calculate. +:rtype: int +)"); + static uint32_t GetVariableAdvance(PackingRules pack, const ShaderConstant &var); + + DOCUMENT(R"(Return a list of shader variables by interpreting a ``bytes`` with a given type description. + +The number of variables can be limited for example to 1 if needed without needing to calculate how to +truncate the byte data. + +This will always return a whole number of variables even if the byte data is insufficient, with standard +out-of-bound reads returning 0 data. + +:param renderdoc.ShaderConstant var: The description of the variable to interpret +:param bytes data: The byte data to read the variable from. +:param int maxVariables=-1: **Optional parameter**. The maximum number of variables to read, or -1 to + read as many as can fit in the given byte data. +:rtype: List[renderdoc.ShaderVariable] +)"); + static rdcarray GetShaderVariables(const ShaderConstant &var, const bytebuf &data, + int32_t maxVariables = -1); +}; + +DECLARE_REFLECTION_STRUCT(BufferInterpreter); diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 7aa6c1e9e..81ccecb97 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -92,6 +92,7 @@ struct ICaptureContext; #include "Analytics.h" #include "Extensions.h" +#include "Helpers.h" #include "PersistentConfig.h" #include "RemoteHost.h" diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp index 23196c6f3..15cc6a145 100644 --- a/qrenderdoc/Code/QRDUtils.cpp +++ b/qrenderdoc/Code/QRDUtils.cpp @@ -1148,13 +1148,13 @@ bool RichResourceTextMouseEvent(const QWidget *owner, const QVariant &var, QRect if(!ptrType.members.isEmpty()) { - Packing::Rules pack = BufferFormatter::EstimatePackingRules(ResourceId(), ptrType); + PackingRules pack = BufferFormatter::EstimatePackingRules(ResourceId(), ptrType); // for scalar-wrapped structs (generated by 'float *foo' type declarations) use scalar // packing by default as that's probably what people will want most often and if we // guess we're going to guess very conservatively. if(ptrType.name.isEmpty() && ptrType.members.size() == 1) - pack = Packing::Scalar; + pack = PackingRules::Scalar(); formatter = BufferFormatter::DeclareStruct(pack, ResourceId(), ptrType.name, ptrType.members, ptrType.arrayByteStride); diff --git a/qrenderdoc/Code/QRDUtils.h b/qrenderdoc/Code/QRDUtils.h index 17c036a99..76675aa3e 100644 --- a/qrenderdoc/Code/QRDUtils.h +++ b/qrenderdoc/Code/QRDUtils.h @@ -81,120 +81,10 @@ inline QMetaType::Type GetVariantMetatype(const QVariant &v) return (QMetaType::Type)v.type(); } -namespace Packing -{ -// see note in Rules below -enum APIConfig -{ - // property | vector_align_component | vector_straddle_16b | tight_arrays | trailing_overlap - std140, // | false | false | false | false - std430, // | false | false | true | false - D3DCB, // | true | false | false | true - C, // | true | true | true | false - Scalar, // | true | true | true | true - - // D3D UAVs are assumed to be the same as C packing. With only 4 and 8 byte types this can't be - // fully verified and it's not documented at all. - D3DUAV = C, -}; - -// individual rules for packing. In general, true is more lenient on packing than false for each -// property, though struct_aligned is an exception (in that case true is more 'sensible') -// NOTE: If any of these rules or the above APIConfigs change, make sure to update -// BufferFormatter::EstimatePackingRules -struct Rules -{ - Rules() = default; - Rules(APIConfig config) - { - // no packing allows this by default, it is only enabled manually - tight_bitfield_packing = false; - - // default to the most conservative packing ruleset - - switch(config) - { - case std140: - { - break; - } - case std430: - { - tight_arrays = true; - break; - } - case D3DCB: - { - vector_align_component = true; - trailing_overlap = true; - break; - } - case C: - { - vector_align_component = true; - vector_straddle_16b = true; - tight_arrays = true; - break; - } - case Scalar: - { - vector_align_component = true; - vector_straddle_16b = true; - tight_arrays = true; - trailing_overlap = true; - break; - } - } - } - - bool operator==(Packing::Rules o) const - { - return vector_align_component == o.vector_align_component && - vector_straddle_16b == o.vector_straddle_16b && tight_arrays == o.tight_arrays && - trailing_overlap == o.trailing_overlap; - } - bool operator!=(Packing::Rules o) const { return !(*this == o); } - // is a vector's alignment equal to its component alignment? If not, vectors must have an - // a larger alignment e.g. for floats a float2 has 8 byte alignment, float3 and float4 have - // 16-byte alignment - bool vector_align_component = false; - - // can vectors straddle a 16-byte boundary? - // if not, offsets of vectors are padded as necessary so they do not cross the boundary - // - // note that vectors can only straddle the 16-byte boundary if they are not component aligned, so - // this can only be true if vector_align_component is also true. - bool vector_straddle_16b = false; - - // are arrays packed tightly with all elements contiguous? if not, each element starts on a - // 16-byte aligned offset - bool tight_arrays = false; - - // do non-tightly packed arrays and structs have reserved padding up to a multiple of their - // alignment? - // if so, subsequent elements must be placed after that padding region, if not subsequent elements - // can be inside that padding region. - // - // For D3D this is allowed for cbuffers, but *not* for UAVs/structured types. This is only - // applicable for structs since structured types have tight arrays, but in that case trailing - // padding is not usable - matching C - // - // note this is compatible with C packing for structs (C structs have a size that includes their - // trailing padding and members after a struct are not packed in that padding). For arrays it does - // not apply since C arrays are packed. - bool trailing_overlap = false; - - // whether bitfields will allow themselves to straddle their base type, or be aligned to stay - // within it. Equivalent to #pragma pack(1) in C++ - bool tight_bitfield_packing = false; -}; - -}; // namespace Packing - struct ParsedFormat { ShaderConstant fixed, repeating; - Packing::Rules packing; + PackingRules packing; QMap errors; }; @@ -213,45 +103,45 @@ private: static bool ContainsUnbounded(const ShaderConstant &structType, rdcpair *found = NULL); - static QString DeclareStruct(Packing::Rules pack, ResourceId shader, + static QString DeclareStruct(PackingRules pack, ResourceId shader, QMap &declaredStructs, QMap &anonStructs, const QString &name, const rdcarray &members, uint32_t requiredByteStride, QString innerSkippedPrefixString); - static uint32_t GetAlignment(Packing::Rules pack, const ShaderConstant &constant); - static uint32_t GetUnpaddedStructAdvance(Packing::Rules pack, + static uint32_t GetAlignment(PackingRules pack, const ShaderConstant &constant); + static uint32_t GetUnpaddedStructAdvance(PackingRules pack, const rdcarray &members); static uint32_t GetVarStraddleSize(const ShaderConstant &var); static uint32_t GetVarSizeAndTrail(const ShaderConstant &var); - static void EstimatePackingRules(Packing::Rules &pack, ResourceId shader, + static void EstimatePackingRules(PackingRules &pack, ResourceId shader, const ShaderConstant &constant, QSet &pointerTypesProcessed, uint32_t knownVecAlignment); - static void EstimatePackingRules(Packing::Rules &pack, ResourceId shader, + static void EstimatePackingRules(PackingRules &pack, ResourceId shader, const rdcarray &members, QSet &pointerTypesProcessed, uint32_t knownVecAlignment); - static QString DeclarePacking(Packing::Rules pack); + static QString DeclarePacking(PackingRules pack); + static QString DeclareEnum(const QString &name, const rdcarray &members, + VarType baseType); public: BufferFormatter() = default; static void Init(GraphicsAPI api) { m_API = api; } static ParsedFormat ParseFormatString(const QString &formatString, uint64_t maxLen, bool cbuffer); - static uint32_t GetVarAdvance(const Packing::Rules &pack, const ShaderConstant &var); + static uint32_t GetVarAdvance(PackingRules pack, const ShaderConstant &var); - static Packing::Rules EstimatePackingRules(ResourceId shader, const ShaderConstantType &baseType); - static Packing::Rules EstimatePackingRules(ResourceId shader, - const rdcarray &members); + static PackingRules EstimatePackingRules(ResourceId shader, const ShaderConstantType &baseType); + static PackingRules EstimatePackingRules(ResourceId shader, + const rdcarray &members); static QString GetTextureFormatString(const TextureDescription &tex); - static QString GetBufferFormatString(Packing::Rules pack, ResourceId shader, + static QString GetBufferFormatString(PackingRules pack, ResourceId shader, const ShaderResource &res, const ResourceFormat &viewFormat); - static QString DeclareStruct(Packing::Rules pack, ResourceId shader, const QString &name, + static QString DeclareStruct(PackingRules pack, ResourceId shader, const QString &name, const rdcarray &members, uint32_t requiredByteStride); - static QString DeclareEnum(const QString &name, const rdcarray &members, - VarType baseType); }; QVariantList GetVariants(ResourceFormat format, const ShaderConstant &var, const byte *&data, diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i index 9b5ddce7e..d280eea23 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i @@ -174,6 +174,7 @@ SWIGPY_DESTRUCTOR_CLOSURE(capviewer_deinit) /* defines capviewer_deinit_destruct %include "Code/Interface/PersistentConfig.h" %include "Code/Interface/RemoteHost.h" %include "Code/Interface/Extensions.h" +%include "Code/Interface/Helpers.h" DOCUMENT(""); @@ -186,6 +187,7 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, DialogButton) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, RemoteHost) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ConnectedTempCapture) TEMPLATE_ARRAY_INSTANTIATE_PTR(rdcarray, ICaptureViewer) +TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ParseError) // unignore the function from above %rename("%s") IReplayManager::BlockInvoke; diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp index 0645e0308..744099651 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp @@ -260,3 +260,48 @@ void RemoteHost::SetConnected(bool connected) void RemoteHost::SetShutdown() { } + +ICaptureContext *BufferInterpreter::context = NULL; + +ParsedBufferFormat BufferInterpreter::Parse(rdcstr format) +{ + return {}; +} + +rdcstr BufferInterpreter::Unparse(ShaderConstantType structType, PackingRules pack, ResourceId shader) +{ + return rdcstr(); +} + +PackingRules BufferInterpreter::EstimatePackingRules(ShaderConstantType baseType, ResourceId shader) +{ + return PackingRules(); +} + +ShaderConstantType BufferInterpreter::GetPointerValType(PointerVal val) +{ + return ShaderConstantType(); +} + +ShaderConstantType BufferInterpreter::GetPointerType(uint32_t pointerTypeId, ResourceId shader) +{ + return ShaderConstantType(); +} + +rdcpair BufferInterpreter::LookupPointer(uint64_t pointerAddress, + uint64_t minSize /*= 0*/) +{ + return {ResourceId(), 0}; +} + +uint32_t BufferInterpreter::GetVariableAdvance(PackingRules pack, const ShaderConstant &var) +{ + return 0; +} + +rdcarray BufferInterpreter::GetShaderVariables(const ShaderConstant &elem, + const bytebuf &data, + int32_t maxVariables) +{ + return {}; +} diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index def2f8430..cb0378059 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -537,7 +537,7 @@ struct BufferConfiguration uint32_t numRows = 0, unclampedNumRows = 0; uint32_t pagingOffset = 0; - Packing::Rules packing; + PackingRules packing; ShaderConstant fixedVars; rdcarray evalVars; uint32_t repeatStride = 1; @@ -3476,7 +3476,7 @@ void BufferViewer::OnEventChanged(uint32_t eventId) reflection->constantBlocks[m_CBufferSlot.slot].variables; if(IsD3D(m_Ctx.APIProps().pipelineType)) - bufdata->inConfig.packing = Packing::D3DCB; + bufdata->inConfig.packing = PackingRules::D3DCB(); else bufdata->inConfig.packing = BufferFormatter::EstimatePackingRules( reflection->resourceId, bufdata->inConfig.fixedVars.type.members); @@ -4224,7 +4224,7 @@ void BufferViewer::UI_AddTaskPayloads(RDTreeWidgetItem *root, size_t baseOffset, noarray.type.elements = 1; // calculate the tight scalar-packed advance, so we can detect padding - uint32_t elSize = BufferFormatter::GetVarAdvance(Packing::Scalar, noarray); + uint32_t elSize = BufferFormatter::GetVarAdvance(PackingRules::Scalar(), noarray); for(uint32_t e = 0; e < v.members.size(); e++) { @@ -4261,7 +4261,7 @@ void BufferViewer::UI_AddTaskPayloads(RDTreeWidgetItem *root, size_t baseOffset, } // advance by the tight scalar-packed advance, so we can detect padding - offset += BufferFormatter::GetVarAdvance(Packing::Scalar, c); + offset += BufferFormatter::GetVarAdvance(PackingRules::Scalar(), c); } } @@ -4350,7 +4350,7 @@ void BufferViewer::UI_AddFixedVariables(RDTreeWidgetItem *root, uint32_t baseOff noarray.type.elements = 1; // calculate the tight scalar-packed advance, so we can detect padding - uint32_t elSize = BufferFormatter::GetVarAdvance(Packing::Scalar, noarray); + uint32_t elSize = BufferFormatter::GetVarAdvance(PackingRules::Scalar(), noarray); for(uint32_t e = 0; e < v.members.size(); e++) { @@ -4411,7 +4411,7 @@ void BufferViewer::UI_AddFixedVariables(RDTreeWidgetItem *root, uint32_t baseOff } // advance by the tight scalar-packed advance, so we can detect padding - offset += BufferFormatter::GetVarAdvance(Packing::Scalar, c); + offset += BufferFormatter::GetVarAdvance(PackingRules::Scalar(), c); } } @@ -5300,25 +5300,25 @@ bool BufferViewer::eventFilter(QObject *watched, QEvent *event) QString tooltip; - Packing::Rules pack = m_ModelIn->getConfig().packing; + PackingRules pack = m_ModelIn->getConfig().packing; if(tag.valid && tag.padding) { tooltip = tr("%1 bytes of padding. Packing rules in effect:\n\n") .arg(Formatter::HumanFormat(tag.byteSize, Formatter::OffsetSize)); - if(pack == Packing::D3DCB) + if(pack == PackingRules::D3DCB()) tooltip += tr("Standard D3D constant buffer packing.\n\n"); - else if(pack == Packing::std140) + else if(pack == PackingRules::STD140()) tooltip += tr("Standard std140 buffer packing.\n\n"); - else if(pack == Packing::std430) + else if(pack == PackingRules::STD430()) tooltip += tr("Standard std430 buffer packing.\n\n"); - else if(pack == Packing::C) + else if(pack == PackingRules::C()) tooltip += tr("Standard C / D3D UAV packing.\n\n"); - else if(pack == Packing::Scalar) + else if(pack == PackingRules::Scalar()) tooltip += tr("Scalar packing.\n\n"); - if(pack.vector_align_component) + if(pack.vectorAlignComponent) tooltip += tr("- Vectors are only aligned to their component (float4 to 4-byte boundary)\n"); else @@ -5326,18 +5326,18 @@ bool BufferViewer::eventFilter(QObject *watched, QEvent *event) tr("- 3- and 4-wide vectors must be aligned to a 4-wide boundary\n" " (vec3 and vec4 to 16-byte boundary)\n"); - if(pack.tight_arrays) + if(pack.tightArrays) tooltip += tr("- Arrays are tightly packed to each element\n"); else tooltip += tr("- Arrays have a stride of a 16 bytes\n"); - if(pack.trailing_overlap) + if(pack.trailingOverlap) tooltip += tr("- Variables can overlap the trailing padding in arrays or structs.\n"); else tooltip += tr("- Variables must not overlap the trailing padding in arrays or structs.\n"); - if(pack.vector_straddle_16b) + if(pack.vectorStraddle16b) tooltip += tr("- Vectors can straddle 16-byte boundaries.\n"); else tooltip += tr("- Vectors must not straddle 16-byte boundaries.\n"); @@ -6131,7 +6131,8 @@ void BufferViewer::on_setFormat_toggled(bool checked) if(IsD3D(m_Ctx.APIProps().pipelineType)) ui->formatSpecifier->setAutoFormat(BufferFormatter::DeclareStruct( - Packing::D3DCB, reflection->resourceId, reflection->constantBlocks[m_CBufferSlot.slot].name, + PackingRules::D3DCB(), reflection->resourceId, + reflection->constantBlocks[m_CBufferSlot.slot].name, reflection->constantBlocks[m_CBufferSlot.slot].variables, 0)); else ui->formatSpecifier->setAutoFormat(BufferFormatter::DeclareStruct( diff --git a/qrenderdoc/Windows/DescriptorViewer.cpp b/qrenderdoc/Windows/DescriptorViewer.cpp index 2b781a22a..f1f0f2e59 100644 --- a/qrenderdoc/Windows/DescriptorViewer.cpp +++ b/qrenderdoc/Windows/DescriptorViewer.cpp @@ -1337,8 +1337,8 @@ DescriptorViewer::DescriptorViewer(ICaptureContext &ctx, QWidget *parent) if(tag.descriptor.type == DescriptorType::TypedBuffer || tag.descriptor.type == DescriptorType::ReadWriteTypedBuffer) - format = BufferFormatter::GetBufferFormatString(Packing::C, ResourceId(), ShaderResource(), - tag.descriptor.format); + format = BufferFormatter::GetBufferFormatString(PackingRules::C(), ResourceId(), + ShaderResource(), tag.descriptor.format); IBufferViewer *viewer = m_Ctx.ViewBuffer(tag.descriptor.byteOffset, tag.descriptor.byteSize, tag.descriptor.resource, format); diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index ebfc1edcd..d0497a077 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -2323,7 +2323,7 @@ void D3D11PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in if(shaderRes) { - format = BufferFormatter::GetBufferFormatString(Packing::D3DUAV, stage->resourceId, + format = BufferFormatter::GetBufferFormatString(PackingRules::D3DUAV(), stage->resourceId, *shaderRes, view.desc.format); if(view.desc.flags & DescriptorFlags::RawBuffer) diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index ef62e1186..f333ad92c 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -2456,7 +2456,7 @@ void D3D12PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in if(shaderRes) { - format = BufferFormatter::GetBufferFormatString(Packing::D3DUAV, stage->resourceId, + format = BufferFormatter::GetBufferFormatString(PackingRules::D3DUAV(), stage->resourceId, *shaderRes, view.descriptor.format); if(view.descriptor.flags & DescriptorFlags::RawBuffer) diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index c8d70334f..dabf69db3 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -183,6 +183,7 @@ SOURCES += Code/qrenderdoc.cpp \ Code/Interface/ShaderProcessingTool.cpp \ Code/Interface/PersistentConfig.cpp \ Code/Interface/RemoteHost.cpp \ + Code/Interface/Helpers.cpp \ Styles/StyleData.cpp \ Styles/RDStyle/RDStyle.cpp \ Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.cpp \ @@ -271,6 +272,7 @@ HEADERS += Code/CaptureContext.h \ Code/Interface/QRDInterface.h \ Code/Interface/Analytics.h \ Code/Interface/PersistentConfig.h \ + Code/Interface/Helpers.h \ Code/Interface/Extensions.h \ Code/Interface/RemoteHost.h \ Styles/StyleData.h \ diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index e8cc28139..a42d4f6bd 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -578,6 +578,7 @@ + @@ -935,6 +936,7 @@ + diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 60875b5e8..aaf333101 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -798,6 +798,9 @@ Code\Interface + + Code\Interface + @@ -1184,6 +1187,9 @@ Code\Interface + + Code\Interface +