Separate entry point reflection in its own function.
This allows adding as an error context the name of the entry point, and dedents the code a little bit. Bug: dawn:563 Change-Id: I1ea9760fc1aca506826ca7ef5a65d40f8370136d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/85500 Auto-Submit: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Brandon Jones <bajones@chromium.org> Commit-Queue: Brandon Jones <bajones@chromium.org>
This commit is contained in:
parent
705b6e3d08
commit
595e20085d
|
@ -130,6 +130,8 @@ namespace dawn::native {
|
||||||
// DAWN_TRY_ASSIGN is the same as DAWN_TRY for ResultOrError and assigns the success value, if
|
// DAWN_TRY_ASSIGN is the same as DAWN_TRY for ResultOrError and assigns the success value, if
|
||||||
// any, to VAR.
|
// any, to VAR.
|
||||||
#define DAWN_TRY_ASSIGN(VAR, EXPR) DAWN_TRY_ASSIGN_WITH_CLEANUP(VAR, EXPR, {})
|
#define DAWN_TRY_ASSIGN(VAR, EXPR) DAWN_TRY_ASSIGN_WITH_CLEANUP(VAR, EXPR, {})
|
||||||
|
#define DAWN_TRY_ASSIGN_CONTEXT(VAR, EXPR, ...) \
|
||||||
|
DAWN_TRY_ASSIGN_WITH_CLEANUP(VAR, EXPR, { error->AppendContext(absl::StrFormat(__VA_ARGS__)); })
|
||||||
|
|
||||||
// Argument helpers are used to determine which macro implementations should be called when
|
// Argument helpers are used to determine which macro implementations should be called when
|
||||||
// overloading with different number of variables.
|
// overloading with different number of variables.
|
||||||
|
|
|
@ -374,9 +374,8 @@ namespace dawn::native {
|
||||||
return EntryPointMetadata::OverridableConstant::Type::Int32;
|
return EntryPointMetadata::OverridableConstant::Type::Int32;
|
||||||
case tint::inspector::OverridableConstant::Type::kUint32:
|
case tint::inspector::OverridableConstant::Type::kUint32:
|
||||||
return EntryPointMetadata::OverridableConstant::Type::Uint32;
|
return EntryPointMetadata::OverridableConstant::Type::Uint32;
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultOrError<tint::Program> ParseWGSL(const tint::Source::File* file,
|
ResultOrError<tint::Program> ParseWGSL(const tint::Source::File* file,
|
||||||
|
@ -598,351 +597,347 @@ namespace dawn::native {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
|
||||||
|
const DeviceBase* device,
|
||||||
|
tint::inspector::Inspector* inspector,
|
||||||
|
const tint::inspector::EntryPoint& entryPoint) {
|
||||||
|
const CombinedLimits& limits = device->GetLimits();
|
||||||
|
constexpr uint32_t kMaxInterStageShaderLocation = kMaxInterStageShaderVariables - 1;
|
||||||
|
|
||||||
|
std::unique_ptr<EntryPointMetadata> metadata = std::make_unique<EntryPointMetadata>();
|
||||||
|
|
||||||
|
if (!entryPoint.overridable_constants.empty()) {
|
||||||
|
DAWN_INVALID_IF(device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs),
|
||||||
|
"Pipeline overridable constants are disallowed because they "
|
||||||
|
"are partially implemented.");
|
||||||
|
|
||||||
|
const auto& name2Id = inspector->GetConstantNameToIdMap();
|
||||||
|
const auto& id2Scalar = inspector->GetConstantIDs();
|
||||||
|
|
||||||
|
for (auto& c : entryPoint.overridable_constants) {
|
||||||
|
uint32_t id = name2Id.at(c.name);
|
||||||
|
OverridableConstantScalar defaultValue;
|
||||||
|
if (c.is_initialized) {
|
||||||
|
// if it is initialized, the scalar must exist
|
||||||
|
const auto& scalar = id2Scalar.at(id);
|
||||||
|
if (scalar.IsBool()) {
|
||||||
|
defaultValue.b = scalar.AsBool();
|
||||||
|
} else if (scalar.IsU32()) {
|
||||||
|
defaultValue.u32 = scalar.AsU32();
|
||||||
|
} else if (scalar.IsI32()) {
|
||||||
|
defaultValue.i32 = scalar.AsI32();
|
||||||
|
} else if (scalar.IsFloat()) {
|
||||||
|
defaultValue.f32 = scalar.AsFloat();
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntryPointMetadata::OverridableConstant constant = {
|
||||||
|
id, FromTintOverridableConstantType(c.type), c.is_initialized,
|
||||||
|
defaultValue};
|
||||||
|
|
||||||
|
std::string identifier =
|
||||||
|
c.is_numeric_id_specified ? std::to_string(constant.id) : c.name;
|
||||||
|
metadata->overridableConstants[identifier] = constant;
|
||||||
|
|
||||||
|
if (!c.is_initialized) {
|
||||||
|
auto [_, inserted] = metadata->uninitializedOverridableConstants.emplace(
|
||||||
|
std::move(identifier));
|
||||||
|
// The insertion should have taken place
|
||||||
|
ASSERT(inserted);
|
||||||
|
} else {
|
||||||
|
auto [_, inserted] = metadata->initializedOverridableConstants.emplace(
|
||||||
|
std::move(identifier));
|
||||||
|
// The insertion should have taken place
|
||||||
|
ASSERT(inserted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY_ASSIGN(metadata->stage, TintPipelineStageToShaderStage(entryPoint.stage));
|
||||||
|
|
||||||
|
if (metadata->stage == SingleShaderStage::Compute) {
|
||||||
|
DAWN_INVALID_IF(
|
||||||
|
entryPoint.workgroup_size_x > limits.v1.maxComputeWorkgroupSizeX ||
|
||||||
|
entryPoint.workgroup_size_y > limits.v1.maxComputeWorkgroupSizeY ||
|
||||||
|
entryPoint.workgroup_size_z > limits.v1.maxComputeWorkgroupSizeZ,
|
||||||
|
"Entry-point uses workgroup_size(%u, %u, %u) that exceeds the "
|
||||||
|
"maximum allowed (%u, %u, %u).",
|
||||||
|
entryPoint.workgroup_size_x, entryPoint.workgroup_size_y,
|
||||||
|
entryPoint.workgroup_size_z, limits.v1.maxComputeWorkgroupSizeX,
|
||||||
|
limits.v1.maxComputeWorkgroupSizeY, limits.v1.maxComputeWorkgroupSizeZ);
|
||||||
|
|
||||||
|
// Dimensions have already been validated against their individual limits above.
|
||||||
|
// Cast to uint64_t to avoid overflow in this multiplication.
|
||||||
|
uint64_t numInvocations = static_cast<uint64_t>(entryPoint.workgroup_size_x) *
|
||||||
|
entryPoint.workgroup_size_y * entryPoint.workgroup_size_z;
|
||||||
|
DAWN_INVALID_IF(numInvocations > limits.v1.maxComputeInvocationsPerWorkgroup,
|
||||||
|
"The total number of workgroup invocations (%u) exceeds the "
|
||||||
|
"maximum allowed (%u).",
|
||||||
|
numInvocations, limits.v1.maxComputeInvocationsPerWorkgroup);
|
||||||
|
|
||||||
|
const size_t workgroupStorageSize =
|
||||||
|
inspector->GetWorkgroupStorageSize(entryPoint.name);
|
||||||
|
DAWN_INVALID_IF(workgroupStorageSize > limits.v1.maxComputeWorkgroupStorageSize,
|
||||||
|
"The total use of workgroup storage (%u bytes) is larger than "
|
||||||
|
"the maximum allowed (%u bytes).",
|
||||||
|
workgroupStorageSize, limits.v1.maxComputeWorkgroupStorageSize);
|
||||||
|
|
||||||
|
metadata->localWorkgroupSize.x = entryPoint.workgroup_size_x;
|
||||||
|
metadata->localWorkgroupSize.y = entryPoint.workgroup_size_y;
|
||||||
|
metadata->localWorkgroupSize.z = entryPoint.workgroup_size_z;
|
||||||
|
|
||||||
|
metadata->usesNumWorkgroups = entryPoint.num_workgroups_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata->stage == SingleShaderStage::Vertex) {
|
||||||
|
for (const auto& inputVar : entryPoint.input_variables) {
|
||||||
|
DAWN_INVALID_IF(
|
||||||
|
!inputVar.has_location_decoration,
|
||||||
|
"Vertex input variable \"%s\" doesn't have a location decoration.",
|
||||||
|
inputVar.name);
|
||||||
|
|
||||||
|
uint32_t unsanitizedLocation = inputVar.location_decoration;
|
||||||
|
DAWN_INVALID_IF(unsanitizedLocation >= kMaxVertexAttributes,
|
||||||
|
"Vertex input variable \"%s\" has a location (%u) that "
|
||||||
|
"exceeds the maximum (%u)",
|
||||||
|
inputVar.name, unsanitizedLocation, kMaxVertexAttributes);
|
||||||
|
VertexAttributeLocation location(static_cast<uint8_t>(unsanitizedLocation));
|
||||||
|
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
metadata->vertexInputBaseTypes[location],
|
||||||
|
TintComponentTypeToVertexFormatBaseType(inputVar.component_type));
|
||||||
|
metadata->usedVertexInputs.set(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [[position]] must be declared in a vertex shader but is not exposed as an
|
||||||
|
// output variable by Tint so we directly add its components to the total.
|
||||||
|
uint32_t totalInterStageShaderComponents = 4;
|
||||||
|
for (const auto& outputVar : entryPoint.output_variables) {
|
||||||
|
DAWN_INVALID_IF(
|
||||||
|
!outputVar.has_location_decoration,
|
||||||
|
"Vertex ouput variable \"%s\" doesn't have a location decoration.",
|
||||||
|
outputVar.name);
|
||||||
|
|
||||||
|
uint32_t location = outputVar.location_decoration;
|
||||||
|
DAWN_INVALID_IF(location > kMaxInterStageShaderLocation,
|
||||||
|
"Vertex output variable \"%s\" has a location (%u) that "
|
||||||
|
"exceeds the maximum (%u).",
|
||||||
|
outputVar.name, location, kMaxInterStageShaderLocation);
|
||||||
|
|
||||||
|
metadata->usedInterStageVariables.set(location);
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
metadata->interStageVariables[location].baseType,
|
||||||
|
TintComponentTypeToInterStageComponentType(outputVar.component_type));
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
metadata->interStageVariables[location].componentCount,
|
||||||
|
TintCompositionTypeToInterStageComponentCount(outputVar.composition_type));
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
metadata->interStageVariables[location].interpolationType,
|
||||||
|
TintInterpolationTypeToInterpolationType(outputVar.interpolation_type));
|
||||||
|
DAWN_TRY_ASSIGN(metadata->interStageVariables[location].interpolationSampling,
|
||||||
|
TintInterpolationSamplingToInterpolationSamplingType(
|
||||||
|
outputVar.interpolation_sampling));
|
||||||
|
|
||||||
|
totalInterStageShaderComponents +=
|
||||||
|
metadata->interStageVariables[location].componentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_INVALID_IF(
|
||||||
|
totalInterStageShaderComponents > kMaxInterStageShaderComponents,
|
||||||
|
"Total vertex output components count (%u) exceeds the maximum (%u).",
|
||||||
|
totalInterStageShaderComponents, kMaxInterStageShaderComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata->stage == SingleShaderStage::Fragment) {
|
||||||
|
uint32_t totalInterStageShaderComponents = 0;
|
||||||
|
for (const auto& inputVar : entryPoint.input_variables) {
|
||||||
|
DAWN_INVALID_IF(
|
||||||
|
!inputVar.has_location_decoration,
|
||||||
|
"Fragment input variable \"%s\" doesn't have a location decoration.",
|
||||||
|
inputVar.name);
|
||||||
|
|
||||||
|
uint32_t location = inputVar.location_decoration;
|
||||||
|
DAWN_INVALID_IF(location > kMaxInterStageShaderLocation,
|
||||||
|
"Fragment input variable \"%s\" has a location (%u) that "
|
||||||
|
"exceeds the maximum (%u).",
|
||||||
|
inputVar.name, location, kMaxInterStageShaderLocation);
|
||||||
|
|
||||||
|
metadata->usedInterStageVariables.set(location);
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
metadata->interStageVariables[location].baseType,
|
||||||
|
TintComponentTypeToInterStageComponentType(inputVar.component_type));
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
metadata->interStageVariables[location].componentCount,
|
||||||
|
TintCompositionTypeToInterStageComponentCount(inputVar.composition_type));
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
metadata->interStageVariables[location].interpolationType,
|
||||||
|
TintInterpolationTypeToInterpolationType(inputVar.interpolation_type));
|
||||||
|
DAWN_TRY_ASSIGN(metadata->interStageVariables[location].interpolationSampling,
|
||||||
|
TintInterpolationSamplingToInterpolationSamplingType(
|
||||||
|
inputVar.interpolation_sampling));
|
||||||
|
|
||||||
|
totalInterStageShaderComponents +=
|
||||||
|
metadata->interStageVariables[location].componentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entryPoint.front_facing_used) {
|
||||||
|
totalInterStageShaderComponents += 1;
|
||||||
|
}
|
||||||
|
if (entryPoint.input_sample_mask_used) {
|
||||||
|
totalInterStageShaderComponents += 1;
|
||||||
|
}
|
||||||
|
if (entryPoint.sample_index_used) {
|
||||||
|
totalInterStageShaderComponents += 1;
|
||||||
|
}
|
||||||
|
if (entryPoint.input_position_used) {
|
||||||
|
totalInterStageShaderComponents += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_INVALID_IF(
|
||||||
|
totalInterStageShaderComponents > kMaxInterStageShaderComponents,
|
||||||
|
"Total fragment input components count (%u) exceeds the maximum (%u).",
|
||||||
|
totalInterStageShaderComponents, kMaxInterStageShaderComponents);
|
||||||
|
|
||||||
|
for (const auto& outputVar : entryPoint.output_variables) {
|
||||||
|
DAWN_INVALID_IF(
|
||||||
|
!outputVar.has_location_decoration,
|
||||||
|
"Fragment input variable \"%s\" doesn't have a location decoration.",
|
||||||
|
outputVar.name);
|
||||||
|
|
||||||
|
uint32_t unsanitizedAttachment = outputVar.location_decoration;
|
||||||
|
DAWN_INVALID_IF(unsanitizedAttachment >= kMaxColorAttachments,
|
||||||
|
"Fragment output variable \"%s\" has a location (%u) that "
|
||||||
|
"exceeds the maximum (%u).",
|
||||||
|
outputVar.name, unsanitizedAttachment, kMaxColorAttachments);
|
||||||
|
ColorAttachmentIndex attachment(static_cast<uint8_t>(unsanitizedAttachment));
|
||||||
|
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
metadata->fragmentOutputVariables[attachment].baseType,
|
||||||
|
TintComponentTypeToTextureComponentType(outputVar.component_type));
|
||||||
|
uint32_t componentCount;
|
||||||
|
DAWN_TRY_ASSIGN(componentCount, TintCompositionTypeToInterStageComponentCount(
|
||||||
|
outputVar.composition_type));
|
||||||
|
// componentCount should be no larger than 4u
|
||||||
|
ASSERT(componentCount <= 4u);
|
||||||
|
metadata->fragmentOutputVariables[attachment].componentCount = componentCount;
|
||||||
|
metadata->fragmentOutputsWritten.set(attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const tint::inspector::ResourceBinding& resource :
|
||||||
|
inspector->GetResourceBindings(entryPoint.name)) {
|
||||||
|
DAWN_INVALID_IF(resource.bind_group >= kMaxBindGroups,
|
||||||
|
"The entry-point uses a binding with a group decoration (%u) "
|
||||||
|
"that exceeds the maximum (%u).",
|
||||||
|
resource.bind_group, kMaxBindGroups);
|
||||||
|
|
||||||
|
BindingNumber bindingNumber(resource.binding);
|
||||||
|
BindGroupIndex bindGroupIndex(resource.bind_group);
|
||||||
|
|
||||||
|
DAWN_INVALID_IF(bindingNumber > kMaxBindingNumberTyped,
|
||||||
|
"Binding number (%u) exceeds the maximum binding number (%u).",
|
||||||
|
uint32_t(bindingNumber), uint32_t(kMaxBindingNumberTyped));
|
||||||
|
|
||||||
|
const auto& [binding, inserted] =
|
||||||
|
metadata->bindings[bindGroupIndex].emplace(bindingNumber, ShaderBindingInfo{});
|
||||||
|
DAWN_INVALID_IF(!inserted,
|
||||||
|
"Entry-point has a duplicate binding for (group:%u, binding:%u).",
|
||||||
|
resource.binding, resource.bind_group);
|
||||||
|
|
||||||
|
ShaderBindingInfo* info = &binding->second;
|
||||||
|
info->bindingType = TintResourceTypeToBindingInfoType(resource.resource_type);
|
||||||
|
|
||||||
|
switch (info->bindingType) {
|
||||||
|
case BindingInfoType::Buffer:
|
||||||
|
info->buffer.minBindingSize = resource.size_no_padding;
|
||||||
|
DAWN_TRY_ASSIGN(info->buffer.type, TintResourceTypeToBufferBindingType(
|
||||||
|
resource.resource_type));
|
||||||
|
break;
|
||||||
|
case BindingInfoType::Sampler:
|
||||||
|
switch (resource.resource_type) {
|
||||||
|
case tint::inspector::ResourceBinding::ResourceType::kSampler:
|
||||||
|
info->sampler.isComparison = false;
|
||||||
|
break;
|
||||||
|
case tint::inspector::ResourceBinding::ResourceType::kComparisonSampler:
|
||||||
|
info->sampler.isComparison = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BindingInfoType::Texture:
|
||||||
|
info->texture.viewDimension =
|
||||||
|
TintTextureDimensionToTextureViewDimension(resource.dim);
|
||||||
|
if (resource.resource_type ==
|
||||||
|
tint::inspector::ResourceBinding::ResourceType::kDepthTexture ||
|
||||||
|
resource.resource_type == tint::inspector::ResourceBinding::
|
||||||
|
ResourceType::kDepthMultisampledTexture) {
|
||||||
|
info->texture.compatibleSampleTypes = SampleTypeBit::Depth;
|
||||||
|
} else {
|
||||||
|
info->texture.compatibleSampleTypes =
|
||||||
|
TintSampledKindToSampleTypeBit(resource.sampled_kind);
|
||||||
|
}
|
||||||
|
info->texture.multisampled =
|
||||||
|
resource.resource_type == tint::inspector::ResourceBinding::
|
||||||
|
ResourceType::kMultisampledTexture ||
|
||||||
|
resource.resource_type == tint::inspector::ResourceBinding::
|
||||||
|
ResourceType::kDepthMultisampledTexture;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case BindingInfoType::StorageTexture:
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
info->storageTexture.access,
|
||||||
|
TintResourceTypeToStorageTextureAccess(resource.resource_type));
|
||||||
|
info->storageTexture.format =
|
||||||
|
TintImageFormatToTextureFormat(resource.image_format);
|
||||||
|
info->storageTexture.viewDimension =
|
||||||
|
TintTextureDimensionToTextureViewDimension(resource.dim);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return DAWN_VALIDATION_ERROR("Unknown binding type in Shader");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<tint::inspector::SamplerTexturePair> samplerTextureUses =
|
||||||
|
inspector->GetSamplerTextureUses(entryPoint.name);
|
||||||
|
metadata->samplerTexturePairs.reserve(samplerTextureUses.size());
|
||||||
|
std::transform(samplerTextureUses.begin(), samplerTextureUses.end(),
|
||||||
|
std::back_inserter(metadata->samplerTexturePairs),
|
||||||
|
[](const tint::inspector::SamplerTexturePair& pair) {
|
||||||
|
EntryPointMetadata::SamplerTexturePair result;
|
||||||
|
result.sampler = {BindGroupIndex(pair.sampler_binding_point.group),
|
||||||
|
BindingNumber(pair.sampler_binding_point.binding)};
|
||||||
|
result.texture = {BindGroupIndex(pair.texture_binding_point.group),
|
||||||
|
BindingNumber(pair.texture_binding_point.binding)};
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
return std::move(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
ResultOrError<EntryPointMetadataTable> ReflectShaderUsingTint(
|
ResultOrError<EntryPointMetadataTable> ReflectShaderUsingTint(
|
||||||
const DeviceBase* device,
|
const DeviceBase* device,
|
||||||
const tint::Program* program) {
|
const tint::Program* program) {
|
||||||
ASSERT(program->IsValid());
|
ASSERT(program->IsValid());
|
||||||
|
|
||||||
const CombinedLimits& limits = device->GetLimits();
|
|
||||||
|
|
||||||
EntryPointMetadataTable result;
|
|
||||||
|
|
||||||
tint::inspector::Inspector inspector(program);
|
tint::inspector::Inspector inspector(program);
|
||||||
auto entryPoints = inspector.GetEntryPoints();
|
std::vector<tint::inspector::EntryPoint> entryPoints = inspector.GetEntryPoints();
|
||||||
DAWN_INVALID_IF(inspector.has_error(), "Tint Reflection failure: Inspector: %s\n",
|
DAWN_INVALID_IF(inspector.has_error(), "Tint Reflection failure: Inspector: %s\n",
|
||||||
inspector.error());
|
inspector.error());
|
||||||
|
|
||||||
// TODO(dawn:563): use DAWN_TRY_CONTEXT to output the name of the entry point we're
|
EntryPointMetadataTable result;
|
||||||
// reflecting.
|
|
||||||
constexpr uint32_t kMaxInterStageShaderLocation = kMaxInterStageShaderVariables - 1;
|
for (const tint::inspector::EntryPoint& entryPoint : entryPoints) {
|
||||||
for (auto& entryPoint : entryPoints) {
|
std::unique_ptr<EntryPointMetadata> metadata;
|
||||||
|
DAWN_TRY_ASSIGN_CONTEXT(metadata,
|
||||||
|
ReflectEntryPointUsingTint(device, &inspector, entryPoint),
|
||||||
|
"processing entry point \"%s\".", entryPoint.name);
|
||||||
|
|
||||||
ASSERT(result.count(entryPoint.name) == 0);
|
ASSERT(result.count(entryPoint.name) == 0);
|
||||||
|
|
||||||
auto metadata = std::make_unique<EntryPointMetadata>();
|
|
||||||
|
|
||||||
if (!entryPoint.overridable_constants.empty()) {
|
|
||||||
DAWN_INVALID_IF(device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs),
|
|
||||||
"Pipeline overridable constants are disallowed because they "
|
|
||||||
"are partially implemented.");
|
|
||||||
|
|
||||||
const auto& name2Id = inspector.GetConstantNameToIdMap();
|
|
||||||
const auto& id2Scalar = inspector.GetConstantIDs();
|
|
||||||
|
|
||||||
for (auto& c : entryPoint.overridable_constants) {
|
|
||||||
uint32_t id = name2Id.at(c.name);
|
|
||||||
OverridableConstantScalar defaultValue;
|
|
||||||
if (c.is_initialized) {
|
|
||||||
// if it is initialized, the scalar must exist
|
|
||||||
const auto& scalar = id2Scalar.at(id);
|
|
||||||
if (scalar.IsBool()) {
|
|
||||||
defaultValue.b = scalar.AsBool();
|
|
||||||
} else if (scalar.IsU32()) {
|
|
||||||
defaultValue.u32 = scalar.AsU32();
|
|
||||||
} else if (scalar.IsI32()) {
|
|
||||||
defaultValue.i32 = scalar.AsI32();
|
|
||||||
} else if (scalar.IsFloat()) {
|
|
||||||
defaultValue.f32 = scalar.AsFloat();
|
|
||||||
} else {
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EntryPointMetadata::OverridableConstant constant = {
|
|
||||||
id, FromTintOverridableConstantType(c.type), c.is_initialized,
|
|
||||||
defaultValue};
|
|
||||||
|
|
||||||
std::string identifier =
|
|
||||||
c.is_numeric_id_specified ? std::to_string(constant.id) : c.name;
|
|
||||||
metadata->overridableConstants[identifier] = constant;
|
|
||||||
|
|
||||||
if (!c.is_initialized) {
|
|
||||||
auto [_, inserted] =
|
|
||||||
metadata->uninitializedOverridableConstants.emplace(
|
|
||||||
std::move(identifier));
|
|
||||||
// The insertion should have taken place
|
|
||||||
ASSERT(inserted);
|
|
||||||
} else {
|
|
||||||
auto [_, inserted] = metadata->initializedOverridableConstants.emplace(
|
|
||||||
std::move(identifier));
|
|
||||||
// The insertion should have taken place
|
|
||||||
ASSERT(inserted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DAWN_TRY_ASSIGN(metadata->stage, TintPipelineStageToShaderStage(entryPoint.stage));
|
|
||||||
|
|
||||||
if (metadata->stage == SingleShaderStage::Compute) {
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
entryPoint.workgroup_size_x > limits.v1.maxComputeWorkgroupSizeX ||
|
|
||||||
entryPoint.workgroup_size_y > limits.v1.maxComputeWorkgroupSizeY ||
|
|
||||||
entryPoint.workgroup_size_z > limits.v1.maxComputeWorkgroupSizeZ,
|
|
||||||
"Entry-point uses workgroup_size(%u, %u, %u) that exceeds the "
|
|
||||||
"maximum allowed (%u, %u, %u).",
|
|
||||||
entryPoint.workgroup_size_x, entryPoint.workgroup_size_y,
|
|
||||||
entryPoint.workgroup_size_z, limits.v1.maxComputeWorkgroupSizeX,
|
|
||||||
limits.v1.maxComputeWorkgroupSizeY, limits.v1.maxComputeWorkgroupSizeZ);
|
|
||||||
|
|
||||||
// Dimensions have already been validated against their individual limits above.
|
|
||||||
// Cast to uint64_t to avoid overflow in this multiplication.
|
|
||||||
uint64_t numInvocations = static_cast<uint64_t>(entryPoint.workgroup_size_x) *
|
|
||||||
entryPoint.workgroup_size_y *
|
|
||||||
entryPoint.workgroup_size_z;
|
|
||||||
DAWN_INVALID_IF(numInvocations > limits.v1.maxComputeInvocationsPerWorkgroup,
|
|
||||||
"The total number of workgroup invocations (%u) exceeds the "
|
|
||||||
"maximum allowed (%u).",
|
|
||||||
numInvocations, limits.v1.maxComputeInvocationsPerWorkgroup);
|
|
||||||
|
|
||||||
const size_t workgroupStorageSize =
|
|
||||||
inspector.GetWorkgroupStorageSize(entryPoint.name);
|
|
||||||
DAWN_INVALID_IF(workgroupStorageSize > limits.v1.maxComputeWorkgroupStorageSize,
|
|
||||||
"The total use of workgroup storage (%u bytes) is larger than "
|
|
||||||
"the maximum allowed (%u bytes).",
|
|
||||||
workgroupStorageSize, limits.v1.maxComputeWorkgroupStorageSize);
|
|
||||||
|
|
||||||
metadata->localWorkgroupSize.x = entryPoint.workgroup_size_x;
|
|
||||||
metadata->localWorkgroupSize.y = entryPoint.workgroup_size_y;
|
|
||||||
metadata->localWorkgroupSize.z = entryPoint.workgroup_size_z;
|
|
||||||
|
|
||||||
metadata->usesNumWorkgroups = entryPoint.num_workgroups_used;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata->stage == SingleShaderStage::Vertex) {
|
|
||||||
for (const auto& inputVar : entryPoint.input_variables) {
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
!inputVar.has_location_decoration,
|
|
||||||
"Vertex input variable \"%s\" doesn't have a location decoration.",
|
|
||||||
inputVar.name);
|
|
||||||
|
|
||||||
uint32_t unsanitizedLocation = inputVar.location_decoration;
|
|
||||||
DAWN_INVALID_IF(unsanitizedLocation >= kMaxVertexAttributes,
|
|
||||||
"Vertex input variable \"%s\" has a location (%u) that "
|
|
||||||
"exceeds the maximum (%u)",
|
|
||||||
inputVar.name, unsanitizedLocation, kMaxVertexAttributes);
|
|
||||||
VertexAttributeLocation location(static_cast<uint8_t>(unsanitizedLocation));
|
|
||||||
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
metadata->vertexInputBaseTypes[location],
|
|
||||||
TintComponentTypeToVertexFormatBaseType(inputVar.component_type));
|
|
||||||
metadata->usedVertexInputs.set(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
// [[position]] must be declared in a vertex shader but is not exposed as an
|
|
||||||
// output variable by Tint so we directly add its components to the total.
|
|
||||||
uint32_t totalInterStageShaderComponents = 4;
|
|
||||||
for (const auto& outputVar : entryPoint.output_variables) {
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
!outputVar.has_location_decoration,
|
|
||||||
"Vertex ouput variable \"%s\" doesn't have a location decoration.",
|
|
||||||
outputVar.name);
|
|
||||||
|
|
||||||
uint32_t location = outputVar.location_decoration;
|
|
||||||
DAWN_INVALID_IF(location > kMaxInterStageShaderLocation,
|
|
||||||
"Vertex output variable \"%s\" has a location (%u) that "
|
|
||||||
"exceeds the maximum (%u).",
|
|
||||||
outputVar.name, location, kMaxInterStageShaderLocation);
|
|
||||||
|
|
||||||
metadata->usedInterStageVariables.set(location);
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
metadata->interStageVariables[location].baseType,
|
|
||||||
TintComponentTypeToInterStageComponentType(outputVar.component_type));
|
|
||||||
DAWN_TRY_ASSIGN(metadata->interStageVariables[location].componentCount,
|
|
||||||
TintCompositionTypeToInterStageComponentCount(
|
|
||||||
outputVar.composition_type));
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
metadata->interStageVariables[location].interpolationType,
|
|
||||||
TintInterpolationTypeToInterpolationType(outputVar.interpolation_type));
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
metadata->interStageVariables[location].interpolationSampling,
|
|
||||||
TintInterpolationSamplingToInterpolationSamplingType(
|
|
||||||
outputVar.interpolation_sampling));
|
|
||||||
|
|
||||||
totalInterStageShaderComponents +=
|
|
||||||
metadata->interStageVariables[location].componentCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
totalInterStageShaderComponents > kMaxInterStageShaderComponents,
|
|
||||||
"Total vertex output components count (%u) exceeds the maximum (%u).",
|
|
||||||
totalInterStageShaderComponents, kMaxInterStageShaderComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata->stage == SingleShaderStage::Fragment) {
|
|
||||||
uint32_t totalInterStageShaderComponents = 0;
|
|
||||||
for (const auto& inputVar : entryPoint.input_variables) {
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
!inputVar.has_location_decoration,
|
|
||||||
"Fragment input variable \"%s\" doesn't have a location decoration.",
|
|
||||||
inputVar.name);
|
|
||||||
|
|
||||||
uint32_t location = inputVar.location_decoration;
|
|
||||||
DAWN_INVALID_IF(location > kMaxInterStageShaderLocation,
|
|
||||||
"Fragment input variable \"%s\" has a location (%u) that "
|
|
||||||
"exceeds the maximum (%u).",
|
|
||||||
inputVar.name, location, kMaxInterStageShaderLocation);
|
|
||||||
|
|
||||||
metadata->usedInterStageVariables.set(location);
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
metadata->interStageVariables[location].baseType,
|
|
||||||
TintComponentTypeToInterStageComponentType(inputVar.component_type));
|
|
||||||
DAWN_TRY_ASSIGN(metadata->interStageVariables[location].componentCount,
|
|
||||||
TintCompositionTypeToInterStageComponentCount(
|
|
||||||
inputVar.composition_type));
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
metadata->interStageVariables[location].interpolationType,
|
|
||||||
TintInterpolationTypeToInterpolationType(inputVar.interpolation_type));
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
metadata->interStageVariables[location].interpolationSampling,
|
|
||||||
TintInterpolationSamplingToInterpolationSamplingType(
|
|
||||||
inputVar.interpolation_sampling));
|
|
||||||
|
|
||||||
totalInterStageShaderComponents +=
|
|
||||||
metadata->interStageVariables[location].componentCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entryPoint.front_facing_used) {
|
|
||||||
totalInterStageShaderComponents += 1;
|
|
||||||
}
|
|
||||||
if (entryPoint.input_sample_mask_used) {
|
|
||||||
totalInterStageShaderComponents += 1;
|
|
||||||
}
|
|
||||||
if (entryPoint.sample_index_used) {
|
|
||||||
totalInterStageShaderComponents += 1;
|
|
||||||
}
|
|
||||||
if (entryPoint.input_position_used) {
|
|
||||||
totalInterStageShaderComponents += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
totalInterStageShaderComponents > kMaxInterStageShaderComponents,
|
|
||||||
"Total fragment input components count (%u) exceeds the maximum (%u).",
|
|
||||||
totalInterStageShaderComponents, kMaxInterStageShaderComponents);
|
|
||||||
|
|
||||||
for (const auto& outputVar : entryPoint.output_variables) {
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
!outputVar.has_location_decoration,
|
|
||||||
"Fragment input variable \"%s\" doesn't have a location decoration.",
|
|
||||||
outputVar.name);
|
|
||||||
|
|
||||||
uint32_t unsanitizedAttachment = outputVar.location_decoration;
|
|
||||||
DAWN_INVALID_IF(unsanitizedAttachment >= kMaxColorAttachments,
|
|
||||||
"Fragment output variable \"%s\" has a location (%u) that "
|
|
||||||
"exceeds the maximum (%u).",
|
|
||||||
outputVar.name, unsanitizedAttachment,
|
|
||||||
kMaxColorAttachments);
|
|
||||||
ColorAttachmentIndex attachment(
|
|
||||||
static_cast<uint8_t>(unsanitizedAttachment));
|
|
||||||
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
metadata->fragmentOutputVariables[attachment].baseType,
|
|
||||||
TintComponentTypeToTextureComponentType(outputVar.component_type));
|
|
||||||
uint32_t componentCount;
|
|
||||||
DAWN_TRY_ASSIGN(componentCount,
|
|
||||||
TintCompositionTypeToInterStageComponentCount(
|
|
||||||
outputVar.composition_type));
|
|
||||||
// componentCount should be no larger than 4u
|
|
||||||
ASSERT(componentCount <= 4u);
|
|
||||||
metadata->fragmentOutputVariables[attachment].componentCount =
|
|
||||||
componentCount;
|
|
||||||
metadata->fragmentOutputsWritten.set(attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const tint::inspector::ResourceBinding& resource :
|
|
||||||
inspector.GetResourceBindings(entryPoint.name)) {
|
|
||||||
DAWN_INVALID_IF(resource.bind_group >= kMaxBindGroups,
|
|
||||||
"The entry-point uses a binding with a group decoration (%u) "
|
|
||||||
"that exceeds the maximum (%u).",
|
|
||||||
resource.bind_group, kMaxBindGroups);
|
|
||||||
|
|
||||||
BindingNumber bindingNumber(resource.binding);
|
|
||||||
BindGroupIndex bindGroupIndex(resource.bind_group);
|
|
||||||
|
|
||||||
DAWN_INVALID_IF(bindingNumber > kMaxBindingNumberTyped,
|
|
||||||
"Binding number (%u) exceeds the maximum binding number (%u).",
|
|
||||||
uint32_t(bindingNumber), uint32_t(kMaxBindingNumberTyped));
|
|
||||||
|
|
||||||
const auto& [binding, inserted] = metadata->bindings[bindGroupIndex].emplace(
|
|
||||||
bindingNumber, ShaderBindingInfo{});
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
!inserted,
|
|
||||||
"Entry-point has a duplicate binding for (group:%u, binding:%u).",
|
|
||||||
resource.binding, resource.bind_group);
|
|
||||||
|
|
||||||
ShaderBindingInfo* info = &binding->second;
|
|
||||||
info->bindingType = TintResourceTypeToBindingInfoType(resource.resource_type);
|
|
||||||
|
|
||||||
switch (info->bindingType) {
|
|
||||||
case BindingInfoType::Buffer:
|
|
||||||
info->buffer.minBindingSize = resource.size_no_padding;
|
|
||||||
DAWN_TRY_ASSIGN(info->buffer.type, TintResourceTypeToBufferBindingType(
|
|
||||||
resource.resource_type));
|
|
||||||
break;
|
|
||||||
case BindingInfoType::Sampler:
|
|
||||||
switch (resource.resource_type) {
|
|
||||||
case tint::inspector::ResourceBinding::ResourceType::kSampler:
|
|
||||||
info->sampler.isComparison = false;
|
|
||||||
break;
|
|
||||||
case tint::inspector::ResourceBinding::ResourceType::
|
|
||||||
kComparisonSampler:
|
|
||||||
info->sampler.isComparison = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BindingInfoType::Texture:
|
|
||||||
info->texture.viewDimension =
|
|
||||||
TintTextureDimensionToTextureViewDimension(resource.dim);
|
|
||||||
if (resource.resource_type ==
|
|
||||||
tint::inspector::ResourceBinding::ResourceType::kDepthTexture ||
|
|
||||||
resource.resource_type ==
|
|
||||||
tint::inspector::ResourceBinding::ResourceType::
|
|
||||||
kDepthMultisampledTexture) {
|
|
||||||
info->texture.compatibleSampleTypes = SampleTypeBit::Depth;
|
|
||||||
} else {
|
|
||||||
info->texture.compatibleSampleTypes =
|
|
||||||
TintSampledKindToSampleTypeBit(resource.sampled_kind);
|
|
||||||
}
|
|
||||||
info->texture.multisampled =
|
|
||||||
resource.resource_type == tint::inspector::ResourceBinding::
|
|
||||||
ResourceType::kMultisampledTexture ||
|
|
||||||
resource.resource_type ==
|
|
||||||
tint::inspector::ResourceBinding::ResourceType::
|
|
||||||
kDepthMultisampledTexture;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case BindingInfoType::StorageTexture:
|
|
||||||
DAWN_TRY_ASSIGN(
|
|
||||||
info->storageTexture.access,
|
|
||||||
TintResourceTypeToStorageTextureAccess(resource.resource_type));
|
|
||||||
info->storageTexture.format =
|
|
||||||
TintImageFormatToTextureFormat(resource.image_format);
|
|
||||||
info->storageTexture.viewDimension =
|
|
||||||
TintTextureDimensionToTextureViewDimension(resource.dim);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case BindingInfoType::ExternalTexture:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return DAWN_VALIDATION_ERROR("Unknown binding type in Shader");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<tint::inspector::SamplerTexturePair> samplerTextureUses =
|
|
||||||
inspector.GetSamplerTextureUses(entryPoint.name);
|
|
||||||
metadata->samplerTexturePairs.reserve(samplerTextureUses.size());
|
|
||||||
std::transform(
|
|
||||||
samplerTextureUses.begin(), samplerTextureUses.end(),
|
|
||||||
std::back_inserter(metadata->samplerTexturePairs),
|
|
||||||
[](const tint::inspector::SamplerTexturePair& pair) {
|
|
||||||
EntryPointMetadata::SamplerTexturePair result;
|
|
||||||
result.sampler = {BindGroupIndex(pair.sampler_binding_point.group),
|
|
||||||
BindingNumber(pair.sampler_binding_point.binding)};
|
|
||||||
result.texture = {BindGroupIndex(pair.texture_binding_point.group),
|
|
||||||
BindingNumber(pair.texture_binding_point.binding)};
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
|
|
||||||
result[entryPoint.name] = std::move(metadata);
|
result[entryPoint.name] = std::move(metadata);
|
||||||
}
|
}
|
||||||
return std::move(result);
|
return std::move(result);
|
||||||
|
|
Loading…
Reference in New Issue