7 #include <Metal/Metal.h>
11 #include "flutter/fml/backtrace.h"
12 #include "flutter/fml/closure.h"
13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/trace_event.h"
15 #include "fml/status.h"
30 ComputePassMTL::ComputePassMTL(std::shared_ptr<const Context>
context,
31 id<MTLCommandBuffer> buffer)
32 : ComputePass(
std::move(
context)), buffer_(buffer) {
36 encoder_ = [buffer_ computeCommandEncoderWithDispatchType:
37 MTLDispatchType::MTLDispatchTypeConcurrent];
41 pass_bindings_cache_.SetEncoder(encoder_);
45 ComputePassMTL::~ComputePassMTL() =
default;
47 bool ComputePassMTL::IsValid()
const {
51 void ComputePassMTL::OnSetLabel(
const std::string& label) {
56 [encoder_ setLabel:@(label.c_str())];
60 void ComputePassMTL::SetCommandLabel(std::string_view label) {
62 [encoder_ pushDebugGroup:@(label.data())];
66 void ComputePassMTL::SetPipeline(
67 const std::shared_ptr<Pipeline<ComputePipelineDescriptor>>&
pipeline) {
68 pass_bindings_cache_.SetComputePipelineState(
69 ComputePipelineMTL::Cast(*pipeline).GetMTLComputePipelineState());
70 workgroup_size_ =
pipeline->GetDescriptor().GetWorkgroupSize();
74 void ComputePassMTL::AddBufferMemoryBarrier() {
75 [encoder_ memoryBarrierWithScope:MTLBarrierScopeBuffers];
79 void ComputePassMTL::AddTextureMemoryBarrier() {
80 [encoder_ memoryBarrierWithScope:MTLBarrierScopeTextures];
84 bool ComputePassMTL::BindResource(
ShaderStage stage,
86 const ShaderUniformSlot& slot,
87 const ShaderMetadata* metadata,
89 if (!view.GetBuffer()) {
93 const DeviceBuffer* device_buffer = view.GetBuffer();
98 id<MTLBuffer> buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
104 pass_bindings_cache_.SetBuffer(slot.ext_res_0, view.GetRange().offset,
110 bool ComputePassMTL::BindResource(
ShaderStage stage,
112 const SampledImageSlot& slot,
113 const ShaderMetadata* metadata,
114 std::shared_ptr<const Texture> texture,
115 raw_ptr<const Sampler> sampler) {
116 if (!sampler || !texture->IsValid()) {
120 pass_bindings_cache_.SetTexture(slot.texture_index,
121 TextureMTL::Cast(*texture).GetMTLTexture());
122 pass_bindings_cache_.SetSampler(
123 slot.texture_index, SamplerMTL::Cast(*sampler).GetMTLSamplerState());
127 fml::Status ComputePassMTL::Compute(std::array<uint32_t, 3> workgroup_count) {
128 if (workgroup_count[0] == 0u || workgroup_count[1] == 0u ||
129 workgroup_count[2] == 0u) {
130 return fml::Status(fml::StatusCode::kCancelled,
131 "Invalid workgroup count for compute command.");
134 const NSUInteger max_total =
135 pass_bindings_cache_.GetPipeline().maxTotalThreadsPerThreadgroup;
142 MTLSize threads_per_threadgroup;
143 if (workgroup_size_[0] == 0u) {
144 const NSUInteger size_y =
145 workgroup_size_[1] == 0u ? 1u : workgroup_size_[1];
146 const NSUInteger size_z =
147 workgroup_size_[2] == 0u ? 1u : workgroup_size_[2];
148 const NSUInteger size_x =
149 std::max<NSUInteger>(1u, max_total / (size_y * size_z));
150 threads_per_threadgroup = MTLSizeMake(size_x, size_y, size_z);
152 threads_per_threadgroup = MTLSizeMake(
153 workgroup_size_[0], workgroup_size_[1] == 0u ? 1 : workgroup_size_[1],
154 workgroup_size_[2] == 0u ? 1 : workgroup_size_[2]);
160 if (threads_per_threadgroup.width * threads_per_threadgroup.height *
161 threads_per_threadgroup.depth >
163 return fml::Status(fml::StatusCode::kCancelled,
164 "Compute shader workgroup size exceeds the device's "
165 "maximum threads per threadgroup.");
169 dispatchThreadgroups:MTLSizeMake(workgroup_count[0], workgroup_count[1],
171 threadsPerThreadgroup:threads_per_threadgroup];
173 #ifdef IMPELLER_DEBUG
175 [encoder_ popDebugGroup];
179 return fml::Status();
182 bool ComputePassMTL::EncodeCommands()
const {
183 [encoder_ endEncoding];
std::shared_ptr< ContextGLES > context
std::shared_ptr< PipelineGLES > pipeline