未验证 提交 5526884e 编写于 作者: C Chinmay Garde 提交者: GitHub

Wire up the Skia Metal backend on iOS. (#8936)

上级 5ad98642
......@@ -498,6 +498,8 @@ FILE: ../../../flutter/shell/gpu/gpu_surface_gl.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_gl.h
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_software.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_software.h
FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan.cc
......@@ -719,6 +721,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_gl.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_gl.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_metal.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_metal.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_software.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_software.mm
FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.h
......
......@@ -145,6 +145,7 @@ shell_gpu_configuration("shell_unittests_gpu_configuration") {
enable_software = true
enable_vulkan = false
enable_gl = false
enable_metal = false
}
test_fixtures("shell_unittests_fixtures") {
......
......@@ -4,4 +4,5 @@
declare_args() {
shell_enable_vulkan = false
shell_enable_metal = false
}
......@@ -45,3 +45,12 @@ source_set("gpu_surface_vulkan") {
"$flutter_root/vulkan",
]
}
source_set("gpu_surface_metal") {
sources = [
"$gpu_dir/gpu_surface_metal.h",
"$gpu_dir/gpu_surface_metal.mm",
]
deps = gpu_common_deps + [ "//third_party/skia" ]
}
......@@ -11,6 +11,8 @@ template("shell_gpu_configuration") {
"Caller must declare if the Vulkan backend must be enabled.")
assert(defined(invoker.enable_gl),
"Caller must declare if the Open GL backend must be enabled.")
assert(defined(invoker.enable_metal),
"Caller must declare if the Metal backend must be enabled.")
group(target_name) {
public_deps = []
......@@ -26,5 +28,9 @@ template("shell_gpu_configuration") {
if (invoker.enable_vulkan) {
public_deps += [ "$flutter_root/shell/gpu:gpu_surface_vulkan" ]
}
if (invoker.enable_metal) {
public_deps += [ "$flutter_root/shell/gpu:gpu_surface_metal" ]
}
}
}
// 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_H_
#define FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_H_
#include <Metal/Metal.h>
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/surface.h"
#include "third_party/skia/include/gpu/GrContext.h"
@class CAMetalLayer;
namespace flutter {
class GPUSurfaceMetal : public Surface {
public:
GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer);
~GPUSurfaceMetal() override;
private:
fml::scoped_nsobject<CAMetalLayer> layer_;
sk_sp<GrContext> context_;
fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue_;
// |Surface|
bool IsValid() override;
// |Surface|
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
// |Surface|
SkMatrix GetRootTransformation() const override;
// |Surface|
GrContext* GetContext() override;
// |Surface|
bool MakeRenderContextCurrent() override;
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceMetal);
};
} // namespace flutter
#endif // FLUTTER_SHELL_GPU_GPU_SURFACE_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.
#include "flutter/shell/gpu/gpu_surface_metal.h"
#include <QuartzCore/CAMetalLayer.h>
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
namespace flutter {
GPUSurfaceMetal::GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer)
: layer_(std::move(layer)) {
if (!layer_) {
FML_LOG(ERROR) << "Could not create metal surface because of invalid layer.";
return;
}
layer.get().pixelFormat = MTLPixelFormatBGRA8Unorm;
auto metal_device = fml::scoped_nsprotocol<id<MTLDevice>>([layer_.get().device retain]);
auto metal_queue = fml::scoped_nsprotocol<id<MTLCommandQueue>>([metal_device newCommandQueue]);
if (!metal_device || !metal_queue) {
FML_LOG(ERROR) << "Could not create metal device or queue.";
return;
}
command_queue_ = metal_queue;
// The context creation routine accepts arguments using transfer semantics.
auto context = GrContext::MakeMetal(metal_device.release(), metal_queue.release());
if (!context) {
FML_LOG(ERROR) << "Could not create Skia metal context.";
return;
}
context_ = context;
}
GPUSurfaceMetal::~GPUSurfaceMetal() = default;
// |Surface|
bool GPUSurfaceMetal::IsValid() {
return layer_ && context_ && command_queue_;
}
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& size) {
if (!IsValid()) {
FML_LOG(ERROR) << "Metal surface was invalid.";
return nullptr;
}
if (size.isEmpty()) {
FML_LOG(ERROR) << "Metal surface was asked for an empty frame.";
return nullptr;
}
const auto bounds = layer_.get().bounds.size;
if (bounds.width <= 0.0 || bounds.height <= 0.0) {
FML_LOG(ERROR) << "Metal layer bounds were invalid.";
return nullptr;
}
const auto scale = layer_.get().contentsScale;
auto next_drawable = fml::scoped_nsprotocol<id<CAMetalDrawable>>([[layer_ nextDrawable] retain]);
if (!next_drawable) {
FML_LOG(ERROR) << "Could not acquire next metal drawable.";
return nullptr;
}
auto metal_texture = fml::scoped_nsprotocol<id<MTLTexture>>([next_drawable.get().texture retain]);
if (!metal_texture) {
FML_LOG(ERROR) << "Could not acquire metal texture from drawable.";
return nullptr;
}
GrMtlTextureInfo metal_texture_info;
metal_texture_info.fTexture = metal_texture.get();
GrBackendRenderTarget metal_render_target(bounds.width * scale, // width
bounds.height * scale, // height
1, // sample count
metal_texture_info // metal texture info
);
auto command_buffer =
fml::scoped_nsprotocol<id<MTLCommandBuffer>>([[command_queue_.get() commandBuffer] retain]);
SkSurface::RenderTargetReleaseProc release_proc = [](SkSurface::ReleaseContext context) {
[reinterpret_cast<id>(context) release];
};
auto surface =
SkSurface::MakeFromBackendRenderTarget(context_.get(), // context
metal_render_target, // backend render target
kTopLeft_GrSurfaceOrigin, // origin
kBGRA_8888_SkColorType, // color type
nullptr, // colorspace
nullptr, // surface properties
release_proc, // release proc
metal_texture.release() // release context (texture)
);
if (!surface) {
FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture.";
return nullptr;
}
auto submit_callback = [drawable = next_drawable, command_buffer](
const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
canvas->flush();
[command_buffer.get() presentDrawable:drawable.get()];
[command_buffer.get() commit];
return true;
};
return std::make_unique<SurfaceFrame>(std::move(surface), submit_callback);
}
// |Surface|
SkMatrix GPUSurfaceMetal::GetRootTransformation() const {
// This backend does not currently support root surface transformations. Just
// return identity.
SkMatrix matrix;
matrix.reset();
return matrix;
}
// |Surface|
GrContext* GPUSurfaceMetal::GetContext() {
return context_.get();
}
// |Surface|
bool GPUSurfaceMetal::MakeRenderContextCurrent() {
// This backend has no such concept.
return true;
}
} // namespace flutter
......@@ -11,6 +11,7 @@ shell_gpu_configuration("android_gpu_configuration") {
enable_software = true
enable_vulkan = shell_enable_vulkan
enable_gl = true
enable_metal = false
}
shared_library("flutter_shell_native") {
......
......@@ -14,6 +14,7 @@ shell_gpu_configuration("ios_gpu_configuration") {
enable_software = true
enable_gl = true
enable_vulkan = false
enable_metal = shell_enable_metal
}
# The headers that will be copied to the Flutter.framework and be accessed
......@@ -100,6 +101,13 @@ shared_library("create_flutter_framework_dylib") {
"platform_view_ios.mm",
]
if (shell_enable_metal) {
sources += [
"ios_surface_metal.h",
"ios_surface_metal.mm",
]
}
sources += _flutter_framework_headers
deps = [
......@@ -117,7 +125,11 @@ shared_library("create_flutter_framework_dylib") {
public_configs = [ "$flutter_root:config" ]
defines = [ "FLUTTER_FRAMEWORK" ]
defines = [ "FLUTTER_FRAMEWORK=1" ]
if (shell_enable_metal) {
defines += [ "FLUTTER_SHELL_ENABLE_METAL=1" ]
}
libs = [
"CoreMedia.framework",
......@@ -241,6 +253,7 @@ copy("copy_license") {
shared_library("copy_and_verify_framework_headers") {
visibility = [ ":*" ]
include_dirs = [ "$_flutter_framework_headers_copy_dir" ]
sources = [
"framework/Source/FlutterUmbrellaImport.m",
]
......
......@@ -17,6 +17,10 @@
#include "flutter/shell/platform/darwin/ios/ios_surface_software.h"
#include "third_party/skia/include/utils/mac/SkCGUtils.h"
#if FLUTTER_SHELL_ENABLE_METAL
#include "flutter/shell/platform/darwin/ios/ios_surface_metal.h"
#endif // FLUTTER_SHELL_ENABLE_METAL
@implementation FlutterView
id<FlutterViewEngineDelegate> _delegate;
......@@ -60,14 +64,26 @@ id<FlutterViewEngineDelegate> _delegate;
layer.rasterizationScale = screenScale;
}
#if FLUTTER_SHELL_ENABLE_METAL
if ([self.layer isKindOfClass:[CAMetalLayer class]]) {
CGFloat screenScale = [UIScreen mainScreen].scale;
self.layer.contentsScale = screenScale;
self.layer.rasterizationScale = screenScale;
}
#endif // FLUTTER_SHELL_ENABLE_METAL
[super layoutSubviews];
}
+ (Class)layerClass {
#if TARGET_IPHONE_SIMULATOR
return [CALayer class];
#else // TARGET_IPHONE_SIMULATOR
#else // TARGET_IPHONE_SIMULATOR
#if FLUTTER_SHELL_ENABLE_METAL
return [CAMetalLayer class];
#else // FLUTTER_SHELL_ENABLE_METAL
return [CAEAGLLayer class];
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // TARGET_IPHONE_SIMULATOR
}
......@@ -87,7 +103,16 @@ id<FlutterViewEngineDelegate> _delegate;
}
return std::make_unique<flutter::IOSSurfaceGL>(context, std::move(eagl_layer),
[_delegate platformViewsController]);
} else {
}
#if FLUTTER_SHELL_ENABLE_METAL
else if ([self.layer isKindOfClass:[CAMetalLayer class]]) {
return std::make_unique<flutter::IOSSurfaceMetal>(
fml::scoped_nsobject<CAMetalLayer>(reinterpret_cast<CAMetalLayer*>([self.layer retain])),
[_delegate platformViewsController]);
}
#endif // FLUTTER_SHELL_ENABLE_METAL
else {
fml::scoped_nsobject<CALayer> layer(reinterpret_cast<CALayer*>([self.layer retain]));
return std::make_unique<flutter::IOSSurfaceSoftware>(std::move(layer),
[_delegate platformViewsController]);
......
......@@ -16,9 +16,9 @@
namespace flutter {
class IOSSurfaceGL : public IOSSurface,
public GPUSurfaceGLDelegate,
public flutter::ExternalViewEmbedder {
class IOSSurfaceGL final : public IOSSurface,
public GPUSurfaceGLDelegate,
public flutter::ExternalViewEmbedder {
public:
IOSSurfaceGL(std::shared_ptr<IOSGLContext> context,
fml::scoped_nsobject<CAEAGLLayer> layer,
......
// 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_PLATFORM_DARWIN_IOS_IOS_SURFACE_METAL_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_METAL_H_
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/gpu/gpu_surface_metal.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
@class CAMetalLayer;
namespace flutter {
class IOSSurfaceMetal final : public IOSSurface {
public:
IOSSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
FlutterPlatformViewsController* platform_views_controller);
~IOSSurfaceMetal() override;
private:
fml::scoped_nsobject<CAMetalLayer> layer_;
// |IOSSurface|
bool IsValid() const override;
// |IOSSurface|
bool ResourceContextMakeCurrent() override;
// |IOSSurface|
void UpdateStorageSizeIfNecessary() override;
// |IOSSurface|
std::unique_ptr<Surface> CreateGPUSurface() override;
FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceMetal);
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_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.
#include "flutter/shell/platform/darwin/ios/ios_surface_metal.h"
#include "flutter/shell/gpu/gpu_surface_metal.h"
namespace flutter {
IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
FlutterPlatformViewsController* platform_views_controller)
: IOSSurface(platform_views_controller), layer_(std::move(layer)) {}
IOSSurfaceMetal::~IOSSurfaceMetal() = default;
// |IOSSurface|
bool IOSSurfaceMetal::IsValid() const {
return layer_;
}
// |IOSSurface|
bool IOSSurfaceMetal::ResourceContextMakeCurrent() {
return false;
}
// |IOSSurface|
void IOSSurfaceMetal::UpdateStorageSizeIfNecessary() {}
// |IOSSurface|
std::unique_ptr<Surface> IOSSurfaceMetal::CreateGPUSurface() {
return std::make_unique<GPUSurfaceMetal>(layer_);
}
} // namespace flutter
......@@ -11,6 +11,7 @@ shell_gpu_configuration("embedder_gpu_configuration") {
enable_software = true
enable_vulkan = false
enable_gl = true
enable_metal = false
}
source_set("embedder") {
......
......@@ -43,6 +43,9 @@ def get_out_dir(args):
if args.enable_vulkan:
target_dir.append('vulkan')
if args.enable_metal:
target_dir.append('metal')
return os.path.join(args.out_dir, 'out', '_'.join(target_dir))
def to_command_line(gn_args):
......@@ -71,6 +74,9 @@ def to_gn_args(args):
if args.target_os != 'android' and args.enable_vulkan:
raise Exception('--enable-vulkan is only supported on Android')
if args.target_os != 'ios' and args.enable_metal:
raise Exception('--enable-metal is only supported on iOS')
runtime_mode = args.runtime_mode
if args.dynamic and runtime_mode in ['profile', 'release']:
runtime_mode = 'dynamic_' + runtime_mode
......@@ -215,6 +221,11 @@ def to_gn_args(args):
gn_args['use_goma'] = False
gn_args['goma_dir'] = None
if args.enable_metal:
gn_args['skia_use_metal'] = True
gn_args['shell_enable_metal'] = True
gn_args['ios_deployment_target'] = '11'
if args.enable_vulkan:
# Enable vulkan in the Flutter shell.
gn_args['shell_enable_vulkan'] = True
......@@ -285,6 +296,7 @@ def parse_args(args):
parser.add_argument('--operator-new-alignment', dest='operator_new_alignment', type=str, default=None)
parser.add_argument('--enable-vulkan', action='store_true', default=False)
parser.add_argument('--enable-metal', action='store_true', default=False)
parser.add_argument('--embedder-for-target', dest='embedder_for_target', action='store_true', default=False)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册