Flutter Impeller
blit_pass_mtl.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <Metal/Metal.h>
8 #import <MetalPerformanceShaders/MetalPerformanceShaders.h>
9 #include <cstdint>
10 #include <memory>
11 #include <utility>
12 #include <variant>
13 
14 #include "flutter/fml/closure.h"
15 #include "flutter/fml/logging.h"
16 #include "flutter/fml/trace_event.h"
18 #include "impeller/core/formats.h"
26 
28 
29 namespace impeller {
30 
31 BlitPassMTL::BlitPassMTL(id<MTLCommandBuffer> buffer, id<MTLDevice> device)
32  : buffer_(buffer), device_(device) {
33  if (!buffer_) {
34  return;
35  }
36  encoder_ = [buffer_ blitCommandEncoder];
37 #ifdef IMPELLER_DEBUG
38  is_metal_trace_active_ =
39  [[MTLCaptureManager sharedCaptureManager] isCapturing];
40 #endif // IMPELLER_DEBUG
41  is_valid_ = true;
42 }
43 
44 BlitPassMTL::~BlitPassMTL() {
45  if (!did_finish_encoding_) {
46  [encoder_ endEncoding];
47  }
48 }
49 
50 bool BlitPassMTL::IsValid() const {
51  return is_valid_;
52 }
53 
54 void BlitPassMTL::OnSetLabel(std::string_view label) {
55  if (label.empty()) {
56  return;
57  }
58  [encoder_ setLabel:@(label.data())];
59 }
60 
61 bool BlitPassMTL::EncodeCommands() const {
62  [encoder_ endEncoding];
63  did_finish_encoding_ = true;
64  return true;
65 }
66 
67 // |BlitPass|
68 bool BlitPassMTL::OnCopyTextureToTextureCommand(
69  std::shared_ptr<Texture> source,
70  std::shared_ptr<Texture> destination,
71  IRect source_region,
72  IPoint destination_origin,
73  std::string_view label) {
74  auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
75  if (!source_mtl) {
76  return false;
77  }
78 
79  auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
80  if (!destination_mtl) {
81  return false;
82  }
83 
84  auto source_origin_mtl =
85  MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
86  auto source_size_mtl =
87  MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
88  auto destination_origin_mtl =
89  MTLOriginMake(destination_origin.x, destination_origin.y, 0);
90 
91 #ifdef IMPELLER_DEBUG
92  if (is_metal_trace_active_) {
93  [encoder_ pushDebugGroup:@(label.data())];
94  }
95 #endif // IMPELLER_DEBUG
96  [encoder_ copyFromTexture:source_mtl
97  sourceSlice:0
98  sourceLevel:0
99  sourceOrigin:source_origin_mtl
100  sourceSize:source_size_mtl
101  toTexture:destination_mtl
102  destinationSlice:0
103  destinationLevel:0
104  destinationOrigin:destination_origin_mtl];
105 
106 #ifdef IMPELLER_DEBUG
107  if (is_metal_trace_active_) {
108  [encoder_ popDebugGroup];
109  }
110 #endif // IMPELLER_DEBUG
111  return true;
112 }
113 
114 // |BlitPass|
115 bool BlitPassMTL::ResizeTexture(const std::shared_ptr<Texture>& source,
116  const std::shared_ptr<Texture>& destination) {
117  auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
118  if (!source_mtl) {
119  return false;
120  }
121 
122  auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
123  if (!destination_mtl) {
124  return false;
125  }
126 
127  [encoder_ endEncoding];
128  auto filter = [[MPSImageBilinearScale alloc] initWithDevice:device_];
129  [filter encodeToCommandBuffer:buffer_
130  sourceTexture:source_mtl
131  destinationTexture:destination_mtl];
132  encoder_ = [buffer_ blitCommandEncoder];
133  return true;
134 }
135 
136 // |BlitPass|
137 bool BlitPassMTL::OnCopyTextureToBufferCommand(
138  std::shared_ptr<Texture> source,
139  std::shared_ptr<DeviceBuffer> destination,
140  IRect source_region,
141  size_t destination_offset,
142  std::string_view label) {
143  auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
144  if (!source_mtl) {
145  return false;
146  }
147 
148  auto destination_mtl = DeviceBufferMTL::Cast(*destination).GetMTLBuffer();
149  if (!destination_mtl) {
150  return false;
151  }
152 
153  auto source_origin_mtl =
154  MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
155  auto source_size_mtl =
156  MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
157 
158  auto destination_bytes_per_pixel =
159  BytesPerPixelForPixelFormat(source->GetTextureDescriptor().format);
160  auto destination_bytes_per_row =
161  source_size_mtl.width * destination_bytes_per_pixel;
162  auto destination_bytes_per_image =
163  source_size_mtl.height * destination_bytes_per_row;
164 
165 #ifdef IMPELLER_DEBUG
166  if (is_metal_trace_active_) {
167  [encoder_ pushDebugGroup:@(label.data())];
168  }
169 #endif // IMPELLER_DEBUG
170  [encoder_ copyFromTexture:source_mtl
171  sourceSlice:0
172  sourceLevel:0
173  sourceOrigin:source_origin_mtl
174  sourceSize:source_size_mtl
175  toBuffer:destination_mtl
176  destinationOffset:destination_offset
177  destinationBytesPerRow:destination_bytes_per_row
178  destinationBytesPerImage:destination_bytes_per_image];
179 
180 #ifdef IMPELLER_DEBUG
181  if (is_metal_trace_active_) {
182  [encoder_ popDebugGroup];
183  }
184 #endif // IMPELLER_DEBUG
185  return true;
186 }
187 
188 bool BlitPassMTL::OnCopyBufferToTextureCommand(
189  BufferView source,
190  std::shared_ptr<Texture> destination,
191  IRect destination_region,
192  std::string_view label,
193  uint32_t mip_level,
194  uint32_t slice,
195  bool convert_to_read) {
196  auto source_mtl = DeviceBufferMTL::Cast(*source.GetBuffer()).GetMTLBuffer();
197  if (!source_mtl) {
198  return false;
199  }
200 
201  auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
202  if (!destination_mtl) {
203  return false;
204  }
205 
206  auto destination_origin_mtl =
207  MTLOriginMake(destination_region.GetX(), destination_region.GetY(), 0);
208  auto source_size_mtl = MTLSizeMake(destination_region.GetWidth(),
209  destination_region.GetHeight(), 1);
210 
211  auto destination_bytes_per_pixel =
212  BytesPerPixelForPixelFormat(destination->GetTextureDescriptor().format);
213  auto source_bytes_per_row =
214  destination_region.GetWidth() * destination_bytes_per_pixel;
215 
216 #ifdef IMPELLER_DEBUG
217  if (is_metal_trace_active_) {
218  [encoder_ pushDebugGroup:@(label.data())];
219  }
220 #endif // IMPELLER_DEBUG
221  [encoder_
222  copyFromBuffer:source_mtl
223  sourceOffset:source.GetRange().offset
224  sourceBytesPerRow:source_bytes_per_row
225  sourceBytesPerImage:
226  0 // 0 for 2D textures according to
227  // https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400752-copyfrombuffer
228  sourceSize:source_size_mtl
229  toTexture:destination_mtl
230  destinationSlice:slice
231  destinationLevel:mip_level
232  destinationOrigin:destination_origin_mtl];
233 
234 #ifdef IMPELLER_DEBUG
235  if (is_metal_trace_active_) {
236  [encoder_ popDebugGroup];
237  }
238 #endif // IMPELLER_DEBUG
239  return true;
240 }
241 
242 // |BlitPass|
243 bool BlitPassMTL::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
244  std::string_view label) {
245 #ifdef IMPELLER_DEBUG
246  if (is_metal_trace_active_) {
247  [encoder_ pushDebugGroup:@(label.data())];
248  }
249 #endif // IMPELLER_DEBUG
250  auto result = TextureMTL::Cast(*texture).GenerateMipmap(encoder_);
251 #ifdef IMPELLER_DEBUG
252  if (is_metal_trace_active_) {
253  [encoder_ popDebugGroup];
254  }
255 #endif // IMPELLER_DEBUG
256  return result;
257 }
258 
259 } // namespace impeller
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
Definition: formats.h:466
IRect64 IRect
Definition: rect.h:795
TPoint< int64_t > IPoint
Definition: point.h:328