|
4 | 4 |
|
5 | 5 | #include "flutter/shell/gpu/gpu_surface_metal.h" |
6 | 6 |
|
7 | | -#import <Metal/Metal.h> |
| 7 | +#include <QuartzCore/CAMetalLayer.h> |
8 | 8 |
|
9 | | -#include "flutter/fml/make_copyable.h" |
10 | | -#include "flutter/fml/platform/darwin/cf_utils.h" |
11 | 9 | #include "flutter/fml/trace_event.h" |
12 | | -#include "flutter/shell/gpu/gpu_surface_metal_delegate.h" |
13 | 10 | #include "third_party/skia/include/core/SkSurface.h" |
14 | 11 | #include "third_party/skia/include/gpu/GrBackendSurface.h" |
15 | 12 | #include "third_party/skia/include/ports/SkCFObject.h" |
|
18 | 15 |
|
19 | 16 | namespace flutter { |
20 | 17 |
|
21 | | -GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate, sk_sp<GrDirectContext> context) |
22 | | - : delegate_(delegate), |
23 | | - render_target_type_(delegate->GetRenderTargetType()), |
24 | | - context_(std::move(context)) {} |
| 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 | +} |
25 | 29 |
|
26 | 30 | GPUSurfaceMetal::~GPUSurfaceMetal() { |
27 | 31 | ReleaseUnusedDrawableIfNecessary(); |
28 | 32 | } |
29 | 33 |
|
30 | 34 | // |Surface| |
31 | 35 | bool GPUSurfaceMetal::IsValid() { |
32 | | - return context_ != nullptr; |
| 36 | + return layer_ && context_ && command_queue_; |
33 | 37 | } |
34 | 38 |
|
35 | 39 | // |Surface| |
|
44 | 48 | return nullptr; |
45 | 49 | } |
46 | 50 |
|
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 | | -} |
| 51 | + const auto drawable_size = CGSizeMake(frame_size.width(), frame_size.height()); |
58 | 52 |
|
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; |
| 53 | + if (!CGSizeEqualToSize(drawable_size, layer_.get().drawableSize)) { |
| 54 | + layer_.get().drawableSize = drawable_size; |
65 | 55 | } |
66 | 56 |
|
67 | 57 | 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(); |
94 | 58 |
|
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); |
| 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 | + ); |
123 | 73 |
|
124 | 74 | if (!surface) { |
125 | 75 | FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture."; |
126 | 76 | return nullptr; |
127 | 77 | } |
128 | 78 |
|
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"); |
| 79 | + auto submit_callback = [this](const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool { |
| 80 | + TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit"); |
132 | 81 | if (canvas == nullptr) { |
133 | 82 | FML_DLOG(ERROR) << "Canvas not available."; |
134 | 83 | return false; |
135 | 84 | } |
136 | 85 |
|
137 | 86 | canvas->flush(); |
138 | 87 |
|
139 | | - return delegate->PresentTexture(texture_id); |
| 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; |
140 | 105 | }; |
141 | 106 |
|
142 | 107 | return std::make_unique<SurfaceFrame>(std::move(surface), true, submit_callback); |
|
0 commit comments