Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c763c91

Browse files
author
Jonah Williams
authored
[Impeller] batch submit vulkan command buffers on newer hardware. (#55956)
Coming back to this from the previous attempt: #50139 * Even if its slower sometimes, its also way faster on more complex scenes * The adreno bugs seem limited to older devices. Conservatively, only enable batching for Mali and newer Adreno On non vulkan backend we immediately submit.
1 parent dd37446 commit c763c91

18 files changed

+285
-129
lines changed

impeller/display_list/canvas.cc

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "display_list/effects/dl_image_filter.h"
1414
#include "flutter/fml/logging.h"
1515
#include "flutter/fml/trace_event.h"
16+
#include "impeller/base/validation.h"
1617
#include "impeller/display_list/color_filter.h"
1718
#include "impeller/display_list/image_filter.h"
1819
#include "impeller/display_list/skia_conversions.h"
@@ -1672,10 +1673,8 @@ bool Canvas::BlitToOnscreen() {
16721673
VALIDATION_LOG << "Failed to encode root pass blit command.";
16731674
return false;
16741675
}
1675-
if (!renderer_.GetContext()
1676-
->GetCommandQueue()
1677-
->Submit({command_buffer})
1678-
.ok()) {
1676+
if (!renderer_.GetContext()->EnqueueCommandBuffer(
1677+
std::move(command_buffer))) {
16791678
return false;
16801679
}
16811680
} else {
@@ -1703,10 +1702,8 @@ bool Canvas::BlitToOnscreen() {
17031702
VALIDATION_LOG << "Failed to encode root pass command buffer.";
17041703
return false;
17051704
}
1706-
if (!renderer_.GetContext()
1707-
->GetCommandQueue()
1708-
->Submit({command_buffer})
1709-
.ok()) {
1705+
if (!renderer_.GetContext()->EnqueueCommandBuffer(
1706+
std::move(command_buffer))) {
17101707
return false;
17111708
}
17121709
}
@@ -1726,6 +1723,10 @@ void Canvas::EndReplay() {
17261723
BlitToOnscreen();
17271724
}
17281725

1726+
if (!renderer_.GetContext()->FlushCommandBuffers()) {
1727+
// Not much we can do.
1728+
VALIDATION_LOG << "Failed to submit command buffers";
1729+
}
17291730
render_passes_.clear();
17301731
renderer_.GetRenderTargetCache()->End();
17311732
clip_geometry_.clear();

impeller/entity/contents/contents.cc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,7 @@ std::optional<Snapshot> Contents::RenderToSnapshot(
110110
if (!render_target.ok()) {
111111
return std::nullopt;
112112
}
113-
if (!renderer.GetContext()
114-
->GetCommandQueue()
115-
->Submit(/*buffers=*/{std::move(command_buffer)})
116-
.ok()) {
113+
if (!renderer.GetContext()->EnqueueCommandBuffer(std::move(command_buffer))) {
117114
return std::nullopt;
118115
}
119116

impeller/entity/contents/filters/blend_filter_contents.cc

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,7 @@ static std::optional<Entity> AdvancedBlend(
243243
if (!render_target.ok()) {
244244
return std::nullopt;
245245
}
246-
if (!renderer.GetContext()
247-
->GetCommandQueue()
248-
->Submit(/*buffers=*/{std::move(command_buffer)})
249-
.ok()) {
246+
if (!renderer.GetContext()->EnqueueCommandBuffer(std::move(command_buffer))) {
250247
return std::nullopt;
251248
}
252249

@@ -655,11 +652,7 @@ static std::optional<Entity> PipelineBlend(
655652
if (!render_target.ok()) {
656653
return std::nullopt;
657654
}
658-
659-
if (!renderer.GetContext()
660-
->GetCommandQueue()
661-
->Submit(/*buffers=*/{std::move(command_buffer)})
662-
.ok()) {
655+
if (!renderer.GetContext()->EnqueueCommandBuffer(std::move(command_buffer))) {
663656
return std::nullopt;
664657
}
665658

@@ -895,11 +888,7 @@ std::optional<Entity> BlendFilterContents::CreateFramebufferAdvancedBlend(
895888
if (!render_target.ok()) {
896889
return std::nullopt;
897890
}
898-
899-
if (!renderer.GetContext()
900-
->GetCommandQueue()
901-
->Submit(/*buffers=*/{std::move(cmd_buffer)})
902-
.ok()) {
891+
if (!renderer.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer))) {
903892
return std::nullopt;
904893
}
905894

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -817,11 +817,12 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
817817
return std::nullopt;
818818
}
819819

820-
if (!renderer.GetContext()
821-
->GetCommandQueue()
822-
->Submit(/*buffers=*/{command_buffer_1, command_buffer_2,
823-
command_buffer_3})
824-
.ok()) {
820+
if (!(renderer.GetContext()->EnqueueCommandBuffer(
821+
std::move(command_buffer_1)) &&
822+
renderer.GetContext()->EnqueueCommandBuffer(
823+
std::move(command_buffer_2)) &&
824+
renderer.GetContext()->EnqueueCommandBuffer(
825+
std::move(command_buffer_3)))) {
825826
return std::nullopt;
826827
}
827828

impeller/entity/contents/filters/morphology_filter_contents.cc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,8 @@ std::optional<Entity> DirectionalMorphologyFilterContents::RenderFilter(
144144
if (!render_target.ok()) {
145145
return std::nullopt;
146146
}
147-
if (!renderer.GetContext()
148-
->GetCommandQueue()
149-
->Submit(/*buffers=*/{std::move(command_buffer)})
150-
.ok()) {
147+
148+
if (!renderer.GetContext()->EnqueueCommandBuffer(std::move(command_buffer))) {
151149
return std::nullopt;
152150
}
153151

impeller/entity/inline_pass_context.cc

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,10 @@ bool InlinePassContext::EndPass() {
6161
return false;
6262
}
6363
}
64-
if (!renderer_.GetContext()
65-
->GetCommandQueue()
66-
->Submit({std::move(command_buffer_)})
67-
.ok()) {
68-
return false;
69-
}
7064

7165
pass_ = nullptr;
72-
command_buffer_ = nullptr;
73-
74-
return true;
66+
return renderer_.GetContext()->EnqueueCommandBuffer(
67+
std::move(command_buffer_));
7568
}
7669

7770
EntityPassTarget& InlinePassContext::GetPassTarget() const {

impeller/renderer/backend/vulkan/context_vk.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ void ContextVK::Setup(Settings settings) {
445445
device_name_ = std::string(physical_device_properties.deviceName);
446446
command_queue_vk_ = std::make_shared<CommandQueueVK>(weak_from_this());
447447
should_disable_surface_control_ = settings.disable_surface_control;
448+
should_batch_cmd_buffers_ = driver_info_->CanBatchSubmitCommandBuffers();
448449
is_valid_ = true;
449450

450451
// Create the GPU Tracer later because it depends on state from
@@ -590,6 +591,26 @@ std::shared_ptr<CommandQueue> ContextVK::GetCommandQueue() const {
590591
return command_queue_vk_;
591592
}
592593

594+
bool ContextVK::EnqueueCommandBuffer(
595+
std::shared_ptr<CommandBuffer> command_buffer) {
596+
if (should_batch_cmd_buffers_) {
597+
pending_command_buffers_.push_back(std::move(command_buffer));
598+
return true;
599+
} else {
600+
return GetCommandQueue()->Submit({command_buffer}).ok();
601+
}
602+
}
603+
604+
bool ContextVK::FlushCommandBuffers() {
605+
if (should_batch_cmd_buffers_) {
606+
bool result = GetCommandQueue()->Submit(pending_command_buffers_).ok();
607+
pending_command_buffers_.clear();
608+
return result;
609+
} else {
610+
return true;
611+
}
612+
}
613+
593614
// Creating a render pass is observed to take an additional 6ms on a Pixel 7
594615
// device as the driver will lazily bootstrap and compile shaders to do so.
595616
// The render pass does not need to be begun or executed.

impeller/renderer/backend/vulkan/context_vk.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "impeller/renderer/backend/vulkan/sampler_library_vk.h"
2323
#include "impeller/renderer/backend/vulkan/shader_library_vk.h"
2424
#include "impeller/renderer/capabilities.h"
25+
#include "impeller/renderer/command_buffer.h"
2526
#include "impeller/renderer/command_queue.h"
2627
#include "impeller/renderer/context.h"
2728

@@ -190,6 +191,13 @@ class ContextVK final : public Context,
190191
/// disabled, even if the device is capable of supporting it.
191192
bool GetShouldDisableSurfaceControlSwapchain() const;
192193

194+
// | Context |
195+
bool EnqueueCommandBuffer(
196+
std::shared_ptr<CommandBuffer> command_buffer) override;
197+
198+
// | Context |
199+
bool FlushCommandBuffers() override;
200+
193201
private:
194202
struct DeviceHolderImpl : public DeviceHolderVK {
195203
// |DeviceHolder|
@@ -223,6 +231,8 @@ class ContextVK final : public Context,
223231
std::shared_ptr<DescriptorPoolRecyclerVK> descriptor_pool_recycler_;
224232
std::shared_ptr<CommandQueue> command_queue_vk_;
225233
bool should_disable_surface_control_ = false;
234+
bool should_batch_cmd_buffers_ = false;
235+
std::vector<std::shared_ptr<CommandBuffer>> pending_command_buffers_;
226236

227237
const uint64_t hash_;
228238

impeller/renderer/backend/vulkan/context_vk_unittests.cc

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,5 +260,56 @@ TEST(ContextVKTest, HasDefaultColorFormat) {
260260
ASSERT_NE(capabilites_vk->GetDefaultColorFormat(), PixelFormat::kUnknown);
261261
}
262262

263+
TEST(ContextVKTest, BatchSubmitCommandBuffersOnArm) {
264+
std::shared_ptr<ContextVK> context =
265+
MockVulkanContextBuilder()
266+
.SetPhysicalPropertiesCallback(
267+
[](VkPhysicalDevice device, VkPhysicalDeviceProperties* prop) {
268+
prop->vendorID = 0x13B5; // ARM
269+
prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
270+
})
271+
.Build();
272+
273+
EXPECT_TRUE(context->EnqueueCommandBuffer(context->CreateCommandBuffer()));
274+
EXPECT_TRUE(context->EnqueueCommandBuffer(context->CreateCommandBuffer()));
275+
276+
// If command buffers are batch submitted, we should have created them but not
277+
// created the fence to track them after enqueing.
278+
auto functions = GetMockVulkanFunctions(context->GetDevice());
279+
EXPECT_TRUE(std::find(functions->begin(), functions->end(),
280+
"vkAllocateCommandBuffers") != functions->end());
281+
EXPECT_TRUE(std::find(functions->begin(), functions->end(),
282+
"vkCreateFence") == functions->end());
283+
284+
context->FlushCommandBuffers();
285+
286+
// After flushing, the fence should be created.
287+
functions = GetMockVulkanFunctions(context->GetDevice());
288+
EXPECT_TRUE(std::find(functions->begin(), functions->end(),
289+
"vkCreateFence") != functions->end());
290+
}
291+
292+
TEST(ContextVKTest, BatchSubmitCommandBuffersOnNonArm) {
293+
std::shared_ptr<ContextVK> context =
294+
MockVulkanContextBuilder()
295+
.SetPhysicalPropertiesCallback(
296+
[](VkPhysicalDevice device, VkPhysicalDeviceProperties* prop) {
297+
prop->vendorID = 0x8686; // Made up ID
298+
prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
299+
})
300+
.Build();
301+
302+
EXPECT_TRUE(context->EnqueueCommandBuffer(context->CreateCommandBuffer()));
303+
EXPECT_TRUE(context->EnqueueCommandBuffer(context->CreateCommandBuffer()));
304+
305+
// If command buffers are batch not submitted, we should have created them and
306+
// a corresponding fence immediately.
307+
auto functions = GetMockVulkanFunctions(context->GetDevice());
308+
EXPECT_TRUE(std::find(functions->begin(), functions->end(),
309+
"vkAllocateCommandBuffers") != functions->end());
310+
EXPECT_TRUE(std::find(functions->begin(), functions->end(),
311+
"vkCreateFence") != functions->end());
312+
}
313+
263314
} // namespace testing
264315
} // namespace impeller

impeller/renderer/backend/vulkan/driver_info_vk.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,12 @@ void DriverInfoVK::DumpToLog() const {
317317
FML_LOG(IMPORTANT) << stream.str();
318318
}
319319

320+
bool DriverInfoVK::CanBatchSubmitCommandBuffers() const {
321+
return vendor_ == VendorVK::kARM ||
322+
(adreno_gpu_.has_value() &&
323+
adreno_gpu_.value() >= AdrenoGPU::kAdreno702);
324+
}
325+
320326
bool DriverInfoVK::IsEmulator() const {
321327
#if FML_OS_ANDROID
322328
// Google SwiftShader on Android.

0 commit comments

Comments
 (0)