tint->dawn: Shuffle source tree in preperation of merging repos

docs/    -> docs/tint/
fuzzers/ -> src/tint/fuzzers/
samples/ -> src/tint/cmd/
src/     -> src/tint/
test/    -> test/tint/

BUG=tint:1418,tint:1433

Change-Id: Id2aa79f989aef3245b80ef4aa37a27ff16cd700b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/80482
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
This commit is contained in:
Ryan Harrison
2022-02-21 15:19:07 +00:00
committed by Tint LUCI CQ
parent 38f1e9c75c
commit dbc13af287
12231 changed files with 4897 additions and 4871 deletions

View File

@@ -0,0 +1,70 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/inspector/entry_point.h"
namespace tint {
namespace inspector {
StageVariable::StageVariable() = default;
StageVariable::StageVariable(const StageVariable& other)
: name(other.name),
has_location_attribute(other.has_location_attribute),
location_attribute(other.location_attribute),
has_location_decoration(has_location_attribute),
location_decoration(location_attribute),
component_type(other.component_type),
composition_type(other.composition_type),
interpolation_type(other.interpolation_type),
interpolation_sampling(other.interpolation_sampling) {}
StageVariable::~StageVariable() = default;
EntryPoint::EntryPoint() = default;
EntryPoint::EntryPoint(EntryPoint&) = default;
EntryPoint::EntryPoint(EntryPoint&&) = default;
EntryPoint::~EntryPoint() = default;
InterpolationType ASTToInspectorInterpolationType(
ast::InterpolationType ast_type) {
switch (ast_type) {
case ast::InterpolationType::kPerspective:
return InterpolationType::kPerspective;
case ast::InterpolationType::kLinear:
return InterpolationType::kLinear;
case ast::InterpolationType::kFlat:
return InterpolationType::kFlat;
}
return InterpolationType::kUnknown;
}
InterpolationSampling ASTToInspectorInterpolationSampling(
ast::InterpolationSampling sampling) {
switch (sampling) {
case ast::InterpolationSampling::kNone:
return InterpolationSampling::kNone;
case ast::InterpolationSampling::kCenter:
return InterpolationSampling::kCenter;
case ast::InterpolationSampling::kCentroid:
return InterpolationSampling::kCentroid;
case ast::InterpolationSampling::kSample:
return InterpolationSampling::kSample;
}
return InterpolationSampling::kUnknown;
}
} // namespace inspector
} // namespace tint

View File

@@ -0,0 +1,187 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_INSPECTOR_ENTRY_POINT_H_
#define SRC_TINT_INSPECTOR_ENTRY_POINT_H_
#include <string>
#include <tuple>
#include <vector>
#include "src/tint/ast/interpolate_attribute.h"
#include "src/tint/ast/pipeline_stage.h"
namespace tint {
namespace inspector {
/// Base component type of a stage variable.
enum class ComponentType {
kUnknown = -1,
kFloat,
kUInt,
kSInt,
};
/// Composition of components of a stage variable.
enum class CompositionType {
kUnknown = -1,
kScalar,
kVec2,
kVec3,
kVec4,
};
/// Type of interpolation of a stage variable.
enum class InterpolationType { kUnknown = -1, kPerspective, kLinear, kFlat };
/// Type of interpolation sampling of a stage variable.
enum class InterpolationSampling {
kUnknown = -1,
kNone,
kCenter,
kCentroid,
kSample
};
/// Reflection data about an entry point input or output.
struct StageVariable {
/// Constructor
StageVariable();
/// Copy constructor
/// @param other the StageVariable to copy
StageVariable(const StageVariable& other);
/// Destructor
~StageVariable();
/// Name of the variable in the shader.
std::string name;
/// Is location attribute present
bool has_location_attribute = false;
/// Value of the location attribute, only valid if #has_location_attribute is
/// true.
uint32_t location_attribute;
/// Is Location attribute present
/// [DEPRECATED]: Use #has_location_attribute
bool& has_location_decoration = has_location_attribute;
/// Value of Location Decoration, only valid if #has_location_decoration is
/// true.
/// [DEPRECATED]: Use #location_attribute
uint32_t& location_decoration = location_attribute;
/// Scalar type that the variable is composed of.
ComponentType component_type = ComponentType::kUnknown;
/// How the scalars are composed for the variable.
CompositionType composition_type = CompositionType::kUnknown;
/// Interpolation type of the variable.
InterpolationType interpolation_type = InterpolationType::kUnknown;
/// Interpolation sampling of the variable.
InterpolationSampling interpolation_sampling =
InterpolationSampling::kUnknown;
};
/// Convert from internal ast::InterpolationType to public ::InterpolationType.
/// @param ast_type internal value to convert from
/// @returns the publicly visible equivalent
InterpolationType ASTToInspectorInterpolationType(
ast::InterpolationType ast_type);
/// Convert from internal ast::InterpolationSampling to public
/// ::InterpolationSampling
/// @param sampling internal value to convert from
/// @returns the publicly visible equivalent
InterpolationSampling ASTToInspectorInterpolationSampling(
ast::InterpolationSampling sampling);
/// Reflection data about a pipeline overridable constant referenced by an entry
/// point
struct OverridableConstant {
/// Name of the constant
std::string name;
/// ID of the constant
uint16_t numeric_id;
/// Type of the scalar
enum class Type {
kBool,
kFloat32,
kUint32,
kInt32,
};
/// Type of the scalar
Type type;
/// Does this pipeline overridable constant have an initializer?
bool is_initialized = false;
/// Does this pipeline overridable constant have a numeric ID specified
/// explicitly?
bool is_numeric_id_specified = false;
};
/// Reflection data for an entry point in the shader.
struct EntryPoint {
/// Constructors
EntryPoint();
/// Copy Constructor
EntryPoint(EntryPoint&);
/// Move Constructor
EntryPoint(EntryPoint&&);
~EntryPoint();
/// The entry point name
std::string name;
/// Remapped entry point name in the backend
std::string remapped_name;
/// The entry point stage
ast::PipelineStage stage = ast::PipelineStage::kNone;
/// The workgroup x size
uint32_t workgroup_size_x = 0;
/// The workgroup y size
uint32_t workgroup_size_y = 0;
/// The workgroup z size
uint32_t workgroup_size_z = 0;
/// List of the input variable accessed via this entry point.
std::vector<StageVariable> input_variables;
/// List of the output variable accessed via this entry point.
std::vector<StageVariable> output_variables;
/// List of the pipeline overridable constants accessed via this entry point.
std::vector<OverridableConstant> overridable_constants;
/// Does the entry point use the sample_mask builtin as an input builtin
/// variable.
bool input_sample_mask_used = false;
/// Does the entry point use the sample_mask builtin as an output builtin
/// variable.
bool output_sample_mask_used = false;
/// Does the entry point use the position builtin as an input builtin
/// variable.
bool input_position_used = false;
/// Does the entry point use the front_facing builtin
bool front_facing_used = false;
/// Does the entry point use the sample_index builtin
bool sample_index_used = false;
/// Does the entry point use the num_workgroups builtin
bool num_workgroups_used = false;
/// @returns the size of the workgroup in {x,y,z} format
std::tuple<uint32_t, uint32_t, uint32_t> workgroup_size() {
return std::tuple<uint32_t, uint32_t, uint32_t>(
workgroup_size_x, workgroup_size_y, workgroup_size_z);
}
};
} // namespace inspector
} // namespace tint
#endif // SRC_TINT_INSPECTOR_ENTRY_POINT_H_

View File

