forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Wire up the Skia Metal backend on iOS. (flutter#8936)
- Loading branch information
1 parent
5ad9864
commit 5526884
Showing
15 changed files
with
352 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,5 @@ | |
|
||
declare_args() { | ||
shell_enable_vulkan = false | ||
shell_enable_metal = false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// 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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.