mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-21 21:26:12 +00:00
Ditch D3D11's anomalous identity bindpoint mapping for proper handling
This commit is contained in:
@@ -890,11 +890,19 @@ BoundCBuffer CommonPipelineState::GetConstantBuffer(ShaderStage stage, uint32_t
|
||||
{
|
||||
const D3D11Pipe::Shader &s = GetD3D11Stage(stage);
|
||||
|
||||
if(BufIdx < (uint32_t)s.ConstantBuffers.count)
|
||||
if(s.ShaderDetails != NULL && BufIdx < (uint32_t)s.ShaderDetails->ConstantBlocks.count)
|
||||
{
|
||||
buf = s.ConstantBuffers[BufIdx].Buffer;
|
||||
ByteOffset = s.ConstantBuffers[BufIdx].VecOffset * 4 * sizeof(float);
|
||||
ByteSize = s.ConstantBuffers[BufIdx].VecCount * 4 * sizeof(float);
|
||||
const BindpointMap &bind =
|
||||
s.BindpointMapping.ConstantBlocks[s.ShaderDetails->ConstantBlocks[BufIdx].bindPoint];
|
||||
|
||||
if(bind.bind >= s.ConstantBuffers.count)
|
||||
return BoundCBuffer();
|
||||
|
||||
const D3D11Pipe::CBuffer &descriptor = s.ConstantBuffers[bind.bind];
|
||||
|
||||
buf = descriptor.Buffer;
|
||||
ByteOffset = descriptor.VecOffset * 4 * sizeof(float);
|
||||
ByteSize = descriptor.VecCount * 4 * sizeof(float);
|
||||
}
|
||||
}
|
||||
else if(IsLogD3D12())
|
||||
|
||||
@@ -1411,13 +1411,15 @@ void BufferViewer::OnEventChanged(uint32_t eventID)
|
||||
|
||||
m_Ctx.Replay().AsyncInvoke([this, vsinHoriz, vsoutHoriz, gsoutHoriz](IReplayController *r) {
|
||||
|
||||
BufferData *buf = NULL;
|
||||
|
||||
if(m_MeshView)
|
||||
{
|
||||
RT_FetchMeshData(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferData *buf = new BufferData;
|
||||
buf = new BufferData;
|
||||
rdctype::array<byte> data;
|
||||
if(m_IsBuffer)
|
||||
{
|
||||
@@ -1435,25 +1437,31 @@ void BufferViewer::OnEventChanged(uint32_t eventID)
|
||||
buf->data = new byte[data.count];
|
||||
memcpy(buf->data, data.elems, data.count);
|
||||
buf->end = buf->data + data.count;
|
||||
|
||||
// calculate tight stride
|
||||
buf->stride = 0;
|
||||
for(const FormatElement &el : m_ModelVSIn->columns)
|
||||
buf->stride += el.byteSize();
|
||||
|
||||
buf->stride = qMax((size_t)1, buf->stride);
|
||||
|
||||
m_ModelVSIn->numRows = uint32_t((data.count + buf->stride - 1) / buf->stride);
|
||||
|
||||
// ownership passes to model
|
||||
m_ModelVSIn->buffers.push_back(buf);
|
||||
}
|
||||
|
||||
updatePreviewColumns();
|
||||
GUIInvoke::call([this, buf, vsinHoriz, vsoutHoriz, gsoutHoriz] {
|
||||
|
||||
RT_UpdateAndDisplay(r);
|
||||
if(buf)
|
||||
{
|
||||
// calculate tight stride
|
||||
buf->stride = 0;
|
||||
for(const FormatElement &el : m_ModelVSIn->columns)
|
||||
buf->stride += el.byteSize();
|
||||
|
||||
buf->stride = qMax((size_t)1, buf->stride);
|
||||
|
||||
uint32_t bufCount = uint32_t(buf->end - buf->data);
|
||||
|
||||
m_ModelVSIn->numRows = uint32_t((bufCount + buf->stride - 1) / buf->stride);
|
||||
|
||||
// ownership passes to model
|
||||
m_ModelVSIn->buffers.push_back(buf);
|
||||
}
|
||||
|
||||
updatePreviewColumns();
|
||||
|
||||
INVOKE_MEMFN(RT_UpdateAndDisplay);
|
||||
|
||||
GUIInvoke::call([this, vsinHoriz, vsoutHoriz, gsoutHoriz] {
|
||||
m_ModelVSIn->endReset();
|
||||
m_ModelVSOut->endReset();
|
||||
m_ModelGSOut->endReset();
|
||||
|
||||
@@ -233,7 +233,7 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx,
|
||||
RDHeaderView *header = new RDHeaderView(Qt::Horizontal, this);
|
||||
cbuffer->setHeader(header);
|
||||
|
||||
cbuffer->setColumns({tr("Slot"), tr("Buffer"), tr("Byte Range"), tr("Size"), tr("Go")});
|
||||
cbuffer->setColumns({tr("Slot"), tr("Buffer"), tr("Vec4 Range"), tr("Size"), tr("Go")});
|
||||
header->setColumnStretchHints({1, 2, 3, 3, -1});
|
||||
|
||||
cbuffer->setHoverIconColumn(4, action, action_hover);
|
||||
@@ -580,7 +580,7 @@ void D3D11PipelineStateViewer::setViewDetails(RDTreeWidgetItem *node, const D3D1
|
||||
|
||||
void D3D11PipelineStateViewer::addResourceRow(const D3D11ViewTag &view,
|
||||
const ShaderResource *shaderInput,
|
||||
RDTreeWidget *resources)
|
||||
const BindpointMap *map, RDTreeWidget *resources)
|
||||
{
|
||||
const D3D11Pipe::View &r = view.res;
|
||||
|
||||
@@ -591,7 +591,7 @@ void D3D11PipelineStateViewer::addResourceRow(const D3D11ViewTag &view,
|
||||
m_Ctx.CurD3D11PipelineState().m_OM.StencilReadOnly;
|
||||
|
||||
bool filledSlot = (r.Resource != ResourceId());
|
||||
bool usedSlot = (shaderInput);
|
||||
bool usedSlot = (map && map->used);
|
||||
|
||||
// if a target is set to RTVs or DSV, it is implicitly used
|
||||
if(filledSlot)
|
||||
@@ -845,6 +845,7 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL
|
||||
RDTreeWidget *cbuffers, RDTreeWidget *classes)
|
||||
{
|
||||
ShaderReflection *shaderDetails = stage.ShaderDetails;
|
||||
const ShaderBindpointMapping &mapping = stage.BindpointMapping;
|
||||
|
||||
if(stage.Object == ResourceId())
|
||||
shader->setText(tr("Unbound Shader"));
|
||||
@@ -866,20 +867,25 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL
|
||||
for(int i = 0; i < stage.SRVs.count; i++)
|
||||
{
|
||||
const ShaderResource *shaderInput = NULL;
|
||||
const BindpointMap *map = NULL;
|
||||
|
||||
if(shaderDetails)
|
||||
{
|
||||
for(const ShaderResource &bind : shaderDetails->ReadOnlyResources)
|
||||
for(int b = 0; b < shaderDetails->ReadOnlyResources.count; b++)
|
||||
{
|
||||
if(!bind.IsSampler && bind.IsReadOnly && bind.bindPoint == i)
|
||||
const ShaderResource &res = shaderDetails->ReadOnlyResources[b];
|
||||
const BindpointMap &bind = mapping.ReadOnlyResources[b];
|
||||
|
||||
if(!res.IsSampler && res.IsReadOnly && bind.bind == i)
|
||||
{
|
||||
shaderInput = &bind;
|
||||
shaderInput = &res;
|
||||
map = &bind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::SRV, i, stage.SRVs[i]), shaderInput, resources);
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::SRV, i, stage.SRVs[i]), shaderInput, map, resources);
|
||||
}
|
||||
resources->clearSelection();
|
||||
resources->endUpdate();
|
||||
@@ -893,21 +899,26 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL
|
||||
const D3D11Pipe::Sampler &s = stage.Samplers[i];
|
||||
|
||||
const ShaderResource *shaderInput = NULL;
|
||||
const BindpointMap *map = NULL;
|
||||
|
||||
if(shaderDetails)
|
||||
{
|
||||
for(const ShaderResource &bind : shaderDetails->ReadOnlyResources)
|
||||
for(int b = 0; b < shaderDetails->ReadOnlyResources.count; b++)
|
||||
{
|
||||
if(bind.IsSampler && bind.bindPoint == i)
|
||||
const ShaderResource &res = shaderDetails->ReadOnlyResources[b];
|
||||
const BindpointMap &bind = mapping.ReadOnlyResources[b];
|
||||
|
||||
if(res.IsSampler && bind.bind == i)
|
||||
{
|
||||
shaderInput = &bind;
|
||||
shaderInput = &res;
|
||||
map = &bind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool filledSlot = s.Samp != ResourceId();
|
||||
bool usedSlot = (shaderInput);
|
||||
bool usedSlot = (map && map->used);
|
||||
|
||||
if(showNode(usedSlot, filledSlot))
|
||||
{
|
||||
@@ -995,26 +1006,26 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL
|
||||
const D3D11Pipe::CBuffer &b = stage.ConstantBuffers[i];
|
||||
|
||||
const ConstantBlock *shaderCBuf = NULL;
|
||||
|
||||
int cbufIdx = -1;
|
||||
const BindpointMap *map = NULL;
|
||||
|
||||
if(shaderDetails)
|
||||
{
|
||||
for(int cb = 0; cb < shaderDetails->ConstantBlocks.count; cb++)
|
||||
{
|
||||
const ConstantBlock &bind = shaderDetails->ConstantBlocks[cb];
|
||||
const ConstantBlock &cbuf = shaderDetails->ConstantBlocks[cb];
|
||||
const BindpointMap &bind = mapping.ConstantBlocks[cb];
|
||||
|
||||
if(bind.bindPoint == i)
|
||||
if(bind.bind == i)
|
||||
{
|
||||
shaderCBuf = &bind;
|
||||
cbufIdx = cb;
|
||||
shaderCBuf = &cbuf;
|
||||
map = &bind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool filledSlot = b.Buffer != ResourceId();
|
||||
bool usedSlot = shaderCBuf;
|
||||
bool usedSlot = (map && map->used);
|
||||
|
||||
if(showNode(usedSlot, filledSlot))
|
||||
{
|
||||
@@ -1056,7 +1067,7 @@ void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, QL
|
||||
|
||||
RDTreeWidgetItem *node = new RDTreeWidgetItem({slotname, name, vecrange, sizestr, QString()});
|
||||
|
||||
node->setTag(QVariant::fromValue(cbufIdx));
|
||||
node->setTag(QVariant::fromValue(i));
|
||||
|
||||
if(!filledSlot)
|
||||
setEmptyRow(node);
|
||||
@@ -1409,20 +1420,28 @@ void D3D11PipelineStateViewer::setState()
|
||||
for(int i = 0; i < state.m_CS.UAVs.count; i++)
|
||||
{
|
||||
const ShaderResource *shaderInput = NULL;
|
||||
const BindpointMap *map = NULL;
|
||||
|
||||
if(state.m_CS.ShaderDetails)
|
||||
const D3D11Pipe::Shader &cs = state.m_CS;
|
||||
|
||||
if(cs.ShaderDetails)
|
||||
{
|
||||
for(const ShaderResource &bind : state.m_CS.ShaderDetails->ReadWriteResources)
|
||||
for(int b = 0; b < cs.ShaderDetails->ReadWriteResources.count; b++)
|
||||
{
|
||||
if(bind.bindPoint == i)
|
||||
const ShaderResource &res = cs.ShaderDetails->ReadWriteResources[b];
|
||||
const BindpointMap &bind = cs.BindpointMapping.ReadWriteResources[b];
|
||||
|
||||
if(bind.bind == i)
|
||||
{
|
||||
shaderInput = &bind;
|
||||
shaderInput = &res;
|
||||
map = &bind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::UAV, i, state.m_CS.UAVs[i]), shaderInput, ui->csUAVs);
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::UAV, i, state.m_CS.UAVs[i]), shaderInput, map,
|
||||
ui->csUAVs);
|
||||
}
|
||||
ui->csUAVs->clearSelection();
|
||||
ui->csUAVs->endUpdate();
|
||||
@@ -1558,7 +1577,7 @@ void D3D11PipelineStateViewer::setState()
|
||||
for(int i = 0; i < state.m_OM.RenderTargets.count; i++)
|
||||
{
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::OMTarget, i, state.m_OM.RenderTargets[i]), NULL,
|
||||
ui->targetOutputs);
|
||||
NULL, ui->targetOutputs);
|
||||
|
||||
if(state.m_OM.RenderTargets[i].Resource != ResourceId())
|
||||
targets[i] = true;
|
||||
@@ -1567,6 +1586,7 @@ void D3D11PipelineStateViewer::setState()
|
||||
for(int i = 0; i < state.m_OM.UAVs.count; i++)
|
||||
{
|
||||
const ShaderResource *shaderInput = NULL;
|
||||
const BindpointMap *map = NULL;
|
||||
|
||||
// any non-CS shader can use these. When that's not supported (Before feature level 11.1)
|
||||
// this search will just boil down to only PS.
|
||||
@@ -1578,22 +1598,25 @@ void D3D11PipelineStateViewer::setState()
|
||||
{
|
||||
if(stage->ShaderDetails)
|
||||
{
|
||||
for(const ShaderResource &bind : stage->ShaderDetails->ReadWriteResources)
|
||||
for(int b = 0; b < stage->ShaderDetails->ReadOnlyResources.count; b++)
|
||||
{
|
||||
if(bind.bindPoint == i + (int)state.m_OM.UAVStartSlot)
|
||||
const ShaderResource &res = stage->ShaderDetails->ReadOnlyResources[b];
|
||||
const BindpointMap &bind = stage->BindpointMapping.ReadOnlyResources[b];
|
||||
|
||||
if(bind.bind == i + (int)state.m_OM.UAVStartSlot)
|
||||
{
|
||||
shaderInput = &bind;
|
||||
shaderInput = &res;
|
||||
map = &bind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::UAV, i, state.m_OM.UAVs[i]), shaderInput,
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::UAV, i, state.m_OM.UAVs[i]), shaderInput, map,
|
||||
ui->targetOutputs);
|
||||
}
|
||||
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::OMDepth, 0, state.m_OM.DepthTarget), NULL,
|
||||
addResourceRow(D3D11ViewTag(D3D11ViewTag::OMDepth, 0, state.m_OM.DepthTarget), NULL, NULL,
|
||||
ui->targetOutputs);
|
||||
}
|
||||
ui->targetOutputs->clearSelection();
|
||||
@@ -2031,7 +2054,33 @@ void D3D11PipelineStateViewer::cbuffer_itemActivated(RDTreeWidgetItem *item, int
|
||||
|
||||
int cb = tag.value<int>();
|
||||
|
||||
IConstantBufferPreviewer *prev = m_Ctx.ViewConstantBuffer(stage->stage, cb, 0);
|
||||
int cbufIdx = -1;
|
||||
|
||||
for(int i = 0; i < stage->BindpointMapping.ConstantBlocks.count; i++)
|
||||
{
|
||||
if(stage->BindpointMapping.ConstantBlocks[i].bind == cb)
|
||||
{
|
||||
cbufIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(cbufIdx == -1)
|
||||
{
|
||||
// unused cbuffer, open regular buffer viewer
|
||||
if(cb >= stage->ConstantBuffers.count)
|
||||
return;
|
||||
|
||||
const D3D11Pipe::CBuffer &bind = stage->ConstantBuffers[cb];
|
||||
|
||||
IBufferViewer *viewer = m_Ctx.ViewBuffer(bind.VecOffset * sizeof(float) * 4,
|
||||
bind.VecCount * sizeof(float) * 4, bind.Buffer);
|
||||
|
||||
m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this);
|
||||
return;
|
||||
}
|
||||
|
||||
IConstantBufferPreviewer *prev = m_Ctx.ViewConstantBuffer(stage->stage, cbufIdx, 0);
|
||||
|
||||
m_Ctx.AddDockWindow(prev->Widget(), DockReference::ConstantBufferArea, this, 0.3f);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
RDTreeWidget *samp, RDTreeWidget *cbuffer, RDTreeWidget *classes);
|
||||
|
||||
void addResourceRow(const D3D11ViewTag &view, const ShaderResource *shaderInput,
|
||||
RDTreeWidget *resources);
|
||||
const BindpointMap *map, RDTreeWidget *resources);
|
||||
|
||||
void clearShaderState(QLabel *shader, RDTreeWidget *tex, RDTreeWidget *samp,
|
||||
RDTreeWidget *cbuffer, RDTreeWidget *classes);
|
||||
|
||||
@@ -719,319 +719,6 @@ StencilOp MakeStencilOp(D3D11_STENCIL_OP op)
|
||||
return StencilOp::Keep;
|
||||
}
|
||||
|
||||
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var, uint32_t &offset);
|
||||
|
||||
static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type, uint32_t &offset)
|
||||
{
|
||||
ShaderVariableType ret;
|
||||
|
||||
switch(type.descriptor.type)
|
||||
{
|
||||
case DXBC::VARTYPE_MIN12INT:
|
||||
case DXBC::VARTYPE_MIN16INT:
|
||||
case DXBC::VARTYPE_INT: ret.descriptor.type = VarType::Int; break;
|
||||
case DXBC::VARTYPE_BOOL:
|
||||
case DXBC::VARTYPE_MIN16UINT:
|
||||
case DXBC::VARTYPE_UINT: ret.descriptor.type = VarType::UInt; break;
|
||||
case DXBC::VARTYPE_DOUBLE: ret.descriptor.type = VarType::Double; break;
|
||||
case DXBC::VARTYPE_FLOAT:
|
||||
case DXBC::VARTYPE_MIN8FLOAT:
|
||||
case DXBC::VARTYPE_MIN10FLOAT:
|
||||
case DXBC::VARTYPE_MIN16FLOAT:
|
||||
default: ret.descriptor.type = VarType::Float; break;
|
||||
}
|
||||
ret.descriptor.rows = (uint8_t)type.descriptor.rows;
|
||||
ret.descriptor.cols = (uint8_t)type.descriptor.cols;
|
||||
ret.descriptor.elements = type.descriptor.elements;
|
||||
ret.descriptor.name = type.descriptor.name;
|
||||
ret.descriptor.rowMajorStorage = (type.descriptor.varClass == DXBC::CLASS_MATRIX_ROWS);
|
||||
|
||||
uint32_t baseElemSize = (ret.descriptor.type == VarType::Double) ? 8 : 4;
|
||||
if(ret.descriptor.rowMajorStorage)
|
||||
{
|
||||
uint32_t primary = ret.descriptor.rows;
|
||||
if(primary == 3)
|
||||
primary = 4;
|
||||
ret.descriptor.arrayStride = baseElemSize * primary * ret.descriptor.cols;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t primary = ret.descriptor.cols;
|
||||
if(primary == 3)
|
||||
primary = 4;
|
||||
ret.descriptor.arrayStride = baseElemSize * primary * ret.descriptor.rows;
|
||||
}
|
||||
|
||||
uint32_t o = offset;
|
||||
|
||||
create_array_uninit(ret.members, type.members.size());
|
||||
for(size_t i = 0; i < type.members.size(); i++)
|
||||
{
|
||||
offset = o;
|
||||
ret.members[i] = MakeConstantBufferVariable(type.members[i], offset);
|
||||
}
|
||||
|
||||
if(ret.members.count > 0)
|
||||
{
|
||||
ret.descriptor.rows = 0;
|
||||
ret.descriptor.cols = 0;
|
||||
ret.descriptor.elements = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var, uint32_t &offset)
|
||||
{
|
||||
ShaderConstant ret;
|
||||
|
||||
ret.name = var.name;
|
||||
ret.reg.vec = offset + var.descriptor.offset / 16;
|
||||
ret.reg.comp = (var.descriptor.offset - (var.descriptor.offset & ~0xf)) / 4;
|
||||
ret.defaultValue = 0;
|
||||
|
||||
offset = ret.reg.vec;
|
||||
|
||||
ret.type = MakeShaderVariableType(var.type, offset);
|
||||
|
||||
offset = ret.reg.vec + RDCMAX(1U, var.type.descriptor.bytesize / 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ShaderReflection *MakeShaderReflection(DXBC::DXBCFile *dxbc)
|
||||
{
|
||||
if(dxbc == NULL || !RenderDoc::Inst().IsReplayApp())
|
||||
return NULL;
|
||||
|
||||
ShaderReflection *ret = new ShaderReflection();
|
||||
|
||||
if(dxbc->m_DebugInfo)
|
||||
{
|
||||
ret->DebugInfo.compileFlags = DXBC::EncodeFlags(dxbc->m_DebugInfo);
|
||||
|
||||
create_array_uninit(ret->DebugInfo.files, dxbc->m_DebugInfo->Files.size());
|
||||
for(size_t i = 0; i < dxbc->m_DebugInfo->Files.size(); i++)
|
||||
{
|
||||
ret->DebugInfo.files[i].first = dxbc->m_DebugInfo->Files[i].first;
|
||||
ret->DebugInfo.files[i].second = dxbc->m_DebugInfo->Files[i].second;
|
||||
}
|
||||
|
||||
string entry = dxbc->m_DebugInfo->GetEntryFunction();
|
||||
if(entry.empty())
|
||||
entry = "main";
|
||||
|
||||
// sort the file with the entry point to the start. We don't have to do anything if there's only
|
||||
// one file.
|
||||
// This isn't a perfect search - it will match entry_point() anywhere in the file, even if it's
|
||||
// in a comment or disabled preprocessor definition. This is just best-effort
|
||||
if(ret->DebugInfo.files.count > 1)
|
||||
{
|
||||
// search from 0 up. If we find a match, we swap it into [0]. If we don't find a match then
|
||||
// we can't rearrange anything. This is a no-op for 0 since it's already in first place, but
|
||||
// since our search isn't perfect we might have multiple matches with some being false
|
||||
// positives, and so we want to bias towards leaving [0] in place.
|
||||
for(int32_t i = 0; i < ret->DebugInfo.files.count; i++)
|
||||
{
|
||||
char *c = strstr(ret->DebugInfo.files[i].first.elems, entry.c_str());
|
||||
char *end = ret->DebugInfo.files[i].first.elems + ret->DebugInfo.files[i].first.count;
|
||||
|
||||
// no substring match? continue
|
||||
if(c == NULL)
|
||||
continue;
|
||||
|
||||
// if we did get a substring match, ensure there's whitespace preceeding it.
|
||||
if(c == entry.c_str() || !isspace((int)*(c - 1)))
|
||||
continue;
|
||||
|
||||
// skip past the entry point. Then skip any whitespace
|
||||
c += entry.size();
|
||||
|
||||
// check for EOF.
|
||||
if(c >= end)
|
||||
continue;
|
||||
|
||||
while(c < end && isspace(*c))
|
||||
c++;
|
||||
|
||||
if(c >= end)
|
||||
continue;
|
||||
|
||||
// if there's an open bracket next, we found a entry_point( which we count as the
|
||||
// declaration.
|
||||
if(*c == '(')
|
||||
{
|
||||
// only do anything if we're looking at a later file
|
||||
if(i > 0)
|
||||
std::swap(ret->DebugInfo.files[0], ret->DebugInfo.files[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dxbc->m_ShaderBlob.empty())
|
||||
create_array_uninit(ret->RawBytes, 0);
|
||||
else
|
||||
create_array_init(ret->RawBytes, dxbc->m_ShaderBlob.size(), &dxbc->m_ShaderBlob[0]);
|
||||
|
||||
ret->DispatchThreadsDimension[0] = dxbc->DispatchThreadsDimension[0];
|
||||
ret->DispatchThreadsDimension[1] = dxbc->DispatchThreadsDimension[1];
|
||||
ret->DispatchThreadsDimension[2] = dxbc->DispatchThreadsDimension[2];
|
||||
|
||||
ret->InputSig = dxbc->m_InputSig;
|
||||
ret->OutputSig = dxbc->m_OutputSig;
|
||||
|
||||
create_array_uninit(ret->ConstantBlocks, dxbc->m_CBuffers.size());
|
||||
for(size_t i = 0; i < dxbc->m_CBuffers.size(); i++)
|
||||
{
|
||||
ConstantBlock &cb = ret->ConstantBlocks[i];
|
||||
cb.name = dxbc->m_CBuffers[i].name;
|
||||
cb.bufferBacked = dxbc->m_CBuffers[i].descriptor.type == DXBC::CBuffer::Descriptor::TYPE_CBUFFER;
|
||||
cb.byteSize = dxbc->m_CBuffers[i].descriptor.byteSize;
|
||||
cb.bindPoint = dxbc->m_CBuffers[i].reg;
|
||||
|
||||
create_array_uninit(cb.variables, dxbc->m_CBuffers[i].variables.size());
|
||||
for(size_t v = 0; v < dxbc->m_CBuffers[i].variables.size(); v++)
|
||||
{
|
||||
uint32_t vecOffset = 0;
|
||||
cb.variables[v] = MakeConstantBufferVariable(dxbc->m_CBuffers[i].variables[v], vecOffset);
|
||||
}
|
||||
}
|
||||
|
||||
int numRWResources = 0;
|
||||
int numROResources = 0;
|
||||
|
||||
for(size_t i = 0; i < dxbc->m_Resources.size(); i++)
|
||||
{
|
||||
const auto &r = dxbc->m_Resources[i];
|
||||
|
||||
if(r.type != DXBC::ShaderInputBind::TYPE_CBUFFER)
|
||||
{
|
||||
bool IsReadOnly = (r.type == DXBC::ShaderInputBind::TYPE_TBUFFER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_TEXTURE ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_SAMPLER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS);
|
||||
|
||||
if(IsReadOnly)
|
||||
numROResources++;
|
||||
else
|
||||
numRWResources++;
|
||||
}
|
||||
}
|
||||
|
||||
create_array_uninit(ret->ReadWriteResources, numRWResources);
|
||||
create_array_uninit(ret->ReadOnlyResources, numROResources);
|
||||
|
||||
int32_t rwidx = 0, roidx = 0;
|
||||
for(size_t i = 0; i < dxbc->m_Resources.size(); i++)
|
||||
{
|
||||
const auto &r = dxbc->m_Resources[i];
|
||||
|
||||
if(r.type == DXBC::ShaderInputBind::TYPE_CBUFFER)
|
||||
continue;
|
||||
|
||||
ShaderResource res;
|
||||
res.bindPoint = r.reg;
|
||||
res.name = r.name;
|
||||
|
||||
res.IsSampler = (r.type == DXBC::ShaderInputBind::TYPE_SAMPLER);
|
||||
res.IsTexture = (r.type == DXBC::ShaderInputBind::TYPE_TEXTURE &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_UNKNOWN &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_BUFFER &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_BUFFEREX);
|
||||
res.IsReadOnly = (r.type == DXBC::ShaderInputBind::TYPE_TBUFFER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_TEXTURE ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_SAMPLER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS);
|
||||
|
||||
switch(r.dimension)
|
||||
{
|
||||
default:
|
||||
case DXBC::ShaderInputBind::DIM_UNKNOWN: res.resType = TextureDim::Unknown; break;
|
||||
case DXBC::ShaderInputBind::DIM_BUFFER:
|
||||
case DXBC::ShaderInputBind::DIM_BUFFEREX: res.resType = TextureDim::Buffer; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE1D: res.resType = TextureDim::Texture1D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE1DARRAY:
|
||||
res.resType = TextureDim::Texture1DArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2D: res.resType = TextureDim::Texture2D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DARRAY:
|
||||
res.resType = TextureDim::Texture2DArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DMS: res.resType = TextureDim::Texture2DMS; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DMSARRAY:
|
||||
res.resType = TextureDim::Texture2DMSArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE3D: res.resType = TextureDim::Texture3D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURECUBE: res.resType = TextureDim::TextureCube; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURECUBEARRAY:
|
||||
res.resType = TextureDim::TextureCubeArray;
|
||||
break;
|
||||
}
|
||||
|
||||
if(r.retType != DXBC::ShaderInputBind::RETTYPE_UNKNOWN &&
|
||||
r.retType != DXBC::ShaderInputBind::RETTYPE_MIXED &&
|
||||
r.retType != DXBC::ShaderInputBind::RETTYPE_CONTINUED)
|
||||
{
|
||||
res.variableType.descriptor.rows = 1;
|
||||
res.variableType.descriptor.cols = (uint8_t)r.numSamples;
|
||||
res.variableType.descriptor.elements = 1;
|
||||
|
||||
string name;
|
||||
|
||||
switch(r.retType)
|
||||
{
|
||||
case DXBC::ShaderInputBind::RETTYPE_UNORM: name = "unorm float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_SNORM: name = "snorm float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_SINT: name = "int"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_UINT: name = "uint"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_FLOAT: name = "float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_DOUBLE: name = "double"; break;
|
||||
default: name = "unknown"; break;
|
||||
}
|
||||
|
||||
name += ToStr::Get(r.numSamples);
|
||||
|
||||
res.variableType.descriptor.name = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dxbc->m_ResourceBinds.find(r.name) != dxbc->m_ResourceBinds.end())
|
||||
{
|
||||
uint32_t vecOffset = 0;
|
||||
res.variableType = MakeShaderVariableType(dxbc->m_ResourceBinds[r.name], vecOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.variableType.descriptor.rows = 0;
|
||||
res.variableType.descriptor.cols = 0;
|
||||
res.variableType.descriptor.elements = 0;
|
||||
res.variableType.descriptor.name = "";
|
||||
}
|
||||
}
|
||||
|
||||
if(res.IsReadOnly)
|
||||
ret->ReadOnlyResources[roidx++] = res;
|
||||
else
|
||||
ret->ReadWriteResources[rwidx++] = res;
|
||||
}
|
||||
|
||||
uint32_t numInterfaces = 0;
|
||||
for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++)
|
||||
numInterfaces = RDCMAX(dxbc->m_Interfaces.variables[i].descriptor.offset + 1, numInterfaces);
|
||||
|
||||
create_array(ret->Interfaces, numInterfaces);
|
||||
for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++)
|
||||
ret->Interfaces[dxbc->m_Interfaces.variables[i].descriptor.offset] =
|
||||
dxbc->m_Interfaces.variables[i].name;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Structures/descriptors. Serialise members separately
|
||||
// instead of ToStrInternal separately. Mostly for convenience of
|
||||
|
||||
@@ -162,8 +162,6 @@ BlendMultiplier MakeBlendMultiplier(D3D11_BLEND blend, bool alpha);
|
||||
BlendOp MakeBlendOp(D3D11_BLEND_OP op);
|
||||
StencilOp MakeStencilOp(D3D11_STENCIL_OP op);
|
||||
|
||||
ShaderReflection *MakeShaderReflection(DXBC::DXBCFile *dxbc);
|
||||
|
||||
template <class T>
|
||||
inline void SetDebugName(T *pObj, const char *name)
|
||||
{
|
||||
|
||||
@@ -310,10 +310,9 @@ ShaderReflection *D3D11Replay::GetShader(ResourceId shader, string entryPoint)
|
||||
if(it == WrappedShader::m_ShaderList.end())
|
||||
return NULL;
|
||||
|
||||
ShaderReflection *ret = it->second->GetDetails();
|
||||
RDCASSERT(ret);
|
||||
ShaderReflection &ret = it->second->GetDetails();
|
||||
|
||||
return ret;
|
||||
return &ret;
|
||||
}
|
||||
|
||||
vector<string> D3D11Replay::GetDisassemblyTargets()
|
||||
@@ -581,7 +580,10 @@ void D3D11Replay::SavePipelineState()
|
||||
ShaderReflection *refl = NULL;
|
||||
|
||||
if(shad != NULL)
|
||||
refl = shad->GetDetails();
|
||||
{
|
||||
refl = &shad->GetDetails();
|
||||
dst.BindpointMapping = shad->GetMapping();
|
||||
}
|
||||
|
||||
dst.Object = rm->GetOriginalID(id);
|
||||
dst.ShaderDetails = refl;
|
||||
@@ -597,61 +599,6 @@ void D3D11Replay::SavePipelineState()
|
||||
|
||||
dst.name = str;
|
||||
|
||||
// create identity bindpoint mapping
|
||||
create_array_uninit(dst.BindpointMapping.InputAttributes,
|
||||
D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT);
|
||||
for(int s = 0; s < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; s++)
|
||||
{
|
||||
// TODO: this should do any semantic rematching as defined by the bytecode
|
||||
// the input layout was built with (not necessarily the vertex shader's bytecode -
|
||||
// in the case of a mismatch). It's commonly, but not always the identity mapping
|
||||
dst.BindpointMapping.InputAttributes[s] = s;
|
||||
}
|
||||
|
||||
create_array_uninit(dst.BindpointMapping.ConstantBlocks,
|
||||
D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT);
|
||||
for(int s = 0; s < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; s++)
|
||||
{
|
||||
dst.BindpointMapping.ConstantBlocks[s].bindset = 0;
|
||||
dst.BindpointMapping.ConstantBlocks[s].bind = s;
|
||||
dst.BindpointMapping.ConstantBlocks[s].used = false;
|
||||
dst.BindpointMapping.ConstantBlocks[s].arraySize = 1;
|
||||
}
|
||||
|
||||
create_array_uninit(dst.BindpointMapping.ReadOnlyResources,
|
||||
D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT);
|
||||
for(int32_t s = 0; s < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; s++)
|
||||
{
|
||||
dst.BindpointMapping.ReadOnlyResources[s].bindset = 0;
|
||||
dst.BindpointMapping.ReadOnlyResources[s].bind = s;
|
||||
dst.BindpointMapping.ReadOnlyResources[s].used = false;
|
||||
dst.BindpointMapping.ReadOnlyResources[s].arraySize = 1;
|
||||
}
|
||||
|
||||
create_array_uninit(dst.BindpointMapping.ReadWriteResources, D3D11_1_UAV_SLOT_COUNT);
|
||||
for(int32_t s = 0; s < D3D11_1_UAV_SLOT_COUNT; s++)
|
||||
{
|
||||
dst.BindpointMapping.ReadWriteResources[s].bindset = 0;
|
||||
dst.BindpointMapping.ReadWriteResources[s].bind = s;
|
||||
dst.BindpointMapping.ReadWriteResources[s].used = false;
|
||||
dst.BindpointMapping.ReadWriteResources[s].arraySize = 1;
|
||||
}
|
||||
|
||||
// mark resources as used if they are referenced by the shader
|
||||
if(refl)
|
||||
{
|
||||
for(int32_t i = 0; i < refl->ConstantBlocks.count; i++)
|
||||
if(refl->ConstantBlocks[i].bufferBacked)
|
||||
dst.BindpointMapping.ConstantBlocks[refl->ConstantBlocks[i].bindPoint].used = true;
|
||||
|
||||
for(int32_t i = 0; i < refl->ReadOnlyResources.count; i++)
|
||||
if(!refl->ReadOnlyResources[i].IsSampler)
|
||||
dst.BindpointMapping.ReadOnlyResources[refl->ReadOnlyResources[i].bindPoint].used = true;
|
||||
|
||||
for(int32_t i = 0; i < refl->ReadWriteResources.count; i++)
|
||||
dst.BindpointMapping.ReadWriteResources[refl->ReadWriteResources[i].bindPoint].used = true;
|
||||
}
|
||||
|
||||
create_array_uninit(dst.ConstantBuffers, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT);
|
||||
for(size_t s = 0; s < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; s++)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "driver/d3d11/d3d11_context.h"
|
||||
#include "driver/d3d11/d3d11_renderstate.h"
|
||||
#include "driver/dxgi/dxgi_wrapped.h"
|
||||
#include "driver/shaders/dxbc/dxbc_reflect.h"
|
||||
|
||||
WRAPPED_POOL_INST(WrappedID3D11Buffer);
|
||||
WRAPPED_POOL_INST(WrappedID3D11Texture1D);
|
||||
@@ -176,6 +177,19 @@ void WrappedShader::ShaderEntry::TryReplaceOriginalByteCode()
|
||||
}
|
||||
}
|
||||
|
||||
void WrappedShader::ShaderEntry::BuildReflection()
|
||||
{
|
||||
RDCCOMPILE_ASSERT(
|
||||
D3Dx_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT == D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT,
|
||||
"Mismatched vertex input count");
|
||||
|
||||
MakeShaderReflection(m_DXBCFile, &m_Details, &m_Mapping);
|
||||
m_Details.ID = m_ID;
|
||||
m_Details.EntryPoint = m_DXBCFile->m_DebugInfo ? m_DXBCFile->m_DebugInfo->GetEntryFunction() : "";
|
||||
if(m_Details.EntryPoint.empty())
|
||||
m_Details.EntryPoint = "main";
|
||||
}
|
||||
|
||||
UINT GetMipForSubresource(ID3D11Resource *res, int Subresource)
|
||||
{
|
||||
D3D11_RESOURCE_DIMENSION dim;
|
||||
|
||||
@@ -903,20 +903,18 @@ public:
|
||||
class ShaderEntry
|
||||
{
|
||||
public:
|
||||
ShaderEntry() : m_DebugInfoSearchPaths(NULL), m_DXBCFile(NULL), m_Details(NULL) {}
|
||||
ShaderEntry() : m_DebugInfoSearchPaths(NULL), m_DXBCFile(NULL) {}
|
||||
ShaderEntry(WrappedID3D11Device *device, ResourceId id, const byte *code, size_t codeLen)
|
||||
{
|
||||
m_ID = id;
|
||||
m_Bytecode.assign(code, code + codeLen);
|
||||
m_DebugInfoSearchPaths = device->GetShaderDebugInfoSearchPaths();
|
||||
m_DXBCFile = NULL;
|
||||
m_Details = NULL;
|
||||
}
|
||||
~ShaderEntry()
|
||||
{
|
||||
m_Bytecode.clear();
|
||||
SAFE_DELETE(m_DXBCFile);
|
||||
SAFE_DELETE(m_Details);
|
||||
}
|
||||
|
||||
void SetDebugInfoPath(const std::string &path) { m_DebugInfoPath = path; }
|
||||
@@ -929,25 +927,30 @@ public:
|
||||
}
|
||||
return m_DXBCFile;
|
||||
}
|
||||
ShaderReflection *GetDetails()
|
||||
|
||||
ShaderReflection &GetDetails()
|
||||
{
|
||||
if(m_Details == NULL && GetDXBC() != NULL)
|
||||
{
|
||||
m_Details = MakeShaderReflection(m_DXBCFile);
|
||||
m_Details->ID = m_ID;
|
||||
m_Details->EntryPoint =
|
||||
m_DXBCFile->m_DebugInfo ? m_DXBCFile->m_DebugInfo->GetEntryFunction() : "";
|
||||
if(m_Details->EntryPoint.empty())
|
||||
m_Details->EntryPoint = "main";
|
||||
}
|
||||
if(!m_Built && GetDXBC() != NULL)
|
||||
BuildReflection();
|
||||
m_Built = true;
|
||||
return m_Details;
|
||||
}
|
||||
|
||||
const ShaderBindpointMapping &GetMapping()
|
||||
{
|
||||
if(!m_Built && GetDXBC() != NULL)
|
||||
BuildReflection();
|
||||
m_Built = true;
|
||||
return m_Mapping;
|
||||
}
|
||||
|
||||
private:
|
||||
ShaderEntry(const ShaderEntry &e);
|
||||
void TryReplaceOriginalByteCode();
|
||||
ShaderEntry &operator=(const ShaderEntry &e);
|
||||
|
||||
void BuildReflection();
|
||||
|
||||
ResourceId m_ID;
|
||||
|
||||
std::string m_DebugInfoPath;
|
||||
@@ -955,8 +958,10 @@ public:
|
||||
|
||||
vector<byte> m_Bytecode;
|
||||
|
||||
bool m_Built = false;
|
||||
DXBC::DXBCFile *m_DXBCFile;
|
||||
ShaderReflection *m_Details;
|
||||
ShaderReflection m_Details;
|
||||
ShaderBindpointMapping m_Mapping;
|
||||
};
|
||||
|
||||
static map<ResourceId, ShaderEntry *> m_ShaderList;
|
||||
@@ -989,11 +994,16 @@ public:
|
||||
SCOPED_LOCK(m_ShaderListLock);
|
||||
return m_ShaderList[m_ID]->GetDXBC();
|
||||
}
|
||||
ShaderReflection *GetDetails()
|
||||
ShaderReflection &GetDetails()
|
||||
{
|
||||
SCOPED_LOCK(m_ShaderListLock);
|
||||
return m_ShaderList[m_ID]->GetDetails();
|
||||
}
|
||||
const ShaderBindpointMapping &GetMapping()
|
||||
{
|
||||
SCOPED_LOCK(m_ShaderListLock);
|
||||
return m_ShaderList[m_ID]->GetMapping();
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceId m_ID;
|
||||
|
||||
@@ -363,359 +363,6 @@ StencilOp MakeStencilOp(D3D12_STENCIL_OP op)
|
||||
return StencilOp::Keep;
|
||||
}
|
||||
|
||||
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var, uint32_t &offset);
|
||||
|
||||
static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type, uint32_t &offset)
|
||||
{
|
||||
ShaderVariableType ret;
|
||||
|
||||
switch(type.descriptor.type)
|
||||
{
|
||||
case DXBC::VARTYPE_MIN12INT:
|
||||
case DXBC::VARTYPE_MIN16INT:
|
||||
case DXBC::VARTYPE_INT: ret.descriptor.type = VarType::Int; break;
|
||||
case DXBC::VARTYPE_BOOL:
|
||||
case DXBC::VARTYPE_MIN16UINT:
|
||||
case DXBC::VARTYPE_UINT: ret.descriptor.type = VarType::UInt; break;
|
||||
case DXBC::VARTYPE_DOUBLE: ret.descriptor.type = VarType::Double; break;
|
||||
case DXBC::VARTYPE_FLOAT:
|
||||
case DXBC::VARTYPE_MIN8FLOAT:
|
||||
case DXBC::VARTYPE_MIN10FLOAT:
|
||||
case DXBC::VARTYPE_MIN16FLOAT:
|
||||
default: ret.descriptor.type = VarType::Float; break;
|
||||
}
|
||||
ret.descriptor.rows = (uint8_t)type.descriptor.rows;
|
||||
ret.descriptor.cols = (uint8_t)type.descriptor.cols;
|
||||
ret.descriptor.elements = type.descriptor.elements;
|
||||
ret.descriptor.name = type.descriptor.name;
|
||||
ret.descriptor.rowMajorStorage = (type.descriptor.varClass == DXBC::CLASS_MATRIX_ROWS);
|
||||
|
||||
uint32_t baseElemSize = (ret.descriptor.type == VarType::Double) ? 8 : 4;
|
||||
if(ret.descriptor.rowMajorStorage)
|
||||
{
|
||||
uint32_t primary = ret.descriptor.rows;
|
||||
if(primary == 3)
|
||||
primary = 4;
|
||||
ret.descriptor.arrayStride = baseElemSize * primary * ret.descriptor.cols;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t primary = ret.descriptor.cols;
|
||||
if(primary == 3)
|
||||
primary = 4;
|
||||
ret.descriptor.arrayStride = baseElemSize * primary * ret.descriptor.rows;
|
||||
}
|
||||
|
||||
uint32_t o = offset;
|
||||
|
||||
create_array_uninit(ret.members, type.members.size());
|
||||
for(size_t i = 0; i < type.members.size(); i++)
|
||||
{
|
||||
offset = o;
|
||||
ret.members[i] = MakeConstantBufferVariable(type.members[i], offset);
|
||||
}
|
||||
|
||||
if(ret.members.count > 0)
|
||||
{
|
||||
ret.descriptor.rows = 0;
|
||||
ret.descriptor.cols = 0;
|
||||
ret.descriptor.elements = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var, uint32_t &offset)
|
||||
{
|
||||
ShaderConstant ret;
|
||||
|
||||
ret.name = var.name;
|
||||
ret.reg.vec = offset + var.descriptor.offset / 16;
|
||||
ret.reg.comp = (var.descriptor.offset - (var.descriptor.offset & ~0xf)) / 4;
|
||||
ret.defaultValue = 0;
|
||||
|
||||
offset = ret.reg.vec;
|
||||
|
||||
ret.type = MakeShaderVariableType(var.type, offset);
|
||||
|
||||
offset = ret.reg.vec + RDCMAX(1U, var.type.descriptor.bytesize / 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl,
|
||||
ShaderBindpointMapping *mapping)
|
||||
{
|
||||
if(dxbc == NULL || !RenderDoc::Inst().IsReplayApp())
|
||||
return;
|
||||
|
||||
if(dxbc->m_DebugInfo)
|
||||
{
|
||||
refl->DebugInfo.compileFlags = DXBC::EncodeFlags(dxbc->m_DebugInfo);
|
||||
|
||||
create_array_uninit(refl->DebugInfo.files, dxbc->m_DebugInfo->Files.size());
|
||||
for(size_t i = 0; i < dxbc->m_DebugInfo->Files.size(); i++)
|
||||
{
|
||||
refl->DebugInfo.files[i].first = dxbc->m_DebugInfo->Files[i].first;
|
||||
refl->DebugInfo.files[i].second = dxbc->m_DebugInfo->Files[i].second;
|
||||
}
|
||||
|
||||
string entry = dxbc->m_DebugInfo->GetEntryFunction();
|
||||
if(entry.empty())
|
||||
entry = "main";
|
||||
|
||||
// sort the file with the entry point to the start. We don't have to do anything if there's only
|
||||
// one file.
|
||||
// This isn't a perfect search - it will match entry_point() anywhere in the file, even if it's
|
||||
// in a comment or disabled preprocessor definition. This is just best-effort
|
||||
if(refl->DebugInfo.files.count > 1)
|
||||
{
|
||||
// search from 0 up. If we find a match, we swap it into [0]. If we don't find a match then
|
||||
// we can't rearrange anything. This is a no-op for 0 since it's already in first place, but
|
||||
// since our search isn't perfect we might have multiple matches with some being false
|
||||
// positives, and so we want to bias towards leaving [0] in place.
|
||||
for(int32_t i = 0; i < refl->DebugInfo.files.count; i++)
|
||||
{
|
||||
char *c = strstr(refl->DebugInfo.files[i].first.elems, entry.c_str());
|
||||
char *end = refl->DebugInfo.files[i].first.elems + refl->DebugInfo.files[i].first.count;
|
||||
|
||||
// no substring match? continue
|
||||
if(c == NULL)
|
||||
continue;
|
||||
|
||||
// if we did get a substring match, ensure there's whitespace preceeding it.
|
||||
if(c == entry.c_str() || !isspace((int)*(c - 1)))
|
||||
continue;
|
||||
|
||||
// skip past the entry point. Then skip any whitespace
|
||||
c += entry.size();
|
||||
|
||||
// check for EOF.
|
||||
if(c >= end)
|
||||
continue;
|
||||
|
||||
while(c < end && isspace(*c))
|
||||
c++;
|
||||
|
||||
if(c >= end)
|
||||
continue;
|
||||
|
||||
// if there's an open bracket next, we found a entry_point( which we count as the
|
||||
// declaration.
|
||||
if(*c == '(')
|
||||
{
|
||||
// only do anything if we're looking at a later file
|
||||
if(i > 0)
|
||||
std::swap(refl->DebugInfo.files[0], refl->DebugInfo.files[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dxbc->m_ShaderBlob.empty())
|
||||
create_array_uninit(refl->RawBytes, 0);
|
||||
else
|
||||
create_array_init(refl->RawBytes, dxbc->m_ShaderBlob.size(), &dxbc->m_ShaderBlob[0]);
|
||||
|
||||
refl->DispatchThreadsDimension[0] = dxbc->DispatchThreadsDimension[0];
|
||||
refl->DispatchThreadsDimension[1] = dxbc->DispatchThreadsDimension[1];
|
||||
refl->DispatchThreadsDimension[2] = dxbc->DispatchThreadsDimension[2];
|
||||
|
||||
refl->InputSig = dxbc->m_InputSig;
|
||||
refl->OutputSig = dxbc->m_OutputSig;
|
||||
|
||||
create_array_uninit(mapping->InputAttributes, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT);
|
||||
for(int s = 0; s < D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; s++)
|
||||
mapping->InputAttributes[s] = s;
|
||||
|
||||
int numCbuffers = 0;
|
||||
|
||||
// skip 'empty' cbuffers added for the benefit of D3D11
|
||||
for(size_t i = 0; i < dxbc->m_CBuffers.size(); i++)
|
||||
{
|
||||
if(dxbc->m_CBuffers[i].descriptor.type == DXBC::CBuffer::Descriptor::TYPE_CBUFFER)
|
||||
numCbuffers++;
|
||||
}
|
||||
|
||||
create_array_uninit(mapping->ConstantBlocks, numCbuffers);
|
||||
create_array_uninit(refl->ConstantBlocks, numCbuffers);
|
||||
for(size_t i = 0; i < dxbc->m_CBuffers.size(); i++)
|
||||
{
|
||||
ConstantBlock &cb = refl->ConstantBlocks[i];
|
||||
|
||||
if(dxbc->m_CBuffers[i].descriptor.type != DXBC::CBuffer::Descriptor::TYPE_CBUFFER)
|
||||
continue;
|
||||
|
||||
cb.name = dxbc->m_CBuffers[i].name;
|
||||
cb.bufferBacked = true;
|
||||
cb.byteSize = dxbc->m_CBuffers[i].descriptor.byteSize;
|
||||
cb.bindPoint = (uint32_t)i;
|
||||
|
||||
BindpointMap map;
|
||||
map.arraySize = 1;
|
||||
map.bindset = dxbc->m_CBuffers[i].space;
|
||||
map.bind = dxbc->m_CBuffers[i].reg;
|
||||
map.used = true;
|
||||
|
||||
mapping->ConstantBlocks[i] = map;
|
||||
|
||||
create_array_uninit(cb.variables, dxbc->m_CBuffers[i].variables.size());
|
||||
for(size_t v = 0; v < dxbc->m_CBuffers[i].variables.size(); v++)
|
||||
{
|
||||
uint32_t vecOffset = 0;
|
||||
cb.variables[v] = MakeConstantBufferVariable(dxbc->m_CBuffers[i].variables[v], vecOffset);
|
||||
}
|
||||
}
|
||||
|
||||
int numRWResources = 0;
|
||||
int numROResources = 0;
|
||||
|
||||
for(size_t i = 0; i < dxbc->m_Resources.size(); i++)
|
||||
{
|
||||
const auto &r = dxbc->m_Resources[i];
|
||||
|
||||
if(r.type != DXBC::ShaderInputBind::TYPE_CBUFFER)
|
||||
{
|
||||
bool IsReadWrite = (r.type == DXBC::ShaderInputBind::TYPE_UAV_RWTYPED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWBYTEADDRESS ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_APPEND_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_CONSUME_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER);
|
||||
|
||||
if(IsReadWrite)
|
||||
numRWResources++;
|
||||
else
|
||||
numROResources++;
|
||||
}
|
||||
}
|
||||
|
||||
create_array_uninit(mapping->ReadWriteResources, numRWResources);
|
||||
create_array_uninit(refl->ReadWriteResources, numRWResources);
|
||||
|
||||
create_array_uninit(mapping->ReadOnlyResources, numROResources);
|
||||
create_array_uninit(refl->ReadOnlyResources, numROResources);
|
||||
|
||||
int32_t rwidx = 0, roidx = 0;
|
||||
for(size_t i = 0; i < dxbc->m_Resources.size(); i++)
|
||||
{
|
||||
const auto &r = dxbc->m_Resources[i];
|
||||
|
||||
if(r.type == DXBC::ShaderInputBind::TYPE_CBUFFER)
|
||||
continue;
|
||||
|
||||
ShaderResource res;
|
||||
res.name = r.name;
|
||||
|
||||
res.IsSampler = (r.type == DXBC::ShaderInputBind::TYPE_SAMPLER);
|
||||
res.IsTexture = (r.type == DXBC::ShaderInputBind::TYPE_TEXTURE &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_UNKNOWN &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_BUFFER &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_BUFFEREX);
|
||||
res.IsReadOnly = (r.type == DXBC::ShaderInputBind::TYPE_TBUFFER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_SAMPLER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_TEXTURE ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS);
|
||||
|
||||
switch(r.dimension)
|
||||
{
|
||||
default:
|
||||
case DXBC::ShaderInputBind::DIM_UNKNOWN: res.resType = TextureDim::Unknown; break;
|
||||
case DXBC::ShaderInputBind::DIM_BUFFER:
|
||||
case DXBC::ShaderInputBind::DIM_BUFFEREX: res.resType = TextureDim::Buffer; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE1D: res.resType = TextureDim::Texture1D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE1DARRAY:
|
||||
res.resType = TextureDim::Texture1DArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2D: res.resType = TextureDim::Texture2D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DARRAY:
|
||||
res.resType = TextureDim::Texture2DArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DMS: res.resType = TextureDim::Texture2DMS; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DMSARRAY:
|
||||
res.resType = TextureDim::Texture2DMSArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE3D: res.resType = TextureDim::Texture3D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURECUBE: res.resType = TextureDim::TextureCube; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURECUBEARRAY:
|
||||
res.resType = TextureDim::TextureCubeArray;
|
||||
break;
|
||||
}
|
||||
|
||||
if(r.retType != DXBC::ShaderInputBind::RETTYPE_UNKNOWN &&
|
||||
r.retType != DXBC::ShaderInputBind::RETTYPE_MIXED &&
|
||||
r.retType != DXBC::ShaderInputBind::RETTYPE_CONTINUED)
|
||||
{
|
||||
res.variableType.descriptor.rows = 1;
|
||||
res.variableType.descriptor.cols = (uint8_t)r.numSamples;
|
||||
res.variableType.descriptor.elements = 1;
|
||||
|
||||
string name;
|
||||
|
||||
switch(r.retType)
|
||||
{
|
||||
case DXBC::ShaderInputBind::RETTYPE_UNORM: name = "unorm float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_SNORM: name = "snorm float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_SINT: name = "int"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_UINT: name = "uint"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_FLOAT: name = "float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_DOUBLE: name = "double"; break;
|
||||
default: name = "unknown"; break;
|
||||
}
|
||||
|
||||
name += ToStr::Get(r.numSamples);
|
||||
|
||||
res.variableType.descriptor.name = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dxbc->m_ResourceBinds.find(r.name) != dxbc->m_ResourceBinds.end())
|
||||
{
|
||||
uint32_t vecOffset = 0;
|
||||
res.variableType = MakeShaderVariableType(dxbc->m_ResourceBinds[r.name], vecOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.variableType.descriptor.rows = 0;
|
||||
res.variableType.descriptor.cols = 0;
|
||||
res.variableType.descriptor.elements = 0;
|
||||
res.variableType.descriptor.name = "";
|
||||
}
|
||||
}
|
||||
|
||||
res.bindPoint = res.IsReadOnly ? roidx : rwidx;
|
||||
|
||||
BindpointMap map;
|
||||
map.arraySize = r.bindCount == 0 ? ~0U : r.bindCount;
|
||||
map.bindset = r.space;
|
||||
map.bind = r.reg;
|
||||
map.used = true;
|
||||
|
||||
if(res.IsReadOnly)
|
||||
{
|
||||
mapping->ReadOnlyResources[roidx] = map;
|
||||
refl->ReadOnlyResources[roidx++] = res;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapping->ReadWriteResources[rwidx] = map;
|
||||
refl->ReadWriteResources[rwidx++] = res;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t numInterfaces = 0;
|
||||
for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++)
|
||||
numInterfaces = RDCMAX(dxbc->m_Interfaces.variables[i].descriptor.offset + 1, numInterfaces);
|
||||
|
||||
create_array(refl->Interfaces, numInterfaces);
|
||||
for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++)
|
||||
refl->Interfaces[dxbc->m_Interfaces.variables[i].descriptor.offset] =
|
||||
dxbc->m_Interfaces.variables[i].name;
|
||||
}
|
||||
|
||||
enum D3D12ResourceBarrierSubresource
|
||||
{
|
||||
D3D12AllSubresources = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES
|
||||
|
||||
@@ -69,9 +69,6 @@ BlendMultiplier MakeBlendMultiplier(D3D12_BLEND blend, bool alpha);
|
||||
BlendOp MakeBlendOp(D3D12_BLEND_OP op);
|
||||
StencilOp MakeStencilOp(D3D12_STENCIL_OP op);
|
||||
|
||||
void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl,
|
||||
ShaderBindpointMapping *mapping);
|
||||
|
||||
// similar to RDCUNIMPLEMENTED but for things that are hit often so we don't want to fire the
|
||||
// debugbreak.
|
||||
#define D3D12NOTIMP(...) \
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "d3d12_resources.h"
|
||||
#include "3rdparty/lz4/lz4.h"
|
||||
#include "driver/shaders/dxbc/dxbc_reflect.h"
|
||||
#include "d3d12_command_list.h"
|
||||
#include "d3d12_command_queue.h"
|
||||
|
||||
@@ -458,3 +459,16 @@ WrappedID3D12DescriptorHeap::~WrappedID3D12DescriptorHeap()
|
||||
Shutdown();
|
||||
SAFE_DELETE_ARRAY(descriptors);
|
||||
}
|
||||
|
||||
void WrappedID3D12PipelineState::ShaderEntry::BuildReflection()
|
||||
{
|
||||
RDCCOMPILE_ASSERT(
|
||||
D3Dx_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT == D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT,
|
||||
"Mismatched vertex input count");
|
||||
|
||||
MakeShaderReflection(m_DXBCFile, &m_Details, &m_Mapping);
|
||||
m_Details.ID = GetResourceID();
|
||||
m_Details.EntryPoint = m_DXBCFile->m_DebugInfo ? m_DXBCFile->m_DebugInfo->GetEntryFunction() : "";
|
||||
if(m_Details.EntryPoint.empty())
|
||||
m_Details.EntryPoint = "main";
|
||||
}
|
||||
|
||||
@@ -610,15 +610,7 @@ public:
|
||||
void TryReplaceOriginalByteCode();
|
||||
ShaderEntry &operator=(const ShaderEntry &e);
|
||||
|
||||
void BuildReflection()
|
||||
{
|
||||
MakeShaderReflection(m_DXBCFile, &m_Details, &m_Mapping);
|
||||
m_Details.ID = GetResourceID();
|
||||
m_Details.EntryPoint =
|
||||
m_DXBCFile->m_DebugInfo ? m_DXBCFile->m_DebugInfo->GetEntryFunction() : "";
|
||||
if(m_Details.EntryPoint.empty())
|
||||
m_Details.EntryPoint = "main";
|
||||
}
|
||||
void BuildReflection();
|
||||
|
||||
DXBCKey m_Key;
|
||||
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 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 "dxbc_reflect.h"
|
||||
#include "api/replay/renderdoc_replay.h"
|
||||
#include "core/core.h"
|
||||
#include "replay/type_helpers.h"
|
||||
#include "dxbc_inspect.h"
|
||||
|
||||
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var, uint32_t &offset);
|
||||
|
||||
static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type, uint32_t &offset)
|
||||
{
|
||||
ShaderVariableType ret;
|
||||
|
||||
switch(type.descriptor.type)
|
||||
{
|
||||
case DXBC::VARTYPE_MIN12INT:
|
||||
case DXBC::VARTYPE_MIN16INT:
|
||||
case DXBC::VARTYPE_INT: ret.descriptor.type = VarType::Int; break;
|
||||
case DXBC::VARTYPE_BOOL:
|
||||
case DXBC::VARTYPE_MIN16UINT:
|
||||
case DXBC::VARTYPE_UINT: ret.descriptor.type = VarType::UInt; break;
|
||||
case DXBC::VARTYPE_DOUBLE: ret.descriptor.type = VarType::Double; break;
|
||||
case DXBC::VARTYPE_FLOAT:
|
||||
case DXBC::VARTYPE_MIN8FLOAT:
|
||||
case DXBC::VARTYPE_MIN10FLOAT:
|
||||
case DXBC::VARTYPE_MIN16FLOAT:
|
||||
default: ret.descriptor.type = VarType::Float; break;
|
||||
}
|
||||
ret.descriptor.rows = (uint8_t)type.descriptor.rows;
|
||||
ret.descriptor.cols = (uint8_t)type.descriptor.cols;
|
||||
ret.descriptor.elements = type.descriptor.elements;
|
||||
ret.descriptor.name = type.descriptor.name;
|
||||
ret.descriptor.rowMajorStorage = (type.descriptor.varClass == DXBC::CLASS_MATRIX_ROWS);
|
||||
|
||||
uint32_t baseElemSize = (ret.descriptor.type == VarType::Double) ? 8 : 4;
|
||||
if(ret.descriptor.rowMajorStorage)
|
||||
{
|
||||
uint32_t primary = ret.descriptor.rows;
|
||||
if(primary == 3)
|
||||
primary = 4;
|
||||
ret.descriptor.arrayStride = baseElemSize * primary * ret.descriptor.cols;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t primary = ret.descriptor.cols;
|
||||
if(primary == 3)
|
||||
primary = 4;
|
||||
ret.descriptor.arrayStride = baseElemSize * primary * ret.descriptor.rows;
|
||||
}
|
||||
|
||||
uint32_t o = offset;
|
||||
|
||||
create_array_uninit(ret.members, type.members.size());
|
||||
for(size_t i = 0; i < type.members.size(); i++)
|
||||
{
|
||||
offset = o;
|
||||
ret.members[i] = MakeConstantBufferVariable(type.members[i], offset);
|
||||
}
|
||||
|
||||
if(ret.members.count > 0)
|
||||
{
|
||||
ret.descriptor.rows = 0;
|
||||
ret.descriptor.cols = 0;
|
||||
ret.descriptor.elements = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ShaderConstant MakeConstantBufferVariable(const DXBC::CBufferVariable &var, uint32_t &offset)
|
||||
{
|
||||
ShaderConstant ret;
|
||||
|
||||
ret.name = var.name;
|
||||
ret.reg.vec = offset + var.descriptor.offset / 16;
|
||||
ret.reg.comp = (var.descriptor.offset - (var.descriptor.offset & ~0xf)) / 4;
|
||||
ret.defaultValue = 0;
|
||||
|
||||
offset = ret.reg.vec;
|
||||
|
||||
ret.type = MakeShaderVariableType(var.type, offset);
|
||||
|
||||
offset = ret.reg.vec + RDCMAX(1U, var.type.descriptor.bytesize / 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl,
|
||||
ShaderBindpointMapping *mapping)
|
||||
{
|
||||
if(dxbc == NULL || !RenderDoc::Inst().IsReplayApp())
|
||||
return;
|
||||
|
||||
if(dxbc->m_DebugInfo)
|
||||
{
|
||||
refl->DebugInfo.compileFlags = DXBC::EncodeFlags(dxbc->m_DebugInfo);
|
||||
|
||||
create_array_uninit(refl->DebugInfo.files, dxbc->m_DebugInfo->Files.size());
|
||||
for(size_t i = 0; i < dxbc->m_DebugInfo->Files.size(); i++)
|
||||
{
|
||||
refl->DebugInfo.files[i].first = dxbc->m_DebugInfo->Files[i].first;
|
||||
refl->DebugInfo.files[i].second = dxbc->m_DebugInfo->Files[i].second;
|
||||
}
|
||||
|
||||
string entry = dxbc->m_DebugInfo->GetEntryFunction();
|
||||
if(entry.empty())
|
||||
entry = "main";
|
||||
|
||||
// sort the file with the entry point to the start. We don't have to do anything if there's only
|
||||
// one file.
|
||||
// This isn't a perfect search - it will match entry_point() anywhere in the file, even if it's
|
||||
// in a comment or disabled preprocessor definition. This is just best-effort
|
||||
if(refl->DebugInfo.files.count > 1)
|
||||
{
|
||||
// search from 0 up. If we find a match, we swap it into [0]. If we don't find a match then
|
||||
// we can't rearrange anything. This is a no-op for 0 since it's already in first place, but
|
||||
// since our search isn't perfect we might have multiple matches with some being false
|
||||
// positives, and so we want to bias towards leaving [0] in place.
|
||||
for(int32_t i = 0; i < refl->DebugInfo.files.count; i++)
|
||||
{
|
||||
char *c = strstr(refl->DebugInfo.files[i].first.elems, entry.c_str());
|
||||
char *end = refl->DebugInfo.files[i].first.elems + refl->DebugInfo.files[i].first.count;
|
||||
|
||||
// no substring match? continue
|
||||
if(c == NULL)
|
||||
continue;
|
||||
|
||||
// if we did get a substring match, ensure there's whitespace preceeding it.
|
||||
if(c == entry.c_str() || !isspace((int)*(c - 1)))
|
||||
continue;
|
||||
|
||||
// skip past the entry point. Then skip any whitespace
|
||||
c += entry.size();
|
||||
|
||||
// check for EOF.
|
||||
if(c >= end)
|
||||
continue;
|
||||
|
||||
while(c < end && isspace(*c))
|
||||
c++;
|
||||
|
||||
if(c >= end)
|
||||
continue;
|
||||
|
||||
// if there's an open bracket next, we found a entry_point( which we count as the
|
||||
// declaration.
|
||||
if(*c == '(')
|
||||
{
|
||||
// only do anything if we're looking at a later file
|
||||
if(i > 0)
|
||||
std::swap(refl->DebugInfo.files[0], refl->DebugInfo.files[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dxbc->m_ShaderBlob.empty())
|
||||
create_array_uninit(refl->RawBytes, 0);
|
||||
else
|
||||
create_array_init(refl->RawBytes, dxbc->m_ShaderBlob.size(), &dxbc->m_ShaderBlob[0]);
|
||||
|
||||
refl->DispatchThreadsDimension[0] = dxbc->DispatchThreadsDimension[0];
|
||||
refl->DispatchThreadsDimension[1] = dxbc->DispatchThreadsDimension[1];
|
||||
refl->DispatchThreadsDimension[2] = dxbc->DispatchThreadsDimension[2];
|
||||
|
||||
refl->InputSig = dxbc->m_InputSig;
|
||||
refl->OutputSig = dxbc->m_OutputSig;
|
||||
|
||||
create_array_uninit(mapping->InputAttributes, D3Dx_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT);
|
||||
for(int s = 0; s < D3Dx_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; s++)
|
||||
mapping->InputAttributes[s] = s;
|
||||
|
||||
create_array_uninit(mapping->ConstantBlocks, dxbc->m_CBuffers.size());
|
||||
create_array_uninit(refl->ConstantBlocks, dxbc->m_CBuffers.size());
|
||||
for(size_t i = 0; i < dxbc->m_CBuffers.size(); i++)
|
||||
{
|
||||
ConstantBlock &cb = refl->ConstantBlocks[i];
|
||||
|
||||
cb.name = dxbc->m_CBuffers[i].name;
|
||||
cb.bufferBacked = true;
|
||||
cb.byteSize = dxbc->m_CBuffers[i].descriptor.byteSize;
|
||||
cb.bindPoint = (uint32_t)i;
|
||||
|
||||
BindpointMap map;
|
||||
map.arraySize = 1;
|
||||
map.bindset = dxbc->m_CBuffers[i].space;
|
||||
map.bind = dxbc->m_CBuffers[i].reg;
|
||||
map.used = true;
|
||||
|
||||
mapping->ConstantBlocks[i] = map;
|
||||
|
||||
create_array_uninit(cb.variables, dxbc->m_CBuffers[i].variables.size());
|
||||
for(size_t v = 0; v < dxbc->m_CBuffers[i].variables.size(); v++)
|
||||
{
|
||||
uint32_t vecOffset = 0;
|
||||
cb.variables[v] = MakeConstantBufferVariable(dxbc->m_CBuffers[i].variables[v], vecOffset);
|
||||
}
|
||||
}
|
||||
|
||||
int numRWResources = 0;
|
||||
int numROResources = 0;
|
||||
|
||||
for(size_t i = 0; i < dxbc->m_Resources.size(); i++)
|
||||
{
|
||||
const auto &r = dxbc->m_Resources[i];
|
||||
|
||||
if(r.type != DXBC::ShaderInputBind::TYPE_CBUFFER)
|
||||
{
|
||||
bool IsReadWrite = (r.type == DXBC::ShaderInputBind::TYPE_UAV_RWTYPED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWBYTEADDRESS ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_APPEND_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_CONSUME_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER);
|
||||
|
||||
if(IsReadWrite)
|
||||
numRWResources++;
|
||||
else
|
||||
numROResources++;
|
||||
}
|
||||
}
|
||||
|
||||
create_array_uninit(mapping->ReadWriteResources, numRWResources);
|
||||
create_array_uninit(refl->ReadWriteResources, numRWResources);
|
||||
|
||||
create_array_uninit(mapping->ReadOnlyResources, numROResources);
|
||||
create_array_uninit(refl->ReadOnlyResources, numROResources);
|
||||
|
||||
int32_t rwidx = 0, roidx = 0;
|
||||
for(size_t i = 0; i < dxbc->m_Resources.size(); i++)
|
||||
{
|
||||
const auto &r = dxbc->m_Resources[i];
|
||||
|
||||
if(r.type == DXBC::ShaderInputBind::TYPE_CBUFFER)
|
||||
continue;
|
||||
|
||||
ShaderResource res;
|
||||
res.name = r.name;
|
||||
|
||||
res.IsSampler = (r.type == DXBC::ShaderInputBind::TYPE_SAMPLER);
|
||||
res.IsTexture = (r.type == DXBC::ShaderInputBind::TYPE_TEXTURE &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_UNKNOWN &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_BUFFER &&
|
||||
r.dimension != DXBC::ShaderInputBind::DIM_BUFFEREX);
|
||||
res.IsReadOnly = (r.type == DXBC::ShaderInputBind::TYPE_TBUFFER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_SAMPLER ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_TEXTURE ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_STRUCTURED ||
|
||||
r.type == DXBC::ShaderInputBind::TYPE_BYTEADDRESS);
|
||||
|
||||
switch(r.dimension)
|
||||
{
|
||||
default:
|
||||
case DXBC::ShaderInputBind::DIM_UNKNOWN: res.resType = TextureDim::Unknown; break;
|
||||
case DXBC::ShaderInputBind::DIM_BUFFER:
|
||||
case DXBC::ShaderInputBind::DIM_BUFFEREX: res.resType = TextureDim::Buffer; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE1D: res.resType = TextureDim::Texture1D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE1DARRAY:
|
||||
res.resType = TextureDim::Texture1DArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2D: res.resType = TextureDim::Texture2D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DARRAY:
|
||||
res.resType = TextureDim::Texture2DArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DMS: res.resType = TextureDim::Texture2DMS; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE2DMSARRAY:
|
||||
res.resType = TextureDim::Texture2DMSArray;
|
||||
break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURE3D: res.resType = TextureDim::Texture3D; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURECUBE: res.resType = TextureDim::TextureCube; break;
|
||||
case DXBC::ShaderInputBind::DIM_TEXTURECUBEARRAY:
|
||||
res.resType = TextureDim::TextureCubeArray;
|
||||
break;
|
||||
}
|
||||
|
||||
if(r.retType != DXBC::ShaderInputBind::RETTYPE_UNKNOWN &&
|
||||
r.retType != DXBC::ShaderInputBind::RETTYPE_MIXED &&
|
||||
r.retType != DXBC::ShaderInputBind::RETTYPE_CONTINUED)
|
||||
{
|
||||
res.variableType.descriptor.rows = 1;
|
||||
res.variableType.descriptor.cols = (uint8_t)r.numSamples;
|
||||
res.variableType.descriptor.elements = 1;
|
||||
|
||||
string name;
|
||||
|
||||
switch(r.retType)
|
||||
{
|
||||
case DXBC::ShaderInputBind::RETTYPE_UNORM: name = "unorm float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_SNORM: name = "snorm float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_SINT: name = "int"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_UINT: name = "uint"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_FLOAT: name = "float"; break;
|
||||
case DXBC::ShaderInputBind::RETTYPE_DOUBLE: name = "double"; break;
|
||||
default: name = "unknown"; break;
|
||||
}
|
||||
|
||||
name += StringFormat::Fmt("%u", r.numSamples);
|
||||
|
||||
res.variableType.descriptor.name = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dxbc->m_ResourceBinds.find(r.name) != dxbc->m_ResourceBinds.end())
|
||||
{
|
||||
uint32_t vecOffset = 0;
|
||||
res.variableType = MakeShaderVariableType(dxbc->m_ResourceBinds[r.name], vecOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.variableType.descriptor.rows = 0;
|
||||
res.variableType.descriptor.cols = 0;
|
||||
res.variableType.descriptor.elements = 0;
|
||||
res.variableType.descriptor.name = "";
|
||||
}
|
||||
}
|
||||
|
||||
res.bindPoint = res.IsReadOnly ? roidx : rwidx;
|
||||
|
||||
BindpointMap map;
|
||||
map.arraySize = r.bindCount == 0 ? ~0U : r.bindCount;
|
||||
map.bindset = r.space;
|
||||
map.bind = r.reg;
|
||||
map.used = true;
|
||||
|
||||
if(res.IsReadOnly)
|
||||
{
|
||||
mapping->ReadOnlyResources[roidx] = map;
|
||||
refl->ReadOnlyResources[roidx++] = res;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapping->ReadWriteResources[rwidx] = map;
|
||||
refl->ReadWriteResources[rwidx++] = res;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t numInterfaces = 0;
|
||||
for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++)
|
||||
numInterfaces = RDCMAX(dxbc->m_Interfaces.variables[i].descriptor.offset + 1, numInterfaces);
|
||||
|
||||
create_array(refl->Interfaces, numInterfaces);
|
||||
for(size_t i = 0; i < dxbc->m_Interfaces.variables.size(); i++)
|
||||
refl->Interfaces[dxbc->m_Interfaces.variables[i].descriptor.offset] =
|
||||
dxbc->m_Interfaces.variables[i].name;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 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
|
||||
|
||||
namespace DXBC
|
||||
{
|
||||
class DXBCFile;
|
||||
}
|
||||
|
||||
struct ShaderReflection;
|
||||
struct ShaderBindpointMapping;
|
||||
|
||||
#define D3Dx_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT 32
|
||||
|
||||
void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl,
|
||||
ShaderBindpointMapping *mapping);
|
||||
@@ -59,7 +59,7 @@
|
||||
<PreprocessorDefinitions>RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
@@ -102,6 +102,7 @@
|
||||
<ClCompile Include="dxbc_debug.cpp" />
|
||||
<ClCompile Include="dxbc_disassemble.cpp" />
|
||||
<ClCompile Include="dxbc_inspect.cpp" />
|
||||
<ClCompile Include="dxbc_reflect.cpp" />
|
||||
<ClCompile Include="precompiled.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -111,6 +112,7 @@
|
||||
<ClInclude Include="dxbc_debug.h" />
|
||||
<ClInclude Include="dxbc_disassemble.h" />
|
||||
<ClInclude Include="dxbc_inspect.h" />
|
||||
<ClInclude Include="dxbc_reflect.h" />
|
||||
<ClInclude Include="dxbc_sdbg.h" />
|
||||
<ClInclude Include="dxbc_spdb.h" />
|
||||
<ClInclude Include="precompiled.h" />
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<ClCompile Include="precompiled.cpp">
|
||||
<Filter>PCH</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dxbc_reflect.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dxbc_debug.h" />
|
||||
@@ -19,6 +20,7 @@
|
||||
<ClInclude Include="precompiled.h">
|
||||
<Filter>PCH</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="dxbc_reflect.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="PCH">
|
||||
|
||||
Reference in New Issue
Block a user