@@ -0,0 +1,969 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/inspector/inspector.h"
#include <limits>
#include <utility>
#include "src/tint/ast/bool_literal_expression.h"
#include "src/tint/ast/call_expression.h"
#include "src/tint/ast/float_literal_expression.h"
#include "src/tint/ast/id_attribute.h"
#include "src/tint/ast/interpolate_attribute.h"
#include "src/tint/ast/location_attribute.h"
#include "src/tint/ast/module.h"
#include "src/tint/ast/sint_literal_expression.h"
#include "src/tint/ast/uint_literal_expression.h"
#include "src/tint/sem/array.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/depth_multisampled_texture_type.h"
#include "src/tint/sem/f32_type.h"
#include "src/tint/sem/function.h"
#include "src/tint/sem/i32_type.h"
#include "src/tint/sem/matrix_type.h"
#include "src/tint/sem/multisampled_texture_type.h"
#include "src/tint/sem/sampled_texture_type.h"
#include "src/tint/sem/statement.h"
#include "src/tint/sem/storage_texture_type.h"
#include "src/tint/sem/struct.h"
#include "src/tint/sem/u32_type.h"
#include "src/tint/sem/variable.h"
#include "src/tint/sem/vector_type.h"
#include "src/tint/sem/void_type.h"
#include "src/tint/utils/math.h"
#include "src/tint/utils/unique_vector.h"
namespace tint {
namespace inspector {
namespace {
void AppendResourceBindings(std::vector<ResourceBinding>* dest,
const std::vector<ResourceBinding>& orig) {
TINT_ASSERT(Inspector, dest);
if (!dest) {
return;
}
dest->reserve(dest->size() + orig.size());
dest->insert(dest->end(), orig.begin(), orig.end());
}
std::tuple<ComponentType, CompositionType> CalculateComponentAndComposition(
const sem::Type* type) {
if (type->is_float_scalar()) {
return {ComponentType::kFloat, CompositionType::kScalar};
} else if (type->is_float_vector()) {
auto* vec = type->As<sem::Vector>();
if (vec->Width() == 2) {
return {ComponentType::kFloat, CompositionType::kVec2};
} else if (vec->Width() == 3) {
return {ComponentType::kFloat, CompositionType::kVec3};
} else if (vec->Width() == 4) {
return {ComponentType::kFloat, CompositionType::kVec4};
}
} else if (type->is_unsigned_integer_scalar()) {
return {ComponentType::kUInt, CompositionType::kScalar};
} else if (type->is_unsigned_integer_vector()) {
auto* vec = type->As<sem::Vector>();
if (vec->Width() == 2) {
return {ComponentType::kUInt, CompositionType::kVec2};
} else if (vec->Width() == 3) {
return {ComponentType::kUInt, CompositionType::kVec3};
} else if (vec->Width() == 4) {
return {ComponentType::kUInt, CompositionType::kVec4};
}
} else if (type->is_signed_integer_scalar()) {
return {ComponentType::kSInt, CompositionType::kScalar};
} else if (type->is_signed_integer_vector()) {
auto* vec = type->As<sem::Vector>();
if (vec->Width() == 2) {
return {ComponentType::kSInt, CompositionType::kVec2};
} else if (vec->Width() == 3) {
return {ComponentType::kSInt, CompositionType::kVec3};
} else if (vec->Width() == 4) {
return {ComponentType::kSInt, CompositionType::kVec4};
}
}
return {ComponentType::kUnknown, CompositionType::kUnknown};
}
std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData(
const sem::Type* type,
const ast::AttributeList& attributes) {
auto* interpolation_attribute =
ast::GetAttribute<ast::InterpolateAttribute>(attributes);
if (type->is_integer_scalar_or_vector()) {
return {InterpolationType::kFlat, InterpolationSampling::kNone};
}
if (!interpolation_attribute) {
return {InterpolationType::kPerspective, InterpolationSampling::kCenter};
}
auto interpolation_type = interpolation_attribute->type;
auto sampling = interpolation_attribute->sampling;
if (interpolation_type != ast::InterpolationType::kFlat &&
sampling == ast::InterpolationSampling::kNone) {
sampling = ast::InterpolationSampling::kCenter;
}
return {ASTToInspectorInterpolationType(interpolation_type),
ASTToInspectorInterpolationSampling(sampling)};
}
} // namespace
Inspector::Inspector(const Program* program) : program_(program) {}
Inspector::~Inspector() = default;
std::vector<EntryPoint> Inspector::GetEntryPoints() {
std::vector<EntryPoint> result;
for (auto* func : program_->AST().Functions()) {
if (!func->IsEntryPoint()) {
continue;
}
auto* sem = program_->Sem().Get(func);
EntryPoint entry_point;
entry_point.name = program_->Symbols().NameFor(func->symbol);
entry_point.remapped_name = program_->Symbols().NameFor(func->symbol);
entry_point.stage = func->PipelineStage();
auto wgsize = sem->WorkgroupSize();
entry_point.workgroup_size_x = wgsize[0].value;
entry_point.workgroup_size_y = wgsize[1].value;
entry_point.workgroup_size_z = wgsize[2].value;
if (wgsize[0].overridable_const || wgsize[1].overridable_const ||
wgsize[2].overridable_const) {
// TODO(crbug.com/tint/713): Handle overridable constants.
TINT_ASSERT(Inspector, false);
}
for (auto* param : sem->Parameters()) {
AddEntryPointInOutVariables(
program_->Symbols().NameFor(param->Declaration()->symbol),
param->Type(), param->Declaration()->attributes,
entry_point.input_variables);
entry_point.input_position_used |=
ContainsBuiltin(ast::Builtin::kPosition, param->Type(),
param->Declaration()->attributes);
entry_point.front_facing_used |=
ContainsBuiltin(ast::Builtin::kFrontFacing, param->Type(),
param->Declaration()->attributes);
entry_point.sample_index_used |=
ContainsBuiltin(ast::Builtin::kSampleIndex, param->Type(),
param->Declaration()->attributes);
entry_point.input_sample_mask_used |=
ContainsBuiltin(ast::Builtin::kSampleMask, param->Type(),
param->Declaration()->attributes);
entry_point.num_workgroups_used |=
ContainsBuiltin(ast::Builtin::kNumWorkgroups, param->Type(),
param->Declaration()->attributes);
}
if (!sem->ReturnType()->Is<sem::Void>()) {
AddEntryPointInOutVariables("<retval>", sem->ReturnType(),
func->return_type_attributes,
entry_point.output_variables);
entry_point.output_sample_mask_used =
ContainsBuiltin(ast::Builtin::kSampleMask, sem->ReturnType(),
func->return_type_attributes);
}
for (auto* var : sem->TransitivelyReferencedGlobals()) {
auto* decl = var->Declaration();
auto name = program_->Symbols().NameFor(decl->symbol);
auto* global = var->As<sem::GlobalVariable>();
if (global && global->IsOverridable()) {
OverridableConstant overridable_constant;
overridable_constant.name = name;
overridable_constant.numeric_id = global->ConstantId();
auto* type = var->Type();
TINT_ASSERT(Inspector, type->is_scalar());
if (type->is_bool_scalar_or_vector()) {
overridable_constant.type = OverridableConstant::Type::kBool;
} else if (type->is_float_scalar()) {
overridable_constant.type = OverridableConstant::Type::kFloat32;
} else if (type->is_signed_integer_scalar()) {
overridable_constant.type = OverridableConstant::Type::kInt32;
} else if (type->is_unsigned_integer_scalar()) {
overridable_constant.type = OverridableConstant::Type::kUint32;
} else {
TINT_UNREACHABLE(Inspector, diagnostics_);
}
overridable_constant.is_initialized =
global->Declaration()->constructor;
overridable_constant.is_numeric_id_specified =
ast::HasAttribute<ast::IdAttribute>(
global->Declaration()->attributes);
entry_point.overridable_constants.push_back(overridable_constant);
}
}
result.push_back(std::move(entry_point));
}
return result;
}
std::string Inspector::GetRemappedNameForEntryPoint(
const std::string& entry_point) {
// TODO(rharrison): Reenable once all of the backends are using the renamed
// entry points.
// auto* func = FindEntryPointByName(entry_point);
// if (!func) {
// return {};
// }
// return func->name();
return entry_point;
}
std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
std::map<uint32_t, Scalar> result;
for (auto* var : program_->AST().GlobalVariables()) {
auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
if (!global || !global->IsOverridable()) {
continue;
}
// If there are conflicting defintions for a constant id, that is invalid
// WGSL, so the resolver should catch it. Thus here the inspector just
// assumes all definitions of the constant id are the same, so only needs
// to find the first reference to constant id.
uint32_t constant_id = global->ConstantId();
if (result.find(constant_id) != result.end()) {
continue;
}
if (!var->constructor) {
result[constant_id] = Scalar();
continue;
}
auto* literal = var->constructor->As<ast::LiteralExpression>();
if (!literal) {
// This is invalid WGSL, but handling gracefully.
result[constant_id] = Scalar();
continue;
}
if (auto* l = literal->As<ast::BoolLiteralExpression>()) {
result[constant_id] = Scalar(l->value);
continue;
}
if (auto* l = literal->As<ast::UintLiteralExpression>()) {
result[constant_id] = Scalar(l->value);
continue;
}
if (auto* l = literal->As<ast::SintLiteralExpression>()) {
result[constant_id] = Scalar(l->value);
continue;
}
if (auto* l = literal->As<ast::FloatLiteralExpression>()) {
result[constant_id] = Scalar(l->value);
continue;
}
result[constant_id] = Scalar();
}
return result;
}
std::map<std::string, uint32_t> Inspector::GetConstantNameToIdMap() {
std::map<std::string, uint32_t> result;
for (auto* var : program_->AST().GlobalVariables()) {
auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
if (global && global->IsOverridable()) {
auto name = program_->Symbols().NameFor(var->symbol);
result[name] = global->ConstantId();
}
}
return result;
}
uint32_t Inspector::GetStorageSize(const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return 0;
}
size_t size = 0;
auto* func_sem = program_->Sem().Get(func);
for (auto& ruv : func_sem->TransitivelyReferencedUniformVariables()) {
size += ruv.first->Type()->UnwrapRef()->Size();
}
for (auto& rsv : func_sem->TransitivelyReferencedStorageBufferVariables()) {
size += rsv.first->Type()->UnwrapRef()->Size();
}
if (static_cast<uint64_t>(size) >
static_cast<uint64_t>(std::numeric_limits<uint32_t>::max())) {
return std::numeric_limits<uint32_t>::max();
}
return static_cast<uint32_t>(size);
}
std::vector<ResourceBinding> Inspector::GetResourceBindings(
const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
std::vector<ResourceBinding> result;
for (auto fn : {
&Inspector::GetUniformBufferResourceBindings,
&Inspector::GetStorageBufferResourceBindings,
&Inspector::GetReadOnlyStorageBufferResourceBindings,
&Inspector::GetSamplerResourceBindings,
&Inspector::GetComparisonSamplerResourceBindings,
&Inspector::GetSampledTextureResourceBindings,
&Inspector::GetMultisampledTextureResourceBindings,
&Inspector::GetWriteOnlyStorageTextureResourceBindings,
&Inspector::GetDepthTextureResourceBindings,
&Inspector::GetDepthMultisampledTextureResourceBindings,
&Inspector::GetExternalTextureResourceBindings,
}) {
AppendResourceBindings(&result, (this->*fn)(entry_point));
}
return result;
}
std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
std::vector<ResourceBinding> result;
auto* func_sem = program_->Sem().Get(func);
for (auto& ruv : func_sem->TransitivelyReferencedUniformVariables()) {
auto* var = ruv.first;
auto binding_info = ruv.second;
auto* unwrapped_type = var->Type()->UnwrapRef();
ResourceBinding entry;
entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
entry.bind_group = binding_info.group->value;
entry.binding = binding_info.binding->value;
entry.size = unwrapped_type->Size();
entry.size_no_padding = entry.size;
if (auto* str = unwrapped_type->As<sem::Struct>()) {
entry.size_no_padding = str->SizeNoPadding();
} else {
entry.size_no_padding = entry.size;
}
result.push_back(entry);
}
return result;
}
std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindings(
const std::string& entry_point) {
return GetStorageBufferResourceBindingsImpl(entry_point, false);
}
std::vector<ResourceBinding>
Inspector::GetReadOnlyStorageBufferResourceBindings(
const std::string& entry_point) {
return GetStorageBufferResourceBindingsImpl(entry_point, true);
}
std::vector<ResourceBinding> Inspector::GetSamplerResourceBindings(
const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
std::vector<ResourceBinding> result;
auto* func_sem = program_->Sem().Get(func);
for (auto& rs : func_sem->TransitivelyReferencedSamplerVariables()) {
auto binding_info = rs.second;
ResourceBinding entry;
entry.resource_type = ResourceBinding::ResourceType::kSampler;
entry.bind_group = binding_info.group->value;
entry.binding = binding_info.binding->value;
result.push_back(entry);
}
return result;
}
std::vector<ResourceBinding> Inspector::GetComparisonSamplerResourceBindings(
const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
std::vector<ResourceBinding> result;
auto* func_sem = program_->Sem().Get(func);
for (auto& rcs :
func_sem->TransitivelyReferencedComparisonSamplerVariables()) {
auto binding_info = rcs.second;
ResourceBinding entry;
entry.resource_type = ResourceBinding::ResourceType::kComparisonSampler;
entry.bind_group = binding_info.group->value;
entry.binding = binding_info.binding->value;
result.push_back(entry);
}
return result;
}
std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindings(
const std::string& entry_point) {
return GetSampledTextureResourceBindingsImpl(entry_point, false);
}
std::vector<ResourceBinding> Inspector::GetMultisampledTextureResourceBindings(
const std::string& entry_point) {
return GetSampledTextureResourceBindingsImpl(entry_point, true);
}
std::vector<ResourceBinding>
Inspector::GetWriteOnlyStorageTextureResourceBindings(
const std::string& entry_point) {
return GetStorageTextureResourceBindingsImpl(entry_point);
}
std::vector<ResourceBinding> Inspector::GetTextureResourceBindings(
const std::string& entry_point,
const tint::TypeInfo* texture_type,
ResourceBinding::ResourceType resource_type) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
std::vector<ResourceBinding> result;
auto* func_sem = program_->Sem().Get(func);
for (auto& ref :
func_sem->TransitivelyReferencedVariablesOfType(texture_type)) {
auto* var = ref.first;
auto binding_info = ref.second;
ResourceBinding entry;
entry.resource_type = resource_type;
entry.bind_group = binding_info.group->value;
entry.binding = binding_info.binding->value;
auto* tex = var->Type()->UnwrapRef()->As<sem::Texture>();
entry.dim =
TypeTextureDimensionToResourceBindingTextureDimension(tex->dim());
result.push_back(entry);
}
return result;
}
std::vector<ResourceBinding> Inspector::GetDepthTextureResourceBindings(
const std::string& entry_point) {
return GetTextureResourceBindings(
entry_point, &TypeInfo::Of<sem::DepthTexture>(),
ResourceBinding::ResourceType::kDepthTexture);
}
std::vector<ResourceBinding>
Inspector::GetDepthMultisampledTextureResourceBindings(
const std::string& entry_point) {
return GetTextureResourceBindings(
entry_point, &TypeInfo::Of<sem::DepthMultisampledTexture>(),
ResourceBinding::ResourceType::kDepthMultisampledTexture);
}
std::vector<ResourceBinding> Inspector::GetExternalTextureResourceBindings(
const std::string& entry_point) {
return GetTextureResourceBindings(
entry_point, &TypeInfo::Of<sem::ExternalTexture>(),
ResourceBinding::ResourceType::kExternalTexture);
}
std::vector<sem::SamplerTexturePair> Inspector::GetSamplerTextureUses(
const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
GenerateSamplerTargets();
auto it = sampler_targets_->find(entry_point);
if (it == sampler_targets_->end()) {
return {};
}
return it->second;
}
std::vector<sem::SamplerTexturePair> Inspector::GetSamplerTextureUses(
const std::string& entry_point,
const sem::BindingPoint& placeholder) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
auto* func_sem = program_->Sem().Get(func);
std::vector<sem::SamplerTexturePair> new_pairs;
for (auto pair : func_sem->TextureSamplerPairs()) {
auto* texture = pair.first->As<sem::GlobalVariable>();
auto* sampler =
pair.second ? pair.second->As<sem::GlobalVariable>() : nullptr;
SamplerTexturePair new_pair;
new_pair.sampler_binding_point =
sampler ? sampler->BindingPoint() : placeholder;
new_pair.texture_binding_point = texture->BindingPoint();
new_pairs.push_back(new_pair);
}
return new_pairs;
}
uint32_t Inspector::GetWorkgroupStorageSize(const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return 0;
}
uint32_t total_size = 0;
auto* func_sem = program_->Sem().Get(func);
for (const sem::Variable* var : func_sem->TransitivelyReferencedGlobals()) {
if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
auto* ty = var->Type()->UnwrapRef();
uint32_t align = ty->Align();
uint32_t size = ty->Size();
// This essentially matches std430 layout rules from GLSL, which are in
// turn specified as an upper bound for Vulkan layout sizing. Since D3D
// and Metal are even less specific, we assume Vulkan behavior as a
// good-enough approximation everywhere.
total_size += utils::RoundUp(align, size);
}
}
return total_size;
}
const ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
auto* func = program_->AST().Functions().Find(program_->Symbols().Get(name));
if (!func) {
diagnostics_.add_error(diag::System::Inspector, name + " was not found!");
return nullptr;
}
if (!func->IsEntryPoint()) {
diagnostics_.add_error(diag::System::Inspector,
name + " is not an entry point!");
return nullptr;
}
return func;
}
void Inspector::AddEntryPointInOutVariables(
std::string name,
const sem::Type* type,
const ast::AttributeList& attributes,
std::vector<StageVariable>& variables) const {
// Skip builtins.
if (ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
return;
}
auto* unwrapped_type = type->UnwrapRef();
if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
// Recurse into members.
for (auto* member : struct_ty->Members()) {
AddEntryPointInOutVariables(
name + "." +
program_->Symbols().NameFor(member->Declaration()->symbol),
member->Type(), member->Declaration()->attributes, variables);
}
return;
}
// Base case: add the variable.
StageVariable stage_variable;
stage_variable.name = name;
std::tie(stage_variable.component_type, stage_variable.composition_type) =
CalculateComponentAndComposition(type);
auto* location = ast::GetAttribute<ast::LocationAttribute>(attributes);
TINT_ASSERT(Inspector, location != nullptr);
stage_variable.has_location_attribute = true;
stage_variable.location_attribute = location->value;
std::tie(stage_variable.interpolation_type,
stage_variable.interpolation_sampling) =
CalculateInterpolationData(type, attributes);
variables.push_back(stage_variable);
}
bool Inspector::ContainsBuiltin(ast::Builtin builtin,
const sem::Type* type,
const ast::AttributeList& attributes) const {
auto* unwrapped_type = type->UnwrapRef();
if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
// Recurse into members.
for (auto* member : struct_ty->Members()) {
if (ContainsBuiltin(builtin, member->Type(),
member->Declaration()->attributes)) {
return true;
}
}
return false;
}
// Base case: check for builtin
auto* builtin_declaration =
ast::GetAttribute<ast::BuiltinAttribute>(attributes);
if (!builtin_declaration || builtin_declaration->builtin != builtin) {
return false;
}
return true;
}
std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
const std::string& entry_point,
bool read_only) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
auto* func_sem = program_->Sem().Get(func);
std::vector<ResourceBinding> result;
for (auto& rsv : func_sem->TransitivelyReferencedStorageBufferVariables()) {
auto* var = rsv.first;
auto binding_info = rsv.second;
if (read_only != (var->Access() == ast::Access::kRead)) {
continue;
}
auto* unwrapped_type = var->Type()->UnwrapRef();
ResourceBinding entry;
entry.resource_type =
read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
: ResourceBinding::ResourceType::kStorageBuffer;
entry.bind_group = binding_info.group->value;
entry.binding = binding_info.binding->value;
entry.size = unwrapped_type->Size();
if (auto* str = unwrapped_type->As<sem::Struct>()) {
entry.size_no_padding = str->SizeNoPadding();
} else {
entry.size_no_padding = entry.size;
}
result.push_back(entry);
}
return result;
}
std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindingsImpl(
const std::string& entry_point,
bool multisampled_only) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
std::vector<ResourceBinding> result;
auto* func_sem = program_->Sem().Get(func);
auto referenced_variables =
multisampled_only
? func_sem->TransitivelyReferencedMultisampledTextureVariables()
: func_sem->TransitivelyReferencedSampledTextureVariables();
for (auto& ref : referenced_variables) {
auto* var = ref.first;
auto binding_info = ref.second;
ResourceBinding entry;
entry.resource_type =
multisampled_only ? ResourceBinding::ResourceType::kMultisampledTexture
: ResourceBinding::ResourceType::kSampledTexture;
entry.bind_group = binding_info.group->value;
entry.binding = binding_info.binding->value;
auto* texture_type = var->Type()->UnwrapRef()->As<sem::Texture>();
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
texture_type->dim());
const sem::Type* base_type = nullptr;
if (multisampled_only) {
base_type = texture_type->As<sem::MultisampledTexture>()->type();
} else {
base_type = texture_type->As<sem::SampledTexture>()->type();
}
entry.sampled_kind = BaseTypeToSampledKind(base_type);
result.push_back(entry);
}
return result;
}
std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
const std::string& entry_point) {
auto* func = FindEntryPointByName(entry_point);
if (!func) {
return {};
}
auto* func_sem = program_->Sem().Get(func);
std::vector<ResourceBinding> result;
for (auto& ref :
func_sem->TransitivelyReferencedVariablesOfType<sem::StorageTexture>()) {
auto* var = ref.first;
auto binding_info = ref.second;
auto* texture_type = var->Type()->UnwrapRef()->As<sem::StorageTexture>();
ResourceBinding entry;
entry.resource_type =
ResourceBinding::ResourceType::kWriteOnlyStorageTexture;
entry.bind_group = binding_info.group->value;
entry.binding = binding_info.binding->value;
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
texture_type->dim());
auto* base_type = texture_type->type();
entry.sampled_kind = BaseTypeToSampledKind(base_type);
entry.image_format = TypeTexelFormatToResourceBindingTexelFormat(
texture_type->texel_format());
result.push_back(entry);
}
return result;
}
void Inspector::GenerateSamplerTargets() {
// Do not re-generate, since |program_| should not change during the lifetime
// of the inspector.
if (sampler_targets_ != nullptr) {
return;
}
sampler_targets_ = std::make_unique<std::unordered_map<
std::string, utils::UniqueVector<sem::SamplerTexturePair>>>();
auto& sem = program_->Sem();
for (auto* node : program_->ASTNodes().Objects()) {
auto* c = node->As<ast::CallExpression>();
if (!c) {
continue;
}
auto* call = sem.Get(c);
if (!call) {
continue;
}
auto* i = call->Target()->As<sem::Builtin>();
if (!i) {
continue;
}
const auto& signature = i->Signature();
int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
if (sampler_index == -1) {
continue;
}
int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
if (texture_index == -1) {
continue;
}
auto* call_func = call->Stmt()->Function();
std::vector<const sem::Function*> entry_points;
if (call_func->Declaration()->IsEntryPoint()) {
entry_points = {call_func};
} else {
entry_points = call_func->AncestorEntryPoints();
}
if (entry_points.empty()) {
continue;
}
auto* t = c->args[texture_index];
auto* s = c->args[sampler_index];
GetOriginatingResources(
std::array<const ast::Expression*, 2>{t, s},
[&](std::array<const sem::GlobalVariable*, 2> globals) {
auto* texture = globals[0];
sem::BindingPoint texture_binding_point = {
texture->Declaration()->BindingPoint().group->value,
texture->Declaration()->BindingPoint().binding->value};
auto* sampler = globals[1];
sem::BindingPoint sampler_binding_point = {
sampler->Declaration()->BindingPoint().group->value,
sampler->Declaration()->BindingPoint().binding->value};
for (auto* entry_point : entry_points) {
const auto& ep_name =
program_->Symbols().NameFor(entry_point->Declaration()->symbol);
(*sampler_targets_)[ep_name].add(
{sampler_binding_point, texture_binding_point});
}
});
}
}
template <size_t N, typename F>
void Inspector::GetOriginatingResources(
std::array<const ast::Expression*, N> exprs,
F&& callback) {
if (!program_->IsValid()) {
TINT_ICE(Inspector, diagnostics_)
<< "attempting to get originating resources in invalid program";
return;
}
auto& sem = program_->Sem();
std::array<const sem::GlobalVariable*, N> globals{};
std::array<const sem::Parameter*, N> parameters{};
utils::UniqueVector<const ast::CallExpression*> callsites;
for (size_t i = 0; i < N; i++) {
auto*& expr = exprs[i];
// Resolve each of the expressions
while (true) {
if (auto* user = sem.Get<sem::VariableUser>(expr)) {
auto* var = user->Variable();
if (auto* global = tint::As<sem::GlobalVariable>(var)) {
// Found the global resource declaration.
globals[i] = global;
break; // Done with this expression.
}
if (auto* local = tint::As<sem::LocalVariable>(var)) {
// Chase the variable
expr = local->Declaration()->constructor;
if (!expr) {
TINT_ICE(Inspector, diagnostics_)
<< "resource variable had no initializer";
return;
}
continue; // Continue chasing the expression in this function
}
if (auto* param = tint::As<sem::Parameter>(var)) {
// Gather each of the callers of this function
auto* func = tint::As<sem::Function>(param->Owner());
if (func->CallSites().empty()) {
// One or more of the expressions is a parameter, but this function
// is not called. Ignore.
return;
}
for (auto* call : func->CallSites()) {
callsites.add(call->Declaration());
}
// Need to evaluate each function call with the group of
// expressions, so move on to the next expression.
parameters[i] = param;
break;
}
TINT_ICE(Inspector, diagnostics_)
<< "unexpected variable type " << var->TypeInfo().name;
}
if (auto* unary = tint::As<ast::UnaryOpExpression>(expr)) {
switch (unary->op) {
case ast::UnaryOp::kAddressOf:
case ast::UnaryOp::kIndirection:
// `*` and `&` are the only valid unary ops for a resource type,
// and must be balanced in order for the program to have passed
// validation. Just skip past these.
expr = unary->expr;
continue;
default: {
TINT_ICE(Inspector, diagnostics_)
<< "unexpected unary op on resource: " << unary->op;
return;
}
}
}
TINT_ICE(Inspector, diagnostics_)
<< "cannot resolve originating resource with expression type "
<< expr->TypeInfo().name;
return;
}
}
if (callsites.size()) {
for (auto* call_expr : callsites) {
// Make a copy of the expressions for this callsite
std::array<const ast::Expression*, N> call_exprs = exprs;
// Patch all the parameter expressions with their argument
for (size_t i = 0; i < N; i++) {
if (auto* param = parameters[i]) {
call_exprs[i] = call_expr->args[param->Index()];
}
}
// Now call GetOriginatingResources() with from the callsite
GetOriginatingResources(call_exprs, callback);
}
} else {
// All the expressions resolved to globals
callback(globals);
}
}
} // namespace inspector
} // namespace tint

