[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/vk.h + ../../../flutter/LICENSE
|
||||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/vma.cc + ../../../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/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.cc + ../../../flutter/LICENSE
|
||||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_library_vk.h + ../../../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
|
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/vk.h
|
||||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vma.cc
|
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vma.cc
|
||||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vma.h
|
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.cc
|
||||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_library_vk.h
|
FILE: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_library_vk.h
|
||||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_vk.cc
|
FILE: ../../../flutter/impeller/renderer/backend/vulkan/yuv_conversion_vk.cc
|
||||||
|
@ -598,6 +598,7 @@ void DlDispatcherBase::drawDiffRoundRect(const DlRoundRect& outer,
|
|||||||
PathBuilder builder;
|
PathBuilder builder;
|
||||||
builder.AddRoundRect(outer);
|
builder.AddRoundRect(outer);
|
||||||
builder.AddRoundRect(inner);
|
builder.AddRoundRect(inner);
|
||||||
|
builder.SetBounds(outer.GetBounds().Union(inner.GetBounds()));
|
||||||
GetCanvas().DrawPath(builder.TakePath(FillType::kOdd), paint_);
|
GetCanvas().DrawPath(builder.TakePath(FillType::kOdd), paint_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +122,8 @@ impeller_component("vulkan") {
|
|||||||
"vk.h",
|
"vk.h",
|
||||||
"vma.cc",
|
"vma.cc",
|
||||||
"vma.h",
|
"vma.h",
|
||||||
|
"workarounds_vk.cc",
|
||||||
|
"workarounds_vk.h",
|
||||||
"yuv_conversion_library_vk.cc",
|
"yuv_conversion_library_vk.cc",
|
||||||
"yuv_conversion_library_vk.h",
|
"yuv_conversion_library_vk.h",
|
||||||
"yuv_conversion_vk.cc",
|
"yuv_conversion_vk.cc",
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "impeller/base/validation.h"
|
#include "impeller/base/validation.h"
|
||||||
#include "impeller/core/formats.h"
|
#include "impeller/core/formats.h"
|
||||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||||
|
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
|
||||||
|
|
||||||
namespace impeller {
|
namespace impeller {
|
||||||
|
|
||||||
@ -482,7 +483,7 @@ bool CapabilitiesVK::HasExtension(const std::string& ext) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CapabilitiesVK::SupportsPrimitiveRestart() const {
|
bool CapabilitiesVK::SupportsPrimitiveRestart() const {
|
||||||
return true;
|
return has_primitive_restart_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CapabilitiesVK::SetOffscreenFormat(PixelFormat pixel_format) const {
|
void CapabilitiesVK::SetOffscreenFormat(PixelFormat pixel_format) const {
|
||||||
@ -759,4 +760,8 @@ ISize CapabilitiesVK::GetMaximumRenderPassAttachmentSize() const {
|
|||||||
return max_render_pass_attachment_size_;
|
return max_render_pass_attachment_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CapabilitiesVK::ApplyWorkarounds(const WorkaroundsVK& workarounds) {
|
||||||
|
has_primitive_restart_ = !workarounds.slow_primitive_restart_performance;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace impeller
|
} // namespace impeller
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "impeller/base/backend_cast.h"
|
#include "impeller/base/backend_cast.h"
|
||||||
#include "impeller/core/texture_descriptor.h"
|
#include "impeller/core/texture_descriptor.h"
|
||||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||||
|
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
|
||||||
#include "impeller/renderer/capabilities.h"
|
#include "impeller/renderer/capabilities.h"
|
||||||
|
|
||||||
namespace impeller {
|
namespace impeller {
|
||||||
@ -281,6 +282,10 @@ class CapabilitiesVK final : public Capabilities,
|
|||||||
CompressionType compression_type,
|
CompressionType compression_type,
|
||||||
const FRCFormatDescriptor& desc) const;
|
const FRCFormatDescriptor& desc) const;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/// @brief Update capabilities for the given set of workarounds.
|
||||||
|
void ApplyWorkarounds(const WorkaroundsVK& workarounds);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool validations_enabled_ = false;
|
bool validations_enabled_ = false;
|
||||||
std::map<std::string, std::set<std::string>> exts_;
|
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;
|
bool supports_texture_fixed_rate_compression_ = false;
|
||||||
ISize max_render_pass_attachment_size_ = ISize{0, 0};
|
ISize max_render_pass_attachment_size_ = ISize{0, 0};
|
||||||
bool has_triangle_fans_ = true;
|
bool has_triangle_fans_ = true;
|
||||||
|
bool has_primitive_restart_ = true;
|
||||||
bool is_valid_ = false;
|
bool is_valid_ = false;
|
||||||
|
|
||||||
// The embedder.h API is responsible for providing the instance and device
|
// 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/command_queue_vk.h"
|
||||||
#include "impeller/renderer/backend/vulkan/descriptor_pool_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/render_pass_builder_vk.h"
|
||||||
|
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
|
||||||
#include "impeller/renderer/render_target.h"
|
#include "impeller/renderer/render_target.h"
|
||||||
|
|
||||||
#ifdef FML_OS_ANDROID
|
#ifdef FML_OS_ANDROID
|
||||||
@ -457,10 +458,16 @@ void ContextVK::Setup(Settings settings) {
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
/// All done!
|
/// 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);
|
device_holder_ = std::move(device_holder);
|
||||||
idle_waiter_vk_ = std::make_shared<IdleWaiterVK>(device_holder_);
|
idle_waiter_vk_ = std::make_shared<IdleWaiterVK>(device_holder_);
|
||||||
driver_info_ =
|
driver_info_ = std::move(driver_info);
|
||||||
std::make_unique<DriverInfoVK>(device_holder_->physical_device);
|
|
||||||
debug_report_ = std::move(debug_report);
|
debug_report_ = std::move(debug_report);
|
||||||
allocator_ = std::move(allocator);
|
allocator_ = std::move(allocator);
|
||||||
shader_library_ = std::move(shader_library);
|
shader_library_ = std::move(shader_library);
|
||||||
@ -477,7 +484,7 @@ void ContextVK::Setup(Settings settings) {
|
|||||||
device_name_ = std::string(physical_device_properties.deviceName);
|
device_name_ = std::string(physical_device_properties.deviceName);
|
||||||
command_queue_vk_ = std::make_shared<CommandQueueVK>(weak_from_this());
|
command_queue_vk_ = std::make_shared<CommandQueueVK>(weak_from_this());
|
||||||
should_disable_surface_control_ = settings.disable_surface_control;
|
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;
|
is_valid_ = true;
|
||||||
|
|
||||||
// Create the GPU Tracer later because it depends on state from
|
// Create the GPU Tracer later because it depends on state from
|
||||||
|
@ -317,12 +317,6 @@ void DriverInfoVK::DumpToLog() const {
|
|||||||
FML_LOG(IMPORTANT) << stream.str();
|
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 {
|
bool DriverInfoVK::IsEmulator() const {
|
||||||
#if FML_OS_ANDROID
|
#if FML_OS_ANDROID
|
||||||
// Google SwiftShader on Android.
|
// Google SwiftShader on Android.
|
||||||
@ -358,4 +352,12 @@ bool DriverInfoVK::IsKnownBadDriver() const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<MaliGPU> DriverInfoVK::GetMaliGPUInfo() const {
|
||||||
|
return mali_gpu_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<AdrenoGPU> DriverInfoVK::GetAdrenoGPUInfo() const {
|
||||||
|
return adreno_gpu_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace impeller
|
} // namespace impeller
|
||||||
|
@ -239,17 +239,16 @@ class DriverInfoVK {
|
|||||||
bool IsKnownBadDriver() const;
|
bool IsKnownBadDriver() const;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
/// @brief Determines if the driver can batch submit command buffers
|
/// @brief Returns Mali GPU info if this is a Mali GPU, otherwise
|
||||||
/// without triggering erronious deadlock errors.
|
/// std::nullopt.
|
||||||
///
|
///
|
||||||
/// Early 600 series Adreno drivers would deadlock if a command
|
std::optional<MaliGPU> GetMaliGPUInfo() const;
|
||||||
/// buffer submission had too much work attached to it, this
|
|
||||||
/// requires the renderer to split up command buffers that could
|
//----------------------------------------------------------------------------
|
||||||
/// be logically combined.
|
/// @brief Returns Adreno GPU info if this is a Adreno GPU, otherwise
|
||||||
|
/// std::nullopt.
|
||||||
///
|
///
|
||||||
/// @return True if device can batch submit command buffers.
|
std::optional<AdrenoGPU> GetAdrenoGPUInfo() const;
|
||||||
///
|
|
||||||
bool CanBatchSubmitCommandBuffers() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_valid_ = false;
|
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;
|
prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
|
||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
return context->GetDriverInfo()->CanBatchSubmitCommandBuffers();
|
return !GetWorkarounds(*context->GetDriverInfo())
|
||||||
|
.batch_submit_command_buffer_timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DriverInfoVKTest, CanBatchSubmitCommandBuffers) {
|
TEST(DriverInfoVKTest, CanBatchSubmitCommandBuffers) {
|
||||||
@ -93,6 +94,35 @@ TEST(DriverInfoVKTest, CanBatchSubmitCommandBuffers) {
|
|||||||
EXPECT_TRUE(CanBatchSubmitTest("Adreno (TM) 750", true));
|
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) {
|
TEST(DriverInfoVKTest, DriverParsingMali) {
|
||||||
EXPECT_EQ(GetMaliVersion("Mali-G51-MORE STUFF"), MaliGPU::kG51);
|
EXPECT_EQ(GetMaliVersion("Mali-G51-MORE STUFF"), MaliGPU::kG51);
|
||||||
EXPECT_EQ(GetMaliVersion("Mali-G51"), MaliGPU::kG51);
|
EXPECT_EQ(GetMaliVersion("Mali-G51"), MaliGPU::kG51);
|
||||||
|
@ -362,6 +362,7 @@ fml::StatusOr<vk::UniquePipeline> MakePipeline(
|
|||||||
const auto topology = ToVKPrimitiveTopology(desc.GetPrimitiveType());
|
const auto topology = ToVKPrimitiveTopology(desc.GetPrimitiveType());
|
||||||
input_assembly.setTopology(topology);
|
input_assembly.setTopology(topology);
|
||||||
input_assembly.setPrimitiveRestartEnable(
|
input_assembly.setPrimitiveRestartEnable(
|
||||||
|
caps->SupportsPrimitiveRestart() &&
|
||||||
PrimitiveTopologySupportsPrimitiveRestart(desc.GetPrimitiveType()));
|
PrimitiveTopologySupportsPrimitiveRestart(desc.GetPrimitiveType()));
|
||||||
pipeline_info.setPInputAssemblyState(&input_assembly);
|
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