| Flutter Impeller |

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
5 #include "impeller/renderer/backend/metal/render_pass_mtl.h"
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
12 #include "impeller/base/backend_cast.h"
13 #include "impeller/core/formats.h"
14 #include "impeller/core/host_buffer.h"
15 #include "impeller/core/shader_types.h"
16 #include "impeller/renderer/backend/metal/context_mtl.h"
17 #include "impeller/renderer/backend/metal/device_buffer_mtl.h"
18 #include "impeller/renderer/backend/metal/formats_mtl.h"
19 #include "impeller/renderer/backend/metal/pipeline_mtl.h"
20 #include "impeller/renderer/backend/metal/sampler_mtl.h"
21 #include "impeller/renderer/backend/metal/texture_mtl.h"
22 #include "impeller/renderer/command.h"
23 #include "impeller/renderer/vertex_descriptor.h"
24
25 namespace impeller {
26
27 static bool ConfigureResolveTextureAttachment(
28 const Attachment& desc,
29 MTLRenderPassAttachmentDescriptor* attachment) {
30 bool needs_resolve =
31 desc.store_action == StoreAction::kMultisampleResolve ||
32 desc.store_action == StoreAction::kStoreAndMultisampleResolve;
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
56 static bool ConfigureAttachment(const Attachment& desc,
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
73 static bool ConfigureColorAttachment(
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
83 static bool ConfigureDepthAttachment(
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
93 static bool ConfigureStencilAttachment(
94 const StencilAttachment& desc,
95 MTLRenderPassStencilAttachmentDescriptor* attachment) {
96 if (!ConfigureAttachment(desc, attachment)) {
97 return false;
98 }
99 attachment.clearStencil = desc.clear_stencil;
100 return true;
101 }
102
103 static MTLRenderPassDescriptor* ToMTLRenderPassDescriptor(
104 const RenderTarget& desc) {
105 auto result = [MTLRenderPassDescriptor renderPassDescriptor];
106
107 const auto& colors = desc.GetColorAttachments();
108
109 for (const auto& color : colors) {
110 if (!ConfigureColorAttachment(color.second,
111 result.colorAttachments[color.first])) {
112 VALIDATION_LOG << "Could not configure color attachment at index "
113 << color.first;
114 return nil;
115 }
116 }
117
118 const auto& depth = desc.GetDepthAttachment();
119
120 if (depth.has_value() &&
121 !ConfigureDepthAttachment(depth.value(), result.depthAttachment)) {
122 VALIDATION_LOG << "Could not configure depth attachment.";
123 return nil;
124 }
125
126 const auto& stencil = desc.GetStencilAttachment();
127
128 if (stencil.has_value() &&
129 !ConfigureStencilAttachment(stencil.value(), result.stencilAttachment)) {
130 VALIDATION_LOG << "Could not configure stencil attachment.";
131 return nil;
132 }
133
134 return result;
135 }
136
137 RenderPassMTL::RenderPassMTL(std::shared_ptr<const Context> context,
138 const RenderTarget& target,
139 id<MTLCommandBuffer> buffer)
140 : RenderPass(std::move(context), target),
141 buffer_(buffer),
142 desc_(ToMTLRenderPassDescriptor(GetRenderTarget())) {
143 if (!buffer_ || !desc_ || !render_target_.IsValid()) {
144 return;
145 }
146 encoder_ = [buffer_ renderCommandEncoderWithDescriptor:desc_];
147
148 if (!encoder_) {
149 return;
150 }
151 #ifdef IMPELLER_DEBUG
152 is_metal_trace_active_ =
153 [[MTLCaptureManager sharedCaptureManager] isCapturing];
154 #endif // IMPELLER_DEBUG
155 pass_bindings_.SetEncoder(encoder_);
156 pass_bindings_.SetViewport(
157 Viewport{.rect = Rect::MakeSize(GetRenderTargetSize())});
158 pass_bindings_.SetScissor(IRect::MakeSize(GetRenderTargetSize()));
159 is_valid_ = true;
160 }
161
162 RenderPassMTL::~RenderPassMTL() {
163 if (!did_finish_encoding_) {
164 [encoder_ endEncoding];
165 did_finish_encoding_ = true;
166 }
167 }
168
169 bool RenderPassMTL::IsValid() const {
170 return is_valid_;
171 }
172
173 void RenderPassMTL::OnSetLabel(std::string label) {
174 #ifdef IMPELLER_DEBUG
175 if (label.empty()) {
176 return;
177 }
178 encoder_.label = @(std::string(label).c_str());
179 #endif // IMPELLER_DEBUG
180 }
181
182 bool RenderPassMTL::OnEncodeCommands(const Context& context) const {
183 did_finish_encoding_ = true;
184 [encoder_ endEncoding];
185 return true;
186 }
187
188 static bool Bind(PassBindingsCacheMTL& pass,
189 ShaderStage stage,
190 size_t bind_index,
191 const BufferView& view) {
192 if (!view.buffer) {
193 return false;
194 }
195
196 auto device_buffer = view.buffer;
197 if (!device_buffer) {
198 return false;
199 }
200
201 auto buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
202 // The Metal call is a void return and we don't want to make it on nil.
203 if (!buffer) {
204 return false;
205 }
206
207 return pass.SetBuffer(stage, bind_index, view.range.offset, buffer);
208 }
209
210 static bool Bind(PassBindingsCacheMTL& pass,
211 ShaderStage stage,
212 size_t bind_index,
213 const std::unique_ptr<const Sampler>& sampler,
214 const Texture& texture) {
215 if (!sampler || !texture.IsValid()) {
216 return false;
217 }
218
219 if (texture.NeedsMipmapGeneration()) {
220 // TODO(127697): generate mips when the GPU is available on iOS.
221 #if !FML_OS_IOS
222 VALIDATION_LOG
223 << "Texture at binding index " << bind_index
224 << " has a mip count > 1, but the mipmap has not been generated.";
225 return false;
226 #endif // !FML_OS_IOS
227 }
228
229 return pass.SetTexture(stage, bind_index,
230 TextureMTL::Cast(texture).GetMTLTexture()) &&
231 pass.SetSampler(stage, bind_index,
232 SamplerMTL::Cast(*sampler).GetMTLSamplerState());
233 }
234
235 // |RenderPass|
236 void RenderPassMTL::SetPipeline(
237 const std::shared_ptr<Pipeline<PipelineDescriptor>>& pipeline) {
238 const PipelineDescriptor& pipeline_desc = pipeline->GetDescriptor();
239 primitive_type_ = pipeline_desc.GetPrimitiveType();
240 pass_bindings_.SetRenderPipelineState(
241 PipelineMTL::Cast(*pipeline).GetMTLRenderPipelineState());
242 pass_bindings_.SetDepthStencilState(
243 PipelineMTL::Cast(*pipeline).GetMTLDepthStencilState());
244
245 [encoder_ setFrontFacingWinding:pipeline_desc.GetWindingOrder() ==
246 WindingOrder::kClockwise
247 ? MTLWindingClockwise
248 : MTLWindingCounterClockwise];
249 [encoder_ setCullMode:ToMTLCullMode(pipeline_desc.GetCullMode())];
250 [encoder_ setTriangleFillMode:ToMTLTriangleFillMode(
251 pipeline_desc.GetPolygonMode())];
252 has_valid_pipeline_ = true;
253 }
254
255 // |RenderPass|
256 void RenderPassMTL::SetCommandLabel(std::string_view label) {
257 #ifdef IMPELLER_DEBUG
258 if (is_metal_trace_active_) {
259 has_label_ = true;
260 std::string label_copy(label);
261 [encoder_ pushDebugGroup:@(label_copy.c_str())];
262 }
263 #endif // IMPELLER_DEBUG
264 }
265
266 // |RenderPass|
267 void RenderPassMTL::SetStencilReference(uint32_t value) {
268 [encoder_ setStencilReferenceValue:value];
269 }
270
271 // |RenderPass|
272 void RenderPassMTL::SetBaseVertex(uint64_t value) {
273 base_vertex_ = value;
274 }
275
276 // |RenderPass|
277 void RenderPassMTL::SetViewport(Viewport viewport) {
278 pass_bindings_.SetViewport(viewport);
279 }
280
281 // |RenderPass|
282 void RenderPassMTL::SetScissor(IRect scissor) {
283 pass_bindings_.SetScissor(scissor);
284 }
285
286 // |RenderPass|
287 void RenderPassMTL::SetInstanceCount(size_t count) {
288 instance_count_ = count;
289 }
290
291 // |RenderPass|
292 bool RenderPassMTL::SetVertexBuffer(VertexBuffer buffer) {
293 if (buffer.index_type == IndexType::kUnknown) {
294 return false;
295 }
296
297 if (!Bind(pass_bindings_, ShaderStage::kVertex,
298 VertexDescriptor::kReservedVertexBufferIndex,
299 buffer.vertex_buffer)) {
300 return false;
301 }
302
303 vertex_count_ = buffer.vertex_count;
304 if (buffer.index_type != IndexType::kNone) {
305 index_type_ = ToMTLIndexType(buffer.index_type);
306 index_buffer_ = std::move(buffer.index_buffer);
307 }
308 return true;
309 }
310
311 // |RenderPass|
312 fml::Status RenderPassMTL::Draw() {
313 if (!has_valid_pipeline_) {
314 return fml::Status(fml::StatusCode::kCancelled, "Invalid pipeline.");
315 }
316
317 if (!index_buffer_) {
318 if (instance_count_ != 1u) {
319 [encoder_ drawPrimitives:ToMTLPrimitiveType(primitive_type_)
320 vertexStart:base_vertex_
321 vertexCount:vertex_count_
322 instanceCount:instance_count_
323 baseInstance:0u];
324 } else {
325 [encoder_ drawPrimitives:ToMTLPrimitiveType(primitive_type_)
326 vertexStart:base_vertex_
327 vertexCount:vertex_count_];
328 }
329 } else {
330 id<MTLBuffer> mtl_index_buffer =
331 DeviceBufferMTL::Cast(*index_buffer_.buffer).GetMTLBuffer();
332 if (instance_count_ != 1u) {
333 [encoder_ drawIndexedPrimitives:ToMTLPrimitiveType(primitive_type_)
334 indexCount:vertex_count_
335 indexType:index_type_
336 indexBuffer:mtl_index_buffer
337 indexBufferOffset:index_buffer_.range.offset
338 instanceCount:instance_count_
339 baseVertex:base_vertex_
340 baseInstance:0u];
341 } else {
342 [encoder_ drawIndexedPrimitives:ToMTLPrimitiveType(primitive_type_)
343 indexCount:vertex_count_
344 indexType:index_type_
345 indexBuffer:mtl_index_buffer
346 indexBufferOffset:index_buffer_.range.offset];
347 }
348 }
349
350 #ifdef IMPELLER_DEBUG
351 if (has_label_) {
352 [encoder_ popDebugGroup];
353 }
354 #endif // IMPELLER_DEBUG
355
356 vertex_count_ = 0u;
357 base_vertex_ = 0u;
358 instance_count_ = 1u;
359 index_buffer_ = {};
360 has_valid_pipeline_ = false;
361 has_label_ = false;
362
363 return fml::Status();
364 }
365
366 // |RenderPass|
367 bool RenderPassMTL::BindResource(ShaderStage stage,
368 DescriptorType type,
369 const ShaderUniformSlot& slot,
370 const ShaderMetadata& metadata,
371 BufferView view) {
372 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
373 }
374
375 // |RenderPass|
376 bool RenderPassMTL::BindResource(
377 ShaderStage stage,
378 DescriptorType type,
379 const ShaderUniformSlot& slot,
380 const std::shared_ptr<const ShaderMetadata>& metadata,
381 BufferView view) {
382 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
383 }
384
385 // |RenderPass|
386 bool RenderPassMTL::BindResource(
387 ShaderStage stage,
388 DescriptorType type,
389 const SampledImageSlot& slot,
390 const ShaderMetadata& metadata,
391 std::shared_ptr<const Texture> texture,
392 const std::unique_ptr<const Sampler>& sampler) {
393 return Bind(pass_bindings_, stage, slot.texture_index, sampler, *texture);
394 }
395
396 } // namespace impeller
impeller::StoreAction::kMultisampleResolve
@ kMultisampleResolve
impeller::Texture::NeedsMipmapGeneration
bool NeedsMipmapGeneration() const
Definition: texture.cc:85
host_buffer.h
impeller::StoreAction::kStoreAndMultisampleResolve
@ kStoreAndMultisampleResolve
impeller::ConfigureColorAttachment
static bool ConfigureColorAttachment(const ColorAttachment &desc, MTLRenderPassColorAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:73
impeller::Attachment::store_action
StoreAction store_action
Definition: formats.h:660
impeller::ConfigureStencilAttachment
static bool ConfigureStencilAttachment(const StencilAttachment &desc, MTLRenderPassStencilAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:93
context_mtl.h
impeller::Bind
static bool Bind(PassBindingsCacheMTL &pass, ShaderStage stage, size_t bind_index, const std::unique_ptr< const Sampler > &sampler, const Texture &texture)
Definition: render_pass_mtl.mm:210
render_pass_mtl.h
impeller::ColorAttachment
Definition: formats.h:665
impeller::Range::offset
size_t offset
Definition: range.h:14
impeller::ConfigureAttachment
static bool ConfigureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:56
impeller::TextureMTL::GetMTLTexture
id< MTLTexture > GetMTLTexture() const
Definition: texture_mtl.mm:134
formats_mtl.h
formats.h
impeller::ShaderStage
ShaderStage
Definition: shader_types.h:22
impeller::ToMTLStoreAction
constexpr MTLStoreAction ToMTLStoreAction(StoreAction action)
Definition: formats_mtl.h:307
impeller::PassBindingsCacheMTL::SetBuffer
bool SetBuffer(ShaderStage stage, uint64_t index, uint64_t offset, id< MTLBuffer > buffer)
Definition: pass_bindings_cache_mtl.mm:31
impeller::PassBindingsCacheMTL
Ensures that bindings on the pass are not redundantly set or updated. Avoids making the driver do add...
Definition: pass_bindings_cache_mtl.h:24
impeller::BufferView::range
Range range
Definition: buffer_view.h:17
impeller::RenderTarget::GetColorAttachments
const std::map< size_t, ColorAttachment > & GetColorAttachments() const
Definition: render_target.cc:198
impeller::Texture::IsValid
virtual bool IsValid() const =0
pipeline_mtl.h
impeller::ToMTLClearColor
MTLClearColor ToMTLClearColor(const Color &color)
Definition: formats_mtl.h:374
vertex_descriptor.h
command.h
impeller::StencilAttachment
Definition: formats.h:673
impeller::ConfigureDepthAttachment
static bool ConfigureDepthAttachment(const DepthAttachment &desc, MTLRenderPassDepthAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:83
impeller::Texture
Definition: texture.h:17
impeller::RenderTarget::GetDepthAttachment
const std::optional< DepthAttachment > & GetDepthAttachment() const
Definition: render_target.cc:203
impeller::ColorAttachment::clear_color
Color clear_color
Definition: formats.h:666
impeller::ToMTLLoadAction
constexpr MTLLoadAction ToMTLLoadAction(LoadAction action)
Definition: formats_mtl.h:279
impeller::ToMTLRenderPassDescriptor
static MTLRenderPassDescriptor * ToMTLRenderPassDescriptor(const RenderTarget &desc)
Definition: render_pass_mtl.mm:103
impeller::Attachment::texture
std::shared_ptr< Texture > texture
Definition: formats.h:657
impeller::ToMTLPrimitiveType
constexpr MTLPrimitiveType ToMTLPrimitiveType(PrimitiveType type)
Definition: formats_mtl.h:150
backend_cast.h
type
GLenum type
Definition: blit_command_gles.cc:127
impeller::Attachment
Definition: formats.h:656
impeller::RenderTarget
Definition: render_target.h:38
impeller::StencilAttachment::clear_stencil
uint32_t clear_stencil
Definition: formats.h:674
impeller::ConfigureResolveTextureAttachment
static bool ConfigureResolveTextureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:27
impeller::PassBindingsCacheMTL::SetTexture
bool SetTexture(ShaderStage stage, uint64_t index, id< MTLTexture > texture)
Definition: pass_bindings_cache_mtl.mm:75
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91
impeller::BufferView
Definition: buffer_view.h:15
impeller::Attachment::resolve_texture
std::shared_ptr< Texture > resolve_texture
Definition: formats.h:658
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
std
Definition: comparable.h:95
texture_mtl.h
impeller::BackendCast< TextureMTL, Texture >::Cast
static TextureMTL & Cast(Texture &base)
Definition: backend_cast.h:13
impeller::BufferView::buffer
std::shared_ptr< const DeviceBuffer > buffer
Definition: buffer_view.h:16
impeller::Attachment::load_action
LoadAction load_action
Definition: formats.h:659
impeller::ToMTLIndexType
constexpr MTLIndexType ToMTLIndexType(IndexType type)
Definition: formats_mtl.h:180
impeller::DepthAttachment::clear_depth
double clear_depth
Definition: formats.h:670
impeller::IRect
IRect64 IRect
Definition: rect.h:779
color
DlColor color
Definition: dl_golden_blur_unittests.cc:24
sampler_mtl.h
impeller::PassBindingsCacheMTL::SetSampler
bool SetSampler(ShaderStage stage, uint64_t index, id< MTLSamplerState > sampler)
Definition: pass_bindings_cache_mtl.mm:99
impeller::DepthAttachment
Definition: formats.h:669
impeller::RenderTarget::GetStencilAttachment
const std::optional< StencilAttachment > & GetStencilAttachment() const
Definition: render_target.cc:207
shader_types.h
impeller::ToMTLCullMode
constexpr MTLCullMode ToMTLCullMode(CullMode mode)
Definition: formats_mtl.h:189
impeller
Definition: allocation.cc:12
impeller::ToMTLTriangleFillMode
constexpr MTLTriangleFillMode ToMTLTriangleFillMode(PolygonMode mode)
Definition: formats_mtl.h:170
device_buffer_mtl.h
impeller::DescriptorType
DescriptorType
Definition: shader_types.h:156