Flutter Impeller
compute_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 #include <memory>
9 
10 #include "flutter/fml/backtrace.h"
11 #include "flutter/fml/closure.h"
12 #include "flutter/fml/logging.h"
13 #include "flutter/fml/trace_event.h"
14 #include "fml/status.h"
17 #include "impeller/core/formats.h"
26 
27 namespace impeller {
28 
29 ComputePassMTL::ComputePassMTL(std::shared_ptr<const Context> context,
30  id<MTLCommandBuffer> buffer)
31  : ComputePass(std::move(context)), buffer_(buffer) {
32  if (!buffer_) {
33  return;
34  }
35  encoder_ = [buffer_ computeCommandEncoderWithDispatchType:
36  MTLDispatchType::MTLDispatchTypeConcurrent];
37  if (!encoder_) {
38  return;
39  }
40  pass_bindings_cache_.SetEncoder(encoder_);
41  is_valid_ = true;
42 }
43 
45 
46 bool ComputePassMTL::IsValid() const {
47  return is_valid_;
48 }
49 
50 void ComputePassMTL::OnSetLabel(const std::string& label) {
51 #ifdef IMPELLER_DEBUG
52  if (label.empty()) {
53  return;
54  }
55  [encoder_ setLabel:@(label.c_str())];
56 #endif // IMPELLER_DEBUG
57 }
58 
59 void ComputePassMTL::SetCommandLabel(std::string_view label) {
60  has_label_ = true;
61  [encoder_ pushDebugGroup:@(label.data())];
62 }
63 
64 // |ComputePass|
65 void ComputePassMTL::SetPipeline(
66  const std::shared_ptr<Pipeline<ComputePipelineDescriptor>>& pipeline) {
67  pass_bindings_cache_.SetComputePipelineState(
69 }
70 
71 // |ComputePass|
72 void ComputePassMTL::AddBufferMemoryBarrier() {
73  [encoder_ memoryBarrierWithScope:MTLBarrierScopeBuffers];
74 }
75 
76 // |ComputePass|
77 void ComputePassMTL::AddTextureMemoryBarrier() {
78  [encoder_ memoryBarrierWithScope:MTLBarrierScopeTextures];
79 }
80 
81 // |ComputePass|
82 bool ComputePassMTL::BindResource(ShaderStage stage,
83  DescriptorType type,
84  const ShaderUniformSlot& slot,
85  const ShaderMetadata& metadata,
86  BufferView view) {
87  if (!view.buffer) {
88  return false;
89  }
90 
91  const std::shared_ptr<const DeviceBuffer>& device_buffer = view.buffer;
92  if (!device_buffer) {
93  return false;
94  }
95 
96  id<MTLBuffer> buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
97  // The Metal call is a void return and we don't want to make it on nil.
98  if (!buffer) {
99  return false;
100  }
101 
102  pass_bindings_cache_.SetBuffer(slot.ext_res_0, view.range.offset, buffer);
103  return true;
104 }
105 
106 // |ComputePass|
107 bool ComputePassMTL::BindResource(
108  ShaderStage stage,
109  DescriptorType type,
110  const SampledImageSlot& slot,
111  const ShaderMetadata& metadata,
112  std::shared_ptr<const Texture> texture,
113  const std::unique_ptr<const Sampler>& sampler) {
114  if (!sampler || !texture->IsValid()) {
115  return false;
116  }
117 
118  pass_bindings_cache_.SetTexture(slot.texture_index,
119  TextureMTL::Cast(*texture).GetMTLTexture());
120  pass_bindings_cache_.SetSampler(
121  slot.texture_index, SamplerMTL::Cast(*sampler).GetMTLSamplerState());
122  return true;
123 }
124 
125 fml::Status ComputePassMTL::Compute(const ISize& grid_size) {
126  if (grid_size.IsEmpty()) {
127  return fml::Status(fml::StatusCode::kUnknown,
128  "Invalid grid size for compute command.");
129  }
130  // TODO(dnfield): use feature detection to support non-uniform threadgroup
131  // sizes.
132  // https://github.com/flutter/flutter/issues/110619
133  auto width = grid_size.width;
134  auto height = grid_size.height;
135 
136  auto max_total_threads_per_threadgroup = static_cast<int64_t>(
137  pass_bindings_cache_.GetPipeline().maxTotalThreadsPerThreadgroup);
138 
139  // Special case for linear processing.
140  if (height == 1) {
141  int64_t thread_groups = std::max(
142  static_cast<int64_t>(
143  std::ceil(width * 1.0 / max_total_threads_per_threadgroup * 1.0)),
144  1LL);
145  [encoder_
146  dispatchThreadgroups:MTLSizeMake(thread_groups, 1, 1)
147  threadsPerThreadgroup:MTLSizeMake(max_total_threads_per_threadgroup, 1,
148  1)];
149  } else {
150  while (width * height > max_total_threads_per_threadgroup) {
151  width = std::max(1LL, width / 2);
152  height = std::max(1LL, height / 2);
153  }
154 
155  auto size = MTLSizeMake(width, height, 1);
156  [encoder_ dispatchThreadgroups:size threadsPerThreadgroup:size];
157  }
158 
159 #ifdef IMPELLER_DEBUG
160  if (has_label_) {
161  [encoder_ popDebugGroup];
162  }
163  has_label_ = false;
164 #endif // IMPELLER_DEBUG
165  return fml::Status();
166 }
167 
168 bool ComputePassMTL::EncodeCommands() const {
169  [encoder_ endEncoding];
170  return true;
171 }
172 
173 } // namespace impeller
impeller::ComputePassBindingsCacheMTL::SetTexture
void SetTexture(uint64_t index, id< MTLTexture > texture)
Definition: compute_pass_bindings_cache_mtl.mm:49
impeller::ComputePassBindingsCacheMTL::SetBuffer
void SetBuffer(uint64_t index, uint64_t offset, id< MTLBuffer > buffer)
Definition: compute_pass_bindings_cache_mtl.mm:27
host_buffer.h
device_buffer.h
compute_pipeline_mtl.h
formats.h
impeller::TextureMTL::GetMTLTexture
id< MTLTexture > GetMTLTexture() const
Definition: texture_mtl.mm:116
formats_mtl.h
impeller::ShaderStage
ShaderStage
Definition: shader_types.h:22
command.h
impeller::ComputePassBindingsCacheMTL::SetComputePipelineState
void SetComputePipelineState(id< MTLComputePipelineState > pipeline)
Definition: compute_pass_bindings_cache_mtl.mm:9
impeller::ComputePassMTL::~ComputePassMTL
~ComputePassMTL() override
impeller::ComputePipelineMTL::GetMTLComputePipelineState
id< MTLComputePipelineState > GetMTLComputePipelineState() const
Definition: compute_pipeline_mtl.mm:25
backend_cast.h
impeller::ComputePassBindingsCacheMTL::SetSampler
void SetSampler(uint64_t index, id< MTLSamplerState > sampler)
Definition: compute_pass_bindings_cache_mtl.mm:61
impeller::DeviceBufferMTL::GetMTLBuffer
id< MTLBuffer > GetMTLBuffer() const
Definition: device_buffer_mtl.mm:21
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:138
std
Definition: comparable.h:95
texture_mtl.h
impeller::BackendCast< ComputePipelineMTL, Pipeline< ComputePipelineDescriptor > >::Cast
static ComputePipelineMTL & Cast(Pipeline< ComputePipelineDescriptor > &base)
Definition: backend_cast.h:13
impeller::ComputePassBindingsCacheMTL::SetEncoder
void SetEncoder(id< MTLComputeCommandEncoder > encoder)
Definition: compute_pass_bindings_cache_mtl.mm:22
compute_pass_mtl.h
sampler_mtl.h
shader_types.h
impeller
Definition: aiks_blur_unittests.cc:20
impeller::SamplerMTL::GetMTLSamplerState
id< MTLSamplerState > GetMTLSamplerState() const
Definition: sampler_mtl.mm:16
device_buffer_mtl.h
impeller::ComputePassBindingsCacheMTL::GetPipeline
id< MTLComputePipelineState > GetPipeline() const
Definition: compute_pass_bindings_cache_mtl.mm:18
impeller::DescriptorType
DescriptorType
Definition: shader_types.h:153