[inspector] Extract UBO information
Also includes adding in sizing information for various types. BUG=tint:257 Change-Id: Iaaa8a7c28851d14790285b5bd14636bf3ae2b9b0 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/30704 Commit-Queue: Ryan Harrison <rharrison@chromium.org> Commit-Queue: dan sinclair <dsinclair@chromium.org> Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
8f7c80347d
commit
88d705dc85
|
@ -35,6 +35,10 @@ std::string AliasType::type_name() const {
|
||||||
return "__alias_" + name_ + subtype_->type_name();
|
return "__alias_" + name_ + subtype_->type_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t AliasType::MinBufferBindingSize() const {
|
||||||
|
return subtype_->MinBufferBindingSize();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace tint {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
namespace type {
|
namespace type {
|
||||||
|
|
||||||
/// A type alias type. Holds a name a pointer to another type.
|
/// A type alias type. Holds a name and pointer to another type.
|
||||||
class AliasType : public Type {
|
class AliasType : public Type {
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
@ -45,6 +45,10 @@ class AliasType : public Type {
|
||||||
/// @returns the name for this type
|
/// @returns the name for this type
|
||||||
std::string type_name() const override;
|
std::string type_name() const override;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
Type* subtype_ = nullptr;
|
Type* subtype_ = nullptr;
|
||||||
|
|
|
@ -33,6 +33,18 @@ bool ArrayType::IsArray() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t ArrayType::MinBufferBindingSize() const {
|
||||||
|
if (IsRuntimeArray()) {
|
||||||
|
return array_stride();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_array_stride()) {
|
||||||
|
return size_ * array_stride();
|
||||||
|
}
|
||||||
|
|
||||||
|
return size_ * type()->MinBufferBindingSize();
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ArrayType::array_stride() const {
|
uint32_t ArrayType::array_stride() const {
|
||||||
for (const auto& deco : decos_) {
|
for (const auto& deco : decos_) {
|
||||||
if (deco->IsStride()) {
|
if (deco->IsStride()) {
|
||||||
|
|
|
@ -46,6 +46,10 @@ class ArrayType : public Type {
|
||||||
/// i.e. the size is determined at runtime
|
/// i.e. the size is determined at runtime
|
||||||
bool IsRuntimeArray() const { return size_ == 0; }
|
bool IsRuntimeArray() const { return size_ == 0; }
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
|
|
||||||
/// Sets the array decorations
|
/// Sets the array decorations
|
||||||
/// @param decos the decorations to set
|
/// @param decos the decorations to set
|
||||||
void set_decorations(ast::ArrayDecorationList decos) {
|
void set_decorations(ast::ArrayDecorationList decos) {
|
||||||
|
|
|
@ -30,6 +30,10 @@ std::string F32Type::type_name() const {
|
||||||
return "__f32";
|
return "__f32";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t F32Type::MinBufferBindingSize() const {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -37,6 +37,10 @@ class F32Type : public Type {
|
||||||
|
|
||||||
/// @returns the name for this type
|
/// @returns the name for this type
|
||||||
std::string type_name() const override;
|
std::string type_name() const override;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
|
|
|
@ -30,6 +30,10 @@ std::string I32Type::type_name() const {
|
||||||
return "__i32";
|
return "__i32";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t I32Type::MinBufferBindingSize() const {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -37,6 +37,10 @@ class I32Type : public Type {
|
||||||
|
|
||||||
/// @returns the name for this type
|
/// @returns the name for this type
|
||||||
std::string type_name() const override;
|
std::string type_name() const override;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
|
|
|
@ -28,6 +28,8 @@ MatrixType::MatrixType(Type* subtype, uint32_t rows, uint32_t columns)
|
||||||
assert(columns < 5);
|
assert(columns < 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MatrixType::~MatrixType() = default;
|
||||||
|
|
||||||
bool MatrixType::IsMatrix() const {
|
bool MatrixType::IsMatrix() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +39,9 @@ std::string MatrixType::type_name() const {
|
||||||
subtype_->type_name();
|
subtype_->type_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
MatrixType::~MatrixType() = default;
|
uint64_t MatrixType::MinBufferBindingSize() const {
|
||||||
|
return rows_ * columns_ * subtype_->MinBufferBindingSize();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
|
|
|
@ -48,6 +48,10 @@ class MatrixType : public Type {
|
||||||
/// @returns the name for this type
|
/// @returns the name for this type
|
||||||
std::string type_name() const override;
|
std::string type_name() const override;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type* subtype_ = nullptr;
|
Type* subtype_ = nullptr;
|
||||||
uint32_t rows_ = 2;
|
uint32_t rows_ = 2;
|
||||||
|
|
|
@ -25,6 +25,10 @@ bool PointerType::IsPointer() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t PointerType::MinBufferBindingSize() const {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
std::string PointerType::type_name() const {
|
std::string PointerType::type_name() const {
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "__ptr_" << storage_class_ << subtype_->type_name();
|
out << "__ptr_" << storage_class_ << subtype_->type_name();
|
||||||
|
|
|
@ -39,6 +39,10 @@ class PointerType : public Type {
|
||||||
/// @returns true if the type is a pointer type
|
/// @returns true if the type is a pointer type
|
||||||
bool IsPointer() const override;
|
bool IsPointer() const override;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
|
|
||||||
/// @returns the pointee type
|
/// @returns the pointee type
|
||||||
Type* type() const { return subtype_; }
|
Type* type() const { return subtype_; }
|
||||||
/// @returns the storage class of the pointer
|
/// @returns the storage class of the pointer
|
||||||
|
|
|
@ -25,6 +25,8 @@ StructType::StructType(const std::string& name, std::unique_ptr<Struct> impl)
|
||||||
|
|
||||||
StructType::StructType(StructType&&) = default;
|
StructType::StructType(StructType&&) = default;
|
||||||
|
|
||||||
|
StructType::~StructType() = default;
|
||||||
|
|
||||||
bool StructType::IsStruct() const {
|
bool StructType::IsStruct() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +35,21 @@ std::string StructType::type_name() const {
|
||||||
return "__struct_" + name_;
|
return "__struct_" + name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
StructType::~StructType() = default;
|
uint64_t StructType::MinBufferBindingSize() const {
|
||||||
|
if (!struct_->members().size()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& last_member = struct_->members().back();
|
||||||
|
|
||||||
|
// If there is no offset, then this is not a host-shareable struct, returning
|
||||||
|
// 0 indicates this to the caller.
|
||||||
|
if (!last_member->has_offset_decoration()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return last_member->offset() + last_member->type()->MinBufferBindingSize();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
|
|
|
@ -48,9 +48,13 @@ class StructType : public Type {
|
||||||
/// @returns the struct name
|
/// @returns the struct name
|
||||||
Struct* impl() const { return struct_.get(); }
|
Struct* impl() const { return struct_.get(); }
|
||||||
|
|
||||||
/// @returns the name for th type
|
/// @returns the name for the type
|
||||||
std::string type_name() const override;
|
std::string type_name() const override;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::unique_ptr<Struct> struct_;
|
std::unique_ptr<Struct> struct_;
|
||||||
|
|
|
@ -109,6 +109,10 @@ bool Type::IsVoid() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Type::MinBufferBindingSize() const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool Type::is_scalar() {
|
bool Type::is_scalar() {
|
||||||
return is_float_scalar() || is_integer_scalar() || IsBool();
|
return is_float_scalar() || is_integer_scalar() || IsBool();
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,10 @@ class Type {
|
||||||
/// @returns the name for this type. The |type_name| is unique over all types.
|
/// @returns the name for this type. The |type_name| is unique over all types.
|
||||||
virtual std::string type_name() const = 0;
|
virtual std::string type_name() const = 0;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
virtual uint64_t MinBufferBindingSize() const;
|
||||||
|
|
||||||
/// @returns the pointee type if this is a pointer, |this| otherwise
|
/// @returns the pointee type if this is a pointer, |this| otherwise
|
||||||
Type* UnwrapPtrIfNeeded();
|
Type* UnwrapPtrIfNeeded();
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,10 @@ std::string U32Type::type_name() const {
|
||||||
return "__u32";
|
return "__u32";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t U32Type::MinBufferBindingSize() const {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -37,6 +37,10 @@ class U32Type : public Type {
|
||||||
|
|
||||||
/// @returns the name for th type
|
/// @returns the name for th type
|
||||||
std::string type_name() const override;
|
std::string type_name() const override;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
|
|
|
@ -38,6 +38,10 @@ std::string VectorType::type_name() const {
|
||||||
return "__vec_" + std::to_string(size_) + subtype_->type_name();
|
return "__vec_" + std::to_string(size_) + subtype_->type_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t VectorType::MinBufferBindingSize() const {
|
||||||
|
return size_ * subtype_->MinBufferBindingSize();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -45,6 +45,10 @@ class VectorType : public Type {
|
||||||
/// @returns the name for th type
|
/// @returns the name for th type
|
||||||
std::string type_name() const override;
|
std::string type_name() const override;
|
||||||
|
|
||||||
|
/// @returns minimum size required for this type, in bytes.
|
||||||
|
/// 0 for non-host shareable types.
|
||||||
|
uint64_t MinBufferBindingSize() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type* subtype_ = nullptr;
|
Type* subtype_ = nullptr;
|
||||||
uint32_t size_ = 2;
|
uint32_t size_ = 2;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "src/ast/null_literal.h"
|
#include "src/ast/null_literal.h"
|
||||||
#include "src/ast/scalar_constructor_expression.h"
|
#include "src/ast/scalar_constructor_expression.h"
|
||||||
#include "src/ast/sint_literal.h"
|
#include "src/ast/sint_literal.h"
|
||||||
|
#include "src/ast/type/struct_type.h"
|
||||||
#include "src/ast/uint_literal.h"
|
#include "src/ast/uint_literal.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -134,5 +135,43 @@ std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
|
||||||
|
const std::string& entry_point) {
|
||||||
|
auto* func = module_.FindFunctionByName(entry_point);
|
||||||
|
if (!func) {
|
||||||
|
error_ += entry_point + " was not found!";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!func->IsEntryPoint()) {
|
||||||
|
error_ += entry_point + " is not an entry point!";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ResourceBinding> result;
|
||||||
|
|
||||||
|
for (auto& ruv : func->referenced_uniform_variables()) {
|
||||||
|
ResourceBinding entry;
|
||||||
|
ast::Variable* var = nullptr;
|
||||||
|
ast::Function::BindingInfo binding_info;
|
||||||
|
std::tie(var, binding_info) = ruv;
|
||||||
|
if (!var->type()->IsStruct()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!var->type()->AsStruct()->IsBlockDecorated()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.bind_group = binding_info.set->value();
|
||||||
|
entry.binding = binding_info.binding->value();
|
||||||
|
entry.min_buffer_binding_size = var->type()->MinBufferBindingSize();
|
||||||
|
|
||||||
|
result.push_back(std::move(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace inspector
|
} // namespace inspector
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -29,6 +29,16 @@
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace inspector {
|
namespace inspector {
|
||||||
|
|
||||||
|
/// Container for information about how a resource is bound
|
||||||
|
struct ResourceBinding {
|
||||||
|
/// Bind group the binding belongs
|
||||||
|
uint32_t bind_group;
|
||||||
|
/// Identifier to identify this binding within the bind group
|
||||||
|
uint32_t binding;
|
||||||
|
/// Minimum size required for this binding, in bytes.
|
||||||
|
uint64_t min_buffer_binding_size;
|
||||||
|
};
|
||||||
|
|
||||||
/// Extracts information from a module
|
/// Extracts information from a module
|
||||||
class Inspector {
|
class Inspector {
|
||||||
public:
|
public:
|
||||||
|
@ -48,6 +58,11 @@ class Inspector {
|
||||||
/// @returns map of const_id to initial value
|
/// @returns map of const_id to initial value
|
||||||
std::map<uint32_t, Scalar> GetConstantIDs();
|
std::map<uint32_t, Scalar> GetConstantIDs();
|
||||||
|
|
||||||
|
/// @param entry_point name of the entry point to get information about.
|
||||||
|
/// @returns vector of all of the bindings for Uniform buffers.
|
||||||
|
std::vector<ResourceBinding> GetUniformBufferResourceBindings(
|
||||||
|
const std::string& entry_point);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ast::Module& module_;
|
const ast::Module& module_;
|
||||||
std::string error_;
|
std::string error_;
|
||||||
|
|
|
@ -24,17 +24,27 @@
|
||||||
#include "src/ast/float_literal.h"
|
#include "src/ast/float_literal.h"
|
||||||
#include "src/ast/function.h"
|
#include "src/ast/function.h"
|
||||||
#include "src/ast/identifier_expression.h"
|
#include "src/ast/identifier_expression.h"
|
||||||
|
#include "src/ast/member_accessor_expression.h"
|
||||||
#include "src/ast/null_literal.h"
|
#include "src/ast/null_literal.h"
|
||||||
#include "src/ast/pipeline_stage.h"
|
#include "src/ast/pipeline_stage.h"
|
||||||
#include "src/ast/return_statement.h"
|
#include "src/ast/return_statement.h"
|
||||||
#include "src/ast/scalar_constructor_expression.h"
|
#include "src/ast/scalar_constructor_expression.h"
|
||||||
#include "src/ast/sint_literal.h"
|
#include "src/ast/sint_literal.h"
|
||||||
#include "src/ast/stage_decoration.h"
|
#include "src/ast/stage_decoration.h"
|
||||||
|
#include "src/ast/struct_decoration.h"
|
||||||
|
#include "src/ast/struct_member.h"
|
||||||
|
#include "src/ast/struct_member_decoration.h"
|
||||||
|
#include "src/ast/struct_member_offset_decoration.h"
|
||||||
|
#include "src/ast/type/array_type.h"
|
||||||
#include "src/ast/type/bool_type.h"
|
#include "src/ast/type/bool_type.h"
|
||||||
#include "src/ast/type/f32_type.h"
|
#include "src/ast/type/f32_type.h"
|
||||||
#include "src/ast/type/i32_type.h"
|
#include "src/ast/type/i32_type.h"
|
||||||
|
#include "src/ast/type/matrix_type.h"
|
||||||
|
#include "src/ast/type/pointer_type.h"
|
||||||
|
#include "src/ast/type/struct_type.h"
|
||||||
#include "src/ast/type/type.h"
|
#include "src/ast/type/type.h"
|
||||||
#include "src/ast/type/u32_type.h"
|
#include "src/ast/type/u32_type.h"
|
||||||
|
#include "src/ast/type/vector_type.h"
|
||||||
#include "src/ast/type/void_type.h"
|
#include "src/ast/type/void_type.h"
|
||||||
#include "src/ast/uint_literal.h"
|
#include "src/ast/uint_literal.h"
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
|
@ -58,7 +68,7 @@ class InspectorHelper {
|
||||||
/// Generates an empty function
|
/// Generates an empty function
|
||||||
/// @param name name of the function created
|
/// @param name name of the function created
|
||||||
/// @returns a function object
|
/// @returns a function object
|
||||||
std::unique_ptr<ast::Function> GenerateEmptyBodyFunction(std::string name) {
|
std::unique_ptr<ast::Function> MakeEmptyBodyFunction(std::string name) {
|
||||||
auto body = std::make_unique<ast::BlockStatement>();
|
auto body = std::make_unique<ast::BlockStatement>();
|
||||||
body->append(std::make_unique<ast::ReturnStatement>());
|
body->append(std::make_unique<ast::ReturnStatement>());
|
||||||
std::unique_ptr<ast::Function> func =
|
std::unique_ptr<ast::Function> func =
|
||||||
|
@ -71,9 +81,8 @@ class InspectorHelper {
|
||||||
/// @param caller name of the function created
|
/// @param caller name of the function created
|
||||||
/// @param callee name of the function to be called
|
/// @param callee name of the function to be called
|
||||||
/// @returns a function object
|
/// @returns a function object
|
||||||
std::unique_ptr<ast::Function> GenerateCallerBodyFunction(
|
std::unique_ptr<ast::Function> MakeCallerBodyFunction(std::string caller,
|
||||||
std::string caller,
|
std::string callee) {
|
||||||
std::string callee) {
|
|
||||||
auto body = std::make_unique<ast::BlockStatement>();
|
auto body = std::make_unique<ast::BlockStatement>();
|
||||||
auto ident_expr = std::make_unique<ast::IdentifierExpression>(callee);
|
auto ident_expr = std::make_unique<ast::IdentifierExpression>(callee);
|
||||||
auto call_expr = std::make_unique<ast::CallExpression>(
|
auto call_expr = std::make_unique<ast::CallExpression>(
|
||||||
|
@ -89,7 +98,7 @@ class InspectorHelper {
|
||||||
/// Add In/Out variables to the global variables
|
/// Add In/Out variables to the global variables
|
||||||
/// @param inout_vars tuples of {in, out} that will be added as entries to the
|
/// @param inout_vars tuples of {in, out} that will be added as entries to the
|
||||||
/// global variables
|
/// global variables
|
||||||
void CreateInOutVariables(
|
void AddInOutVariables(
|
||||||
std::vector<std::tuple<std::string, std::string>> inout_vars) {
|
std::vector<std::tuple<std::string, std::string>> inout_vars) {
|
||||||
for (auto inout : inout_vars) {
|
for (auto inout : inout_vars) {
|
||||||
std::string in, out;
|
std::string in, out;
|
||||||
|
@ -108,7 +117,7 @@ class InspectorHelper {
|
||||||
/// @param inout_vars tuples of {in, out} that will be converted into out = in
|
/// @param inout_vars tuples of {in, out} that will be converted into out = in
|
||||||
/// calls in the function body
|
/// calls in the function body
|
||||||
/// @returns a function object
|
/// @returns a function object
|
||||||
std::unique_ptr<ast::Function> GenerateInOutVariableBodyFunction(
|
std::unique_ptr<ast::Function> MakeInOutVariableBodyFunction(
|
||||||
std::string name,
|
std::string name,
|
||||||
std::vector<std::tuple<std::string, std::string>> inout_vars) {
|
std::vector<std::tuple<std::string, std::string>> inout_vars) {
|
||||||
auto body = std::make_unique<ast::BlockStatement>();
|
auto body = std::make_unique<ast::BlockStatement>();
|
||||||
|
@ -133,7 +142,7 @@ class InspectorHelper {
|
||||||
/// @param inout_vars tuples of {in, out} that will be converted into out = in
|
/// @param inout_vars tuples of {in, out} that will be converted into out = in
|
||||||
/// calls in the function body
|
/// calls in the function body
|
||||||
/// @returns a function object
|
/// @returns a function object
|
||||||
std::unique_ptr<ast::Function> GenerateInOutVariableCallerBodyFunction(
|
std::unique_ptr<ast::Function> MakeInOutVariableCallerBodyFunction(
|
||||||
std::string caller,
|
std::string caller,
|
||||||
std::string callee,
|
std::string callee,
|
||||||
std::vector<std::tuple<std::string, std::string>> inout_vars) {
|
std::vector<std::tuple<std::string, std::string>> inout_vars) {
|
||||||
|
@ -163,10 +172,10 @@ class InspectorHelper {
|
||||||
/// @param val value to initialize the variable with, if NULL no initializer
|
/// @param val value to initialize the variable with, if NULL no initializer
|
||||||
/// will be added.
|
/// will be added.
|
||||||
template <class T>
|
template <class T>
|
||||||
void CreateConstantID(std::string name,
|
void AddConstantID(std::string name,
|
||||||
uint32_t id,
|
uint32_t id,
|
||||||
ast::type::Type* type,
|
ast::type::Type* type,
|
||||||
T* val) {
|
T* val) {
|
||||||
auto dvar = std::make_unique<ast::DecoratedVariable>(
|
auto dvar = std::make_unique<ast::DecoratedVariable>(
|
||||||
std::make_unique<ast::Variable>(name, ast::StorageClass::kNone, type));
|
std::make_unique<ast::Variable>(name, ast::StorageClass::kNone, type));
|
||||||
dvar->set_is_const(true);
|
dvar->set_is_const(true);
|
||||||
|
@ -180,35 +189,53 @@ class InspectorHelper {
|
||||||
mod()->AddGlobalVariable(std::move(dvar));
|
mod()->AddGlobalVariable(std::move(dvar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates an ast::Literal for the given value
|
||||||
|
/// @tparam T C++ type of the literal, must agree with type
|
||||||
|
/// @returns a Literal of the expected type and value
|
||||||
template <class T>
|
template <class T>
|
||||||
std::unique_ptr<ast::Literal> MakeLiteral(ast::type::Type*, T*) {
|
std::unique_ptr<ast::Literal> MakeLiteral(ast::type::Type*, T*) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @param type AST type of the literal, must resolve to BoolLiteral
|
||||||
|
/// @param val scalar value for the literal to contain
|
||||||
|
/// @returns a Literal of the expected type and value
|
||||||
template <>
|
template <>
|
||||||
std::unique_ptr<ast::Literal> MakeLiteral<bool>(ast::type::Type* type,
|
std::unique_ptr<ast::Literal> MakeLiteral<bool>(ast::type::Type* type,
|
||||||
bool* val) {
|
bool* val) {
|
||||||
return std::make_unique<ast::BoolLiteral>(type, *val);
|
return std::make_unique<ast::BoolLiteral>(type, *val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @param type AST type of the literal, must resolve to UIntLiteral
|
||||||
|
/// @param val scalar value for the literal to contain
|
||||||
|
/// @returns a Literal of the expected type and value
|
||||||
template <>
|
template <>
|
||||||
std::unique_ptr<ast::Literal> MakeLiteral<uint32_t>(ast::type::Type* type,
|
std::unique_ptr<ast::Literal> MakeLiteral<uint32_t>(ast::type::Type* type,
|
||||||
uint32_t* val) {
|
uint32_t* val) {
|
||||||
return std::make_unique<ast::UintLiteral>(type, *val);
|
return std::make_unique<ast::UintLiteral>(type, *val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @param type AST type of the literal, must resolve to IntLiteral
|
||||||
|
/// @param val scalar value for the literal to contain
|
||||||
|
/// @returns a Literal of the expected type and value
|
||||||
template <>
|
template <>
|
||||||
std::unique_ptr<ast::Literal> MakeLiteral<int32_t>(ast::type::Type* type,
|
std::unique_ptr<ast::Literal> MakeLiteral<int32_t>(ast::type::Type* type,
|
||||||
int32_t* val) {
|
int32_t* val) {
|
||||||
return std::make_unique<ast::SintLiteral>(type, *val);
|
return std::make_unique<ast::SintLiteral>(type, *val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @param type AST type of the literal, must resolve to FloattLiteral
|
||||||
|
/// @param val scalar value for the literal to contain
|
||||||
|
/// @returns a Literal of the expected type and value
|
||||||
template <>
|
template <>
|
||||||
std::unique_ptr<ast::Literal> MakeLiteral<float>(ast::type::Type* type,
|
std::unique_ptr<ast::Literal> MakeLiteral<float>(ast::type::Type* type,
|
||||||
float* val) {
|
float* val) {
|
||||||
return std::make_unique<ast::FloatLiteral>(type, *val);
|
return std::make_unique<ast::FloatLiteral>(type, *val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @param vec Vector of strings to be searched
|
||||||
|
/// @param str String to be searching for
|
||||||
|
/// @returns true if str is in vec, otherwise false
|
||||||
bool ContainsString(const std::vector<std::string>& vec,
|
bool ContainsString(const std::vector<std::string>& vec,
|
||||||
const std::string& str) {
|
const std::string& str) {
|
||||||
for (auto& s : vec) {
|
for (auto& s : vec) {
|
||||||
|
@ -219,6 +246,105 @@ class InspectorHelper {
|
||||||
return false;
|
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* type) {
|
||||||
|
return std::to_string(idx) + type->type_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a struct type appropriate for using in a UBO
|
||||||
|
/// @param name name for the type
|
||||||
|
/// @param members_info a vector of {type, offset} where each entry is the
|
||||||
|
/// type and offset of a member of the struct
|
||||||
|
/// @returns a struct type suitable to use for a UBO
|
||||||
|
std::unique_ptr<ast::type::StructType> MakeUBOStructType(
|
||||||
|
const std::string& name,
|
||||||
|
std::vector<std::tuple<ast::type::Type*, uint32_t>> members_info) {
|
||||||
|
ast::StructMemberList members;
|
||||||
|
for (auto& member_info : members_info) {
|
||||||
|
ast::type::Type* type;
|
||||||
|
uint32_t offset;
|
||||||
|
std::tie(type, offset) = member_info;
|
||||||
|
|
||||||
|
ast::StructMemberDecorationList deco;
|
||||||
|
deco.push_back(
|
||||||
|
std::make_unique<ast::StructMemberOffsetDecoration>(offset));
|
||||||
|
|
||||||
|
members.push_back(std::make_unique<ast::StructMember>(
|
||||||
|
StructMemberName(members.size(), type), type, std::move(deco)));
|
||||||
|
}
|
||||||
|
ast::StructDecorationList decos;
|
||||||
|
decos.push_back(ast::StructDecoration::kBlock);
|
||||||
|
|
||||||
|
auto str =
|
||||||
|
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
|
||||||
|
|
||||||
|
return std::make_unique<ast::type::StructType>(name, std::move(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a UBO variable to the module
|
||||||
|
/// @param name the name of the variable
|
||||||
|
/// @param struct_type the type to use
|
||||||
|
/// @param set the binding group/set to use for the UBO
|
||||||
|
/// @param binding the binding number to use for the UBO
|
||||||
|
void AddUBO(const std::string& name,
|
||||||
|
ast::type::StructType* struct_type,
|
||||||
|
uint32_t set,
|
||||||
|
uint32_t binding) {
|
||||||
|
auto var = std::make_unique<ast::DecoratedVariable>(
|
||||||
|
std::make_unique<ast::Variable>(name, ast::StorageClass::kUniform,
|
||||||
|
struct_type));
|
||||||
|
ast::VariableDecorationList decorations;
|
||||||
|
|
||||||
|
decorations.push_back(std::make_unique<ast::BindingDecoration>(binding));
|
||||||
|
decorations.push_back(std::make_unique<ast::SetDecoration>(set));
|
||||||
|
var->set_decorations(std::move(decorations));
|
||||||
|
|
||||||
|
mod()->AddGlobalVariable(std::move(var));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a function that references a specific UBO
|
||||||
|
/// @param func_name name of the function created
|
||||||
|
/// @param ubo_name name of the UBO to be accessed
|
||||||
|
/// @param member_idx index of the member to access
|
||||||
|
/// @returns a function that references all of the UBO members specified
|
||||||
|
std::unique_ptr<ast::Function> MakeUBOReferenceBodyFunction(
|
||||||
|
std::string func_name,
|
||||||
|
std::string ubo_name,
|
||||||
|
std::vector<std::tuple<size_t, ast::type::Type*>> members) {
|
||||||
|
auto body = std::make_unique<ast::BlockStatement>();
|
||||||
|
|
||||||
|
for (auto member : members) {
|
||||||
|
size_t member_idx;
|
||||||
|
ast::type::Type* member_type;
|
||||||
|
std::tie(member_idx, member_type) = member;
|
||||||
|
std::string member_name = StructMemberName(member_idx, member_type);
|
||||||
|
body->append(std::make_unique<ast::VariableDeclStatement>(
|
||||||
|
std::make_unique<ast::Variable>(
|
||||||
|
"local" + member_name, ast::StorageClass::kNone, member_type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto member : members) {
|
||||||
|
size_t member_idx;
|
||||||
|
ast::type::Type* member_type;
|
||||||
|
std::tie(member_idx, member_type) = member;
|
||||||
|
std::string member_name = StructMemberName(member_idx, member_type);
|
||||||
|
body->append(std::make_unique<ast::AssignmentStatement>(
|
||||||
|
std::make_unique<ast::IdentifierExpression>("local" + member_name),
|
||||||
|
std::make_unique<ast::MemberAccessorExpression>(
|
||||||
|
std::make_unique<ast::IdentifierExpression>(ubo_name),
|
||||||
|
std::make_unique<ast::IdentifierExpression>(member_name))));
|
||||||
|
}
|
||||||
|
|
||||||
|
body->append(std::make_unique<ast::ReturnStatement>());
|
||||||
|
auto func = std::make_unique<ast::Function>(func_name, ast::VariableList(),
|
||||||
|
void_type());
|
||||||
|
func->set_body(std::move(body));
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
ast::Module* mod() { return &mod_; }
|
ast::Module* mod() { return &mod_; }
|
||||||
TypeDeterminer* td() { return td_.get(); }
|
TypeDeterminer* td() { return td_.get(); }
|
||||||
Inspector* inspector() { return inspector_.get(); }
|
Inspector* inspector() { return inspector_.get(); }
|
||||||
|
@ -227,6 +353,14 @@ class InspectorHelper {
|
||||||
ast::type::F32Type* f32_type() { return &f32_type_; }
|
ast::type::F32Type* f32_type() { return &f32_type_; }
|
||||||
ast::type::I32Type* i32_type() { return &i32_type_; }
|
ast::type::I32Type* i32_type() { return &i32_type_; }
|
||||||
ast::type::U32Type* u32_type() { return &u32_type_; }
|
ast::type::U32Type* u32_type() { return &u32_type_; }
|
||||||
|
ast::type::ArrayType* u32_array_type(uint32_t count) {
|
||||||
|
static std::map<uint32_t, std::unique_ptr<ast::type::ArrayType>> memo;
|
||||||
|
if (memo.find(count) == memo.end()) {
|
||||||
|
memo[count] = std::make_unique<ast::type::ArrayType>(u32_type(), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return memo[count].get();
|
||||||
|
}
|
||||||
ast::type::VoidType* void_type() { return &void_type_; }
|
ast::type::VoidType* void_type() { return &void_type_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -245,6 +379,8 @@ class InspectorHelper {
|
||||||
class InspectorTest : public InspectorHelper, public testing::Test {};
|
class InspectorTest : public InspectorHelper, public testing::Test {};
|
||||||
|
|
||||||
class InspectorGetEntryPointTest : public InspectorTest {};
|
class InspectorGetEntryPointTest : public InspectorTest {};
|
||||||
|
class InspectorGetConstantIDsTest : public InspectorTest {};
|
||||||
|
class InspectorGetUniformBufferResourceBindings : public InspectorTest {};
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, NoFunctions) {
|
TEST_F(InspectorGetEntryPointTest, NoFunctions) {
|
||||||
auto result = inspector()->GetEntryPoints();
|
auto result = inspector()->GetEntryPoints();
|
||||||
|
@ -254,7 +390,7 @@ TEST_F(InspectorGetEntryPointTest, NoFunctions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
|
TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
|
||||||
mod()->AddFunction(GenerateEmptyBodyFunction("foo"));
|
mod()->AddFunction(MakeEmptyBodyFunction("foo"));
|
||||||
|
|
||||||
auto result = inspector()->GetEntryPoints();
|
auto result = inspector()->GetEntryPoints();
|
||||||
ASSERT_FALSE(inspector()->has_error());
|
ASSERT_FALSE(inspector()->has_error());
|
||||||
|
@ -263,7 +399,7 @@ TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
|
TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
|
||||||
auto foo = GenerateEmptyBodyFunction("foo");
|
auto foo = MakeEmptyBodyFunction("foo");
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
@ -277,12 +413,12 @@ TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
|
TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
|
||||||
auto foo = GenerateEmptyBodyFunction("foo");
|
auto foo = MakeEmptyBodyFunction("foo");
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
|
||||||
auto bar = GenerateEmptyBodyFunction("bar");
|
auto bar = MakeEmptyBodyFunction("bar");
|
||||||
bar->add_decoration(
|
bar->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kCompute));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kCompute));
|
||||||
mod()->AddFunction(std::move(bar));
|
mod()->AddFunction(std::move(bar));
|
||||||
|
@ -298,15 +434,15 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
|
TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
|
||||||
auto func = GenerateEmptyBodyFunction("func");
|
auto func = MakeEmptyBodyFunction("func");
|
||||||
mod()->AddFunction(std::move(func));
|
mod()->AddFunction(std::move(func));
|
||||||
|
|
||||||
auto foo = GenerateCallerBodyFunction("foo", "func");
|
auto foo = MakeCallerBodyFunction("foo", "func");
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
|
||||||
auto bar = GenerateCallerBodyFunction("bar", "func");
|
auto bar = MakeCallerBodyFunction("bar", "func");
|
||||||
bar->add_decoration(
|
bar->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kFragment));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kFragment));
|
||||||
mod()->AddFunction(std::move(bar));
|
mod()->AddFunction(std::move(bar));
|
||||||
|
@ -322,7 +458,7 @@ TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
|
TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
|
||||||
auto foo = GenerateCallerBodyFunction("foo", "func");
|
auto foo = MakeCallerBodyFunction("foo", "func");
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
@ -339,7 +475,7 @@ TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
|
TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
|
||||||
auto foo = GenerateEmptyBodyFunction("foo");
|
auto foo = MakeEmptyBodyFunction("foo");
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kCompute));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kCompute));
|
||||||
foo->add_decoration(std::make_unique<ast::WorkgroupDecoration>(8u, 2u, 1u));
|
foo->add_decoration(std::make_unique<ast::WorkgroupDecoration>(8u, 2u, 1u));
|
||||||
|
@ -357,10 +493,10 @@ TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
|
TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
|
||||||
auto func = GenerateEmptyBodyFunction("func");
|
auto func = MakeEmptyBodyFunction("func");
|
||||||
mod()->AddFunction(std::move(func));
|
mod()->AddFunction(std::move(func));
|
||||||
|
|
||||||
auto foo = GenerateCallerBodyFunction("foo", "func");
|
auto foo = MakeCallerBodyFunction("foo", "func");
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
@ -374,9 +510,9 @@ TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, EntryPointInOutVariables) {
|
TEST_F(InspectorGetEntryPointTest, EntryPointInOutVariables) {
|
||||||
CreateInOutVariables({{"in_var", "out_var"}});
|
AddInOutVariables({{"in_var", "out_var"}});
|
||||||
|
|
||||||
auto foo = GenerateInOutVariableBodyFunction("foo", {{"in_var", "out_var"}});
|
auto foo = MakeInOutVariableBodyFunction("foo", {{"in_var", "out_var"}});
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
@ -395,13 +531,12 @@ TEST_F(InspectorGetEntryPointTest, EntryPointInOutVariables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, FunctionInOutVariables) {
|
TEST_F(InspectorGetEntryPointTest, FunctionInOutVariables) {
|
||||||
CreateInOutVariables({{"in_var", "out_var"}});
|
AddInOutVariables({{"in_var", "out_var"}});
|
||||||
|
|
||||||
auto func =
|
auto func = MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}});
|
||||||
GenerateInOutVariableBodyFunction("func", {{"in_var", "out_var"}});
|
|
||||||
mod()->AddFunction(std::move(func));
|
mod()->AddFunction(std::move(func));
|
||||||
|
|
||||||
auto foo = GenerateCallerBodyFunction("foo", "func");
|
auto foo = MakeCallerBodyFunction("foo", "func");
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
@ -420,14 +555,13 @@ TEST_F(InspectorGetEntryPointTest, FunctionInOutVariables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, RepeatedInOutVariables) {
|
TEST_F(InspectorGetEntryPointTest, RepeatedInOutVariables) {
|
||||||
CreateInOutVariables({{"in_var", "out_var"}});
|
AddInOutVariables({{"in_var", "out_var"}});
|
||||||
|
|
||||||
auto func =
|
auto func = MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}});
|
||||||
GenerateInOutVariableBodyFunction("func", {{"in_var", "out_var"}});
|
|
||||||
mod()->AddFunction(std::move(func));
|
mod()->AddFunction(std::move(func));
|
||||||
|
|
||||||
auto foo = GenerateInOutVariableCallerBodyFunction("foo", "func",
|
auto foo = MakeInOutVariableCallerBodyFunction("foo", "func",
|
||||||
{{"in_var", "out_var"}});
|
{{"in_var", "out_var"}});
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
@ -446,9 +580,9 @@ TEST_F(InspectorGetEntryPointTest, RepeatedInOutVariables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, EntryPointMultipleInOutVariables) {
|
TEST_F(InspectorGetEntryPointTest, EntryPointMultipleInOutVariables) {
|
||||||
CreateInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
||||||
|
|
||||||
auto foo = GenerateInOutVariableBodyFunction(
|
auto foo = MakeInOutVariableBodyFunction(
|
||||||
"foo", {{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
"foo", {{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
|
@ -470,13 +604,13 @@ TEST_F(InspectorGetEntryPointTest, EntryPointMultipleInOutVariables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, FunctionMultipleInOutVariables) {
|
TEST_F(InspectorGetEntryPointTest, FunctionMultipleInOutVariables) {
|
||||||
CreateInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
||||||
|
|
||||||
auto func = GenerateInOutVariableBodyFunction(
|
auto func = MakeInOutVariableBodyFunction(
|
||||||
"func", {{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
"func", {{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
||||||
mod()->AddFunction(std::move(func));
|
mod()->AddFunction(std::move(func));
|
||||||
|
|
||||||
auto foo = GenerateCallerBodyFunction("foo", "func");
|
auto foo = MakeCallerBodyFunction("foo", "func");
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
@ -497,14 +631,14 @@ TEST_F(InspectorGetEntryPointTest, FunctionMultipleInOutVariables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
|
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
|
||||||
CreateInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
||||||
|
|
||||||
auto foo = GenerateInOutVariableBodyFunction("foo", {{"in_var", "out2_var"}});
|
auto foo = MakeInOutVariableBodyFunction("foo", {{"in_var", "out2_var"}});
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
|
||||||
auto bar = GenerateInOutVariableBodyFunction("bar", {{"in2_var", "out_var"}});
|
auto bar = MakeInOutVariableBodyFunction("bar", {{"in2_var", "out_var"}});
|
||||||
bar->add_decoration(
|
bar->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kCompute));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kCompute));
|
||||||
mod()->AddFunction(std::move(bar));
|
mod()->AddFunction(std::move(bar));
|
||||||
|
@ -530,19 +664,18 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsSharedInOutVariables) {
|
TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsSharedInOutVariables) {
|
||||||
CreateInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
|
||||||
|
|
||||||
auto func =
|
auto func = MakeInOutVariableBodyFunction("func", {{"in2_var", "out2_var"}});
|
||||||
GenerateInOutVariableBodyFunction("func", {{"in2_var", "out2_var"}});
|
|
||||||
mod()->AddFunction(std::move(func));
|
mod()->AddFunction(std::move(func));
|
||||||
|
|
||||||
auto foo = GenerateInOutVariableCallerBodyFunction("foo", "func",
|
auto foo = MakeInOutVariableCallerBodyFunction("foo", "func",
|
||||||
{{"in_var", "out_var"}});
|
{{"in_var", "out_var"}});
|
||||||
foo->add_decoration(
|
foo->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
mod()->AddFunction(std::move(foo));
|
mod()->AddFunction(std::move(foo));
|
||||||
|
|
||||||
auto bar = GenerateCallerBodyFunction("bar", "func");
|
auto bar = MakeCallerBodyFunction("bar", "func");
|
||||||
bar->add_decoration(
|
bar->add_decoration(
|
||||||
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kCompute));
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kCompute));
|
||||||
mod()->AddFunction(std::move(bar));
|
mod()->AddFunction(std::move(bar));
|
||||||
|
@ -569,12 +702,12 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsSharedInOutVariables) {
|
||||||
EXPECT_EQ("out2_var", result[1].output_variables[0]);
|
EXPECT_EQ("out2_var", result[1].output_variables[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, BoolConstantIDs) {
|
TEST_F(InspectorGetConstantIDsTest, Bool) {
|
||||||
bool val_true = true;
|
bool val_true = true;
|
||||||
bool val_false = false;
|
bool val_false = false;
|
||||||
CreateConstantID<bool>("foo", 1, bool_type(), nullptr);
|
AddConstantID<bool>("foo", 1, bool_type(), nullptr);
|
||||||
CreateConstantID<bool>("bar", 20, bool_type(), &val_true);
|
AddConstantID<bool>("bar", 20, bool_type(), &val_true);
|
||||||
CreateConstantID<bool>("baz", 300, bool_type(), &val_false);
|
AddConstantID<bool>("baz", 300, bool_type(), &val_false);
|
||||||
|
|
||||||
auto result = inspector()->GetConstantIDs();
|
auto result = inspector()->GetConstantIDs();
|
||||||
ASSERT_EQ(3u, result.size());
|
ASSERT_EQ(3u, result.size());
|
||||||
|
@ -591,10 +724,10 @@ TEST_F(InspectorGetEntryPointTest, BoolConstantIDs) {
|
||||||
EXPECT_FALSE(result[300].AsBool());
|
EXPECT_FALSE(result[300].AsBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, U32ConstantIDs) {
|
TEST_F(InspectorGetConstantIDsTest, U32) {
|
||||||
uint32_t val = 42;
|
uint32_t val = 42;
|
||||||
CreateConstantID<uint32_t>("foo", 1, u32_type(), nullptr);
|
AddConstantID<uint32_t>("foo", 1, u32_type(), nullptr);
|
||||||
CreateConstantID<uint32_t>("bar", 20, u32_type(), &val);
|
AddConstantID<uint32_t>("bar", 20, u32_type(), &val);
|
||||||
|
|
||||||
auto result = inspector()->GetConstantIDs();
|
auto result = inspector()->GetConstantIDs();
|
||||||
ASSERT_EQ(2u, result.size());
|
ASSERT_EQ(2u, result.size());
|
||||||
|
@ -607,12 +740,12 @@ TEST_F(InspectorGetEntryPointTest, U32ConstantIDs) {
|
||||||
EXPECT_EQ(42u, result[20].AsU32());
|
EXPECT_EQ(42u, result[20].AsU32());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, I32ConstantIDs) {
|
TEST_F(InspectorGetConstantIDsTest, I32) {
|
||||||
int32_t val_neg = -42;
|
int32_t val_neg = -42;
|
||||||
int32_t val_pos = 42;
|
int32_t val_pos = 42;
|
||||||
CreateConstantID<int32_t>("foo", 1, i32_type(), nullptr);
|
AddConstantID<int32_t>("foo", 1, i32_type(), nullptr);
|
||||||
CreateConstantID<int32_t>("bar", 20, i32_type(), &val_neg);
|
AddConstantID<int32_t>("bar", 20, i32_type(), &val_neg);
|
||||||
CreateConstantID<int32_t>("baz", 300, i32_type(), &val_pos);
|
AddConstantID<int32_t>("baz", 300, i32_type(), &val_pos);
|
||||||
|
|
||||||
auto result = inspector()->GetConstantIDs();
|
auto result = inspector()->GetConstantIDs();
|
||||||
ASSERT_EQ(3u, result.size());
|
ASSERT_EQ(3u, result.size());
|
||||||
|
@ -629,14 +762,14 @@ TEST_F(InspectorGetEntryPointTest, I32ConstantIDs) {
|
||||||
EXPECT_EQ(42, result[300].AsI32());
|
EXPECT_EQ(42, result[300].AsI32());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetEntryPointTest, FloatConstantIDs) {
|
TEST_F(InspectorGetConstantIDsTest, Float) {
|
||||||
float val_zero = 0.0f;
|
float val_zero = 0.0f;
|
||||||
float val_neg = -10.0f;
|
float val_neg = -10.0f;
|
||||||
float val_pos = 15.0f;
|
float val_pos = 15.0f;
|
||||||
CreateConstantID<float>("foo", 1, f32_type(), nullptr);
|
AddConstantID<float>("foo", 1, f32_type(), nullptr);
|
||||||
CreateConstantID<float>("bar", 20, f32_type(), &val_zero);
|
AddConstantID<float>("bar", 20, f32_type(), &val_zero);
|
||||||
CreateConstantID<float>("baz", 300, f32_type(), &val_neg);
|
AddConstantID<float>("baz", 300, f32_type(), &val_neg);
|
||||||
CreateConstantID<float>("x", 4000, f32_type(), &val_pos);
|
AddConstantID<float>("x", 4000, f32_type(), &val_pos);
|
||||||
|
|
||||||
auto result = inspector()->GetConstantIDs();
|
auto result = inspector()->GetConstantIDs();
|
||||||
ASSERT_EQ(4u, result.size());
|
ASSERT_EQ(4u, result.size());
|
||||||
|
@ -657,6 +790,200 @@ TEST_F(InspectorGetEntryPointTest, FloatConstantIDs) {
|
||||||
EXPECT_FLOAT_EQ(15.0, result[4000].AsFloat());
|
EXPECT_FLOAT_EQ(15.0, result[4000].AsFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(InspectorGetUniformBufferResourceBindings, MissingEntryPoint) {
|
||||||
|
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(InspectorGetUniformBufferResourceBindings, NonEntryPointFunc) {
|
||||||
|
auto foo_type = MakeUBOStructType("foo_type", {{i32_type(), 0}});
|
||||||
|
AddUBO("foo_ubo", foo_type.get(), 0, 0);
|
||||||
|
|
||||||
|
auto ubo_func =
|
||||||
|
MakeUBOReferenceBodyFunction("ubo_func", "foo_ubo", {{0, i32_type()}});
|
||||||
|
mod()->AddFunction(std::move(ubo_func));
|
||||||
|
|
||||||
|
auto ep_func = MakeCallerBodyFunction("ep_func", "ubo_func");
|
||||||
|
ep_func->add_decoration(
|
||||||
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
|
mod()->AddFunction(std::move(ep_func));
|
||||||
|
|
||||||
|
ASSERT_TRUE(td()->Determine()) << td()->error();
|
||||||
|
|
||||||
|
auto result = inspector()->GetUniformBufferResourceBindings("ubo_func");
|
||||||
|
std::string error = inspector()->error();
|
||||||
|
EXPECT_TRUE(error.find("not an entry point") != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(InspectorGetUniformBufferResourceBindings, MissingBlockDeco) {
|
||||||
|
ast::StructMemberList members;
|
||||||
|
ast::StructMemberDecorationList deco;
|
||||||
|
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
|
||||||
|
|
||||||
|
members.push_back(std::make_unique<ast::StructMember>(
|
||||||
|
StructMemberName(members.size(), i32_type()), i32_type(),
|
||||||
|
std::move(deco)));
|
||||||
|
|
||||||
|
ast::StructDecorationList decos;
|
||||||
|
|
||||||
|
auto str =
|
||||||
|
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
|
||||||
|
auto foo_type =
|
||||||
|
std::make_unique<ast::type::StructType>("foo_type", std::move(str));
|
||||||
|
|
||||||
|
AddUBO("foo_ubo", foo_type.get(), 0, 0);
|
||||||
|
|
||||||
|
auto ubo_func =
|
||||||
|
MakeUBOReferenceBodyFunction("ubo_func", "foo_ubo", {{0, i32_type()}});
|
||||||
|
mod()->AddFunction(std::move(ubo_func));
|
||||||
|
|
||||||
|
auto ep_func = MakeCallerBodyFunction("ep_func", "ubo_func");
|
||||||
|
ep_func->add_decoration(
|
||||||
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
|
mod()->AddFunction(std::move(ep_func));
|
||||||
|
|
||||||
|
ASSERT_TRUE(td()->Determine()) << td()->error();
|
||||||
|
|
||||||
|
auto result = inspector()->GetUniformBufferResourceBindings("ep_func");
|
||||||
|
ASSERT_FALSE(inspector()->has_error());
|
||||||
|
EXPECT_EQ(0u, result.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(InspectorGetUniformBufferResourceBindings, Simple) {
|
||||||
|
auto foo_type = MakeUBOStructType("foo_type", {{i32_type(), 0}});
|
||||||
|
AddUBO("foo_ubo", foo_type.get(), 0, 0);
|
||||||
|
|
||||||
|
auto ubo_func =
|
||||||
|
MakeUBOReferenceBodyFunction("ubo_func", "foo_ubo", {{0, i32_type()}});
|
||||||
|
mod()->AddFunction(std::move(ubo_func));
|
||||||
|
|
||||||
|
auto ep_func = MakeCallerBodyFunction("ep_func", "ubo_func");
|
||||||
|
ep_func->add_decoration(
|
||||||
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
|
mod()->AddFunction(std::move(ep_func));
|
||||||
|
|
||||||
|
ASSERT_TRUE(td()->Determine()) << td()->error();
|
||||||
|
|
||||||
|
auto result = inspector()->GetUniformBufferResourceBindings("ep_func");
|
||||||
|
ASSERT_FALSE(inspector()->has_error());
|
||||||
|
ASSERT_EQ(1u, result.size());
|
||||||
|
|
||||||
|
EXPECT_EQ(0u, result[0].bind_group);
|
||||||
|
EXPECT_EQ(0u, result[0].binding);
|
||||||
|
EXPECT_EQ(4u, result[0].min_buffer_binding_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(InspectorGetUniformBufferResourceBindings, MultipleMembers) {
|
||||||
|
auto foo_type = MakeUBOStructType(
|
||||||
|
"foo_type", {{i32_type(), 0}, {u32_type(), 4}, {f32_type(), 8}});
|
||||||
|
AddUBO("foo_ubo", foo_type.get(), 0, 0);
|
||||||
|
|
||||||
|
auto ubo_func = MakeUBOReferenceBodyFunction(
|
||||||
|
"ubo_func", "foo_ubo",
|
||||||
|
{{0, i32_type()}, {1, u32_type()}, {2, f32_type()}});
|
||||||
|
mod()->AddFunction(std::move(ubo_func));
|
||||||
|
|
||||||
|
auto ep_func = MakeCallerBodyFunction("ep_func", "ubo_func");
|
||||||
|
ep_func->add_decoration(
|
||||||
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
|
mod()->AddFunction(std::move(ep_func));
|
||||||
|
|
||||||
|
ASSERT_TRUE(td()->Determine()) << td()->error();
|
||||||
|
|
||||||
|
auto result = inspector()->GetUniformBufferResourceBindings("ep_func");
|
||||||
|
ASSERT_FALSE(inspector()->has_error());
|
||||||
|
ASSERT_EQ(1u, result.size());
|
||||||
|
|
||||||
|
EXPECT_EQ(0u, result[0].bind_group);
|
||||||
|
EXPECT_EQ(0u, result[0].binding);
|
||||||
|
EXPECT_EQ(12u, result[0].min_buffer_binding_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(InspectorGetUniformBufferResourceBindings, MultipleUBOs) {
|
||||||
|
auto ubo_type = MakeUBOStructType(
|
||||||
|
"ubo_type", {{i32_type(), 0}, {u32_type(), 4}, {f32_type(), 8}});
|
||||||
|
AddUBO("ubo_foo", ubo_type.get(), 0, 0);
|
||||||
|
AddUBO("ubo_bar", ubo_type.get(), 0, 1);
|
||||||
|
AddUBO("ubo_baz", ubo_type.get(), 2, 0);
|
||||||
|
|
||||||
|
auto AddReferenceFunc = [this](const std::string& func_name,
|
||||||
|
const std::string& var_name) {
|
||||||
|
auto ubo_func = MakeUBOReferenceBodyFunction(
|
||||||
|
func_name, var_name,
|
||||||
|
{{0, i32_type()}, {1, u32_type()}, {2, f32_type()}});
|
||||||
|
mod()->AddFunction(std::move(ubo_func));
|
||||||
|
};
|
||||||
|
AddReferenceFunc("ubo_foo_func", "ubo_foo");
|
||||||
|
AddReferenceFunc("ubo_bar_func", "ubo_bar");
|
||||||
|
AddReferenceFunc("ubo_baz_func", "ubo_baz");
|
||||||
|
|
||||||
|
auto AddFuncCall = [](ast::BlockStatement* body, const std::string& callee) {
|
||||||
|
auto ident_expr = std::make_unique<ast::IdentifierExpression>(callee);
|
||||||
|
auto call_expr = std::make_unique<ast::CallExpression>(
|
||||||
|
std::move(ident_expr), ast::ExpressionList());
|
||||||
|
body->append(std::make_unique<ast::CallStatement>(std::move(call_expr)));
|
||||||
|
};
|
||||||
|
auto body = std::make_unique<ast::BlockStatement>();
|
||||||
|
|
||||||
|
AddFuncCall(body.get(), "ubo_foo_func");
|
||||||
|
AddFuncCall(body.get(), "ubo_bar_func");
|
||||||
|
AddFuncCall(body.get(), "ubo_baz_func");
|
||||||
|
|
||||||
|
body->append(std::make_unique<ast::ReturnStatement>());
|
||||||
|
std::unique_ptr<ast::Function> func = std::make_unique<ast::Function>(
|
||||||
|
"ep_func", ast::VariableList(), void_type());
|
||||||
|
func->set_body(std::move(body));
|
||||||
|
|
||||||
|
func->add_decoration(
|
||||||
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
|
mod()->AddFunction(std::move(func));
|
||||||
|
|
||||||
|
ASSERT_TRUE(td()->Determine()) << td()->error();
|
||||||
|
|
||||||
|
auto result = inspector()->GetUniformBufferResourceBindings("ep_func");
|
||||||
|
ASSERT_FALSE(inspector()->has_error());
|
||||||
|
ASSERT_EQ(3u, result.size());
|
||||||
|
|
||||||
|
EXPECT_EQ(0u, result[0].bind_group);
|
||||||
|
EXPECT_EQ(0u, result[0].binding);
|
||||||
|
EXPECT_EQ(12u, result[0].min_buffer_binding_size);
|
||||||
|
|
||||||
|
EXPECT_EQ(0u, result[1].bind_group);
|
||||||
|
EXPECT_EQ(1u, result[1].binding);
|
||||||
|
EXPECT_EQ(12u, result[1].min_buffer_binding_size);
|
||||||
|
|
||||||
|
EXPECT_EQ(2u, result[2].bind_group);
|
||||||
|
EXPECT_EQ(0u, result[2].binding);
|
||||||
|
EXPECT_EQ(12u, result[2].min_buffer_binding_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(InspectorGetUniformBufferResourceBindings, ContainingArray) {
|
||||||
|
auto foo_type =
|
||||||
|
MakeUBOStructType("foo_type", {{i32_type(), 0}, {u32_array_type(4), 4}});
|
||||||
|
AddUBO("foo_ubo", foo_type.get(), 0, 0);
|
||||||
|
|
||||||
|
auto ubo_func =
|
||||||
|
MakeUBOReferenceBodyFunction("ubo_func", "foo_ubo", {{0, i32_type()}});
|
||||||
|
mod()->AddFunction(std::move(ubo_func));
|
||||||
|
|
||||||
|
auto ep_func = MakeCallerBodyFunction("ep_func", "ubo_func");
|
||||||
|
ep_func->add_decoration(
|
||||||
|
std::make_unique<ast::StageDecoration>(ast::PipelineStage::kVertex));
|
||||||
|
mod()->AddFunction(std::move(ep_func));
|
||||||
|
|
||||||
|
ASSERT_TRUE(td()->Determine()) << td()->error();
|
||||||
|
|
||||||
|
auto result = inspector()->GetUniformBufferResourceBindings("ep_func");
|
||||||
|
ASSERT_FALSE(inspector()->has_error());
|
||||||
|
ASSERT_EQ(1u, result.size());
|
||||||
|
|
||||||
|
EXPECT_EQ(0u, result[0].bind_group);
|
||||||
|
EXPECT_EQ(0u, result[0].binding);
|
||||||
|
EXPECT_EQ(20u, result[0].min_buffer_binding_size);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace inspector
|
} // namespace inspector
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
Loading…
Reference in New Issue