blob: e6a04e529692cd13a4d69c8682e7454880e6e2f0 [file] [log] [blame] [edit]
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dawn/native/BindingInfo.h"
#include <algorithm>
#include "dawn/common/MatchVariant.h"
#include "dawn/native/Adapter.h"
#include "dawn/native/ChainUtils.h"
#include "dawn/native/Limits.h"
#include "dawn/native/Sampler.h"
namespace dawn::native {
BindingInfoType GetBindingInfoType(const BindingInfo& info) {
return MatchVariant(
info.bindingLayout,
[](const BufferBindingInfo&) -> BindingInfoType { return BindingInfoType::Buffer; },
[](const SamplerBindingInfo&) -> BindingInfoType { return BindingInfoType::Sampler; },
[](const TextureBindingInfo&) -> BindingInfoType { return BindingInfoType::Texture; },
[](const StorageTextureBindingInfo&) -> BindingInfoType {
return BindingInfoType::StorageTexture;
},
[](const StaticSamplerBindingInfo&) -> BindingInfoType {
return BindingInfoType::StaticSampler;
},
[](const InputAttachmentBindingInfo&) -> BindingInfoType {
return BindingInfoType::InputAttachment;
});
}
void IncrementBindingCounts(BindingCounts* bindingCounts,
const UnpackedPtr<BindGroupLayoutEntry>& entry) {
uint32_t arraySize = std::max(1u, entry->bindingArraySize);
bindingCounts->totalCount += arraySize;
uint32_t PerStageBindingCounts::*perStageBindingCountMember = nullptr;
if (entry->buffer.type != wgpu::BufferBindingType::BindingNotUsed) {
bindingCounts->bufferCount += arraySize;
const BufferBindingLayout& buffer = entry->buffer;
if (buffer.minBindingSize == 0) {
bindingCounts->unverifiedBufferCount += arraySize;
}
switch (buffer.type) {
case wgpu::BufferBindingType::Uniform:
if (buffer.hasDynamicOffset) {
bindingCounts->dynamicUniformBufferCount += arraySize;
}
perStageBindingCountMember = &PerStageBindingCounts::uniformBufferCount;
break;
case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
case kInternalReadOnlyStorageBufferBinding:
case wgpu::BufferBindingType::ReadOnlyStorage:
if (buffer.hasDynamicOffset) {
bindingCounts->dynamicStorageBufferCount += arraySize;
}
perStageBindingCountMember = &PerStageBindingCounts::storageBufferCount;
break;
case wgpu::BufferBindingType::BindingNotUsed:
// Can't get here due to the enclosing if statement.
case wgpu::BufferBindingType::Undefined:
DAWN_UNREACHABLE();
break;
}
} else if (entry->sampler.type != wgpu::SamplerBindingType::BindingNotUsed) {
perStageBindingCountMember = &PerStageBindingCounts::samplerCount;
} else if (entry->texture.sampleType != wgpu::TextureSampleType::BindingNotUsed) {
if (entry->texture.viewDimension == kInternalInputAttachmentDim) {
// Internal use only.
return;
} else {
perStageBindingCountMember = &PerStageBindingCounts::sampledTextureCount;
}
} else if (entry->storageTexture.access != wgpu::StorageTextureAccess::BindingNotUsed) {
perStageBindingCountMember = &PerStageBindingCounts::storageTextureCount;
} else if (entry.Get<ExternalTextureBindingLayout>()) {
perStageBindingCountMember = &PerStageBindingCounts::externalTextureCount;
} else if (entry.Get<StaticSamplerBindingLayout>()) {
++bindingCounts->staticSamplerCount;
perStageBindingCountMember = &PerStageBindingCounts::staticSamplerCount;
}
DAWN_ASSERT(perStageBindingCountMember != nullptr);
for (SingleShaderStage stage : IterateStages(entry->visibility)) {
(bindingCounts->perStage[stage].*perStageBindingCountMember) += arraySize;
}
}
void AccumulateBindingCounts(BindingCounts* bindingCounts, const BindingCounts& rhs) {
bindingCounts->totalCount += rhs.totalCount;
bindingCounts->bufferCount += rhs.bufferCount;
bindingCounts->unverifiedBufferCount += rhs.unverifiedBufferCount;
bindingCounts->dynamicUniformBufferCount += rhs.dynamicUniformBufferCount;
bindingCounts->dynamicStorageBufferCount += rhs.dynamicStorageBufferCount;
for (SingleShaderStage stage : IterateStages(kAllStages)) {
bindingCounts->perStage[stage].sampledTextureCount +=
rhs.perStage[stage].sampledTextureCount;
bindingCounts->perStage[stage].samplerCount += rhs.perStage[stage].samplerCount;
bindingCounts->perStage[stage].storageBufferCount += rhs.perStage[stage].storageBufferCount;
bindingCounts->perStage[stage].storageTextureCount +=
rhs.perStage[stage].storageTextureCount;
bindingCounts->perStage[stage].uniformBufferCount += rhs.perStage[stage].uniformBufferCount;
bindingCounts->perStage[stage].externalTextureCount +=
rhs.perStage[stage].externalTextureCount;
bindingCounts->perStage[stage].staticSamplerCount += rhs.perStage[stage].staticSamplerCount;
}
}
MaybeError ValidateBindingCounts(const CombinedLimits& limits,
const BindingCounts& bindingCounts,
const AdapterBase* adapter) {
uint32_t maxDynamicUniformBuffersPerPipelineLayout =
limits.v1.maxDynamicUniformBuffersPerPipelineLayout;
DAWN_INVALID_IF(
bindingCounts.dynamicUniformBufferCount > maxDynamicUniformBuffersPerPipelineLayout,
"The number of dynamic uniform buffers (%u) exceeds the maximum per-pipeline-layout "
"limit (%u).%s",
bindingCounts.dynamicUniformBufferCount, maxDynamicUniformBuffersPerPipelineLayout,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1,
maxDynamicUniformBuffersPerPipelineLayout,
bindingCounts.dynamicUniformBufferCount));
uint32_t maxDynamicStorageBuffersPerPipelineLayout =
limits.v1.maxDynamicStorageBuffersPerPipelineLayout;
DAWN_INVALID_IF(
bindingCounts.dynamicStorageBufferCount > maxDynamicStorageBuffersPerPipelineLayout,
"The number of dynamic storage buffers (%u) exceeds the maximum per-pipeline-layout "
"limit (%u).%s",
bindingCounts.dynamicStorageBufferCount, maxDynamicStorageBuffersPerPipelineLayout,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1,
maxDynamicStorageBuffersPerPipelineLayout,
bindingCounts.dynamicStorageBufferCount));
uint32_t maxSampledTexturesPerShaderStage = limits.v1.maxSampledTexturesPerShaderStage;
uint32_t maxSamplersPerShaderStage = limits.v1.maxSamplersPerShaderStage;
uint32_t maxStorageBuffersInFragmentStage = limits.compat.maxStorageBuffersInFragmentStage;
uint32_t maxStorageBuffersInVertexStage = limits.compat.maxStorageBuffersInVertexStage;
uint32_t maxStorageBuffersPerShaderStage = limits.v1.maxStorageBuffersPerShaderStage;
uint32_t maxUniformBuffersPerShaderStage = limits.v1.maxUniformBuffersPerShaderStage;
uint32_t maxStorageTexturesInFragmentStage = limits.compat.maxStorageTexturesInFragmentStage;
uint32_t maxStorageTexturesInVertexStage = limits.compat.maxStorageTexturesInVertexStage;
uint32_t maxStorageTexturesPerShaderStage = limits.v1.maxStorageTexturesPerShaderStage;
for (SingleShaderStage stage : IterateStages(kAllStages)) {
uint32_t sampledTextureCount = bindingCounts.perStage[stage].sampledTextureCount;
DAWN_INVALID_IF(
sampledTextureCount > maxSampledTexturesPerShaderStage,
"The number of sampled textures (%u) in the %s stage exceeds the maximum "
"per-stage limit (%u).%s",
sampledTextureCount, stage, maxSampledTexturesPerShaderStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1, maxSampledTexturesPerShaderStage,
sampledTextureCount));
uint32_t externalTextureCount = bindingCounts.perStage[stage].externalTextureCount;
uint32_t sampledTextureAndExternalTextureCount =
sampledTextureCount + (externalTextureCount * kSampledTexturesPerExternalTexture);
DAWN_INVALID_IF(
sampledTextureAndExternalTextureCount > maxSampledTexturesPerShaderStage,
"The combination of sampled textures (%u) and external textures (%u × %u) in the %s "
"stage exceeds the maximum per-stage limit (%u).%s",
sampledTextureCount, externalTextureCount, kSampledTexturesPerExternalTexture, stage,
maxSampledTexturesPerShaderStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1, maxSampledTexturesPerShaderStage,
sampledTextureCount));
uint32_t samplerCount = bindingCounts.perStage[stage].samplerCount;
// TODO(crbug.com/dawn/2463): Account for static samplers here.
DAWN_INVALID_IF(
samplerCount > maxSamplersPerShaderStage,
"The number of samplers (%u) in the %s stage exceeds the maximum per-stage limit "
"(%u).%s",
samplerCount, stage, maxSamplersPerShaderStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1, maxSamplersPerShaderStage,
samplerCount));
uint32_t samplerAndExternalTextureCount =
samplerCount + (externalTextureCount * kSamplersPerExternalTexture);
// TODO(crbug.com/dawn/2463): Account for static samplers here.
DAWN_INVALID_IF(
samplerAndExternalTextureCount > maxSamplersPerShaderStage,
"The combination of samplers (%u) and external textures (%u × %u) in the %s stage "
"exceeds the maximum per-stage limit (%u).%s",
samplerCount, externalTextureCount, kSamplersPerExternalTexture, stage,
maxSamplersPerShaderStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1, maxSamplersPerShaderStage,
samplerAndExternalTextureCount));
uint32_t storageBufferCount = bindingCounts.perStage[stage].storageBufferCount;
DAWN_INVALID_IF(
storageBufferCount > maxStorageBuffersPerShaderStage,
"The number of storage buffers (%u) in the %s stage exceeds the maximum per-stage "
"limit (%u).%s",
storageBufferCount, stage, maxStorageBuffersPerShaderStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1, maxStorageBuffersPerShaderStage,
storageBufferCount));
uint32_t storageTextureCount = bindingCounts.perStage[stage].storageTextureCount;
DAWN_INVALID_IF(
storageTextureCount > maxStorageTexturesPerShaderStage,
"The number of storage textures (%u) in the %s stage exceeds the maximum per-stage "
"limit (%u).%s",
storageTextureCount, stage, maxStorageTexturesPerShaderStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1, maxStorageTexturesPerShaderStage,
storageTextureCount));
uint32_t uniformBufferCount = bindingCounts.perStage[stage].uniformBufferCount;
DAWN_INVALID_IF(
uniformBufferCount > maxUniformBuffersPerShaderStage,
"The number of uniform buffers (%u) in the %s stage exceeds the maximum per-stage "
"limit (%u).%s",
uniformBufferCount, stage, maxUniformBuffersPerShaderStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1, maxUniformBuffersPerShaderStage,
uniformBufferCount));
uint32_t uniformBuffersAndExternalTextureCount =
uniformBufferCount + (externalTextureCount * kUniformsPerExternalTexture);
DAWN_INVALID_IF(
uniformBuffersAndExternalTextureCount > maxUniformBuffersPerShaderStage,
"The combination of uniform buffers (%u) and external textures (%u × %u) in the %s "
"stage exceeds the maximum per-stage limit (%u).%s",
uniformBufferCount, externalTextureCount, kUniformsPerExternalTexture, stage,
maxUniformBuffersPerShaderStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().v1, maxUniformBuffersPerShaderStage,
uniformBuffersAndExternalTextureCount));
switch (stage) {
case SingleShaderStage::Fragment:
DAWN_INVALID_IF(storageBufferCount > maxStorageBuffersInFragmentStage,
"number of storage buffers used in fragment stage (%u) exceeds "
"maxStorageBuffersInFragmentStage (%u).%s",
storageBufferCount, maxStorageBuffersInFragmentStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().compat,
maxStorageBuffersInFragmentStage,
storageBufferCount));
DAWN_INVALID_IF(storageTextureCount > maxStorageTexturesInFragmentStage,
"number of storage textures used in fragment stage (%u) exceeds "
"maxStorageTexturesInFragmentStage (%u).%s",
storageTextureCount, maxStorageTexturesInFragmentStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().compat,
maxStorageTexturesInFragmentStage,
storageTextureCount));
break;
case SingleShaderStage::Vertex:
DAWN_INVALID_IF(storageBufferCount > maxStorageBuffersInVertexStage,
"number of storage buffers used in vertex stage (%u) exceeds "
"maxStorageBuffersInVertexStage (%u).%s",
storageBufferCount, maxStorageBuffersInVertexStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().compat,
maxStorageBuffersInVertexStage,
storageBufferCount));
DAWN_INVALID_IF(storageTextureCount > maxStorageTexturesInVertexStage,
"number of storage textures used in vertex stage (%u) exceeds "
"maxStorageTexturesInVertexStage (%u).%s",
storageTextureCount, maxStorageTexturesInVertexStage,
DAWN_INCREASE_LIMIT_MESSAGE(adapter->GetLimits().compat,
maxStorageTexturesInVertexStage,
storageTextureCount));
break;
default:
break;
}
}
return {};
}
// BufferBindingInfo
// static
BufferBindingInfo BufferBindingInfo::From(const BufferBindingLayout& layout) {
BufferBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
return {{
.type = defaultedLayout.type,
.minBindingSize = defaultedLayout.minBindingSize,
.hasDynamicOffset = defaultedLayout.hasDynamicOffset,
}};
}
// TextureBindingInfo
// static
TextureBindingInfo TextureBindingInfo::From(const TextureBindingLayout& layout) {
TextureBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
return {{
.sampleType = defaultedLayout.sampleType,
.viewDimension = defaultedLayout.viewDimension,
.multisampled = defaultedLayout.multisampled,
}};
}
// StorageTextureBindingInfo
// static
StorageTextureBindingInfo StorageTextureBindingInfo::From(
const StorageTextureBindingLayout& layout) {
StorageTextureBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
return {{
.format = defaultedLayout.format,
.viewDimension = defaultedLayout.viewDimension,
.access = defaultedLayout.access,
}};
}
// SamplerBindingInfo
// static
SamplerBindingInfo SamplerBindingInfo::From(const SamplerBindingLayout& layout) {
SamplerBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
return {{
.type = defaultedLayout.type,
}};
}
// SamplerBindingInfo
// static
StaticSamplerBindingInfo StaticSamplerBindingInfo::From(const StaticSamplerBindingLayout& layout) {
return {
.sampler = layout.sampler,
.sampledTextureBinding = BindingNumber{layout.sampledTextureBinding},
.isUsedForSingleTextureBinding = layout.sampledTextureBinding < WGPU_LIMIT_U32_UNDEFINED,
};
}
} // namespace dawn::native