[Impeller] workarounds for slow Adreno primitive restart performance. (#160683)
Fixes https://github.com/flutter/flutter/issues/160593 Primitive Restart cannot be used on some (All?) Adreno's because it causes a dramatic performance regression. Opt out and use the GLES strategy. Refactors the batch submit command buffer capability into workarounds_vk
This commit is contained in:
parent
4c8b0a3873
commit
5e8b6247d2
@ -42738,6 +42738,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.h
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/vma.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/vma.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/workarounds_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/workarounds_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_library_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_library_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_vk.cc + ../../../flutter/LICENSE
|
||||
@ -45674,6 +45676,8 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vma.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vma.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/workarounds_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/workarounds_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_library_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_library_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_vk.cc
|
||||
|
@ -598,6 +598,7 @@ void DlDispatcherBase::drawDiffRoundRect(const DlRoundRect& outer,
|
||||
PathBuilder builder;
|
||||
builder.AddRoundRect(outer);
|
||||
builder.AddRoundRect(inner);
|
||||
builder.SetBounds(outer.GetBounds().Union(inner.GetBounds()));
|
||||
GetCanvas().DrawPath(builder.TakePath(FillType::kOdd), paint_);
|
||||
}
|
||||
|
||||
|
@ -122,6 +122,8 @@ impeller_component("vulkan") {
|
||||
"vk.h",
|
||||
"vma.cc",
|
||||
"vma.h",
|
||||
"workarounds_vk.cc",
|
||||
"workarounds_vk.h",
|
||||
"yuv_conversion_library_vk.cc",
|
||||
"yuv_conversion_library_vk.h",
|
||||
"yuv_conversion_vk.cc",
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -482,7 +483,7 @@ bool CapabilitiesVK::HasExtension(const std::string& ext) const {
|
||||
}
|
||||
|
||||
bool CapabilitiesVK::SupportsPrimitiveRestart() const {
|
||||
return true;
|
||||
return has_primitive_restart_;
|
||||
}
|
||||
|
||||
void CapabilitiesVK::SetOffscreenFormat(PixelFormat pixel_format) const {
|
||||
@ -759,4 +760,8 @@ ISize CapabilitiesVK::GetMaximumRenderPassAttachmentSize() const {
|
||||
return max_render_pass_attachment_size_;
|
||||
}
|
||||
|
||||
void CapabilitiesVK::ApplyWorkarounds(const WorkaroundsVK& workarounds) {
|
||||
has_primitive_restart_ = !workarounds.slow_primitive_restart_performance;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "impeller/base/backend_cast.h"
|
||||
#include "impeller/core/texture_descriptor.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
|
||||
namespace impeller {
|
||||
@ -281,6 +282,10 @@ class CapabilitiesVK final : public Capabilities,
|
||||
CompressionType compression_type,
|
||||
const FRCFormatDescriptor& desc) const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Update capabilities for the given set of workarounds.
|
||||
void ApplyWorkarounds(const WorkaroundsVK& workarounds);
|
||||
|
||||
private:
|
||||
bool validations_enabled_ = false;
|
||||
std::map<std::string, std::set<std::string>> exts_;
|
||||
@ -298,6 +303,7 @@ class CapabilitiesVK final : public Capabilities,
|
||||
bool supports_texture_fixed_rate_compression_ = false;
|
||||
ISize max_render_pass_attachment_size_ = ISize{0, 0};
|
||||
bool has_triangle_fans_ = true;
|
||||
bool has_primitive_restart_ = true;
|
||||
bool is_valid_ = false;
|
||||
|
||||
// The embedder.h API is responsible for providing the instance and device
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "impeller/renderer/backend/vulkan/command_queue_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/render_pass_builder_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
|
||||
#include "impeller/renderer/render_target.h"
|
||||
|
||||
#ifdef FML_OS_ANDROID
|
||||
@ -457,10 +458,16 @@ void ContextVK::Setup(Settings settings) {
|
||||
//----------------------------------------------------------------------------
|
||||
/// All done!
|
||||
///
|
||||
|
||||
// Apply workarounds for broken drivers.
|
||||
auto driver_info =
|
||||
std::make_unique<DriverInfoVK>(device_holder->physical_device);
|
||||
WorkaroundsVK workarounds = GetWorkarounds(*driver_info);
|
||||
caps->ApplyWorkarounds(workarounds);
|
||||
|
||||
device_holder_ = std::move(device_holder);
|
||||
idle_waiter_vk_ = std::make_shared<IdleWaiterVK>(device_holder_);
|
||||
driver_info_ =
|
||||
std::make_unique<DriverInfoVK>(device_holder_->physical_device);
|
||||
driver_info_ = std::move(driver_info);
|
||||
debug_report_ = std::move(debug_report);
|
||||
allocator_ = std::move(allocator);
|
||||
shader_library_ = std::move(shader_library);
|
||||
@ -477,7 +484,7 @@ void ContextVK::Setup(Settings settings) {
|
||||
device_name_ = std::string(physical_device_properties.deviceName);
|
||||
command_queue_vk_ = std::make_shared<CommandQueueVK>(weak_from_this());
|
||||
should_disable_surface_control_ = settings.disable_surface_control;
|
||||
should_batch_cmd_buffers_ = driver_info_->CanBatchSubmitCommandBuffers();
|
||||
should_batch_cmd_buffers_ = !workarounds.batch_submit_command_buffer_timeout;
|
||||
is_valid_ = true;
|
||||
|
||||
// Create the GPU Tracer later because it depends on state from
|
||||
|
@ -317,12 +317,6 @@ void DriverInfoVK::DumpToLog() const {
|
||||
FML_LOG(IMPORTANT) << stream.str();
|
||||
}
|
||||
|
||||
bool DriverInfoVK::CanBatchSubmitCommandBuffers() const {
|
||||
return vendor_ == VendorVK::kARM ||
|
||||
(adreno_gpu_.has_value() &&
|
||||
adreno_gpu_.value() >= AdrenoGPU::kAdreno702);
|
||||
}
|
||||
|
||||
bool DriverInfoVK::IsEmulator() const {
|
||||
#if FML_OS_ANDROID
|
||||
// Google SwiftShader on Android.
|
||||
@ -358,4 +352,12 @@ bool DriverInfoVK::IsKnownBadDriver() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<MaliGPU> DriverInfoVK::GetMaliGPUInfo() const {
|
||||
return mali_gpu_;
|
||||
}
|
||||
|
||||
std::optional<AdrenoGPU> DriverInfoVK::GetAdrenoGPUInfo() const {
|
||||
return adreno_gpu_;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
@ -239,17 +239,16 @@ class DriverInfoVK {
|
||||
bool IsKnownBadDriver() const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Determines if the driver can batch submit command buffers
|
||||
/// without triggering erronious deadlock errors.
|
||||
/// @brief Returns Mali GPU info if this is a Mali GPU, otherwise
|
||||
/// std::nullopt.
|
||||
///
|
||||
/// Early 600 series Adreno drivers would deadlock if a command
|
||||
/// buffer submission had too much work attached to it, this
|
||||
/// requires the renderer to split up command buffers that could
|
||||
/// be logically combined.
|
||||
std::optional<MaliGPU> GetMaliGPUInfo() const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Returns Adreno GPU info if this is a Adreno GPU, otherwise
|
||||
/// std::nullopt.
|
||||
///
|
||||
/// @return True if device can batch submit command buffers.
|
||||
///
|
||||
bool CanBatchSubmitCommandBuffers() const;
|
||||
std::optional<AdrenoGPU> GetAdrenoGPUInfo() const;
|
||||
|
||||
private:
|
||||
bool is_valid_ = false;
|
||||
|
@ -82,7 +82,8 @@ bool CanBatchSubmitTest(std::string_view driver_name, bool qc = true) {
|
||||
prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
|
||||
})
|
||||
.Build();
|
||||
return context->GetDriverInfo()->CanBatchSubmitCommandBuffers();
|
||||
return !GetWorkarounds(*context->GetDriverInfo())
|
||||
.batch_submit_command_buffer_timeout;
|
||||
}
|
||||
|
||||
TEST(DriverInfoVKTest, CanBatchSubmitCommandBuffers) {
|
||||
@ -93,6 +94,35 @@ TEST(DriverInfoVKTest, CanBatchSubmitCommandBuffers) {
|
||||
EXPECT_TRUE(CanBatchSubmitTest("Adreno (TM) 750", true));
|
||||
}
|
||||
|
||||
bool CanUsePrimitiveRestartSubmitTest(std::string_view driver_name,
|
||||
bool qc = true) {
|
||||
auto const context =
|
||||
MockVulkanContextBuilder()
|
||||
.SetPhysicalPropertiesCallback(
|
||||
[&driver_name, qc](VkPhysicalDevice device,
|
||||
VkPhysicalDeviceProperties* prop) {
|
||||
if (qc) {
|
||||
prop->vendorID = 0x168C; // Qualcomm
|
||||
} else {
|
||||
prop->vendorID = 0x13B5; // ARM
|
||||
}
|
||||
driver_name.copy(prop->deviceName, driver_name.size());
|
||||
prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
|
||||
})
|
||||
.Build();
|
||||
return !GetWorkarounds(*context->GetDriverInfo())
|
||||
.slow_primitive_restart_performance;
|
||||
}
|
||||
|
||||
TEST(DriverInfoVKTest, CanUsePrimitiveRestart) {
|
||||
// Adreno no primitive restart
|
||||
EXPECT_FALSE(CanUsePrimitiveRestartSubmitTest("Adreno (TM) 540", true));
|
||||
EXPECT_FALSE(CanUsePrimitiveRestartSubmitTest("Adreno (TM) 750", true));
|
||||
|
||||
// Mali A-OK
|
||||
EXPECT_TRUE(CanUsePrimitiveRestartSubmitTest("Mali-G51", false));
|
||||
}
|
||||
|
||||
TEST(DriverInfoVKTest, DriverParsingMali) {
|
||||
EXPECT_EQ(GetMaliVersion("Mali-G51-MORE STUFF"), MaliGPU::kG51);
|
||||
EXPECT_EQ(GetMaliVersion("Mali-G51"), MaliGPU::kG51);
|
||||
|
@ -362,6 +362,7 @@ fml::StatusOr<vk::UniquePipeline> MakePipeline(
|
||||
const auto topology = ToVKPrimitiveTopology(desc.GetPrimitiveType());
|
||||
input_assembly.setTopology(topology);
|
||||
input_assembly.setPrimitiveRestartEnable(
|
||||
caps->SupportsPrimitiveRestart() &&
|
||||
PrimitiveTopologySupportsPrimitiveRestart(desc.GetPrimitiveType()));
|
||||
pipeline_info.setPInputAssemblyState(&input_assembly);
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
WorkaroundsVK GetWorkarounds(DriverInfoVK& driver_info) {
|
||||
WorkaroundsVK workarounds;
|
||||
|
||||
const auto& adreno_gpu = driver_info.GetAdrenoGPUInfo();
|
||||
const auto& mali_gpu = driver_info.GetMaliGPUInfo();
|
||||
|
||||
workarounds.batch_submit_command_buffer_timeout = true;
|
||||
if (adreno_gpu.has_value()) {
|
||||
workarounds.slow_primitive_restart_performance = true;
|
||||
|
||||
if (adreno_gpu.value() >= AdrenoGPU::kAdreno702) {
|
||||
workarounds.batch_submit_command_buffer_timeout = false;
|
||||
}
|
||||
} else if (mali_gpu.has_value()) {
|
||||
workarounds.batch_submit_command_buffer_timeout = false;
|
||||
}
|
||||
return workarounds;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
@ -0,0 +1,30 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_WORKAROUNDS_VK_H_
|
||||
#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_WORKAROUNDS_VK_H_
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/driver_info_vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
/// A non-exhaustive set of driver specific workarounds.
|
||||
struct WorkaroundsVK {
|
||||
// Adreno GPUs exhibit terrible performance when primitive
|
||||
// restart is used. This was confirmed up to Adreno 640 (Pixel 4).
|
||||
// Because this feature is fairly marginal, we disable it for _all_
|
||||
// Adreno GPUs until we have an upper bound for this bug.
|
||||
bool slow_primitive_restart_performance = false;
|
||||
|
||||
/// Early 600 series Adreno drivers would deadlock if a command
|
||||
/// buffer submission had too much work attached to it, this
|
||||
/// requires the renderer to split up command buffers that could
|
||||
/// be logically combined.
|
||||
bool batch_submit_command_buffer_timeout = false;
|
||||
};
|
||||
WorkaroundsVK GetWorkarounds(DriverInfoVK& driver_info);
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_WORKAROUNDS_VK_H_
|
Loading…
x
Reference in New Issue
Block a user