mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-08-25 13:12:00 +00:00
BUG=tint:424 Change-Id: Ic378173ac4e6697b57102db611cdc0b29b25c72a Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56302 Auto-Submit: Ryan Harrison <rharrison@chromium.org> Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com> Reviewed-by: James Price <jrprice@google.com>
3232 lines
127 KiB
C++
3232 lines
127 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/disable_validation_decoration.h"
|
|
#include "src/ast/override_decoration.h"
|
|
#include "src/ast/stage_decoration.h"
|
|
#include "src/ast/struct_block_decoration.h"
|
|
#include "src/ast/workgroup_decoration.h"
|
|
#include "src/program_builder.h"
|
|
#include "src/sem/depth_texture_type.h"
|
|
#include "src/sem/external_texture_type.h"
|
|
#include "src/sem/multisampled_texture_type.h"
|
|
#include "src/sem/sampled_texture_type.h"
|
|
#include "src/sem/variable.h"
|
|
#include "tint/tint.h"
|
|
|
|
namespace tint {
|
|
namespace inspector {
|
|
namespace {
|
|
|
|
class InspectorHelper : public ProgramBuilder {
|
|
public:
|
|
InspectorHelper() {}
|
|
|
|
/// 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{Return()},
|
|
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(Return());
|
|
|
|
Func(caller, ast::VariableList(), ty.void_(), body, decorations);
|
|
}
|
|
|
|
/// Generates a struct that contains user-defined IO members
|
|
/// @param name the name of the generated struct
|
|
/// @param inout_vars tuples of {name, loc} that will be the struct members
|
|
ast::Struct* MakeInOutStruct(
|
|
std::string name,
|
|
std::vector<std::tuple<std::string, uint32_t>> inout_vars) {
|
|
ast::StructMemberList members;
|
|
for (auto var : inout_vars) {
|
|
std::string member_name;
|
|
uint32_t location;
|
|
std::tie(member_name, location) = var;
|
|
members.push_back(Member(member_name, ty.u32(), {Location(location)}));
|
|
}
|
|
return Structure(name, members);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
/// Add In/Out variables to the global variables
|
|
/// @param inout_vars tuples of {in, out} that will be added as entries to the
|
|
/// global variables
|
|
void AddInOutVariables(
|
|
std::vector<std::tuple<std::string, std::string>> inout_vars) {
|
|
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{
|
|
Location(location++),
|
|
ASTNodes().Create<ast::DisableValidationDecoration>(
|
|
ID(), ast::DisabledValidation::kIgnoreStorageClass)});
|
|
Global(out, ty.u32(), ast::StorageClass::kOutput, nullptr,
|
|
ast::DecorationList{
|
|
Location(location++),
|
|
ASTNodes().Create<ast::DisableValidationDecoration>(
|
|
ID(), ast::DisabledValidation::kIgnoreStorageClass)});
|
|
}
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
/// Generates a function that references in/out variables
|
|
/// @param name name of the function created
|
|
/// @param inout_vars tuples of {in, out} that will be converted into out = in
|
|
/// calls in the function body
|
|
/// @param 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(Assign(out, in));
|
|
}
|
|
stmts.emplace_back(Return());
|
|
Func(name, ast::VariableList(), ty.void_(), stmts, decorations);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
/// Generates a function that references in/out variables and calls another
|
|
/// function.
|
|
/// @param caller name of the function created
|
|
/// @param callee name of the function to be called
|
|
/// @param inout_vars tuples of {in, out} that will be converted into out = in
|
|
/// calls in the function body
|
|
/// @param 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(Assign(out, in));
|
|
}
|
|
stmts.emplace_back(create<ast::CallStatement>(Call(callee)));
|
|
stmts.emplace_back(Return());
|
|
|
|
return Func(caller, ast::VariableList(), ty.void_(), stmts, decorations);
|
|
}
|
|
|
|
/// Add a pipeline constant to the global variables, with a specific ID.
|
|
/// @param name name of the variable to add
|
|
/// @param id id number for the constant id
|
|
/// @param type type of the variable
|
|
/// @param val value to initialize the variable with, if NULL no initializer
|
|
/// will be added.
|
|
/// @returns the constant that was created
|
|
template <class T>
|
|
ast::Variable* AddOverridableConstantWithID(std::string name,
|
|
uint32_t id,
|
|
ast::Type* type,
|
|
T* val) {
|
|
ast::Expression* constructor = nullptr;
|
|
if (val) {
|
|
constructor = Expr(*val);
|
|
}
|
|
return GlobalConst(name, type, constructor,
|
|
ast::DecorationList{
|
|
Override(id),
|
|
});
|
|
}
|
|
|
|
/// Add a pipeline constant to the global variables, without a specific ID.
|
|
/// @param name name of the variable to add
|
|
/// @param type type of the variable
|
|
/// @param val value to initialize the variable with, if NULL no initializer
|
|
/// will be added.
|
|
/// @returns the constant that was created
|
|
template <class T>
|
|
ast::Variable* AddOverridableConstantWithoutID(std::string name,
|
|
ast::Type* type,
|
|
T* val) {
|
|
ast::Expression* constructor = nullptr;
|
|
if (val) {
|
|
constructor = Expr(*val);
|
|
}
|
|
return GlobalConst(name, type, constructor,
|
|
ast::DecorationList{
|
|
Override(),
|
|
});
|
|
}
|
|
|
|
/// Generates a function that references module constant
|
|
/// @param func name of the function created
|
|
/// @param var name of the constant to be reference
|
|
/// @param type type of the const being referenced
|
|
/// @param decorations the function decorations
|
|
/// @returns a function object
|
|
ast::Function* MakeConstReferenceBodyFunction(
|
|
std::string func,
|
|
std::string var,
|
|
ast::Type* type,
|
|
ast::DecorationList decorations) {
|
|
ast::StatementList stmts;
|
|
stmts.emplace_back(Decl(Var("local_" + var, type)));
|
|
stmts.emplace_back(Assign("local_" + var, var));
|
|
stmts.emplace_back(Return());
|
|
|
|
return Func(func, ast::VariableList(), ty.void_(), stmts, decorations);
|
|
}
|
|
|
|
/// @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, ast::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
|
|
ast::Struct* MakeStructType(const std::string& name,
|
|
std::vector<ast::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>());
|
|
}
|
|
|
|
return Structure(name, members, decos);
|
|
}
|
|
|
|
/// 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.
|
|
ast::Struct* MakeUniformBufferType(const std::string& name,
|
|
std::vector<ast::Type*> member_types) {
|
|
return MakeStructType(name, member_types, true);
|
|
}
|
|
|
|
/// Generates types appropriate for using in a storage buffer
|
|
/// @param name name for the type
|
|
/// @param member_types a vector of member types
|
|
/// @returns a function that returns the created structure.
|
|
std::function<ast::TypeName*()> MakeStorageBufferTypes(
|
|
const std::string& name,
|
|
std::vector<ast::Type*> member_types) {
|
|
MakeStructType(name, member_types, true);
|
|
return [this, name] { return ty.type_name(name); };
|
|
}
|
|
|
|
/// 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,
|
|
ast::Type* type,
|
|
uint32_t group,
|
|
uint32_t binding) {
|
|
Global(name, type, ast::StorageClass::kUniform,
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
/// Adds a storage buffer variable to the program
|
|
/// @param name the name of the variable
|
|
/// @param type the type to use
|
|
/// @param access the storage buffer access control
|
|
/// @param group the binding/group to use for the storage buffer
|
|
/// @param binding the binding number to use for the storage buffer
|
|
void AddStorageBuffer(const std::string& name,
|
|
ast::Type* type,
|
|
ast::Access access,
|
|
uint32_t group,
|
|
uint32_t binding) {
|
|
Global(name, type, ast::StorageClass::kStorage, access,
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
/// 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, ast::Type*>> members) {
|
|
ast::StatementList stmts;
|
|
for (auto member : members) {
|
|
size_t member_idx;
|
|
ast::Type* member_type;
|
|
std::tie(member_idx, member_type) = member;
|
|
std::string member_name = StructMemberName(member_idx, member_type);
|
|
|
|
stmts.emplace_back(Decl(Var("local" + member_name, member_type)));
|
|
}
|
|
|
|
for (auto member : members) {
|
|
size_t member_idx;
|
|
ast::Type* member_type;
|
|
std::tie(member_idx, member_type) = member;
|
|
std::string member_name = StructMemberName(member_idx, member_type);
|
|
|
|
stmts.emplace_back(Assign("local" + member_name,
|
|
MemberAccessor(struct_name, member_name)));
|
|
}
|
|
|
|
stmts.emplace_back(Return());
|
|
|
|
Func(func_name, ast::VariableList(), ty.void_(), stmts,
|
|
ast::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) {
|
|
Global(name, sampler_type(),
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
/// 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) {
|
|
Global(name, comparison_sampler_type(),
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
/// 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
|
|
ast::SampledTexture* MakeSampledTextureType(ast::TextureDimension dim,
|
|
ast::Type* type) {
|
|
return ty.sampled_texture(dim, type);
|
|
}
|
|
|
|
/// Generates a DepthTexture appropriate for the params
|
|
/// @param dim the dimensions of the texture
|
|
/// @returns the generated DepthTexture
|
|
ast::DepthTexture* MakeDepthTextureType(ast::TextureDimension dim) {
|
|
return ty.depth_texture(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
|
|
ast::MultisampledTexture* MakeMultisampledTextureType(
|
|
ast::TextureDimension dim,
|
|
ast::Type* type) {
|
|
return ty.multisampled_texture(dim, type);
|
|
}
|
|
|
|
/// Generates an ExternalTexture appropriate for the params
|
|
/// @returns the generated ExternalTexture
|
|
ast::ExternalTexture* MakeExternalTextureType() {
|
|
return ty.external_texture();
|
|
}
|
|
|
|
/// 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,
|
|
ast::Type* type,
|
|
uint32_t group,
|
|
uint32_t binding) {
|
|
Global(name, type,
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
/// 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,
|
|
ast::Type* type,
|
|
uint32_t group,
|
|
uint32_t binding) {
|
|
Global(name, type,
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
void AddGlobalVariable(const std::string& name, ast::Type* type) {
|
|
Global(name, type, ast::StorageClass::kPrivate);
|
|
}
|
|
|
|
/// 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,
|
|
ast::Type* type,
|
|
uint32_t group,
|
|
uint32_t binding) {
|
|
Global(name, type,
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
/// Adds an external 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 external texture
|
|
/// @param binding the binding number to use for the external texture
|
|
void AddExternalTexture(const std::string& name,
|
|
ast::Type* type,
|
|
uint32_t group,
|
|
uint32_t binding) {
|
|
Global(name, type,
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
/// 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,
|
|
ast::Type* base_type,
|
|
ast::DecorationList decorations) {
|
|
std::string result_name = "sampler_result";
|
|
|
|
ast::StatementList stmts;
|
|
stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4))));
|
|
|
|
stmts.emplace_back(Assign(result_name, Call("textureSample", texture_name,
|
|
sampler_name, coords_name)));
|
|
stmts.emplace_back(Return());
|
|
|
|
return Func(func_name, ast::VariableList(), ty.void_(), stmts, 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,
|
|
ast::Type* base_type,
|
|
ast::DecorationList decorations) {
|
|
std::string result_name = "sampler_result";
|
|
|
|
ast::StatementList stmts;
|
|
|
|
stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4))));
|
|
|
|
stmts.emplace_back(
|
|
Assign("sampler_result", Call("textureSample", texture_name,
|
|
sampler_name, coords_name, array_index)));
|
|
stmts.emplace_back(Return());
|
|
|
|
return Func(func_name, ast::VariableList(), ty.void_(), stmts, 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,
|
|
ast::Type* base_type,
|
|
ast::DecorationList decorations) {
|
|
std::string result_name = "sampler_result";
|
|
|
|
ast::StatementList stmts;
|
|
|
|
stmts.emplace_back(Decl(Var("sampler_result", base_type)));
|
|
stmts.emplace_back(
|
|
Assign("sampler_result", Call("textureSampleCompare", texture_name,
|
|
sampler_name, coords_name, depth_name)));
|
|
stmts.emplace_back(Return());
|
|
|
|
return Func(func_name, ast::VariableList(), ty.void_(), stmts, 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
|
|
ast::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
|
|
ast::Type* GetCoordsType(ast::TextureDimension dim, ast::Type* scalar) {
|
|
switch (dim) {
|
|
case ast::TextureDimension::k1d:
|
|
return scalar;
|
|
case ast::TextureDimension::k2d:
|
|
case ast::TextureDimension::k2dArray:
|
|
return create<ast::Vector>(scalar, 2);
|
|
case ast::TextureDimension::k3d:
|
|
case ast::TextureDimension::kCube:
|
|
case ast::TextureDimension::kCubeArray:
|
|
return create<ast::Vector>(scalar, 3);
|
|
default:
|
|
[=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/// 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
|
|
ast::Type* MakeStorageTextureTypes(ast::TextureDimension dim,
|
|
ast::ImageFormat format,
|
|
bool read_only) {
|
|
auto access = read_only ? ast::Access::kRead : ast::Access::kWrite;
|
|
return ty.storage_texture(dim, format, access);
|
|
}
|
|
|
|
/// 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,
|
|
ast::Type* type,
|
|
uint32_t group,
|
|
uint32_t binding) {
|
|
Global(name, type,
|
|
ast::DecorationList{
|
|
create<ast::BindingDecoration>(binding),
|
|
create<ast::GroupDecoration>(group),
|
|
});
|
|
}
|
|
|
|
/// 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,
|
|
ast::Type* dim_type,
|
|
ast::DecorationList decorations) {
|
|
ast::StatementList stmts;
|
|
|
|
stmts.emplace_back(Decl(Var("dim", dim_type)));
|
|
stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name)));
|
|
stmts.emplace_back(Return());
|
|
|
|
return Func(func_name, ast::VariableList(), ty.void_(), stmts, 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_;
|
|
}
|
|
|
|
ast::Sampler* sampler_type() {
|
|
return ty.sampler(ast::SamplerKind::kSampler);
|
|
}
|
|
ast::Sampler* comparison_sampler_type() {
|
|
return ty.sampler(ast::SamplerKind::kComparisonSampler);
|
|
}
|
|
|
|
protected:
|
|
std::unique_ptr<Program> program_;
|
|
std::unique_ptr<Inspector> inspector_;
|
|
};
|
|
|
|
class InspectorGetEntryPointTest : public InspectorHelper,
|
|
public testing::Test {};
|
|
class InspectorGetEntryPointTestWithComponentTypeParam
|
|
: public InspectorHelper,
|
|
public testing::TestWithParam<ComponentType> {};
|
|
class InspectorGetRemappedNameForEntryPointTest : public InspectorHelper,
|
|
public testing::Test {};
|
|
class InspectorGetConstantIDsTest : public InspectorHelper,
|
|
public testing::Test {};
|
|
class InspectorGetConstantNameToIdMapTest : 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 {
|
|
ast::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 {
|
|
ast::TextureDimension type_dim;
|
|
inspector::ResourceBinding::TextureDimension inspector_dim;
|
|
};
|
|
class InspectorGetDepthTextureResourceBindingsTestWithParam
|
|
: public InspectorHelper,
|
|
public testing::TestWithParam<GetDepthTextureTestParams> {};
|
|
|
|
typedef std::tuple<ast::TextureDimension, ResourceBinding::TextureDimension>
|
|
DimensionParams;
|
|
typedef std::tuple<ast::ImageFormat,
|
|
ResourceBinding::ImageFormat,
|
|
ResourceBinding::SampledKind>
|
|
ImageFormatParams;
|
|
typedef std::tuple<bool, DimensionParams, ImageFormatParams>
|
|
GetStorageTextureTestParams;
|
|
class InspectorGetStorageTextureResourceBindingsTestWithParam
|
|
: public InspectorHelper,
|
|
public testing::TestWithParam<GetStorageTextureTestParams> {};
|
|
|
|
class InspectorGetExternalTextureResourceBindingsTest : public InspectorHelper,
|
|
public testing::Test {};
|
|
|
|
class InspectorGetSamplerTextureUsesTest : public InspectorHelper,
|
|
public testing::Test {};
|
|
|
|
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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
// 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::kFragment, result[0].stage);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
|
|
MakeEmptyBodyFunction("foo", ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
MakeEmptyBodyFunction("bar",
|
|
ast::DecorationList{Stage(ast::PipelineStage::kCompute),
|
|
WorkgroupSize(1)});
|
|
|
|
// 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::kFragment, 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{Stage(ast::PipelineStage::kCompute),
|
|
WorkgroupSize(1)});
|
|
|
|
MakeCallerBodyFunction("bar", {"func"},
|
|
ast::DecorationList{
|
|
Stage(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::kCompute, 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{Stage(ast::PipelineStage::kCompute),
|
|
WorkgroupSize(8, 2, 1)});
|
|
|
|
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, NonDefaultWorkgroupSize) {
|
|
MakeEmptyBodyFunction(
|
|
"foo", {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8, 2, 1)});
|
|
|
|
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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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_P(InspectorGetEntryPointTestWithComponentTypeParam, InOutVariables) {
|
|
ComponentType inspector_type = GetParam();
|
|
std::function<ast::Type*()> tint_type;
|
|
switch (inspector_type) {
|
|
case ComponentType::kFloat:
|
|
tint_type = [this]() -> ast::Type* { return ty.f32(); };
|
|
break;
|
|
case ComponentType::kSInt:
|
|
tint_type = [this]() -> ast::Type* { return ty.i32(); };
|
|
break;
|
|
case ComponentType::kUInt:
|
|
tint_type = [this]() -> ast::Type* { return ty.u32(); };
|
|
break;
|
|
case ComponentType::kUnknown:
|
|
return;
|
|
}
|
|
|
|
auto* in_var = Param("in_var", tint_type(), {Location(0u)});
|
|
Func("foo", {in_var}, tint_type(), {Return("in_var")},
|
|
{Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
|
|
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(inspector_type, result[0].input_variables[0].component_type);
|
|
|
|
ASSERT_EQ(1u, result[0].output_variables.size());
|
|
EXPECT_EQ("<retval>", result[0].output_variables[0].name);
|
|
EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
|
|
EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
|
|
EXPECT_EQ(inspector_type, result[0].output_variables[0].component_type);
|
|
}
|
|
INSTANTIATE_TEST_SUITE_P(InspectorGetEntryPointTest,
|
|
InspectorGetEntryPointTestWithComponentTypeParam,
|
|
testing::Values(ComponentType::kFloat,
|
|
ComponentType::kSInt,
|
|
ComponentType::kUInt));
|
|
|
|
TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) {
|
|
auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u)});
|
|
auto* in_var1 = Param("in_var1", ty.u32(), {Location(1u)});
|
|
auto* in_var4 = Param("in_var4", ty.u32(), {Location(4u)});
|
|
Func("foo", {in_var0, in_var1, in_var4}, ty.u32(), {Return("in_var0")},
|
|
{Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
|
|
ASSERT_EQ(3u, result[0].input_variables.size());
|
|
EXPECT_EQ("in_var0", 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);
|
|
EXPECT_EQ("in_var1", result[0].input_variables[1].name);
|
|
EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
|
|
EXPECT_EQ(1u, result[0].input_variables[1].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
|
|
EXPECT_EQ("in_var4", result[0].input_variables[2].name);
|
|
EXPECT_TRUE(result[0].input_variables[2].has_location_decoration);
|
|
EXPECT_EQ(4u, result[0].input_variables[2].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type);
|
|
|
|
ASSERT_EQ(1u, result[0].output_variables.size());
|
|
EXPECT_EQ("<retval>", result[0].output_variables[0].name);
|
|
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);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
|
|
auto* in_var_foo = Param("in_var_foo", ty.u32(), {Location(0u)});
|
|
Func("foo", {in_var_foo}, ty.u32(), {Return("in_var_foo")},
|
|
{Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
|
|
|
|
auto* in_var_bar = Param("in_var_bar", ty.u32(), {Location(0u)});
|
|
Func("bar", {in_var_bar}, ty.u32(), {Return("in_var_bar")},
|
|
{Stage(ast::PipelineStage::kFragment)}, {Location(1u)});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
ASSERT_EQ(2u, result.size());
|
|
|
|
ASSERT_EQ(1u, result[0].input_variables.size());
|
|
EXPECT_EQ("in_var_foo", 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("<retval>", result[0].output_variables[0].name);
|
|
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);
|
|
|
|
ASSERT_EQ(1u, result[1].input_variables.size());
|
|
EXPECT_EQ("in_var_bar", result[1].input_variables[0].name);
|
|
EXPECT_TRUE(result[1].input_variables[0].has_location_decoration);
|
|
EXPECT_EQ(0u, 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("<retval>", 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, BuiltInsNotStageVariables) {
|
|
auto* in_var0 =
|
|
Param("in_var0", ty.u32(), {Builtin(ast::Builtin::kInstanceIndex)});
|
|
auto* in_var1 = Param("in_var1", ty.u32(), {Location(0u)});
|
|
Func("foo", {in_var0, in_var1}, ty.u32(), {Return("in_var1")},
|
|
{Stage(ast::PipelineStage::kFragment)},
|
|
{Builtin(ast::Builtin::kSampleMask)});
|
|
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_var1", 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(0u, result[0].output_variables.size());
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, InOutStruct) {
|
|
auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
|
|
Func("foo", {Param("param", ty.Of(interface))}, ty.Of(interface),
|
|
{Return("param")}, {Stage(ast::PipelineStage::kFragment)});
|
|
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_EQ("param.a", 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);
|
|
EXPECT_EQ("param.b", result[0].input_variables[1].name);
|
|
EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
|
|
EXPECT_EQ(1u, 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_EQ("<retval>.a", result[0].output_variables[0].name);
|
|
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);
|
|
EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
|
|
EXPECT_TRUE(result[0].output_variables[1].has_location_decoration);
|
|
EXPECT_EQ(1u, result[0].output_variables[1].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutSharedStruct) {
|
|
auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
|
|
Func("foo", {}, ty.Of(interface), {Return(Construct(ty.Of(interface)))},
|
|
{Stage(ast::PipelineStage::kFragment)});
|
|
Func("bar", {Param("param", ty.Of(interface))}, ty.void_(), {},
|
|
{Stage(ast::PipelineStage::kFragment)});
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
ASSERT_EQ(2u, result.size());
|
|
|
|
ASSERT_EQ(0u, result[0].input_variables.size());
|
|
|
|
ASSERT_EQ(2u, result[0].output_variables.size());
|
|
EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
|
|
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);
|
|
EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
|
|
EXPECT_TRUE(result[0].output_variables[1].has_location_decoration);
|
|
EXPECT_EQ(1u, result[0].output_variables[1].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
|
|
|
|
ASSERT_EQ(2u, result[1].input_variables.size());
|
|
EXPECT_EQ("param.a", result[1].input_variables[0].name);
|
|
EXPECT_TRUE(result[1].input_variables[0].has_location_decoration);
|
|
EXPECT_EQ(0u, result[1].input_variables[0].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
|
|
EXPECT_EQ("param.b", result[1].input_variables[1].name);
|
|
EXPECT_TRUE(result[1].input_variables[1].has_location_decoration);
|
|
EXPECT_EQ(1u, result[1].input_variables[1].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[1].component_type);
|
|
|
|
ASSERT_EQ(0u, result[1].output_variables.size());
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, MixInOutVariablesAndStruct) {
|
|
auto* struct_a = MakeInOutStruct("struct_a", {{"a", 0u}, {"b", 1u}});
|
|
auto* struct_b = MakeInOutStruct("struct_b", {{"a", 2u}});
|
|
Func("foo",
|
|
{Param("param_a", ty.Of(struct_a)), Param("param_b", ty.Of(struct_b)),
|
|
Param("param_c", ty.f32(), {Location(3u)}),
|
|
Param("param_d", ty.f32(), {Location(4u)})},
|
|
ty.Of(struct_a), {Return("param_a")},
|
|
{Stage(ast::PipelineStage::kFragment)});
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
|
|
ASSERT_EQ(5u, result[0].input_variables.size());
|
|
EXPECT_EQ("param_a.a", 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);
|
|
EXPECT_EQ("param_a.b", result[0].input_variables[1].name);
|
|
EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
|
|
EXPECT_EQ(1u, result[0].input_variables[1].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
|
|
EXPECT_EQ("param_b.a", result[0].input_variables[2].name);
|
|
EXPECT_TRUE(result[0].input_variables[2].has_location_decoration);
|
|
EXPECT_EQ(2u, result[0].input_variables[2].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type);
|
|
EXPECT_EQ("param_c", result[0].input_variables[3].name);
|
|
EXPECT_TRUE(result[0].input_variables[3].has_location_decoration);
|
|
EXPECT_EQ(3u, result[0].input_variables[3].location_decoration);
|
|
EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[3].component_type);
|
|
EXPECT_EQ("param_d", result[0].input_variables[4].name);
|
|
EXPECT_TRUE(result[0].input_variables[4].has_location_decoration);
|
|
EXPECT_EQ(4u, result[0].input_variables[4].location_decoration);
|
|
EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[4].component_type);
|
|
|
|
ASSERT_EQ(2u, result[0].output_variables.size());
|
|
EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
|
|
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);
|
|
EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
|
|
EXPECT_TRUE(result[0].output_variables[1].has_location_decoration);
|
|
EXPECT_EQ(1u, result[0].output_variables[1].location_decoration);
|
|
EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
TEST_F(InspectorGetEntryPointTest, EntryPointInOutVariables_Legacy) {
|
|
AddInOutVariables({{"in_var", "out_var"}});
|
|
|
|
MakeInOutVariableBodyFunction("foo", {{"in_var", "out_var"}},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
TEST_F(InspectorGetEntryPointTest, FunctionInOutVariables_Legacy) {
|
|
AddInOutVariables({{"in_var", "out_var"}});
|
|
|
|
MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
|
|
|
|
MakeCallerBodyFunction("foo", {"func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
TEST_F(InspectorGetEntryPointTest, RepeatedInOutVariables_Legacy) {
|
|
AddInOutVariables({{"in_var", "out_var"}});
|
|
|
|
MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
|
|
|
|
MakeInOutVariableCallerBodyFunction("foo", "func", {{"in_var", "out_var"}},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
TEST_F(InspectorGetEntryPointTest, EntryPointMultipleInOutVariables_Legacy) {
|
|
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
|
|
|
MakeInOutVariableBodyFunction(
|
|
"foo", {{"in_var", "out_var"}, {"in2_var", "out2_var"}},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
TEST_F(InspectorGetEntryPointTest, FunctionMultipleInOutVariables_Legacy) {
|
|
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
|
|
|
MakeInOutVariableBodyFunction(
|
|
"func", {{"in_var", "out_var"}, {"in2_var", "out2_var"}}, {});
|
|
|
|
MakeCallerBodyFunction("foo", {"func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables_Legacy) {
|
|
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
|
|
|
MakeInOutVariableBodyFunction("foo", {{"in_var", "out2_var"}},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
MakeInOutVariableBodyFunction(
|
|
"bar", {{"in2_var", "out_var"}},
|
|
ast::DecorationList{Stage(ast::PipelineStage::kCompute),
|
|
WorkgroupSize(1)});
|
|
|
|
// 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);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
TEST_F(InspectorGetEntryPointTest,
|
|
MultipleEntryPointsSharedInOutVariables_Legacy) {
|
|
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
|
|
|
MakeInOutVariableBodyFunction("func", {{"in2_var", "out2_var"}}, {});
|
|
|
|
MakeInOutVariableCallerBodyFunction("foo", "func", {{"in_var", "out_var"}},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
MakeCallerBodyFunction(
|
|
"bar", {"func"},
|
|
ast::DecorationList{Stage(ast::PipelineStage::kCompute),
|
|
WorkgroupSize(1)});
|
|
|
|
// 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);
|
|
}
|
|
|
|
// TODO(crbug.com/tint/697): Remove this.
|
|
TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables_Legacy) {
|
|
Global("in_var", ty.u32(), ast::StorageClass::kInput, nullptr,
|
|
ast::DecorationList{
|
|
Builtin(ast::Builtin::kPosition),
|
|
ASTNodes().Create<ast::DisableValidationDecoration>(
|
|
ID(), ast::DisabledValidation::kIgnoreStorageClass)});
|
|
Global("out_var", ty.u32(), ast::StorageClass::kOutput, nullptr,
|
|
ast::DecorationList{
|
|
Location(0),
|
|
ASTNodes().Create<ast::DisableValidationDecoration>(
|
|
ID(), ast::DisabledValidation::kIgnoreStorageClass)});
|
|
|
|
MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
|
|
|
|
MakeCallerBodyFunction("foo", {"func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
// 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);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, OverridableConstantUnreferenced) {
|
|
AddOverridableConstantWithoutID<float>("foo", ty.f32(), nullptr);
|
|
MakeEmptyBodyFunction(
|
|
"ep_func", {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
EXPECT_EQ(0u, result[0].overridable_constants.size());
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByEntryPoint) {
|
|
AddOverridableConstantWithoutID<float>("foo", ty.f32(), nullptr);
|
|
MakeConstReferenceBodyFunction(
|
|
"ep_func", "foo", ty.f32(),
|
|
{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
tint::writer::wgsl::Generator writer(program_.get());
|
|
writer.Generate();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
ASSERT_EQ(1u, result[0].overridable_constants.size());
|
|
EXPECT_EQ("foo", result[0].overridable_constants[0].name);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByCallee) {
|
|
AddOverridableConstantWithoutID<float>("foo", ty.f32(), nullptr);
|
|
MakeConstReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
|
|
MakeCallerBodyFunction(
|
|
"ep_func", {"callee_func"},
|
|
{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
ASSERT_EQ(1u, result[0].overridable_constants.size());
|
|
EXPECT_EQ("foo", result[0].overridable_constants[0].name);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, OverridableConstantSomeReferenced) {
|
|
AddOverridableConstantWithID<float>("foo", 1, ty.f32(), nullptr);
|
|
AddOverridableConstantWithID<float>("bar", 2, ty.f32(), nullptr);
|
|
MakeConstReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
|
|
MakeCallerBodyFunction(
|
|
"ep_func", {"callee_func"},
|
|
{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
ASSERT_EQ(1u, result[0].overridable_constants.size());
|
|
EXPECT_EQ("foo", result[0].overridable_constants[0].name);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, NonOverridableConstantSkipped) {
|
|
ast::Struct* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
|
|
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
|
|
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
|
|
MakeCallerBodyFunction("ep_func", {"ub_func"},
|
|
{Stage(ast::PipelineStage::kFragment)});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
EXPECT_EQ(0u, result[0].overridable_constants.size());
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, SampleMaskNotReferenced) {
|
|
MakeEmptyBodyFunction("ep_func", {Stage(ast::PipelineStage::kFragment)});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
EXPECT_FALSE(result[0].sample_mask_used);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, SampleMaskSimpleReferenced) {
|
|
auto* in_var =
|
|
Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
|
|
Func("ep_func", {in_var}, ty.u32(), {Return("in_var")},
|
|
{Stage(ast::PipelineStage::kFragment)},
|
|
{Builtin(ast::Builtin::kSampleMask)});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
EXPECT_TRUE(result[0].sample_mask_used);
|
|
}
|
|
|
|
TEST_F(InspectorGetEntryPointTest, SampleMaskStructReferenced) {
|
|
ast::StructMemberList members;
|
|
members.push_back(Member("inner_sample_mask", ty.u32(),
|
|
{Builtin(ast::Builtin::kSampleMask)}));
|
|
Structure("out_struct", members, {});
|
|
|
|
Func("ep_func", {}, ty.type_name("out_struct"),
|
|
{Decl(Var("out_var", ty.type_name("out_struct"))), Return("out_var")},
|
|
{Stage(ast::PipelineStage::kFragment)}, {});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetEntryPoints();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
EXPECT_TRUE(result[0].sample_mask_used);
|
|
}
|
|
|
|
// 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{
|
|
Stage(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{
|
|
Stage(ast::PipelineStage::kVertex),
|
|
});
|
|
|
|
// TODO(dsinclair): Update to run the namer transform when
|
|
// available.
|
|
|
|
MakeEmptyBodyFunction("bar",
|
|
ast::DecorationList{Stage(ast::PipelineStage::kCompute),
|
|
WorkgroupSize(1)});
|
|
|
|
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;
|
|
AddOverridableConstantWithID<bool>("foo", 1, ty.bool_(), nullptr);
|
|
AddOverridableConstantWithID<bool>("bar", 20, ty.bool_(), &val_true);
|
|
AddOverridableConstantWithID<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;
|
|
AddOverridableConstantWithID<uint32_t>("foo", 1, ty.u32(), nullptr);
|
|
AddOverridableConstantWithID<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;
|
|
AddOverridableConstantWithID<int32_t>("foo", 1, ty.i32(), nullptr);
|
|
AddOverridableConstantWithID<int32_t>("bar", 20, ty.i32(), &val_neg);
|
|
AddOverridableConstantWithID<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;
|
|
AddOverridableConstantWithID<float>("foo", 1, ty.f32(), nullptr);
|
|
AddOverridableConstantWithID<float>("bar", 20, ty.f32(), &val_zero);
|
|
AddOverridableConstantWithID<float>("baz", 300, ty.f32(), &val_neg);
|
|
AddOverridableConstantWithID<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(InspectorGetConstantNameToIdMapTest, WithAndWithoutIds) {
|
|
AddOverridableConstantWithID<float>("v1", 1, ty.f32(), nullptr);
|
|
AddOverridableConstantWithID<float>("v20", 20, ty.f32(), nullptr);
|
|
AddOverridableConstantWithID<float>("v300", 300, ty.f32(), nullptr);
|
|
auto* a = AddOverridableConstantWithoutID<float>("a", ty.f32(), nullptr);
|
|
auto* b = AddOverridableConstantWithoutID<float>("b", ty.f32(), nullptr);
|
|
auto* c = AddOverridableConstantWithoutID<float>("c", ty.f32(), nullptr);
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetConstantNameToIdMap();
|
|
ASSERT_EQ(6u, result.size());
|
|
|
|
ASSERT_TRUE(result.count("v1"));
|
|
EXPECT_EQ(result["v1"], 1u);
|
|
|
|
ASSERT_TRUE(result.count("v20"));
|
|
EXPECT_EQ(result["v20"], 20u);
|
|
|
|
ASSERT_TRUE(result.count("v300"));
|
|
EXPECT_EQ(result["v300"], 300u);
|
|
|
|
ASSERT_TRUE(result.count("a"));
|
|
ASSERT_TRUE(program_->Sem().Get(a));
|
|
EXPECT_EQ(result["a"], program_->Sem().Get(a)->ConstantId());
|
|
|
|
ASSERT_TRUE(result.count("b"));
|
|
ASSERT_TRUE(program_->Sem().Get(b));
|
|
EXPECT_EQ(result["b"], program_->Sem().Get(b)->ConstantId());
|
|
|
|
ASSERT_TRUE(result.count("c"));
|
|
ASSERT_TRUE(program_->Sem().Get(c));
|
|
EXPECT_EQ(result["c"], program_->Sem().Get(c)->ConstantId());
|
|
}
|
|
|
|
TEST_F(InspectorGetResourceBindingsTest, Empty) {
|
|
MakeCallerBodyFunction("ep_func", {},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
ast::Struct* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32()});
|
|
AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
|
|
MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
|
|
|
|
auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
|
|
AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
|
|
|
|
auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
|
|
AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
|
|
MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
|
|
{{0, ty.i32()}});
|
|
|
|
auto* s_texture_type =
|
|
MakeSampledTextureType(ast::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(ast::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(), {});
|
|
|
|
auto* st_type = MakeStorageTextureTypes(ast::TextureDimension::k2d,
|
|
ast::ImageFormat::kR32Uint, false);
|
|
AddStorageTexture("st_var", st_type, 4, 0);
|
|
MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<i32>(), {});
|
|
|
|
auto* rost_type = MakeStorageTextureTypes(ast::TextureDimension::k2d,
|
|
ast::ImageFormat::kR32Uint, true);
|
|
AddStorageTexture("rost_var", rost_type, 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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
ast::Struct* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
|
|
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"ub_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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, Simple) {
|
|
ast::Struct* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
|
|
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"ub_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
ast::Struct* foo_struct_type =
|
|
MakeUniformBufferType("foo_type", {ty.i32(), ty.u32(), ty.f32()});
|
|
AddUniformBuffer("foo_ub", ty.Of(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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
ast::Struct* foo_struct_type =
|
|
MakeUniformBufferType("foo_type", {ty.vec3<f32>()});
|
|
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
|
|
{{0, ty.vec3<f32>()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"ub_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
ast::Struct* ub_struct_type =
|
|
MakeUniformBufferType("ub_type", {ty.i32(), ty.u32(), ty.f32()});
|
|
AddUniformBuffer("ub_foo", ty.Of(ub_struct_type), 0, 0);
|
|
AddUniformBuffer("ub_bar", ty.Of(ub_struct_type), 0, 1);
|
|
AddUniformBuffer("ub_baz", ty.Of(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"), Return()},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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.
|
|
ast::Struct* foo_struct_type =
|
|
MakeUniformBufferType("foo_type", {ty.i32(), ty.array<u32, 4>()});
|
|
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"ub_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
|
|
ty.i32(),
|
|
ty.u32(),
|
|
ty.f32(),
|
|
});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction(
|
|
"sb_func", "foo_sb", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
|
|
ty.i32(),
|
|
ty.u32(),
|
|
ty.f32(),
|
|
});
|
|
AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kReadWrite, 0, 0);
|
|
AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kReadWrite, 0, 1);
|
|
AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kReadWrite, 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"),
|
|
Return(),
|
|
},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type =
|
|
MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32, 4>()});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
|
|
ty.i32(),
|
|
ty.array<u32>(),
|
|
});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
|
|
{{0, ty.vec3<f32>()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
|
|
ty.i32(),
|
|
ty.u32(),
|
|
ty.f32(),
|
|
});
|
|
AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kRead, 0, 0);
|
|
AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kRead, 0, 1);
|
|
AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kRead, 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"),
|
|
Return(),
|
|
},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type =
|
|
MakeStorageBufferTypes("foo_type", {
|
|
ty.i32(),
|
|
ty.array<u32, 4>(),
|
|
});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
|
|
ty.i32(),
|
|
ty.array<u32>(),
|
|
});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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) {
|
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
|
|
AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
|
|
|
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
|
|
|
MakeCallerBodyFunction("ep_func", {"sb_func"},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetSamplerResourceBindings("foo");
|
|
ASSERT_TRUE(inspector.has_error()) << inspector.error();
|
|
}
|
|
|
|
TEST_F(InspectorGetSamplerResourceBindingsTest, SkipsComparisonSamplers) {
|
|
auto* depth_texture_type = MakeDepthTextureType(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetSamplerResourceBindings("foo");
|
|
ASSERT_TRUE(inspector.has_error()) << inspector.error();
|
|
}
|
|
|
|
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, SkipsSamplers) {
|
|
auto* sampled_texture_type =
|
|
MakeSampledTextureType(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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{
|
|
ast::TextureDimension::k1d,
|
|
inspector::ResourceBinding::TextureDimension::k1d,
|
|
inspector::ResourceBinding::SampledKind::kFloat},
|
|
GetSampledTextureTestParams{
|
|
ast::TextureDimension::k2d,
|
|
inspector::ResourceBinding::TextureDimension::k2d,
|
|
inspector::ResourceBinding::SampledKind::kFloat},
|
|
GetSampledTextureTestParams{
|
|
ast::TextureDimension::k3d,
|
|
inspector::ResourceBinding::TextureDimension::k3d,
|
|
inspector::ResourceBinding::SampledKind::kFloat},
|
|
GetSampledTextureTestParams{
|
|
ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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{
|
|
ast::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::SampledKind::kFloat},
|
|
GetSampledTextureTestParams{
|
|
ast::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{
|
|
Ignore(Call("textureLoad", "foo_texture", "foo_coords",
|
|
"foo_sample_index")),
|
|
},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetMultisampledTextureResourceBindings("ep");
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture,
|
|
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);
|
|
|
|
// 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{
|
|
ast::TextureDimension::k2d,
|
|
inspector::ResourceBinding::TextureDimension::k2d,
|
|
inspector::ResourceBinding::SampledKind::kFloat},
|
|
GetMultisampledTextureTestParams{
|
|
ast::TextureDimension::k2d,
|
|
inspector::ResourceBinding::TextureDimension::k2d,
|
|
inspector::ResourceBinding::SampledKind::kSInt},
|
|
GetMultisampledTextureTestParams{
|
|
ast::TextureDimension::k2d,
|
|
inspector::ResourceBinding::TextureDimension::k2d,
|
|
inspector::ResourceBinding::SampledKind::kUInt}));
|
|
|
|
TEST_F(InspectorGetMultisampledArrayTextureResourceBindingsTest, Empty) {
|
|
MakeEmptyBodyFunction("foo", ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetMultisampledTextureResourceBindings("ep");
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
ASSERT_EQ(1u, result.size());
|
|
|
|
EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture,
|
|
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{
|
|
ast::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::SampledKind::kFloat},
|
|
GetMultisampledTextureTestParams{
|
|
ast::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::SampledKind::kSInt},
|
|
GetMultisampledTextureTestParams{
|
|
ast::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::SampledKind::kUInt}));
|
|
|
|
TEST_F(InspectorGetStorageTextureResourceBindingsTest, Empty) {
|
|
MakeEmptyBodyFunction("ep", ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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();
|
|
|
|
ast::TextureDimension dim;
|
|
ResourceBinding::TextureDimension expected_dim;
|
|
std::tie(dim, expected_dim) = dim_params;
|
|
|
|
ast::ImageFormat format;
|
|
ResourceBinding::ImageFormat expected_format;
|
|
ResourceBinding::SampledKind expected_kind;
|
|
std::tie(format, expected_format, expected_kind) = format_params;
|
|
|
|
auto* st_type = MakeStorageTextureTypes(dim, format, read_only);
|
|
AddStorageTexture("st_var", st_type, 0, 0);
|
|
|
|
ast::Type* dim_type = nullptr;
|
|
switch (dim) {
|
|
case ast::TextureDimension::k1d:
|
|
dim_type = ty.i32();
|
|
break;
|
|
case ast::TextureDimension::k2d:
|
|
case ast::TextureDimension::k2dArray:
|
|
dim_type = ty.vec2<i32>();
|
|
break;
|
|
case ast::TextureDimension::k3d:
|
|
dim_type = ty.vec3<i32>();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ASSERT_FALSE(dim_type == nullptr);
|
|
|
|
MakeStorageTextureBodyFunction(
|
|
"ep", "st_var", dim_type,
|
|
ast::DecorationList{Stage(ast::PipelineStage::kFragment)});
|
|
|
|
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(ast::TextureDimension::k1d,
|
|
ResourceBinding::TextureDimension::k1d),
|
|
std::make_tuple(ast::TextureDimension::k2d,
|
|
ResourceBinding::TextureDimension::k2d),
|
|
std::make_tuple(ast::TextureDimension::k2dArray,
|
|
ResourceBinding::TextureDimension::k2dArray),
|
|
std::make_tuple(ast::TextureDimension::k3d,
|
|
ResourceBinding::TextureDimension::k3d)),
|
|
testing::Values(
|
|
std::make_tuple(ast::ImageFormat::kR32Float,
|
|
ResourceBinding::ImageFormat::kR32Float,
|
|
ResourceBinding::SampledKind::kFloat),
|
|
std::make_tuple(ast::ImageFormat::kR32Sint,
|
|
ResourceBinding::ImageFormat::kR32Sint,
|
|
ResourceBinding::SampledKind::kSInt),
|
|
std::make_tuple(ast::ImageFormat::kR32Uint,
|
|
ResourceBinding::ImageFormat::kR32Uint,
|
|
ResourceBinding::SampledKind::kUInt),
|
|
std::make_tuple(ast::ImageFormat::kRg32Float,
|
|
ResourceBinding::ImageFormat::kRg32Float,
|
|
ResourceBinding::SampledKind::kFloat),
|
|
std::make_tuple(ast::ImageFormat::kRg32Sint,
|
|
ResourceBinding::ImageFormat::kRg32Sint,
|
|
ResourceBinding::SampledKind::kSInt),
|
|
std::make_tuple(ast::ImageFormat::kRg32Uint,
|
|
ResourceBinding::ImageFormat::kRg32Uint,
|
|
ResourceBinding::SampledKind::kUInt),
|
|
std::make_tuple(ast::ImageFormat::kRgba16Float,
|
|
ResourceBinding::ImageFormat::kRgba16Float,
|
|
ResourceBinding::SampledKind::kFloat),
|
|
std::make_tuple(ast::ImageFormat::kRgba16Sint,
|
|
ResourceBinding::ImageFormat::kRgba16Sint,
|
|
ResourceBinding::SampledKind::kSInt),
|
|
std::make_tuple(ast::ImageFormat::kRgba16Uint,
|
|
ResourceBinding::ImageFormat::kRgba16Uint,
|
|
ResourceBinding::SampledKind::kUInt),
|
|
std::make_tuple(ast::ImageFormat::kRgba32Float,
|
|
ResourceBinding::ImageFormat::kRgba32Float,
|
|
ResourceBinding::SampledKind::kFloat),
|
|
std::make_tuple(ast::ImageFormat::kRgba32Sint,
|
|
ResourceBinding::ImageFormat::kRgba32Sint,
|
|
ResourceBinding::SampledKind::kSInt),
|
|
std::make_tuple(ast::ImageFormat::kRgba32Uint,
|
|
ResourceBinding::ImageFormat::kRgba32Uint,
|
|
ResourceBinding::SampledKind::kUInt),
|
|
std::make_tuple(ast::ImageFormat::kRgba8Sint,
|
|
ResourceBinding::ImageFormat::kRgba8Sint,
|
|
ResourceBinding::SampledKind::kSInt),
|
|
std::make_tuple(ast::ImageFormat::kRgba8Snorm,
|
|
ResourceBinding::ImageFormat::kRgba8Snorm,
|
|
ResourceBinding::SampledKind::kFloat),
|
|
std::make_tuple(ast::ImageFormat::kRgba8Uint,
|
|
ResourceBinding::ImageFormat::kRgba8Uint,
|
|
ResourceBinding::SampledKind::kUInt),
|
|
std::make_tuple(ast::ImageFormat::kRgba8Unorm,
|
|
ResourceBinding::ImageFormat::kRgba8Unorm,
|
|
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{
|
|
Ignore(Call("textureDimensions", "dt", "dt_level")),
|
|
},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
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{
|
|
ast::TextureDimension::k2d,
|
|
inspector::ResourceBinding::TextureDimension::k2d},
|
|
GetDepthTextureTestParams{
|
|
ast::TextureDimension::k2dArray,
|
|
inspector::ResourceBinding::TextureDimension::k2dArray},
|
|
GetDepthTextureTestParams{
|
|
ast::TextureDimension::kCube,
|
|
inspector::ResourceBinding::TextureDimension::kCube},
|
|
GetDepthTextureTestParams{
|
|
ast::TextureDimension::kCubeArray,
|
|
inspector::ResourceBinding::TextureDimension::kCubeArray}));
|
|
|
|
TEST_F(InspectorGetExternalTextureResourceBindingsTest, Simple) {
|
|
auto* external_texture_type = MakeExternalTextureType();
|
|
AddExternalTexture("et", external_texture_type, 0, 0);
|
|
|
|
Func("ep", ast::VariableList(), ty.void_(),
|
|
ast::StatementList{
|
|
Ignore(Call("textureDimensions", "et")),
|
|
},
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetExternalTextureResourceBindings("ep");
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
EXPECT_EQ(ResourceBinding::ResourceType::kExternalTexture,
|
|
result[0].resource_type);
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
EXPECT_EQ(0u, result[0].bind_group);
|
|
EXPECT_EQ(0u, result[0].binding);
|
|
}
|
|
|
|
TEST_F(InspectorGetSamplerTextureUsesTest, None) {
|
|
MakeEmptyBodyFunction("ep_func", ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetSamplerTextureUses("ep_func");
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
ASSERT_EQ(0u, result.size());
|
|
}
|
|
|
|
TEST_F(InspectorGetSamplerTextureUsesTest, Simple) {
|
|
auto* sampled_texture_type =
|
|
MakeSampledTextureType(ast::TextureDimension::k1d, ty.f32());
|
|
AddSampledTexture("foo_texture", sampled_texture_type, 0, 10);
|
|
AddSampler("foo_sampler", 0, 1);
|
|
AddGlobalVariable("foo_coords", ty.f32());
|
|
|
|
MakeSamplerReferenceBodyFunction("ep_func", "foo_texture", "foo_sampler",
|
|
"foo_coords", ty.f32(),
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetSamplerTextureUses("ep_func");
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
|
|
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
|
|
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
|
|
EXPECT_EQ(0u, result[0].texture_binding_point.group);
|
|
EXPECT_EQ(10u, result[0].texture_binding_point.binding);
|
|
}
|
|
|
|
TEST_F(InspectorGetSamplerTextureUsesTest, MultipleCalls) {
|
|
auto* sampled_texture_type =
|
|
MakeSampledTextureType(ast::TextureDimension::k1d, ty.f32());
|
|
AddSampledTexture("foo_texture", sampled_texture_type, 0, 10);
|
|
AddSampler("foo_sampler", 0, 1);
|
|
AddGlobalVariable("foo_coords", ty.f32());
|
|
|
|
MakeSamplerReferenceBodyFunction("ep_func", "foo_texture", "foo_sampler",
|
|
"foo_coords", ty.f32(),
|
|
ast::DecorationList{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result_0 = inspector.GetSamplerTextureUses("ep_func");
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
auto result_1 = inspector.GetSamplerTextureUses("ep_func");
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
EXPECT_EQ(result_0, result_1);
|
|
}
|
|
|
|
TEST_F(InspectorGetSamplerTextureUsesTest, InFunction) {
|
|
auto* sampled_texture_type =
|
|
MakeSampledTextureType(ast::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{
|
|
Stage(ast::PipelineStage::kFragment),
|
|
});
|
|
|
|
Inspector& inspector = Build();
|
|
|
|
auto result = inspector.GetSamplerTextureUses("ep_func");
|
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
|
|
|
ASSERT_EQ(1u, result.size());
|
|
EXPECT_EQ(0u, result[0].sampler_binding_point.group);
|
|
EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
|
|
EXPECT_EQ(0u, result[0].texture_binding_point.group);
|
|
EXPECT_EQ(0u, result[0].texture_binding_point.binding);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace inspector
|
|
} // namespace tint
|