Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] iOS/macOS: Only wait for command scheduling prior to present (redux) #41501

Merged
merged 2 commits into from Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 0 additions & 21 deletions impeller/renderer/backend/metal/command_buffer_mtl.mm
Expand Up @@ -167,27 +167,6 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {

[buffer_ commit];

#if (FML_OS_MACOSX || FML_OS_IOS_SIMULATOR)
// We're using waitUntilScheduled on macOS and iOS simulator to force a hard
// barrier between the execution of different command buffers. This forces all
// renderable texture access to be synchronous (i.e. a write from a previous
// command buffer will not get scheduled to happen at the same time as a read
// in a future command buffer).
//
// Metal hazard tracks shared memory resources by default, and we don't need
// to do any additional work to synchronize access to MTLTextures and
// MTLBuffers on iOS devices with UMA. However, shared textures are disallowed
// on macOS according to the documentation:
// https://developer.apple.com/documentation/metal/mtlstoragemode/shared
// And so this is a stopgap solution that has been present in Impeller since
// multi-pass rendering/SaveLayer support was first set up.
//
// TODO(bdero): Remove this for all targets once a solution for resource
// tracking that works everywhere is established:
// https://github.com/flutter/flutter/issues/120406
[buffer_ waitUntilScheduled];
#endif

buffer_ = nil;
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions impeller/renderer/backend/metal/context_mtl.h
Expand Up @@ -63,6 +63,8 @@ class ContextMTL final : public Context,
// |Context|
bool UpdateOffscreenLayerPixelFormat(PixelFormat format) override;

id<MTLCommandBuffer> CreateMTLCommandBuffer() const;

private:
id<MTLDevice> device_ = nullptr;
id<MTLCommandQueue> command_queue_ = nullptr;
Expand Down
4 changes: 4 additions & 0 deletions impeller/renderer/backend/metal/context_mtl.mm
Expand Up @@ -289,4 +289,8 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) {
return true;
}

id<MTLCommandBuffer> ContextMTL::CreateMTLCommandBuffer() const {
return [command_queue_ commandBuffer];
}

} // namespace impeller
5 changes: 4 additions & 1 deletion impeller/renderer/backend/metal/surface_mtl.h
Expand Up @@ -43,9 +43,12 @@ class SurfaceMTL final : public Surface {
id<MTLDrawable> drawable() const { return drawable_; }

private:
std::weak_ptr<Context> context_;
id<MTLDrawable> drawable_ = nil;

SurfaceMTL(const RenderTarget& target, id<MTLDrawable> drawable);
SurfaceMTL(const std::weak_ptr<Context>& context,
const RenderTarget& target,
id<MTLDrawable> drawable);

// |Surface|
bool Present() const override;
Expand Down
25 changes: 21 additions & 4 deletions impeller/renderer/backend/metal/surface_mtl.mm
Expand Up @@ -6,6 +6,7 @@

#include "flutter/fml/trace_event.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/metal/context_mtl.h"
#include "impeller/renderer/backend/metal/formats_mtl.h"
#include "impeller/renderer/backend/metal/texture_mtl.h"
#include "impeller/renderer/render_target.h"
Expand Down Expand Up @@ -111,12 +112,14 @@
render_target_desc.SetStencilAttachment(stencil0);

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

SurfaceMTL::SurfaceMTL(const RenderTarget& target, id<MTLDrawable> drawable)
: Surface(target), drawable_(drawable) {}
SurfaceMTL::SurfaceMTL(const std::weak_ptr<Context>& context,
const RenderTarget& target,
id<MTLDrawable> drawable)
: Surface(target), context_(context), drawable_(drawable) {}

// |Surface|
SurfaceMTL::~SurfaceMTL() = default;
Expand All @@ -127,7 +130,21 @@
return false;
}

auto context = context_.lock();
if (!context) {
return false;
}

// If a transaction is present, `presentDrawable` will present too early. And
// so we wait on an empty command buffer to get scheduled instead, which
// forces us to also wait for all of the previous command buffers in the queue
// to get scheduled.
id<MTLCommandBuffer> command_buffer =
ContextMTL::Cast(context.get())->CreateMTLCommandBuffer();
[command_buffer commit];
[command_buffer waitUntilScheduled];
[drawable_ present];

return true;
}
#pragma GCC diagnostic pop
Expand Down
2 changes: 1 addition & 1 deletion shell/platform/darwin/ios/ios_surface_metal_impeller.mm
Expand Up @@ -59,7 +59,7 @@
// When there are platform views in the scene, the drawable needs to be presented in the same
// transaction as the one created for platform views. When the drawable are being presented from
// the raster thread, there is no such transaction.
layer.presentsWithTransaction = [[NSThread currentThread] isMainThread];
layer.presentsWithTransaction = YES;

return layer;
}
Expand Down