dawn-cmake/src/inspector/inspector_test.cc
Ben Clayton 6b2fc057c5 Resolver: Check that initializers and assignments are valid
This performs very basic type verification for assignments and variable initializers.

Pulls part of the validation logic out of the Validator into the Resolver.
Involves fixing up a bunch of broken tests.

Bug: tint:642
Fixed: tint:631
Change-Id: Ifbdc139ff7eeab810856e0ba9e3c380c6555ec20
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/45281
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
2021-03-18 21:14:44 +00:00

2837 lines
108 KiB
C++

// 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 "gtest/gtest.h"
#include "src/ast/call_statement.h"
#include "src/ast/constant_id_decoration.h"
#include "src/ast/stage_decoration.h"
#include "src/ast/struct_block_decoration.h"
#include "src/ast/workgroup_decoration.h"
#include "src/type/depth_texture_type.h"
#include "src/type/multisampled_texture_type.h"
#include "src/type/sampled_texture_type.h"
#include "tint/tint.h"
namespace tint {
namespace inspector {
namespace {
class InspectorHelper : public ProgramBuilder {
public:
InspectorHelper()
: sampler_type_(type::SamplerKind::kSampler),
comparison_sampler_type_(type::SamplerKind::kComparisonSampler) {}
/// Generates an empty function
/// @param name name of the function created
/// @param decorations the function decorations
void MakeEmptyBodyFunction(std::string name,
ast::DecorationList decorations) {
Func(name, ast::VariableList(), ty.void_(),
ast::StatementList{create<ast::ReturnStatement>()}, decorations);
}
/// Generates a function that calls other functions
/// @param caller name of the function created
/// @param callees names of the functions to be called
/// @param decorations the function decorations
void MakeCallerBodyFunction(std::string caller,
std::vector<std::string> callees,
ast::DecorationList decorations) {
ast::StatementList body;
body.reserve(callees.size() + 1);
for (auto callee : callees) {
body.push_back(create<ast::CallStatement>(Call(callee)));
}
body.push_back(create<ast::ReturnStatement>());
Func(caller, ast::VariableList(), ty.void_(), body, decorations);
}
/// 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) {
uint32_t location = 0;
for (auto inout : inout_vars) {
std::string in, out;
std::tie(in, out) = inout;
Global(in, ty.u32(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{create<ast::LocationDecoration>(location++)});
Global(out, ty.u32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{create<ast::LocationDecoration>(location++)});
}
}
/// 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 decorations the function decorations
void MakeInOutVariableBodyFunction(
std::string name,
std::vector<std::tuple<std::string, std::string>> inout_vars,
ast::DecorationList decorations) {
ast::StatementList stmts;
for (auto inout : inout_vars) {
std::string in, out;
std::tie(in, out) = inout;
stmts.emplace_back(create<ast::AssignmentStatement>(Expr(out), Expr(in)));
}
stmts.emplace_back(create<ast::ReturnStatement>());
Func(name, ast::VariableList(), ty.void_(), stmts, decorations);
}
/// 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 decorations the function decorations
/// @returns a function object
ast::Function* MakeInOutVariableCallerBodyFunction(
std::string caller,
std::string callee,
std::vector<std::tuple<std::string, std::string>> inout_vars,
ast::DecorationList decorations) {
ast::StatementList stmts;
for (auto inout : inout_vars) {
std::string in, out;
std::tie(in, out) = inout;
stmts.emplace_back(create<ast::AssignmentStatement>(Expr(out), Expr(in)));
}
stmts.emplace_back(create<ast::CallStatement>(Call(callee)));
stmts.emplace_back(create<ast::ReturnStatement>());
return Func(caller, ast::VariableList(), ty.void_(), stmts, decorations);
}
/// Add a Constant ID to the global variables.
/// @param name name of the variable to add
/// @param id id number for the constant id
/// @param type type of the variable
/// @param val value to initialize the variable with, if NULL no initializer
/// will be added.
template <class T>
void AddConstantID(std::string name, uint32_t id, type::Type* type, T* val) {
ast::Expression* constructor = nullptr;
if (val) {
constructor =
create<ast::ScalarConstructorExpression>(MakeLiteral(type, val));
}
GlobalConst(name, type, constructor,
ast::DecorationList{
create<ast::ConstantIdDecoration>(id),
});
}
/// @param type AST type of the literal, must resolve to BoolLiteral
/// @param val scalar value for the literal to contain
/// @returns a Literal of the expected type and value
ast::Literal* MakeLiteral(type::Type* type, bool* val) {
return create<ast::BoolLiteral>(type, *val);
}
/// @param type AST type of the literal, must resolve to UIntLiteral
/// @param val scalar value for the literal to contain
/// @returns a Literal of the expected type and value
ast::Literal* MakeLiteral(type::Type* type, uint32_t* val) {
return create<ast::UintLiteral>(type, *val);
}
/// @param type AST type of the literal, must resolve to IntLiteral
/// @param val scalar value for the literal to contain
/// @returns a Literal of the expected type and value
ast::Literal* MakeLiteral(type::Type* type, int32_t* val) {
return create<ast::SintLiteral>(type, *val);
}
/// @param type AST type of the literal, must resolve to FloattLiteral
/// @param val scalar value for the literal to contain
/// @returns a Literal of the expected type and value
ast::Literal* MakeLiteral(type::Type* type, float* val) {
return create<ast::FloatLiteral>(type, *val);
}
/// @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) {
for (auto& s : vec) {
if (s.name == name) {
return true;
}
}
return false;
}
/// 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, type::Type* type) {
return std::to_string(idx) + type->type_name();
}
/// 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
type::Struct* MakeStructType(const std::string& name,
std::vector<type::Type*> member_types,
bool is_block) {
ast::StructMemberList members;
for (auto* type : member_types) {
members.push_back(Member(StructMemberName(members.size(), type), type));
}
ast::DecorationList decos;
if (is_block) {
decos.push_back(create<ast::StructBlockDecoration>());
}
auto* str = create<ast::Struct>(members, decos);
auto* str_ty = ty.struct_(name, str);
AST().AddConstructedType(str_ty);
return str_ty;
}
/// 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.
type::Struct* MakeUniformBufferType(const std::string& name,
std::vector<type::Type*> member_types) {
auto* struct_type = MakeStructType(name, member_types, true);
return struct_type;
}
/// Returns true if the struct with `member_types` requires a block decoration
/// @param member_types a vector of member types
/// @returns true if block decoration is required
bool StructRequiresBlockDecoration(
std::vector<type::Type*> member_types) const {
// Structure needs a [[block]] attribute if the last member is a
// dynamically-sized array.
return member_types.back()->Is<type::Array>(
[](auto&& a) { return a->IsRuntimeArray(); });
}
/// 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 tuple {struct type, access control type}, where the struct has
/// the layout for a storage buffer, and the control type wraps the
/// struct.
std::tuple<type::Struct*, type::AccessControl*> MakeStorageBufferTypes(
const std::string& name,
std::vector<type::Type*> member_types) {
bool is_block = StructRequiresBlockDecoration(member_types);
auto* struct_type = MakeStructType(name, member_types, is_block);
auto* access_type = create<type::AccessControl>(
ast::AccessControl::kReadWrite, struct_type);
return {struct_type, std::move(access_type)};
}
/// Generates types appropriate for using in a read-only storage buffer
/// @param name name for the type
/// @param member_types a vector of member types
/// @returns a tuple {struct type, access control type}, where the struct has
/// the layout for a read-only storage buffer, and the control type
/// wraps the struct.
std::tuple<type::Struct*, type::AccessControl*>
MakeReadOnlyStorageBufferTypes(const std::string& name,
std::vector<type::Type*> member_types) {
bool is_block = StructRequiresBlockDecoration(member_types);
auto* struct_type = MakeStructType(name, member_types, is_block);
auto* access_type =
create<type::AccessControl>(ast::AccessControl::kReadOnly, struct_type);
return {struct_type, std::move(access_type)};
}
/// Adds a binding variable with a struct type to the program
/// @param name the name of the variable
/// @param type the type to use
/// @param storage_class the storage class to use
/// @param group the binding and group to use for the uniform buffer
/// @param binding the binding number to use for the uniform buffer
void AddBinding(const std::string& name,
type::Type* type,
ast::StorageClass storage_class,
uint32_t group,
uint32_t binding) {
Global(name, type, storage_class, nullptr,
ast::DecorationList{
create<ast::BindingDecoration>(binding),
create<ast::GroupDecoration>(group),
});
}
/// 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,
type::Type* type,
uint32_t group,
uint32_t binding) {
AddBinding(name, type, ast::StorageClass::kUniform, group, binding);
}
/// Adds a storage 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 storage buffer
/// @param binding the binding number to use for the storage buffer
void AddStorageBuffer(const std::string& name,
type::Type* type,
uint32_t group,
uint32_t binding) {
AddBinding(name, type, ast::StorageClass::kStorage, group, 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, type::Type*>> members) {
ast::StatementList stmts;
for (auto member : members) {
size_t member_idx;
type::Type* member_type;
std::tie(member_idx, member_type) = member;
std::string member_name = StructMemberName(member_idx, member_type);
stmts.emplace_back(create<ast::VariableDeclStatement>(
Var("local" + member_name, member_type, ast::StorageClass::kNone)));
}
for (auto member : members) {
size_t member_idx;
type::Type* member_type;
std::tie(member_idx, member_type) = member;
std::string member_name = StructMemberName(member_idx, member_type);
stmts.emplace_back(create<ast::AssignmentStatement>(
Expr("local" + member_name),
MemberAccessor(struct_name, member_name)));
}
stmts.emplace_back(create<ast::ReturnStatement>());
Func(func_name, ast::VariableList(), ty.void_(), stmts,
ast::DecorationList{});
}
/// 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) {
AddBinding(name, sampler_type(), ast::StorageClass::kUniformConstant, group,
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) {
AddBinding(name, comparison_sampler_type(),
ast::StorageClass::kUniformConstant, group, binding);
}
/// Generates a SampledTexture appropriate for the params
/// @param dim the dimensions of the texture
/// @param type the data type of the sampled texture
/// @returns the generated SampleTextureType
type::SampledTexture* MakeSampledTextureType(type::TextureDimension dim,
type::Type* type) {
return create<type::SampledTexture>(dim, type);
}
/// Generates a DepthTexture appropriate for the params
/// @param dim the dimensions of the texture
/// @returns the generated DepthTexture
type::DepthTexture* MakeDepthTextureType(type::TextureDimension dim) {
return create<type::DepthTexture>(dim);
}
/// Generates a MultisampledTexture appropriate for the params
/// @param dim the dimensions of the texture
/// @param type the data type of the sampled texture
/// @returns the generated SampleTextureType
type::MultisampledTexture* MakeMultisampledTextureType(
type::TextureDimension dim,
type::Type* type) {
return create<type::MultisampledTexture>(dim, type);
}
/// Adds a sampled 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 binding number to use for the sampled texture
void AddSampledTexture(const std::string& name,
type::Type* type,
uint32_t group,
uint32_t binding) {
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
}
/// Adds a multi-sampled 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 multi-sampled texture
/// @param binding the binding number to use for the multi-sampled texture
void AddMultisampledTexture(const std::string& name,
type::Type* type,
uint32_t group,
uint32_t binding) {
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
}
void AddGlobalVariable(const std::string& name, type::Type* type) {
Global(name, type, ast::StorageClass::kUniformConstant);
}
/// Adds a depth 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 depth texture
/// @param binding the binding number to use for the depth texture
void AddDepthTexture(const std::string& name,
type::Type* type,
uint32_t group,
uint32_t binding) {
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
}
/// 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 decorations the function decorations
/// @returns a function that references all of the values specified
ast::Function* MakeSamplerReferenceBodyFunction(
const std::string& func_name,
const std::string& texture_name,
const std::string& sampler_name,
const std::string& coords_name,
type::Type* base_type,
ast::DecorationList decorations) {
std::string result_name = "sampler_result";
ast::StatementList stmts;
stmts.emplace_back(create<ast::VariableDeclStatement>(
Var("sampler_result", vec_type(base_type, 4),
ast::StorageClass::kFunction)));
stmts.emplace_back(create<ast::AssignmentStatement>(
Expr("sampler_result"),
Call("textureSample", texture_name, sampler_name, coords_name)));
stmts.emplace_back(create<ast::ReturnStatement>());
return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
}
/// 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 decorations the function decorations
/// @returns a function that references all of the values specified
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,
type::Type* base_type,
ast::DecorationList decorations) {
std::string result_name = "sampler_result";
ast::StatementList stmts;
stmts.emplace_back(create<ast::VariableDeclStatement>(
Var("sampler_result", vec_type(base_type, 4),
ast::StorageClass::kFunction)));
stmts.emplace_back(create<ast::AssignmentStatement>(
Expr("sampler_result"), Call("textureSample", texture_name,
sampler_name, coords_name, array_index)));
stmts.emplace_back(create<ast::ReturnStatement>());
return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
}
/// 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 decorations the function decorations
/// @returns a function that references all of the values specified
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,
type::Type* base_type,
ast::DecorationList decorations) {
std::string result_name = "sampler_result";
ast::StatementList stmts;
stmts.emplace_back(create<ast::VariableDeclStatement>(
Var("sampler_result", base_type, ast::StorageClass::kFunction)));
stmts.emplace_back(create<ast::AssignmentStatement>(
Expr("sampler_result"), Call("textureSampleCompare", texture_name,
sampler_name, coords_name, depth_name)));
stmts.emplace_back(create<ast::ReturnStatement>());
return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
}
/// 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
type::Type* 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;
}
}
/// 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
type::Type* GetCoordsType(type::TextureDimension dim, type::Type* scalar) {
switch (dim) {
case type::TextureDimension::k1d:
return scalar;
case type::TextureDimension::k2d:
case type::TextureDimension::k2dArray:
return create<type::Vector>(scalar, 2);
case type::TextureDimension::k3d:
case type::TextureDimension::kCube:
case type::TextureDimension::kCubeArray:
return create<type::Vector>(scalar, 3);
default:
[=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
}
return nullptr;
}
/// Generates appropriate types for a StorageTexture
/// @param dim the texture dimension of the storage texture
/// @param format the image format of the storage texture
/// @returns the storage texture type and subtype
std::tuple<type::StorageTexture*, type::Type*> MakeStorageTextureTypes(
type::TextureDimension dim,
type::ImageFormat format) {
type::Type* subtype = type::StorageTexture::SubtypeFor(format, Types());
return {create<type::StorageTexture>(dim, format, subtype), subtype};
}
/// Generates appropriate types for a Read-Only StorageTexture
/// @param dim the texture dimension of the storage texture
/// @param format the image format of the storage texture
/// @param read_only should the access type be read only, otherwise write only
/// @returns the storage texture type, subtype & access control type
std::tuple<type::StorageTexture*, type::Type*, type::AccessControl*>
MakeStorageTextureTypes(type::TextureDimension dim,
type::ImageFormat format,
bool read_only) {
type::StorageTexture* texture_type;
type::Type* subtype;
std::tie(texture_type, subtype) = MakeStorageTextureTypes(dim, format);
auto* access_control =
create<type::AccessControl>(read_only ? ast::AccessControl::kReadOnly
: ast::AccessControl::kWriteOnly,
texture_type);
return {texture_type, subtype, access_control};
}
/// 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 binding number to use for the sampled texture
void AddStorageTexture(const std::string& name,
type::Type* type,
uint32_t group,
uint32_t binding) {
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, 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 decorations the function decorations
/// @returns a function that references all of the values specified
ast::Function* MakeStorageTextureBodyFunction(
const std::string& func_name,
const std::string& st_name,
type::Type* dim_type,
ast::DecorationList decorations) {
ast::StatementList stmts;
stmts.emplace_back(create<ast::VariableDeclStatement>(
Var("dim", dim_type, ast::StorageClass::kFunction)));
stmts.emplace_back(create<ast::AssignmentStatement>(
Expr("dim"), Call("textureDimensions", st_name)));
stmts.emplace_back(create<ast::ReturnStatement>());
return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
}
Inspector& 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_;
}
type::Array* u32_array_type(uint32_t count) {
if (array_type_memo_.find(count) == array_type_memo_.end()) {
array_type_memo_[count] =
create<type::Array>(ty.u32(), count,
ast::DecorationList{
create<ast::StrideDecoration>(4),
});
}
return array_type_memo_[count];
}
type::Vector* vec_type(type::Type* type, uint32_t count) {
if (vector_type_memo_.find(std::tie(type, count)) ==
vector_type_memo_.end()) {
vector_type_memo_[std::tie(type, count)] =
create<type::Vector>(type, count);
}
return vector_type_memo_[std::tie(type, count)];
}
type::Sampler* sampler_type() { return &sampler_type_; }
type::Sampler* comparison_sampler_type() { return &comparison_sampler_type_; }
private:
std::unique_ptr<Program> program_;
std::unique_ptr<Inspector> inspector_;
type::Sampler sampler_type_;
type::Sampler comparison_sampler_type_;
std::map<uint32_t, type::Array*> array_type_memo_;
std::map<std::tuple<type::Type*, uint32_t>, type::Vector*> vector_type_memo_;
};
class InspectorGetEntryPointTest : public InspectorHelper,
public testing::Test {};
class InspectorGetRemappedNameForEntryPointTest : public InspectorHelper,
public testing::Test {};
class InspectorGetConstantIDsTest : public InspectorHelper,
public testing::Test {};
class InspectorGetResourceBindingsTest : public InspectorHelper,
public testing::Test {};
class InspectorGetUniformBufferResourceBindingsTest : public InspectorHelper,
public testing::Test {};
class InspectorGetStorageBufferResourceBindingsTest : public InspectorHelper,
public testing::Test {};
class InspectorGetReadOnlyStorageBufferResourceBindingsTest
: public InspectorHelper,
public testing::Test {};
class InspectorGetSamplerResourceBindingsTest : public InspectorHelper,
public testing::Test {};
class InspectorGetComparisonSamplerResourceBindingsTest
: public InspectorHelper,
public testing::Test {};
class InspectorGetSampledTextureResourceBindingsTest : public InspectorHelper,
public testing::Test {};
class InspectorGetSampledArrayTextureResourceBindingsTest
: public InspectorHelper,
public testing::Test {};
struct GetSampledTextureTestParams {
type::TextureDimension type_dim;
inspector::ResourceBinding::TextureDimension inspector_dim;
inspector::ResourceBinding::SampledKind sampled_kind;
};
class InspectorGetSampledTextureResourceBindingsTestWithParam
: public InspectorHelper,
public testing::TestWithParam<GetSampledTextureTestParams> {};
class InspectorGetSampledArrayTextureResourceBindingsTestWithParam
: public InspectorHelper,
public testing::TestWithParam<GetSampledTextureTestParams> {};
class InspectorGetMultisampledTextureResourceBindingsTest
: public InspectorHelper,
public testing::Test {};
class InspectorGetMultisampledArrayTextureResourceBindingsTest
: public InspectorHelper,
public testing::Test {};
typedef GetSampledTextureTestParams GetMultisampledTextureTestParams;
class InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam
: public InspectorHelper,
public testing::TestWithParam<GetMultisampledTextureTestParams> {};
class InspectorGetMultisampledTextureResourceBindingsTestWithParam
: public InspectorHelper,
public testing::TestWithParam<GetMultisampledTextureTestParams> {};
class InspectorGetStorageTextureResourceBindingsTest : public InspectorHelper,
public testing::Test {};
struct GetDepthTextureTestParams {
type::TextureDimension type_dim;
inspector::ResourceBinding::TextureDimension inspector_dim;
};
class InspectorGetDepthTextureResourceBindingsTestWithParam
: public InspectorHelper,
public testing::TestWithParam<GetDepthTextureTestParams> {};
typedef std::tuple<type::TextureDimension, ResourceBinding::TextureDimension>
DimensionParams;
typedef std::tuple<type::ImageFormat,
ResourceBinding::ImageFormat,
ResourceBinding::SampledKind>
ImageFormatParams;
typedef std::tuple<bool, DimensionParams, ImageFormatParams>
GetStorageTextureTestParams;
class InspectorGetStorageTextureResourceBindingsTestWithParam
: public InspectorHelper,
public testing::TestWithParam<GetStorageTextureTestParams> {};
TEST_F(InspectorGetEntryPointTest, NoFunctions) {
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(0u, result.size());
}
TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(0u, result.size());
}
TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
MakeEmptyBodyFunction(
"foo", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
// TODO(dsinclair): Update to run the namer transform when available.
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ("foo", result[0].name);
EXPECT_EQ("foo", result[0].remapped_name);
EXPECT_EQ(ast::PipelineStage::kVertex, result[0].stage);
}
TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
MakeEmptyBodyFunction(
"foo", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
MakeEmptyBodyFunction(
"bar", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
});
// TODO(dsinclair): Update to run the namer transform when available.
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(2u, result.size());
EXPECT_EQ("foo", result[0].name);
EXPECT_EQ("foo", result[0].remapped_name);
EXPECT_EQ(ast::PipelineStage::kVertex, result[0].stage);
EXPECT_EQ("bar", result[1].name);
EXPECT_EQ("bar", result[1].remapped_name);
EXPECT_EQ(ast::PipelineStage::kCompute, result[1].stage);
}
TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
MakeEmptyBodyFunction("func", {});
MakeCallerBodyFunction(
"foo", {"func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
MakeCallerBodyFunction(
"bar", {"func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
});
// TODO(dsinclair): Update to run the namer transform when available.
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
EXPECT_FALSE(inspector.has_error());
ASSERT_EQ(2u, result.size());
EXPECT_EQ("foo", result[0].name);
EXPECT_EQ("foo", result[0].remapped_name);
EXPECT_EQ(ast::PipelineStage::kVertex, result[0].stage);
EXPECT_EQ("bar", result[1].name);
EXPECT_EQ("bar", result[1].remapped_name);
EXPECT_EQ(ast::PipelineStage::kFragment, result[1].stage);
}
TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
MakeEmptyBodyFunction(
"foo", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
uint32_t x, y, z;
std::tie(x, y, z) = result[0].workgroup_size();
EXPECT_EQ(1u, x);
EXPECT_EQ(1u, y);
EXPECT_EQ(1u, z);
}
TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
MakeEmptyBodyFunction(
"foo", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
create<ast::WorkgroupDecoration>(8u, 2u, 1u),
});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
uint32_t x, y, z;
std::tie(x, y, z) = result[0].workgroup_size();
EXPECT_EQ(8u, x);
EXPECT_EQ(2u, y);
EXPECT_EQ(1u, z);
}
TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
MakeEmptyBodyFunction("func", {});
MakeCallerBodyFunction(
"foo", {"func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(0u, result[0].input_variables.size());
EXPECT_EQ(0u, result[0].output_variables.size());
}
TEST_F(InspectorGetEntryPointTest, EntryPointInOutVariables) {
AddInOutVariables({{"in_var", "out_var"}});
MakeInOutVariableBodyFunction(
"foo", {{"in_var", "out_var"}},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
ASSERT_EQ(1u, result[0].input_variables.size());
EXPECT_EQ("in_var", result[0].input_variables[0].name);
EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
ASSERT_EQ(1u, result[0].output_variables.size());
EXPECT_EQ("out_var", result[0].output_variables[0].name);
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(1u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
}
TEST_F(InspectorGetEntryPointTest, FunctionInOutVariables) {
AddInOutVariables({{"in_var", "out_var"}});
MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
MakeCallerBodyFunction(
"foo", {"func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
ASSERT_EQ(1u, result[0].input_variables.size());
EXPECT_EQ("in_var", result[0].input_variables[0].name);
EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
ASSERT_EQ(1u, result[0].output_variables.size());
EXPECT_EQ("out_var", result[0].output_variables[0].name);
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(1u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
}
TEST_F(InspectorGetEntryPointTest, RepeatedInOutVariables) {
AddInOutVariables({{"in_var", "out_var"}});
MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
MakeInOutVariableCallerBodyFunction(
"foo", "func", {{"in_var", "out_var"}},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
ASSERT_EQ(1u, result[0].input_variables.size());
EXPECT_EQ("in_var", result[0].input_variables[0].name);
EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
ASSERT_EQ(1u, result[0].output_variables.size());
EXPECT_EQ("out_var", result[0].output_variables[0].name);
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(1u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
}
TEST_F(InspectorGetEntryPointTest, EntryPointMultipleInOutVariables) {
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
MakeInOutVariableBodyFunction(
"foo", {{"in_var", "out_var"}, {"in2_var", "out2_var"}},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
ASSERT_EQ(2u, result[0].input_variables.size());
EXPECT_TRUE(ContainsName(result[0].input_variables, "in_var"));
EXPECT_TRUE(ContainsName(result[0].input_variables, "in2_var"));
EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
EXPECT_EQ(2u, result[0].input_variables[1].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
ASSERT_EQ(2u, result[0].output_variables.size());
EXPECT_TRUE(ContainsName(result[0].output_variables, "out_var"));
EXPECT_TRUE(ContainsName(result[0].output_variables, "out2_var"));
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(1u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
EXPECT_TRUE(result[0].output_variables[1].has_location_decoration);
EXPECT_EQ(3u, result[0].output_variables[1].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
}
TEST_F(InspectorGetEntryPointTest, FunctionMultipleInOutVariables) {
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
MakeInOutVariableBodyFunction(
"func", {{"in_var", "out_var"}, {"in2_var", "out2_var"}}, {});
MakeCallerBodyFunction(
"foo", {"func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
ASSERT_EQ(2u, result[0].input_variables.size());
EXPECT_TRUE(ContainsName(result[0].input_variables, "in_var"));
EXPECT_TRUE(ContainsName(result[0].input_variables, "in2_var"));
EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
EXPECT_EQ(2u, result[0].input_variables[1].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
ASSERT_EQ(2u, result[0].output_variables.size());
EXPECT_TRUE(ContainsName(result[0].output_variables, "out_var"));
EXPECT_TRUE(ContainsName(result[0].output_variables, "out2_var"));
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(1u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
EXPECT_TRUE(result[0].output_variables[1].has_location_decoration);
EXPECT_EQ(3u, result[0].output_variables[1].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
}
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
MakeInOutVariableBodyFunction(
"foo", {{"in_var", "out2_var"}},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
MakeInOutVariableBodyFunction(
"bar", {{"in2_var", "out_var"}},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
});
// TODO(dsinclair): Update to run the namer transform when
// available.
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(2u, result.size());
ASSERT_EQ("foo", result[0].name);
ASSERT_EQ("foo", result[0].remapped_name);
ASSERT_EQ(1u, result[0].input_variables.size());
EXPECT_EQ("in_var", result[0].input_variables[0].name);
EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
ASSERT_EQ(1u, result[0].output_variables.size());
EXPECT_EQ("out2_var", result[0].output_variables[0].name);
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(3u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
ASSERT_EQ("bar", result[1].name);
ASSERT_EQ("bar", result[1].remapped_name);
ASSERT_EQ(1u, result[1].input_variables.size());
EXPECT_EQ("in2_var", result[1].input_variables[0].name);
EXPECT_TRUE(result[1].input_variables[0].has_location_decoration);
EXPECT_EQ(2u, result[1].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
ASSERT_EQ(1u, result[1].output_variables.size());
EXPECT_EQ("out_var", result[1].output_variables[0].name);
EXPECT_TRUE(result[1].output_variables[0].has_location_decoration);
EXPECT_EQ(1u, result[1].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[1].output_variables[0].component_type);
}
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsSharedInOutVariables) {
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
MakeInOutVariableBodyFunction("func", {{"in2_var", "out2_var"}}, {});
MakeInOutVariableCallerBodyFunction(
"foo", "func", {{"in_var", "out_var"}},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
MakeCallerBodyFunction(
"bar", {"func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
});
// TODO(dsinclair): Update to run the namer transform when
// available.
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(2u, result.size());
ASSERT_EQ("foo", result[0].name);
ASSERT_EQ("foo", result[0].remapped_name);
ASSERT_EQ(2u, result[0].input_variables.size());
EXPECT_TRUE(ContainsName(result[0].input_variables, "in_var"));
EXPECT_TRUE(ContainsName(result[0].input_variables, "in2_var"));
EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
EXPECT_EQ(2u, result[0].input_variables[1].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
ASSERT_EQ(2u, result[0].output_variables.size());
EXPECT_TRUE(ContainsName(result[0].output_variables, "out_var"));
EXPECT_TRUE(ContainsName(result[0].output_variables, "out2_var"));
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(1u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(3u, result[0].output_variables[1].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
ASSERT_EQ("bar", result[1].name);
ASSERT_EQ("bar", result[1].remapped_name);
ASSERT_EQ(1u, result[1].input_variables.size());
EXPECT_EQ("in2_var", result[1].input_variables[0].name);
EXPECT_TRUE(result[1].input_variables[0].has_location_decoration);
EXPECT_EQ(2u, result[1].input_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
ASSERT_EQ(1u, result[1].output_variables.size());
EXPECT_EQ("out2_var", result[1].output_variables[0].name);
EXPECT_TRUE(result[1].output_variables[0].has_location_decoration);
EXPECT_EQ(3u, result[1].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[1].output_variables[0].component_type);
}
TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables) {
Global("in_var", ty.u32(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{
create<ast::BuiltinDecoration>(ast::Builtin::kPosition)});
Global("out_var", ty.u32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{create<ast::LocationDecoration>(0)});
MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
MakeCallerBodyFunction(
"foo", {"func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
// TODO(dsinclair): Update to run the namer transform when available.
Inspector& inspector = Build();
auto result = inspector.GetEntryPoints();
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
ASSERT_EQ("foo", result[0].name);
ASSERT_EQ("foo", result[0].remapped_name);
EXPECT_EQ(0u, result[0].input_variables.size());
EXPECT_EQ(1u, result[0].output_variables.size());
EXPECT_TRUE(ContainsName(result[0].output_variables, "out_var"));
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
}
// TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
// through
TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_NoFunctions) {
Inspector& inspector = Build();
auto result = inspector.GetRemappedNameForEntryPoint("foo");
ASSERT_TRUE(inspector.has_error());
EXPECT_EQ("", result);
}
// TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
// through
TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_NoEntryPoints) {
Inspector& inspector = Build();
auto result = inspector.GetRemappedNameForEntryPoint("foo");
ASSERT_TRUE(inspector.has_error());
EXPECT_EQ("", result);
}
// TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
// through
TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_OneEntryPoint) {
MakeEmptyBodyFunction(
"foo", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
// TODO(dsinclair): Update to run the namer transform when
// available.
Inspector& inspector = Build();
auto result = inspector.GetRemappedNameForEntryPoint("foo");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ("foo", result);
}
// TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
// through
TEST_F(InspectorGetRemappedNameForEntryPointTest,
DISABLED_MultipleEntryPoints) {
MakeEmptyBodyFunction(
"foo", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
// TODO(dsinclair): Update to run the namer transform when
// available.
MakeEmptyBodyFunction(
"bar", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
});
Inspector& inspector = Build();
{
auto result = inspector.GetRemappedNameForEntryPoint("foo");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ("foo", result);
}
{
auto result = inspector.GetRemappedNameForEntryPoint("bar");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ("bar", result);
}
}
TEST_F(InspectorGetConstantIDsTest, Bool) {
bool val_true = true;
bool val_false = false;
AddConstantID<bool>("foo", 1, ty.bool_(), nullptr);
AddConstantID<bool>("bar", 20, ty.bool_(), &val_true);
AddConstantID<bool>("baz", 300, ty.bool_(), &val_false);
Inspector& inspector = Build();
auto result = inspector.GetConstantIDs();
ASSERT_EQ(3u, result.size());
ASSERT_TRUE(result.find(1) != result.end());
EXPECT_TRUE(result[1].IsNull());
ASSERT_TRUE(result.find(20) != result.end());
EXPECT_TRUE(result[20].IsBool());
EXPECT_TRUE(result[20].AsBool());
ASSERT_TRUE(result.find(300) != result.end());
EXPECT_TRUE(result[300].IsBool());
EXPECT_FALSE(result[300].AsBool());
}
TEST_F(InspectorGetConstantIDsTest, U32) {
uint32_t val = 42;
AddConstantID<uint32_t>("foo", 1, ty.u32(), nullptr);
AddConstantID<uint32_t>("bar", 20, ty.u32(), &val);
Inspector& inspector = Build();
auto result = inspector.GetConstantIDs();
ASSERT_EQ(2u, result.size());
ASSERT_TRUE(result.find(1) != result.end());
EXPECT_TRUE(result[1].IsNull());
ASSERT_TRUE(result.find(20) != result.end());
EXPECT_TRUE(result[20].IsU32());
EXPECT_EQ(42u, result[20].AsU32());
}
TEST_F(InspectorGetConstantIDsTest, I32) {
int32_t val_neg = -42;
int32_t val_pos = 42;
AddConstantID<int32_t>("foo", 1, ty.i32(), nullptr);
AddConstantID<int32_t>("bar", 20, ty.i32(), &val_neg);
AddConstantID<int32_t>("baz", 300, ty.i32(), &val_pos);
Inspector& inspector = Build();
auto result = inspector.GetConstantIDs();
ASSERT_EQ(3u, result.size());
ASSERT_TRUE(result.find(1) != result.end());
EXPECT_TRUE(result[1].IsNull());
ASSERT_TRUE(result.find(20) != result.end());
EXPECT_TRUE(result[20].IsI32());
EXPECT_EQ(-42, result[20].AsI32());
ASSERT_TRUE(result.find(300) != result.end());
EXPECT_TRUE(result[300].IsI32());
EXPECT_EQ(42, result[300].AsI32());
}
TEST_F(InspectorGetConstantIDsTest, Float) {
float val_zero = 0.0f;
float val_neg = -10.0f;
float val_pos = 15.0f;
AddConstantID<float>("foo", 1, ty.f32(), nullptr);
AddConstantID<float>("bar", 20, ty.f32(), &val_zero);
AddConstantID<float>("baz", 300, ty.f32(), &val_neg);
AddConstantID<float>("x", 4000, ty.f32(), &val_pos);
Inspector& inspector = Build();
auto result = inspector.GetConstantIDs();
ASSERT_EQ(4u, result.size());
ASSERT_TRUE(result.find(1) != result.end());
EXPECT_TRUE(result[1].IsNull());
ASSERT_TRUE(result.find(20) != result.end());
EXPECT_TRUE(result[20].IsFloat());
EXPECT_FLOAT_EQ(0.0, result[20].AsFloat());
ASSERT_TRUE(result.find(300) != result.end());
EXPECT_TRUE(result[300].IsFloat());
EXPECT_FLOAT_EQ(-10.0, result[300].AsFloat());
ASSERT_TRUE(result.find(4000) != result.end());
EXPECT_TRUE(result[4000].IsFloat());
EXPECT_FLOAT_EQ(15.0, result[4000].AsFloat());
}
TEST_F(InspectorGetResourceBindingsTest, Empty) {
MakeCallerBodyFunction(
"ep_func", {},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(0u, result.size());
}
TEST_F(InspectorGetResourceBindingsTest, Simple) {
type::Struct* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32()});
AddUniformBuffer("ub_var", ub_struct_type, 0, 0);
MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
type::Struct* sb_struct_type;
type::AccessControl* sb_control_type;
std::tie(sb_struct_type, sb_control_type) =
MakeStorageBufferTypes("sb_type", {ty.i32()});
AddStorageBuffer("sb_var", sb_control_type, 1, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
type::Struct* rosb_struct_type;
type::AccessControl* rosb_control_type;
std::tie(rosb_struct_type, rosb_control_type) =
MakeReadOnlyStorageBufferTypes("rosb_type", {ty.i32()});
AddStorageBuffer("rosb_var", rosb_control_type, 1, 1);
MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
{{0, ty.i32()}});
auto* s_texture_type =
MakeSampledTextureType(type::TextureDimension::k1d, ty.f32());
AddSampledTexture("s_texture", s_texture_type, 2, 0);
AddSampler("s_var", 3, 0);
AddGlobalVariable("s_coords", ty.f32());
MakeSamplerReferenceBodyFunction("s_func", "s_texture", "s_var", "s_coords",
ty.f32(), {});
auto* cs_depth_texture_type =
MakeDepthTextureType(type::TextureDimension::k2d);
AddDepthTexture("cs_texture", cs_depth_texture_type, 3, 1);
AddComparisonSampler("cs_var", 3, 2);
AddGlobalVariable("cs_coords", ty.vec2<f32>());
AddGlobalVariable("cs_depth", ty.f32());
MakeComparisonSamplerReferenceBodyFunction(
"cs_func", "cs_texture", "cs_var", "cs_coords", "cs_depth", ty.f32(), {});
type::StorageTexture* st_type;
type::Type* st_subtype;
type::AccessControl* st_ac;
std::tie(st_type, st_subtype, st_ac) = MakeStorageTextureTypes(
type::TextureDimension::k2d, type::ImageFormat::kR8Uint, false);
AddStorageTexture("st_var", st_ac, 4, 0);
MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<i32>(), {});
type::StorageTexture* rost_type;
type::Type* rost_subtype;
type::AccessControl* rost_ac;
std::tie(rost_type, rost_subtype, rost_ac) = MakeStorageTextureTypes(
type::TextureDimension::k2d, type::ImageFormat::kR8Uint, true);
AddStorageTexture("rost_var", rost_ac, 4, 1);
MakeStorageTextureBodyFunction("rost_func", "rost_var", ty.vec2<i32>(), {});
MakeCallerBodyFunction(
"ep_func",
{"ub_func", "sb_func", "rosb_func", "s_func", "cs_func", "st_func",
"rost_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(9u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[1].resource_type);
EXPECT_EQ(1u, result[1].bind_group);
EXPECT_EQ(0u, result[1].binding);
EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
result[2].resource_type);
EXPECT_EQ(1u, result[2].bind_group);
EXPECT_EQ(1u, result[2].binding);
EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[3].resource_type);
EXPECT_EQ(3u, result[3].bind_group);
EXPECT_EQ(0u, result[3].binding);
EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
result[4].resource_type);
EXPECT_EQ(3u, result[4].bind_group);
EXPECT_EQ(2u, result[4].binding);
EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
result[5].resource_type);
EXPECT_EQ(2u, result[5].bind_group);
EXPECT_EQ(0u, result[5].binding);
EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageTexture,
result[6].resource_type);
EXPECT_EQ(4u, result[6].bind_group);
EXPECT_EQ(1u, result[6].binding);
EXPECT_EQ(ResourceBinding::ResourceType::kWriteOnlyStorageTexture,
result[7].resource_type);
EXPECT_EQ(4u, result[7].bind_group);
EXPECT_EQ(0u, result[7].binding);
EXPECT_EQ(ResourceBinding::ResourceType::kDepthTexture,
result[8].resource_type);
EXPECT_EQ(3u, result[8].bind_group);
EXPECT_EQ(1u, result[8].binding);
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, MissingEntryPoint) {
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ep_func");
ASSERT_TRUE(inspector.has_error());
std::string error = inspector.error();
EXPECT_TRUE(error.find("not found") != std::string::npos);
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonEntryPointFunc) {
type::Struct* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
AddUniformBuffer("foo_ub", foo_struct_type, 0, 0);
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"ub_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ub_func");
std::string error = inspector.error();
EXPECT_TRUE(error.find("not an entry point") != std::string::npos);
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, MissingBlockDeco) {
ast::DecorationList decos;
auto* str = create<ast::Struct>(
ast::StructMemberList{Member(StructMemberName(0, ty.i32()), ty.i32())},
decos);
auto* foo_type = ty.struct_("foo_type", str);
AddUniformBuffer("foo_ub", foo_type, 0, 0);
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"ub_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(0u, result.size());
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple) {
type::Struct* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
AddUniformBuffer("foo_ub", foo_struct_type, 0, 0);
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"ub_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(4u, result[0].size);
EXPECT_EQ(4u, result[0].size_no_padding);
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleMembers) {
type::Struct* foo_struct_type =
MakeUniformBufferType("foo_type", {ty.i32(), ty.u32(), ty.f32()});
AddUniformBuffer("foo_ub", foo_struct_type, 0, 0);
MakeStructVariableReferenceBodyFunction(
"ub_func", "foo_ub", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
MakeCallerBodyFunction(
"ep_func", {"ub_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(12u, result[0].size);
EXPECT_EQ(12u, result[0].size_no_padding);
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingPadding) {
type::Struct* foo_struct_type =
MakeUniformBufferType("foo_type", {ty.vec3<f32>()});
AddUniformBuffer("foo_ub", foo_struct_type, 0, 0);
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
{{0, ty.vec3<f32>()}});
MakeCallerBodyFunction(
"ep_func", {"ub_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(16u, result[0].size);
EXPECT_EQ(12u, result[0].size_no_padding);
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleUniformBuffers) {
type::Struct* ub_struct_type =
MakeUniformBufferType("ub_type", {ty.i32(), ty.u32(), ty.f32()});
AddUniformBuffer("ub_foo", ub_struct_type, 0, 0);
AddUniformBuffer("ub_bar", ub_struct_type, 0, 1);
AddUniformBuffer("ub_baz", ub_struct_type, 2, 0);
auto AddReferenceFunc = [this](const std::string& func_name,
const std::string& var_name) {
MakeStructVariableReferenceBodyFunction(
func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
};
AddReferenceFunc("ub_foo_func", "ub_foo");
AddReferenceFunc("ub_bar_func", "ub_bar");
AddReferenceFunc("ub_baz_func", "ub_baz");
auto FuncCall = [&](const std::string& callee) {
return create<ast::CallStatement>(Call(callee));
};
Func("ep_func", ast::VariableList(), ty.void_(),
ast::StatementList{FuncCall("ub_foo_func"), FuncCall("ub_bar_func"),
FuncCall("ub_baz_func"),
create<ast::ReturnStatement>()},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(3u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(12u, result[0].size);
EXPECT_EQ(12u, result[0].size_no_padding);
EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
result[1].resource_type);
EXPECT_EQ(0u, result[1].bind_group);
EXPECT_EQ(1u, result[1].binding);
EXPECT_EQ(12u, result[1].size);
EXPECT_EQ(12u, result[1].size_no_padding);
EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
result[2].resource_type);
EXPECT_EQ(2u, result[2].bind_group);
EXPECT_EQ(0u, result[2].binding);
EXPECT_EQ(12u, result[2].size);
EXPECT_EQ(12u, result[2].size_no_padding);
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
// TODO(bclayton) - This is not a legal structure layout for uniform buffer
// usage. Once crbug.com/tint/628 is implemented, this will fail validation
// and will need to be fixed.
type::Struct* foo_struct_type =
MakeUniformBufferType("foo_type", {ty.i32(), u32_array_type(4)});
AddUniformBuffer("foo_ub", foo_struct_type, 0, 0);
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"ub_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(20u, result[0].size);
EXPECT_EQ(20u, result[0].size_no_padding);
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeStorageBufferTypes("foo_type", {ty.i32()});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(4u, result[0].size);
EXPECT_EQ(4u, result[0].size_no_padding);
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeStorageBufferTypes("foo_type", {ty.i32(), ty.u32(), ty.f32()});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction(
"sb_func", "foo_sb", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(12u, result[0].size);
EXPECT_EQ(12u, result[0].size_no_padding);
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
type::Struct* sb_struct_type;
type::AccessControl* sb_control_type;
std::tie(sb_struct_type, sb_control_type) =
MakeStorageBufferTypes("sb_type", {ty.i32(), ty.u32(), ty.f32()});
AddStorageBuffer("sb_foo", sb_control_type, 0, 0);
AddStorageBuffer("sb_bar", sb_control_type, 0, 1);
AddStorageBuffer("sb_baz", sb_control_type, 2, 0);
auto AddReferenceFunc = [this](const std::string& func_name,
const std::string& var_name) {
MakeStructVariableReferenceBodyFunction(
func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
};
AddReferenceFunc("sb_foo_func", "sb_foo");
AddReferenceFunc("sb_bar_func", "sb_bar");
AddReferenceFunc("sb_baz_func", "sb_baz");
auto FuncCall = [&](const std::string& callee) {
return create<ast::CallStatement>(Call(callee));
};
Func("ep_func", ast::VariableList(), ty.void_(),
ast::StatementList{
FuncCall("sb_foo_func"),
FuncCall("sb_bar_func"),
FuncCall("sb_baz_func"),
create<ast::ReturnStatement>(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(3u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(12u, result[0].size);
EXPECT_EQ(12u, result[0].size_no_padding);
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[1].resource_type);
EXPECT_EQ(0u, result[1].bind_group);
EXPECT_EQ(1u, result[1].binding);
EXPECT_EQ(12u, result[1].size);
EXPECT_EQ(12u, result[1].size_no_padding);
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[2].resource_type);
EXPECT_EQ(2u, result[2].bind_group);
EXPECT_EQ(0u, result[2].binding);
EXPECT_EQ(12u, result[2].size);
EXPECT_EQ(12u, result[2].size_no_padding);
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeStorageBufferTypes("foo_type", {ty.i32(), u32_array_type(4)});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(20u, result[0].size);
EXPECT_EQ(20u, result[0].size_no_padding);
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeStorageBufferTypes("foo_type", {ty.i32(), u32_array_type(0)});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(8u, result[0].size);
EXPECT_EQ(8u, result[0].size_no_padding);
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
{{0, ty.vec3<f32>()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(16u, result[0].size);
EXPECT_EQ(12u, result[0].size_no_padding);
}
TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32()});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(0u, result.size());
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32()});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(4u, result[0].size);
EXPECT_EQ(4u, result[0].size_no_padding);
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
MultipleStorageBuffers) {
type::Struct* sb_struct_type;
type::AccessControl* sb_control_type;
std::tie(sb_struct_type, sb_control_type) =
MakeReadOnlyStorageBufferTypes("sb_type", {ty.i32(), ty.u32(), ty.f32()});
AddStorageBuffer("sb_foo", sb_control_type, 0, 0);
AddStorageBuffer("sb_bar", sb_control_type, 0, 1);
AddStorageBuffer("sb_baz", sb_control_type, 2, 0);
auto AddReferenceFunc = [this](const std::string& func_name,
const std::string& var_name) {
MakeStructVariableReferenceBodyFunction(
func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
};
AddReferenceFunc("sb_foo_func", "sb_foo");
AddReferenceFunc("sb_bar_func", "sb_bar");
AddReferenceFunc("sb_baz_func", "sb_baz");
auto FuncCall = [&](const std::string& callee) {
return create<ast::CallStatement>(Call(callee));
};
Func("ep_func", ast::VariableList(), ty.void_(),
ast::StatementList{
FuncCall("sb_foo_func"),
FuncCall("sb_bar_func"),
FuncCall("sb_baz_func"),
create<ast::ReturnStatement>(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(3u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(12u, result[0].size);
EXPECT_EQ(12u, result[0].size_no_padding);
EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
result[1].resource_type);
EXPECT_EQ(0u, result[1].bind_group);
EXPECT_EQ(1u, result[1].binding);
EXPECT_EQ(12u, result[1].size);
EXPECT_EQ(12u, result[1].size_no_padding);
EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
result[2].resource_type);
EXPECT_EQ(2u, result[2].bind_group);
EXPECT_EQ(0u, result[2].binding);
EXPECT_EQ(12u, result[2].size);
EXPECT_EQ(12u, result[2].size_no_padding);
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32(), u32_array_type(4)});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(20u, result[0].size);
EXPECT_EQ(20u, result[0].size_no_padding);
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
ContainingRuntimeArray) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32(), u32_array_type(0)});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(8u, result[0].size);
EXPECT_EQ(8u, result[0].size_no_padding);
}
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) {
type::Struct* foo_struct_type;
type::AccessControl* foo_control_type;
std::tie(foo_struct_type, foo_control_type) =
MakeStorageBufferTypes("foo_type", {ty.i32()});
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"sb_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(0u, result.size());
}
TEST_F(InspectorGetSamplerResourceBindingsTest, Simple) {
auto* sampled_texture_type =
MakeSampledTextureType(type::TextureDimension::k1d, ty.f32());
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
AddSampler("foo_sampler", 0, 1);
AddGlobalVariable("foo_coords", ty.f32());
MakeSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSamplerResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[0].resource_type);
ASSERT_EQ(1u, result.size());
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(1u, result[0].binding);
}
TEST_F(InspectorGetSamplerResourceBindingsTest, NoSampler) {
MakeEmptyBodyFunction(
"ep_func", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSamplerResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(0u, result.size());
}
TEST_F(InspectorGetSamplerResourceBindingsTest, InFunction) {
auto* sampled_texture_type =
MakeSampledTextureType(type::TextureDimension::k1d, ty.f32());
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
AddSampler("foo_sampler", 0, 1);
AddGlobalVariable("foo_coords", ty.f32());
MakeSamplerReferenceBodyFunction("foo_func", "foo_texture", "foo_sampler",
"foo_coords", ty.f32(), {});
MakeCallerBodyFunction(
"ep_func", {"foo_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSamplerResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[0].resource_type);
ASSERT_EQ(1u, result.size());
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(1u, result[0].binding);
}
TEST_F(InspectorGetSamplerResourceBindingsTest, UnknownEntryPoint) {
auto* sampled_texture_type =
MakeSampledTextureType(type::TextureDimension::k1d, ty.f32());
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
AddSampler("foo_sampler", 0, 1);
AddGlobalVariable("foo_coords", ty.f32());
MakeSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSamplerResourceBindings("foo");
ASSERT_TRUE(inspector.has_error()) << inspector.error();
}
TEST_F(InspectorGetSamplerResourceBindingsTest, SkipsComparisonSamplers) {
auto* depth_texture_type = MakeDepthTextureType(type::TextureDimension::k2d);
AddDepthTexture("foo_texture", depth_texture_type, 0, 0);
AddComparisonSampler("foo_sampler", 0, 1);
AddGlobalVariable("foo_coords", ty.vec2<f32>());
AddGlobalVariable("foo_depth", ty.f32());
MakeComparisonSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSamplerResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(0u, result.size());
}
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, Simple) {
auto* depth_texture_type = MakeDepthTextureType(type::TextureDimension::k2d);
AddDepthTexture("foo_texture", depth_texture_type, 0, 0);
AddComparisonSampler("foo_sampler", 0, 1);
AddGlobalVariable("foo_coords", ty.vec2<f32>());
AddGlobalVariable("foo_depth", ty.f32());
MakeComparisonSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetComparisonSamplerResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
result[0].resource_type);
ASSERT_EQ(1u, result.size());
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(1u, result[0].binding);
}
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, NoSampler) {
MakeEmptyBodyFunction(
"ep_func", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetComparisonSamplerResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(0u, result.size());
}
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, InFunction) {
auto* depth_texture_type = MakeDepthTextureType(type::TextureDimension::k2d);
AddDepthTexture("foo_texture", depth_texture_type, 0, 0);
AddComparisonSampler("foo_sampler", 0, 1);
AddGlobalVariable("foo_coords", ty.vec2<f32>());
AddGlobalVariable("foo_depth", ty.f32());
MakeComparisonSamplerReferenceBodyFunction("foo_func", "foo_texture",
"foo_sampler", "foo_coords",
"foo_depth", ty.f32(), {});
MakeCallerBodyFunction(
"ep_func", {"foo_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetComparisonSamplerResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
result[0].resource_type);
ASSERT_EQ(1u, result.size());
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(1u, result[0].binding);
}
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, UnknownEntryPoint) {
auto* depth_texture_type = MakeDepthTextureType(type::TextureDimension::k2d);
AddDepthTexture("foo_texture", depth_texture_type, 0, 0);
AddComparisonSampler("foo_sampler", 0, 1);
AddGlobalVariable("foo_coords", ty.vec2<f32>());
AddGlobalVariable("foo_depth", ty.f32());
MakeComparisonSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSamplerResourceBindings("foo");
ASSERT_TRUE(inspector.has_error()) << inspector.error();
}
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, SkipsSamplers) {
auto* sampled_texture_type =
MakeSampledTextureType(type::TextureDimension::k1d, ty.f32());
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
AddSampler("foo_sampler", 0, 1);
AddGlobalVariable("foo_coords", ty.f32());
MakeSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetComparisonSamplerResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(0u, result.size());
}
TEST_F(InspectorGetSampledTextureResourceBindingsTest, Empty) {
MakeEmptyBodyFunction(
"foo", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSampledTextureResourceBindings("foo");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(0u, result.size());
}
TEST_P(InspectorGetSampledTextureResourceBindingsTestWithParam, textureSample) {
auto* sampled_texture_type = MakeSampledTextureType(
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
AddSampler("foo_sampler", 0, 1);
auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
AddGlobalVariable("foo_coords", coord_type);
MakeSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords",
GetBaseType(GetParam().sampled_kind),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSampledTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
result[0].resource_type);
ASSERT_EQ(1u, result.size());
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
// Prove that sampled and multi-sampled bindings are accounted
// for separately.
auto multisampled_result =
inspector.GetMultisampledTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_TRUE(multisampled_result.empty());
}
INSTANTIATE_TEST_SUITE_P(
InspectorGetSampledTextureResourceBindingsTest,
InspectorGetSampledTextureResourceBindingsTestWithParam,
testing::Values(
GetSampledTextureTestParams{
type::TextureDimension::k1d,
inspector::ResourceBinding::TextureDimension::k1d,
inspector::ResourceBinding::SampledKind::kFloat},
GetSampledTextureTestParams{
type::TextureDimension::k2d,
inspector::ResourceBinding::TextureDimension::k2d,
inspector::ResourceBinding::SampledKind::kFloat},
GetSampledTextureTestParams{
type::TextureDimension::k3d,
inspector::ResourceBinding::TextureDimension::k3d,
inspector::ResourceBinding::SampledKind::kFloat},
GetSampledTextureTestParams{
type::TextureDimension::kCube,
inspector::ResourceBinding::TextureDimension::kCube,
inspector::ResourceBinding::SampledKind::kFloat}));
TEST_P(InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
textureSample) {
auto* sampled_texture_type = MakeSampledTextureType(
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
AddSampler("foo_sampler", 0, 1);
auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
AddGlobalVariable("foo_coords", coord_type);
AddGlobalVariable("foo_array_index", ty.i32());
MakeSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords", "foo_array_index",
GetBaseType(GetParam().sampled_kind),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSampledTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
}
INSTANTIATE_TEST_SUITE_P(
InspectorGetSampledArrayTextureResourceBindingsTest,
InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
testing::Values(
GetSampledTextureTestParams{
type::TextureDimension::k2dArray,
inspector::ResourceBinding::TextureDimension::k2dArray,
inspector::ResourceBinding::SampledKind::kFloat},
GetSampledTextureTestParams{
type::TextureDimension::kCubeArray,
inspector::ResourceBinding::TextureDimension::kCubeArray,
inspector::ResourceBinding::SampledKind::kFloat}));
TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
textureLoad) {
auto* multisampled_texture_type = MakeMultisampledTextureType(
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
AddMultisampledTexture("foo_texture", multisampled_texture_type, 0, 0);
auto* coord_type = GetCoordsType(GetParam().type_dim, ty.i32());
AddGlobalVariable("foo_coords", coord_type);
AddGlobalVariable("foo_sample_index", ty.i32());
Func("ep", ast::VariableList(), ty.void_(),
ast::StatementList{
create<ast::CallStatement>(Call("textureLoad", "foo_texture",
"foo_coords", "foo_sample_index")),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetMultisampledTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(ResourceBinding::ResourceType::kMulitsampledTexture,
result[0].resource_type);
ASSERT_EQ(1u, result.size());
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
// Prove that sampled and multi-sampled bindings are accounted
// for separately.
auto single_sampled_result =
inspector.GetSampledTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_TRUE(single_sampled_result.empty());
}
INSTANTIATE_TEST_SUITE_P(
InspectorGetMultisampledTextureResourceBindingsTest,
InspectorGetMultisampledTextureResourceBindingsTestWithParam,
testing::Values(
GetMultisampledTextureTestParams{
type::TextureDimension::k2d,
inspector::ResourceBinding::TextureDimension::k2d,
inspector::ResourceBinding::SampledKind::kFloat},
GetMultisampledTextureTestParams{
type::TextureDimension::k2d,
inspector::ResourceBinding::TextureDimension::k2d,
inspector::ResourceBinding::SampledKind::kSInt},
GetMultisampledTextureTestParams{
type::TextureDimension::k2d,
inspector::ResourceBinding::TextureDimension::k2d,
inspector::ResourceBinding::SampledKind::kUInt}));
TEST_F(InspectorGetMultisampledArrayTextureResourceBindingsTest, Empty) {
MakeEmptyBodyFunction(
"foo", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetSampledTextureResourceBindings("foo");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(0u, result.size());
}
TEST_P(InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
DISABLED_textureSample) {
auto* multisampled_texture_type = MakeMultisampledTextureType(
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
AddMultisampledTexture("foo_texture", multisampled_texture_type, 0, 0);
AddSampler("foo_sampler", 0, 1);
auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
AddGlobalVariable("foo_coords", coord_type);
AddGlobalVariable("foo_array_index", ty.i32());
MakeSamplerReferenceBodyFunction(
"ep", "foo_texture", "foo_sampler", "foo_coords", "foo_array_index",
GetBaseType(GetParam().sampled_kind),
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetMultisampledTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(ResourceBinding::ResourceType::kMulitsampledTexture,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
}
INSTANTIATE_TEST_SUITE_P(
InspectorGetMultisampledArrayTextureResourceBindingsTest,
InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
testing::Values(
GetMultisampledTextureTestParams{
type::TextureDimension::k2dArray,
inspector::ResourceBinding::TextureDimension::k2dArray,
inspector::ResourceBinding::SampledKind::kFloat},
GetMultisampledTextureTestParams{
type::TextureDimension::k2dArray,
inspector::ResourceBinding::TextureDimension::k2dArray,
inspector::ResourceBinding::SampledKind::kSInt},
GetMultisampledTextureTestParams{
type::TextureDimension::k2dArray,
inspector::ResourceBinding::TextureDimension::k2dArray,
inspector::ResourceBinding::SampledKind::kUInt}));
TEST_F(InspectorGetStorageTextureResourceBindingsTest, Empty) {
MakeEmptyBodyFunction(
"ep", ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetReadOnlyStorageTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(0u, result.size());
result = inspector.GetWriteOnlyStorageTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(0u, result.size());
}
TEST_P(InspectorGetStorageTextureResourceBindingsTestWithParam, Simple) {
bool read_only;
DimensionParams dim_params;
ImageFormatParams format_params;
std::tie(read_only, dim_params, format_params) = GetParam();
type::TextureDimension dim;
ResourceBinding::TextureDimension expected_dim;
std::tie(dim, expected_dim) = dim_params;
type::ImageFormat format;
ResourceBinding::ImageFormat expected_format;
ResourceBinding::SampledKind expected_kind;
std::tie(format, expected_format, expected_kind) = format_params;
type::StorageTexture* st_type;
type::Type* st_subtype;
type::AccessControl* ac;
std::tie(st_type, st_subtype, ac) =
MakeStorageTextureTypes(dim, format, read_only);
AddStorageTexture("st_var", ac, 0, 0);
type::Type* dim_type = nullptr;
switch (dim) {
case type::TextureDimension::k1d:
dim_type = ty.i32();
break;
case type::TextureDimension::k2d:
case type::TextureDimension::k2dArray:
dim_type = ty.vec2<i32>();
break;
case type::TextureDimension::k3d:
dim_type = ty.vec3<i32>();
break;
default:
break;
}
ASSERT_FALSE(dim_type == nullptr);
MakeStorageTextureBodyFunction(
"ep", "st_var", dim_type,
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
Inspector& inspector = Build();
auto result =
read_only ? inspector.GetReadOnlyStorageTextureResourceBindings("ep")
: inspector.GetWriteOnlyStorageTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(1u, result.size());
EXPECT_EQ(read_only ? ResourceBinding::ResourceType::kReadOnlyStorageTexture
: ResourceBinding::ResourceType::kWriteOnlyStorageTexture,
result[0].resource_type);
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(expected_dim, result[0].dim);
EXPECT_EQ(expected_format, result[0].image_format);
EXPECT_EQ(expected_kind, result[0].sampled_kind);
result = read_only
? inspector.GetWriteOnlyStorageTextureResourceBindings("ep")
: inspector.GetReadOnlyStorageTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
ASSERT_EQ(0u, result.size());
}
INSTANTIATE_TEST_SUITE_P(
InspectorGetStorageTextureResourceBindingsTest,
InspectorGetStorageTextureResourceBindingsTestWithParam,
testing::Combine(
testing::Bool(),
testing::Values(
std::make_tuple(type::TextureDimension::k1d,
ResourceBinding::TextureDimension::k1d),
std::make_tuple(type::TextureDimension::k2d,
ResourceBinding::TextureDimension::k2d),
std::make_tuple(type::TextureDimension::k2dArray,
ResourceBinding::TextureDimension::k2dArray),
std::make_tuple(type::TextureDimension::k3d,
ResourceBinding::TextureDimension::k3d)),
testing::Values(
std::make_tuple(type::ImageFormat::kR8Uint,
ResourceBinding::ImageFormat::kR8Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kR16Uint,
ResourceBinding::ImageFormat::kR16Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kRg8Uint,
ResourceBinding::ImageFormat::kRg8Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kR32Uint,
ResourceBinding::ImageFormat::kR32Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kRg16Uint,
ResourceBinding::ImageFormat::kRg16Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kRgba8Uint,
ResourceBinding::ImageFormat::kRgba8Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kRg32Uint,
ResourceBinding::ImageFormat::kRg32Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kRgba16Uint,
ResourceBinding::ImageFormat::kRgba16Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kRgba32Uint,
ResourceBinding::ImageFormat::kRgba32Uint,
ResourceBinding::SampledKind::kUInt),
std::make_tuple(type::ImageFormat::kR8Sint,
ResourceBinding::ImageFormat::kR8Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kR16Sint,
ResourceBinding::ImageFormat::kR16Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kRg8Sint,
ResourceBinding::ImageFormat::kRg8Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kR32Sint,
ResourceBinding::ImageFormat::kR32Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kRg16Sint,
ResourceBinding::ImageFormat::kRg16Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kRgba8Sint,
ResourceBinding::ImageFormat::kRgba8Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kRg32Sint,
ResourceBinding::ImageFormat::kRg32Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kRgba16Sint,
ResourceBinding::ImageFormat::kRgba16Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kRgba32Sint,
ResourceBinding::ImageFormat::kRgba32Sint,
ResourceBinding::SampledKind::kSInt),
std::make_tuple(type::ImageFormat::kR8Unorm,
ResourceBinding::ImageFormat::kR8Unorm,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRg8Unorm,
ResourceBinding::ImageFormat::kRg8Unorm,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRgba8Unorm,
ResourceBinding::ImageFormat::kRgba8Unorm,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRgba8UnormSrgb,
ResourceBinding::ImageFormat::kRgba8UnormSrgb,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kBgra8Unorm,
ResourceBinding::ImageFormat::kBgra8Unorm,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kBgra8UnormSrgb,
ResourceBinding::ImageFormat::kBgra8UnormSrgb,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRgb10A2Unorm,
ResourceBinding::ImageFormat::kRgb10A2Unorm,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kR8Snorm,
ResourceBinding::ImageFormat::kR8Snorm,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRg8Snorm,
ResourceBinding::ImageFormat::kRg8Snorm,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRgba8Snorm,
ResourceBinding::ImageFormat::kRgba8Snorm,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kR16Float,
ResourceBinding::ImageFormat::kR16Float,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kR32Float,
ResourceBinding::ImageFormat::kR32Float,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRg16Float,
ResourceBinding::ImageFormat::kRg16Float,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRg11B10Float,
ResourceBinding::ImageFormat::kRg11B10Float,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRg32Float,
ResourceBinding::ImageFormat::kRg32Float,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRgba16Float,
ResourceBinding::ImageFormat::kRgba16Float,
ResourceBinding::SampledKind::kFloat),
std::make_tuple(type::ImageFormat::kRgba32Float,
ResourceBinding::ImageFormat::kRgba32Float,
ResourceBinding::SampledKind::kFloat))));
TEST_P(InspectorGetDepthTextureResourceBindingsTestWithParam,
textureDimensions) {
auto* depth_texture_type = MakeDepthTextureType(GetParam().type_dim);
AddDepthTexture("dt", depth_texture_type, 0, 0);
AddGlobalVariable("dt_level", ty.i32());
Func("ep", ast::VariableList(), ty.void_(),
ast::StatementList{
create<ast::CallStatement>(
Call("textureDimensions", "dt", "dt_level")),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
});
Inspector& inspector = Build();
auto result = inspector.GetDepthTextureResourceBindings("ep");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(ResourceBinding::ResourceType::kDepthTexture,
result[0].resource_type);
ASSERT_EQ(1u, result.size());
EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
}
INSTANTIATE_TEST_SUITE_P(
InspectorGetDepthTextureResourceBindingsTest,
InspectorGetDepthTextureResourceBindingsTestWithParam,
testing::Values(
GetDepthTextureTestParams{
type::TextureDimension::k2d,
inspector::ResourceBinding::TextureDimension::k2d},
GetDepthTextureTestParams{
type::TextureDimension::k2dArray,
inspector::ResourceBinding::TextureDimension::k2dArray},
GetDepthTextureTestParams{
type::TextureDimension::kCube,
inspector::ResourceBinding::TextureDimension::kCube},
GetDepthTextureTestParams{
type::TextureDimension::kCubeArray,
inspector::ResourceBinding::TextureDimension::kCubeArray}));
} // namespace
} // namespace inspector
} // namespace tint