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

Commit 21d2761

Browse files
committed
[Impeller] Use waitUntilScheduled before presenting
1 parent 7d190aa commit 21d2761

File tree

6 files changed

+57
-18
lines changed

6 files changed

+57
-18
lines changed

impeller/renderer/backend/metal/command_buffer_mtl.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include <Metal/Metal.h>
8+
#include <functional>
89

910
#include "flutter/fml/macros.h"
1011
#include "impeller/renderer/command_buffer.h"
@@ -13,16 +14,20 @@ namespace impeller {
1314

1415
class CommandBufferMTL final : public CommandBuffer {
1516
public:
17+
using SubmitCallback = std::function<void(id<MTLCommandBuffer> buffer)>;
18+
1619
// |CommandBuffer|
1720
~CommandBufferMTL() override;
1821

1922
private:
2023
friend class ContextMTL;
2124

2225
id<MTLCommandBuffer> buffer_ = nullptr;
26+
SubmitCallback submit_callback_;
2327

2428
CommandBufferMTL(const std::weak_ptr<const Context>& context,
25-
id<MTLCommandQueue> queue);
29+
id<MTLCommandQueue> queue,
30+
SubmitCallback on_submit);
2631

2732
// |CommandBuffer|
2833
void SetLabel(const std::string& label) const override;

impeller/renderer/backend/metal/command_buffer_mtl.mm

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "impeller/renderer/backend/metal/blit_pass_mtl.h"
88
#include "impeller/renderer/backend/metal/compute_pass_mtl.h"
9+
#include "impeller/renderer/backend/metal/context_mtl.h"
910
#include "impeller/renderer/backend/metal/render_pass_mtl.h"
1011

1112
namespace impeller {
@@ -124,8 +125,11 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
124125
}
125126

126127
CommandBufferMTL::CommandBufferMTL(const std::weak_ptr<const Context>& context,
127-
id<MTLCommandQueue> queue)
128-
: CommandBuffer(context), buffer_(CreateCommandBuffer(queue)) {}
128+
id<MTLCommandQueue> queue,
129+
SubmitCallback on_submit)
130+
: CommandBuffer(context),
131+
buffer_(CreateCommandBuffer(queue)),
132+
submit_callback_(std::move(on_submit)) {}
129133

130134
CommandBufferMTL::~CommandBufferMTL() = default;
131135

@@ -166,20 +170,16 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
166170
}
167171

168172
[buffer_ commit];
173+
submit_callback_(buffer_);
169174

170-
#if (FML_OS_MACOSX || FML_OS_IOS_SIMULATOR)
171-
// We're using waitUntilScheduled on macOS and iOS simulator to force a hard
172-
// barrier between the execution of different command buffers. This forces all
173-
// renderable texture access to be synchronous (i.e. a write from a previous
174-
// command buffer will not get scheduled to happen at the same time as a read
175-
// in a future command buffer).
176-
//
175+
#if (FML_OS_MACOSX)
177176
// Metal hazard tracks shared memory resources by default, and we don't need
178177
// to do any additional work to synchronize access to MTLTextures and
179178
// MTLBuffers on iOS devices with UMA. However, shared textures are disallowed
180179
// on macOS according to the documentation:
181180
// https://developer.apple.com/documentation/metal/mtlstoragemode/shared
182-
// And so this is a stopgap solution that has been present in Impeller since
181+
//
182+
// This is a stopgap solution that has been present in Impeller since
183183
// multi-pass rendering/SaveLayer support was first set up.
184184
//
185185
// TODO(bdero): Remove this for all targets once a solution for resource

impeller/renderer/backend/metal/context_mtl.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,21 @@ class ContextMTL final : public Context,
6464
// |Context|
6565
bool UpdateOffscreenLayerPixelFormat(PixelFormat format) override;
6666

67+
/// @brief Block the current thread until all of the previously submitted
68+
/// command buffers have been scheduled. This should be called before
69+
/// using non-command Metal functions that access resources mutated by
70+
/// a previous command buffer.
71+
/// For example, when rendering a frame, this should be called
72+
/// immediately before `MTLDrawable::present()` (which should be
73+
/// called after all command buffers in the frame have already been
74+
/// submitted).
75+
void WaitUntilScheduled();
76+
6777
private:
6878
id<MTLDevice> device_ = nullptr;
6979
id<MTLCommandQueue> command_queue_ = nullptr;
80+
mutable id<MTLCommandBuffer> last_committed_buffer_ = nullptr;
81+
mutable std::mutex last_committed_buffer_lock_;
7082
std::shared_ptr<ShaderLibraryMTL> shader_library_;
7183
std::shared_ptr<PipelineLibraryMTL> pipeline_library_;
7284
std::shared_ptr<SamplerLibrary> sampler_library_;

