Vulkan: Skip index clamping on runtime-sized arrays in robustness transform
This patch disables index clamping on all runtime-sized arrays in robustness
transform when VK_EXT_robustness2 is supported and robustBufferAccess2 is
VK_TRUE.
This patch can improve about 11% of the performance of
dawn_perf_tests.ShaderRobustnessPerf.
Fixed: dawn:1882
Bug: tint:1890
Change-Id: Ib7113c91787a51c34fdc3496f3d700cb1d74e709
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/139760
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp
index e5ceb56..b551e51 100644
--- a/src/dawn/native/Toggles.cpp
+++ b/src/dawn/native/Toggles.cpp
@@ -430,6 +430,11 @@
"Disable Tint robustness transform on textures when VK_EXT_robustness2 is supported and "
"robustImageAccess2 == VK_TRUE.",
"https://crbug.com/tint/1890", ToggleStage::Device}},
+ {Toggle::VulkanUseBufferRobustAccess2,
+ {"vulkan_use_buffer_robust_access_2",
+ "Disable index clamping on the runtime-sized arrays on buffers in Tint robustness transform "
+ "when VK_EXT_robustness2 is supported and robustBufferAccess2 == VK_TRUE.",
+ "https://crbug.com/tint/1890", ToggleStage::Device}},
{Toggle::NoWorkaroundSampleMaskBecomesZeroForAllButLastColorTarget,
{"no_workaround_sample_mask_becomes_zero_for_all_but_last_color_target",
"MacOS 12.0+ Intel has a bug where the sample mask is only applied for the last color "
diff --git a/src/dawn/native/Toggles.h b/src/dawn/native/Toggles.h
index 271b5c9..c7061a7 100644
--- a/src/dawn/native/Toggles.h
+++ b/src/dawn/native/Toggles.h
@@ -100,6 +100,7 @@
VulkanClearGen12TextureWithCCSAmbiguateOnCreation,
D3D12UseRootSignatureVersion1_1,
VulkanUseImageRobustAccess2,
+ VulkanUseBufferRobustAccess2,
// Unresolved issues.
NoWorkaroundSampleMaskBecomesZeroForAllButLastColorTarget,
diff --git a/src/dawn/native/vulkan/DeviceVk.cpp b/src/dawn/native/vulkan/DeviceVk.cpp
index 9617771..fbe8172 100644
--- a/src/dawn/native/vulkan/DeviceVk.cpp
+++ b/src/dawn/native/vulkan/DeviceVk.cpp
@@ -524,9 +524,6 @@
ASSERT(usedKnobs.HasExt(DeviceExt::Robustness2));
usedKnobs.robustness2Features = mDeviceInfo.robustness2Features;
- // TODO(tint:1890): investigate how we can safely disable buffer access in Tint when
- // robustBufferAccess2 == TRUE
- usedKnobs.robustness2Features.robustBufferAccess2 = VK_FALSE;
featuresChain.Add(&usedKnobs.robustness2Features);
}
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
index 3ebb617..b5d3d56 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -565,6 +565,15 @@
// By default try to skip robustness transform on textures according to the Vulkan extension
// VK_EXT_robustness2.
deviceToggles->Default(Toggle::VulkanUseImageRobustAccess2, true);
+ // The environment can only request to use VK_EXT_robustness2 when the extension is available.
+ // Override the decision if it is not applicable or robustBufferAccess2 is false.
+ if (!GetDeviceInfo().HasExt(DeviceExt::Robustness2) ||
+ GetDeviceInfo().robustness2Features.robustBufferAccess2 == VK_FALSE) {
+ deviceToggles->ForceSet(Toggle::VulkanUseBufferRobustAccess2, false);
+ }
+ // By default try to disable index clamping on the runtime-sized arrays on storage buffers in
+ // Tint robustness transform according to the Vulkan extension VK_EXT_robustness2.
+ deviceToggles->Default(Toggle::VulkanUseBufferRobustAccess2, true);
}
ResultOrError<Ref<DeviceBase>> PhysicalDevice::CreateDeviceImpl(AdapterBase* adapter,
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index 55f5911..4074ba5 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -177,6 +177,7 @@
X(bool, useZeroInitializeWorkgroupMemoryExtension) \
X(bool, clampFragDepth) \
X(bool, disableImageRobustness) \
+ X(bool, disableRuntimeSizedArrayIndexClamping) \
X(CacheKey::UnsafeUnkeyedValue<dawn::platform::Platform*>, tracePlatform)
DAWN_MAKE_CACHE_REQUEST(SpirvCompilationRequest, SPIRV_COMPILATION_REQUEST_MEMBERS);
@@ -264,6 +265,10 @@
GetDevice()->IsToggleEnabled(Toggle::VulkanUseZeroInitializeWorkgroupMemoryExtension);
req.clampFragDepth = clampFragDepth;
req.disableImageRobustness = GetDevice()->IsToggleEnabled(Toggle::VulkanUseImageRobustAccess2);
+ // Currently we can disable index clamping on all runtime-sized arrays in Tint robustness
+ // transform as unsized arrays can only be declared on storage address space.
+ req.disableRuntimeSizedArrayIndexClamping =
+ GetDevice()->IsToggleEnabled(Toggle::VulkanUseBufferRobustAccess2);
req.tracePlatform = UnsafeUnkeyedValue(GetDevice()->GetPlatform());
req.substituteOverrideConfig = std::move(substituteOverrideConfig);
@@ -336,6 +341,8 @@
options.binding_remapper_options = r.bindingRemapper;
options.external_texture_options = r.externalTextureOptions;
options.disable_image_robustness = r.disableImageRobustness;
+ options.disable_runtime_sized_array_index_clamping =
+ r.disableRuntimeSizedArrayIndexClamping;
TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General,
"tint::writer::spirv::Generate()");
diff --git a/src/tint/ast/transform/robustness.cc b/src/tint/ast/transform/robustness.cc
index e0cb752..1e9a4a0 100644
--- a/src/tint/ast/transform/robustness.cc
+++ b/src/tint/ast/transform/robustness.cc
@@ -66,6 +66,14 @@
if (IsIgnoredResourceBinding(expr->Object()->RootIdentifier())) {
return;
}
+ if (cfg.disable_runtime_sized_array_index_clamping &&
+ IsIndexAccessingRuntimeSizedArray(expr)) {
+ // Ensure the index is always u32 as using a negative index is an undefined
+ // behavior in SPIRV.
+ auto* idx = CastToU32(expr->Index());
+ ctx.Replace(expr->Declaration()->index, idx);
+ return;
+ }
switch (ActionFor(expr)) {
case Action::kPredicate:
PredicateIndexAccessor(expr);
@@ -342,11 +350,7 @@
}
auto* expr_sem = expr->Unwrap()->As<sem::IndexAccessorExpression>();
-
- auto idx = ctx.Clone(expr->Declaration()->index);
- if (expr_sem->Index()->Type()->is_signed_integer_scalar()) {
- idx = b.Call<u32>(idx); // u32(idx)
- }
+ auto idx = CastToU32(expr_sem->Index());
auto* clamped_idx = b.Call(builtin::Function::kMin, idx, max);
ctx.Replace(expr->Declaration()->index, clamped_idx);
}
@@ -693,6 +697,22 @@
sem::BindingPoint bindingPoint = *globalVariable->BindingPoint();
return cfg.bindings_ignored.find(bindingPoint) != cfg.bindings_ignored.cend();
}
+
+ /// @returns true if expr is an IndexAccessorExpression whose object is a runtime-sized array.
+ bool IsIndexAccessingRuntimeSizedArray(const sem::IndexAccessorExpression* expr) {
+ auto* array_type = expr->Object()->Type()->UnwrapRef()->As<type::Array>();
+ return array_type != nullptr && array_type->Count()->Is<type::RuntimeArrayCount>();
+ }
+
+ /// @returns a clone of expr->Declaration() if it is an unsigned integer scalar, or
+ /// expr->Declaration() cast to u32.
+ const ast::Expression* CastToU32(const sem::ValueExpression* expr) {
+ auto* idx = ctx.Clone(expr->Declaration());
+ if (expr->Type()->is_unsigned_integer_scalar()) {
+ return idx;
+ }
+ return b.Call<u32>(idx); // u32(idx)
+ }
};
Robustness::Config::Config() = default;
diff --git a/src/tint/ast/transform/robustness.h b/src/tint/ast/transform/robustness.h
index 7278a41..be01bb5 100644
--- a/src/tint/ast/transform/robustness.h
+++ b/src/tint/ast/transform/robustness.h
@@ -81,8 +81,11 @@
/// Robustness action for variables in the 'workgroup' address space
Action workgroup_action = Action::kDefault;
- /// Bindings that should always be applied Actions::kIgnore on.
+ /// Bindings that should always be applied Actions::kIgnore on
std::unordered_set<tint::sem::BindingPoint> bindings_ignored;
+
+ /// If we should disable index clamping on runtime-sized arrays in robustness transform
+ bool disable_runtime_sized_array_index_clamping = false;
};
/// Constructor
diff --git a/src/tint/ast/transform/robustness_test.cc b/src/tint/ast/transform/robustness_test.cc
index ebe7dc2..0b7e15c 100644
--- a/src/tint/ast/transform/robustness_test.cc
+++ b/src/tint/ast/transform/robustness_test.cc
@@ -32,7 +32,8 @@
namespace {
-Transform::DataMap Config(Robustness::Action action) {
+Transform::DataMap Config(Robustness::Action action,
+ bool disable_runtime_sized_array_index_clamping = false) {
Robustness::Config cfg;
cfg.value_action = action;
cfg.texture_action = action;
@@ -42,6 +43,7 @@
cfg.storage_action = action;
cfg.uniform_action = action;
cfg.workgroup_action = action;
+ cfg.disable_runtime_sized_array_index_clamping = disable_runtime_sized_array_index_clamping;
Transform::DataMap data;
data.Add<Robustness::Config>(cfg);
return data;
@@ -5490,6 +5492,136 @@
EXPECT_EQ(expect, str(got));
}
+////////////////////////////////////////////////////////////////////////////////
+// disable_runtime_sized_array_index_clamping == true
+////////////////////////////////////////////////////////////////////////////////
+
+TEST_P(RobustnessTest, Read_disable_unsized_array_index_clamping_i32) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read> s : array<f32>;
+
+fn f() {
+ let i = 25i;
+ var d : f32 = s[i];
+}
+)";
+
+ auto* expect = R"(
+@group(0) @binding(0) var<storage, read> s : array<f32>;
+
+fn f() {
+ let i = 25i;
+ var d : f32 = s[u32(i)];
+}
+)";
+
+ auto got = Run<Robustness>(src, Config(GetParam(), true));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_P(RobustnessTest, Read_disable_unsized_array_index_clamping_u32) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read> s : array<f32>;
+
+fn f() {
+ let i = 25u;
+ var d : f32 = s[i];
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<Robustness>(src, Config(GetParam(), true));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_P(RobustnessTest, Read_disable_unsized_array_index_clamping_abstract_int) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read> s : array<f32>;
+
+fn f() {
+ var d : f32 = s[25];
+}
+)";
+
+ auto* expect = R"(
+@group(0) @binding(0) var<storage, read> s : array<f32>;
+
+fn f() {
+ var d : f32 = s[u32(25)];
+}
+)";
+
+ auto got = Run<Robustness>(src, Config(GetParam(), true));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_P(RobustnessTest, Assign_disable_unsized_array_index_clamping_i32) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> s : array<f32>;
+
+fn f() {
+ let i = 25i;
+ s[i] = 0.5f;
+}
+)";
+
+ auto* expect = R"(
+@group(0) @binding(0) var<storage, read_write> s : array<f32>;
+
+fn f() {
+ let i = 25i;
+ s[u32(i)] = 0.5f;
+}
+)";
+
+ auto got = Run<Robustness>(src, Config(GetParam(), true));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_P(RobustnessTest, Assign_disable_unsized_array_index_clamping_u32) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> s : array<f32>;
+
+fn f() {
+ let i = 25u;
+ s[i] = 0.5f;
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<Robustness>(src, Config(GetParam(), true));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_P(RobustnessTest, Assign_disable_unsized_array_index_clamping_abstract_int) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> s : array<f32>;
+
+fn f() {
+ s[25] = 0.5f;
+}
+)";
+
+ auto* expect = R"(
+@group(0) @binding(0) var<storage, read_write> s : array<f32>;
+
+fn f() {
+ s[u32(25)] = 0.5f;
+}
+)";
+
+ auto got = Run<Robustness>(src, Config(GetParam(), true));
+
+ EXPECT_EQ(expect, str(got));
+}
+
INSTANTIATE_TEST_SUITE_P(,
RobustnessTest,
testing::Values(Robustness::Action::kIgnore,
diff --git a/src/tint/writer/spirv/generator.h b/src/tint/writer/spirv/generator.h
index 3319c05..f9bc2c2 100644
--- a/src/tint/writer/spirv/generator.h
+++ b/src/tint/writer/spirv/generator.h
@@ -60,10 +60,12 @@
/// VK_KHR_zero_initialize_workgroup_memory is enabled.
bool use_zero_initialize_workgroup_memory_extension = false;
- /// Set to `true` to skip robustness transform on textures when VK_EXT_robustness is enabled and
- /// robustImageAccess == VK_TRUE.
+ /// Set to `true` to skip robustness transform on textures.
bool disable_image_robustness = false;
+ /// Set to `true` to disable index clamping on the runtime-sized arrays in robustness transform.
+ bool disable_runtime_sized_array_index_clamping = false;
+
#if TINT_BUILD_IR
/// Set to `true` to generate SPIR-V via the Tint IR instead of from the AST.
bool use_tint_ir = false;
@@ -75,7 +77,8 @@
disable_workgroup_init,
external_texture_options,
use_zero_initialize_workgroup_memory_extension,
- disable_image_robustness);
+ disable_image_robustness,
+ disable_runtime_sized_array_index_clamping);
};
/// The result produced when generating SPIR-V.
diff --git a/src/tint/writer/spirv/generator_impl.cc b/src/tint/writer/spirv/generator_impl.cc
index b5e5a5c..edab51c 100644
--- a/src/tint/writer/spirv/generator_impl.cc
+++ b/src/tint/writer/spirv/generator_impl.cc
@@ -87,6 +87,8 @@
if (options.disable_image_robustness) {
config.texture_action = ast::transform::Robustness::Action::kIgnore;
}
+ config.disable_runtime_sized_array_index_clamping =
+ options.disable_runtime_sized_array_index_clamping;
data.Add<ast::transform::Robustness::Config>(config);
}