Refactor PipelineLayoutBase::CreateDefault
This function was bit long and was difficult to read. Refactor it to use a single double keyed map and helper functions. Bug: dawn:527 Change-Id: I8c1173fd0e06256c7e7060a850996e1e90187d50 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/28640 Reviewed-by: Stephen White <senorblanco@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
75e5ed6161
commit
ed0b3cf153
|
@ -24,20 +24,6 @@
|
|||
|
||||
namespace dawn_native {
|
||||
|
||||
namespace {
|
||||
|
||||
bool InferredBindGroupLayoutEntriesCompatible(const BindGroupLayoutEntry& lhs,
|
||||
const BindGroupLayoutEntry& rhs) {
|
||||
// Minimum buffer binding size excluded because we take the maximum seen across stages.
|
||||
// Visibility is excluded because we take the OR across stages.
|
||||
return lhs.binding == rhs.binding && lhs.type == rhs.type &&
|
||||
lhs.hasDynamicOffset == rhs.hasDynamicOffset &&
|
||||
lhs.multisampled == rhs.multisampled && lhs.viewDimension == rhs.viewDimension &&
|
||||
lhs.textureComponentType == rhs.textureComponentType;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
MaybeError ValidatePipelineLayoutDescriptor(DeviceBase* device,
|
||||
const PipelineLayoutDescriptor* descriptor) {
|
||||
if (descriptor->nextInChain != nullptr) {
|
||||
|
@ -92,113 +78,127 @@ namespace dawn_native {
|
|||
ResultOrError<PipelineLayoutBase*> PipelineLayoutBase::CreateDefault(
|
||||
DeviceBase* device,
|
||||
std::vector<StageAndDescriptor> stages) {
|
||||
ASSERT(!stages.empty());
|
||||
using EntryMap = std::map<BindingNumber, BindGroupLayoutEntry>;
|
||||
|
||||
// Data which BindGroupLayoutDescriptor will point to for creation
|
||||
ityp::array<
|
||||
BindGroupIndex,
|
||||
ityp::stack_vec<BindingIndex, BindGroupLayoutEntry, kMaxOptimalBindingsPerGroup>,
|
||||
kMaxBindGroups>
|
||||
entryData = {};
|
||||
|
||||
// A map of bindings to the index in |entryData|
|
||||
ityp::array<BindGroupIndex, std::map<BindingNumber, BindingIndex>, kMaxBindGroups>
|
||||
usedBindingsMap = {};
|
||||
|
||||
// A counter of how many bindings we've populated in |entryData|
|
||||
ityp::array<BindGroupIndex, BindingIndex, kMaxBindGroups> entryCounts = {};
|
||||
|
||||
BindingCounts bindingCounts = {};
|
||||
BindGroupIndex bindGroupLayoutCount(0);
|
||||
for (const StageAndDescriptor& stage : stages) {
|
||||
// Extract argument for this stage.
|
||||
SingleShaderStage shaderStage = stage.first;
|
||||
const EntryPointMetadata::BindingInfo& info =
|
||||
stage.second->module->GetEntryPoint(stage.second->entryPoint, shaderStage).bindings;
|
||||
|
||||
for (BindGroupIndex group(0); group < info.size(); ++group) {
|
||||
for (const auto& it : info[group]) {
|
||||
BindingNumber bindingNumber = it.first;
|
||||
const EntryPointMetadata::ShaderBindingInfo& bindingInfo = it.second;
|
||||
|
||||
BindGroupLayoutEntry bindingSlot;
|
||||
bindingSlot.binding = static_cast<uint32_t>(bindingNumber);
|
||||
bindingSlot.visibility = StageBit(shaderStage);
|
||||
bindingSlot.type = bindingInfo.type;
|
||||
bindingSlot.hasDynamicOffset = false;
|
||||
bindingSlot.multisampled = bindingInfo.multisampled;
|
||||
bindingSlot.viewDimension = bindingInfo.viewDimension;
|
||||
bindingSlot.textureComponentType =
|
||||
Format::FormatTypeToTextureComponentType(bindingInfo.textureComponentType);
|
||||
bindingSlot.storageTextureFormat = bindingInfo.storageTextureFormat;
|
||||
bindingSlot.minBufferBindingSize = bindingInfo.minBufferBindingSize;
|
||||
|
||||
{
|
||||
const auto& it = usedBindingsMap[group].find(bindingNumber);
|
||||
if (it != usedBindingsMap[group].end()) {
|
||||
BindGroupLayoutEntry* existingEntry = &entryData[group][it->second];
|
||||
// Merges two entries at the same location, if they are allowed to be merged.
|
||||
auto MergeEntries = [](BindGroupLayoutEntry* modifiedEntry,
|
||||
const BindGroupLayoutEntry& mergedEntry) -> MaybeError {
|
||||
// Minimum buffer binding size excluded because we take the maximum seen across stages.
|
||||
// Visibility is excluded because we take the OR across stages.
|
||||
bool compatible =
|
||||
modifiedEntry->binding == mergedEntry.binding && //
|
||||
modifiedEntry->type == mergedEntry.type && //
|
||||
modifiedEntry->hasDynamicOffset == mergedEntry.hasDynamicOffset && //
|
||||
modifiedEntry->multisampled == mergedEntry.multisampled && //
|
||||
modifiedEntry->viewDimension == mergedEntry.viewDimension && //
|
||||
modifiedEntry->textureComponentType == mergedEntry.textureComponentType;
|
||||
|
||||
// Check if any properties are incompatible with existing entry
|
||||
// If compatible, we will merge some properties
|
||||
if (!InferredBindGroupLayoutEntriesCompatible(*existingEntry,
|
||||
bindingSlot)) {
|
||||
if (!compatible) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Duplicate binding in default pipeline layout initialization "
|
||||
"not compatible with previous declaration");
|
||||
}
|
||||
|
||||
// Use the max |minBufferBindingSize| we find.
|
||||
existingEntry->minBufferBindingSize =
|
||||
std::max(existingEntry->minBufferBindingSize,
|
||||
bindingSlot.minBufferBindingSize);
|
||||
modifiedEntry->minBufferBindingSize =
|
||||
std::max(modifiedEntry->minBufferBindingSize, mergedEntry.minBufferBindingSize);
|
||||
|
||||
// Use the OR of all the stages at which we find this binding.
|
||||
existingEntry->visibility |= bindingSlot.visibility;
|
||||
modifiedEntry->visibility |= mergedEntry.visibility;
|
||||
|
||||
// Already used slot, continue
|
||||
continue;
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
// Does the trivial conversions from a ShaderBindingInfo to a BindGroupLayoutEntry
|
||||
auto ConvertMetadataToEntry =
|
||||
[](const EntryPointMetadata::ShaderBindingInfo& shaderBinding) -> BindGroupLayoutEntry {
|
||||
BindGroupLayoutEntry entry = {};
|
||||
entry.type = shaderBinding.type;
|
||||
entry.hasDynamicOffset = false;
|
||||
entry.multisampled = shaderBinding.multisampled;
|
||||
entry.viewDimension = shaderBinding.viewDimension;
|
||||
entry.textureComponentType =
|
||||
Format::FormatTypeToTextureComponentType(shaderBinding.textureComponentType);
|
||||
entry.storageTextureFormat = shaderBinding.storageTextureFormat;
|
||||
entry.minBufferBindingSize = shaderBinding.minBufferBindingSize;
|
||||
return entry;
|
||||
};
|
||||
|
||||
// Creates the BGL from the entries for a stage, checking it is valid.
|
||||
auto CreateBGL = [](DeviceBase* device,
|
||||
const EntryMap& entries) -> ResultOrError<Ref<BindGroupLayoutBase>> {
|
||||
std::vector<BindGroupLayoutEntry> entryVec;
|
||||
entryVec.reserve(entries.size());
|
||||
for (auto& it : entries) {
|
||||
entryVec.push_back(it.second);
|
||||
}
|
||||
|
||||
IncrementBindingCounts(&bindingCounts, bindingSlot);
|
||||
BindingIndex currentBindingCount = entryCounts[group];
|
||||
entryData[group].resize(currentBindingCount + BindingIndex(1));
|
||||
entryData[group][currentBindingCount] = bindingSlot;
|
||||
|
||||
usedBindingsMap[group][bindingNumber] = currentBindingCount;
|
||||
|
||||
entryCounts[group]++;
|
||||
|
||||
bindGroupLayoutCount =
|
||||
std::max(bindGroupLayoutCount, group + BindGroupIndex(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the deduced BGLs, validating if they are valid.
|
||||
ityp::array<BindGroupIndex, Ref<BindGroupLayoutBase>, kMaxBindGroups> bindGroupLayouts = {};
|
||||
for (BindGroupIndex group(0); group < bindGroupLayoutCount; ++group) {
|
||||
BindGroupLayoutDescriptor desc = {};
|
||||
desc.entries = entryData[group].data();
|
||||
desc.entryCount = static_cast<uint32_t>(entryCounts[group]);
|
||||
desc.entries = entryVec.data();
|
||||
desc.entryCount = entryVec.size();
|
||||
|
||||
DAWN_TRY(ValidateBindGroupLayoutDescriptor(device, &desc));
|
||||
DAWN_TRY_ASSIGN(bindGroupLayouts[group], device->GetOrCreateBindGroupLayout(&desc));
|
||||
return device->GetOrCreateBindGroupLayout(&desc);
|
||||
};
|
||||
|
||||
ASSERT(!bindGroupLayouts[group]->IsError());
|
||||
ASSERT(!stages.empty());
|
||||
|
||||
// Data which BindGroupLayoutDescriptor will point to for creation
|
||||
ityp::array<BindGroupIndex, std::map<BindingNumber, BindGroupLayoutEntry>, kMaxBindGroups>
|
||||
entryData = {};
|
||||
|
||||
// Loops over all the reflected BindGroupLayoutEntries from shaders.
|
||||
for (const StageAndDescriptor& stage : stages) {
|
||||
SingleShaderStage shaderStage = stage.first;
|
||||
const EntryPointMetadata::BindingInfo& info =
|
||||
stage.second->module->GetEntryPoint(stage.second->entryPoint, shaderStage).bindings;
|
||||
|
||||
for (BindGroupIndex group(0); group < info.size(); ++group) {
|
||||
for (const auto& bindingIt : info[group]) {
|
||||
BindingNumber bindingNumber = bindingIt.first;
|
||||
const EntryPointMetadata::ShaderBindingInfo& shaderBinding = bindingIt.second;
|
||||
|
||||
// Create the BindGroupLayoutEntry
|
||||
BindGroupLayoutEntry entry = ConvertMetadataToEntry(shaderBinding);
|
||||
entry.binding = static_cast<uint32_t>(bindingNumber);
|
||||
entry.visibility = StageBit(shaderStage);
|
||||
|
||||
// Add it to our map of all entries, if there is an existing entry, then we
|
||||
// need to merge, if we can.
|
||||
const auto& insertion = entryData[group].insert({bindingNumber, entry});
|
||||
if (!insertion.second) {
|
||||
DAWN_TRY(MergeEntries(&insertion.first->second, entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the bind group layouts. We need to keep track of the last non-empty BGL because
|
||||
// Dawn doesn't yet know that an empty BGL and a null BGL are the same thing.
|
||||
// TODO(cwallez@chromium.org): remove this when Dawn knows that empty and null BGL are the
|
||||
// same.
|
||||
BindGroupIndex pipelineBGLCount = BindGroupIndex(0);
|
||||
ityp::array<BindGroupIndex, Ref<BindGroupLayoutBase>, kMaxBindGroups> bindGroupLayouts = {};
|
||||
for (BindGroupIndex group(0); group < kMaxBindGroupsTyped; ++group) {
|
||||
DAWN_TRY_ASSIGN(bindGroupLayouts[group], CreateBGL(device, entryData[group]));
|
||||
if (entryData[group].size() != 0) {
|
||||
pipelineBGLCount = group + BindGroupIndex(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the deduced pipeline layout, validating if it is valid.
|
||||
PipelineLayoutBase* pipelineLayout = nullptr;
|
||||
{
|
||||
ityp::array<BindGroupIndex, BindGroupLayoutBase*, kMaxBindGroups> bgls = {};
|
||||
for (BindGroupIndex group(0); group < bindGroupLayoutCount; ++group) {
|
||||
for (BindGroupIndex group(0); group < pipelineBGLCount; ++group) {
|
||||
bgls[group] = bindGroupLayouts[group].Get();
|
||||
}
|
||||
|
||||
PipelineLayoutDescriptor desc = {};
|
||||
desc.bindGroupLayouts = bgls.data();
|
||||
desc.bindGroupLayoutCount = static_cast<uint32_t>(bindGroupLayoutCount);
|
||||
desc.bindGroupLayoutCount = static_cast<uint32_t>(pipelineBGLCount);
|
||||
|
||||
DAWN_TRY(ValidatePipelineLayoutDescriptor(device, &desc));
|
||||
DAWN_TRY_ASSIGN(pipelineLayout, device->GetOrCreatePipelineLayout(&desc));
|
||||
|
|
Loading…
Reference in New Issue