View File

@@ -0,0 +1,239 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_INSPECTOR_INSPECTOR_H_
#define SRC_TINT_INSPECTOR_INSPECTOR_H_
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <unordered_map>
#include <vector>
#include "src/tint/inspector/entry_point.h"
#include "src/tint/inspector/resource_binding.h"
#include "src/tint/inspector/scalar.h"
#include "src/tint/program.h"
#include "src/tint/sem/sampler_texture_pair.h"
#include "src/tint/utils/unique_vector.h"
namespace tint {
namespace inspector {
/// A temporary alias to sem::SamplerTexturePair. [DEPRECATED]
using SamplerTexturePair = sem::SamplerTexturePair;
/// Extracts information from a program
class Inspector {
public:
/// Constructor
/// @param program Shader program to extract information from.
explicit Inspector(const Program* program);
/// Destructor
~Inspector();
/// @returns error messages from the Inspector
std::string error() { return diagnostics_.str(); }
/// @returns true if an error was encountered
bool has_error() const { return diagnostics_.contains_errors(); }
/// @returns vector of entry point information
std::vector<EntryPoint> GetEntryPoints();
/// @param entry_point name of the entry point to get the remapped version of
/// @returns the remapped name of the entry point, or the empty string if it
/// isn't a known entry point.
std::string GetRemappedNameForEntryPoint(const std::string& entry_point);
/// @returns map of const_id to initial value
std::map<uint32_t, Scalar> GetConstantIDs();
/// @returns map of module-constant name to pipeline constant ID
std::map<std::string, uint32_t> GetConstantNameToIdMap();
/// @param entry_point name of the entry point to get information about.
/// @returns the total size of shared storage required by an entry point,
/// including all uniform storage buffers.
uint32_t GetStorageSize(const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the resource bindings.
std::vector<ResourceBinding> GetResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for uniform buffers.
std::vector<ResourceBinding> GetUniformBufferResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for storage buffers.
std::vector<ResourceBinding> GetStorageBufferResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for read-only storage buffers.
std::vector<ResourceBinding> GetReadOnlyStorageBufferResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for regular samplers.
std::vector<ResourceBinding> GetSamplerResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for comparison samplers.
std::vector<ResourceBinding> GetComparisonSamplerResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for sampled textures.
std::vector<ResourceBinding> GetSampledTextureResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for multisampled textures.
std::vector<ResourceBinding> GetMultisampledTextureResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for write-only storage textures.
std::vector<ResourceBinding> GetWriteOnlyStorageTextureResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for depth textures.
std::vector<ResourceBinding> GetDepthTextureResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for depth textures.
std::vector<ResourceBinding> GetDepthMultisampledTextureResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for external textures.
std::vector<ResourceBinding> GetExternalTextureResourceBindings(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the sampler/texture sampling pairs that are used
/// by that entry point.
std::vector<sem::SamplerTexturePair> GetSamplerTextureUses(
const std::string& entry_point);
/// @param entry_point name of the entry point to get information about.
/// @param placeholder the sampler binding point to use for texture-only
/// access (e.g., textureLoad)
/// @returns vector of all of the sampler/texture sampling pairs that are used
/// by that entry point.
std::vector<sem::SamplerTexturePair> GetSamplerTextureUses(
const std::string& entry_point,
const sem::BindingPoint& placeholder);
/// @param entry_point name of the entry point to get information about.
/// @returns the total size in bytes of all Workgroup storage-class storage
/// referenced transitively by the entry point.
uint32_t GetWorkgroupStorageSize(const std::string& entry_point);
private:
const Program* program_;
diag::List diagnostics_;
std::unique_ptr<
std::unordered_map<std::string,
utils::UniqueVector<sem::SamplerTexturePair>>>
sampler_targets_;
/// @param name name of the entry point to find
/// @returns a pointer to the entry point if it exists, otherwise returns
/// nullptr and sets the error string.
const ast::Function* FindEntryPointByName(const std::string& name);
/// Recursively add entry point IO variables.
/// If `type` is a struct, recurse into members, appending the member name.
/// Otherwise, add the variable unless it is a builtin.
/// @param name the name of the variable being added
/// @param type the type of the variable
/// @param attributes the variable attributes
/// @param variables the list to add the variables to
void AddEntryPointInOutVariables(std::string name,
const sem::Type* type,
const ast::AttributeList& attributes,
std::vector<StageVariable>& variables) const;
/// Recursively determine if the type contains builtin.
/// If `type` is a struct, recurse into members to check for the attribute.
/// Otherwise, check `attributes` for the attribute.
bool ContainsBuiltin(ast::Builtin builtin,
const sem::Type* type,
const ast::AttributeList& attributes) const;
/// Gathers all the texture resource bindings of the given type for the given
/// entry point.
/// @param entry_point name of the entry point to get information about.
/// @param texture_type the type of the textures to gather.
/// @param resource_type the ResourceBinding::ResourceType for the given
/// texture type.
/// @returns vector of all of the bindings for depth textures.
std::vector<ResourceBinding> GetTextureResourceBindings(
const std::string& entry_point,
const tint::TypeInfo* texture_type,
ResourceBinding::ResourceType resource_type);
/// @param entry_point name of the entry point to get information about.
/// @param read_only if true get only read-only bindings, if false get
/// write-only bindings.
/// @returns vector of all of the bindings for the requested storage buffers.
std::vector<ResourceBinding> GetStorageBufferResourceBindingsImpl(
const std::string& entry_point,
bool read_only);
/// @param entry_point name of the entry point to get information about.
/// @param multisampled_only only get multisampled textures if true, otherwise
/// only get sampled textures.
/// @returns vector of all of the bindings for the request storage buffers.
std::vector<ResourceBinding> GetSampledTextureResourceBindingsImpl(
const std::string& entry_point,
bool multisampled_only);
/// @param entry_point name of the entry point to get information about.
/// @returns vector of all of the bindings for the requested storage textures.
std::vector<ResourceBinding> GetStorageTextureResourceBindingsImpl(
const std::string& entry_point);
/// Constructs |sampler_targets_| if it hasn't already been instantiated.
void GenerateSamplerTargets();
/// For a N-uple of expressions, resolve to the appropriate global resources
/// and call 'cb'.
/// 'cb' may be called multiple times.
/// Assumes that not being able to resolve the resources is an error, so will
/// invoke TINT_ICE when that occurs.
/// @tparam N number of expressions in the n-uple
/// @tparam F type of the callback provided.
/// @param exprs N-uple of expressions to resolve.
/// @param cb is a callback function with the signature:
/// `void(std::array<const sem::GlobalVariable*, N>)`, which is invoked
/// whenever a set of expressions are resolved to globals.
template <size_t N, typename F>
void GetOriginatingResources(std::array<const ast::Expression*, N> exprs,
F&& cb);
};
} // namespace inspector
} // namespace tint
#endif // SRC_TINT_INSPECTOR_INSPECTOR_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/inspector/resource_binding.h"
#include "src/tint/sem/array.h"
#include "src/tint/sem/f32_type.h"
#include "src/tint/sem/i32_type.h"
#include "src/tint/sem/matrix_type.h"
#include "src/tint/sem/type.h"
#include "src/tint/sem/u32_type.h"
#include "src/tint/sem/vector_type.h"
namespace tint {
namespace inspector {
ResourceBinding::TextureDimension
TypeTextureDimensionToResourceBindingTextureDimension(
const ast::TextureDimension& type_dim) {
switch (type_dim) {
case ast::TextureDimension::k1d:
return ResourceBinding::TextureDimension::k1d;
case ast::TextureDimension::k2d:
return ResourceBinding::TextureDimension::k2d;
case ast::TextureDimension::k2dArray:
return ResourceBinding::TextureDimension::k2dArray;
case ast::TextureDimension::k3d:
return ResourceBinding::TextureDimension::k3d;
case ast::TextureDimension::kCube:
return ResourceBinding::TextureDimension::kCube;
case ast::TextureDimension::kCubeArray:
return ResourceBinding::TextureDimension::kCubeArray;
case ast::TextureDimension::kNone:
return ResourceBinding::TextureDimension::kNone;
}
return ResourceBinding::TextureDimension::kNone;
}
ResourceBinding::SampledKind BaseTypeToSampledKind(const sem::Type* base_type) {
if (!base_type) {
return ResourceBinding::SampledKind::kUnknown;
}
if (auto* at = base_type->As<sem::Array>()) {
base_type = at->ElemType();
} else if (auto* mt = base_type->As<sem::Matrix>()) {
base_type = mt->type();
} else if (auto* vt = base_type->As<sem::Vector>()) {
base_type = vt->type();
}
if (base_type->Is<sem::F32>()) {
return ResourceBinding::SampledKind::kFloat;
} else if (base_type->Is<sem::U32>()) {
return ResourceBinding::SampledKind::kUInt;
} else if (base_type->Is<sem::I32>()) {
return ResourceBinding::SampledKind::kSInt;
} else {
return ResourceBinding::SampledKind::kUnknown;
}
}
ResourceBinding::TexelFormat TypeTexelFormatToResourceBindingTexelFormat(
const ast::TexelFormat& image_format) {
switch (image_format) {
case ast::TexelFormat::kR32Uint:
return ResourceBinding::TexelFormat::kR32Uint;
case ast::TexelFormat::kR32Sint:
return ResourceBinding::TexelFormat::kR32Sint;
case ast::TexelFormat::kR32Float:
return ResourceBinding::TexelFormat::kR32Float;
case ast::TexelFormat::kRgba8Unorm:
return ResourceBinding::TexelFormat::kRgba8Unorm;
case ast::TexelFormat::kRgba8Snorm:
return ResourceBinding::TexelFormat::kRgba8Snorm;
case ast::TexelFormat::kRgba8Uint:
return ResourceBinding::TexelFormat::kRgba8Uint;
case ast::TexelFormat::kRgba8Sint:
return ResourceBinding::TexelFormat::kRgba8Sint;
case ast::TexelFormat::kRg32Uint:
return ResourceBinding::TexelFormat::kRg32Uint;
case ast::TexelFormat::kRg32Sint:
return ResourceBinding::TexelFormat::kRg32Sint;
case ast::TexelFormat::kRg32Float:
return ResourceBinding::TexelFormat::kRg32Float;
case ast::TexelFormat::kRgba16Uint:
return ResourceBinding::TexelFormat::kRgba16Uint;
case ast::TexelFormat::kRgba16Sint:
return ResourceBinding::TexelFormat::kRgba16Sint;
case ast::TexelFormat::kRgba16Float:
return ResourceBinding::TexelFormat::kRgba16Float;
case ast::TexelFormat::kRgba32Uint:
return ResourceBinding::TexelFormat::kRgba32Uint;
case ast::TexelFormat::kRgba32Sint:
return ResourceBinding::TexelFormat::kRgba32Sint;
case ast::TexelFormat::kRgba32Float:
return ResourceBinding::TexelFormat::kRgba32Float;
case ast::TexelFormat::kNone:
return ResourceBinding::TexelFormat::kNone;
}
return ResourceBinding::TexelFormat::kNone;
}
} // namespace inspector
} // namespace tint

View File

@@ -0,0 +1,129 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_INSPECTOR_RESOURCE_BINDING_H_
#define SRC_TINT_INSPECTOR_RESOURCE_BINDING_H_
#include <cstdint>
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/texture.h"
namespace tint {
namespace inspector {
/// Container for information about how a resource is bound
struct ResourceBinding {
/// The dimensionality of a texture
enum class TextureDimension {
/// Invalid texture
kNone = -1,
/// 1 dimensional texture
k1d,
/// 2 dimensional texture
k2d,
/// 2 dimensional array texture
k2dArray,
/// 3 dimensional texture
k3d,
/// cube texture
kCube,
/// cube array texture
kCubeArray,
};
/// Component type of the texture's data. Same as the Sampled Type parameter
/// in SPIR-V OpTypeImage.
enum class SampledKind { kUnknown = -1, kFloat, kUInt, kSInt };
/// Enumerator of texel image formats
enum class TexelFormat {
kNone = -1,
kRgba8Unorm,
kRgba8Snorm,
kRgba8Uint,
kRgba8Sint,
kRgba16Uint,
kRgba16Sint,
kRgba16Float,
kR32Uint,
kR32Sint,
kR32Float,
kRg32Uint,
kRg32Sint,
kRg32Float,
kRgba32Uint,
kRgba32Sint,
kRgba32Float,
};
/// kXXX maps to entries returned by GetXXXResourceBindings call.
enum class ResourceType {
kUniformBuffer,
kStorageBuffer,
kReadOnlyStorageBuffer,
kSampler,
kComparisonSampler,
kSampledTexture,
kMultisampledTexture,
kWriteOnlyStorageTexture,
kDepthTexture,
kDepthMultisampledTexture,
kExternalTexture
};
/// Type of resource that is bound.
ResourceType resource_type;
/// Bind group the binding belongs
uint32_t bind_group;
/// Identifier to identify this binding within the bind group
uint32_t binding;
/// Size for this binding, in bytes, if defined.
uint64_t size;
/// Size for this binding without trailing structure padding, in bytes, if
/// defined.
uint64_t size_no_padding;
/// Dimensionality of this binding, if defined.
TextureDimension dim;
/// Kind of data being sampled, if defined.
SampledKind sampled_kind;
/// Format of data, if defined.
TexelFormat image_format;
};
/// Convert from internal ast::TextureDimension to public
/// ResourceBinding::TextureDimension
/// @param type_dim internal value to convert from
/// @returns the publicly visible equivalent
ResourceBinding::TextureDimension
TypeTextureDimensionToResourceBindingTextureDimension(
const ast::TextureDimension& type_dim);
/// Infer ResourceBinding::SampledKind for a given sem::Type
/// @param base_type internal type to infer from
/// @returns the publicly visible equivalent
ResourceBinding::SampledKind BaseTypeToSampledKind(const sem::Type* base_type);
/// Convert from internal ast::TexelFormat to public
/// ResourceBinding::TexelFormat
/// @param image_format internal value to convert from
/// @returns the publicly visible equivalent
ResourceBinding::TexelFormat TypeTexelFormatToResourceBindingTexelFormat(
const ast::TexelFormat& image_format);
} // namespace inspector
} // namespace tint
#endif // SRC_TINT_INSPECTOR_RESOURCE_BINDING_H_

View File

@@ -0,0 +1,75 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/inspector/scalar.h"
namespace tint {
namespace inspector {
Scalar::Scalar() : type_(kNull) {}
Scalar::Scalar(bool val) : type_(kBool) {
value_.b = val;
}
Scalar::Scalar(uint32_t val) : type_(kU32) {
value_.u = val;
}
Scalar::Scalar(int32_t val) : type_(kI32) {
value_.i = val;
}
Scalar::Scalar(float val) : type_(kFloat) {
value_.f = val;
}
bool Scalar::IsNull() const {
return type_ == kNull;
}
bool Scalar::IsBool() const {
return type_ == kBool;
}
bool Scalar::IsU32() const {
return type_ == kU32;
}
bool Scalar::IsI32() const {
return type_ == kI32;
}
bool Scalar::IsFloat() const {
return type_ == kFloat;
}
bool Scalar::AsBool() const {
return value_.b;
}
uint32_t Scalar::AsU32() const {
return value_.u;
}
int32_t Scalar::AsI32() const {
return value_.i;
}
float Scalar::AsFloat() const {
return value_.f;
}
} // namespace inspector
} // namespace tint

View File

@@ -0,0 +1,80 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_INSPECTOR_SCALAR_H_
#define SRC_TINT_INSPECTOR_SCALAR_H_
#include <cstdint>
namespace tint {
namespace inspector {
/// Contains a literal scalar value
class Scalar {
public:
/// Null Constructor
Scalar();
/// @param val literal scalar value to contain
explicit Scalar(bool val);
/// @param val literal scalar value to contain
explicit Scalar(uint32_t val);
/// @param val literal scalar value to contain
explicit Scalar(int32_t val);
/// @param val literal scalar value to contain
explicit Scalar(float val);
/// @returns true if this is a null
bool IsNull() const;
/// @returns true if this is a bool
bool IsBool() const;
/// @returns true if this is a unsigned integer.
bool IsU32() const;
/// @returns true if this is a signed integer.
bool IsI32() const;
/// @returns true if this is a float.
bool IsFloat() const;
/// @returns scalar value if bool, otherwise undefined behaviour.
bool AsBool() const;
/// @returns scalar value if unsigned integer, otherwise undefined behaviour.
uint32_t AsU32() const;
/// @returns scalar value if signed integer, otherwise undefined behaviour.
int32_t AsI32() const;
/// @returns scalar value if float, otherwise undefined behaviour.
float AsFloat() const;
private:
typedef enum {
kNull,
kBool,
kU32,
kI32,
kFloat,
} Type;
typedef union {
bool b;
uint32_t u;
int32_t i;
float f;
} Value;
Type type_;
Value value_;
};
} // namespace inspector
} // namespace tint
#endif // SRC_TINT_INSPECTOR_SCALAR_H_

View File

@@ -0,0 +1,405 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/inspector/test_inspector_builder.h"
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "gtest/gtest.h"
namespace tint {
namespace inspector {
InspectorBuilder::InspectorBuilder() = default;
InspectorBuilder::~InspectorBuilder() = default;
void InspectorBuilder::MakeEmptyBodyFunction(std::string name,
ast::AttributeList attributes) {
Func(name, ast::VariableList(), ty.void_(), ast::StatementList{Return()},
attributes);
}
void InspectorBuilder::MakeCallerBodyFunction(std::string caller,
std::vector<std::string> callees,
ast::AttributeList attributes) {
ast::StatementList body;
body.reserve(callees.size() + 1);
for (auto callee : callees) {
body.push_back(CallStmt(Call(callee)));
}
body.push_back(Return());
Func(caller, ast::VariableList(), ty.void_(), body, attributes);
}
const ast::Struct* InspectorBuilder::MakeInOutStruct(
std::string name,
std::vector<std::tuple<std::string, uint32_t>> inout_vars) {
ast::StructMemberList members;
for (auto var : inout_vars) {
std::string member_name;
uint32_t location;
std::tie(member_name, location) = var;
members.push_back(
Member(member_name, ty.u32(), {Location(location), Flat()}));
}
return Structure(name, members);
}
const ast::Function* InspectorBuilder::MakePlainGlobalReferenceBodyFunction(
std::string func,
std::string var,
const ast::Type* type,
ast::AttributeList attributes) {
ast::StatementList stmts;
stmts.emplace_back(Decl(Var("local_" + var, type)));
stmts.emplace_back(Assign("local_" + var, var));
stmts.emplace_back(Return());
return Func(func, ast::VariableList(), ty.void_(), stmts, attributes);
}
bool InspectorBuilder::ContainsName(const std::vector<StageVariable>& vec,
const std::string& name) {
for (auto& s : vec) {
if (s.name == name) {
return true;
}
}
return false;
}
std::string InspectorBuilder::StructMemberName(size_t idx,
const ast::Type* type) {
return std::to_string(idx) + type->FriendlyName(Symbols());
}
const ast::Struct* InspectorBuilder::MakeStructType(
const std::string& name,
std::vector<const ast::Type*> member_types,
bool is_block) {
ast::StructMemberList members;
for (auto* type : member_types) {
members.push_back(MakeStructMember(members.size(), type, {}));
}
return MakeStructTypeFromMembers(name, std::move(members), is_block);
}
const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(
const std::string& name,
ast::StructMemberList members,
bool is_block) {
ast::AttributeList attrs;
if (is_block) {
attrs.push_back(create<ast::StructBlockAttribute>());
}
return Structure(name, std::move(members), attrs);
}
const ast::StructMember* InspectorBuilder::MakeStructMember(
size_t index,
const ast::Type* type,
ast::AttributeList attributes) {
return Member(StructMemberName(index, type), type, std::move(attributes));
}
const ast::Struct* InspectorBuilder::MakeUniformBufferType(
const std::string& name,
std::vector<const ast::Type*> member_types) {
return MakeStructType(name, member_types, true);
}
std::function<const ast::TypeName*()> InspectorBuilder::MakeStorageBufferTypes(
const std::string& name,
std::vector<const ast::Type*> member_types) {
MakeStructType(name, member_types, true);
return [this, name] { return ty.type_name(name); };
}
void InspectorBuilder::AddUniformBuffer(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding) {
Global(name, type, ast::StorageClass::kUniform,
ast::AttributeList{
create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group),
});
}
void InspectorBuilder::AddWorkgroupStorage(const std::string& name,
const ast::Type* type) {
Global(name, type, ast::StorageClass::kWorkgroup);
}
void InspectorBuilder::AddStorageBuffer(const std::string& name,
const ast::Type* type,
ast::Access access,
uint32_t group,
uint32_t binding) {
Global(name, type, ast::StorageClass::kStorage, access,
ast::AttributeList{
create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group),
});
}
void InspectorBuilder::MakeStructVariableReferenceBodyFunction(
std::string func_name,
std::string struct_name,
std::vector<std::tuple<size_t, const ast::Type*>> members) {
ast::StatementList stmts;
for (auto member : members) {
size_t member_idx;
const ast::Type* member_type;
std::tie(member_idx, member_type) = member;
std::string member_name = StructMemberName(member_idx, member_type);
stmts.emplace_back(Decl(Var("local" + member_name, member_type)));
}
for (auto member : members) {
size_t member_idx;
const ast::Type* member_type;
std::tie(member_idx, member_type) = member;
std::string member_name = StructMemberName(member_idx, member_type);
stmts.emplace_back(Assign("local" + member_name,
MemberAccessor(struct_name, member_name)));
}
stmts.emplace_back(Return());
Func(func_name, ast::VariableList(), ty.void_(), stmts, ast::AttributeList{});
}
void InspectorBuilder::AddSampler(const std::string& name,
uint32_t group,
uint32_t binding) {
Global(name, sampler_type(),
ast::AttributeList{
create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group),
});
}
void InspectorBuilder::AddComparisonSampler(const std::string& name,
uint32_t group,
uint32_t binding) {
Global(name, comparison_sampler_type(),
ast::AttributeList{
create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group),
});
}
void InspectorBuilder::AddResource(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding) {
Global(name, type,
ast::AttributeList{
create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group),
});
}
void InspectorBuilder::AddGlobalVariable(const std::string& name,
const ast::Type* type) {
Global(name, type, ast::StorageClass::kPrivate);
}
const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
const std::string& func_name,
const std::string& texture_name,
const std::string& sampler_name,
const std::string& coords_name,
const ast::Type* base_type,
ast::AttributeList attributes) {
std::string result_name = "sampler_result";
ast::StatementList stmts;
stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4))));
stmts.emplace_back(Assign(result_name, Call("textureSample", texture_name,
sampler_name, coords_name)));
stmts.emplace_back(Return());
return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
}
const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
const std::string& func_name,
const std::string& texture_name,
const std::string& sampler_name,
const std::string& coords_name,
const std::string& array_index,
const ast::Type* base_type,
ast::AttributeList attributes) {
std::string result_name = "sampler_result";
ast::StatementList stmts;
stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4))));
stmts.emplace_back(
Assign("sampler_result", Call("textureSample", texture_name, sampler_name,
coords_name, array_index)));
stmts.emplace_back(Return());
return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
}
const ast::Function*
InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction(
const std::string& func_name,
const std::string& texture_name,
const std::string& sampler_name,
const std::string& coords_name,
const std::string& depth_name,
const ast::Type* base_type,
ast::AttributeList attributes) {
std::string result_name = "sampler_result";
ast::StatementList stmts;
stmts.emplace_back(Decl(Var("sampler_result", base_type)));
stmts.emplace_back(
Assign("sampler_result", Call("textureSampleCompare", texture_name,
sampler_name, coords_name, depth_name)));
stmts.emplace_back(Return());
return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
}
const ast::Type* InspectorBuilder::GetBaseType(
ResourceBinding::SampledKind sampled_kind) {
switch (sampled_kind) {
case ResourceBinding::SampledKind::kFloat:
return ty.f32();
case ResourceBinding::SampledKind::kSInt:
return ty.i32();
case ResourceBinding::SampledKind::kUInt:
return ty.u32();
default:
return nullptr;
}
}
const ast::Type* InspectorBuilder::GetCoordsType(ast::TextureDimension dim,
const ast::Type* scalar) {
switch (dim) {
case ast::TextureDimension::k1d:
return scalar;
case ast::TextureDimension::k2d:
case ast::TextureDimension::k2dArray:
return create<ast::Vector>(scalar, 2);
case ast::TextureDimension::k3d:
case ast::TextureDimension::kCube:
case ast::TextureDimension::kCubeArray:
return create<ast::Vector>(scalar, 3);
default:
[=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
}
return nullptr;
}
const ast::Type* InspectorBuilder::MakeStorageTextureTypes(
ast::TextureDimension dim,
ast::TexelFormat format) {
return ty.storage_texture(dim, format, ast::Access::kWrite);
}
void InspectorBuilder::AddStorageTexture(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding) {
Global(name, type,
ast::AttributeList{
create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group),
});
}
const ast::Function* InspectorBuilder::MakeStorageTextureBodyFunction(
const std::string& func_name,
const std::string& st_name,
const ast::Type* dim_type,
ast::AttributeList attributes) {
ast::StatementList stmts;
stmts.emplace_back(Decl(Var("dim", dim_type)));
stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name)));
stmts.emplace_back(Return());
return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
}
std::function<const ast::Type*()> InspectorBuilder::GetTypeFunction(
ComponentType component,
CompositionType composition) {
std::function<const ast::Type*()> func;
switch (component) {
case ComponentType::kFloat:
func = [this]() -> const ast::Type* { return ty.f32(); };
break;
case ComponentType::kSInt:
func = [this]() -> const ast::Type* { return ty.i32(); };
break;
case ComponentType::kUInt:
func = [this]() -> const ast::Type* { return ty.u32(); };
break;
case ComponentType::kUnknown:
return []() -> const ast::Type* { return nullptr; };
}
uint32_t n;
switch (composition) {
case CompositionType::kScalar:
return func;
case CompositionType::kVec2:
n = 2;
break;
case CompositionType::kVec3:
n = 3;
break;
case CompositionType::kVec4:
n = 4;
break;
default:
return []() -> ast::Type* { return nullptr; };
}
return [this, func, n]() -> const ast::Type* { return ty.vec(func(), n); };
}
Inspector& InspectorBuilder::Build() {
if (inspector_) {
return *inspector_;
}
program_ = std::make_unique<Program>(std::move(*this));
[&]() {
ASSERT_TRUE(program_->IsValid())
<< diag::Formatter().format(program_->Diagnostics());
}();
inspector_ = std::make_unique<Inspector>(program_.get());
return *inspector_;
}
} // namespace inspector
} // namespace tint

