未验证 提交 5bf65335 编写于 作者: K Kaushik Iska 提交者: GitHub

Introduce a delegate class for gpu metal rendering (#22611)

上级 3c516792
......@@ -673,6 +673,8 @@ FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.h
FILE: ../../../flutter/shell/gpu/gpu_surface_metal.h
FILE: ../../../flutter/shell/gpu/gpu_surface_metal.mm
FILE: ../../../flutter/shell/gpu/gpu_surface_metal_delegate.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_metal_delegate.h
FILE: ../../../flutter/shell/gpu/gpu_surface_software.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_software.h
FILE: ../../../flutter/shell/gpu/gpu_surface_software_delegate.cc
......@@ -932,6 +934,8 @@ FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStan
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_codecs_unittest.mm
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_standard_codec_unittest.mm
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.h
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Flutter.podspec
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h
......
......@@ -29,9 +29,9 @@ Animator::Animator(Delegate& delegate,
last_vsync_start_time_(),
last_frame_target_time_(),
dart_frame_deadline_(0),
#if FLUTTER_SHELL_ENABLE_METAL
#if SHELL_ENABLE_METAL
layer_tree_pipeline_(fml::MakeRefCounted<LayerTreePipeline>(2)),
#else // FLUTTER_SHELL_ENABLE_METAL
#else // SHELL_ENABLE_METAL
// TODO(dnfield): We should remove this logic and set the pipeline depth
// back to 2 in this case. See
// https://github.com/flutter/engine/pull/9132 for discussion.
......@@ -40,7 +40,7 @@ Animator::Animator(Delegate& delegate,
task_runners.GetRasterTaskRunner()
? 1
: 2)),
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // SHELL_ENABLE_METAL
pending_frame_semaphore_(1),
frame_number_(1),
paused_(false),
......
......@@ -51,6 +51,8 @@ source_set("gpu_surface_metal") {
sources = [
"gpu_surface_metal.h",
"gpu_surface_metal.mm",
"gpu_surface_metal_delegate.cc",
"gpu_surface_metal_delegate.h",
]
deps = gpu_common_deps
......
......@@ -5,36 +5,31 @@
#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_H_
#define FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_H_
#include <Metal/Metal.h>
#include "flutter/flow/surface.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/mtl/GrMtlTypes.h"
@class CAMetalLayer;
namespace flutter {
class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface {
public:
GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
sk_sp<GrDirectContext> context,
fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue);
GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate,
sk_sp<GrDirectContext> context);
// |Surface|
~GPUSurfaceMetal();
private:
fml::scoped_nsobject<CAMetalLayer> layer_;
sk_sp<GrDirectContext> context_;
fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue_;
GrMTLHandle next_drawable_ = nullptr;
// |Surface|
bool IsValid() override;
private:
const GPUSurfaceMetalDelegate* delegate_;
const MTLRenderTargetType render_target_type_;
GrMTLHandle next_drawable_ = nullptr;
sk_sp<GrDirectContext> context_;
// |Surface|
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
......@@ -47,6 +42,12 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface {
// |Surface|
std::unique_ptr<GLContextResult> MakeRenderContextCurrent() override;
std::unique_ptr<SurfaceFrame> AcquireFrameFromCAMetalLayer(
const SkISize& frame_info);
std::unique_ptr<SurfaceFrame> AcquireFrameFromMTLTexture(
const SkISize& frame_info);
void ReleaseUnusedDrawableIfNecessary();
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceMetal);
......
......@@ -4,9 +4,12 @@
#include "flutter/shell/gpu/gpu_surface_metal.h"
#include <QuartzCore/CAMetalLayer.h>
#import <Metal/Metal.h>
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/platform/darwin/cf_utils.h"
#include "flutter/fml/trace_event.h"
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/ports/SkCFObject.h"
......@@ -15,17 +18,10 @@ static_assert(!__has_feature(objc_arc), "ARC must be disabled.");
namespace flutter {
GPUSurfaceMetal::GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
sk_sp<GrDirectContext> context,
fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue)
: layer_(std::move(layer)),
context_(std::move(context)),
command_queue_(std::move(command_queue)) {
layer_.get().pixelFormat = MTLPixelFormatBGRA8Unorm;
// Flutter needs to read from the color attachment in cases where there are effects such as
// backdrop filters.
layer_.get().framebufferOnly = NO;
}
GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate, sk_sp<GrDirectContext> context)
: delegate_(delegate),
render_target_type_(delegate->GetRenderTargetType()),
context_(std::move(context)) {}
GPUSurfaceMetal::~GPUSurfaceMetal() {
ReleaseUnusedDrawableIfNecessary();
......@@ -33,7 +29,7 @@ GPUSurfaceMetal::~GPUSurfaceMetal() {
// |Surface|
bool GPUSurfaceMetal::IsValid() {
return layer_ && context_ && command_queue_;
return context_ != nullptr;
}
// |Surface|
......@@ -48,36 +44,91 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& frame
return nullptr;
}
const auto drawable_size = CGSizeMake(frame_size.width(), frame_size.height());
switch (render_target_type_) {
case MTLRenderTargetType::kCAMetalLayer:
return AcquireFrameFromCAMetalLayer(frame_size);
case MTLRenderTargetType::kMTLTexture:
return AcquireFrameFromMTLTexture(frame_size);
default:
FML_CHECK(false) << "Unknown MTLRenderTargetType type.";
}
return nullptr;
}
if (!CGSizeEqualToSize(drawable_size, layer_.get().drawableSize)) {
layer_.get().drawableSize = drawable_size;
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrameFromCAMetalLayer(
const SkISize& frame_info) {
auto layer = delegate_->GetCAMetalLayer(frame_info);
if (!layer) {
FML_LOG(ERROR) << "Invalid CAMetalLayer given by the embedder.";
return nullptr;
}
ReleaseUnusedDrawableIfNecessary();
sk_sp<SkSurface> surface =
SkSurface::MakeFromCAMetalLayer(context_.get(), // context
layer, // layer
kTopLeft_GrSurfaceOrigin, // origin
1, // sample count
kBGRA_8888_SkColorType, // color type
nullptr, // colorspace
nullptr, // surface properties
&next_drawable_ // drawable (transfer out)
);
if (!surface) {
FML_LOG(ERROR) << "Could not create the SkSurface from the CAMetalLayer.";
return nullptr;
}
auto submit_callback =
fml::MakeCopyable([drawable = next_drawable_, delegate = delegate_](
const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit");
if (canvas == nullptr) {
FML_DLOG(ERROR) << "Canvas not available.";
return false;
}
canvas->flush();
// 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_.get().presentsWithTransaction = [[NSThread currentThread] isMainThread];
auto surface = SkSurface::MakeFromCAMetalLayer(context_.get(), // context
layer_.get(), // layer
kTopLeft_GrSurfaceOrigin, // origin
1, // sample count
kBGRA_8888_SkColorType, // color type
nullptr, // colorspace
nullptr, // surface properties
&next_drawable_ // drawable (transfer out)
);
if (!drawable) {
FML_DLOG(ERROR) << "Unable to obtain a metal drawable.";
return false;
}
return delegate->PresentDrawable(drawable);
});
return std::make_unique<SurfaceFrame>(std::move(surface), true, submit_callback);
}
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrameFromMTLTexture(
const SkISize& frame_info) {
GPUMTLTextureInfo texture = delegate_->GetMTLTexture(frame_info);
id<MTLTexture> mtl_texture = (id<MTLTexture>)(texture.texture);
if (!mtl_texture) {
FML_LOG(ERROR) << "Invalid MTLTexture given by the embedder.";
return nullptr;
}
GrMtlTextureInfo info;
info.fTexture.reset([mtl_texture retain]);
GrBackendTexture backend_texture(frame_info.width(), frame_info.height(), GrMipmapped::kNo, info);
sk_sp<SkSurface> surface =
SkSurface::MakeFromBackendTexture(context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin,
1, kBGRA_8888_SkColorType, nullptr, nullptr);
if (!surface) {
FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture.";
return nullptr;
}
auto submit_callback = [this](const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit");
auto submit_callback = [texture_id = texture.texture_id, delegate = delegate_](
const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
TRACE_EVENT0("flutter", "GPUSurfaceMetal::PresentTexture");
if (canvas == nullptr) {
FML_DLOG(ERROR) << "Canvas not available.";
return false;
......@@ -85,23 +136,7 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& frame
canvas->flush();
if (next_drawable_ == nullptr) {
FML_DLOG(ERROR) << "Could not acquire next Metal drawable from the SkSurface.";
return false;
}
auto command_buffer =
fml::scoped_nsprotocol<id<MTLCommandBuffer>>([[command_queue_.get() commandBuffer] retain]);
fml::scoped_nsprotocol<id<CAMetalDrawable>> drawable(
reinterpret_cast<id<CAMetalDrawable>>(next_drawable_));
next_drawable_ = nullptr;
[command_buffer.get() commit];
[command_buffer.get() waitUntilScheduled];
[drawable.get() present];
return true;
return delegate->PresentTexture(texture_id);
};
return std::make_unique<SurfaceFrame>(std::move(surface), true, submit_callback);
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
namespace flutter {
GPUSurfaceMetalDelegate::GPUSurfaceMetalDelegate(
MTLRenderTargetType render_target_type)
: render_target_type_(render_target_type) {}
GPUSurfaceMetalDelegate::~GPUSurfaceMetalDelegate() = default;
MTLRenderTargetType GPUSurfaceMetalDelegate::GetRenderTargetType() {
return render_target_type_;
}
} // namespace flutter
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_DELEGATE_H_
#define FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_DELEGATE_H_
#include <stdint.h>
#include "flutter/fml/macros.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/mtl/GrMtlTypes.h"
namespace flutter {
// expected to be id<MTLDevice>
typedef void* GPUMTLDeviceHandle;
// expected to be id<MTLCommandQueues>
typedef void* GPUMTLCommandQueueHandle;
// expected to be CAMetalLayer*
typedef void* GPUCAMetalLayerHandle;
// expected to be id<MTLTexture>
typedef void* GPUMTLTextureHandle;
struct GPUMTLTextureInfo {
intptr_t texture_id;
GPUMTLTextureHandle texture;
};
enum class MTLRenderTargetType { kMTLTexture, kCAMetalLayer };
//------------------------------------------------------------------------------
/// @brief Interface implemented by all platform surfaces that can present
/// a metal backing store to the "screen". The GPU surface
/// abstraction (which abstracts the client rendering API) uses this
/// delegation pattern to tell the platform surface (which abstracts
/// how backing stores fulfilled by the selected client rendering
/// API end up on the "screen" on a particular platform) when the
/// rasterizer needs to allocate and present the software backing
/// store.
///
/// @see |IOSurfaceMetal| and |EmbedderSurfaceMetal|.
///
class GPUSurfaceMetalDelegate {
public:
//------------------------------------------------------------------------------
/// @brief Construct a new GPUSurfaceMetalDelegate object with the specified
/// render_target type.
///
/// @see |MTLRenderTargetType|
///
explicit GPUSurfaceMetalDelegate(MTLRenderTargetType render_target);
virtual ~GPUSurfaceMetalDelegate();
//------------------------------------------------------------------------------
/// @brief Returns the handle to the CAMetalLayer to render to. This is only
/// called when the specifed render target type is `kCAMetalLayer`.
///
virtual GPUCAMetalLayerHandle GetCAMetalLayer(
const SkISize& frame_info) const = 0;
//------------------------------------------------------------------------------
/// @brief Presents the drawable to the "screen". The drawable is obtained
/// from the CAMetalLayer that given by `GetCAMetalLayer` call. This is only
/// called when the specified render target type in `kCAMetalLayer`.
///
/// @see |GPUSurfaceMetalDelegate::GetCAMetalLayer|
///
virtual bool PresentDrawable(GrMTLHandle drawable) const = 0;
//------------------------------------------------------------------------------
/// @brief Returns the handle to the MTLTexture to render to. This is only
/// called when the specefied render target type is `kMTLTexture`.
///
virtual GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_info) const = 0;
//------------------------------------------------------------------------------
/// @brief Presents the texture with `texture_id` to the "screen".
/// `texture_id` corresponds to a texture that has been obtained by an earlier
/// call to `GetMTLTexture`. This is only called when the specefied render
/// target type is `kMTLTexture`.
///
/// @see |GPUSurfaceMetalDelegate::GetMTLTexture|
///
virtual bool PresentTexture(intptr_t texture_id) const = 0;
MTLRenderTargetType GetRenderTargetType();
private:
const MTLRenderTargetType render_target_type_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_DELEGATE_H_
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
assert(is_ios || is_mac)
import("//flutter/common/config.gni")
source_set("graphics") {
cflags_objc = flutter_cflags_objc
cflags_objcc = flutter_cflags_objcc
sources = [
"FlutterDarwinContextMetal.h",
"FlutterDarwinContextMetal.mm",
]
deps = [
"//flutter/common/graphics",
"//flutter/fml",
]
public_deps = [ "//third_party/skia" ]
public_configs = [ "//flutter:config" ]
}
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SHELL_PLATFORM_DARWIN_GRAPHICS_DARWIN_CONTEXT_METAL_H_
#define SHELL_PLATFORM_DARWIN_GRAPHICS_DARWIN_CONTEXT_METAL_H_
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
#include "third_party/skia/include/gpu/GrDirectContext.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Provides skia GrContexts that are shared between iOS and macOS embeddings.
*/
@interface FlutterDarwinContextMetal : NSObject
/**
* Initializes a FlutterDarwinContextMetal with the system default MTLDevice and a new
* MTLCommandQueue.
*/
- (instancetype)initWithDefaultMTLDevice;
/**
* Initializes a FlutterDarwinContextMetal with provided MTLDevice and MTLCommandQueue.
*/
- (instancetype)initWithMTLDevice:(id<MTLDevice>)mtlDevice
commandQueue:(id<MTLCommandQueue>)commandQueue;
/**
* MTLDevice that is backing this context.s
*/
@property(nonatomic, readonly) id<MTLDevice> mtlDevice;
/**
* MTLCommandQueue that is acquired from the `mtlDevice`. This queue is used both for rendering and
* resource related commands.
*/
@property(nonatomic, readonly) id<MTLCommandQueue> mtlCommandQueue;
/**
* Skia GrContext that is used for rendering.
*/
@property(nonatomic, readonly) sk_sp<GrDirectContext> mainContext;
/**
* Skia GrContext that is used for resources (uploading textures etc).
*/
@property(nonatomic, readonly) sk_sp<GrDirectContext> resourceContext;
@end
NS_ASSUME_NONNULL_END
#endif // SHELL_PLATFORM_DARWIN_GRAPHICS_DARWIN_CONTEXT_METAL_H_
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.h"
#include "flutter/common/graphics/persistent_cache.h"
#include "flutter/fml/logging.h"
#include "third_party/skia/include/gpu/GrContextOptions.h"
static GrContextOptions CreateMetalGrContextOptions() {
GrContextOptions options = {};
if (flutter::PersistentCache::cache_sksl()) {
options.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kSkSL;
}
flutter::PersistentCache::MarkStrategySet();
options.fPersistentCache = flutter::PersistentCache::GetCacheForProcess();
return options;
}
@implementation FlutterDarwinContextMetal
- (instancetype)initWithDefaultMTLDevice {
id<MTLDevice> mtlDevice = MTLCreateSystemDefaultDevice();
return [self initWithMTLDevice:mtlDevice commandQueue:[mtlDevice newCommandQueue]];
}
- (instancetype)initWithMTLDevice:(id<MTLDevice>)mtlDevice
commandQueue:(id<MTLCommandQueue>)commandQueue {
self = [super init];
if (self != nil) {
_mtlDevice = mtlDevice;
if (!_mtlDevice) {
FML_DLOG(ERROR) << "Could not acquire Metal device.";
[self release];
return nil;
}
_mtlCommandQueue = commandQueue;
if (!_mtlCommandQueue) {
FML_DLOG(ERROR) << "Could not create Metal command queue.";
[self release];
return nil;
}
[_mtlCommandQueue setLabel:@"Flutter Main Queue"];
auto contextOptions = CreateMetalGrContextOptions();
// Skia expect arguments to `MakeMetal` transfer ownership of the reference in for release later
// when the GrDirectContext is collected.
_mainContext =
GrDirectContext::MakeMetal([_mtlDevice retain], [_mtlCommandQueue retain], contextOptions);
_resourceContext =
GrDirectContext::MakeMetal([_mtlDevice retain], [_mtlCommandQueue retain], contextOptions);
if (!_mainContext || !_resourceContext) {
FML_DLOG(ERROR) << "Could not create Skia Metal contexts.";
[self release];
return nil;
}
_resourceContext->setResourceCacheLimits(0u, 0u);
}
return self;
}
@end
......@@ -42,6 +42,8 @@ source_set("flutter_framework_source") {
cflags_objc = flutter_cflags_objc
cflags_objcc = flutter_cflags_objcc
deps = []
sources = [
"framework/Source/FlutterAppDelegate.mm",
"framework/Source/FlutterBinaryMessengerRelay.mm",
......@@ -116,8 +118,6 @@ source_set("flutter_framework_source") {
defines = [ "FLUTTER_FRAMEWORK=1" ]
if (shell_enable_metal) {
defines += [ "FLUTTER_SHELL_ENABLE_METAL=1" ]
sources += [
"ios_context_metal.h",
"ios_context_metal.mm",
......@@ -126,9 +126,11 @@ source_set("flutter_framework_source") {
"ios_surface_metal.h",
"ios_surface_metal.mm",
]
deps += [ "//flutter/shell/platform/darwin/graphics" ]
}
deps = [
deps += [
":ios_gpu_configuration",
"//flutter/common",
"//flutter/common/graphics",
......@@ -144,7 +146,10 @@ source_set("flutter_framework_source") {
"//third_party/skia",
]
public_configs = [ "//flutter:config" ]
public_configs = [
":ios_gpu_configuration_config",
"//flutter:config",
]
libs = [
"AudioToolbox.framework",
......@@ -219,6 +224,7 @@ shared_library("ios_test_flutter") {
]
deps = [
":flutter_framework_source",
":ios_gpu_configuration",
":ios_test_flutter_mrc",
"//flutter/common:common",
"//flutter/shell/platform/darwin/common:framework_shared",
......@@ -228,7 +234,10 @@ shared_library("ios_test_flutter") {
"//third_party/rapidjson",
"//third_party/skia",
]
public_configs = [ "//flutter:config" ]
public_configs = [
":ios_gpu_configuration_config",
"//flutter:config",
]
}
shared_library("create_flutter_framework_dylib") {
......
......@@ -8,9 +8,9 @@
#import "flutter/shell/platform/darwin/ios/ios_context_gl.h"
#import "flutter/shell/platform/darwin/ios/ios_context_software.h"
#if FLUTTER_SHELL_ENABLE_METAL
#if SHELL_ENABLE_METAL
#import "flutter/shell/platform/darwin/ios/ios_context_metal.h"
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // SHELL_ENABLE_METAL
namespace flutter {
......@@ -24,10 +24,10 @@ std::unique_ptr<IOSContext> IOSContext::Create(IOSRenderingAPI rendering_api) {
return std::make_unique<IOSContextGL>();
case IOSRenderingAPI::kSoftware:
return std::make_unique<IOSContextSoftware>();
#if FLUTTER_SHELL_ENABLE_METAL
#if SHELL_ENABLE_METAL
case IOSRenderingAPI::kMetal:
return std::make_unique<IOSContextMetal>();
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // SHELL_ENABLE_METAL
default:
break;
}
......
......@@ -10,6 +10,7 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/cf_utils.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.h"
#import "flutter/shell/platform/darwin/ios/ios_context.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
......@@ -21,21 +22,15 @@ class IOSContextMetal final : public IOSContext {
~IOSContextMetal();
fml::scoped_nsprotocol<id<MTLDevice>> GetDevice() const;
fml::scoped_nsprotocol<id<MTLCommandQueue>> GetMainCommandQueue() const;
fml::scoped_nsprotocol<id<MTLCommandQueue>> GetResourceCommandQueue() const;
fml::scoped_nsobject<FlutterDarwinContextMetal> GetDarwinContext() const;
sk_sp<GrDirectContext> GetMainContext() const;
sk_sp<GrDirectContext> GetResourceContext() const;
private:
fml::scoped_nsprotocol<id<MTLDevice>> device_;
fml::scoped_nsprotocol<id<MTLCommandQueue>> main_queue_;
sk_sp<GrDirectContext> main_context_;
sk_sp<GrDirectContext> resource_context_;
fml::scoped_nsobject<FlutterDarwinContextMetal> darwin_context_metal_;
fml::scoped_nsprotocol<id<MTLCommandQueue>> main_command_queue_;
fml::CFRef<CVMetalTextureCacheRef> texture_cache_;
// |IOSContext|
......
......@@ -6,58 +6,27 @@
#include "flutter/common/graphics/persistent_cache.h"
#include "flutter/fml/logging.h"
#import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.h"
#import "flutter/shell/platform/darwin/ios/ios_external_texture_metal.h"
#include "third_party/skia/include/gpu/GrContextOptions.h"
namespace flutter {
static GrContextOptions CreateMetalGrContextOptions() {
GrContextOptions options = {};
if (PersistentCache::cache_sksl()) {
options.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kSkSL;
}
PersistentCache::MarkStrategySet();
options.fPersistentCache = PersistentCache::GetCacheForProcess();
return options;
}
IOSContextMetal::IOSContextMetal() {
device_.reset([MTLCreateSystemDefaultDevice() retain]);
if (!device_) {
FML_DLOG(ERROR) << "Could not acquire Metal device.";
return;
}
main_queue_.reset([device_ newCommandQueue]);
if (!main_queue_) {
FML_DLOG(ERROR) << "Could not create Metal command queue.";
return;
}
[main_queue_ setLabel:@"Flutter Main Queue"];
const auto& context_options = CreateMetalGrContextOptions();
// Skia expect arguments to `MakeMetal` transfer ownership of the reference in for release later
// when the GrDirectContext is collected.
main_context_ =
GrDirectContext::MakeMetal([device_ retain], [main_queue_ retain], context_options);
resource_context_ =
GrDirectContext::MakeMetal([device_ retain], [main_queue_ retain], context_options);
darwin_context_metal_ = fml::scoped_nsobject<FlutterDarwinContextMetal>{
[[[FlutterDarwinContextMetal alloc] initWithDefaultMTLDevice] retain]};
if (!main_context_ || !resource_context_) {
FML_DLOG(ERROR) << "Could not create Skia Metal contexts.";
if (!darwin_context_metal_) {
return;
}
resource_context_->setResourceCacheLimits(0u, 0u);
main_command_queue_.reset([darwin_context_metal_.get().mtlCommandQueue retain]);
CVMetalTextureCacheRef texture_cache_raw = NULL;
auto cv_return = CVMetalTextureCacheCreate(kCFAllocatorDefault, // allocator
NULL, // cache attributes (NULL default)
device_.get(), // metal device
NULL, // texture attributes (NULL default)
NULL, // cache attributes (NULL default)
darwin_context_metal_.get().mtlDevice, // metal device
NULL, // texture attributes (NULL default)
&texture_cache_raw // [out] cache
);
if (cv_return != kCVReturnSuccess) {
......@@ -69,30 +38,21 @@ IOSContextMetal::IOSContextMetal() {
IOSContextMetal::~IOSContextMetal() = default;
fml::scoped_nsprotocol<id<MTLDevice>> IOSContextMetal::GetDevice() const {
return device_;
}
fml::scoped_nsprotocol<id<MTLCommandQueue>> IOSContextMetal::GetMainCommandQueue() const {
return main_queue_;
}
fml::scoped_nsprotocol<id<MTLCommandQueue>> IOSContextMetal::GetResourceCommandQueue() const {
// TODO(52150): Create a dedicated resource queue once multiple queues are supported in Skia.
return main_queue_;
fml::scoped_nsobject<FlutterDarwinContextMetal> IOSContextMetal::GetDarwinContext() const {
return darwin_context_metal_;
}
sk_sp<GrDirectContext> IOSContextMetal::GetMainContext() const {
return main_context_;
return darwin_context_metal_.get().mainContext;
}
sk_sp<GrDirectContext> IOSContextMetal::GetResourceContext() const {
return resource_context_;
return darwin_context_metal_.get().resourceContext;
}
// |IOSContext|
sk_sp<GrDirectContext> IOSContextMetal::CreateResourceContext() {
return resource_context_;
return darwin_context_metal_.get().resourceContext;
}
// |IOSContext|
......
......@@ -9,9 +9,9 @@
#include "flutter/shell/platform/darwin/ios/rendering_api_selection.h"
#if FLUTTER_SHELL_ENABLE_METAL
#if SHELL_ENABLE_METAL
#import "flutter/shell/platform/darwin/ios/ios_surface_metal.h"
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // SHELL_ENABLE_METAL
namespace flutter {
......@@ -28,7 +28,7 @@ std::unique_ptr<IOSSurface> IOSSurface::Create(std::shared_ptr<IOSContext> conte
);
}
#if FLUTTER_SHELL_ENABLE_METAL
#if SHELL_ENABLE_METAL
if (@available(iOS METAL_IOS_VERSION_BASELINE, *)) {
if ([layer.get() isKindOfClass:[CAMetalLayer class]]) {
return std::make_unique<IOSSurfaceMetal>(
......@@ -38,7 +38,7 @@ std::unique_ptr<IOSSurface> IOSSurface::Create(std::shared_ptr<IOSContext> conte
);
}
}
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // SHELL_ENABLE_METAL
return std::make_unique<IOSSurfaceSoftware>(std::move(layer), // layer
std::move(context) // context
......
......@@ -6,6 +6,7 @@
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_METAL_H_
#include "flutter/fml/macros.h"
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
#import "flutter/shell/platform/darwin/ios/ios_surface.h"
#include "third_party/skia/include/gpu/mtl/GrMtlTypes.h"
......@@ -13,7 +14,8 @@
namespace flutter {
class SK_API_AVAILABLE_CA_METAL_LAYER IOSSurfaceMetal final : public IOSSurface {
class SK_API_AVAILABLE_CA_METAL_LAYER IOSSurfaceMetal final : public IOSSurface,
public GPUSurfaceMetalDelegate {
public:
IOSSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer, std::shared_ptr<IOSContext> context);
......@@ -22,6 +24,8 @@ class SK_API_AVAILABLE_CA_METAL_LAYER IOSSurfaceMetal final : public IOSSurface
private:
fml::scoped_nsobject<CAMetalLayer> layer_;
id<MTLDevice> device_;
id<MTLCommandQueue> command_queue_;
bool is_valid_ = false;
// |IOSSurface|
......@@ -33,6 +37,18 @@ class SK_API_AVAILABLE_CA_METAL_LAYER IOSSurfaceMetal final : public IOSSurface
// |IOSSurface|
std::unique_ptr<Surface> CreateGPUSurface(GrDirectContext* gr_context) override;
// |GPUSurfaceMetalDelegate|
GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override;
// |GPUSurfaceMetalDelegate|
bool PresentDrawable(GrMTLHandle drawable) const override;
// |GPUSurfaceMetalDelegate|
GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_info) const override;
// |GPUSurfaceMetalDelegate|
bool PresentTexture(intptr_t texture_id) const override;
FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceMetal);
};
......
......@@ -5,7 +5,8 @@
#import "flutter/shell/platform/darwin/ios/ios_surface_metal.h"
#include "flutter/shell/gpu/gpu_surface_metal.h"
#import "flutter/shell/platform/darwin/ios/ios_context_metal.h"
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
#include "flutter/shell/platform/darwin/ios/ios_context_metal.h"
namespace flutter {
......@@ -15,17 +16,14 @@ static IOSContextMetal* CastToMetalContext(const std::shared_ptr<IOSContext>& co
IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
std::shared_ptr<IOSContext> context)
: IOSSurface(std::move(context)), layer_(std::move(layer)) {
if (!layer_) {
return;
}
: IOSSurface(std::move(context)),
GPUSurfaceMetalDelegate(MTLRenderTargetType::kCAMetalLayer),
layer_(std::move(layer)) {
is_valid_ = layer_;
auto metal_context = CastToMetalContext(GetContext());
layer_.get().device = metal_context->GetDevice().get();
layer_.get().presentsWithTransaction = YES;
is_valid_ = true;
auto darwin_context = metal_context->GetDarwinContext().get();
command_queue_ = darwin_context.mtlCommandQueue;
device_ = darwin_context.mtlDevice;
}
// |IOSSurface|
......@@ -44,11 +42,60 @@ void IOSSurfaceMetal::UpdateStorageSizeIfNecessary() {
// |IOSSurface|
std::unique_ptr<Surface> IOSSurfaceMetal::CreateGPUSurface(GrDirectContext* /* unused */) {
auto metal_context = CastToMetalContext(GetContext());
return std::make_unique<GPUSurfaceMetal>(layer_, // layer
metal_context->GetMainContext(), // context
metal_context->GetMainCommandQueue() // command queue
return std::make_unique<GPUSurfaceMetal>(this, // layer
metal_context->GetMainContext() // context
);
}
// |GPUSurfaceMetalDelegate|
GPUCAMetalLayerHandle IOSSurfaceMetal::GetCAMetalLayer(const SkISize& frame_info) const {
CAMetalLayer* layer = layer_.get();
layer.device = device_;
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
// Flutter needs to read from the color attachment in cases where there are effects such as
// backdrop filters.
layer.framebufferOnly = NO;
const auto drawable_size = CGSizeMake(frame_info.width(), frame_info.height());
if (!CGSizeEqualToSize(drawable_size, layer.drawableSize)) {
layer.drawableSize = drawable_size;
}
// 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];
return layer;
}
// |GPUSurfaceMetalDelegate|
bool IOSSurfaceMetal::PresentDrawable(GrMTLHandle drawable) const {
if (drawable == nullptr) {
FML_DLOG(ERROR) << "Could not acquire next Metal drawable from the SkSurface.";
return false;
}
auto command_buffer =
fml::scoped_nsprotocol<id<MTLCommandBuffer>>([[command_queue_ commandBuffer] retain]);
[command_buffer.get() commit];
[command_buffer.get() waitUntilScheduled];
[reinterpret_cast<id<CAMetalDrawable>>(drawable) present];
return true;
}
// |GPUSurfaceMetalDelegate|
GPUMTLTextureInfo IOSSurfaceMetal::GetMTLTexture(const SkISize& frame_info) const {
FML_CHECK(false) << "render to texture not supported on ios";
return {.texture_id = -1, .texture = nullptr};
}
// |GPUSurfaceMetalDelegate|
bool IOSSurfaceMetal::PresentTexture(intptr_t texture_id) const {
FML_CHECK(false) << "render to texture not supported on ios";
return false;
}
} // namespace flutter
......@@ -6,17 +6,17 @@
#include <Foundation/Foundation.h>
#include <QuartzCore/CAEAGLLayer.h>
#include <QuartzCore/CAMetalLayer.h>
#if FLUTTER_SHELL_ENABLE_METAL
#import <QuartzCore/CAMetalLayer.h>
#if SHELL_ENABLE_METAL
#include <Metal/Metal.h>
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // SHELL_ENABLE_METAL
#import <TargetConditionals.h>
#include "flutter/fml/logging.h"
namespace flutter {
#if FLUTTER_SHELL_ENABLE_METAL
#if SHELL_ENABLE_METAL
bool ShouldUseMetalRenderer() {
bool ios_version_supports_metal = false;
if (@available(iOS METAL_IOS_VERSION_BASELINE, *)) {
......@@ -25,7 +25,7 @@ bool ShouldUseMetalRenderer() {
}
return ios_version_supports_metal;
}
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // SHELL_ENABLE_METAL
IOSRenderingAPI GetRenderingAPIForProcess(bool force_software) {
#if TARGET_OS_SIMULATOR
......@@ -39,12 +39,12 @@ IOSRenderingAPI GetRenderingAPIForProcess(bool force_software) {
}
#endif // TARGET_OS_SIMULATOR
#if FLUTTER_SHELL_ENABLE_METAL
#if SHELL_ENABLE_METAL
static bool should_use_metal = ShouldUseMetalRenderer();
if (should_use_metal) {
return IOSRenderingAPI::kMetal;
}
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // SHELL_ENABLE_METAL
// OpenGL will be emulated using software rendering by Apple on the simulator, so we use the
// Skia software rendering since it performs a little better than the emulated OpenGL.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册