Remove support for the @stride attribute
We still use the StrideAttribute AST node in the SPIR-V reader for strided arrays and matrices, which are then removed by transforms. The WGSL parser no longer has to handle attributes on types. Bug: tint:1381 Change-Id: Ifa39575ce207d3fdfcbef7125fe6a3686fad5f20 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/83963 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
1a72a76e4f
commit
dfc1a2c081
|
@ -5,6 +5,7 @@
|
|||
### Breaking changes
|
||||
|
||||
* The `@block` attribute has been removed. [tint:1324](crbug.com/tint/1324)
|
||||
* The `@stride` attribute has been removed. [tint:1381](crbug.com/tint/1381)
|
||||
* Attributes using `[[attribute]]` syntax are no longer supported. [tint:1382](crbug.com/tint/1382)
|
||||
|
||||
## Changes for M101
|
||||
|
|
|
@ -467,8 +467,6 @@ libtint_source_set("libtint_core_all_src") {
|
|||
"transform/multiplanar_external_texture.h",
|
||||
"transform/num_workgroups_from_uniform.cc",
|
||||
"transform/num_workgroups_from_uniform.h",
|
||||
"transform/pad_array_elements.cc",
|
||||
"transform/pad_array_elements.h",
|
||||
"transform/promote_initializers_to_const_var.cc",
|
||||
"transform/promote_initializers_to_const_var.h",
|
||||
"transform/promote_side_effects_to_decl.cc",
|
||||
|
|
|
@ -345,8 +345,6 @@ set(TINT_LIB_SRCS
|
|||
transform/multiplanar_external_texture.h
|
||||
transform/num_workgroups_from_uniform.cc
|
||||
transform/num_workgroups_from_uniform.h
|
||||
transform/pad_array_elements.cc
|
||||
transform/pad_array_elements.h
|
||||
transform/promote_initializers_to_const_var.cc
|
||||
transform/promote_initializers_to_const_var.h
|
||||
transform/promote_side_effects_to_decl.cc
|
||||
|
@ -1023,7 +1021,6 @@ if(TINT_BUILD_TESTS)
|
|||
transform/module_scope_var_to_entry_point_param_test.cc
|
||||
transform/multiplanar_external_texture_test.cc
|
||||
transform/num_workgroups_from_uniform_test.cc
|
||||
transform/pad_array_elements_test.cc
|
||||
transform/promote_initializers_to_const_var_test.cc
|
||||
transform/promote_side_effects_to_decl_test.cc
|
||||
transform/remove_phonies_test.cc
|
||||
|
|
|
@ -41,7 +41,7 @@ struct S1 {
|
|||
let c0 : i32 = 10;
|
||||
let c1 : bool = true;
|
||||
|
||||
type t0 = @stride(16) array<vec4<f32>>;
|
||||
type t0 = array<vec4<f32>>;
|
||||
type t1 = array<vec4<f32>>;
|
||||
|
||||
var<private> g0 : u32 = 20u;
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
#include <string>
|
||||
|
||||
#include "src/tint/ast/attribute.h"
|
||||
#include "src/tint/ast/internal_attribute.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
/// A stride attribute
|
||||
/// A stride attribute used by the SPIR-V reader for strided arrays and
|
||||
/// matrices.
|
||||
class StrideAttribute final : public Castable<StrideAttribute, Attribute> {
|
||||
public:
|
||||
/// constructor
|
||||
|
|
|
@ -119,7 +119,6 @@ const char kLocationAttribute[] = "location";
|
|||
const char kSizeAttribute[] = "size";
|
||||
const char kAlignAttribute[] = "align";
|
||||
const char kStageAttribute[] = "stage";
|
||||
const char kStrideAttribute[] = "stride";
|
||||
const char kWorkgroupSizeAttribute[] = "workgroup_size";
|
||||
|
||||
// https://gpuweb.github.io/gpuweb/wgsl.html#reserved-keywords
|
||||
|
@ -799,7 +798,7 @@ Expect<ast::TexelFormat> ParserImpl::expect_texel_format(std::string_view use) {
|
|||
}
|
||||
|
||||
// variable_ident_decl
|
||||
// : IDENT COLON variable_attribute_list* type_decl
|
||||
// : IDENT COLON type_decl
|
||||
Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(
|
||||
std::string_view use,
|
||||
bool allow_inferred) {
|
||||
|
@ -814,20 +813,13 @@ Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(
|
|||
if (!expect(use, Token::Type::kColon))
|
||||
return Failure::kErrored;
|
||||
|
||||
auto attrs = attribute_list();
|
||||
if (attrs.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
auto t = peek();
|
||||
auto type = type_decl(attrs.value);
|
||||
auto type = type_decl();
|
||||
if (type.errored)
|
||||
return Failure::kErrored;
|
||||
if (!type.matched)
|
||||
return add_error(t.source(), "invalid type", use);
|
||||
|
||||
if (!expect_attributes_consumed(attrs.value))
|
||||
return Failure::kErrored;
|
||||
|
||||
return TypedIdentifier{type.value, ident.value, ident.source};
|
||||
}
|
||||
|
||||
|
@ -929,25 +921,6 @@ Maybe<const ast::Alias*> ParserImpl::type_alias() {
|
|||
// | MAT4x4 LESS_THAN type_decl GREATER_THAN
|
||||
// | texture_sampler_types
|
||||
Maybe<const ast::Type*> ParserImpl::type_decl() {
|
||||
auto attrs = attribute_list();
|
||||
if (attrs.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
auto type = type_decl(attrs.value);
|
||||
if (type.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (!expect_attributes_consumed(attrs.value)) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (!type.matched) {
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
Maybe<const ast::Type*> ParserImpl::type_decl(ast::AttributeList& attrs) {
|
||||
auto t = peek();
|
||||
Source source;
|
||||
if (match(Token::Type::kIdentifier, &source)) {
|
||||
|
@ -981,7 +954,7 @@ Maybe<const ast::Type*> ParserImpl::type_decl(ast::AttributeList& attrs) {
|
|||
}
|
||||
|
||||
if (match(Token::Type::kArray, &source)) {
|
||||
return expect_type_decl_array(t, std::move(attrs));
|
||||
return expect_type_decl_array(t);
|
||||
}
|
||||
|
||||
if (t.IsMatrix()) {
|
||||
|
@ -1080,9 +1053,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(Token t) {
|
|||
return builder_.ty.vec(make_source_range_from(t.source()), subtype, count);
|
||||
}
|
||||
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_array(
|
||||
Token t,
|
||||
ast::AttributeList attrs) {
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_array(Token t) {
|
||||
const char* use = "array declaration";
|
||||
|
||||
const ast::Expression* size = nullptr;
|
||||
|
@ -1111,7 +1082,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_array(
|
|||
}
|
||||
|
||||
return builder_.ty.array(make_source_range_from(t.source()), subtype.value,
|
||||
size, std::move(attrs));
|
||||
size);
|
||||
}
|
||||
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(Token t) {
|
||||
|
@ -1321,19 +1292,7 @@ Maybe<ParserImpl::FunctionHeader> ParserImpl::function_header() {
|
|||
}
|
||||
return_attributes = attrs.value;
|
||||
|
||||
// Apply stride attributes to the type node instead of the function.
|
||||
ast::AttributeList type_attributes;
|
||||
auto itr =
|
||||
std::find_if(return_attributes.begin(), return_attributes.end(),
|
||||
[](auto* attr) { return Is<ast::StrideAttribute>(attr); });
|
||||
if (itr != return_attributes.end()) {
|
||||
type_attributes.emplace_back(*itr);
|
||||
return_attributes.erase(itr);
|
||||
}
|
||||
|
||||
auto tok = peek();
|
||||
|
||||
auto type = type_decl(type_attributes);
|
||||
auto type = type_decl();
|
||||
if (type.errored) {
|
||||
errored = true;
|
||||
} else if (!type.matched) {
|
||||
|
@ -2974,19 +2933,6 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
|
|||
});
|
||||
}
|
||||
|
||||
if (t == kStrideAttribute) {
|
||||
const char* use = "stride attribute";
|
||||
return expect_paren_block(use, [&]() -> Result {
|
||||
auto val = expect_nonzero_positive_sint(use);
|
||||
if (val.errored)
|
||||
return Failure::kErrored;
|
||||
deprecated(t.source(),
|
||||
"the @stride attribute is deprecated; use a larger type if "
|
||||
"necessary");
|
||||
return create<ast::StrideAttribute>(t.source(), val.value);
|
||||
});
|
||||
}
|
||||
|
||||
if (t == kSizeAttribute) {
|
||||
const char* use = "size attribute";
|
||||
return expect_paren_block(use, [&]() -> Result {
|
||||
|
|
|
@ -419,11 +419,6 @@ class ParserImpl {
|
|||
/// Parses a `type_decl` grammar element
|
||||
/// @returns the parsed Type or nullptr if none matched.
|
||||
Maybe<const ast::Type*> type_decl();
|
||||
/// Parses a `type_decl` grammar element with the given pre-parsed
|
||||
/// attributes.
|
||||
/// @param attrs the list of attributes for the type.
|
||||
/// @returns the parsed Type or nullptr if none matched.
|
||||
Maybe<const ast::Type*> type_decl(ast::AttributeList& attrs);
|
||||
/// Parses a `storage_class` grammar element, erroring on parse failure.
|
||||
/// @param use a description of what was being parsed if an error was raised.
|
||||
/// @returns the storage class or StorageClass::kNone if none matched
|
||||
|
@ -849,8 +844,7 @@ class ParserImpl {
|
|||
Expect<const ast::Type*> expect_type_decl_pointer(Token t);
|
||||
Expect<const ast::Type*> expect_type_decl_atomic(Token t);
|
||||
Expect<const ast::Type*> expect_type_decl_vector(Token t);
|
||||
Expect<const ast::Type*> expect_type_decl_array(Token t,
|
||||
ast::AttributeList attrs);
|
||||
Expect<const ast::Type*> expect_type_decl_array(Token t);
|
||||
Expect<const ast::Type*> expect_type_decl_matrix(Token t);
|
||||
|
||||
Expect<const ast::Type*> expect_type(std::string_view use);
|
||||
|
|
|
@ -445,9 +445,9 @@ fn f() {
|
|||
|
||||
TEST_F(ParserImplErrorTest, FunctionScopeUnusedDecl) {
|
||||
EXPECT("fn f(a:i32)->i32{return a;@size(1)}",
|
||||
R"(test.wgsl:1:28 error: unexpected attributes
|
||||
R"(test.wgsl:1:27 error: expected '}'
|
||||
fn f(a:i32)->i32{return a;@size(1)}
|
||||
^^^^
|
||||
^
|
||||
)");
|
||||
}
|
||||
|
||||
|
@ -774,31 +774,6 @@ var i : array<u32, 3;
|
|||
)");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayAttrNotArray) {
|
||||
EXPECT("var i : @location(1) i32;",
|
||||
R"(test.wgsl:1:10 error: unexpected attributes
|
||||
var i : @location(1) i32;
|
||||
^^^^^^^^
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayStrideInvalid) {
|
||||
EXPECT(
|
||||
"var i : @stride(x) array<i32>;",
|
||||
R"(test.wgsl:1:17 error: expected signed integer literal for stride attribute
|
||||
var i : @stride(x) array<i32>;
|
||||
^
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayStrideNegative) {
|
||||
EXPECT("var i : @stride(-1) array<i32>;",
|
||||
R"(test.wgsl:1:17 error: stride attribute must be greater than 0
|
||||
var i : @stride(-1) array<i32>;
|
||||
^^
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingType) {
|
||||
EXPECT("var i : array<1, 3>;",
|
||||
R"(test.wgsl:1:15 error: invalid type for array declaration
|
||||
|
|
|
@ -75,27 +75,6 @@ TEST_F(ParserImplTest, FunctionHeader_InvariantReturnType) {
|
|||
EXPECT_TRUE(f->return_type_attributes[0]->Is<ast::InvariantAttribute>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionHeader_AttributeReturnType_WithArrayStride) {
|
||||
auto p = parser("fn main() -> @location(1) @stride(16) array<f32, 4>");
|
||||
auto f = p->function_header();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
EXPECT_TRUE(f.matched);
|
||||
EXPECT_FALSE(f.errored);
|
||||
|
||||
EXPECT_EQ(f->name, "main");
|
||||
EXPECT_EQ(f->params.size(), 0u);
|
||||
ASSERT_EQ(f->return_type_attributes.size(), 1u);
|
||||
auto* loc = f->return_type_attributes[0]->As<ast::LocationAttribute>();
|
||||
ASSERT_TRUE(loc != nullptr);
|
||||
EXPECT_EQ(loc->value, 1u);
|
||||
|
||||
auto* array_type = f->return_type->As<ast::Array>();
|
||||
ASSERT_EQ(array_type->attributes.size(), 1u);
|
||||
auto* stride = array_type->attributes[0]->As<ast::StrideAttribute>();
|
||||
ASSERT_TRUE(stride != nullptr);
|
||||
EXPECT_EQ(stride->stride, 16u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionHeader_MissingIdent) {
|
||||
auto p = parser("fn ()");
|
||||
auto f = p->function_header();
|
||||
|
|
|
@ -166,33 +166,6 @@ TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
|
|||
EXPECT_EQ(str->members.size(), 2u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, GlobalDecl_Struct_WithStride) {
|
||||
auto p = parser("struct A { data: @stride(4) array<f32>; }");
|
||||
|
||||
p->expect_global_decl();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
|
||||
auto program = p->program();
|
||||
ASSERT_EQ(program.AST().TypeDecls().size(), 1u);
|
||||
|
||||
auto* t = program.AST().TypeDecls()[0];
|
||||
ASSERT_NE(t, nullptr);
|
||||
ASSERT_TRUE(t->Is<ast::Struct>());
|
||||
|
||||
auto* str = t->As<ast::Struct>();
|
||||
EXPECT_EQ(str->name, program.Symbols().Get("A"));
|
||||
EXPECT_EQ(str->members.size(), 1u);
|
||||
|
||||
const auto* ty = str->members[0]->type;
|
||||
ASSERT_TRUE(ty->Is<ast::Array>());
|
||||
const auto* arr = ty->As<ast::Array>();
|
||||
|
||||
ASSERT_EQ(arr->attributes.size(), 1u);
|
||||
auto* stride = arr->attributes[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideAttribute>());
|
||||
ASSERT_EQ(stride->As<ast::StrideAttribute>()->stride, 4u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) {
|
||||
auto p = parser("A {}");
|
||||
p->expect_global_decl();
|
||||
|
|
|
@ -439,172 +439,6 @@ TEST_F(ParserImplTest, TypeDecl_Array_ConstantSize) {
|
|||
EXPECT_EQ(p->builder().Symbols().NameFor(count_expr->symbol), "size");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
|
||||
auto p = parser("@stride(16) array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
|
||||
auto* size = a->count->As<ast::SintLiteralExpression>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->ValueAsI32(), 5);
|
||||
|
||||
ASSERT_EQ(a->attributes.size(), 1u);
|
||||
auto* stride = a->attributes[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideAttribute>());
|
||||
ASSERT_EQ(stride->As<ast::StrideAttribute>()->stride, 16u);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 13u}, {1u, 26u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) {
|
||||
auto p = parser("@stride(16) array<f32>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_TRUE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
|
||||
ASSERT_EQ(a->attributes.size(), 1u);
|
||||
auto* stride = a->attributes[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideAttribute>());
|
||||
ASSERT_EQ(stride->As<ast::StrideAttribute>()->stride, 16u);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 13u}, {1u, 23u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_MultipleAttributes_OneBlock) {
|
||||
auto p = parser("@stride(16) @stride(32) array<f32>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_TRUE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
|
||||
auto& attrs = a->attributes;
|
||||
ASSERT_EQ(attrs.size(), 2u);
|
||||
EXPECT_TRUE(attrs[0]->Is<ast::StrideAttribute>());
|
||||
EXPECT_EQ(attrs[0]->As<ast::StrideAttribute>()->stride, 16u);
|
||||
EXPECT_TRUE(attrs[1]->Is<ast::StrideAttribute>());
|
||||
EXPECT_EQ(attrs[1]->As<ast::StrideAttribute>()->stride, 32u);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 25u}, {1u, 35u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_MultipleAttributes_MultipleBlocks) {
|
||||
auto p = parser("@stride(16) @stride(32) array<f32>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_TRUE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
|
||||
auto& attrs = a->attributes;
|
||||
ASSERT_EQ(attrs.size(), 2u);
|
||||
EXPECT_TRUE(attrs[0]->Is<ast::StrideAttribute>());
|
||||
EXPECT_EQ(attrs[0]->As<ast::StrideAttribute>()->stride, 16u);
|
||||
EXPECT_TRUE(attrs[1]->Is<ast::StrideAttribute>());
|
||||
EXPECT_EQ(attrs[1]->As<ast::StrideAttribute>()->stride, 32u);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 25u}, {1u, 35u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Attribute_MissingArray) {
|
||||
auto p = parser("@stride(16) f32");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(
|
||||
p->error(),
|
||||
R"(1:2: use of deprecated language feature: the @stride attribute is deprecated; use a larger type if necessary
|
||||
1:2: unexpected attributes)");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Attribute_UnknownAttribute) {
|
||||
auto p = parser("@unknown(16) array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), R"(1:2: expected attribute)");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingLeftParen) {
|
||||
auto p = parser("@stride 4) array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), R"(1:9: expected '(' for stride attribute)");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingRightParen) {
|
||||
auto p = parser("@stride(4 array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(
|
||||
p->error(),
|
||||
R"(1:2: use of deprecated language feature: the @stride attribute is deprecated; use a larger type if necessary
|
||||
1:11: expected ')' for stride attribute)");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingValue) {
|
||||
auto p = parser("@stride() array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(),
|
||||
"1:9: expected signed integer literal for stride attribute");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) {
|
||||
auto p = parser("@stride(invalid) array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(),
|
||||
"1:9: expected signed integer literal for stride attribute");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue_Negative) {
|
||||
auto p = parser("@stride(-1) array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:9: stride attribute must be greater than 0");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
|
||||
auto p = parser("array<u32>");
|
||||
auto t = p->type_decl();
|
||||
|
|
|
@ -75,35 +75,6 @@ TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
|
|||
ASSERT_EQ(p->error(), "1:1: expected identifier for test");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, VariableIdentDecl_NonAccessAttrFail) {
|
||||
auto p = parser("my_var : @location(1) S");
|
||||
|
||||
auto* mem = Member("a", ty.i32(), ast::AttributeList{});
|
||||
ast::StructMemberList members;
|
||||
members.push_back(mem);
|
||||
|
||||
auto decl = p->expect_variable_ident_decl("test");
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(decl.errored);
|
||||
ASSERT_EQ(p->error(), "1:11: unexpected attributes");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, VariableIdentDecl_AttributeMissingRightParen) {
|
||||
auto p = parser("my_var : @location(4 S");
|
||||
auto decl = p->expect_variable_ident_decl("test");
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(decl.errored);
|
||||
ASSERT_EQ(p->error(), "1:22: expected ')' for location attribute");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, VariableIdentDecl_AttributeMissingLeftParen) {
|
||||
auto p = parser("my_var : @stride 4) S");
|
||||
auto decl = p->expect_variable_ident_decl("test");
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(decl.errored);
|
||||
ASSERT_EQ(p->error(), "1:18: expected '(' for stride attribute");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace wgsl
|
||||
} // namespace reader
|
||||
|
|
|
@ -177,94 +177,6 @@ fn main() {
|
|||
got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
|
||||
}
|
||||
|
||||
TEST_F(ArrayLengthFromUniformTest, WithStride) {
|
||||
auto* src = R"(
|
||||
@group(0) @binding(0) var<storage, read> sb : @stride(64) array<i32>;
|
||||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var len : u32 = arrayLength(&sb);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
struct tint_symbol {
|
||||
buffer_size : array<vec4<u32>, 1u>;
|
||||
}
|
||||
|
||||
@group(0) @binding(30) var<uniform> tint_symbol_1 : tint_symbol;
|
||||
|
||||
@group(0) @binding(0) var<storage, read> sb : @stride(64) array<i32>;
|
||||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var len : u32 = (tint_symbol_1.buffer_size[0u][0u] / 64u);
|
||||
}
|
||||
)";
|
||||
|
||||
ArrayLengthFromUniform::Config cfg({0, 30u});
|
||||
cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
|
||||
|
||||
DataMap data;
|
||||
data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
|
||||
|
||||
auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
EXPECT_EQ(std::unordered_set<uint32_t>({0}),
|
||||
got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
|
||||
}
|
||||
|
||||
TEST_F(ArrayLengthFromUniformTest, WithStride_InStruct) {
|
||||
auto* src = R"(
|
||||
struct SB {
|
||||
x : i32;
|
||||
y : f32;
|
||||
arr : @stride(64) array<i32>;
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<storage, read> sb : SB;
|
||||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var len : u32 = arrayLength(&sb.arr);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
struct tint_symbol {
|
||||
buffer_size : array<vec4<u32>, 1u>;
|
||||
}
|
||||
|
||||
@group(0) @binding(30) var<uniform> tint_symbol_1 : tint_symbol;
|
||||
|
||||
struct SB {
|
||||
x : i32;
|
||||
y : f32;
|
||||
arr : @stride(64) array<i32>;
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<storage, read> sb : SB;
|
||||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var len : u32 = ((tint_symbol_1.buffer_size[0u][0u] - 8u) / 64u);
|
||||
}
|
||||
)";
|
||||
|
||||
ArrayLengthFromUniform::Config cfg({0, 30u});
|
||||
cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
|
||||
|
||||
DataMap data;
|
||||
data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
|
||||
|
||||
auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
EXPECT_EQ(std::unordered_set<uint32_t>({0}),
|
||||
got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
|
||||
}
|
||||
|
||||
TEST_F(ArrayLengthFromUniformTest, MultipleStorageBuffers) {
|
||||
auto* src = R"(
|
||||
struct SB1 {
|
||||
|
|
|
@ -287,78 +287,6 @@ fn main() {
|
|||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(CalculateArrayLengthTest, WithStride) {
|
||||
auto* src = R"(
|
||||
@group(0) @binding(0) var<storage, read> sb : @stride(64) array<i32>;
|
||||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var len : u32 = arrayLength(&sb);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
@internal(intrinsic_buffer_size)
|
||||
fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : @stride(64) array<i32>, result : ptr<function, u32>)
|
||||
|
||||
@group(0) @binding(0) var<storage, read> sb : @stride(64) array<i32>;
|
||||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var tint_symbol_1 : u32 = 0u;
|
||||
tint_symbol(sb, &(tint_symbol_1));
|
||||
let tint_symbol_2 : u32 = (tint_symbol_1 / 64u);
|
||||
var len : u32 = tint_symbol_2;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(CalculateArrayLengthTest, WithStride_InStruct) {
|
||||
auto* src = R"(
|
||||
struct SB {
|
||||
x : i32;
|
||||
y : f32;
|
||||
arr : @stride(64) array<i32>;
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<storage, read> sb : SB;
|
||||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var len : u32 = arrayLength(&sb.arr);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
@internal(intrinsic_buffer_size)
|
||||
fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
|
||||
|
||||
struct SB {
|
||||
x : i32;
|
||||
y : f32;
|
||||
arr : @stride(64) array<i32>;
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<storage, read> sb : SB;
|
||||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var tint_symbol_1 : u32 = 0u;
|
||||
tint_symbol(sb, &(tint_symbol_1));
|
||||
let tint_symbol_2 : u32 = ((tint_symbol_1 - 8u) / 64u);
|
||||
var len : u32 = tint_symbol_2;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(CalculateArrayLengthTest, Nested) {
|
||||
auto* src = R"(
|
||||
struct SB {
|
||||
|
|
|
@ -1970,22 +1970,26 @@ struct SB {
|
|||
|
||||
TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain) {
|
||||
auto* src = R"(
|
||||
// sizeof(S1) == 32
|
||||
// alignof(S1) == 16
|
||||
struct S1 {
|
||||
a : i32;
|
||||
b : vec3<f32>;
|
||||
c : i32;
|
||||
};
|
||||
|
||||
// sizeof(S2) == 116
|
||||
// alignof(S2) == 16
|
||||
struct S2 {
|
||||
a : i32;
|
||||
b : @stride(32) array<S1, 3>;
|
||||
b : array<S1, 3>;
|
||||
c : i32;
|
||||
};
|
||||
|
||||
struct SB {
|
||||
@size(128)
|
||||
a : i32;
|
||||
b : @stride(256) array<S2>;
|
||||
b : array<S2>;
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> sb : SB;
|
||||
|
@ -1999,9 +2003,9 @@ fn main() {
|
|||
// sb.b[4].b[1].b.z
|
||||
// ^ ^ ^ ^ ^ ^
|
||||
// | | | | | |
|
||||
// 128 | |1200| 1224
|
||||
// 128 | |688 | 712
|
||||
// | | |
|
||||
// 1152 1168 1216
|
||||
// 640 656 704
|
||||
|
||||
auto* expect = R"(
|
||||
struct S1 {
|
||||
|
@ -2012,14 +2016,14 @@ struct S1 {
|
|||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
b : @stride(32) array<S1, 3>;
|
||||
b : array<S1, 3>;
|
||||
c : i32;
|
||||
}
|
||||
|
||||
struct SB {
|
||||
@size(128)
|
||||
a : i32;
|
||||
b : @stride(256) array<S2>;
|
||||
b : array<S2>;
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> sb : SB;
|
||||
|
@ -2029,7 +2033,7 @@ fn tint_symbol(@internal(disable_validation__ignore_constructible_function_param
|
|||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var x : f32 = tint_symbol(sb, 1224u);
|
||||
var x : f32 = tint_symbol(sb, 712u);
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -2050,12 +2054,12 @@ fn main() {
|
|||
struct SB {
|
||||
@size(128)
|
||||
a : i32;
|
||||
b : @stride(256) array<S2>;
|
||||
b : array<S2>;
|
||||
};
|
||||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
b : @stride(32) array<S1, 3>;
|
||||
b : array<S1, 3>;
|
||||
c : i32;
|
||||
};
|
||||
|
||||
|
@ -2069,9 +2073,9 @@ struct S1 {
|
|||
// sb.b[4].b[1].b.z
|
||||
// ^ ^ ^ ^ ^ ^
|
||||
// | | | | | |
|
||||
// 128 | |1200| 1224
|
||||
// 128 | |688 | 712
|
||||
// | | |
|
||||
// 1152 1168 1216
|
||||
// 640 656 704
|
||||
|
||||
auto* expect = R"(
|
||||
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
|
||||
|
@ -2079,7 +2083,7 @@ fn tint_symbol(@internal(disable_validation__ignore_constructible_function_param
|
|||
|
||||
@stage(compute) @workgroup_size(1)
|
||||
fn main() {
|
||||
var x : f32 = tint_symbol(sb, 1224u);
|
||||
var x : f32 = tint_symbol(sb, 712u);
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> sb : SB;
|
||||
|
@ -2087,12 +2091,12 @@ fn main() {
|
|||
struct SB {
|
||||
@size(128)
|
||||
a : i32;
|
||||
b : @stride(256) array<S2>;
|
||||
b : array<S2>;
|
||||
}
|
||||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
b : @stride(32) array<S1, 3>;
|
||||
b : array<S1, 3>;
|
||||
c : i32;
|
||||
}
|
||||
|
||||
|
@ -2118,14 +2122,14 @@ struct S1 {
|
|||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
b : @stride(32) array<S1, 3>;
|
||||
b : array<S1, 3>;
|
||||
c : i32;
|
||||
};
|
||||
|
||||
struct SB {
|
||||
@size(128)
|
||||
a : i32;
|
||||
b : @stride(256) array<S2>;
|
||||
b : array<S2>;
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> sb : SB;
|
||||
|
@ -2148,14 +2152,14 @@ struct S1 {
|
|||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
b : @stride(32) array<S1, 3>;
|
||||
b : array<S1, 3>;
|
||||
c : i32;
|
||||
}
|
||||
|
||||
struct SB {
|
||||
@size(128)
|
||||
a : i32;
|
||||
b : @stride(256) array<S2>;
|
||||
b : array<S2>;
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> sb : SB;
|
||||
|
@ -2168,7 +2172,7 @@ fn main() {
|
|||
var i : i32 = 4;
|
||||
var j : u32 = 1u;
|
||||
var k : i32 = 2;
|
||||
var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
|
||||
var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -2192,12 +2196,12 @@ fn main() {
|
|||
struct SB {
|
||||
@size(128)
|
||||
a : i32;
|
||||
b : @stride(256) array<S2>;
|
||||
b :array<S2>;
|
||||
};
|
||||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
b : @stride(32) array<S1, 3>;
|
||||
b : array<S1, 3>;
|
||||
c : i32;
|
||||
};
|
||||
|
||||
|
@ -2217,7 +2221,7 @@ fn main() {
|
|||
var i : i32 = 4;
|
||||
var j : u32 = 1u;
|
||||
var k : i32 = 2;
|
||||
var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
|
||||
var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> sb : SB;
|
||||
|
@ -2225,12 +2229,12 @@ fn main() {
|
|||
struct SB {
|
||||
@size(128)
|
||||
a : i32;
|
||||
b : @stride(256) array<S2>;
|
||||
b : array<S2>;
|
||||
}
|
||||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
b : @stride(32) array<S1, 3>;
|
||||
b : array<S1, 3>;
|
||||
c : i32;
|
||||
}
|
||||
|
||||
|
@ -2256,7 +2260,7 @@ struct S1 {
|
|||
|
||||
type A1 = S1;
|
||||
|
||||
type A1_Array = @stride(32) array<S1, 3>;
|
||||
type A1_Array = array<S1, 3>;
|
||||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
|
@ -2266,7 +2270,7 @@ struct S2 {
|
|||
|
||||
type A2 = S2;
|
||||
|
||||
type A2_Array = @stride(256) array<S2>;
|
||||
type A2_Array = array<S2>;
|
||||
|
||||
struct SB {
|
||||
@size(128)
|
||||
|
@ -2294,7 +2298,7 @@ struct S1 {
|
|||
|
||||
type A1 = S1;
|
||||
|
||||
type A1_Array = @stride(32) array<S1, 3>;
|
||||
type A1_Array = array<S1, 3>;
|
||||
|
||||
struct S2 {
|
||||
a : i32;
|
||||
|
@ -2304,7 +2308,7 @@ struct S2 {
|
|||
|
||||
type A2 = S2;
|
||||
|
||||
type A2_Array = @stride(256) array<S2>;
|
||||
type A2_Array = array<S2>;
|
||||
|
||||
struct SB {
|
||||
@size(128)
|
||||
|
@ -2322,7 +2326,7 @@ fn main() {
|
|||
var i : i32 = 4;
|
||||
var j : u32 = 1u;
|
||||
var k : i32 = 2;
|
||||
var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
|
||||
var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -2350,7 +2354,7 @@ struct SB {
|
|||
b : A2_Array;
|
||||
};
|
||||
|
||||
type A2_Array = @stride(256) array<S2>;
|
||||
type A2_Array = array<S2>;
|
||||
|
||||
type A2 = S2;
|
||||
|
||||
|
@ -2362,7 +2366,7 @@ struct S2 {
|
|||
|
||||
type A1 = S1;
|
||||
|
||||
type A1_Array = @stride(32) array<S1, 3>;
|
||||
type A1_Array = array<S1, 3>;
|
||||
|
||||
struct S1 {
|
||||
a : i32;
|
||||
|
@ -2380,7 +2384,7 @@ fn main() {
|
|||
var i : i32 = 4;
|
||||
var j : u32 = 1u;
|
||||
var k : i32 = 2;
|
||||
var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
|
||||
var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> sb : SB;
|
||||
|
@ -2391,7 +2395,7 @@ struct SB {
|
|||
b : A2_Array;
|
||||
}
|
||||
|
||||
type A2_Array = @stride(256) array<S2>;
|
||||
type A2_Array = array<S2>;
|
||||
|
||||
type A2 = S2;
|
||||
|
||||
|
@ -2403,7 +2407,7 @@ struct S2 {
|
|||
|
||||
type A1 = S1;
|
||||
|
||||
type A1_Array = @stride(32) array<S1, 3>;
|
||||
type A1_Array = array<S1, 3>;
|
||||
|
||||
struct S1 {
|
||||
a : i32;
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "src/tint/transform/fold_trivial_single_use_lets.h"
|
||||
#include "src/tint/transform/loop_to_for_loop.h"
|
||||
#include "src/tint/transform/manager.h"
|
||||
#include "src/tint/transform/pad_array_elements.h"
|
||||
#include "src/tint/transform/promote_initializers_to_const_var.h"
|
||||
#include "src/tint/transform/promote_side_effects_to_decl.h"
|
||||
#include "src/tint/transform/remove_phonies.h"
|
||||
|
@ -105,7 +104,6 @@ Output Glsl::Run(const Program* in, const DataMap& inputs) const {
|
|||
}
|
||||
manager.Add<PromoteInitializersToConstVar>();
|
||||
|
||||
manager.Add<PadArrayElements>();
|
||||
manager.Add<AddEmptyEntryPoint>();
|
||||
manager.Add<AddSpirvBlockAttribute>();
|
||||
|
||||
|
|
|
@ -1,177 +0,0 @@
|
|||
// Copyright 2021 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/tint/transform/pad_array_elements.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "src/tint/program_builder.h"
|
||||
#include "src/tint/sem/array.h"
|
||||
#include "src/tint/sem/call.h"
|
||||
#include "src/tint/sem/expression.h"
|
||||
#include "src/tint/sem/type_constructor.h"
|
||||
#include "src/tint/utils/map.h"
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::transform::PadArrayElements);
|
||||
|
||||
namespace tint {
|
||||
namespace transform {
|
||||
namespace {
|
||||
|
||||
using ArrayBuilder = std::function<const ast::Array*()>;
|
||||
|
||||
/// PadArray returns a function that constructs a new array in `ctx.dst` with
|
||||
/// the element type padded to account for the explicit stride. PadArray will
|
||||
/// recursively pad arrays-of-arrays. The new array element type will be added
|
||||
/// to module-scope type declarations of `ctx.dst`.
|
||||
/// @param ctx the CloneContext
|
||||
/// @param create_ast_type_for Transform::CreateASTTypeFor()
|
||||
/// @param padded_arrays a map of src array type to the new array name
|
||||
/// @param array the array type
|
||||
/// @return the new AST array
|
||||
template <typename CREATE_AST_TYPE_FOR>
|
||||
ArrayBuilder PadArray(
|
||||
CloneContext& ctx,
|
||||
CREATE_AST_TYPE_FOR&& create_ast_type_for,
|
||||
std::unordered_map<const sem::Array*, ArrayBuilder>& padded_arrays,
|
||||
const sem::Array* array) {
|
||||
if (array->IsStrideImplicit()) {
|
||||
// We don't want to wrap arrays that have an implicit stride
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return utils::GetOrCreate(padded_arrays, array, [&] {
|
||||
// Generate a unique name for the array element type
|
||||
auto name = ctx.dst->Symbols().New("tint_padded_array_element");
|
||||
|
||||
// Examine the element type. Is it also an array?
|
||||
const ast::Type* el_ty = nullptr;
|
||||
if (auto* el_array = array->ElemType()->As<sem::Array>()) {
|
||||
// Array of array - call PadArray() on the element type
|
||||
if (auto p =
|
||||
PadArray(ctx, create_ast_type_for, padded_arrays, el_array)) {
|
||||
el_ty = p();
|
||||
}
|
||||
}
|
||||
|
||||
// If the element wasn't a padded array, just create the typical AST type
|
||||
// for it
|
||||
if (el_ty == nullptr) {
|
||||
el_ty = create_ast_type_for(ctx, array->ElemType());
|
||||
}
|
||||
|
||||
// Structure() will create and append the ast::Struct to the
|
||||
// global declarations of `ctx.dst`. As we haven't finished building the
|
||||
// current module-scope statement or function, this will be placed
|
||||
// immediately before the usage.
|
||||
ctx.dst->Structure(
|
||||
name,
|
||||
{ctx.dst->Member("el", el_ty, {ctx.dst->MemberSize(array->Stride())})});
|
||||
|
||||
auto* dst = ctx.dst;
|
||||
return [=] {
|
||||
if (array->IsRuntimeSized()) {
|
||||
return dst->ty.array(dst->create<ast::TypeName>(name));
|
||||
} else {
|
||||
return dst->ty.array(dst->create<ast::TypeName>(name), array->Count());
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PadArrayElements::PadArrayElements() = default;
|
||||
|
||||
PadArrayElements::~PadArrayElements() = default;
|
||||
|
||||
bool PadArrayElements::ShouldRun(const Program* program, const DataMap&) const {
|
||||
for (auto* node : program->ASTNodes().Objects()) {
|
||||
if (auto* var = node->As<ast::Type>()) {
|
||||
if (auto* arr = program->Sem().Get<sem::Array>(var)) {
|
||||
if (!arr->IsStrideImplicit()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PadArrayElements::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
|
||||
auto& sem = ctx.src->Sem();
|
||||
|
||||
std::unordered_map<const sem::Array*, ArrayBuilder> padded_arrays;
|
||||
auto pad = [&](const sem::Array* array) {
|
||||
return PadArray(ctx, CreateASTTypeFor, padded_arrays, array);
|
||||
};
|
||||
|
||||
// Replace all array types with their corresponding padded array type
|
||||
ctx.ReplaceAll([&](const ast::Type* ast_type) -> const ast::Type* {
|
||||
auto* type = ctx.src->TypeOf(ast_type);
|
||||
if (auto* array = type->UnwrapRef()->As<sem::Array>()) {
|
||||
if (auto p = pad(array)) {
|
||||
return p();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
// Fix up index accessors so `a[1]` becomes `a[1].el`
|
||||
ctx.ReplaceAll([&](const ast::IndexAccessorExpression* accessor)
|
||||
-> const ast::Expression* {
|
||||
if (auto* array = tint::As<sem::Array>(
|
||||
sem.Get(accessor->object)->Type()->UnwrapRef())) {
|
||||
if (pad(array)) {
|
||||
// Array element is wrapped in a structure. Emit a member accessor
|
||||
// to get to the actual array element.
|
||||
auto* idx = ctx.CloneWithoutTransform(accessor);
|
||||
return ctx.dst->MemberAccessor(idx, "el");
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
// Fix up array constructors so `A(1,2)` becomes
|
||||
// `A(padded(1), padded(2))`
|
||||
ctx.ReplaceAll(
|
||||
[&](const ast::CallExpression* expr) -> const ast::Expression* {
|
||||
auto* call = sem.Get(expr);
|
||||
if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
|
||||
if (auto* array = ctor->ReturnType()->As<sem::Array>()) {
|
||||
if (auto p = pad(array)) {
|
||||
auto* arr_ty = p();
|
||||
auto el_typename = arr_ty->type->As<ast::TypeName>()->name;
|
||||
|
||||
ast::ExpressionList args;
|
||||
args.reserve(call->Arguments().size());
|
||||
for (auto* arg : call->Arguments()) {
|
||||
auto* val = ctx.Clone(arg->Declaration());
|
||||
args.emplace_back(ctx.dst->Construct(
|
||||
ctx.dst->create<ast::TypeName>(el_typename), val));
|
||||
}
|
||||
|
||||
return ctx.dst->Construct(arr_ty, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
ctx.Clone();
|
||||
}
|
||||
|
||||
} // namespace transform
|
||||
} // namespace tint
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright 2021 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SRC_TINT_TRANSFORM_PAD_ARRAY_ELEMENTS_H_
|
||||
#define SRC_TINT_TRANSFORM_PAD_ARRAY_ELEMENTS_H_
|
||||
|
||||
#include "src/tint/transform/transform.h"
|
||||
|
||||
namespace tint {
|
||||
namespace transform {
|
||||
|
||||
/// PadArrayElements is a transform that replaces array types with an explicit
|
||||
/// stride that is larger than the implicit stride, with an array of a new
|
||||
/// structure type. This structure holds with a single field of the element
|
||||
/// type, decorated with a `@size` attribute to pad the structure to the
|
||||
/// required array stride. The new array types have no explicit stride,
|
||||
/// structure size is equal to the desired stride.
|
||||
/// Array index expressions and constructors are also adjusted to deal with this
|
||||
/// structure element type.
|
||||
/// This transform helps with backends that cannot directly return arrays or use
|
||||
/// them as parameters.
|
||||
class PadArrayElements : public Castable<PadArrayElements, Transform> {
|
||||
public:
|
||||
/// Constructor
|
||||
PadArrayElements();
|
||||
|
||||
/// Destructor
|
||||
~PadArrayElements() override;
|
||||
|
||||
/// @param program the program to inspect
|
||||
/// @param data optional extra transform-specific input data
|
||||
/// @returns true if this transform should be run for the given program
|
||||
bool ShouldRun(const Program* program,
|
||||
const DataMap& data = {}) const override;
|
||||
|
||||
protected:
|
||||
/// Runs the transform using the CloneContext built for transforming a
|
||||
/// program. Run() is responsible for calling Clone() on the CloneContext.
|
||||
/// @param ctx the CloneContext primed with the input program and
|
||||
/// ProgramBuilder
|
||||
/// @param inputs optional extra transform-specific input data
|
||||
/// @param outputs optional extra transform-specific output data
|
||||
void Run(CloneContext& ctx,
|
||||
const DataMap& inputs,
|
||||
DataMap& outputs) const override;
|
||||
};
|
||||
|
||||
} // namespace transform
|
||||
} // namespace tint
|
||||
|
||||
#endif // SRC_TINT_TRANSFORM_PAD_ARRAY_ELEMENTS_H_
|
|
@ -1,518 +0,0 @@
|
|||
// Copyright 2021 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/tint/transform/pad_array_elements.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "src/tint/transform/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
namespace transform {
|
||||
namespace {
|
||||
|
||||
using PadArrayElementsTest = TransformTest;
|
||||
|
||||
TEST_F(PadArrayElementsTest, ShouldRunEmptyModule) {
|
||||
auto* src = R"()";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<PadArrayElements>(src));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ShouldRunHasImplicitArrayStride) {
|
||||
auto* src = R"(
|
||||
var<private> arr : array<i32, 4>;
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<PadArrayElements>(src));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ShouldRunHasExplicitArrayStride) {
|
||||
auto* src = R"(
|
||||
var<private> arr : @stride(8) array<i32, 4>;
|
||||
)";
|
||||
|
||||
EXPECT_TRUE(ShouldRun<PadArrayElements>(src));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, EmptyModule) {
|
||||
auto* src = "";
|
||||
auto* expect = "";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ImplicitArrayStride) {
|
||||
auto* src = R"(
|
||||
var<private> arr : array<i32, 4>;
|
||||
)";
|
||||
auto* expect = src;
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ArrayAsGlobal) {
|
||||
auto* src = R"(
|
||||
var<private> arr : @stride(8) array<i32, 4>;
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
var<private> arr : array<tint_padded_array_element, 4u>;
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, RuntimeArray) {
|
||||
auto* src = R"(
|
||||
struct S {
|
||||
rta : @stride(8) array<i32>;
|
||||
};
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct S {
|
||||
rta : array<tint_padded_array_element>;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ArrayFunctionVar) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
var arr : @stride(16) array<i32, 4>;
|
||||
arr = @stride(16) array<i32, 4>();
|
||||
arr = @stride(16) array<i32, 4>(1, 2, 3, 4);
|
||||
let x = arr[3];
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(16)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
fn f() {
|
||||
var arr : array<tint_padded_array_element, 4u>;
|
||||
arr = array<tint_padded_array_element, 4u>();
|
||||
arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
let x = arr[3].el;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ArrayAsParam) {
|
||||
auto* src = R"(
|
||||
fn f(a : @stride(12) array<i32, 4>) -> i32 {
|
||||
return a[2];
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(12)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
fn f(a : array<tint_padded_array_element, 4u>) -> i32 {
|
||||
return a[2].el;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
// TODO(crbug.com/tint/781): Cannot parse the stride on the return array type.
|
||||
TEST_F(PadArrayElementsTest, DISABLED_ArrayAsReturn) {
|
||||
auto* src = R"(
|
||||
fn f() -> @stride(8) array<i32, 4> {
|
||||
return array<i32, 4>(1, 2, 3, 4);
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
el : i32;
|
||||
@size(4)
|
||||
padding : u32;
|
||||
};
|
||||
|
||||
fn f() -> array<tint_padded_array_element, 4> {
|
||||
return array<tint_padded_array_element, 4>(tint_padded_array_element(1, 0u), tint_padded_array_element(2, 0u), tint_padded_array_element(3, 0u), tint_padded_array_element(4, 0u));
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ArrayAlias) {
|
||||
auto* src = R"(
|
||||
type Array = @stride(16) array<i32, 4>;
|
||||
|
||||
fn f() {
|
||||
var arr : Array;
|
||||
arr = Array();
|
||||
arr = Array(1, 2, 3, 4);
|
||||
let vals : Array = Array(1, 2, 3, 4);
|
||||
arr = vals;
|
||||
let x = arr[3];
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(16)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
type Array = array<tint_padded_array_element, 4u>;
|
||||
|
||||
fn f() {
|
||||
var arr : array<tint_padded_array_element, 4u>;
|
||||
arr = array<tint_padded_array_element, 4u>();
|
||||
arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
let vals : array<tint_padded_array_element, 4u> = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
arr = vals;
|
||||
let x = arr[3].el;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ArrayAlias_OutOfOrder) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
var arr : Array;
|
||||
arr = Array();
|
||||
arr = Array(1, 2, 3, 4);
|
||||
let vals : Array = Array(1, 2, 3, 4);
|
||||
arr = vals;
|
||||
let x = arr[3];
|
||||
}
|
||||
|
||||
type Array = @stride(16) array<i32, 4>;
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(16)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
fn f() {
|
||||
var arr : array<tint_padded_array_element, 4u>;
|
||||
arr = array<tint_padded_array_element, 4u>();
|
||||
arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
let vals : array<tint_padded_array_element, 4u> = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
arr = vals;
|
||||
let x = arr[3].el;
|
||||
}
|
||||
|
||||
type Array = array<tint_padded_array_element, 4u>;
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ArraysInStruct) {
|
||||
auto* src = R"(
|
||||
struct S {
|
||||
a : @stride(8) array<i32, 4>;
|
||||
b : @stride(8) array<i32, 8>;
|
||||
c : @stride(8) array<i32, 4>;
|
||||
d : @stride(12) array<i32, 8>;
|
||||
};
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_1 {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_2 {
|
||||
@size(12)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct S {
|
||||
a : array<tint_padded_array_element, 4u>;
|
||||
b : array<tint_padded_array_element_1, 8u>;
|
||||
c : array<tint_padded_array_element, 4u>;
|
||||
d : array<tint_padded_array_element_2, 8u>;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, ArraysOfArraysInStruct) {
|
||||
auto* src = R"(
|
||||
struct S {
|
||||
a : @stride(512) array<i32, 4>;
|
||||
b : @stride(512) array<@stride(32) array<i32, 4>, 4>;
|
||||
c : @stride(512) array<@stride(64) array<@stride(8) array<i32, 4>, 4>, 4>;
|
||||
};
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(512)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_2 {
|
||||
@size(32)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_1 {
|
||||
@size(512)
|
||||
el : array<tint_padded_array_element_2, 4u>;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_5 {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_4 {
|
||||
@size(64)
|
||||
el : array<tint_padded_array_element_5, 4u>;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_3 {
|
||||
@size(512)
|
||||
el : array<tint_padded_array_element_4, 4u>;
|
||||
}
|
||||
|
||||
struct S {
|
||||
a : array<tint_padded_array_element, 4u>;
|
||||
b : array<tint_padded_array_element_1, 4u>;
|
||||
c : array<tint_padded_array_element_3, 4u>;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, AccessArraysOfArraysInStruct) {
|
||||
auto* src = R"(
|
||||
struct S {
|
||||
a : @stride(512) array<i32, 4>;
|
||||
b : @stride(512) array<@stride(32) array<i32, 4>, 4>;
|
||||
c : @stride(512) array<@stride(64) array<@stride(8) array<i32, 4>, 4>, 4>;
|
||||
};
|
||||
|
||||
fn f(s : S) -> i32 {
|
||||
return s.a[2] + s.b[1][2] + s.c[3][1][2];
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(512)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_2 {
|
||||
@size(32)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_1 {
|
||||
@size(512)
|
||||
el : array<tint_padded_array_element_2, 4u>;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_5 {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_4 {
|
||||
@size(64)
|
||||
el : array<tint_padded_array_element_5, 4u>;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_3 {
|
||||
@size(512)
|
||||
el : array<tint_padded_array_element_4, 4u>;
|
||||
}
|
||||
|
||||
struct S {
|
||||
a : array<tint_padded_array_element, 4u>;
|
||||
b : array<tint_padded_array_element_1, 4u>;
|
||||
c : array<tint_padded_array_element_3, 4u>;
|
||||
}
|
||||
|
||||
fn f(s : S) -> i32 {
|
||||
return ((s.a[2].el + s.b[1].el[2].el) + s.c[3].el[1].el[2].el);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, AccessArraysOfArraysInStruct_OutOfOrder) {
|
||||
auto* src = R"(
|
||||
fn f(s : S) -> i32 {
|
||||
return s.a[2] + s.b[1][2] + s.c[3][1][2];
|
||||
}
|
||||
|
||||
struct S {
|
||||
a : @stride(512) array<i32, 4>;
|
||||
b : @stride(512) array<@stride(32) array<i32, 4>, 4>;
|
||||
c : @stride(512) array<@stride(64) array<@stride(8) array<i32, 4>, 4>, 4>;
|
||||
};
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
@size(512)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_1 {
|
||||
@size(32)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_2 {
|
||||
@size(512)
|
||||
el : array<tint_padded_array_element_1, 4u>;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_3 {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_4 {
|
||||
@size(64)
|
||||
el : array<tint_padded_array_element_3, 4u>;
|
||||
}
|
||||
|
||||
struct tint_padded_array_element_5 {
|
||||
@size(512)
|
||||
el : array<tint_padded_array_element_4, 4u>;
|
||||
}
|
||||
|
||||
fn f(s : S) -> i32 {
|
||||
return ((s.a[2].el + s.b[1].el[2].el) + s.c[3].el[1].el[2].el);
|
||||
}
|
||||
|
||||
struct S {
|
||||
a : array<tint_padded_array_element, 4u>;
|
||||
b : array<tint_padded_array_element_2, 4u>;
|
||||
c : array<tint_padded_array_element_5, 4u>;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, DeclarationOrder) {
|
||||
auto* src = R"(
|
||||
type T0 = i32;
|
||||
|
||||
type T1 = @stride(8) array<i32, 1>;
|
||||
|
||||
type T2 = i32;
|
||||
|
||||
fn f1(a : @stride(8) array<i32, 2>) {
|
||||
}
|
||||
|
||||
type T3 = i32;
|
||||
|
||||
fn f2() {
|
||||
var v : @stride(8) array<i32, 3>;
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
type T0 = i32;
|
||||
|
||||
struct tint_padded_array_element {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
type T1 = array<tint_padded_array_element, 1u>;
|
||||
|
||||
type T2 = i32;
|
||||
|
||||
struct tint_padded_array_element_1 {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
fn f1(a : array<tint_padded_array_element_1, 2u>) {
|
||||
}
|
||||
|
||||
type T3 = i32;
|
||||
|
||||
struct tint_padded_array_element_2 {
|
||||
@size(8)
|
||||
el : i32;
|
||||
}
|
||||
|
||||
fn f2() {
|
||||
var v : array<tint_padded_array_element_2, 3u>;
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace transform
|
||||
} // namespace tint
|
|
@ -1431,7 +1431,7 @@ struct S {
|
|||
};
|
||||
@group(0) @binding(0) var<storage, read> s : S;
|
||||
|
||||
type UArr = @stride(16) array<f32, 4>;
|
||||
type UArr = array<vec4<f32>, 4>;
|
||||
struct U {
|
||||
a : UArr;
|
||||
};
|
||||
|
@ -1451,11 +1451,11 @@ fn f() {
|
|||
var i32_sb4 : f32 = s.b[-1];
|
||||
var i32_sb5 : f32 = s.b[-4];
|
||||
|
||||
var i32_ua1 : f32 = u.a[4];
|
||||
var i32_ua2 : f32 = u.a[1];
|
||||
var i32_ua3 : f32 = u.a[0];
|
||||
var i32_ua4 : f32 = u.a[-1];
|
||||
var i32_ua5 : f32 = u.a[-4];
|
||||
var i32_ua1 : f32 = u.a[4].x;
|
||||
var i32_ua2 : f32 = u.a[1].x;
|
||||
var i32_ua3 : f32 = u.a[0].x;
|
||||
var i32_ua4 : f32 = u.a[-1].x;
|
||||
var i32_ua5 : f32 = u.a[-4].x;
|
||||
|
||||
// Unsigned
|
||||
var u32_sa1 : f32 = s.a[0u];
|
||||
|
@ -1472,12 +1472,12 @@ fn f() {
|
|||
var u32_sb5 : f32 = s.b[10u];
|
||||
var u32_sb6 : f32 = s.b[100u];
|
||||
|
||||
var u32_ua1 : f32 = u.a[0u];
|
||||
var u32_ua2 : f32 = u.a[1u];
|
||||
var u32_ua3 : f32 = u.a[3u];
|
||||
var u32_ua4 : f32 = u.a[4u];
|
||||
var u32_ua5 : f32 = u.a[10u];
|
||||
var u32_ua6 : f32 = u.a[100u];
|
||||
var u32_ua1 : f32 = u.a[0u].x;
|
||||
var u32_ua2 : f32 = u.a[1u].x;
|
||||
var u32_ua3 : f32 = u.a[3u].x;
|
||||
var u32_ua4 : f32 = u.a[4u].x;
|
||||
var u32_ua5 : f32 = u.a[10u].x;
|
||||
var u32_ua6 : f32 = u.a[100u].x;
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -1490,7 +1490,7 @@ struct S {
|
|||
|
||||
@group(0) @binding(0) var<storage, read> s : S;
|
||||
|
||||
type UArr = @stride(16) array<f32, 4>;
|
||||
type UArr = array<vec4<f32>, 4>;
|
||||
|
||||
struct U {
|
||||
a : UArr;
|
||||
|
@ -1509,11 +1509,11 @@ fn f() {
|
|||
var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
|
||||
var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
|
||||
var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
|
||||
var i32_ua1 : f32 = u.a[3];
|
||||
var i32_ua2 : f32 = u.a[1];
|
||||
var i32_ua3 : f32 = u.a[0];
|
||||
var i32_ua4 : f32 = u.a[0];
|
||||
var i32_ua5 : f32 = u.a[0];
|
||||
var i32_ua1 : f32 = u.a[3].x;
|
||||
var i32_ua2 : f32 = u.a[1].x;
|
||||
var i32_ua3 : f32 = u.a[0].x;
|
||||
var i32_ua4 : f32 = u.a[0].x;
|
||||
var i32_ua5 : f32 = u.a[0].x;
|
||||
var u32_sa1 : f32 = s.a[0u];
|
||||
var u32_sa2 : f32 = s.a[1u];
|
||||
var u32_sa3 : f32 = s.a[3u];
|
||||
|
@ -1526,12 +1526,12 @@ fn f() {
|
|||
var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
|
||||
var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))];
|
||||
var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))];
|
||||
var u32_ua1 : f32 = u.a[0u];
|
||||
var u32_ua2 : f32 = u.a[1u];
|
||||
var u32_ua3 : f32 = u.a[3u];
|
||||
var u32_ua4 : f32 = u.a[3u];
|
||||
var u32_ua5 : f32 = u.a[3u];
|
||||
var u32_ua6 : f32 = u.a[3u];
|
||||
var u32_ua1 : f32 = u.a[0u].x;
|
||||
var u32_ua2 : f32 = u.a[1u].x;
|
||||
var u32_ua3 : f32 = u.a[3u].x;
|
||||
var u32_ua4 : f32 = u.a[3u].x;
|
||||
var u32_ua5 : f32 = u.a[3u].x;
|
||||
var u32_ua6 : f32 = u.a[3u].x;
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -1553,7 +1553,7 @@ struct S {
|
|||
|
||||
@group(0) @binding(0) var<storage, read> s : S;
|
||||
|
||||
type UArr = @stride(16) array<f32, 4>;
|
||||
type UArr = array<vec4<f32>, 4>;
|
||||
|
||||
struct U {
|
||||
a : UArr;
|
||||
|
@ -1572,11 +1572,11 @@ fn f() {
|
|||
var i32_sb3 : f32 = s.b[0];
|
||||
var i32_sb4 : f32 = s.b[-1];
|
||||
var i32_sb5 : f32 = s.b[-4];
|
||||
var i32_ua1 : f32 = u.a[3];
|
||||
var i32_ua2 : f32 = u.a[1];
|
||||
var i32_ua3 : f32 = u.a[0];
|
||||
var i32_ua4 : f32 = u.a[0];
|
||||
var i32_ua5 : f32 = u.a[0];
|
||||
var i32_ua1 : f32 = u.a[3].x;
|
||||
var i32_ua2 : f32 = u.a[1].x;
|
||||
var i32_ua3 : f32 = u.a[0].x;
|
||||
var i32_ua4 : f32 = u.a[0].x;
|
||||
var i32_ua5 : f32 = u.a[0].x;
|
||||
var u32_sa1 : f32 = s.a[0u];
|
||||
var u32_sa2 : f32 = s.a[1u];
|
||||
var u32_sa3 : f32 = s.a[3u];
|
||||
|
@ -1589,12 +1589,12 @@ fn f() {
|
|||
var u32_sb4 : f32 = s.b[4u];
|
||||
var u32_sb5 : f32 = s.b[10u];
|
||||
var u32_sb6 : f32 = s.b[100u];
|
||||
var u32_ua1 : f32 = u.a[0u];
|
||||
var u32_ua2 : f32 = u.a[1u];
|
||||
var u32_ua3 : f32 = u.a[3u];
|
||||
var u32_ua4 : f32 = u.a[3u];
|
||||
var u32_ua5 : f32 = u.a[3u];
|
||||
var u32_ua6 : f32 = u.a[3u];
|
||||
var u32_ua1 : f32 = u.a[0u].x;
|
||||
var u32_ua2 : f32 = u.a[1u].x;
|
||||
var u32_ua3 : f32 = u.a[3u].x;
|
||||
var u32_ua4 : f32 = u.a[3u].x;
|
||||
var u32_ua5 : f32 = u.a[3u].x;
|
||||
var u32_ua6 : f32 = u.a[3u].x;
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -1618,7 +1618,7 @@ struct S {
|
|||
|
||||
@group(0) @binding(0) var<storage, read> s : S;
|
||||
|
||||
type UArr = @stride(16) array<f32, 4>;
|
||||
type UArr = array<vec4<f32>, 4>;
|
||||
|
||||
struct U {
|
||||
a : UArr;
|
||||
|
@ -1637,11 +1637,11 @@ fn f() {
|
|||
var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
|
||||
var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
|
||||
var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
|
||||
var i32_ua1 : f32 = u.a[4];
|
||||
var i32_ua2 : f32 = u.a[1];
|
||||
var i32_ua3 : f32 = u.a[0];
|
||||
var i32_ua4 : f32 = u.a[-1];
|
||||
var i32_ua5 : f32 = u.a[-4];
|
||||
var i32_ua1 : f32 = u.a[4].x;
|
||||
var i32_ua2 : f32 = u.a[1].x;
|
||||
var i32_ua3 : f32 = u.a[0].x;
|
||||
var i32_ua4 : f32 = u.a[-1].x;
|
||||
var i32_ua5 : f32 = u.a[-4].x;
|
||||
var u32_sa1 : f32 = s.a[0u];
|
||||
var u32_sa2 : f32 = s.a[1u];
|
||||
var u32_sa3 : f32 = s.a[3u];
|
||||
|
@ -1654,12 +1654,12 @@ fn f() {
|
|||
var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
|
||||
var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))];
|
||||
var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))];
|
||||
var u32_ua1 : f32 = u.a[0u];
|
||||
var u32_ua2 : f32 = u.a[1u];
|
||||
var u32_ua3 : f32 = u.a[3u];
|
||||
var u32_ua4 : f32 = u.a[4u];
|
||||
var u32_ua5 : f32 = u.a[10u];
|
||||
var u32_ua6 : f32 = u.a[100u];
|
||||
var u32_ua1 : f32 = u.a[0u].x;
|
||||
var u32_ua2 : f32 = u.a[1u].x;
|
||||
var u32_ua3 : f32 = u.a[3u].x;
|
||||
var u32_ua4 : f32 = u.a[4u].x;
|
||||
var u32_ua5 : f32 = u.a[10u].x;
|
||||
var u32_ua6 : f32 = u.a[100u].x;
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -1683,7 +1683,7 @@ struct S {
|
|||
|
||||
@group(0) @binding(0) var<storage, read> s : S;
|
||||
|
||||
type UArr = @stride(16) array<f32, 4>;
|
||||
type UArr = array<vec4<f32>, 4>;
|
||||
|
||||
struct U {
|
||||
a : UArr;
|
||||
|
@ -1702,11 +1702,11 @@ fn f() {
|
|||
var i32_sb3 : f32 = s.b[0];
|
||||
var i32_sb4 : f32 = s.b[-1];
|
||||
var i32_sb5 : f32 = s.b[-4];
|
||||
var i32_ua1 : f32 = u.a[4];
|
||||
var i32_ua2 : f32 = u.a[1];
|
||||
var i32_ua3 : f32 = u.a[0];
|
||||
var i32_ua4 : f32 = u.a[-1];
|
||||
var i32_ua5 : f32 = u.a[-4];
|
||||
var i32_ua1 : f32 = u.a[4].x;
|
||||
var i32_ua2 : f32 = u.a[1].x;
|
||||
var i32_ua3 : f32 = u.a[0].x;
|
||||
var i32_ua4 : f32 = u.a[-1].x;
|
||||
var i32_ua5 : f32 = u.a[-4].x;
|
||||
var u32_sa1 : f32 = s.a[0u];
|
||||
var u32_sa2 : f32 = s.a[1u];
|
||||
var u32_sa3 : f32 = s.a[3u];
|
||||
|
@ -1719,12 +1719,12 @@ fn f() {
|
|||
var u32_sb4 : f32 = s.b[4u];
|
||||
var u32_sb5 : f32 = s.b[10u];
|
||||
var u32_sb6 : f32 = s.b[100u];
|
||||
var u32_ua1 : f32 = u.a[0u];
|
||||
var u32_ua2 : f32 = u.a[1u];
|
||||
var u32_ua3 : f32 = u.a[3u];
|
||||
var u32_ua4 : f32 = u.a[4u];
|
||||
var u32_ua5 : f32 = u.a[10u];
|
||||
var u32_ua6 : f32 = u.a[100u];
|
||||
var u32_ua1 : f32 = u.a[0u].x;
|
||||
var u32_ua2 : f32 = u.a[1u].x;
|
||||
var u32_ua3 : f32 = u.a[3u].x;
|
||||
var u32_ua4 : f32 = u.a[4u].x;
|
||||
var u32_ua5 : f32 = u.a[10u].x;
|
||||
var u32_ua6 : f32 = u.a[100u].x;
|
||||
}
|
||||
)";
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ struct State {
|
|||
ctx.dst->Symbols().New(kStructName),
|
||||
{
|
||||
ctx.dst->Member(GetStructBufferName(),
|
||||
ctx.dst->ty.array<ProgramBuilder::u32>(4)),
|
||||
ctx.dst->ty.array<ProgramBuilder::u32>()),
|
||||
});
|
||||
for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
|
||||
// The decorated variable with struct type
|
||||
|
|
|
@ -108,7 +108,7 @@ fn main() -> @builtin(position) vec4<f32> {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@stage(vertex)
|
||||
|
@ -137,7 +137,7 @@ fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -175,7 +175,7 @@ fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -213,7 +213,7 @@ fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(5) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -256,7 +256,7 @@ fn main(inputs : Inputs) -> @builtin(position) vec4<f32> {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -304,7 +304,7 @@ fn main(@location(0) var_a : f32,
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -364,7 +364,7 @@ fn main(inputs : Inputs) -> @builtin(position) vec4<f32> {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -444,7 +444,7 @@ struct Inputs {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -526,7 +526,7 @@ fn main(inputs : Inputs, indices : Indices) -> @builtin(position) vec4<f32> {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -603,7 +603,7 @@ struct Indices {
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -670,7 +670,7 @@ fn main(@location(0) var_a : f32,
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -715,7 +715,7 @@ fn main(@location(0) var_a : vec2<f32>,
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -771,7 +771,7 @@ fn main(@location(0) var_a : f32,
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data_1 : @stride(4) array<u32>;
|
||||
tint_vertex_data_1 : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0_1 : TintVertexData;
|
||||
|
@ -848,7 +848,7 @@ fn main(
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -1008,7 +1008,7 @@ fn main(
|
|||
auto* expect =
|
||||
R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
@ -1167,7 +1167,7 @@ fn main(
|
|||
|
||||
auto* expect = R"(
|
||||
struct TintVertexData {
|
||||
tint_vertex_data : @stride(4) array<u32>;
|
||||
tint_vertex_data : array<u32>;
|
||||
}
|
||||
|
||||
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
|
||||
|
|
|
@ -363,7 +363,7 @@ void main() {
|
|||
TEST_F(GlslGeneratorImplTest_MemberAccessor,
|
||||
EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray) {
|
||||
// struct Data {
|
||||
// a : @stride(4) array<i32, 5>;
|
||||
// a : array<i32, 5>;
|
||||
// };
|
||||
// var<storage> data : Data;
|
||||
// data.a[2];
|
||||
|
@ -409,7 +409,7 @@ void main() {
|
|||
TEST_F(GlslGeneratorImplTest_MemberAccessor,
|
||||
EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
|
||||
// struct Data {
|
||||
// a : @stride(4) array<i32, 5>;
|
||||
// a : array<i32, 5>;
|
||||
// };
|
||||
// var<storage> data : Data;
|
||||
// data.a[(2 + 4) - 3];
|
||||
|
@ -455,7 +455,7 @@ void main() {
|
|||
|
||||
TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) {
|
||||
// struct Data {
|
||||
// a : @stride(4) array<i32, 5>;
|
||||
// a : array<i32, 5>;
|
||||
// };
|
||||
// var<storage> data : Data;
|
||||
// data.a[2] = 2;
|
||||
|
@ -503,7 +503,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -562,7 +562,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -623,7 +623,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -684,7 +684,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -744,7 +744,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -802,7 +802,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
#include "src/tint/transform/loop_to_for_loop.h"
|
||||
#include "src/tint/transform/manager.h"
|
||||
#include "src/tint/transform/num_workgroups_from_uniform.h"
|
||||
#include "src/tint/transform/pad_array_elements.h"
|
||||
#include "src/tint/transform/promote_initializers_to_const_var.h"
|
||||
#include "src/tint/transform/promote_side_effects_to_decl.h"
|
||||
#include "src/tint/transform/remove_phonies.h"
|
||||
|
@ -209,7 +208,6 @@ SanitizedResult Sanitize(
|
|||
manager.Add<transform::CalculateArrayLength>();
|
||||
manager.Add<transform::PromoteInitializersToConstVar>();
|
||||
|
||||
manager.Add<transform::PadArrayElements>();
|
||||
manager.Add<transform::AddEmptyEntryPoint>();
|
||||
|
||||
data.Add<transform::CanonicalizeEntryPointIO::Config>(
|
||||
|
|
|
@ -391,7 +391,7 @@ void main() {
|
|||
TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
||||
EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray) {
|
||||
// struct Data {
|
||||
// a : @stride(4) array<i32, 5>;
|
||||
// a : array<i32, 5>;
|
||||
// };
|
||||
// var<storage> data : Data;
|
||||
// data.a[2];
|
||||
|
@ -423,7 +423,7 @@ void main() {
|
|||
TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
||||
EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
|
||||
// struct Data {
|
||||
// a : @stride(4) array<i32, 5>;
|
||||
// a : array<i32, 5>;
|
||||
// };
|
||||
// var<storage> data : Data;
|
||||
// data.a[(2 + 4) - 3];
|
||||
|
@ -455,7 +455,7 @@ void main() {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) {
|
||||
// struct Data {
|
||||
// a : @stride(4) array<i32, 5>;
|
||||
// a : array<i32, 5>;
|
||||
// };
|
||||
// var<storage> data : Data;
|
||||
// data.a[2] = 2;
|
||||
|
@ -489,7 +489,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -531,7 +531,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -575,7 +575,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -619,7 +619,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -662,7 +662,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
@ -703,7 +703,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
|||
// b : vec3<f32>;
|
||||
// };
|
||||
// struct Data {
|
||||
// var c : @stride(32) array<Inner, 4>;
|
||||
// var c : array<Inner, 4>;
|
||||
// };
|
||||
//
|
||||
// var<storage> data : Pre;
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
#include "src/tint/transform/canonicalize_entry_point_io.h"
|
||||
#include "src/tint/transform/manager.h"
|
||||
#include "src/tint/transform/module_scope_var_to_entry_point_param.h"
|
||||
#include "src/tint/transform/pad_array_elements.h"
|
||||
#include "src/tint/transform/promote_initializers_to_const_var.h"
|
||||
#include "src/tint/transform/promote_side_effects_to_decl.h"
|
||||
#include "src/tint/transform/remove_phonies.h"
|
||||
|
@ -179,7 +178,6 @@ SanitizedResult Sanitize(
|
|||
|
||||
manager.Add<transform::VectorizeScalarMatrixConstructors>();
|
||||
manager.Add<transform::WrapArraysInStructs>();
|
||||
manager.Add<transform::PadArrayElements>();
|
||||
manager.Add<transform::RemovePhonies>();
|
||||
manager.Add<transform::SimplifyPointers>();
|
||||
// ArrayLengthFromUniform must come after SimplifyPointers, as
|
||||
|
@ -2945,9 +2943,8 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(
|
|||
|
||||
[&](const sem::Array* arr) {
|
||||
if (!arr->IsStrideImplicit()) {
|
||||
TINT_ICE(Writer, diagnostics_)
|
||||
<< "arrays with explicit strides should have "
|
||||
"removed with the PadArrayElements transform";
|
||||
TINT_ICE(Writer, diagnostics_) << "arrays with explicit strides not "
|
||||
"exist past the SPIR-V reader";
|
||||
return SizeAndAlign{};
|
||||
}
|
||||
auto num_els = std::max<uint32_t>(arr->Count(), 1);
|
||||
|
|
|
@ -119,30 +119,6 @@ TEST_F(MslGeneratorImplTest, EmitType_RuntimeArray) {
|
|||
EXPECT_EQ(out.str(), "bool ary[1]");
|
||||
}
|
||||
|
||||
TEST_F(MslGeneratorImplTest, EmitType_ArrayWithStride) {
|
||||
auto* s = Structure("s", {Member("arr", ty.array<f32, 4>(64))});
|
||||
auto* ubo = Global("ubo", ty.Of(s), ast::StorageClass::kUniform,
|
||||
ast::AttributeList{
|
||||
create<ast::GroupAttribute>(0),
|
||||
create<ast::BindingAttribute>(1),
|
||||
});
|
||||
WrapInFunction(MemberAccessor(ubo, "arr"));
|
||||
|
||||
GeneratorImpl& gen = SanitizeAndBuild();
|
||||
|
||||
ASSERT_TRUE(gen.Generate()) << gen.error();
|
||||
EXPECT_THAT(gen.result(), HasSubstr(R"(struct tint_padded_array_element {
|
||||
/* 0x0000 */ float el;
|
||||
/* 0x0004 */ int8_t tint_pad[60];
|
||||
};)"));
|
||||
EXPECT_THAT(gen.result(), HasSubstr(R"(struct tint_array_wrapper {
|
||||
/* 0x0000 */ tint_padded_array_element arr[4];
|
||||
};)"));
|
||||
EXPECT_THAT(gen.result(), HasSubstr(R"(struct s {
|
||||
/* 0x0000 */ tint_array_wrapper arr;
|
||||
};)"));
|
||||
}
|
||||
|
||||
TEST_F(MslGeneratorImplTest, EmitType_Bool) {
|
||||
auto* bool_ = create<sem::Bool>();
|
||||
|
||||
|
|
|
@ -1622,7 +1622,7 @@ OpReturn
|
|||
|
||||
TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) {
|
||||
// struct my_struct {
|
||||
// a : @stride(4) array<f32>;
|
||||
// a : array<f32>;
|
||||
// };
|
||||
// @binding(1) @group(2) var<storage, read> b : my_struct;
|
||||
//
|
||||
|
|
|
@ -327,7 +327,6 @@ tint_unittests_source_set("tint_unittests_transform_src") {
|
|||
"../../src/tint/transform/module_scope_var_to_entry_point_param_test.cc",
|
||||
"../../src/tint/transform/multiplanar_external_texture_test.cc",
|
||||
"../../src/tint/transform/num_workgroups_from_uniform_test.cc",
|
||||
"../../src/tint/transform/pad_array_elements_test.cc",
|
||||
"../../src/tint/transform/promote_initializers_to_const_var_test.cc",
|
||||
"../../src/tint/transform/promote_side_effects_to_decl_test.cc",
|
||||
"../../src/tint/transform/remove_phonies_test.cc",
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
#version 310 es
|
||||
|
||||
float tint_float_modulo(float lhs, float rhs) {
|
||||
return (lhs - rhs * trunc(lhs / rhs));
|
||||
}
|
||||
|
||||
|
||||
layout(location = 0) in vec4 position_1;
|
||||
layout(location = 1) in vec4 color_1;
|
||||
layout(location = 0) out vec4 v_color_1;
|
||||
struct Time {
|
||||
float value;
|
||||
};
|
||||
|
||||
struct Uniforms {
|
||||
float scale;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
float scalar;
|
||||
float scalarOffset;
|
||||
};
|
||||
|
||||
layout(binding = 0) uniform Time_1 {
|
||||
float value;
|
||||
} time;
|
||||
|
||||
layout(binding = 1) uniform Uniforms_1 {
|
||||
float scale;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
float scalar;
|
||||
float scalarOffset;
|
||||
} uniforms;
|
||||
|
||||
struct VertexOutput {
|
||||
vec4 Position;
|
||||
vec4 v_color;
|
||||
};
|
||||
|
||||
VertexOutput vert_main(vec4 position, vec4 color) {
|
||||
float fade = tint_float_modulo((uniforms.scalarOffset + ((time.value * uniforms.scalar) / 10.0f)), 1.0f);
|
||||
if ((fade < 0.5f)) {
|
||||
fade = (fade * 2.0f);
|
||||
} else {
|
||||
fade = ((1.0f - fade) * 2.0f);
|
||||
}
|
||||
float xpos = (position.x * uniforms.scale);
|
||||
float ypos = (position.y * uniforms.scale);
|
||||
float angle = ((3.141590118f * 2.0f) * fade);
|
||||
float xrot = ((xpos * cos(angle)) - (ypos * sin(angle)));
|
||||
float yrot = ((xpos * sin(angle)) + (ypos * cos(angle)));
|
||||
xpos = (xrot + uniforms.offsetX);
|
||||
ypos = (yrot + uniforms.offsetY);
|
||||
VertexOutput tint_symbol = VertexOutput(vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
tint_symbol.v_color = (vec4(fade, (1.0f - fade), 0.0f, 1.0f) + color);
|
||||
tint_symbol.Position = vec4(xpos, ypos, 0.0f, 1.0f);
|
||||
return tint_symbol;
|
||||
}
|
||||
|
||||
void main() {
|
||||
VertexOutput inner_result = vert_main(position_1, color_1);
|
||||
gl_Position = inner_result.Position;
|
||||
v_color_1 = inner_result.v_color;
|
||||
gl_Position.y = -(gl_Position.y);
|
||||
gl_Position.z = ((2.0f * gl_Position.z) - gl_Position.w);
|
||||
return;
|
||||
}
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(location = 0) in vec4 v_color_1;
|
||||
layout(location = 0) out vec4 value_1;
|
||||
struct Time {
|
||||
float value;
|
||||
};
|
||||
|
||||
struct Uniforms {
|
||||
float scale;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
float scalar;
|
||||
float scalarOffset;
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
vec4 Position;
|
||||
vec4 v_color;
|
||||
};
|
||||
|
||||
vec4 frag_main(vec4 v_color) {
|
||||
return v_color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 inner_result = frag_main(v_color_1);
|
||||
value_1 = inner_result;
|
||||
return;
|
||||
}
|
|
@ -48,7 +48,7 @@ struct GlobalLights {
|
|||
dirIntensity : f32;
|
||||
dirDirection : vec3<f32>;
|
||||
lightCount : u32;
|
||||
lights : @stride(32) array<Light>;
|
||||
lights : array<Light>;
|
||||
}
|
||||
|
||||
@binding(2) @group(0) var<storage, read> globalLights : GlobalLights;
|
||||
|
|
|
@ -1,381 +0,0 @@
|
|||
benchmark/skinned-shadowed-pbr-fragment.wgsl:51:13 warning: use of deprecated language feature: the @stride attribute is deprecated; use a larger type if necessary
|
||||
lights : @stride(32) array<Light>;
|
||||
^^^^^^
|
||||
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(location = 0) in vec3 worldPos_1;
|
||||
layout(location = 1) in vec3 view_1;
|
||||
layout(location = 2) in vec2 texcoord_1;
|
||||
layout(location = 3) in vec2 texcoord2_1;
|
||||
layout(location = 4) in vec4 color_1;
|
||||
layout(location = 5) in vec4 instanceColor_1;
|
||||
layout(location = 6) in vec3 normal_1;
|
||||
layout(location = 7) in vec3 tangent_1;
|
||||
layout(location = 8) in vec3 bitangent_1;
|
||||
layout(location = 0) out vec4 color_2;
|
||||
layout(location = 1) out vec4 emissive_1;
|
||||
const float GAMMA = 2.200000048f;
|
||||
vec3 linearTosRGB(vec3 linear) {
|
||||
float INV_GAMMA = (1.0f / GAMMA);
|
||||
return pow(linear, vec3(INV_GAMMA));
|
||||
}
|
||||
|
||||
struct Camera {
|
||||
mat4 projection;
|
||||
mat4 inverseProjection;
|
||||
mat4 view;
|
||||
vec3 position;
|
||||
float time;
|
||||
vec2 outputSize;
|
||||
float zNear;
|
||||
float zFar;
|
||||
};
|
||||
|
||||
layout(binding = 0) uniform Camera_1 {
|
||||
mat4 projection;
|
||||
mat4 inverseProjection;
|
||||
mat4 view;
|
||||
vec3 position;
|
||||
float time;
|
||||
vec2 outputSize;
|
||||
float zNear;
|
||||
float zFar;
|
||||
} camera;
|
||||
|
||||
struct ClusterLights {
|
||||
uint offset;
|
||||
uint count;
|
||||
};
|
||||
|
||||
struct ClusterLightGroup {
|
||||
uint offset;
|
||||
ClusterLights lights[27648];
|
||||
uint indices[1769472];
|
||||
};
|
||||
|
||||
layout(binding = 1, std430) buffer ClusterLightGroup_1 {
|
||||
uint offset;
|
||||
ClusterLights lights[27648];
|
||||
uint indices[1769472];
|
||||
} clusterLights;
|
||||
struct Light {
|
||||
vec3 position;
|
||||
float range;
|
||||
vec3 color;
|
||||
float intensity;
|
||||
};
|
||||
|
||||
layout(binding = 2, std430) buffer GlobalLights_1 {
|
||||
vec3 ambient;
|
||||
vec3 dirColor;
|
||||
float dirIntensity;
|
||||
vec3 dirDirection;
|
||||
uint lightCount;
|
||||
Light lights[];
|
||||
} globalLights;
|
||||
const uvec3 tileCount = uvec3(32u, 18u, 48u);
|
||||
float linearDepth(float depthSample) {
|
||||
return ((camera.zFar * camera.zNear) / ((depthSample) * ((camera.zNear - camera.zFar)) + (camera.zFar)));
|
||||
}
|
||||
|
||||
uvec3 getTile(vec4 fragCoord) {
|
||||
float sliceScale = (float(tileCount.z) / log2((camera.zFar / camera.zNear)));
|
||||
float sliceBias = -(((float(tileCount.z) * log2(camera.zNear)) / log2((camera.zFar / camera.zNear))));
|
||||
float tint_symbol_3 = linearDepth(fragCoord.z);
|
||||
float tint_symbol_4 = log2(tint_symbol_3);
|
||||
float tint_symbol_5 = max(((tint_symbol_4 * sliceScale) + sliceBias), 0.0f);
|
||||
uint zTile = uint(tint_symbol_5);
|
||||
return uvec3(uint((fragCoord.x / (camera.outputSize.x / float(tileCount.x)))), uint((fragCoord.y / (camera.outputSize.y / float(tileCount.y)))), zTile);
|
||||
}
|
||||
|
||||
uint getClusterIndex(vec4 fragCoord) {
|
||||
uvec3 tile = getTile(fragCoord);
|
||||
return ((tile.x + (tile.y * tileCount.x)) + ((tile.z * tileCount.x) * tileCount.y));
|
||||
}
|
||||
|
||||
layout(binding = 6, std430) buffer LightShadowTable_1 {
|
||||
int light[];
|
||||
} lightShadowTable;
|
||||
vec2 shadowSampleOffsets[16] = vec2[16](vec2(-1.5f, -1.5f), vec2(-1.5f, -0.5f), vec2(-1.5f, 0.5f), vec2(-1.5f, 1.5f), vec2(-0.5f, -1.5f), vec2(-0.5f, -0.5f), vec2(-0.5f, 0.5f), vec2(-0.5f, 1.5f), vec2(0.5f, -1.5f), vec2(0.5f, -0.5f), vec2(0.5f, 0.5f), vec2(0.5f, 1.5f), vec2(1.5f, -1.5f), vec2(1.5f, -0.5f), vec2(1.5f, 0.5f), vec2(1.5f, 1.5f));
|
||||
const uint shadowSampleCount = 16u;
|
||||
struct ShadowProperties {
|
||||
vec4 viewport;
|
||||
mat4 viewProj;
|
||||
};
|
||||
|
||||
layout(binding = 7, std430) buffer LightShadows_1 {
|
||||
ShadowProperties properties[];
|
||||
} shadow;
|
||||
uniform highp sampler2D shadowTexture_1;
|
||||
uniform highp sampler2DShadow shadowTexture_shadowSampler;
|
||||
|
||||
float dirLightVisibility(vec3 worldPos) {
|
||||
int shadowIndex = lightShadowTable.light[0u];
|
||||
if ((shadowIndex == -1)) {
|
||||
return 1.0f;
|
||||
}
|
||||
vec4 viewport = shadow.properties[shadowIndex].viewport;
|
||||
vec4 lightPos = (shadow.properties[shadowIndex].viewProj * vec4(worldPos, 1.0f));
|
||||
vec3 shadowPos = vec3((((lightPos.xy / lightPos.w) * vec2(0.5f, -0.5f)) + vec2(0.5f, 0.5f)), (lightPos.z / lightPos.w));
|
||||
vec2 viewportPos = vec2((viewport.xy + (shadowPos.xy * viewport.zw)));
|
||||
vec2 texelSize = (1.0f / vec2(textureSize(shadowTexture_1, 0)));
|
||||
vec4 clampRect = vec4((viewport.xy - texelSize), ((viewport.xy + viewport.zw) + texelSize));
|
||||
float visibility = 0.0f;
|
||||
{
|
||||
for(uint i = 0u; (i < shadowSampleCount); i = (i + 1u)) {
|
||||
visibility = (visibility + texture(shadowTexture_shadowSampler, vec3(clamp((viewportPos + (shadowSampleOffsets[i] * texelSize)), clampRect.xy, clampRect.zw), (shadowPos.z - 0.003f))));
|
||||
}
|
||||
}
|
||||
return (visibility / float(shadowSampleCount));
|
||||
}
|
||||
|
||||
int getCubeFace(vec3 v) {
|
||||
vec3 vAbs = abs(v);
|
||||
bool tint_tmp = (vAbs.z >= vAbs.x);
|
||||
if (tint_tmp) {
|
||||
tint_tmp = (vAbs.z >= vAbs.y);
|
||||
}
|
||||
if ((tint_tmp)) {
|
||||
if ((v.z < 0.0f)) {
|
||||
return 5;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
if ((vAbs.y >= vAbs.x)) {
|
||||
if ((v.y < 0.0f)) {
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
if ((v.x < 0.0f)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float pointLightVisibility(uint lightIndex, vec3 worldPos, vec3 pointToLight) {
|
||||
int shadowIndex = lightShadowTable.light[(lightIndex + 1u)];
|
||||
if ((shadowIndex == -1)) {
|
||||
return 1.0f;
|
||||
}
|
||||
int tint_symbol_6 = shadowIndex;
|
||||
int tint_symbol_7 = getCubeFace((pointToLight * -1.0f));
|
||||
shadowIndex = (tint_symbol_6 + tint_symbol_7);
|
||||
vec4 viewport = shadow.properties[shadowIndex].viewport;
|
||||
vec4 lightPos = (shadow.properties[shadowIndex].viewProj * vec4(worldPos, 1.0f));
|
||||
vec3 shadowPos = vec3((((lightPos.xy / lightPos.w) * vec2(0.5f, -0.5f)) + vec2(0.5f, 0.5f)), (lightPos.z / lightPos.w));
|
||||
vec2 viewportPos = vec2((viewport.xy + (shadowPos.xy * viewport.zw)));
|
||||
vec2 texelSize = (1.0f / vec2(textureSize(shadowTexture_1, 0)));
|
||||
vec4 clampRect = vec4(viewport.xy, (viewport.xy + viewport.zw));
|
||||
float visibility = 0.0f;
|
||||
{
|
||||
for(uint i = 0u; (i < shadowSampleCount); i = (i + 1u)) {
|
||||
visibility = (visibility + texture(shadowTexture_shadowSampler, vec3(clamp((viewportPos + (shadowSampleOffsets[i] * texelSize)), clampRect.xy, clampRect.zw), (shadowPos.z - 0.01f))));
|
||||
}
|
||||
}
|
||||
return (visibility / float(shadowSampleCount));
|
||||
}
|
||||
|
||||
struct VertexOutput {
|
||||
vec4 position;
|
||||
vec3 worldPos;
|
||||
vec3 view;
|
||||
vec2 texcoord;
|
||||
vec2 texcoord2;
|
||||
vec4 color;
|
||||
vec4 instanceColor;
|
||||
vec3 normal;
|
||||
vec3 tangent;
|
||||
vec3 bitangent;
|
||||
};
|
||||
|
||||
struct Material {
|
||||
vec4 baseColorFactor;
|
||||
vec3 emissiveFactor;
|
||||
float occlusionStrength;
|
||||
vec2 metallicRoughnessFactor;
|
||||
float alphaCutoff;
|
||||
};
|
||||
|
||||
layout(binding = 8) uniform Material_1 {
|
||||
vec4 baseColorFactor;
|
||||
vec3 emissiveFactor;
|
||||
float occlusionStrength;
|
||||
vec2 metallicRoughnessFactor;
|
||||
float alphaCutoff;
|
||||
} material;
|
||||
|
||||
struct SurfaceInfo {
|
||||
vec4 baseColor;
|
||||
vec3 albedo;
|
||||
float metallic;
|
||||
float roughness;
|
||||
vec3 normal;
|
||||
vec3 f0;
|
||||
float ao;
|
||||
vec3 emissive;
|
||||
vec3 v;
|
||||
};
|
||||
|
||||
uniform highp sampler2D normalTexture_normalSampler;
|
||||
uniform highp sampler2D baseColorTexture_baseColorSampler;
|
||||
uniform highp sampler2D metallicRoughnessTexture_metallicRoughnessSampler;
|
||||
uniform highp sampler2D occlusionTexture_occlusionSampler;
|
||||
uniform highp sampler2D emissiveTexture_emissiveSampler;
|
||||
|
||||
SurfaceInfo GetSurfaceInfo(VertexOutput tint_symbol) {
|
||||
SurfaceInfo surface = SurfaceInfo(vec4(0.0f, 0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f), 0.0f, 0.0f, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f), 0.0f, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f));
|
||||
surface.v = normalize(tint_symbol.view);
|
||||
mat3 tbn = mat3(tint_symbol.tangent, tint_symbol.bitangent, tint_symbol.normal);
|
||||
vec3 normalMap = texture(normalTexture_normalSampler, tint_symbol.texcoord).rgb;
|
||||
surface.normal = normalize((tbn * ((2.0f * normalMap) - vec3(1.0f))));
|
||||
vec4 baseColorMap = texture(baseColorTexture_baseColorSampler, tint_symbol.texcoord);
|
||||
surface.baseColor = ((tint_symbol.color * material.baseColorFactor) * baseColorMap);
|
||||
if ((surface.baseColor.a < material.alphaCutoff)) {
|
||||
discard;
|
||||
}
|
||||
surface.albedo = surface.baseColor.rgb;
|
||||
vec4 metallicRoughnessMap = texture(metallicRoughnessTexture_metallicRoughnessSampler, tint_symbol.texcoord);
|
||||
surface.metallic = (material.metallicRoughnessFactor.x * metallicRoughnessMap.b);
|
||||
surface.roughness = (material.metallicRoughnessFactor.y * metallicRoughnessMap.g);
|
||||
vec3 dielectricSpec = vec3(0.039999999f);
|
||||
surface.f0 = mix(dielectricSpec, surface.albedo, vec3(surface.metallic));
|
||||
vec4 occlusionMap = texture(occlusionTexture_occlusionSampler, tint_symbol.texcoord);
|
||||
surface.ao = (material.occlusionStrength * occlusionMap.r);
|
||||
vec4 emissiveMap = texture(emissiveTexture_emissiveSampler, tint_symbol.texcoord);
|
||||
surface.emissive = (material.emissiveFactor * emissiveMap.rgb);
|
||||
if ((tint_symbol.instanceColor.a == 0.0f)) {
|
||||
surface.albedo = (surface.albedo + tint_symbol.instanceColor.rgb);
|
||||
} else {
|
||||
surface.albedo = (surface.albedo * tint_symbol.instanceColor.rgb);
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
const float PI = 3.141592741f;
|
||||
const uint LightType_Point = 0u;
|
||||
const uint LightType_Directional = 2u;
|
||||
struct PuctualLight {
|
||||
uint lightType;
|
||||
vec3 pointToLight;
|
||||
float range;
|
||||
vec3 color;
|
||||
float intensity;
|
||||
};
|
||||
|
||||
vec3 FresnelSchlick(float cosTheta, vec3 F0) {
|
||||
return (F0 + ((vec3(1.0f) - F0) * pow((1.0f - cosTheta), 5.0f)));
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness) {
|
||||
float a_1 = (roughness * roughness);
|
||||
float a2 = (a_1 * a_1);
|
||||
float NdotH = max(dot(N, H), 0.0f);
|
||||
float NdotH2 = (NdotH * NdotH);
|
||||
float num = a2;
|
||||
float denom = ((NdotH2 * (a2 - 1.0f)) + 1.0f);
|
||||
return (num / ((PI * denom) * denom));
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness) {
|
||||
float r_1 = (roughness + 1.0f);
|
||||
float k = ((r_1 * r_1) / 8.0f);
|
||||
float num = NdotV;
|
||||
float denom = ((NdotV * (1.0f - k)) + k);
|
||||
return (num / denom);
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
|
||||
float NdotV = max(dot(N, V), 0.0f);
|
||||
float NdotL = max(dot(N, L), 0.0f);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
return (ggx1 * ggx2);
|
||||
}
|
||||
|
||||
float lightAttenuation(PuctualLight light) {
|
||||
if ((light.lightType == LightType_Directional)) {
|
||||
return 1.0f;
|
||||
}
|
||||
float tint_symbol_1 = length(light.pointToLight);
|
||||
if ((light.range <= 0.0f)) {
|
||||
return (1.0f / pow(tint_symbol_1, 2.0f));
|
||||
}
|
||||
return (clamp((1.0f - pow((tint_symbol_1 / light.range), 4.0f)), 0.0f, 1.0f) / pow(tint_symbol_1, 2.0f));
|
||||
}
|
||||
|
||||
vec3 lightRadiance(PuctualLight light, SurfaceInfo surface) {
|
||||
vec3 L = normalize(light.pointToLight);
|
||||
vec3 H = normalize((surface.v + L));
|
||||
float NDF = DistributionGGX(surface.normal, H, surface.roughness);
|
||||
float G = GeometrySmith(surface.normal, surface.v, L, surface.roughness);
|
||||
vec3 F = FresnelSchlick(max(dot(H, surface.v), 0.0f), surface.f0);
|
||||
vec3 kD = ((vec3(1.0f) - F) * (1.0f - surface.metallic));
|
||||
float NdotL = max(dot(surface.normal, L), 0.0f);
|
||||
vec3 numerator = ((NDF * G) * F);
|
||||
float denominator = max(((4.0f * max(dot(surface.normal, surface.v), 0.0f)) * NdotL), 0.001f);
|
||||
vec3 specular = (numerator / vec3(denominator));
|
||||
vec3 tint_symbol_8 = (light.color * light.intensity);
|
||||
float tint_symbol_9 = lightAttenuation(light);
|
||||
vec3 radiance = (tint_symbol_8 * tint_symbol_9);
|
||||
return (((((kD * surface.albedo) / vec3(PI)) + specular) * radiance) * NdotL);
|
||||
}
|
||||
|
||||
struct FragmentOutput {
|
||||
vec4 color;
|
||||
vec4 emissive;
|
||||
};
|
||||
|
||||
uniform highp sampler2D ssaoTexture_1;
|
||||
uniform highp sampler2D ssaoTexture_defaultSampler;
|
||||
FragmentOutput fragmentMain(VertexOutput tint_symbol) {
|
||||
SurfaceInfo surface = GetSurfaceInfo(tint_symbol);
|
||||
vec3 Lo = vec3(0.0f, 0.0f, 0.0f);
|
||||
if ((globalLights.dirIntensity > 0.0f)) {
|
||||
PuctualLight light = PuctualLight(0u, vec3(0.0f, 0.0f, 0.0f), 0.0f, vec3(0.0f, 0.0f, 0.0f), 0.0f);
|
||||
light.lightType = LightType_Directional;
|
||||
light.pointToLight = globalLights.dirDirection;
|
||||
light.color = globalLights.dirColor;
|
||||
light.intensity = globalLights.dirIntensity;
|
||||
float lightVis = dirLightVisibility(tint_symbol.worldPos);
|
||||
vec3 tint_symbol_10 = Lo;
|
||||
vec3 tint_symbol_11 = lightRadiance(light, surface);
|
||||
Lo = (tint_symbol_10 + (tint_symbol_11 * lightVis));
|
||||
}
|
||||
uint clusterIndex = getClusterIndex(tint_symbol.position);
|
||||
uint lightOffset = clusterLights.lights[clusterIndex].offset;
|
||||
uint lightCount = clusterLights.lights[clusterIndex].count;
|
||||
{
|
||||
for(uint lightIndex = 0u; (lightIndex < lightCount); lightIndex = (lightIndex + 1u)) {
|
||||
uint i = clusterLights.indices[(lightOffset + lightIndex)];
|
||||
PuctualLight light = PuctualLight(0u, vec3(0.0f, 0.0f, 0.0f), 0.0f, vec3(0.0f, 0.0f, 0.0f), 0.0f);
|
||||
light.lightType = LightType_Point;
|
||||
light.pointToLight = (globalLights.lights[i].position.xyz - tint_symbol.worldPos);
|
||||
light.range = globalLights.lights[i].range;
|
||||
light.color = globalLights.lights[i].color;
|
||||
light.intensity = globalLights.lights[i].intensity;
|
||||
float lightVis = pointLightVisibility(i, tint_symbol.worldPos, light.pointToLight);
|
||||
vec3 tint_symbol_12 = Lo;
|
||||
vec3 tint_symbol_13 = lightRadiance(light, surface);
|
||||
Lo = (tint_symbol_12 + (tint_symbol_13 * lightVis));
|
||||
}
|
||||
}
|
||||
vec2 ssaoCoord = (tint_symbol.position.xy / vec2(textureSize(ssaoTexture_1, 0).xy));
|
||||
float ssaoFactor = texture(ssaoTexture_defaultSampler, ssaoCoord).r;
|
||||
vec3 ambient = (((globalLights.ambient * surface.albedo) * surface.ao) * ssaoFactor);
|
||||
vec3 color = linearTosRGB(((Lo + ambient) + surface.emissive));
|
||||
FragmentOutput tint_symbol_2 = FragmentOutput(vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
tint_symbol_2.color = vec4(color, surface.baseColor.a);
|
||||
tint_symbol_2.emissive = vec4(surface.emissive, surface.baseColor.a);
|
||||
return tint_symbol_2;
|
||||
}
|
||||
|
||||
void main() {
|
||||
VertexOutput tint_symbol_14 = VertexOutput(gl_FragCoord, worldPos_1, view_1, texcoord_1, texcoord2_1, color_1, instanceColor_1, normal_1, tangent_1, bitangent_1);
|
||||
FragmentOutput inner_result = fragmentMain(tint_symbol_14);
|
||||
color_2 = inner_result.color;
|
||||
emissive_1 = inner_result.emissive;
|
||||
return;
|
||||
}
|
Loading…
Reference in New Issue