Flutter Engine
The Flutter Engine
render_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 "flutter/fml/closure.h"
8#include "flutter/fml/logging.h"
9#include "flutter/fml/make_copyable.h"
10#include "fml/status.h"
11
24
25namespace impeller {
26
28 const Attachment& desc,
29 MTLRenderPassAttachmentDescriptor* attachment) {
30 bool needs_resolve =
31 desc.store_action == StoreAction::kMultisampleResolve ||
33
34 if (needs_resolve && !desc.resolve_texture) {
35 VALIDATION_LOG << "Resolve store action specified on attachment but no "
36 "resolve texture was specified.";
37 return false;
38 }
39
40 if (desc.resolve_texture && !needs_resolve) {
41 VALIDATION_LOG << "A resolve texture was specified even though the store "
42 "action doesn't require it.";
43 return false;
44 }
45
46 if (!desc.resolve_texture) {
47 return true;
48 }
49
50 attachment.resolveTexture =
51 TextureMTL::Cast(*desc.resolve_texture).GetMTLTexture();
52
53 return true;
54}
55
57 MTLRenderPassAttachmentDescriptor* attachment) {
58 if (!desc.texture) {
59 return false;
60 }
61
62 attachment.texture = TextureMTL::Cast(*desc.texture).GetMTLTexture();
63 attachment.loadAction = ToMTLLoadAction(desc.load_action);
64 attachment.storeAction = ToMTLStoreAction(desc.store_action);
65
66 if (!ConfigureResolveTextureAttachment(desc, attachment)) {
67 return false;
68 }
69
70 return true;
71}
72
74 const ColorAttachment& desc,
75 MTLRenderPassColorAttachmentDescriptor* attachment) {
76 if (!ConfigureAttachment(desc, attachment)) {
77 return false;
78 }
79 attachment.clearColor = ToMTLClearColor(desc.clear_color);
80 return true;
81}
82
84 const DepthAttachment& desc,
85 MTLRenderPassDepthAttachmentDescriptor* attachment) {
86 if (!ConfigureAttachment(desc, attachment)) {
87 return false;
88 }
89 attachment.clearDepth = desc.clear_depth;
90 return true;
91}
92
95 MTLRenderPassStencilAttachmentDescriptor* attachment) {
96 if (!ConfigureAttachment(desc, attachment)) {
97 return false;
98 }
99 attachment.clearStencil = desc.clear_stencil;
100 return true;
101}
102
103// TODO(csg): Move this to formats_mtl.h
104static MTLRenderPassDescriptor* ToMTLRenderPassDescriptor(
105 const RenderTarget& desc) {
106 auto result = [MTLRenderPassDescriptor renderPassDescriptor];
107
108 const auto& colors = desc.GetColorAttachments();
109
110 for (const auto& color : colors) {
112 result.colorAttachments[color.first])) {
113 VALIDATION_LOG << "Could not configure color attachment at index "
114 << color.first;
115 return nil;
116 }
117 }
118
119 const auto& depth = desc.GetDepthAttachment();
120
121 if (depth.has_value() &&
122 !ConfigureDepthAttachment(depth.value(), result.depthAttachment)) {
123 VALIDATION_LOG << "Could not configure depth attachment.";
124 return nil;
125 }
126
127 const auto& stencil = desc.GetStencilAttachment();
128
129 if (stencil.has_value() &&
130 !ConfigureStencilAttachment(stencil.value(), result.stencilAttachment)) {
131 VALIDATION_LOG << "Could not configure stencil attachment.";
132 return nil;
133 }
134
135 return result;
136}
137
138RenderPassMTL::RenderPassMTL(std::shared_ptr<const Context> context,
139 const RenderTarget& target,
140 id<MTLCommandBuffer> buffer)
141 : RenderPass(std::move(context), target),
142 buffer_(buffer),
143 desc_(ToMTLRenderPassDescriptor(GetRenderTarget())) {
144 if (!buffer_ || !desc_ || !render_target_.IsValid()) {
145 return;
146 }
147 encoder_ = [buffer_ renderCommandEncoderWithDescriptor:desc_];
148
149 if (!encoder_) {
150 return;
151 }
152#ifdef IMPELLER_DEBUG
153 is_metal_trace_active_ =
154 [[MTLCaptureManager sharedCaptureManager] isCapturing];
155#endif // IMPELLER_DEBUG
156 pass_bindings_.SetEncoder(encoder_);
157 pass_bindings_.SetViewport(
158 Viewport{.rect = Rect::MakeSize(GetRenderTargetSize())});
159 pass_bindings_.SetScissor(IRect::MakeSize(GetRenderTargetSize()));
160 is_valid_ = true;
161}
162
163RenderPassMTL::~RenderPassMTL() {
164 if (!did_finish_encoding_) {
165 [encoder_ endEncoding];
166 did_finish_encoding_ = true;
167 }
168}
169
170bool RenderPassMTL::IsValid() const {
171 return is_valid_;
172}
173
174void RenderPassMTL::OnSetLabel(std::string label) {
175#ifdef IMPELLER_DEBUG
176 if (label.empty()) {
177 return;
178 }
179 encoder_.label = @(std::string(label).c_str());
180#endif // IMPELLER_DEBUG
181}
182
183bool RenderPassMTL::OnEncodeCommands(const Context& context) const {
184 did_finish_encoding_ = true;
185 [encoder_ endEncoding];
186 return true;
187}
188
189static bool Bind(PassBindingsCacheMTL& pass,
190 ShaderStage stage,
191 size_t bind_index,
192 const BufferView& view) {
193 if (!view.buffer) {
194 return false;
195 }
196
197 auto device_buffer = view.buffer;
198 if (!device_buffer) {
199 return false;
200 }
201
202 auto buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
203 // The Metal call is a void return and we don't want to make it on nil.
204 if (!buffer) {
205 return false;
206 }
207
208 return pass.SetBuffer(stage, bind_index, view.range.offset, buffer);
209}
210
211static bool Bind(PassBindingsCacheMTL& pass,
212 ShaderStage stage,
213 size_t bind_index,
214 const std::unique_ptr<const Sampler>& sampler,
215 const Texture& texture) {
216 if (!sampler || !texture.IsValid()) {
217 return false;
218 }
219
220 if (texture.NeedsMipmapGeneration()) {
221 // TODO(127697): generate mips when the GPU is available on iOS.
222#if !FML_OS_IOS
224 << "Texture at binding index " << bind_index
225 << " has a mip count > 1, but the mipmap has not been generated.";
226 return false;
227#endif // !FML_OS_IOS
228 }
229
230 return pass.SetTexture(stage, bind_index,
231 TextureMTL::Cast(texture).GetMTLTexture()) &&
232 pass.SetSampler(stage, bind_index,
233 SamplerMTL::Cast(*sampler).GetMTLSamplerState());
234}
235
236// |RenderPass|
237void RenderPassMTL::SetPipeline(
238 const std::shared_ptr<Pipeline<PipelineDescriptor>>& pipeline) {
239 const PipelineDescriptor& pipeline_desc = pipeline->GetDescriptor();
240 primitive_type_ = pipeline_desc.GetPrimitiveType();
241 pass_bindings_.SetRenderPipelineState(
242 PipelineMTL::Cast(*pipeline).GetMTLRenderPipelineState());
243 pass_bindings_.SetDepthStencilState(
244 PipelineMTL::Cast(*pipeline).GetMTLDepthStencilState());
245
246 [encoder_ setFrontFacingWinding:pipeline_desc.GetWindingOrder() ==
247 WindingOrder::kClockwise
248 ? MTLWindingClockwise
249 : MTLWindingCounterClockwise];
250 [encoder_ setCullMode:ToMTLCullMode(pipeline_desc.GetCullMode())];
251 [encoder_ setTriangleFillMode:ToMTLTriangleFillMode(
252 pipeline_desc.GetPolygonMode())];
253 has_valid_pipeline_ = true;
254}
255
256// |RenderPass|
257void RenderPassMTL::SetCommandLabel(std::string_view label) {
258#ifdef IMPELLER_DEBUG
259 if (is_metal_trace_active_) {
260 has_label_ = true;
261 std::string label_copy(label);
262 [encoder_ pushDebugGroup:@(label_copy.c_str())];
263 }
264#endif // IMPELLER_DEBUG
265}
266
267// |RenderPass|
268void RenderPassMTL::SetStencilReference(uint32_t value) {
269 [encoder_ setStencilReferenceValue:value];
270}
271
272// |RenderPass|
273void RenderPassMTL::SetBaseVertex(uint64_t value) {
274 base_vertex_ = value;
275}
276
277// |RenderPass|
278void RenderPassMTL::SetViewport(Viewport viewport) {
279 pass_bindings_.SetViewport(viewport);
280}
281
282// |RenderPass|
283void RenderPassMTL::SetScissor(IRect scissor) {
284 pass_bindings_.SetScissor(scissor);
285}
286
287// |RenderPass|
288void RenderPassMTL::SetInstanceCount(size_t count) {
289 instance_count_ = count;
290}
291
292// |RenderPass|
293bool RenderPassMTL::SetVertexBuffer(VertexBuffer buffer) {
294 if (buffer.index_type == IndexType::kUnknown) {
295 return false;
296 }
297
298 if (!Bind(pass_bindings_, ShaderStage::kVertex,
299 VertexDescriptor::kReservedVertexBufferIndex,
300 buffer.vertex_buffer)) {
301 return false;
302 }
303
304 vertex_count_ = buffer.vertex_count;
305 if (buffer.index_type != IndexType::kNone) {
306 index_type_ = ToMTLIndexType(buffer.index_type);
307 index_buffer_ = std::move(buffer.index_buffer);
308 }
309 return true;
310}
311
312// |RenderPass|
314 if (!has_valid_pipeline_) {
315 return fml::Status(fml::StatusCode::kCancelled, "Invalid pipeline.");
316 }
317
318 if (!index_buffer_) {
319 if (instance_count_ != 1u) {
320 [encoder_ drawPrimitives:ToMTLPrimitiveType(primitive_type_)
321 vertexStart:base_vertex_
322 vertexCount:vertex_count_
323 instanceCount:instance_count_
324 baseInstance:0u];
325 } else {
326 [encoder_ drawPrimitives:ToMTLPrimitiveType(primitive_type_)
327 vertexStart:base_vertex_
328 vertexCount:vertex_count_];
329 }
330 } else {
331 id<MTLBuffer> mtl_index_buffer =
332 DeviceBufferMTL::Cast(*index_buffer_.buffer).GetMTLBuffer();
333 if (instance_count_ != 1u) {
334 [encoder_ drawIndexedPrimitives:ToMTLPrimitiveType(primitive_type_)
335 indexCount:vertex_count_
336 indexType:index_type_
337 indexBuffer:mtl_index_buffer
338 indexBufferOffset:index_buffer_.range.offset
339 instanceCount:instance_count_
340 baseVertex:base_vertex_
341 baseInstance:0u];
342 } else {
343 [encoder_ drawIndexedPrimitives:ToMTLPrimitiveType(primitive_type_)
344 indexCount:vertex_count_
345 indexType:index_type_
346 indexBuffer:mtl_index_buffer
347 indexBufferOffset:index_buffer_.range.offset];
348 }
349 }
350
351#ifdef IMPELLER_DEBUG
352 if (has_label_) {
353 [encoder_ popDebugGroup];
354 }
355#endif // IMPELLER_DEBUG
356
357 vertex_count_ = 0u;
358 base_vertex_ = 0u;
359 instance_count_ = 1u;
360 index_buffer_ = {};
361 has_valid_pipeline_ = false;
362 has_label_ = false;
363
364 return fml::Status();
365}
366
367// |RenderPass|
368bool RenderPassMTL::BindResource(ShaderStage stage,
370 const ShaderUniformSlot& slot,
371 const ShaderMetadata& metadata,
372 BufferView view) {
373 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
374}
375
376// |RenderPass|
377bool RenderPassMTL::BindResource(
378 ShaderStage stage,
380 const ShaderUniformSlot& slot,
381 const std::shared_ptr<const ShaderMetadata>& metadata,
382 BufferView view) {
383 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
384}
385
386// |RenderPass|
387bool RenderPassMTL::BindResource(
388 ShaderStage stage,
390 const SampledImageSlot& slot,
391 const ShaderMetadata& metadata,
392 std::shared_ptr<const Texture> texture,
393 const std::unique_ptr<const Sampler>& sampler) {
394 return Bind(pass_bindings_, stage, slot.texture_index, sampler, *texture);
395}
396
397} // namespace impeller
int count
Definition: FontMgrTest.cpp:50
GLenum type
static TextureMTL & Cast(Texture &base)
Definition: backend_cast.h:13
id< MTLTexture > GetMTLTexture() const
Definition: texture_mtl.mm:116
static void Draw(SkCanvas *canvas, const SkRect &rect)
DlColor color
uint8_t value
GAsyncResult * result
uint32_t * target
FlTexture * texture
PODArray< SkColor > colors
Definition: SkRecords.h:276
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
@ kNone
Definition: layer.h:53
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
static bool ConfigureColorAttachment(const ColorAttachment &desc, MTLRenderPassColorAttachmentDescriptor *attachment)
static bool ConfigureDepthAttachment(const DepthAttachment &desc, MTLRenderPassDepthAttachmentDescriptor *attachment)
IRect64 IRect
Definition: rect.h:772
constexpr MTLLoadAction ToMTLLoadAction(LoadAction action)
Definition: formats_mtl.h:275
static bool Bind(PassBindingsCacheMTL &pass, ShaderStage stage, size_t bind_index, const std::unique_ptr< const Sampler > &sampler, const Texture &texture)
static MTLRenderPassDescriptor * ToMTLRenderPassDescriptor(const RenderTarget &desc)
static bool ConfigureResolveTextureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
constexpr MTLPrimitiveType ToMTLPrimitiveType(PrimitiveType type)
Definition: formats_mtl.h:150
static bool ConfigureStencilAttachment(const StencilAttachment &desc, MTLRenderPassStencilAttachmentDescriptor *attachment)
constexpr MTLTriangleFillMode ToMTLTriangleFillMode(PolygonMode mode)
Definition: formats_mtl.h:166
constexpr MTLIndexType ToMTLIndexType(IndexType type)
Definition: formats_mtl.h:176
constexpr MTLStoreAction ToMTLStoreAction(StoreAction action)
Definition: formats_mtl.h:303
MTLClearColor ToMTLClearColor(const Color &color)
Definition: formats_mtl.h:370
static bool ConfigureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
constexpr MTLCullMode ToMTLCullMode(CullMode mode)
Definition: formats_mtl.h:185
Task::Status Status
Definition: TaskList.cpp:15
Definition: ref_ptr.h:256
std::shared_ptr< const DeviceBuffer > buffer
Definition: buffer_view.h:16
Ensures that bindings on the pass are not redundantly set or updated. Avoids making the driver do add...
bool SetSampler(ShaderStage stage, uint64_t index, id< MTLSamplerState > sampler)
bool SetBuffer(ShaderStage stage, uint64_t index, uint64_t offset, id< MTLBuffer > buffer)
bool SetTexture(ShaderStage stage, uint64_t index, id< MTLTexture > texture)
size_t offset
Definition: range.h:13
static constexpr TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
#define VALIDATION_LOG
Definition: validation.h:73