diff --git a/src/tint/builtin/extension.cc b/src/tint/builtin/extension.cc index 3d57867bbb..36171dbd07 100644 --- a/src/tint/builtin/extension.cc +++ b/src/tint/builtin/extension.cc @@ -40,6 +40,9 @@ Extension ParseExtension(std::string_view str) { if (str == "chromium_experimental_push_constant") { return Extension::kChromiumExperimentalPushConstant; } + if (str == "chromium_internal_relaxed_uniform_layout") { + return Extension::kChromiumInternalRelaxedUniformLayout; + } if (str == "f16") { return Extension::kF16; } @@ -58,6 +61,8 @@ std::ostream& operator<<(std::ostream& out, Extension value) { return out << "chromium_experimental_full_ptr_parameters"; case Extension::kChromiumExperimentalPushConstant: return out << "chromium_experimental_push_constant"; + case Extension::kChromiumInternalRelaxedUniformLayout: + return out << "chromium_internal_relaxed_uniform_layout"; case Extension::kF16: return out << "f16"; } diff --git a/src/tint/builtin/extension.h b/src/tint/builtin/extension.h index f0ebeca278..aace5049c1 100644 --- a/src/tint/builtin/extension.h +++ b/src/tint/builtin/extension.h @@ -37,6 +37,7 @@ enum class Extension { kChromiumExperimentalDp4A, kChromiumExperimentalFullPtrParameters, kChromiumExperimentalPushConstant, + kChromiumInternalRelaxedUniformLayout, kF16, }; @@ -51,11 +52,9 @@ std::ostream& operator<<(std::ostream& out, Extension value); Extension ParseExtension(std::string_view str); constexpr const char* kExtensionStrings[] = { - "chromium_disable_uniformity_analysis", - "chromium_experimental_dp4a", - "chromium_experimental_full_ptr_parameters", - "chromium_experimental_push_constant", - "f16", + "chromium_disable_uniformity_analysis", "chromium_experimental_dp4a", + "chromium_experimental_full_ptr_parameters", "chromium_experimental_push_constant", + "chromium_internal_relaxed_uniform_layout", "f16", }; // A unique vector of extensions diff --git a/src/tint/builtin/extension_bench.cc b/src/tint/builtin/extension_bench.cc index 4619ce2faa..b3e410e591 100644 --- a/src/tint/builtin/extension_bench.cc +++ b/src/tint/builtin/extension_bench.cc @@ -59,13 +59,20 @@ void ExtensionParser(::benchmark::State& state) { "chromium_exp9rimFntal_ush_constant", "chrmium_experimental_push_constant", "cOOromium_experiVeHtal_puh_conRRtant", - "y1", - "l77rrn6", - "4016", + "chromium_internl_relaxyd_uniform_layout", + "chromnnum_internrr77_Gelaxell_uniform_layout", + "chromium_intern4l_relaxe00_uniform_layout", + "chromium_internal_relaxed_uniform_layout", + "chrmoom_internal_relaxed_uniform_lyout", + "chroium_internal_rlaxed_uniform_layzzut", + "chromium_internaii_r11axed_uppifor_layout", + "f1XX", + "55199II", + "frSSHHa", "f16", - "5", - "u16", - "f", + "U", + "jV3", + "", }; for (auto _ : state) { for (auto* str : kStrings) { diff --git a/src/tint/builtin/extension_test.cc b/src/tint/builtin/extension_test.cc index 01eb1aec5f..9ef86830ac 100644 --- a/src/tint/builtin/extension_test.cc +++ b/src/tint/builtin/extension_test.cc @@ -48,6 +48,7 @@ static constexpr Case kValidCases[] = { {"chromium_experimental_full_ptr_parameters", Extension::kChromiumExperimentalFullPtrParameters}, {"chromium_experimental_push_constant", Extension::kChromiumExperimentalPushConstant}, + {"chromium_internal_relaxed_uniform_layout", Extension::kChromiumInternalRelaxedUniformLayout}, {"f16", Extension::kF16}, }; @@ -64,9 +65,12 @@ static constexpr Case kInvalidCases[] = { {"chvomium_experimental_push_constiint", Extension::kUndefined}, {"chromiu8WWexperimental_push_constant", Extension::kUndefined}, {"chromium_experiMental_push_costanxx", Extension::kUndefined}, - {"fgg", Extension::kUndefined}, - {"X", Extension::kUndefined}, - {"316", Extension::kUndefined}, + {"chromium_internal_relaxed_unXform_layugg", Extension::kUndefined}, + {"chromiuu_iVterna_relxed_unifXrm_layout", Extension::kUndefined}, + {"chromium_internal_relaxed_uni3orm_layout", Extension::kUndefined}, + {"fE6", Extension::kUndefined}, + {"fPTT", Extension::kUndefined}, + {"dxx6", Extension::kUndefined}, }; using ExtensionParseTest = testing::TestWithParam; diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def index 826a667416..4b85f3f457 100644 --- a/src/tint/intrinsics.def +++ b/src/tint/intrinsics.def @@ -70,6 +70,8 @@ enum extension { // A Chromium-specific extension that enables passing of uniform, storage and workgroup // address-spaced pointers as parameters, as well as pointers into sub-objects. chromium_experimental_full_ptr_parameters + // A Chromium-specific extension that relaxes memory layout requirements for uniform storage. + chromium_internal_relaxed_uniform_layout } // https://gpuweb.github.io/gpuweb/wgsl/#storage-class diff --git a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc index fea7c2dcb4..7ad39c2a65 100644 --- a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc +++ b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc @@ -62,7 +62,7 @@ TEST_F(EnableDirectiveTest, InvalidIdentifier) { // Error when unknown extension found EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), R"(1:8: expected extension -Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')"); +Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')"); auto program = p->program(); auto& ast = program.AST(); EXPECT_EQ(ast.Enables().Length(), 0u); @@ -76,7 +76,7 @@ TEST_F(EnableDirectiveTest, InvalidIdentifierSuggest) { EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), R"(1:8: expected extension Did you mean 'f16'? -Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')"); +Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')"); auto program = p->program(); auto& ast = program.AST(); EXPECT_EQ(ast.Enables().Length(), 0u); @@ -124,7 +124,7 @@ TEST_F(EnableDirectiveTest, InvalidTokens) { p->translation_unit(); EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), R"(1:8: expected extension -Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')"); +Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')"); auto program = p->program(); auto& ast = program.AST(); EXPECT_EQ(ast.Enables().Length(), 0u); @@ -135,7 +135,7 @@ Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_ p->translation_unit(); EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), R"(1:8: expected extension -Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')"); +Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')"); auto program = p->program(); auto& ast = program.AST(); EXPECT_EQ(ast.Enables().Length(), 0u); @@ -147,7 +147,7 @@ Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_ EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), R"(1:8: expected extension Did you mean 'f16'? -Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')"); +Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')"); auto program = p->program(); auto& ast = program.AST(); EXPECT_EQ(ast.Enables().Length(), 0u); diff --git a/src/tint/resolver/address_space_layout_validation_test.cc b/src/tint/resolver/address_space_layout_validation_test.cc index 79e2781deb..9a621e311a 100644 --- a/src/tint/resolver/address_space_layout_validation_test.cc +++ b/src/tint/resolver/address_space_layout_validation_test.cc @@ -603,5 +603,150 @@ TEST_F(ResolverAddressSpaceLayoutValidationTest, PushConstant_Aligned) { ASSERT_TRUE(r()->Resolve()) << r()->error(); } +TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_StructMemberOffset_Struct) { + // enable chromium_internal_relaxed_uniform_layout; + // + // struct Inner { + // scalar : i32; + // }; + // + // struct Outer { + // scalar : f32; + // inner : Inner; + // }; + // + // @group(0) @binding(0) + // var a : Outer; + + Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout); + + Structure(Source{{12, 34}}, "Inner", + utils::Vector{ + Member("scalar", ty.i32()), + }); + + Structure(Source{{34, 56}}, "Outer", + utils::Vector{ + Member("scalar", ty.f32()), + Member(Source{{56, 78}}, "inner", ty("Inner")), + }); + + GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a), + Binding(0_a)); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); +} + +TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_StructMemberOffset_Array) { + // enable chromium_internal_relaxed_uniform_layout; + // + // type Inner = @stride(16) array; + // + // struct Outer { + // scalar : f32; + // inner : Inner; + // }; + // + // @group(0) @binding(0) + // var a : Outer; + + Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout); + + Alias("Inner", ty.array(utils::Vector{Stride(16)})); + + Structure(Source{{12, 34}}, "Outer", + utils::Vector{ + Member("scalar", ty.f32()), + Member(Source{{56, 78}}, "inner", ty("Inner")), + }); + + GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a), + Binding(0_a)); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); +} + +TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_MemberOffsetNotMutipleOf16) { + // enable chromium_internal_relaxed_uniform_layout; + // + // struct Inner { + // @align(1) @size(5) scalar : i32; + // }; + // + // struct Outer { + // inner : Inner; + // scalar : i32; + // }; + // + // @group(0) @binding(0) + // var a : Outer; + + Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout); + + Structure(Source{{12, 34}}, "Inner", + utils::Vector{ + Member("scalar", ty.i32(), utils::Vector{MemberAlign(1_i), MemberSize(5_a)}), + }); + + Structure(Source{{34, 56}}, "Outer", + utils::Vector{ + Member(Source{{56, 78}}, "inner", ty("Inner")), + Member(Source{{78, 90}}, "scalar", ty.i32()), + }); + + GlobalVar(Source{{22, 24}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a), + Binding(0_a)); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); +} + +TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_ArrayStride_Scalar) { + // enable chromium_internal_relaxed_uniform_layout; + // + // struct Outer { + // arr : array; + // }; + // + // @group(0) @binding(0) + // var a : Outer; + + Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout); + + Structure(Source{{12, 34}}, "Outer", + utils::Vector{ + Member("arr", ty.array()), + }); + + GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a), + Binding(0_a)); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); +} + +TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_ArrayStride_Vech) { + // enable f16; + // enable chromium_internal_relaxed_uniform_layout; + // + // struct Outer { + // arr : array, 10u>; + // }; + // + // @group(0) @binding(0) + // var a : Outer; + + Enable(builtin::Extension::kF16); + Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout); + + Structure(Source{{12, 34}}, "Outer", + utils::Vector{ + Member("arr", ty.array(ty.vec3(), 10_u)), + }); + + GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a), + Binding(0_a)); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); +} + } // namespace } // namespace tint::resolver diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc index b272b15ab1..0d186cce8f 100644 --- a/src/tint/resolver/validator.cc +++ b/src/tint/resolver/validator.cc @@ -467,7 +467,9 @@ bool Validator::AddressSpaceLayout(const type::Type* store_ty, } // Validate that member is at a valid byte offset - if (m->Offset() % required_align != 0) { + if (m->Offset() % required_align != 0 && + !enabled_extensions_.Contains( + builtin::Extension::kChromiumInternalRelaxedUniformLayout)) { AddError("the offset of a struct member of type '" + m->Type()->UnwrapRef()->FriendlyName(symbols_) + "' in address space '" + utils::ToString(address_space) + @@ -493,7 +495,9 @@ bool Validator::AddressSpaceLayout(const type::Type* store_ty, auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1]; if (prev_member && is_uniform_struct(prev_member->Type())) { const uint32_t prev_to_curr_offset = m->Offset() - prev_member->Offset(); - if (prev_to_curr_offset % 16 != 0) { + if (prev_to_curr_offset % 16 != 0 && + !enabled_extensions_.Contains( + builtin::Extension::kChromiumInternalRelaxedUniformLayout)) { AddError( "uniform storage requires that the number of bytes between the " "start of the previous member of type struct and the current " @@ -526,7 +530,9 @@ bool Validator::AddressSpaceLayout(const type::Type* store_ty, return false; } - if (address_space == builtin::AddressSpace::kUniform) { + if (address_space == builtin::AddressSpace::kUniform && + !enabled_extensions_.Contains( + builtin::Extension::kChromiumInternalRelaxedUniformLayout)) { // We already validated that this array member is itself aligned to 16 bytes above, so // we only need to validate that stride is a multiple of 16 bytes. if (arr->Stride() % 16 != 0) {