Bring across FillCBufferVariables from D3D11

* These implementations are identical and really only depend on DXBC -
  they should be shared.
This commit is contained in:
baldurk
2016-09-23 14:08:26 +02:00
parent aa7b5558af
commit dbe82f31e6
3 changed files with 443 additions and 1 deletions
+356
View File
@@ -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<DXBC::CBufferVariable> &invars,
vector<ShaderVariable> &outvars,
const vector<byte> &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<ShaderVariable> 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<ShaderVariable> 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<ShaderVariable> varmembers;
vector<ShaderVariable> *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<DXBC::CBufferVariable> &invars,
vector<ShaderVariable> &outvars, bool flattenVec4s,
const vector<byte> &data)
{
size_t zero = 0;
vector<ShaderVariable> 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<byte> &retData)
{
+9
View File
@@ -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<DXBC::CBufferVariable> &invars,
vector<ShaderVariable> &outvars, bool flattenVec4s,
const vector<byte> &data);
void GetBufferData(ResourceId buff, uint64_t offset, uint64_t length, vector<byte> &retData);
void GetBufferData(ID3D12Resource *buff, uint64_t offset, uint64_t length, vector<byte> &retData);
@@ -190,6 +195,10 @@ private:
bool m_ShaderCacheDirty, m_CacheShaders;
map<uint32_t, ID3DBlob *> m_ShaderCache;
void FillCBufferVariables(const string &prefix, size_t &offset, bool flatten,
const vector<DXBC::CBufferVariable> &invars,
vector<ShaderVariable> &outvars, const vector<byte> &data);
void RenderTextInternal(ID3D12GraphicsCommandList *list, float x, float y, const char *text);
bool RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, TextureDisplay cfg, bool blendAlpha);
+78 -1
View File
@@ -1316,7 +1316,84 @@ void D3D12Replay::RenderHighlightBox(float w, float h, float scale)
void D3D12Replay::FillCBufferVariables(ResourceId shader, string entryPoint, uint32_t cbufSlot,
vector<ShaderVariable> &outvars, const vector<byte> &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<D3D12RenderState::SignatureElement> *sigElems = NULL;
if(dxbc->m_Type == D3D11_ShaderType_Compute && rs.compute.rootsig != ResourceId())
{
sig = m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(
rs.compute.rootsig);
sigElems = &rs.compute.sigelems;
}
else if(dxbc->m_Type != D3D11_ShaderType_Compute && rs.graphics.rootsig != ResourceId())
{
sig = m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(
rs.graphics.rootsig);
sigElems = &rs.graphics.sigelems;
}
vector<byte> 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<PixelModification> D3D12Replay::PixelHistory(vector<EventUsage> events, ResourceId target,