|
4 | 4 |
|
5 | 5 | #include "flutter/shell/gpu/gpu_surface_metal.h"
|
6 | 6 |
|
7 |
| -#include <QuartzCore/CAMetalLayer.h> |
| 7 | +#import <Metal/Metal.h> |
8 | 8 |
|
| 9 | +#include "flutter/fml/make_copyable.h" |
| 10 | +#include "flutter/fml/platform/darwin/cf_utils.h" |
9 | 11 | #include "flutter/fml/trace_event.h"
|
| 12 | +#include "flutter/shell/gpu/gpu_surface_metal_delegate.h" |
10 | 13 | #include "third_party/skia/include/core/SkSurface.h"
|
11 | 14 | #include "third_party/skia/include/gpu/GrBackendSurface.h"
|
12 | 15 | #include "third_party/skia/include/ports/SkCFObject.h"
|
|
15 | 18 |
|
16 | 19 | namespace flutter {
|
17 | 20 |
|
18 |
| -GPUSurfaceMetal::GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer, |
19 |
| - sk_sp<GrDirectContext> context, |
20 |
| - fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue) |
21 |
| - : layer_(std::move(layer)), |
22 |
| - context_(std::move(context)), |
23 |
| - command_queue_(std::move(command_queue)) { |
24 |
| - layer_.get().pixelFormat = MTLPixelFormatBGRA8Unorm; |
25 |
| - // Flutter needs to read from the color attachment in cases where there are effects such as |
26 |
| - // backdrop filters. |
27 |
| - layer_.get().framebufferOnly = NO; |
28 |
| -} |
| 21 | +GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate, sk_sp<GrDirectContext> context) |
| 22 | + : delegate_(delegate), |
| 23 | + render_target_type_(delegate->GetRenderTargetType()), |
| 24 | + context_(std::move(context)) {} |
29 | 25 |
|
30 | 26 | GPUSurfaceMetal::~GPUSurfaceMetal() {
|
31 | 27 | ReleaseUnusedDrawableIfNecessary();
|
32 | 28 | }
|
33 | 29 |
|
34 | 30 | // |Surface|
|
35 | 31 | bool GPUSurfaceMetal::IsValid() {
|
36 |
| - return layer_ && context_ && command_queue_; |
| 32 | + return context_ != nullptr; |
37 | 33 | }
|
38 | 34 |
|
39 | 35 | // |Surface|
|
|
48 | 44 | return nullptr;
|
49 | 45 | }
|
50 | 46 |
|
51 |
| - const auto drawable_size = CGSizeMake(frame_size.width(), frame_size.height()); |
| 47 | + switch (render_target_type_) { |
| 48 | + case MTLRenderTargetType::kCAMetalLayer: |
| 49 | + return AcquireFrameFromCAMetalLayer(frame_size); |
| 50 | + case MTLRenderTargetType::kMTLTexture: |
| 51 | + return AcquireFrameFromMTLTexture(frame_size); |
| 52 | + default: |
| 53 | + FML_CHECK(false) << "Unknown MTLRenderTargetType type."; |
| 54 | + } |
| 55 | + |
| 56 | + return nullptr; |
| 57 | +} |
52 | 58 |
|
53 |
| - if (!CGSizeEqualToSize(drawable_size, layer_.get().drawableSize)) { |
54 |
| - layer_.get().drawableSize = drawable_size; |
| 59 | +std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrameFromCAMetalLayer( |
| 60 | + const SkISize& frame_info) { |
| 61 | + auto layer = delegate_->GetCAMetalLayer(frame_info); |
| 62 | + if (!layer) { |
| 63 | + FML_LOG(ERROR) << "Invalid CAMetalLayer given by the embedder."; |
| 64 | + return nullptr; |
55 | 65 | }
|
56 | 66 |
|
57 | 67 | ReleaseUnusedDrawableIfNecessary();
|
| 68 | + sk_sp<SkSurface> surface = |
| 69 | + SkSurface::MakeFromCAMetalLayer(context_.get(), // context |
| 70 | + layer, // layer |
| 71 | + kTopLeft_GrSurfaceOrigin, // origin |
| 72 | + 1, // sample count |
| 73 | + kBGRA_8888_SkColorType, // color type |
| 74 | + nullptr, // colorspace |
| 75 | + nullptr, // surface properties |
| 76 | + &next_drawable_ // drawable (transfer out) |
| 77 | + ); |
| 78 | + |
| 79 | + if (!surface) { |
| 80 | + FML_LOG(ERROR) << "Could not create the SkSurface from the CAMetalLayer."; |
| 81 | + return nullptr; |
| 82 | + } |
| 83 | + |
| 84 | + auto submit_callback = |
| 85 | + fml::MakeCopyable([drawable = next_drawable_, delegate = delegate_]( |
| 86 | + const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool { |
| 87 | + TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit"); |
| 88 | + if (canvas == nullptr) { |
| 89 | + FML_DLOG(ERROR) << "Canvas not available."; |
| 90 | + return false; |
| 91 | + } |
| 92 | + |
| 93 | + canvas->flush(); |
58 | 94 |
|
59 |
| - // When there are platform views in the scene, the drawable needs to be presented in the same |
60 |
| - // transaction as the one created for platform views. When the drawable are being presented from |
61 |
| - // the raster thread, there is no such transaction. |
62 |
| - layer_.get().presentsWithTransaction = [[NSThread currentThread] isMainThread]; |
63 |
| - |
64 |
| - auto surface = SkSurface::MakeFromCAMetalLayer(context_.get(), // context |
65 |
| - layer_.get(), // layer |
66 |
| - kTopLeft_GrSurfaceOrigin, // origin |
67 |
| - 1, // sample count |
68 |
| - kBGRA_8888_SkColorType, // color type |
69 |
| - nullptr, // colorspace |
70 |
| - nullptr, // surface properties |
71 |
| - &next_drawable_ // drawable (transfer out) |
72 |
| - ); |
| 95 | + if (!drawable) { |
| 96 | + FML_DLOG(ERROR) << "Unable to obtain a metal drawable."; |
| 97 | + return false; |
| 98 | + } |
| 99 | + |
| 100 | + return delegate->PresentDrawable(drawable); |
| 101 | + }); |
| 102 | + |
| 103 | + return std::make_unique<SurfaceFrame>(std::move(surface), true, submit_callback); |
| 104 | +} |
| 105 | + |
| 106 | +std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrameFromMTLTexture( |
| 107 | + const SkISize& frame_info) { |
| 108 | + GPUMTLTextureInfo texture = delegate_->GetMTLTexture(frame_info); |
| 109 | + id<MTLTexture> mtl_texture = (id<MTLTexture>)(texture.texture); |
| 110 | + |
| 111 | + if (!mtl_texture) { |
| 112 | + FML_LOG(ERROR) << "Invalid MTLTexture given by the embedder."; |
| 113 | + return nullptr; |
| 114 | + } |
| 115 | + |
| 116 | + GrMtlTextureInfo info; |
| 117 | + info.fTexture.reset([mtl_texture retain]); |
| 118 | + GrBackendTexture backend_texture(frame_info.width(), frame_info.height(), GrMipmapped::kNo, info); |
| 119 | + |
| 120 | + sk_sp<SkSurface> surface = |
| 121 | + SkSurface::MakeFromBackendTexture(context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin, |
| 122 | + 1, kBGRA_8888_SkColorType, nullptr, nullptr); |
73 | 123 |
|
74 | 124 | if (!surface) {
|
75 | 125 | FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture.";
|
76 | 126 | return nullptr;
|
77 | 127 | }
|
78 | 128 |
|
79 |
| - auto submit_callback = [this](const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool { |
80 |
| - TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit"); |
| 129 | + auto submit_callback = [texture_id = texture.texture_id, delegate = delegate_]( |
| 130 | + const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool { |
| 131 | + TRACE_EVENT0("flutter", "GPUSurfaceMetal::PresentTexture"); |
81 | 132 | if (canvas == nullptr) {
|
82 | 133 | FML_DLOG(ERROR) << "Canvas not available.";
|
83 | 134 | return false;
|
84 | 135 | }
|
85 | 136 |
|
86 | 137 | canvas->flush();
|
87 | 138 |
|
88 |
| - if (next_drawable_ == nullptr) { |
89 |
| - FML_DLOG(ERROR) << "Could not acquire next Metal drawable from the SkSurface."; |
90 |
| - return false; |
91 |
| - } |
92 |
| - |
93 |
| - auto command_buffer = |
94 |
| - fml::scoped_nsprotocol<id<MTLCommandBuffer>>([[command_queue_.get() commandBuffer] retain]); |
95 |
| - |
96 |
| - fml::scoped_nsprotocol<id<CAMetalDrawable>> drawable( |
97 |
| - reinterpret_cast<id<CAMetalDrawable>>(next_drawable_)); |
98 |
| - next_drawable_ = nullptr; |
99 |
| - |
100 |
| - [command_buffer.get() commit]; |
101 |
| - [command_buffer.get() waitUntilScheduled]; |
102 |
| - [drawable.get() present]; |
103 |
| - |
104 |
| - return true; |
| 139 | + return delegate->PresentTexture(texture_id); |
105 | 140 | };
|
106 | 141 |
|
107 | 142 | return std::make_unique<SurfaceFrame>(std::move(surface), true, submit_callback);
|
|
0 commit comments