Skip to content

Commit f7d37ca

Browse files
author
Jonah Williams
authored
[Impeller] when decoding image on iOS, block on command buffer scheduling and log gpu errors. (flutter#169378)
Attempted fix for flutter#166668 . Plan is to ask for testing once rolled into g3 since we weren't given a repro. Explaination: we can only submit command buffers to the metal command queue when the device is in the foreground. push notifications temporarily wake up the app and can trigger images to begin decoding. This decoding can fail, possibly due to the app re-backgrounding. In theory, the sync switch should prevent this from happening - but because we don't actually block on the scheduling of the command buffer there is technically a race that can happen. Add the ability to block submission on scheduling for metal. note that other graphics APIs do not have a distinction for commited vs scheduled and so it no-ops for them. See https://developer.apple.com/documentation/metal/preparing-your-metal-app-to-run-in-the-background > When UIKit calls your app delegate’s [applicationDidEnterBackground(_:)](https://developer.apple.com/documentation/UIKit/UIApplicationDelegate/applicationDidEnterBackground(_:)) method, make sure Metal has scheduled all command buffers you’ve already committed before your app returns control to the system. ... Finish encoding commands to render the frame and commit the command buffer, then call [waitUntilScheduled()](https://developer.apple.com/documentation/metal/mtlcommandbuffer/waituntilscheduled()).
1 parent 7cc60d8 commit f7d37ca

File tree

15 files changed

+60
-26
lines changed

15 files changed

+60
-26
lines changed

engine/src/flutter/impeller/renderer/backend/gles/command_buffer_gles.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ bool CommandBufferGLES::IsValid() const {
2929
}
3030

3131
// |CommandBuffer|
32-
bool CommandBufferGLES::OnSubmitCommands(CompletionCallback callback) {
32+
bool CommandBufferGLES::OnSubmitCommands(bool block_on_schedule,
33+
CompletionCallback callback) {
3334
const auto result = reactor_->React();
3435
if (callback) {
3536
callback(result ? CommandBuffer::Status::kCompleted

engine/src/flutter/impeller/renderer/backend/gles/command_buffer_gles.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ class CommandBufferGLES final : public CommandBuffer {
3232
bool IsValid() const override;
3333

3434
// |CommandBuffer|
35-
bool OnSubmitCommands(CompletionCallback callback) override;
35+
bool OnSubmitCommands(bool block_on_schedule,
36+
CompletionCallback callback) override;
3637

3738
// |CommandBuffer|
3839
void OnWaitUntilCompleted() override;

engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ class CommandBufferMTL final : public CommandBuffer {
3434
bool IsValid() const override;
3535

3636
// |CommandBuffer|
37-
bool OnSubmitCommands(CompletionCallback callback) override;
37+
bool OnSubmitCommands(bool block_on_schedule,
38+
CompletionCallback callback) override;
3839

3940
// |CommandBuffer|
4041
void OnWaitUntilCompleted() override;

engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.mm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
162162
return CommandBufferMTL::Status::kError;
163163
}
164164

165-
bool CommandBufferMTL::OnSubmitCommands(CompletionCallback callback) {
165+
bool CommandBufferMTL::OnSubmitCommands(bool block_on_schedule,
166+
CompletionCallback callback) {
166167
auto context = context_.lock();
167168
if (!context) {
168169
return false;
@@ -182,6 +183,9 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
182183
}
183184

184185
[buffer_ commit];
186+
if (block_on_schedule) {
187+
[buffer_ waitUntilScheduled];
188+
}
185189

186190
buffer_ = nil;
187191
return true;

engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ bool CommandBufferVK::IsValid() const {
4343
return true;
4444
}
4545

46-
bool CommandBufferVK::OnSubmitCommands(CompletionCallback callback) {
46+
bool CommandBufferVK::OnSubmitCommands(bool block_on_schedule,
47+
CompletionCallback callback) {
4748
FML_UNREACHABLE()
4849
}
4950

engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ class CommandBufferVK final
9898
bool IsValid() const override;
9999

100100
// |CommandBuffer|
101-
bool OnSubmitCommands(CompletionCallback callback) override;
101+
bool OnSubmitCommands(bool block_on_schedule,
102+
CompletionCallback callback) override;
102103

103104
// |CommandBuffer|
104105
void OnWaitUntilCompleted() override;

engine/src/flutter/impeller/renderer/backend/vulkan/command_queue_vk.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ CommandQueueVK::~CommandQueueVK() = default;
2222

2323
fml::Status CommandQueueVK::Submit(
2424
const std::vector<std::shared_ptr<CommandBuffer>>& buffers,
25-
const CompletionCallback& completion_callback) {
25+
const CompletionCallback& completion_callback,
26+
bool block_on_schedule) {
2627
if (buffers.empty()) {
2728
return fml::Status(fml::StatusCode::kInvalidArgument,
2829
"No command buffers provided.");

engine/src/flutter/impeller/renderer/backend/vulkan/command_queue_vk.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ class CommandQueueVK : public CommandQueue {
1717

1818
~CommandQueueVK() override;
1919

20-
fml::Status Submit(
21-
const std::vector<std::shared_ptr<CommandBuffer>>& buffers,
22-
const CompletionCallback& completion_callback = {}) override;
20+
fml::Status Submit(const std::vector<std::shared_ptr<CommandBuffer>>& buffers,
21+
const CompletionCallback& completion_callback = {},
22+
bool block_on_schedule = false) override;
2323

2424
private:
2525
std::weak_ptr<ContextVK> context_;

engine/src/flutter/impeller/renderer/command_buffer.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,20 @@ CommandBuffer::CommandBuffer(std::weak_ptr<const Context> context)
1515

1616
CommandBuffer::~CommandBuffer() = default;
1717

18-
bool CommandBuffer::SubmitCommands(const CompletionCallback& callback) {
18+
bool CommandBuffer::SubmitCommands(bool block_on_schedule,
19+
const CompletionCallback& callback) {
1920
if (!IsValid()) {
2021
// Already committed or was never valid. Either way, this is caller error.
2122
if (callback) {
2223
callback(Status::kError);
2324
}
2425
return false;
2526
}
26-
return OnSubmitCommands(callback);
27+
return OnSubmitCommands(block_on_schedule, callback);
2728
}
2829

29-
bool CommandBuffer::SubmitCommands() {
30-
return SubmitCommands(nullptr);
30+
bool CommandBuffer::SubmitCommands(bool block_on_schedule) {
31+
return SubmitCommands(block_on_schedule, nullptr);
3132
}
3233

3334
void CommandBuffer::WaitUntilCompleted() {

engine/src/flutter/impeller/renderer/command_buffer.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ class CommandBuffer {
107107

108108
virtual std::shared_ptr<BlitPass> OnCreateBlitPass() = 0;
109109

110-
[[nodiscard]] virtual bool OnSubmitCommands(CompletionCallback callback) = 0;
110+
/// @brief Submit the command buffer to the GPU for execution.
111+
///
112+
/// See also: [SubmitCommands].
113+
[[nodiscard]] virtual bool OnSubmitCommands(bool block_on_schedule,
114+
CompletionCallback callback) = 0;
111115

112116
virtual void OnWaitUntilCompleted() = 0;
113117

@@ -124,12 +128,15 @@ class CommandBuffer {
124128
/// performed immediately on the calling thread.
125129
///
126130
/// A command buffer may only be committed once.
127-
///
131+
/// @param[in] block_on_schedule If true, this function will not return
132+
/// until the command buffer has been scheduled. This only impacts
133+
/// the Metal backend.
128134
/// @param[in] callback The completion callback.
129135
///
130-
[[nodiscard]] bool SubmitCommands(const CompletionCallback& callback);
136+
[[nodiscard]] bool SubmitCommands(bool block_on_schedule,
137+
const CompletionCallback& callback);
131138

132-
[[nodiscard]] bool SubmitCommands();
139+
[[nodiscard]] bool SubmitCommands(bool block_on_schedule);
133140

134141
CommandBuffer(const CommandBuffer&) = delete;
135142

0 commit comments

Comments
 (0)