Flutter Engine
The Flutter Engine
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
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
56static 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
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
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// 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|
313fml::Status RenderPassMTL::Draw() {
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
SkColor4f color
static TextureMTL & Cast(Texture &base)
To do anything rendering related with Impeller, you need a context.
Definition context.h:46
PrimitiveType GetPrimitiveType() const
Describes the fixed function and programmable aspects of rendering and compute operations performed b...
Definition pipeline.h:49
id< MTLTexture > GetMTLTexture() const
static const uint8_t buffer[]
uint8_t value
GAsyncResult * result
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)
constexpr MTLTriangleFillMode ToMTLTriangleFillMode(PolygonMode mode)
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)
constexpr MTLCullMode ToMTLCullMode(CullMode mode)
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:15
Metadata required to bind a combined texture and sampler.
size_t texture_index
ext_res_0 is the Metal binding value.
Metadata required to bind a buffer.
size_t ext_res_0
ext_res_0 is the Metal binding value.
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:146
#define VALIDATION_LOG
Definition validation.h:73