Expose interpolation and dimensional data about IO variables

BUG=tint:859

Change-Id: I12da0fa49d7384bc321d27e84bad76b23081a56e
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56623
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
Ryan Harrison 2021-06-30 21:07:42 +00:00 committed by Tint LUCI CQ
parent 62c8f2a9d6
commit d4c64af117
6 changed files with 319 additions and 46 deletions

View File

@ -22,5 +22,35 @@ EntryPoint::EntryPoint(EntryPoint&) = default;
EntryPoint::EntryPoint(EntryPoint&&) = default; EntryPoint::EntryPoint(EntryPoint&&) = default;
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 inspector
} // namespace tint } // namespace tint

View File

@ -19,6 +19,7 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "src/ast/interpolate_decoration.h"
#include "src/ast/pipeline_stage.h" #include "src/ast/pipeline_stage.h"
namespace tint { namespace tint {
@ -32,19 +33,60 @@ enum class ComponentType {
kSInt, 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. /// Reflection data about an entry point input or output.
struct StageVariable { struct StageVariable {
/// Name of the variable in the shader. /// Name of the variable in the shader.
std::string name; std::string name;
/// Is Location Decoration present /// Is Location Decoration present
bool has_location_decoration; bool has_location_decoration = false;
/// Value of Location Decoration, only valid if |has_location_decoration| is /// Value of Location Decoration, only valid if |has_location_decoration| is
/// true. /// true.
uint32_t location_decoration; uint32_t location_decoration;
/// Scalar type that the variable is composed of. /// Scalar type that the variable is composed of.
ComponentType component_type; 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 /// Reflection data about a pipeline overridable constant referenced by an entry
/// point /// point
struct OverridableConstant { struct OverridableConstant {

View File

@ -19,6 +19,8 @@
#include "src/ast/bool_literal.h" #include "src/ast/bool_literal.h"
#include "src/ast/call_expression.h" #include "src/ast/call_expression.h"
#include "src/ast/float_literal.h" #include "src/ast/float_literal.h"
#include "src/ast/interpolate_decoration.h"
#include "src/ast/location_decoration.h"
#include "src/ast/module.h" #include "src/ast/module.h"
#include "src/ast/override_decoration.h" #include "src/ast/override_decoration.h"
#include "src/ast/scalar_constructor_expression.h" #include "src/ast/scalar_constructor_expression.h"
@ -56,6 +58,68 @@ void AppendResourceBindings(std::vector<ResourceBinding>* dest,
dest->insert(dest->end(), orig.begin(), orig.end()); 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->size() == 2) {
return {ComponentType::kFloat, CompositionType::kVec2};
} else if (vec->size() == 3) {
return {ComponentType::kFloat, CompositionType::kVec3};
} else if (vec->size() == 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->size() == 2) {
return {ComponentType::kUInt, CompositionType::kVec2};
} else if (vec->size() == 3) {
return {ComponentType::kUInt, CompositionType::kVec3};
} else if (vec->size() == 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->size() == 2) {
return {ComponentType::kSInt, CompositionType::kVec2};
} else if (vec->size() == 3) {
return {ComponentType::kSInt, CompositionType::kVec3};
} else if (vec->size() == 4) {
return {ComponentType::kSInt, CompositionType::kVec4};
}
}
return {ComponentType::kUnknown, CompositionType::kUnknown};
}
std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData(
const sem::Type* type,
const ast::DecorationList& decorations) {
auto* interpolation_decoration =
ast::GetDecoration<ast::InterpolateDecoration>(decorations);
if (type->is_integer_scalar_or_vector()) {
return {InterpolationType::kFlat, InterpolationSampling::kNone};
}
if (!interpolation_decoration) {
return {InterpolationType::kPerspective, InterpolationSampling::kCenter};
}
auto interpolation_type = interpolation_decoration->type();
auto sampling = interpolation_decoration->sampling();
if (interpolation_type != ast::InterpolationType::kFlat &&
sampling == ast::InterpolationSampling::kNone) {
sampling = ast::InterpolationSampling::kCenter;
}
return {ASTToInspectorInterpolationType(interpolation_type),
ASTToInspectorInterpolationSampling(sampling)};
}
} // namespace } // namespace
Inspector::Inspector(const Program* program) : program_(program) {} Inspector::Inspector(const Program* program) : program_(program) {}
@ -116,15 +180,10 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
StageVariable stage_variable; StageVariable stage_variable;
stage_variable.name = name; stage_variable.name = name;
stage_variable.component_type = ComponentType::kUnknown;
auto* type = var->Type()->UnwrapRef(); auto* type = var->Type()->UnwrapRef();
if (type->is_float_scalar_or_vector() || type->is_float_matrix()) { std::tie(stage_variable.component_type,
stage_variable.component_type = ComponentType::kFloat; stage_variable.composition_type) =
} else if (type->is_unsigned_scalar_or_vector()) { CalculateComponentAndComposition(type);
stage_variable.component_type = ComponentType::kUInt;
} else if (type->is_signed_scalar_or_vector()) {
stage_variable.component_type = ComponentType::kSInt;
}
auto* location_decoration = auto* location_decoration =
ast::GetDecoration<ast::LocationDecoration>(decl->decorations()); ast::GetDecoration<ast::LocationDecoration>(decl->decorations());
@ -135,6 +194,10 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
stage_variable.has_location_decoration = false; stage_variable.has_location_decoration = false;
} }
std::tie(stage_variable.interpolation_type,
stage_variable.interpolation_sampling) =
CalculateInterpolationData(type, decl->decorations());
if (var->StorageClass() == ast::StorageClass::kInput) { if (var->StorageClass() == ast::StorageClass::kInput) {
entry_point.input_variables.push_back(stage_variable); entry_point.input_variables.push_back(stage_variable);
} else if (var->StorageClass() == ast::StorageClass::kOutput) { } else if (var->StorageClass() == ast::StorageClass::kOutput) {
@ -520,21 +583,18 @@ void Inspector::AddEntryPointInOutVariables(
StageVariable stage_variable; StageVariable stage_variable;
stage_variable.name = name; stage_variable.name = name;
stage_variable.component_type = ComponentType::kUnknown; std::tie(stage_variable.component_type, stage_variable.composition_type) =
if (unwrapped_type->is_float_scalar_or_vector() || CalculateComponentAndComposition(type);
unwrapped_type->is_float_matrix()) {
stage_variable.component_type = ComponentType::kFloat;
} else if (unwrapped_type->is_unsigned_scalar_or_vector()) {
stage_variable.component_type = ComponentType::kUInt;
} else if (unwrapped_type->is_signed_scalar_or_vector()) {
stage_variable.component_type = ComponentType::kSInt;
}
auto* location = ast::GetDecoration<ast::LocationDecoration>(decorations); auto* location = ast::GetDecoration<ast::LocationDecoration>(decorations);
TINT_ASSERT(Inspector, location != nullptr); TINT_ASSERT(Inspector, location != nullptr);
stage_variable.has_location_decoration = true; stage_variable.has_location_decoration = true;
stage_variable.location_decoration = location->value(); stage_variable.location_decoration = location->value();
std::tie(stage_variable.interpolation_type,
stage_variable.interpolation_sampling) =
CalculateInterpolationData(type, decorations);
variables.push_back(stage_variable); variables.push_back(stage_variable);
} }

View File

@ -639,6 +639,43 @@ class InspectorHelper : public ProgramBuilder {
return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
} }
std::function<ast::Type*()> GetTypeFunction(ComponentType component,
CompositionType composition) {
std::function<ast::Type*()> func;
switch (component) {
case ComponentType::kFloat:
func = [this]() -> ast::Type* { return ty.f32(); };
break;
case ComponentType::kSInt:
func = [this]() -> ast::Type* { return ty.i32(); };
break;
case ComponentType::kUInt:
func = [this]() -> ast::Type* { return ty.u32(); };
break;
case ComponentType::kUnknown:
return []() -> 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]() -> ast::Type* { return ty.vec(func(), n); };
}
Inspector& Build() { Inspector& Build() {
if (inspector_) { if (inspector_) {
return *inspector_; return *inspector_;
@ -666,9 +703,23 @@ class InspectorHelper : public ProgramBuilder {
class InspectorGetEntryPointTest : public InspectorHelper, class InspectorGetEntryPointTest : public InspectorHelper,
public testing::Test {}; public testing::Test {};
class InspectorGetEntryPointTestWithComponentTypeParam
typedef std::tuple<inspector::ComponentType, inspector::CompositionType>
InspectorGetEntryPointComponentAndCompositionTestParams;
class InspectorGetEntryPointComponentAndCompositionTest
: public InspectorHelper, : public InspectorHelper,
public testing::TestWithParam<ComponentType> {}; public testing::TestWithParam<
InspectorGetEntryPointComponentAndCompositionTestParams> {};
struct InspectorGetEntryPointInterpolateTestParams {
ast::InterpolationType in_type;
ast::InterpolationSampling in_sampling;
inspector::InterpolationType out_type;
inspector::InterpolationSampling out_sampling;
};
class InspectorGetEntryPointInterpolateTest
: public InspectorHelper,
public testing::TestWithParam<
InspectorGetEntryPointInterpolateTestParams> {};
class InspectorGetRemappedNameForEntryPointTest : public InspectorHelper, class InspectorGetRemappedNameForEntryPointTest : public InspectorHelper,
public testing::Test {}; public testing::Test {};
class InspectorGetConstantIDsTest : public InspectorHelper, class InspectorGetConstantIDsTest : public InspectorHelper,
@ -889,22 +940,12 @@ TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
EXPECT_EQ(0u, result[0].output_variables.size()); EXPECT_EQ(0u, result[0].output_variables.size());
} }
TEST_P(InspectorGetEntryPointTestWithComponentTypeParam, InOutVariables) { TEST_P(InspectorGetEntryPointComponentAndCompositionTest, Test) {
ComponentType inspector_type = GetParam(); ComponentType component;
std::function<ast::Type*()> tint_type; CompositionType composition;
switch (inspector_type) { std::tie(component, composition) = GetParam();
case ComponentType::kFloat: std::function<ast::Type*()> tint_type =
tint_type = [this]() -> ast::Type* { return ty.f32(); }; GetTypeFunction(component, composition);
break;
case ComponentType::kSInt:
tint_type = [this]() -> ast::Type* { return ty.i32(); };
break;
case ComponentType::kUInt:
tint_type = [this]() -> ast::Type* { return ty.u32(); };
break;
case ComponentType::kUnknown:
return;
}
auto* in_var = Param("in_var", tint_type(), {Location(0u)}); auto* in_var = Param("in_var", tint_type(), {Location(0u)});
Func("foo", {in_var}, tint_type(), {Return("in_var")}, Func("foo", {in_var}, tint_type(), {Return("in_var")},
@ -920,19 +961,24 @@ TEST_P(InspectorGetEntryPointTestWithComponentTypeParam, InOutVariables) {
EXPECT_EQ("in_var", result[0].input_variables[0].name); EXPECT_EQ("in_var", result[0].input_variables[0].name);
EXPECT_TRUE(result[0].input_variables[0].has_location_decoration); EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].input_variables[0].location_decoration); EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
EXPECT_EQ(inspector_type, result[0].input_variables[0].component_type); EXPECT_EQ(component, result[0].input_variables[0].component_type);
ASSERT_EQ(1u, result[0].output_variables.size()); ASSERT_EQ(1u, result[0].output_variables.size());
EXPECT_EQ("<retval>", result[0].output_variables[0].name); EXPECT_EQ("<retval>", result[0].output_variables[0].name);
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration); EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].output_variables[0].location_decoration); EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(inspector_type, result[0].output_variables[0].component_type); EXPECT_EQ(component, result[0].output_variables[0].component_type);
} }
INSTANTIATE_TEST_SUITE_P(InspectorGetEntryPointTest, INSTANTIATE_TEST_SUITE_P(
InspectorGetEntryPointTestWithComponentTypeParam, InspectorGetEntryPointTest,
testing::Values(ComponentType::kFloat, InspectorGetEntryPointComponentAndCompositionTest,
testing::Combine(testing::Values(ComponentType::kFloat,
ComponentType::kSInt, ComponentType::kSInt,
ComponentType::kUInt)); ComponentType::kUInt),
testing::Values(CompositionType::kScalar,
CompositionType::kVec2,
CompositionType::kVec3,
CompositionType::kVec4)));
TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) { TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) {
auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u)}); auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u)});
@ -1603,6 +1649,89 @@ TEST_F(InspectorGetEntryPointTest, SampleMaskStructReferenced) {
EXPECT_TRUE(result[0].sample_mask_used); EXPECT_TRUE(result[0].sample_mask_used);
} }
TEST_F(InspectorGetEntryPointTest, ImplicitInterpolate) {
ast::StructMemberList members;
members.push_back(Member("struct_inner", ty.f32(), {Location(0)}));
Structure("in_struct", members, {});
auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
Func("ep_func", {in_var}, ty.void_(), {Return()},
{Stage(ast::PipelineStage::kFragment)}, {});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
ASSERT_EQ(1u, result[0].input_variables.size());
EXPECT_EQ(InterpolationType::kPerspective,
result[0].input_variables[0].interpolation_type);
EXPECT_EQ(InterpolationSampling::kCenter,
result[0].input_variables[0].interpolation_sampling);
}
TEST_P(InspectorGetEntryPointInterpolateTest, Test) {
auto& params = GetParam();
ast::StructMemberList members;
members.push_back(
Member("struct_inner", ty.f32(),
{Interpolate(params.in_type, params.in_sampling), Location(0)}));
Structure("in_struct", members, {});
auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
Func("ep_func", {in_var}, ty.void_(), {Return()},
{Stage(ast::PipelineStage::kFragment)}, {});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_EQ(1u, result.size());
ASSERT_EQ(1u, result[0].input_variables.size());
EXPECT_EQ(params.out_type, result[0].input_variables[0].interpolation_type);
EXPECT_EQ(params.out_sampling,
result[0].input_variables[0].interpolation_sampling);
}
INSTANTIATE_TEST_SUITE_P(
InspectorGetEntryPointTest,
InspectorGetEntryPointInterpolateTest,
testing::Values(
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kPerspective,
ast::InterpolationSampling::kCenter,
InterpolationType::kPerspective, InterpolationSampling::kCenter},
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kPerspective,
ast::InterpolationSampling::kCentroid,
InterpolationType::kPerspective, InterpolationSampling::kCentroid},
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kPerspective,
ast::InterpolationSampling::kSample,
InterpolationType::kPerspective, InterpolationSampling::kSample},
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kPerspective,
ast::InterpolationSampling::kNone, InterpolationType::kPerspective,
InterpolationSampling::kCenter},
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kLinear,
ast::InterpolationSampling::kCenter, InterpolationType::kLinear,
InterpolationSampling::kCenter},
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kLinear,
ast::InterpolationSampling::kCentroid, InterpolationType::kLinear,
InterpolationSampling::kCentroid},
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kLinear,
ast::InterpolationSampling::kSample, InterpolationType::kLinear,
InterpolationSampling::kSample},
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kLinear, ast::InterpolationSampling::kNone,
InterpolationType::kLinear, InterpolationSampling::kCenter},
InspectorGetEntryPointInterpolateTestParams{
ast::InterpolationType::kFlat, ast::InterpolationSampling::kNone,
InterpolationType::kFlat, InterpolationSampling::kNone}));
// TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass // TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
// through // through
TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_NoFunctions) { TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_NoFunctions) {

View File

@ -86,14 +86,22 @@ bool Type::is_integer_scalar() const {
return IsAnyOf<U32, I32>(); return IsAnyOf<U32, I32>();
} }
bool Type::is_unsigned_integer_vector() const { bool Type::is_signed_integer_scalar() const {
return Is<Vector>([](const Vector* v) { return v->type()->Is<U32>(); }); return Is<I32>();
}
bool Type::is_unsigned_integer_scalar() const {
return Is<U32>();
} }
bool Type::is_signed_integer_vector() const { bool Type::is_signed_integer_vector() const {
return Is<Vector>([](const Vector* v) { return v->type()->Is<I32>(); }); return Is<Vector>([](const Vector* v) { return v->type()->Is<I32>(); });
} }
bool Type::is_unsigned_integer_vector() const {
return Is<Vector>([](const Vector* v) { return v->type()->Is<U32>(); });
}
bool Type::is_unsigned_scalar_or_vector() const { bool Type::is_unsigned_scalar_or_vector() const {
return Is<U32>() || is_unsigned_integer_vector(); return Is<U32>() || is_unsigned_integer_vector();
} }

View File

@ -69,6 +69,10 @@ class Type : public Castable<Type, Node> {
bool is_float_scalar_or_vector_or_matrix() const; bool is_float_scalar_or_vector_or_matrix() const;
/// @returns true if this type is an integer scalar /// @returns true if this type is an integer scalar
bool is_integer_scalar() const; bool is_integer_scalar() const;
/// @returns true if this type is a signed integer scalar
bool is_signed_integer_scalar() const;
/// @returns true if this type is an unsigned integer scalar
bool is_unsigned_integer_scalar() const;
/// @returns true if this type is a signed integer vector /// @returns true if this type is a signed integer vector
bool is_signed_integer_vector() const; bool is_signed_integer_vector() const;
/// @returns true if this type is an unsigned vector /// @returns true if this type is an unsigned vector