|
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