impeller/renderer/backend/metal/context_mtl.mm

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "impeller/renderer/backend/metal/context_mtl.h"
66

77
#include <Foundation/Foundation.h>
8+
#include <mutex>
89

910
#include "flutter/fml/file.h"
1011
#include "flutter/fml/logging.h"
@@ -264,8 +265,11 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) {
264265
return nullptr;
265266
}
266267

267-
auto buffer = std::shared_ptr<CommandBufferMTL>(
268-
new CommandBufferMTL(weak_from_this(), queue));
268+
auto buffer = std::shared_ptr<CommandBufferMTL>(new CommandBufferMTL(
269+
weak_from_this(), queue, [this](id<MTLCommandBuffer> buffer) mutable {
270+
std::scoped_lock lock(last_committed_buffer_lock_);
271+
last_committed_buffer_ = buffer;
272+
}));
269273
if (!buffer->IsValid()) {
270274
return nullptr;
271275
}
@@ -290,4 +294,13 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) {
290294
return true;
291295
}
292296

297+
void ContextMTL::WaitUntilScheduled() {
298+
if (!last_committed_buffer_) {
299+
return;
300+
}
301+
302+
[last_committed_buffer_ waitUntilScheduled];
303+
last_committed_buffer_ = nullptr;
304+
}
305+
293306
} // namespace impeller

impeller/renderer/backend/metal/surface_mtl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include <QuartzCore/CAMetalLayer.h>
8+
#include <memory>
89

910
#include "flutter/fml/macros.h"
1011
#include "impeller/renderer/context.h"
@@ -43,9 +44,12 @@ class SurfaceMTL final : public Surface {
4344
id<MTLDrawable> drawable() const { return drawable_; }
4445

4546
private:
47+
std::weak_ptr<Context> context_;
4648
id<MTLDrawable> drawable_ = nil;
4749

48-
SurfaceMTL(const RenderTarget& target, id<MTLDrawable> drawable);
50+
SurfaceMTL(const std::weak_ptr<Context>& context,
51+
const RenderTarget& target,
52+
id<MTLDrawable> drawable);
4953

5054
// |Surface|
5155
bool Present() const override;

impeller/renderer/backend/metal/surface_mtl.mm

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "flutter/fml/trace_event.h"
88
#include "impeller/base/validation.h"
9+
#include "impeller/renderer/backend/metal/context_mtl.h"
910
#include "impeller/renderer/backend/metal/formats_mtl.h"
1011
#include "impeller/renderer/backend/metal/texture_mtl.h"
1112
#include "impeller/renderer/render_target.h"
@@ -111,12 +112,14 @@
111112
render_target_desc.SetStencilAttachment(stencil0);
112113

113114
// The constructor is private. So make_unique may not be used.
114-
return std::unique_ptr<SurfaceMTL>(
115-
new SurfaceMTL(render_target_desc, current_drawable));
115+
return std::unique_ptr<SurfaceMTL>(new SurfaceMTL(
116+
context->weak_from_this(), render_target_desc, current_drawable));
116117
}
117118

118-
SurfaceMTL::SurfaceMTL(const RenderTarget& target, id<MTLDrawable> drawable)
119-
: Surface(target), drawable_(drawable) {}
119+
SurfaceMTL::SurfaceMTL(const std::weak_ptr<Context>& context,
120+
const RenderTarget& target,
121+
id<MTLDrawable> drawable)
122+
: Surface(target), context_(context), drawable_(drawable) {}
120123

121124
// |Surface|
122125
SurfaceMTL::~SurfaceMTL() = default;
@@ -127,6 +130,8 @@
127130
return false;
128131
}
129132

133+
ContextMTL::Cast(context_.lock().get())->WaitUntilScheduled();
134+
130135
[drawable_ present];
131136
return true;
132137
}

0 commit comments

Comments
 (0)