mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-11-11 08:23:46 +00:00
Allow cbuffer previewer to apply custom format to non-buffer-backed CBs
* This in particular means push constants and specialization constants on vulkan but also applies to root-value cbuffers on D3D12. * GL bare uniforms are not feasible to expose in this way.
This commit is contained in:
14 files changed
+342
-132
No files matched your search
@@ -393,7 +393,6 @@ TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, DescriptorSet)
|
||||
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, ImageData)
|
||||
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, ImageLayout)
|
||||
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, RenderArea)
|
||||
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, SpecializationConstant)
|
||||
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, XFBBuffer)
|
||||
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, VertexBuffer)
|
||||
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, VertexAttribute)
|
||||
|
||||
@@ -107,6 +107,7 @@ void ConstantBufferPreviewer::OnEventChanged(uint32_t eventId)
|
||||
m_cbuffer = cb.resourceId;
|
||||
uint64_t offset = cb.byteOffset;
|
||||
uint64_t size = cb.byteSize;
|
||||
bytebuf inlineData = cb.inlineData;
|
||||
|
||||
ResourceId prevShader = m_shader;
|
||||
|
||||
@@ -136,26 +137,24 @@ void ConstantBufferPreviewer::OnEventChanged(uint32_t eventId)
|
||||
|
||||
if(!m_formatOverride.type.members.empty())
|
||||
{
|
||||
m_Ctx.Replay().AsyncInvoke([this, offset, size, wasEmpty](IReplayController *r) {
|
||||
bytebuf data;
|
||||
if(size > 0)
|
||||
data = r->GetBufferData(m_cbuffer, offset, size);
|
||||
rdcarray<ShaderVariable> vars = applyFormatOverride(data);
|
||||
GUIInvoke::call(this, [this, vars, wasEmpty] {
|
||||
RDTreeViewExpansionState state;
|
||||
ui->variables->saveExpansion(state, 0);
|
||||
setVariables(vars);
|
||||
if(wasEmpty)
|
||||
{
|
||||
// Expand before resizing so that collapsed data will already be visible when expanded
|
||||
ui->variables->expandAll();
|
||||
for(int i = 0; i < 3; i++)
|
||||
ui->variables->resizeColumnToContents(i);
|
||||
ui->variables->collapseAll();
|
||||
}
|
||||
ui->variables->applyExpansion(state, 0);
|
||||
if(!inlineData.empty() && m_cbuffer == ResourceId())
|
||||
{
|
||||
setVariablesPreserveExpansion(applyFormatOverride(inlineData), wasEmpty);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Ctx.Replay().AsyncInvoke([this, offset, size, wasEmpty](IReplayController *r) {
|
||||
bytebuf data;
|
||||
|
||||
if(size > 0 && m_cbuffer != ResourceId())
|
||||
data = r->GetBufferData(m_cbuffer, offset, size);
|
||||
|
||||
rdcarray<ShaderVariable> vars = applyFormatOverride(data);
|
||||
|
||||
GUIInvoke::call(this,
|
||||
[this, vars, wasEmpty] { setVariablesPreserveExpansion(vars, wasEmpty); });
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -327,6 +326,26 @@ void ConstantBufferPreviewer::setVariables(const rdcarray<ShaderVariable> &vars)
|
||||
ui->variables->endUpdate();
|
||||
}
|
||||
|
||||
void ConstantBufferPreviewer::setVariablesPreserveExpansion(const rdcarray<ShaderVariable> &vars,
|
||||
bool wasEmpty)
|
||||
{
|
||||
RDTreeViewExpansionState state;
|
||||
ui->variables->saveExpansion(state, 0);
|
||||
|
||||
setVariables(vars);
|
||||
|
||||
if(wasEmpty)
|
||||
{
|
||||
// Expand before resizing so that collapsed data will already be visible when expanded
|
||||
ui->variables->expandAll();
|
||||
for(int i = 0; i < 3; i++)
|
||||
ui->variables->resizeColumnToContents(i);
|
||||
ui->variables->collapseAll();
|
||||
}
|
||||
|
||||
ui->variables->applyExpansion(state, 0);
|
||||
}
|
||||
|
||||
void ConstantBufferPreviewer::updateLabels()
|
||||
{
|
||||
QString bufName = m_Ctx.GetResourceName(m_cbuffer);
|
||||
|
||||
@@ -84,6 +84,7 @@ private:
|
||||
|
||||
void addVariables(RDTreeWidgetItem *root, const rdcarray<ShaderVariable> &vars);
|
||||
void setVariables(const rdcarray<ShaderVariable> &vars);
|
||||
void setVariablesPreserveExpansion(const rdcarray<ShaderVariable> &vars, bool wasEmpty);
|
||||
|
||||
void updateLabels();
|
||||
|
||||
|
||||
@@ -1626,12 +1626,28 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta
|
||||
{
|
||||
setname = QString();
|
||||
slotname = cblock->name;
|
||||
name = tr("Push constants");
|
||||
if(cblock->compileConstants)
|
||||
name = tr("Specialization constants");
|
||||
else if(descriptorBind && descriptorBind->inlineBlock)
|
||||
name = tr("Inline uniforms");
|
||||
else
|
||||
name = tr("Push constants");
|
||||
|
||||
vecrange = QString();
|
||||
sizestr = tr("%1 Variables").arg(numvars);
|
||||
|
||||
// could maybe get range from ShaderVariable.reg if it's filled out
|
||||
// from SPIR-V side.
|
||||
if(descriptorBind && descriptorBind->inlineBlock)
|
||||
{
|
||||
vecrange = QFormatStr("%1 - %2")
|
||||
.arg(descriptorBind->byteOffset)
|
||||
.arg(descriptorBind->byteOffset + descriptorBind->byteSize);
|
||||
}
|
||||
else if(!cblock->compileConstants)
|
||||
{
|
||||
vecrange = QFormatStr("%1 - %2")
|
||||
.arg(stage.pushConstantRangeByteOffset)
|
||||
.arg(stage.pushConstantRangeByteOffset + stage.pushConstantRangeByteSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1850,16 +1866,9 @@ void VulkanPipelineStateViewer::setShaderState(const VKPipe::Shader &stage,
|
||||
ConstantBlock &cblock = shaderDetails->constantBlocks[cb];
|
||||
if(cblock.bufferBacked == false)
|
||||
{
|
||||
// could maybe get range from ShaderVariable.reg if it's filled out
|
||||
// from SPIR-V side.
|
||||
|
||||
RDTreeWidgetItem *node =
|
||||
new RDTreeWidgetItem({QString(), QString(), cblock.name, tr("Push constants"), QString(),
|
||||
tr("%1 Variables").arg(cblock.variables.count()), QString()});
|
||||
|
||||
node->setTag(QVariant::fromValue(VulkanCBufferTag(cb)));
|
||||
|
||||
ubos->addTopLevelItem(node);
|
||||
addConstantBlockRow(
|
||||
shaderDetails, stage, stage.bindpointMapping.constantBlocks[cblock.bindPoint].bindset,
|
||||
stage.bindpointMapping.constantBlocks[cblock.bindPoint].bind, pipe, ubos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3225,18 +3234,42 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe::
|
||||
// push constants
|
||||
if(!b.bufferBacked)
|
||||
{
|
||||
const VKPipe::BindingElement *descriptorBind = NULL;
|
||||
|
||||
if(bindMap.bindset < pipeline.descriptorSets.count() &&
|
||||
bindMap.bind < pipeline.descriptorSets[bindMap.bindset].bindings.count())
|
||||
descriptorBind = &pipeline.descriptorSets[bindMap.bindset].bindings[bindMap.bind].binds[0];
|
||||
|
||||
QString name;
|
||||
if(b.compileConstants)
|
||||
name = tr("Specialization constants");
|
||||
else if(descriptorBind->inlineBlock)
|
||||
name = tr("Inline uniforms");
|
||||
else
|
||||
name = tr("Push constants");
|
||||
|
||||
qulonglong offset = 0, size = 0;
|
||||
|
||||
if(descriptorBind->inlineBlock)
|
||||
{
|
||||
offset = descriptorBind->byteOffset;
|
||||
size = descriptorBind->byteSize;
|
||||
}
|
||||
else if(!b.compileConstants)
|
||||
{
|
||||
offset = sh.pushConstantRangeByteOffset;
|
||||
size = sh.pushConstantRangeByteSize;
|
||||
}
|
||||
|
||||
// could maybe get range/size from ShaderVariable.reg if it's filled out
|
||||
// from SPIR-V side.
|
||||
rows.push_back({QString(), b.name, tr("Push constants"), (qulonglong)0, (qulonglong)0,
|
||||
b.variables.count(), b.byteSize});
|
||||
rows.push_back({QString(), b.name, name, offset, size, b.variables.count(), b.byteSize});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const VKPipe::DescriptorSet &set =
|
||||
pipeline.descriptorSets[sh.bindpointMapping.constantBlocks[i].bindset];
|
||||
const VKPipe::DescriptorBinding &bind =
|
||||
set.bindings[sh.bindpointMapping.constantBlocks[i].bind];
|
||||
const VKPipe::DescriptorSet &set = pipeline.descriptorSets[bindMap.bindset];
|
||||
const VKPipe::DescriptorBinding &bind = set.bindings[bindMap.bind];
|
||||
|
||||
QString setname = QString::number(bindMap.bindset);
|
||||
|
||||
|
||||
@@ -409,6 +409,13 @@ struct BoundCBuffer
|
||||
uint64_t byteOffset = 0;
|
||||
DOCUMENT("The size in bytes for the constant buffer. Access outside this size returns 0.");
|
||||
uint64_t byteSize = 0;
|
||||
|
||||
DOCUMENT(R"(The inline byte data for this constant buffer, if this binding is not backed by a
|
||||
typical buffer.
|
||||
|
||||
:type: bytes
|
||||
)");
|
||||
bytebuf inlineData;
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(BoundCBuffer);
|
||||
|
||||
@@ -905,9 +905,7 @@ rdcarray<VertexInputAttribute> PipeState::GetVertexInputs() const
|
||||
|
||||
BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, uint32_t ArrayIdx) const
|
||||
{
|
||||
ResourceId buf;
|
||||
uint64_t ByteOffset = 0;
|
||||
uint64_t ByteSize = 0;
|
||||
BoundCBuffer ret;
|
||||
|
||||
if(IsCaptureLoaded())
|
||||
{
|
||||
@@ -925,9 +923,9 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui
|
||||
|
||||
const D3D11Pipe::ConstantBuffer &descriptor = s.constantBuffers[bind.bind];
|
||||
|
||||
buf = descriptor.resourceId;
|
||||
ByteOffset = descriptor.vecOffset * 4 * sizeof(float);
|
||||
ByteSize = descriptor.vecCount * 4 * sizeof(float);
|
||||
ret.resourceId = descriptor.resourceId;
|
||||
ret.byteOffset = descriptor.vecOffset * 4 * sizeof(float);
|
||||
ret.byteSize = descriptor.vecCount * 4 * sizeof(float);
|
||||
}
|
||||
}
|
||||
else if(IsCaptureD3D12())
|
||||
@@ -956,10 +954,16 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui
|
||||
const D3D12Pipe::ConstantBuffer &cb = element.constantBuffers[j];
|
||||
if(cb.bind == (uint32_t)shaderReg)
|
||||
{
|
||||
buf = cb.resourceId;
|
||||
ByteOffset = cb.byteOffset;
|
||||
ByteSize = cb.byteSize;
|
||||
found = true;
|
||||
|
||||
ret.resourceId = cb.resourceId;
|
||||
ret.byteOffset = cb.byteOffset;
|
||||
ret.byteSize = cb.byteSize;
|
||||
if(element.immediate)
|
||||
{
|
||||
ret.inlineData.resize(cb.rootValues.byteSize());
|
||||
memcpy(ret.inlineData.data(), cb.rootValues.data(), ret.inlineData.size());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -981,12 +985,12 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui
|
||||
{
|
||||
const GLPipe::Buffer &b = m_GL->uniformBuffers[uboIdx];
|
||||
|
||||
buf = b.resourceId;
|
||||
ByteOffset = b.byteOffset;
|
||||
ByteSize = b.byteSize;
|
||||
ret.resourceId = b.resourceId;
|
||||
ret.byteOffset = b.byteOffset;
|
||||
ret.byteSize = b.byteSize;
|
||||
|
||||
if(ByteSize == 0)
|
||||
ByteSize = ~0ULL;
|
||||
if(ret.byteSize == 0)
|
||||
ret.byteSize = ~0ULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1004,33 +1008,95 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui
|
||||
|
||||
if(s.reflection->constantBlocks[BufIdx].bufferBacked == false)
|
||||
{
|
||||
BoundCBuffer ret;
|
||||
// dummy value, it would be nice to fetch this properly
|
||||
ret.byteSize = 1024;
|
||||
if(s.reflection->constantBlocks[BufIdx].compileConstants)
|
||||
{
|
||||
ret.inlineData = s.specializationData;
|
||||
ret.byteSize = ret.inlineData.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.inlineData.resize((size_t)ret.byteSize);
|
||||
|
||||
const bytebuf *src = NULL;
|
||||
|
||||
// push constants have a magic bindset value higher than any descriptor set
|
||||
if(bind.bindset < pipe.descriptorSets.count())
|
||||
{
|
||||
if(bind.bind >= pipe.descriptorSets[bind.bindset].bindings.count() ||
|
||||
ArrayIdx >= pipe.descriptorSets[bind.bindset].bindings[bind.bind].binds.size())
|
||||
return BoundCBuffer();
|
||||
|
||||
src = &pipe.descriptorSets[bind.bindset].inlineData;
|
||||
|
||||
const VKPipe::BindingElement &descriptorBind =
|
||||
pipe.descriptorSets[bind.bindset].bindings[bind.bind].binds[ArrayIdx];
|
||||
|
||||
ret.byteOffset = descriptorBind.byteOffset;
|
||||
ret.byteSize = descriptorBind.byteSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = &m_Vulkan->pushconsts;
|
||||
|
||||
switch(stage)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
ret.byteOffset = m_Vulkan->vertexShader.pushConstantRangeByteOffset;
|
||||
ret.byteSize = m_Vulkan->vertexShader.pushConstantRangeByteSize;
|
||||
break;
|
||||
case ShaderStage::Tess_Control:
|
||||
ret.byteOffset = m_Vulkan->tessControlShader.pushConstantRangeByteOffset;
|
||||
ret.byteSize = m_Vulkan->tessControlShader.pushConstantRangeByteSize;
|
||||
break;
|
||||
case ShaderStage::Tess_Eval:
|
||||
ret.byteOffset = m_Vulkan->tessEvalShader.pushConstantRangeByteOffset;
|
||||
ret.byteSize = m_Vulkan->tessEvalShader.pushConstantRangeByteSize;
|
||||
break;
|
||||
case ShaderStage::Geometry:
|
||||
ret.byteOffset = m_Vulkan->geometryShader.pushConstantRangeByteOffset;
|
||||
ret.byteSize = m_Vulkan->geometryShader.pushConstantRangeByteSize;
|
||||
break;
|
||||
case ShaderStage::Fragment:
|
||||
ret.byteOffset = m_Vulkan->fragmentShader.pushConstantRangeByteOffset;
|
||||
ret.byteSize = m_Vulkan->fragmentShader.pushConstantRangeByteSize;
|
||||
break;
|
||||
case ShaderStage::Compute:
|
||||
ret.byteOffset = m_Vulkan->computeShader.pushConstantRangeByteOffset;
|
||||
ret.byteSize = m_Vulkan->computeShader.pushConstantRangeByteSize;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ret.byteOffset > src->size())
|
||||
ret.byteSize = 0;
|
||||
else if(ret.byteOffset + ret.byteSize > src->size())
|
||||
ret.byteSize = src->size() - (ret.byteOffset + ret.byteSize);
|
||||
|
||||
// consume the byteoffset here when copying data from the source data
|
||||
ret.inlineData.resize((size_t)ret.byteSize);
|
||||
memcpy(ret.inlineData.data(), src->data() + ret.byteOffset, (size_t)ret.byteSize);
|
||||
ret.byteOffset = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(bind.bindset >= pipe.descriptorSets.count() ||
|
||||
bind.bind >= pipe.descriptorSets[bind.bindset].bindings.count() ||
|
||||
ArrayIdx > pipe.descriptorSets[bind.bindset].bindings[bind.bind].binds.size())
|
||||
ArrayIdx >= pipe.descriptorSets[bind.bindset].bindings[bind.bind].binds.size())
|
||||
return BoundCBuffer();
|
||||
|
||||
const VKPipe::BindingElement &descriptorBind =
|
||||
pipe.descriptorSets[bind.bindset].bindings[bind.bind].binds[ArrayIdx];
|
||||
|
||||
buf = descriptorBind.resourceResourceId;
|
||||
ByteOffset = descriptorBind.byteOffset;
|
||||
ByteSize = descriptorBind.byteSize;
|
||||
ret.resourceId = descriptorBind.resourceResourceId;
|
||||
ret.byteOffset = descriptorBind.byteOffset;
|
||||
ret.byteSize = descriptorBind.byteSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoundCBuffer ret;
|
||||
|
||||
ret.resourceId = buf;
|
||||
ret.byteOffset = ByteOffset;
|
||||
ret.byteSize = ByteSize;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1025,7 +1025,8 @@ struct ConstantBlock
|
||||
bool operator==(const ConstantBlock &o) const
|
||||
{
|
||||
return name == o.name && variables == o.variables && bindPoint == o.bindPoint &&
|
||||
byteSize == o.byteSize && bufferBacked == o.bufferBacked;
|
||||
byteSize == o.byteSize && bufferBacked == o.bufferBacked &&
|
||||
compileConstants == o.compileConstants;
|
||||
}
|
||||
bool operator<(const ConstantBlock &o) const
|
||||
{
|
||||
@@ -1039,6 +1040,8 @@ struct ConstantBlock
|
||||
return byteSize < o.byteSize;
|
||||
if(!(bufferBacked == o.bufferBacked))
|
||||
return bufferBacked < o.bufferBacked;
|
||||
if(!(compileConstants == o.compileConstants))
|
||||
return compileConstants < o.compileConstants;
|
||||
return false;
|
||||
}
|
||||
DOCUMENT("The name of this constant block, may be empty on some APIs.");
|
||||
@@ -1051,14 +1054,16 @@ struct ConstantBlock
|
||||
DOCUMENT(R"(The bindpoint for this block. This is an index in the
|
||||
:data:`ShaderBindpointMapping.constantBlocks` list.
|
||||
)");
|
||||
int32_t bindPoint;
|
||||
int32_t bindPoint = 0;
|
||||
DOCUMENT("The total number of bytes consumed by all of the constants contained in this block.");
|
||||
uint32_t byteSize;
|
||||
uint32_t byteSize = 0;
|
||||
DOCUMENT(R"(``True`` if the contents are stored in a buffer of memory. If not then they are set by
|
||||
some other API-specific method, such as direct function calls or they may be compile-time
|
||||
specialisation constants.
|
||||
)");
|
||||
bool bufferBacked;
|
||||
bool bufferBacked = true;
|
||||
DOCUMENT("``True`` if this is a virtual buffer listing compile-time specialisation constants.");
|
||||
bool compileConstants = false;
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(ConstantBlock);
|
||||
|
||||
@@ -144,7 +144,11 @@ since single descriptors may only be dynamically skipped by control flow.
|
||||
DOCUMENT("For 3D textures and texture arrays - the number of array slices in the view.");
|
||||
uint32_t numSlices = 0;
|
||||
|
||||
DOCUMENT("For buffers - the byte offset where the buffer view starts in the underlying buffer.");
|
||||
DOCUMENT(R"(For buffers - the byte offset where the buffer view starts in the underlying buffer.
|
||||
|
||||
For inline block uniforms (see :data:`inlineBlock`) this is the byte offset into the descriptor
|
||||
set's inline block data.
|
||||
)");
|
||||
uint64_t byteOffset = 0;
|
||||
DOCUMENT("For buffers - how many bytes are in this buffer view.");
|
||||
uint64_t byteSize = 0;
|
||||
@@ -294,7 +298,8 @@ struct DescriptorSet
|
||||
{
|
||||
return layoutResourceId == o.layoutResourceId &&
|
||||
descriptorSetResourceId == o.descriptorSetResourceId &&
|
||||
pushDescriptor == o.pushDescriptor && bindings == o.bindings;
|
||||
pushDescriptor == o.pushDescriptor && bindings == o.bindings &&
|
||||
inlineData == o.inlineData;
|
||||
}
|
||||
bool operator<(const DescriptorSet &o) const
|
||||
{
|
||||
@@ -306,6 +311,8 @@ struct DescriptorSet
|
||||
return pushDescriptor < o.pushDescriptor;
|
||||
if(!(bindings == o.bindings))
|
||||
return bindings < o.bindings;
|
||||
if(!(inlineData == o.inlineData))
|
||||
return inlineData < o.inlineData;
|
||||
return false;
|
||||
}
|
||||
DOCUMENT("The :class:`ResourceId` of the descriptor set layout that matches this set.");
|
||||
@@ -321,6 +328,13 @@ This list is indexed by the binding, so it may be sparse (some entries do not co
|
||||
:type: List[VKDescriptorBinding]
|
||||
)");
|
||||
rdcarray<DescriptorBinding> bindings;
|
||||
|
||||
DOCUMENT(R"(The inline byte data within this descriptor set. Individual bindings will have an
|
||||
offset and size into this buffer.
|
||||
|
||||
:type: bytes
|
||||
)");
|
||||
bytebuf inlineData;
|
||||
};
|
||||
|
||||
DOCUMENT("Describes the object and descriptor set bindings of a Vulkan pipeline object.");
|
||||
@@ -526,32 +540,6 @@ struct VertexInput
|
||||
rdcarray<VertexBuffer> vertexBuffers;
|
||||
};
|
||||
|
||||
DOCUMENT("The provided value for a specialization constant.");
|
||||
struct SpecializationConstant
|
||||
{
|
||||
DOCUMENT("");
|
||||
SpecializationConstant() = default;
|
||||
SpecializationConstant(const SpecializationConstant &) = default;
|
||||
SpecializationConstant &operator=(const SpecializationConstant &) = default;
|
||||
|
||||
bool operator==(const SpecializationConstant &o) const
|
||||
{
|
||||
return specializationId == o.specializationId && data == o.data;
|
||||
}
|
||||
bool operator<(const SpecializationConstant &o) const
|
||||
{
|
||||
if(!(specializationId == o.specializationId))
|
||||
return specializationId < o.specializationId;
|
||||
if(!(data == o.data))
|
||||
return data < o.data;
|
||||
return false;
|
||||
}
|
||||
DOCUMENT("The specialization ID");
|
||||
uint32_t specializationId = 0;
|
||||
DOCUMENT("A ``bytes`` with the contents of the constant.");
|
||||
bytebuf data;
|
||||
};
|
||||
|
||||
DOCUMENT("Describes a Vulkan shader stage.");
|
||||
struct Shader
|
||||
{
|
||||
@@ -579,11 +567,20 @@ struct Shader
|
||||
DOCUMENT("A :class:`ShaderStage` identifying which stage this shader is bound to.");
|
||||
ShaderStage stage = ShaderStage::Vertex;
|
||||
|
||||
DOCUMENT(R"(The provided specialization constants.
|
||||
DOCUMENT("The byte offset into the push constant data that is visible to this shader.");
|
||||
uint32_t pushConstantRangeByteOffset = 0;
|
||||
|
||||
:type: List[VKSpecializationConstant]
|
||||
DOCUMENT("The number of bytes in the push constant data that is visible to this shader.");
|
||||
uint32_t pushConstantRangeByteSize = 0;
|
||||
|
||||
DOCUMENT(R"(The provided specialization constant data. Shader constants store the byte offset into
|
||||
this buffer as their byteOffset. This data includes the applied specialization constants over the
|
||||
top of the default values, so it is safe to read any constant from here and get the correct current
|
||||
value.
|
||||
|
||||
:type: bytes
|
||||
)");
|
||||
rdcarray<SpecializationConstant> specialization;
|
||||
bytebuf specializationData;
|
||||
};
|
||||
|
||||
DOCUMENT("Describes the state of the fixed-function tessellator.");
|
||||
@@ -1319,7 +1316,6 @@ DECLARE_REFLECTION_STRUCT(VKPipe::VertexAttribute);
|
||||
DECLARE_REFLECTION_STRUCT(VKPipe::VertexBinding);
|
||||
DECLARE_REFLECTION_STRUCT(VKPipe::VertexBuffer);
|
||||
DECLARE_REFLECTION_STRUCT(VKPipe::VertexInput);
|
||||
DECLARE_REFLECTION_STRUCT(VKPipe::SpecializationConstant);
|
||||
DECLARE_REFLECTION_STRUCT(VKPipe::Shader);
|
||||
DECLARE_REFLECTION_STRUCT(VKPipe::Tessellation);
|
||||
DECLARE_REFLECTION_STRUCT(VKPipe::XFBBuffer);
|
||||
|
||||
@@ -954,6 +954,8 @@ void D3D12Replay::FillRootElements(const D3D12RenderState::RootSignature &rootSi
|
||||
|
||||
element.constantBuffers.push_back(D3D12Pipe::ConstantBuffer(p.Constants.ShaderRegister));
|
||||
D3D12Pipe::ConstantBuffer &cb = element.constantBuffers.back();
|
||||
cb.resourceId = ResourceId();
|
||||
cb.byteOffset = 0;
|
||||
cb.byteSize = uint32_t(sizeof(uint32_t) * p.Constants.Num32BitValues);
|
||||
|
||||
if(rootEl < rootSig.sigelems.size())
|
||||
|
||||
@@ -46,7 +46,7 @@ void FillSpecConstantVariables(ResourceId shader, const rdcarray<ShaderConstant>
|
||||
{
|
||||
for(size_t v = 0; v < invars.size() && v < outvars.size(); v++)
|
||||
{
|
||||
if(specInfo[i].specID == invars[v].byteOffset)
|
||||
if(specInfo[i].specID * sizeof(uint64_t) == invars[v].byteOffset)
|
||||
{
|
||||
outvars[v].value.u64v[0] = specInfo[i].value;
|
||||
}
|
||||
@@ -1115,7 +1115,7 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
|
||||
ShaderConstant spec;
|
||||
MakeConstantBlockVariable(spec, pointerTypes, dataTypes[c.type], name, decorations[c.id],
|
||||
specInfo);
|
||||
spec.byteOffset = decorations[c.id].specID;
|
||||
spec.byteOffset = decorations[c.id].specID * sizeof(uint64_t);
|
||||
spec.defaultValue = c.value.value.u64v[0];
|
||||
specblock.variables.push_back(spec);
|
||||
}
|
||||
@@ -1125,6 +1125,7 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
|
||||
{
|
||||
specblock.name = "Specialization Constants";
|
||||
specblock.bufferBacked = false;
|
||||
specblock.compileConstants = true;
|
||||
specblock.byteSize = 0;
|
||||
|
||||
Bindpoint bindmap;
|
||||
|
||||
@@ -521,6 +521,25 @@ int StageIndex(VkShaderStageFlagBits stageFlag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
VkShaderStageFlags ShaderMaskFromIndex(size_t index)
|
||||
{
|
||||
VkShaderStageFlagBits mask[] = {
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
|
||||
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
|
||||
VK_SHADER_STAGE_GEOMETRY_BIT,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
};
|
||||
|
||||
if(index < ARRAY_COUNT(mask))
|
||||
return mask[index];
|
||||
|
||||
RDCERR("Unrecognised shader stage index %d", index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DoPipelineBarrier(VkCommandBuffer cmd, size_t count, const VkImageMemoryBarrier *barriers)
|
||||
{
|
||||
RDCASSERT(cmd != VK_NULL_HANDLE);
|
||||
|
||||
@@ -102,6 +102,7 @@ void DoPipelineBarrier(VkCommandBuffer cmd, size_t count, const VkMemoryBarrier
|
||||
int SampleCount(VkSampleCountFlagBits countFlag);
|
||||
int SampleIndex(VkSampleCountFlagBits countFlag);
|
||||
int StageIndex(VkShaderStageFlagBits stageFlag);
|
||||
VkShaderStageFlags ShaderMaskFromIndex(size_t index);
|
||||
|
||||
struct PackedWindowHandle
|
||||
{
|
||||
|
||||
@@ -1059,6 +1059,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
|
||||
|
||||
m_VulkanPipelineState.compute.pipelineLayoutResourceId = rm->GetOriginalID(p.layout);
|
||||
|
||||
const VulkanCreationInfo::PipelineLayout &pl = c.m_PipelineLayout[p.layout];
|
||||
|
||||
m_VulkanPipelineState.compute.flags = p.flags;
|
||||
|
||||
VKPipe::Shader &stage = m_VulkanPipelineState.computeShader;
|
||||
@@ -1074,13 +1076,43 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
|
||||
if(p.shaders[i].refl)
|
||||
stage.reflection = p.shaders[i].refl;
|
||||
|
||||
stage.specialization.resize(p.shaders[i].specialization.size());
|
||||
for(size_t s = 0; s < p.shaders[i].specialization.size(); s++)
|
||||
stage.pushConstantRangeByteOffset = stage.pushConstantRangeByteSize = 0;
|
||||
for(const VkPushConstantRange &pr : pl.pushRanges)
|
||||
{
|
||||
const SpecConstant &spec = p.shaders[i].specialization[s];
|
||||
stage.specialization[s].specializationId = spec.specID;
|
||||
stage.specialization[s].data.resize(spec.dataSize);
|
||||
memcpy(stage.specialization[s].data.data(), &spec.value, spec.dataSize);
|
||||
if(pr.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT)
|
||||
{
|
||||
stage.pushConstantRangeByteOffset = pr.offset;
|
||||
stage.pushConstantRangeByteSize = pr.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stage.specializationData.clear();
|
||||
|
||||
// set up the defaults
|
||||
if(p.shaders[i].mapping && p.shaders[i].refl)
|
||||
{
|
||||
for(size_t cb = 0; cb < p.shaders[i].mapping->constantBlocks.size(); cb++)
|
||||
{
|
||||
if(p.shaders[i].mapping->constantBlocks[cb].bindset == SpecializationConstantBindSet)
|
||||
{
|
||||
for(const ShaderConstant &sc : p.shaders[i].refl->constantBlocks[cb].variables)
|
||||
{
|
||||
stage.specializationData.resize_for_index(sc.byteOffset + sizeof(uint64_t));
|
||||
memcpy(stage.specializationData.data() + sc.byteOffset, &sc.defaultValue,
|
||||
sizeof(uint64_t));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply any specializations
|
||||
for(const SpecConstant &s : p.shaders[i].specialization)
|
||||
{
|
||||
size_t offs = s.specID * sizeof(uint64_t);
|
||||
stage.specializationData.resize_for_index(offs + sizeof(uint64_t));
|
||||
memcpy(stage.specializationData.data() + offs, &s.value, s.dataSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1097,6 +1129,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
|
||||
|
||||
m_VulkanPipelineState.graphics.pipelineLayoutResourceId = rm->GetOriginalID(p.layout);
|
||||
|
||||
const VulkanCreationInfo::PipelineLayout &pl = c.m_PipelineLayout[p.layout];
|
||||
|
||||
m_VulkanPipelineState.graphics.flags = p.flags;
|
||||
|
||||
// Input Assembly
|
||||
@@ -1157,13 +1191,43 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
|
||||
if(p.shaders[i].refl)
|
||||
stages[i]->reflection = p.shaders[i].refl;
|
||||
|
||||
stages[i]->specialization.resize(p.shaders[i].specialization.size());
|
||||
for(size_t s = 0; s < p.shaders[i].specialization.size(); s++)
|
||||
stages[i]->pushConstantRangeByteOffset = stages[i]->pushConstantRangeByteSize = 0;
|
||||
for(const VkPushConstantRange &pr : pl.pushRanges)
|
||||
{
|
||||
const SpecConstant &spec = p.shaders[i].specialization[s];
|
||||
stages[i]->specialization[s].specializationId = spec.specID;
|
||||
stages[i]->specialization[s].data.resize(spec.dataSize);
|
||||
memcpy(stages[i]->specialization[s].data.data(), &spec.value, spec.dataSize);
|
||||
if(pr.stageFlags & ShaderMaskFromIndex(i))
|
||||
{
|
||||
stages[i]->pushConstantRangeByteOffset = pr.offset;
|
||||
stages[i]->pushConstantRangeByteSize = pr.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stages[i]->specializationData.clear();
|
||||
|
||||
// set up the defaults
|
||||
if(p.shaders[i].mapping && p.shaders[i].refl)
|
||||
{
|
||||
for(size_t cb = 0; cb < p.shaders[i].mapping->constantBlocks.size(); cb++)
|
||||
{
|
||||
if(p.shaders[i].mapping->constantBlocks[cb].bindset == SpecializationConstantBindSet)
|
||||
{
|
||||
for(const ShaderConstant &sc : p.shaders[i].refl->constantBlocks[cb].variables)
|
||||
{
|
||||
stages[i]->specializationData.resize_for_index(sc.byteOffset + sizeof(uint64_t));
|
||||
memcpy(stages[i]->specializationData.data() + sc.byteOffset, &sc.defaultValue,
|
||||
sizeof(uint64_t));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply any specializations
|
||||
for(const SpecConstant &s : p.shaders[i].specialization)
|
||||
{
|
||||
size_t offs = s.specID * sizeof(uint64_t);
|
||||
stages[i]->specializationData.resize_for_index(offs + sizeof(uint64_t));
|
||||
memcpy(stages[i]->specializationData.data() + offs, &s.value, s.dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1600,6 +1664,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
|
||||
const uint32_t *srcOffset = (*srcs[p])[i].offsets.begin();
|
||||
VKPipe::DescriptorSet &dst = (*dsts[p])[i];
|
||||
|
||||
dst.inlineData = m_pDriver->m_DescriptorSetState[src].data.inlineBytes;
|
||||
|
||||
curBind.bindset = (uint32_t)i;
|
||||
|
||||
ResourceId layoutId = m_pDriver->m_DescriptorSetState[src].layout;
|
||||
@@ -1869,7 +1935,7 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
|
||||
dst.bindings[b].binds[a].viewResourceId = ResourceId();
|
||||
dst.bindings[b].binds[a].resourceResourceId = ResourceId();
|
||||
dst.bindings[b].binds[a].inlineBlock = true;
|
||||
dst.bindings[b].binds[a].byteOffset = 0;
|
||||
dst.bindings[b].binds[a].byteOffset = info[a].inlineOffset;
|
||||
dst.bindings[b].binds[a].byteSize = descriptorCount;
|
||||
}
|
||||
else if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
|
||||
@@ -2034,7 +2100,7 @@ void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader,
|
||||
|
||||
if(pipeIt != m_pDriver->m_CreationInfo.m_Pipeline.end())
|
||||
{
|
||||
auto specInfo =
|
||||
const rdcarray<SpecConstant> &specInfo =
|
||||
pipeIt->second.shaders[it->second.GetReflection(entryPoint, pipeline).stageIndex].specialization;
|
||||
|
||||
FillSpecConstantVariables(refl.resourceId, c.variables, outvars, specInfo);
|
||||
|
||||
@@ -215,6 +215,7 @@ void DoSerialise(SerialiserType &ser, ConstantBlock &el)
|
||||
SERIALISE_MEMBER(bindPoint);
|
||||
SERIALISE_MEMBER(byteSize);
|
||||
SERIALISE_MEMBER(bufferBacked);
|
||||
SERIALISE_MEMBER(compileConstants);
|
||||
|
||||
SIZE_CHECK(64);
|
||||
}
|
||||
@@ -1920,7 +1921,9 @@ void DoSerialise(SerialiserType &ser, VKPipe::DescriptorSet &el)
|
||||
|
||||
SERIALISE_MEMBER(bindings);
|
||||
|
||||
SIZE_CHECK(48);
|
||||
SERIALISE_MEMBER(inlineData);
|
||||
|
||||
SIZE_CHECK(72);
|
||||
}
|
||||
|
||||
template <typename SerialiserType>
|
||||
@@ -1997,15 +2000,6 @@ void DoSerialise(SerialiserType &ser, VKPipe::VertexInput &el)
|
||||
SIZE_CHECK(72);
|
||||
}
|
||||
|
||||
template <typename SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, VKPipe::SpecializationConstant &el)
|
||||
{
|
||||
SERIALISE_MEMBER(specializationId);
|
||||
SERIALISE_MEMBER(data);
|
||||
|
||||
SIZE_CHECK(32);
|
||||
}
|
||||
|
||||
template <typename SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, VKPipe::Shader &el)
|
||||
{
|
||||
@@ -2017,9 +2011,11 @@ void DoSerialise(SerialiserType &ser, VKPipe::Shader &el)
|
||||
SERIALISE_MEMBER(bindpointMapping);
|
||||
|
||||
SERIALISE_MEMBER(stage);
|
||||
SERIALISE_MEMBER(specialization);
|
||||
SERIALISE_MEMBER(pushConstantRangeByteOffset);
|
||||
SERIALISE_MEMBER(pushConstantRangeByteSize);
|
||||
SERIALISE_MEMBER(specializationData);
|
||||
|
||||
SIZE_CHECK(192);
|
||||
SIZE_CHECK(200);
|
||||
}
|
||||
|
||||
template <typename SerialiserType>
|
||||
@@ -2278,7 +2274,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::State &el)
|
||||
|
||||
SERIALISE_MEMBER(conditionalRendering);
|
||||
|
||||
SIZE_CHECK(1928);
|
||||
SIZE_CHECK(1976);
|
||||
}
|
||||
|
||||
#pragma endregion Vulkan pipeline state
|
||||
@@ -2380,7 +2376,6 @@ INSTANTIATE_SERIALISE_TYPE(VKPipe::DescriptorSet)
|
||||
INSTANTIATE_SERIALISE_TYPE(VKPipe::Pipeline)
|
||||
INSTANTIATE_SERIALISE_TYPE(VKPipe::VertexAttribute)
|
||||
INSTANTIATE_SERIALISE_TYPE(VKPipe::VertexInput)
|
||||
INSTANTIATE_SERIALISE_TYPE(VKPipe::SpecializationConstant)
|
||||
INSTANTIATE_SERIALISE_TYPE(VKPipe::Shader)
|
||||
INSTANTIATE_SERIALISE_TYPE(VKPipe::ViewState)
|
||||
INSTANTIATE_SERIALISE_TYPE(VKPipe::ColorBlendState)
|
||||
|
||||
Reference in new issue
Block a user