View File

@@ -0,0 +1,391 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_INSPECTOR_TEST_INSPECTOR_BUILDER_H_
#define SRC_TINT_INSPECTOR_TEST_INSPECTOR_BUILDER_H_
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "src/tint/ast/call_statement.h"
#include "src/tint/ast/disable_validation_attribute.h"
#include "src/tint/ast/id_attribute.h"
#include "src/tint/ast/stage_attribute.h"
#include "src/tint/ast/struct_block_attribute.h"
#include "src/tint/ast/workgroup_attribute.h"
#include "src/tint/program_builder.h"
#include "src/tint/sem/depth_texture_type.h"
#include "src/tint/sem/external_texture_type.h"
#include "src/tint/sem/multisampled_texture_type.h"
#include "src/tint/sem/sampled_texture_type.h"
#include "src/tint/sem/variable.h"
#include "tint/tint.h"
namespace tint {
namespace inspector {
/// Utility class for building programs in inspector tests
class InspectorBuilder : public ProgramBuilder {
public:
InspectorBuilder();
~InspectorBuilder() override;
/// Generates an empty function
/// @param name name of the function created
/// @param attributes the function attributes
void MakeEmptyBodyFunction(std::string name, ast::AttributeList attributes);
/// Generates a function that calls other functions
/// @param caller name of the function created
/// @param callees names of the functions to be called
/// @param attributes the function attributes
void MakeCallerBodyFunction(std::string caller,
std::vector<std::string> callees,
ast::AttributeList attributes);
/// Generates a struct that contains user-defined IO members
/// @param name the name of the generated struct
/// @param inout_vars tuples of {name, loc} that will be the struct members
/// @returns a structure object
const ast::Struct* MakeInOutStruct(
std::string name,
std::vector<std::tuple<std::string, uint32_t>> inout_vars);
// TODO(crbug.com/tint/697): Remove this.
/// Add In/Out variables to the global variables
/// @param inout_vars tuples of {in, out} that will be added as entries to the
/// global variables
void AddInOutVariables(
std::vector<std::tuple<std::string, std::string>> inout_vars);
// TODO(crbug.com/tint/697): Remove this.
/// Generates a function that references in/out variables
/// @param name name of the function created
/// @param inout_vars tuples of {in, out} that will be converted into out = in
/// calls in the function body
/// @param attributes the function attributes
void MakeInOutVariableBodyFunction(
std::string name,
std::vector<std::tuple<std::string, std::string>> inout_vars,
ast::AttributeList attributes);
// TODO(crbug.com/tint/697): Remove this.
/// Generates a function that references in/out variables and calls another
/// function.
/// @param caller name of the function created
/// @param callee name of the function to be called
/// @param inout_vars tuples of {in, out} that will be converted into out = in
/// calls in the function body
/// @param attributes the function attributes
/// @returns a function object
const ast::Function* MakeInOutVariableCallerBodyFunction(
std::string caller,
std::string callee,
std::vector<std::tuple<std::string, std::string>> inout_vars,
ast::AttributeList attributes);
/// Add a pipeline constant to the global variables, with a specific ID.
/// @param name name of the variable to add
/// @param id id number for the constant id
/// @param type type of the variable
/// @param constructor val to initialize the constant with, if NULL no
/// constructor will be added.
/// @returns the constant that was created
const ast::Variable* AddOverridableConstantWithID(
std::string name,
uint32_t id,
const ast::Type* type,
const ast::Expression* constructor) {
return Override(name, type, constructor, {Id(id)});
}
/// Add a pipeline constant to the global variables, without a specific ID.
/// @param name name of the variable to add
/// @param type type of the variable
/// @param constructor val to initialize the constant with, if NULL no
/// constructor will be added.
/// @returns the constant that was created
const ast::Variable* AddOverridableConstantWithoutID(
std::string name,
const ast::Type* type,
const ast::Expression* constructor) {
return Override(name, type, constructor);
}
/// Generates a function that references module-scoped, plain-typed constant
/// or variable.
/// @param func name of the function created
/// @param var name of the constant to be reference
/// @param type type of the const being referenced
/// @param attributes the function attributes
/// @returns a function object
const ast::Function* MakePlainGlobalReferenceBodyFunction(
std::string func,
std::string var,
const ast::Type* type,
ast::AttributeList attributes);
/// @param vec Vector of StageVariable to be searched
/// @param name Name to be searching for
/// @returns true if name is in vec, otherwise false
bool ContainsName(const std::vector<StageVariable>& vec,
const std::string& name);
/// Builds a string for accessing a member in a generated struct
/// @param idx index of member
/// @param type type of member
/// @returns a string for the member
std::string StructMemberName(size_t idx, const ast::Type* type);
/// Generates a struct type
/// @param name name for the type
/// @param member_types a vector of member types
/// @param is_block whether or not to decorate as a Block
/// @returns a struct type
const ast::Struct* MakeStructType(const std::string& name,
std::vector<const ast::Type*> member_types,
bool is_block);
/// Generates a struct type from a list of member nodes.
/// @param name name for the struct type
/// @param members a vector of members
/// @param is_block whether or not to decorate as a Block
/// @returns a struct type
const ast::Struct* MakeStructTypeFromMembers(const std::string& name,
ast::StructMemberList members,
bool is_block);
/// Generates a struct member with a specified index and type.
/// @param index index of the field within the struct
/// @param type the type of the member field
/// @param attributes a list of attributes to apply to the member field
/// @returns a struct member
const ast::StructMember* MakeStructMember(size_t index,
const ast::Type* type,
ast::AttributeList attributes);
/// Generates types appropriate for using in an uniform buffer
/// @param name name for the type
/// @param member_types a vector of member types
/// @returns a struct type that has the layout for an uniform buffer.
const ast::Struct* MakeUniformBufferType(
const std::string& name,
std::vector<const ast::Type*> member_types);
/// Generates types appropriate for using in a storage buffer
/// @param name name for the type
/// @param member_types a vector of member types
/// @returns a function that returns the created structure.
std::function<const ast::TypeName*()> MakeStorageBufferTypes(
const std::string& name,
std::vector<const ast::Type*> member_types);
/// Adds an uniform buffer variable to the program
/// @param name the name of the variable
/// @param type the type to use
/// @param group the binding/group/ to use for the uniform buffer
/// @param binding the binding number to use for the uniform buffer
void AddUniformBuffer(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding);
/// Adds a workgroup storage variable to the program
/// @param name the name of the variable
/// @param type the type of the variable
void AddWorkgroupStorage(const std::string& name, const ast::Type* type);
/// Adds a storage buffer variable to the program
/// @param name the name of the variable
/// @param type the type to use
/// @param access the storage buffer access control
/// @param group the binding/group to use for the storage buffer
/// @param binding the binding number to use for the storage buffer
void AddStorageBuffer(const std::string& name,
const ast::Type* type,
ast::Access access,
uint32_t group,
uint32_t binding);
/// Generates a function that references a specific struct variable
/// @param func_name name of the function created
/// @param struct_name name of the struct variabler to be accessed
/// @param members list of members to access, by index and type
void MakeStructVariableReferenceBodyFunction(
std::string func_name,
std::string struct_name,
std::vector<std::tuple<size_t, const ast::Type*>> members);
/// Adds a regular sampler variable to the program
/// @param name the name of the variable
/// @param group the binding/group to use for the storage buffer
/// @param binding the binding number to use for the storage buffer
void AddSampler(const std::string& name, uint32_t group, uint32_t binding);
/// Adds a comparison sampler variable to the program
/// @param name the name of the variable
/// @param group the binding/group to use for the storage buffer
/// @param binding the binding number to use for the storage buffer
void AddComparisonSampler(const std::string& name,
uint32_t group,
uint32_t binding);
/// Adds a sampler or texture variable to the program
/// @param name the name of the variable
/// @param type the type to use
/// @param group the binding/group to use for the resource
/// @param binding the binding number to use for the resource
void AddResource(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding);
/// Add a module scope private variable to the progames
/// @param name the name of the variable
/// @param type the type to use
void AddGlobalVariable(const std::string& name, const ast::Type* type);
/// Generates a function that references a specific sampler variable
/// @param func_name name of the function created
/// @param texture_name name of the texture to be sampled
/// @param sampler_name name of the sampler to use
/// @param coords_name name of the coords variable to use
/// @param base_type sampler base type
/// @param attributes the function attributes
/// @returns a function that references all of the values specified
const ast::Function* MakeSamplerReferenceBodyFunction(
const std::string& func_name,
const std::string& texture_name,
const std::string& sampler_name,
const std::string& coords_name,
const ast::Type* base_type,
ast::AttributeList attributes);
/// Generates a function that references a specific sampler variable
/// @param func_name name of the function created
/// @param texture_name name of the texture to be sampled
/// @param sampler_name name of the sampler to use
/// @param coords_name name of the coords variable to use
/// @param array_index name of the array index variable to use
/// @param base_type sampler base type
/// @param attributes the function attributes
/// @returns a function that references all of the values specified
const ast::Function* MakeSamplerReferenceBodyFunction(
const std::string& func_name,
const std::string& texture_name,
const std::string& sampler_name,
const std::string& coords_name,
const std::string& array_index,
const ast::Type* base_type,
ast::AttributeList attributes);
/// Generates a function that references a specific comparison sampler
/// variable.
/// @param func_name name of the function created
/// @param texture_name name of the depth texture to use
/// @param sampler_name name of the sampler to use
/// @param coords_name name of the coords variable to use
/// @param depth_name name of the depth reference to use
/// @param base_type sampler base type
/// @param attributes the function attributes
/// @returns a function that references all of the values specified
const ast::Function* MakeComparisonSamplerReferenceBodyFunction(
const std::string& func_name,
const std::string& texture_name,
const std::string& sampler_name,
const std::string& coords_name,
const std::string& depth_name,
const ast::Type* base_type,
ast::AttributeList attributes);
/// Gets an appropriate type for the data in a given texture type.
/// @param sampled_kind type of in the texture
/// @returns a pointer to a type appropriate for the coord param
const ast::Type* GetBaseType(ResourceBinding::SampledKind sampled_kind);
/// Gets an appropriate type for the coords parameter depending the the
/// dimensionality of the texture being sampled.
/// @param dim dimensionality of the texture being sampled
/// @param scalar the scalar type
/// @returns a pointer to a type appropriate for the coord param
const ast::Type* GetCoordsType(ast::TextureDimension dim,
const ast::Type* scalar);
/// Generates appropriate types for a Read-Only StorageTexture
/// @param dim the texture dimension of the storage texture
/// @param format the texel format of the storage texture
/// @returns the storage texture type
const ast::Type* MakeStorageTextureTypes(ast::TextureDimension dim,
ast::TexelFormat format);
/// Adds a storage texture variable to the program
/// @param name the name of the variable
/// @param type the type to use
/// @param group the binding/group to use for the sampled texture
/// @param binding the binding57 number to use for the sampled texture
void AddStorageTexture(const std::string& name,
const ast::Type* type,
uint32_t group,
uint32_t binding);
/// Generates a function that references a storage texture variable.
/// @param func_name name of the function created
/// @param st_name name of the storage texture to use
/// @param dim_type type expected by textureDimensons to return
/// @param attributes the function attributes
/// @returns a function that references all of the values specified
const ast::Function* MakeStorageTextureBodyFunction(
const std::string& func_name,
const std::string& st_name,
const ast::Type* dim_type,
ast::AttributeList attributes);
/// Get a generator function that returns a type appropriate for a stage
/// variable with the given combination of component and composition type.
/// @param component component type of the stage variable
/// @param composition composition type of the stage variable
/// @returns a generator function for the stage variable's type.
std::function<const ast::Type*()> GetTypeFunction(
ComponentType component,
CompositionType composition);
/// Build the Program given all of the previous methods called and return an
/// Inspector for it.
/// Should only be called once per test.
/// @returns a reference to the Inspector for the built Program.
Inspector& Build();
/// @returns the type for a SamplerKind::kSampler
const ast::Sampler* sampler_type() {
return ty.sampler(ast::SamplerKind::kSampler);
}
/// @returns the type for a SamplerKind::kComparison
const ast::Sampler* comparison_sampler_type() {
return ty.sampler(ast::SamplerKind::kComparisonSampler);
}
protected:
/// Program built by this builder.
std::unique_ptr<Program> program_;
/// Inspector for |program_|
std::unique_ptr<Inspector> inspector_;
};
} // namespace inspector
} // namespace tint
#endif // SRC_TINT_INSPECTOR_TEST_INSPECTOR_BUILDER_H_

