Generate baked per-pipeline static descriptor access on Vulkan

This commit is contained in:
baldurk
2024-03-07 15:59:13 +00:00
parent 58c3dc52a7
commit 50091dcffc
8 changed files with 178 additions and 2 deletions
+6 -1
View File
@@ -1242,7 +1242,8 @@ struct ShaderResource
bool operator==(const ShaderResource &o) const
{
return resType == o.resType && name == o.name && variableType == o.variableType &&
bindPoint == o.bindPoint && isTexture == o.isTexture && isReadOnly == o.isReadOnly;
bindPoint == o.bindPoint && isTexture == o.isTexture && hasSampler == o.hasSampler &&
isReadOnly == o.isReadOnly;
}
bool operator<(const ShaderResource &o) const
{
@@ -1256,6 +1257,8 @@ struct ShaderResource
return bindPoint < o.bindPoint;
if(!(isTexture == o.isTexture))
return isTexture < o.isTexture;
if(!(hasSampler == o.hasSampler))
return hasSampler < o.hasSampler;
if(!(isReadOnly == o.isReadOnly))
return isReadOnly < o.isReadOnly;
return false;
@@ -1280,6 +1283,8 @@ struct ShaderResource
DOCUMENT("``True`` if this resource is a texture, otherwise it is a buffer.");
bool isTexture;
DOCUMENT("``True`` if this texture resource has a sampler as well.");
bool hasSampler = false;
DOCUMENT(R"(``True`` if this resource is available to the shader for reading only, otherwise it is
able to be read from and written to arbitrarily.
)");
+2
View File
@@ -1757,6 +1757,8 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref
continue;
}
res.hasSampler = res.isReadOnly;
char *namebuf = new char[values[1] + 1];
GL.glGetProgramResourceName(sepProg, eGL_UNIFORM, u, values[1], NULL, namebuf);
namebuf[values[1]] = 0;
@@ -1437,7 +1437,10 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
Id imageTypeId = varType->id;
if(varType->type == DataType::SampledImageType)
{
imageTypeId = sampledImageTypes[varType->id].baseId;
res.hasSampler = true;
}
const Image &imageType = imageTypes[imageTypeId];
+2
View File
@@ -566,6 +566,8 @@ VkShaderStageFlags ShaderMaskFromIndex(size_t index)
VK_SHADER_STAGE_MESH_BIT_EXT,
};
RDCCOMPILE_ASSERT(ARRAY_COUNT(mask) == NumShaderStages, "Array is out of date");
if(index < ARRAY_COUNT(mask))
return mask[index];
+119
View File
@@ -817,6 +817,111 @@ bool CreateDescriptorWritesForSlotData(WrappedVulkan *vk, rdcarray<VkWriteDescri
return ret;
}
void VulkanCreationInfo::Pipeline::Shader::ProcessStaticDescriptorAccess(
rdcarray<DescriptorAccess> &staticDescriptorAccess,
rdcarray<const DescSetLayout *> setLayoutInfos) const
{
if(!refl)
return;
DescriptorAccess access;
access.stage = refl->stage;
// we will store the descriptor set in byteSize to be decoded into descriptorStore later
access.byteSize = 0;
staticDescriptorAccess.reserve(staticDescriptorAccess.size() + mapping->constantBlocks.size() +
mapping->samplers.size() + mapping->readOnlyResources.size() +
mapping->readWriteResources.size());
RDCASSERT(mapping->constantBlocks.size() < 0xffff, mapping->constantBlocks.size());
for(uint16_t i = 0; i < mapping->constantBlocks.size(); i++)
{
const Bindpoint &bind = mapping->constantBlocks[i];
// arrayed descriptors will be handled with bindless feedback
if(bind.arraySize > 1)
continue;
access.staticallyUnused = !bind.used;
access.type = DescriptorType::ConstantBuffer;
access.index = i;
if(bind.bindset == PushConstantBindSet)
{
access.byteSize = bind.bindset;
access.byteOffset = 0;
staticDescriptorAccess.push_back(access);
}
else if(bind.bindset == SpecializationConstantBindSet)
{
access.byteSize = bind.bindset;
access.byteOffset = 0;
staticDescriptorAccess.push_back(access);
}
else
{
access.byteSize = bind.bindset;
access.byteOffset = setLayoutInfos[bind.bindset]->bindings[bind.bind].elemOffset;
staticDescriptorAccess.push_back(access);
}
}
RDCASSERT(mapping->samplers.size() < 0xffff, mapping->samplers.size());
for(uint16_t i = 0; i < mapping->samplers.size(); i++)
{
const Bindpoint &bind = mapping->samplers[i];
// arrayed descriptors will be handled with bindless feedback
if(bind.arraySize > 1)
continue;
access.staticallyUnused = !bind.used;
access.type = DescriptorType::Sampler;
access.index = i;
access.byteSize = bind.bindset;
access.byteOffset = setLayoutInfos[bind.bindset]->bindings[bind.bind].elemOffset;
staticDescriptorAccess.push_back(access);
}
RDCASSERT(mapping->readOnlyResources.size() < 0xffff, mapping->readOnlyResources.size());
for(uint16_t i = 0; i < mapping->readOnlyResources.size(); i++)
{
const Bindpoint &bind = mapping->readOnlyResources[i];
// arrayed descriptors will be handled with bindless feedback
if(bind.arraySize > 1)
continue;
access.staticallyUnused = !bind.used;
access.type = DescriptorType::Image;
if(!refl->readOnlyResources[i].isTexture)
access.type = DescriptorType::TypedBuffer;
if(refl->readOnlyResources[i].hasSampler)
access.type = DescriptorType::ImageSampler;
access.index = i;
access.byteSize = bind.bindset;
access.byteOffset = setLayoutInfos[bind.bindset]->bindings[bind.bind].elemOffset;
staticDescriptorAccess.push_back(access);
}
RDCASSERT(mapping->readWriteResources.size() < 0xffff, mapping->readWriteResources.size());
for(uint16_t i = 0; i < mapping->readWriteResources.size(); i++)
{
const Bindpoint &bind = mapping->readWriteResources[i];
// arrayed descriptors will be handled with bindless feedback
if(bind.arraySize > 1)
continue;
access.staticallyUnused = !bind.used;
access.type = DescriptorType::ReadWriteImage;
if(!refl->readWriteResources[i].isTexture)
access.type = DescriptorType::ReadWriteBuffer;
access.index = i;
access.byteSize = bind.bindset;
access.byteOffset = setLayoutInfos[bind.bindset]->bindings[bind.bind].elemOffset;
staticDescriptorAccess.push_back(access);
}
}
void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan,
VulkanCreationInfo &info, ResourceId id,
const VkGraphicsPipelineCreateInfo *pCreateInfo)
@@ -1487,6 +1592,13 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan,
}
}
}
rdcarray<const DescSetLayout *> setLayoutInfos;
for(ResourceId setLayout : descSetLayouts)
setLayoutInfos.push_back(&info.m_DescSetLayout[setLayout]);
for(const Shader &shad : shaders)
shad.ProcessStaticDescriptorAccess(staticDescriptorAccess, setLayoutInfos);
}
void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info,
@@ -1585,6 +1697,13 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk
alphaToCoverageEnable = false;
logicOpEnable = false;
logicOp = VK_LOGIC_OP_NO_OP;
rdcarray<const DescSetLayout *> setLayoutInfos;
for(ResourceId setLayout : descSetLayouts)
setLayoutInfos.push_back(&info.m_DescSetLayout[setLayout]);
for(const Shader &shad : shaders)
shad.ProcessStaticDescriptorAccess(staticDescriptorAccess, setLayoutInfos);
}
void VulkanCreationInfo::PipelineLayout::Init(VulkanResourceManager *resourceMan,
+5
View File
@@ -275,9 +275,14 @@ struct VulkanCreationInfo
// VkPipelineShaderStageRequiredSubgroupSizeCreateInfo
uint32_t requiredSubgroupSize = 0;
void ProcessStaticDescriptorAccess(rdcarray<DescriptorAccess> &staticDescriptorAccess,
rdcarray<const DescSetLayout *> setLayoutInfos) const;
};
Shader shaders[NumShaderStages];
rdcarray<DescriptorAccess> staticDescriptorAccess;
// VkPipelineVertexInputStateCreateInfo
struct VertBinding
{
+40 -1
View File
@@ -2607,7 +2607,46 @@ rdcarray<SamplerDescriptor> VulkanReplay::GetSamplerDescriptors(ResourceId descr
rdcarray<DescriptorAccess> VulkanReplay::GetDescriptorAccess()
{
return {};
VulkanResourceManager *rm = m_pDriver->GetResourceManager();
const VulkanRenderState &state = m_pDriver->m_RenderState;
rdcarray<DescriptorAccess> ret;
if(state.graphics.pipeline != ResourceId())
ret.append(m_pDriver->m_CreationInfo.m_Pipeline[state.graphics.pipeline].staticDescriptorAccess);
if(state.compute.pipeline != ResourceId())
ret.append(m_pDriver->m_CreationInfo.m_Pipeline[state.compute.pipeline].staticDescriptorAccess);
for(DescriptorAccess &access : ret)
{
uint32_t bindset = (uint32_t)access.byteSize;
access.byteSize = 1;
if(bindset == PushConstantBindSet || bindset == SpecializationConstantBindSet)
{
// TODO
}
else
{
const rdcarray<VulkanStatePipeline::DescriptorAndOffsets> &descSets =
access.stage == ShaderStage::Compute ? state.compute.descSets : state.graphics.descSets;
if(bindset >= descSets.size())
{
RDCERR("Unbound descriptor set referenced in static usage");
}
else
{
access.descriptorStore = rm->GetOriginalID(descSets[bindset].descSet);
}
}
if(access.descriptorStore == ResourceId())
access = DescriptorAccess();
}
return ret;
}
void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, ShaderStage stage,
+1
View File
@@ -222,6 +222,7 @@ void DoSerialise(SerialiserType &ser, ShaderResource &el)
SERIALISE_MEMBER(variableType);
SERIALISE_MEMBER(bindPoint);
SERIALISE_MEMBER(isTexture);
SERIALISE_MEMBER(hasSampler);
SERIALISE_MEMBER(isReadOnly);
SIZE_CHECK(112);