Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
10#include "fml/status.h"
11
26
27namespace impeller {
28
30 const Attachment& desc,
31 MTLRenderPassAttachmentDescriptor* attachment) {
32 bool needs_resolve =
35
36 if (needs_resolve && !desc.resolve_texture) {
37 VALIDATION_LOG << "Resolve store action specified on attachment but no "
38 "resolve texture was specified.";
39 return false;
40 }
41
42 if (desc.resolve_texture && !needs_resolve) {
43 VALIDATION_LOG << "A resolve texture was specified even though the store "
44 "action doesn't require it.";
45 return false;
46 }
47
48 if (!desc.resolve_texture) {
49 return true;
50 }
51
52 attachment.resolveTexture =
54
55 return true;
56}
57
58static bool ConfigureAttachment(const Attachment& desc,
59 MTLRenderPassAttachmentDescriptor* attachment) {
60 if (!desc.texture) {
61 return false;
62 }
63
64 attachment.texture = TextureMTL::Cast(*desc.texture).GetMTLTexture();
65 attachment.loadAction = ToMTLLoadAction(desc.load_action);
66 attachment.storeAction = ToMTLStoreAction(desc.store_action);
67 // mip_level/slice select the subresource of the primary texture. The
68 // resolve texture, if any, resolves into its own level 0 / slice 0.
69 attachment.level = desc.mip_level;
70 attachment.slice = desc.slice;
71
72 if (!ConfigureResolveTextureAttachment(desc, attachment)) {
73 return false;
74 }
75
76 return true;
77}
78
80 const ColorAttachment& desc,
81 MTLRenderPassColorAttachmentDescriptor* attachment) {
82 if (!ConfigureAttachment(desc, attachment)) {
83 return false;
84 }
85 attachment.clearColor = ToMTLClearColor(desc.clear_color);
86 return true;
87}
88
90 const DepthAttachment& desc,
91 MTLRenderPassDepthAttachmentDescriptor* attachment) {
92 if (!ConfigureAttachment(desc, attachment)) {
93 return false;
94 }
95 attachment.clearDepth = desc.clear_depth;
96 return true;
97}
98
100 const StencilAttachment& desc,
101 MTLRenderPassStencilAttachmentDescriptor* attachment) {
102 if (!ConfigureAttachment(desc, attachment)) {
103 return false;
104 }
105 attachment.clearStencil = desc.clear_stencil;
106 return true;
107}
108
109static MTLRenderPassDescriptor* ToMTLRenderPassDescriptor(
110 const RenderTarget& desc) {
111 auto result = [MTLRenderPassDescriptor renderPassDescriptor];
112
113 bool configured_attachment = desc.IterateAllColorAttachments(
114 [&result](size_t index, const ColorAttachment& attachment) -> bool {
115 return ConfigureColorAttachment(attachment,
116 result.colorAttachments[index]);
117 });
118
119 if (!configured_attachment) {
120 VALIDATION_LOG << "Could not configure color attachments";
121 return nil;
122 }
123
124 const auto& depth = desc.GetDepthAttachment();
125
126 if (depth.has_value() &&
127 !ConfigureDepthAttachment(depth.value(), result.depthAttachment)) {
128 VALIDATION_LOG << "Could not configure depth attachment.";
129 return nil;
130 }
131
132 const auto& stencil = desc.GetStencilAttachment();
133
134 if (stencil.has_value() &&
135 !ConfigureStencilAttachment(stencil.value(), result.stencilAttachment)) {
136 VALIDATION_LOG << "Could not configure stencil attachment.";
137 return nil;
138 }
139
140 return result;
141}
142
143RenderPassMTL::RenderPassMTL(std::shared_ptr<const Context> context,
144 const RenderTarget& target,
145 id<MTLCommandBuffer> buffer)
146 : RenderPass(std::move(context), target),
147 buffer_(buffer),
148 desc_(ToMTLRenderPassDescriptor(GetRenderTarget())) {
149 if (!buffer_ || !desc_ || !render_target_.IsValid()) {
150 return;
151 }
152 encoder_ = [buffer_ renderCommandEncoderWithDescriptor:desc_];
153
154 if (!encoder_) {
155 return;
156 }
157#ifdef IMPELLER_DEBUG
158 is_metal_trace_active_ =
159 [[MTLCaptureManager sharedCaptureManager] isCapturing];
160#endif // IMPELLER_DEBUG
161 pass_bindings_.SetEncoder(encoder_);
162 pass_bindings_.SetViewport(
163 Viewport{.rect = Rect::MakeSize(GetRenderTargetSize())});
164 pass_bindings_.SetScissor(IRect32::MakeSize(GetRenderTargetSize()));
165 is_valid_ = true;
166}
167
168RenderPassMTL::~RenderPassMTL() {
169 if (!did_finish_encoding_) {
170 [encoder_ endEncoding];
171 did_finish_encoding_ = true;
172 }
173}
174
175bool RenderPassMTL::IsValid() const {
176 return is_valid_;
177}
178
179void RenderPassMTL::OnSetLabel(std::string_view label) {
180#ifdef IMPELLER_DEBUG
181 if (label.empty()) {
182 return;
183 }
184 encoder_.label = @(std::string(label).c_str());
185#endif // IMPELLER_DEBUG
186}
187
188bool RenderPassMTL::OnEncodeCommands(const Context& context) const {
189 did_finish_encoding_ = true;
190 [encoder_ endEncoding];
191 return true;
192}
193
194static bool Bind(PassBindingsCacheMTL& pass,
195 ShaderStage stage,
196 size_t bind_index,
197 const BufferView& view) {
198 if (!view.GetBuffer()) {
199 return false;
200 }
201
202 const DeviceBuffer* device_buffer = view.GetBuffer();
203 if (!device_buffer) {
204 return false;
205 }
206
207 auto buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
208 // The Metal call is a void return and we don't want to make it on nil.
209 if (!buffer) {
210 return false;
211 }
212
213 return pass.SetBuffer(stage, bind_index, view.GetRange().offset, buffer);
214}
215
216static bool Bind(PassBindingsCacheMTL& pass,
217 ShaderStage stage,
218 size_t bind_index,
220 const Texture& texture) {
221 if (!sampler || !texture.IsValid()) {
222 return false;
223 }
224
225 return pass.SetTexture(stage, bind_index,
226 TextureMTL::Cast(texture).GetMTLTexture()) &&
227 pass.SetSampler(stage, bind_index,
228 SamplerMTL::Cast(*sampler).GetMTLSamplerState());
229}
230
231// |RenderPass|
232void RenderPassMTL::SetPipeline(PipelineRef pipeline) {
233 const PipelineDescriptor& pipeline_desc = pipeline->GetDescriptor();
234 context_->GetPipelineLibrary()->LogPipelineUsage(pipeline_desc);
235 primitive_type_ = pipeline_desc.GetPrimitiveType();
236 pass_bindings_.SetRenderPipelineState(
237 PipelineMTL::Cast(*pipeline).GetMTLRenderPipelineState());
238 pass_bindings_.SetDepthStencilState(
239 PipelineMTL::Cast(*pipeline).GetMTLDepthStencilState());
240
241 [encoder_ setFrontFacingWinding:pipeline_desc.GetWindingOrder() ==
242 WindingOrder::kClockwise
243 ? MTLWindingClockwise
244 : MTLWindingCounterClockwise];
245 [encoder_ setCullMode:ToMTLCullMode(pipeline_desc.GetCullMode())];
246 [encoder_ setTriangleFillMode:ToMTLTriangleFillMode(
247 pipeline_desc.GetPolygonMode())];
248 has_valid_pipeline_ = true;
249}
250
251// |RenderPass|
252void RenderPassMTL::SetCommandLabel(std::string_view label) {
253#ifdef IMPELLER_DEBUG
254 if (is_metal_trace_active_) {
255 has_label_ = true;
256 std::string label_copy(label);
257 [encoder_ pushDebugGroup:@(label_copy.c_str())];
258 }
259#endif // IMPELLER_DEBUG
260}
261
262// |RenderPass|
263void RenderPassMTL::SetStencilReference(uint32_t value) {
264 pass_bindings_.SetStencilRef(value);
265}
266
267// |RenderPass|
268void RenderPassMTL::SetBaseVertex(uint64_t value) {
269 base_vertex_ = value;
270}
271
272// |RenderPass|
273void RenderPassMTL::SetViewport(Viewport viewport) {
274 pass_bindings_.SetViewport(viewport);
275}
276
277// |RenderPass|
278void RenderPassMTL::SetScissor(IRect32 scissor) {
279 pass_bindings_.SetScissor(scissor);
280}
281
282// |RenderPass|
283void RenderPassMTL::SetElementCount(size_t count) {
284 vertex_count_ = count;
285}
286
287// |RenderPass|
288void RenderPassMTL::SetInstanceCount(size_t count) {
289 instance_count_ = count;
290}
291
292// |RenderPass|
293bool RenderPassMTL::SetVertexBuffer(BufferView vertex_buffers[],
294 size_t vertex_buffer_count) {
295 if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
296 return false;
297 }
298
299 for (size_t i = 0; i < vertex_buffer_count; i++) {
300 if (!Bind(pass_bindings_, ShaderStage::kVertex,
301 VertexDescriptor::kReservedVertexBufferIndex - i,
302 vertex_buffers[i])) {
303 return false;
304 }
305 }
306
307 return true;
308}
309
310// |RenderPass|
311bool RenderPassMTL::SetIndexBuffer(BufferView index_buffer,
312 IndexType index_type) {
313 if (!ValidateIndexBuffer(index_buffer, index_type)) {
314 return false;
315 }
316
317 if (index_type != IndexType::kNone) {
318 index_type_ = ToMTLIndexType(index_type);
319 index_buffer_ = std::move(index_buffer);
320 }
321
322 return true;
323}
324
325// |RenderPass|
326fml::Status RenderPassMTL::Draw() {
327 if (!has_valid_pipeline_) {
328 return fml::Status(fml::StatusCode::kCancelled, "Invalid pipeline.");
329 }
330
331 if (!index_buffer_) {
332 if (instance_count_ != 1u) {
333 [encoder_ drawPrimitives:ToMTLPrimitiveType(primitive_type_)
334 vertexStart:base_vertex_
335 vertexCount:vertex_count_
336 instanceCount:instance_count_
337 baseInstance:0u];
338 } else {
339 [encoder_ drawPrimitives:ToMTLPrimitiveType(primitive_type_)
340 vertexStart:base_vertex_
341 vertexCount:vertex_count_];
342 }
343 } else {
344 id<MTLBuffer> mtl_index_buffer =
345 DeviceBufferMTL::Cast(*index_buffer_.GetBuffer()).GetMTLBuffer();
346 if (instance_count_ != 1u) {
347 [encoder_ drawIndexedPrimitives:ToMTLPrimitiveType(primitive_type_)
348 indexCount:vertex_count_
349 indexType:index_type_
350 indexBuffer:mtl_index_buffer
351 indexBufferOffset:index_buffer_.GetRange().offset
352 instanceCount:instance_count_
353 baseVertex:base_vertex_
354 baseInstance:0u];
355 } else {
356 [encoder_ drawIndexedPrimitives:ToMTLPrimitiveType(primitive_type_)
357 indexCount:vertex_count_
358 indexType:index_type_
359 indexBuffer:mtl_index_buffer
360 indexBufferOffset:index_buffer_.GetRange().offset];
361 }
362 }
363
364#ifdef IMPELLER_DEBUG
365 if (has_label_) {
366 [encoder_ popDebugGroup];
367 }
368#endif // IMPELLER_DEBUG
369
370 vertex_count_ = 0u;
371 base_vertex_ = 0u;
372 instance_count_ = 1u;
373 index_buffer_ = {};
374 has_valid_pipeline_ = false;
375 has_label_ = false;
376
377 return fml::Status();
378}
379
380// |RenderPass|
381bool RenderPassMTL::BindResource(ShaderStage stage,
382 DescriptorType type,
383 const ShaderUniformSlot& slot,
384 const ShaderMetadata* metadata,
385 BufferView view) {
386 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
387}
388
389// |RenderPass|
390bool RenderPassMTL::BindDynamicResource(
391 ShaderStage stage,
392 DescriptorType type,
393 const ShaderUniformSlot& slot,
394 std::unique_ptr<ShaderMetadata> metadata,
395 BufferView view) {
396 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
397}
398
399// |RenderPass|
400bool RenderPassMTL::BindResource(ShaderStage stage,
401 DescriptorType type,
402 const SampledImageSlot& slot,
403 const ShaderMetadata* metadata,
404 std::shared_ptr<const Texture> texture,
405 raw_ptr<const Sampler> sampler) {
406 if (!texture) {
407 return false;
408 }
409 return Bind(pass_bindings_, stage, slot.texture_index, sampler, *texture);
410}
411
412bool RenderPassMTL::BindDynamicResource(
413 ShaderStage stage,
414 DescriptorType type,
415 const SampledImageSlot& slot,
416 std::unique_ptr<ShaderMetadata> metadata,
417 std::shared_ptr<const Texture> texture,
418 raw_ptr<const Sampler> sampler) {
419 if (!texture) {
420 return false;
421 }
422 return Bind(pass_bindings_, stage, slot.texture_index, sampler, *texture);
423}
424
425} // namespace impeller
static TextureMTL & Cast(Texture &base)
bool IterateAllColorAttachments(const std::function< bool(size_t index, const ColorAttachment &attachment)> &iterator) const
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
id< MTLTexture > GetMTLTexture() const
A wrapper around a raw ptr that adds additional unopt mode only checks.
Definition raw_ptr.h:15
std::optional< PipelineDescriptor > desc_
int32_t value
FlView * view
uint32_t * target
FlTexture * texture
static bool ConfigureColorAttachment(const ColorAttachment &desc, MTLRenderPassColorAttachmentDescriptor *attachment)
static bool ConfigureDepthAttachment(const DepthAttachment &desc, MTLRenderPassDepthAttachmentDescriptor *attachment)
constexpr MTLLoadAction ToMTLLoadAction(LoadAction action)
static MTLRenderPassDescriptor * ToMTLRenderPassDescriptor(const RenderTarget &desc)
static bool ConfigureResolveTextureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
constexpr MTLPrimitiveType ToMTLPrimitiveType(PrimitiveType type)
static bool ConfigureStencilAttachment(const StencilAttachment &desc, MTLRenderPassStencilAttachmentDescriptor *attachment)
static bool Bind(PassBindingsCacheMTL &pass, ShaderStage stage, size_t bind_index, const BufferView &view)
constexpr MTLIndexType ToMTLIndexType(IndexType type)
constexpr MTLStoreAction ToMTLStoreAction(StoreAction action)
MTLClearColor ToMTLClearColor(const Color &color)
static bool ConfigureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
Definition ref_ptr.h:261
std::shared_ptr< ContextGLES > context
std::shared_ptr< PipelineGLES > pipeline
impeller::ShaderType type
std::shared_ptr< Texture > resolve_texture
Definition formats.h:910
LoadAction load_action
Definition formats.h:911
std::shared_ptr< Texture > texture
Definition formats.h:909
StoreAction store_action
Definition formats.h:912
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)
Set the sampler for the given stage and binding.
bool SetBuffer(ShaderStage stage, uint64_t index, uint64_t offset, id< MTLBuffer > buffer)
Set the buffer for the given shader stage, binding, and offset.
bool SetTexture(ShaderStage stage, uint64_t index, id< MTLTexture > texture)
Set the texture for the given stage and binding.
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
#define VALIDATION_LOG
Definition validation.h:91