mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Don’t depend on an implicit transaction when no external view embedder is present. (flutter/engine#17258)
All Metal layers have their presentsWithTransaction property set to true. However, when an external view embedder is not present, there is no mechanism to ensure that the command buffer commit is within transaction scope. This works in most cases as there there is usually an implicit (possibly nested) transaction in place during rendering. However, when there isn’t, rendering will look paused at an incorrect size. This code now works similar to OpenGL but will be refactored for ease of understanding and consistency between the various backends.
This commit is contained in:
parent
23b8e74799
commit
09be477a9f
@ -39,32 +39,25 @@ bool GPUSurfaceMetal::IsValid() {
|
||||
}
|
||||
|
||||
// |Surface|
|
||||
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& size) {
|
||||
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& frame_size) {
|
||||
if (!IsValid()) {
|
||||
FML_LOG(ERROR) << "Metal surface was invalid.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (size.isEmpty()) {
|
||||
if (frame_size.isEmpty()) {
|
||||
FML_LOG(ERROR) << "Metal surface was asked for an empty frame.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto bounds = layer_.get().bounds.size;
|
||||
const auto scale = layer_.get().contentsScale;
|
||||
if (bounds.width <= 0.0 || bounds.height <= 0.0 || scale <= 0.0) {
|
||||
FML_LOG(ERROR) << "Metal layer bounds were invalid.";
|
||||
return nullptr;
|
||||
}
|
||||
const auto drawable_size = CGSizeMake(frame_size.width(), frame_size.height());
|
||||
|
||||
const auto scaled_bounds = CGSizeMake(bounds.width * scale, bounds.height * scale);
|
||||
if (!CGSizeEqualToSize(drawable_size, layer_.get().drawableSize)) {
|
||||
layer_.get().drawableSize = drawable_size;
|
||||
}
|
||||
|
||||
ReleaseUnusedDrawableIfNecessary();
|
||||
|
||||
if (!CGSizeEqualToSize(scaled_bounds, layer_.get().drawableSize)) {
|
||||
layer_.get().drawableSize = scaled_bounds;
|
||||
}
|
||||
|
||||
auto surface = SkSurface::MakeFromCAMetalLayer(context_.get(), // context
|
||||
layer_.get(), // layer
|
||||
kTopLeft_GrSurfaceOrigin, // origin
|
||||
@ -89,8 +82,6 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& size)
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto has_external_view_embedder = delegate_->GetExternalViewEmbedder() != nullptr;
|
||||
|
||||
auto command_buffer =
|
||||
fml::scoped_nsprotocol<id<MTLCommandBuffer>>([[command_queue_.get() commandBuffer] retain]);
|
||||
|
||||
@ -98,21 +89,10 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& size)
|
||||
reinterpret_cast<id<CAMetalDrawable>>(next_drawable_));
|
||||
next_drawable_ = nullptr;
|
||||
|
||||
// External views need to present with transaction. When presenting with
|
||||
// transaction, we have to block, otherwise we risk presenting the drawable
|
||||
// after the CATransaction has completed.
|
||||
// See:
|
||||
// https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction
|
||||
// TODO(dnfield): only do this if transactions are actually being used.
|
||||
// https://github.com/flutter/flutter/issues/24133
|
||||
if (!has_external_view_embedder) {
|
||||
[command_buffer.get() presentDrawable:drawable.get()];
|
||||
[command_buffer.get() commit];
|
||||
} else {
|
||||
[command_buffer.get() commit];
|
||||
[command_buffer.get() waitUntilScheduled];
|
||||
[drawable.get() present];
|
||||
}
|
||||
[command_buffer.get() commit];
|
||||
[command_buffer.get() waitUntilScheduled];
|
||||
[drawable.get() present];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user