From dbe82f31e64920453b7b6c88f0a400b65143f776 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 23 Sep 2016 14:08:26 +0200 Subject: [PATCH] Bring across FillCBufferVariables from D3D11 * These implementations are identical and really only depend on DXBC - they should be shared. --- renderdoc/driver/d3d12/d3d12_debug.cpp | 356 ++++++++++++++++++++++++ renderdoc/driver/d3d12/d3d12_debug.h | 9 + renderdoc/driver/d3d12/d3d12_replay.cpp | 79 +++++- 3 files changed, 443 insertions(+), 1 deletion(-) diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index 0e7e0549d..e01243666 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -1391,6 +1391,362 @@ void D3D12DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, ui m_ReadbackBuffer->Unmap(0, &range); } +void D3D12DebugManager::FillCBufferVariables(const string &prefix, size_t &offset, bool flatten, + const vector &invars, + vector &outvars, + const vector &data) +{ + using namespace DXBC; + using namespace ShaderDebug; + + size_t o = offset; + + for(size_t v = 0; v < invars.size(); v++) + { + size_t vec = o + invars[v].descriptor.offset / 16; + size_t comp = (invars[v].descriptor.offset - (invars[v].descriptor.offset & ~0xf)) / 4; + size_t sz = RDCMAX(1U, invars[v].type.descriptor.bytesize / 16); + + offset = vec + sz; + + string basename = prefix + invars[v].name; + + uint32_t rows = invars[v].type.descriptor.rows; + uint32_t cols = invars[v].type.descriptor.cols; + uint32_t elems = RDCMAX(1U, invars[v].type.descriptor.elements); + + if(!invars[v].type.members.empty()) + { + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "[%d]", elems); + + ShaderVariable var; + var.name = basename; + var.rows = var.columns = 0; + var.type = eVar_Float; + + std::vector varmembers; + + if(elems > 1) + { + for(uint32_t i = 0; i < elems; i++) + { + StringFormat::snprintf(buf, 63, "[%d]", i); + + if(flatten) + { + FillCBufferVariables(basename + buf + ".", vec, flatten, invars[v].type.members, + outvars, data); + } + else + { + ShaderVariable vr; + vr.name = basename + buf; + vr.rows = vr.columns = 0; + vr.type = eVar_Float; + + std::vector mems; + + FillCBufferVariables("", vec, flatten, invars[v].type.members, mems, data); + + vr.isStruct = true; + + vr.members = mems; + + varmembers.push_back(vr); + } + } + + var.isStruct = false; + } + else + { + var.isStruct = true; + + if(flatten) + FillCBufferVariables(basename + ".", vec, flatten, invars[v].type.members, outvars, data); + else + FillCBufferVariables("", vec, flatten, invars[v].type.members, varmembers, data); + } + + if(!flatten) + { + var.members = varmembers; + outvars.push_back(var); + } + + continue; + } + + if(invars[v].type.descriptor.varClass == CLASS_OBJECT || + invars[v].type.descriptor.varClass == CLASS_STRUCT || + invars[v].type.descriptor.varClass == CLASS_INTERFACE_CLASS || + invars[v].type.descriptor.varClass == CLASS_INTERFACE_POINTER) + { + RDCWARN("Unexpected variable '%s' of class '%u' in cbuffer, skipping.", + invars[v].name.c_str(), invars[v].type.descriptor.type); + continue; + } + + size_t elemByteSize = 4; + VarType type = eVar_Float; + switch(invars[v].type.descriptor.type) + { + case VARTYPE_INT: type = eVar_Int; break; + case VARTYPE_FLOAT: type = eVar_Float; break; + case VARTYPE_BOOL: + case VARTYPE_UINT: + case VARTYPE_UINT8: type = eVar_UInt; break; + case VARTYPE_DOUBLE: + elemByteSize = 8; + type = eVar_Double; + break; + default: + RDCERR("Unexpected type %d for variable '%s' in cbuffer", invars[v].type.descriptor.type, + invars[v].name.c_str()); + } + + bool columnMajor = invars[v].type.descriptor.varClass == CLASS_MATRIX_COLUMNS; + + size_t outIdx = vec; + if(!flatten) + { + outIdx = outvars.size(); + outvars.resize(RDCMAX(outIdx + 1, outvars.size())); + } + else + { + if(columnMajor) + outvars.resize(RDCMAX(outIdx + cols * elems, outvars.size())); + else + outvars.resize(RDCMAX(outIdx + rows * elems, outvars.size())); + } + + size_t dataOffset = vec * sizeof(Vec4f) + comp * sizeof(float); + + if(outvars[outIdx].name.count > 0) + { + RDCASSERT(flatten); + + RDCASSERT(outvars[vec].rows == 1); + RDCASSERT(outvars[vec].columns == comp); + RDCASSERT(rows == 1); + + string combinedName = outvars[outIdx].name.elems; + combinedName += ", " + basename; + outvars[outIdx].name = combinedName; + outvars[outIdx].rows = 1; + outvars[outIdx].isStruct = false; + outvars[outIdx].columns += cols; + + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + memcpy(&outvars[outIdx].value.uv[comp], d, + RDCMIN(data.size() - dataOffset, elemByteSize * cols)); + } + } + else + { + outvars[outIdx].name = basename; + outvars[outIdx].rows = 1; + outvars[outIdx].type = type; + outvars[outIdx].isStruct = false; + outvars[outIdx].columns = cols; + + ShaderVariable &var = outvars[outIdx]; + + bool isArray = invars[v].type.descriptor.elements > 1; + + if(rows * elems == 1) + { + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + memcpy(&outvars[outIdx].value.uv[flatten ? comp : 0], d, + RDCMIN(data.size() - dataOffset, elemByteSize * cols)); + } + } + else if(!isArray && !flatten) + { + outvars[outIdx].rows = rows; + + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + RDCASSERT(rows <= 4 && rows * cols <= 16); + + if(columnMajor) + { + uint32_t tmp[16] = {0}; + + // matrices always have 4 columns, for padding reasons (the same reason arrays + // put every element on a new vec4) + for(uint32_t c = 0; c < cols; c++) + { + size_t srcoffs = 4 * elemByteSize * c; + size_t dstoffs = rows * elemByteSize * c; + memcpy((byte *)(tmp) + dstoffs, d + srcoffs, + RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * rows)); + } + + // transpose + for(size_t r = 0; r < rows; r++) + for(size_t c = 0; c < cols; c++) + outvars[outIdx].value.uv[r * cols + c] = tmp[c * rows + r]; + } + else // CLASS_MATRIX_ROWS or other data not to transpose. + { + // matrices always have 4 columns, for padding reasons (the same reason arrays + // put every element on a new vec4) + for(uint32_t r = 0; r < rows; r++) + { + size_t srcoffs = 4 * elemByteSize * r; + size_t dstoffs = cols * elemByteSize * r; + memcpy((byte *)(&outvars[outIdx].value.uv[0]) + dstoffs, d + srcoffs, + RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * cols)); + } + } + } + } + else if(rows * elems > 1) + { + char buf[64] = {0}; + + var.name = outvars[outIdx].name; + + vector varmembers; + vector *out = &outvars; + size_t rowCopy = 1; + + uint32_t registers = rows; + uint32_t regLen = cols; + const char *regName = "row"; + + string base = outvars[outIdx].name.elems; + + if(!flatten) + { + var.rows = 0; + var.columns = 0; + outIdx = 0; + out = &varmembers; + varmembers.resize(elems); + rowCopy = rows; + rows = 1; + registers = 1; + } + else + { + if(columnMajor) + { + registers = cols; + regLen = rows; + regName = "col"; + } + } + + size_t rowDataOffset = vec * sizeof(Vec4f); + + for(size_t r = 0; r < registers * elems; r++) + { + if(isArray && registers > 1) + StringFormat::snprintf(buf, 63, "[%d].%s%d", r / registers, regName, r % registers); + else if(registers > 1) + StringFormat::snprintf(buf, 63, ".%s%d", regName, r); + else + StringFormat::snprintf(buf, 63, "[%d]", r); + + (*out)[outIdx + r].name = base + buf; + (*out)[outIdx + r].rows = (uint32_t)rowCopy; + (*out)[outIdx + r].type = type; + (*out)[outIdx + r].isStruct = false; + (*out)[outIdx + r].columns = regLen; + + size_t totalSize = 0; + + if(flatten) + { + totalSize = elemByteSize * regLen; + } + else + { + // in a matrix, each major element before the last takes up a full + // vec4 at least + size_t vecSize = elemByteSize * 4; + + if(columnMajor) + totalSize = vecSize * (cols - 1) + elemByteSize * rowCopy; + else + totalSize = vecSize * (rowCopy - 1) + elemByteSize * cols; + } + + if((rowDataOffset % sizeof(Vec4f) != 0) && + (rowDataOffset / sizeof(Vec4f) != (rowDataOffset + totalSize) / sizeof(Vec4f))) + { + rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); + } + + if(rowDataOffset < data.size()) + { + const byte *d = &data[rowDataOffset]; + + memcpy(&((*out)[outIdx + r].value.uv[0]), d, + RDCMIN(data.size() - rowDataOffset, totalSize)); + + if(!flatten && columnMajor) + { + ShaderVariable tmp = (*out)[outIdx + r]; + + size_t transposeRows = rowCopy > 1 ? 4 : 1; + + // transpose + for(size_t ri = 0; ri < transposeRows; ri++) + for(size_t ci = 0; ci < cols; ci++) + (*out)[outIdx + r].value.uv[ri * cols + ci] = tmp.value.uv[ci * transposeRows + ri]; + } + } + + if(flatten) + { + rowDataOffset += sizeof(Vec4f); + } + else + { + if(columnMajor) + rowDataOffset += sizeof(Vec4f) * (cols - 1) + sizeof(float) * rowCopy; + else + rowDataOffset += sizeof(Vec4f) * (rowCopy - 1) + sizeof(float) * cols; + } + } + + if(!flatten) + { + var.isStruct = false; + var.members = varmembers; + } + } + } + } +} + +void D3D12DebugManager::FillCBufferVariables(const vector &invars, + vector &outvars, bool flattenVec4s, + const vector &data) +{ + size_t zero = 0; + + vector v; + FillCBufferVariables("", zero, flattenVec4s, invars, v, data); + + outvars.reserve(v.size()); + for(size_t i = 0; i < v.size(); i++) + outvars.push_back(v[i]); +} + void D3D12DebugManager::GetBufferData(ResourceId buff, uint64_t offset, uint64_t length, vector &retData) { diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index aa211f795..862dfb013 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -26,6 +26,7 @@ #include "api/replay/renderdoc_replay.h" #include "core/core.h" +#include "driver/shaders/dxbc/dxbc_debug.h" #include "replay/replay_driver.h" #include "d3d12_common.h" @@ -73,6 +74,10 @@ public: void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, FormatComponentType typeHint, float pixel[4]); + void FillCBufferVariables(const vector &invars, + vector &outvars, bool flattenVec4s, + const vector &data); + void GetBufferData(ResourceId buff, uint64_t offset, uint64_t length, vector &retData); void GetBufferData(ID3D12Resource *buff, uint64_t offset, uint64_t length, vector &retData); @@ -190,6 +195,10 @@ private: bool m_ShaderCacheDirty, m_CacheShaders; map m_ShaderCache; + void FillCBufferVariables(const string &prefix, size_t &offset, bool flatten, + const vector &invars, + vector &outvars, const vector &data); + void RenderTextInternal(ID3D12GraphicsCommandList *list, float x, float y, const char *text); bool RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, TextureDisplay cfg, bool blendAlpha); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index f9e81b8f0..28de22d31 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -1316,7 +1316,84 @@ void D3D12Replay::RenderHighlightBox(float w, float h, float scale) void D3D12Replay::FillCBufferVariables(ResourceId shader, string entryPoint, uint32_t cbufSlot, vector &outvars, const vector &data) { - return; + if(shader == ResourceId()) + return; + + ID3D12DeviceChild *res = m_pDevice->GetResourceManager()->GetCurrentResource(shader); + + if(!WrappedID3D12PipelineState::ShaderEntry::IsAlloc(res)) + { + RDCERR("Shader ID %llu does not correspond to a known fake shader", shader); + return; + } + + WrappedID3D12PipelineState::ShaderEntry *sh = (WrappedID3D12PipelineState::ShaderEntry *)res; + + DXBC::DXBCFile *dxbc = sh->GetDXBC(); + const ShaderBindpointMapping &bindMap = sh->GetMapping(); + + RDCASSERT(dxbc); + + DXBC::CBuffer *cb = NULL; + + uint32_t idx = 0; + for(size_t i = 0; i < dxbc->m_CBuffers.size(); i++) + { + if(dxbc->m_CBuffers[i].descriptor.type != DXBC::CBuffer::Descriptor::TYPE_CBUFFER) + continue; + + if(idx == cbufSlot) + cb = &dxbc->m_CBuffers[i]; + + idx++; + } + + if(cb && cbufSlot < (uint32_t)bindMap.ConstantBlocks.count) + { + // check if the data actually comes from root constants + + const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; + BindpointMap bind = bindMap.ConstantBlocks[cbufSlot]; + + WrappedID3D12RootSignature *sig = NULL; + const vector *sigElems = NULL; + + if(dxbc->m_Type == D3D11_ShaderType_Compute && rs.compute.rootsig != ResourceId()) + { + sig = m_pDevice->GetResourceManager()->GetCurrentAs( + rs.compute.rootsig); + sigElems = &rs.compute.sigelems; + } + else if(dxbc->m_Type != D3D11_ShaderType_Compute && rs.graphics.rootsig != ResourceId()) + { + sig = m_pDevice->GetResourceManager()->GetCurrentAs( + rs.graphics.rootsig); + sigElems = &rs.graphics.sigelems; + } + + vector rootData; + + for(size_t i = 0; sig && i < sig->sig.params.size(); i++) + { + const D3D12RootSignatureParameter &p = sig->sig.params[i]; + + if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS && + p.Constants.RegisterSpace == (UINT)bind.bindset && + p.Constants.ShaderRegister == (UINT)bind.bind) + { + rootData.resize(sig->sig.params[i].Constants.Num32BitValues); + + if(i < sigElems->size() && (*sigElems)[i].type == eRootConst) + { + memcpy(&rootData[0], &(*sigElems)[i].constants[0], + RDCMIN((*sigElems)[i].constants.size() * sizeof(uint32_t), rootData.size())); + } + } + } + + m_pDevice->GetDebugManager()->FillCBufferVariables(cb->variables, outvars, false, + rootData.empty() ? data : rootData); + } } vector D3D12Replay::PixelHistory(vector events, ResourceId target,