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 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,
|
MaybeError ValidatePipelineLayoutDescriptor(DeviceBase* device,
|
||||||
const PipelineLayoutDescriptor* descriptor) {
|
const PipelineLayoutDescriptor* descriptor) {
|
||||||
if (descriptor->nextInChain != nullptr) {
|
if (descriptor->nextInChain != nullptr) {
|
||||||
|
@ -92,113 +78,127 @@ namespace dawn_native {
|
||||||
ResultOrError<PipelineLayoutBase*> PipelineLayoutBase::CreateDefault(
|
ResultOrError<PipelineLayoutBase*> PipelineLayoutBase::CreateDefault(
|
||||||
DeviceBase* device,
|
DeviceBase* device,
|
||||||
std::vector<StageAndDescriptor> stages) {
|
std::vector<StageAndDescriptor> stages) {
|
||||||
ASSERT(!stages.empty());
|
using EntryMap = std::map<BindingNumber, BindGroupLayoutEntry>;
|
||||||
|
|
||||||
// Data which BindGroupLayoutDescriptor will point to for creation
|
// Merges two entries at the same location, if they are allowed to be merged.
|
||||||
ityp::array<
|
auto MergeEntries = [](BindGroupLayoutEntry* modifiedEntry,
|
||||||
BindGroupIndex,
|
const BindGroupLayoutEntry& mergedEntry) -> MaybeError {
|
||||||
ityp::stack_vec<BindingIndex, BindGroupLayoutEntry, kMaxOptimalBindingsPerGroup>,
|
// Minimum buffer binding size excluded because we take the maximum seen across stages.
|
||||||
kMaxBindGroups>
|
// Visibility is excluded because we take the OR across stages.
|
||||||
entryData = {};
|
bool compatible =
|
||||||
|
modifiedEntry->binding == mergedEntry.binding && //
|
||||||
// A map of bindings to the index in |entryData|
|
modifiedEntry->type == mergedEntry.type && //
|
||||||
ityp::array<BindGroupIndex, std::map<BindingNumber, BindingIndex>, kMaxBindGroups>
|
modifiedEntry->hasDynamicOffset == mergedEntry.hasDynamicOffset && //
|
||||||
usedBindingsMap = {};
|
modifiedEntry->multisampled == mergedEntry.multisampled && //
|
||||||
|
modifiedEntry->viewDimension == mergedEntry.viewDimension && //
|
||||||
// A counter of how many bindings we've populated in |entryData|
|
modifiedEntry->textureComponentType == mergedEntry.textureComponentType;
|
||||||
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];
|
|
||||||
|
|
||||||
// Check if any properties are incompatible with existing entry
|
// Check if any properties are incompatible with existing entry
|
||||||
// If compatible, we will merge some properties
|
// If compatible, we will merge some properties
|
||||||
if (!InferredBindGroupLayoutEntriesCompatible(*existingEntry,
|
if (!compatible) {
|
||||||
bindingSlot)) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"Duplicate binding in default pipeline layout initialization "
|
"Duplicate binding in default pipeline layout initialization "
|
||||||
"not compatible with previous declaration");
|
"not compatible with previous declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the max |minBufferBindingSize| we find.
|
// Use the max |minBufferBindingSize| we find.
|
||||||
existingEntry->minBufferBindingSize =
|
modifiedEntry->minBufferBindingSize =
|
||||||
std::max(existingEntry->minBufferBindingSize,
|
std::max(modifiedEntry->minBufferBindingSize, mergedEntry.minBufferBindingSize);
|
||||||
bindingSlot.minBufferBindingSize);
|
|
||||||
|
|
||||||
// Use the OR of all the stages at which we find this binding.
|
// 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
|
return {};
|
||||||
continue;
|
};
|
||||||
}
|
|
||||||
|
// 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 = {};
|
BindGroupLayoutDescriptor desc = {};
|
||||||
desc.entries = entryData[group].data();
|
desc.entries = entryVec.data();
|
||||||
desc.entryCount = static_cast<uint32_t>(entryCounts[group]);
|
desc.entryCount = entryVec.size();
|
||||||
|
|
||||||
DAWN_TRY(ValidateBindGroupLayoutDescriptor(device, &desc));
|
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.
|
// Create the deduced pipeline layout, validating if it is valid.
|
||||||
PipelineLayoutBase* pipelineLayout = nullptr;
|
PipelineLayoutBase* pipelineLayout = nullptr;
|
||||||
{
|
{
|
||||||
ityp::array<BindGroupIndex, BindGroupLayoutBase*, kMaxBindGroups> bgls = {};
|
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();
|
bgls[group] = bindGroupLayouts[group].Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
PipelineLayoutDescriptor desc = {};
|
PipelineLayoutDescriptor desc = {};
|
||||||
desc.bindGroupLayouts = bgls.data();
|
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(ValidatePipelineLayoutDescriptor(device, &desc));
|
||||||
DAWN_TRY_ASSIGN(pipelineLayout, device->GetOrCreatePipelineLayout(&desc));
|
DAWN_TRY_ASSIGN(pipelineLayout, device->GetOrCreatePipelineLayout(&desc));
|
||||||
|
|
Loading…
Reference in New Issue