View File

@@ -0,0 +1,39 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/inspector/test_inspector_runner.h"
namespace tint {
namespace inspector {
InspectorRunner::InspectorRunner() = default;
InspectorRunner::~InspectorRunner() = default;
Inspector& InspectorRunner::Initialize(std::string shader) {
if (inspector_) {
return *inspector_;
}
file_ = std::make_unique<Source::File>("test", shader);
program_ = std::make_unique<Program>(reader::wgsl::Parse(file_.get()));
[&]() {
ASSERT_TRUE(program_->IsValid())
<< diag::Formatter().format(program_->Diagnostics());
}();
inspector_ = std::make_unique<Inspector>(program_.get());
return *inspector_;
}
} // namespace inspector
} // namespace tint

View File

@@ -0,0 +1,51 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_INSPECTOR_TEST_INSPECTOR_RUNNER_H_
#define SRC_TINT_INSPECTOR_TEST_INSPECTOR_RUNNER_H_
#include <memory>
#include <string>
#include "gtest/gtest.h"
#include "tint/tint.h"
namespace tint {
namespace inspector {
/// Utility class for running shaders in inspector tests
class InspectorRunner {
public:
InspectorRunner();
virtual ~InspectorRunner();
/// Create a Program with Inspector from the provided WGSL shader.
/// Should only be called once per test.
/// @param shader a WGSL shader
/// @returns a reference to the Inspector for the built Program.
Inspector& Initialize(std::string shader);
protected:
/// File created from input shader and used to create Program.
std::unique_ptr<Source::File> file_;
/// Program created by this runner.
std::unique_ptr<Program> program_;
/// Inspector for |program_|
std::unique_ptr<Inspector> inspector_;
};
} // namespace inspector
} // namespace tint
#endif // SRC_TINT_INSPECTOR_TEST_INSPECTOR_RUNNER_H_