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 source_bytes_per_row =
212  BytesPerRowForTextureWidth(destination->GetTextureDescriptor().format,
213  destination_region.GetWidth());
214 
215 #ifdef IMPELLER_DEBUG
216  if (is_metal_trace_active_) {
217  [encoder_ pushDebugGroup:@(label.data())];
218  }
219 #endif // IMPELLER_DEBUG
220  [encoder_
221  copyFromBuffer:source_mtl
222  sourceOffset:source.GetRange().offset
223  sourceBytesPerRow:source_bytes_per_row
224  sourceBytesPerImage:
225  0 // 0 for 2D textures according to
226  // https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400752-copyfrombuffer
227  sourceSize:source_size_mtl
228  toTexture:destination_mtl
229  destinationSlice:slice
230  destinationLevel:mip_level
231  destinationOrigin:destination_origin_mtl];
232 
233 #ifdef IMPELLER_DEBUG
234  if (is_metal_trace_active_) {
235  [encoder_ popDebugGroup];
236  }
237 #endif // IMPELLER_DEBUG
238  return true;
239 }
240 
241 // |BlitPass|
242 bool BlitPassMTL::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
243  std::string_view label) {
244 #ifdef IMPELLER_DEBUG
245  if (is_metal_trace_active_) {
246  [encoder_ pushDebugGroup:@(label.data())];
247  }
248 #endif // IMPELLER_DEBUG
249  auto result = TextureMTL::Cast(*texture).GenerateMipmap(encoder_);
250 #ifdef IMPELLER_DEBUG
251  if (is_metal_trace_active_) {
252  [encoder_ popDebugGroup];
253  }
254 #endif // IMPELLER_DEBUG
255  return result;
256 }
257 
258 } // namespace impeller
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
Definition: formats.h:643
IRect64 IRect
Definition: rect.h:860
TPoint< int64_t > IPoint
Definition: point.h:427
constexpr size_t BytesPerRowForTextureWidth(PixelFormat format, int64_t width)
The number of bytes in a single row of texel blocks for a texture of the given width in format.
Definition: formats.h:741