7 #include "flutter/fml/closure.h"
8 #include "flutter/fml/logging.h"
9 #include "flutter/fml/make_copyable.h"
10 #include "fml/status.h"
29 MTLRenderPassAttachmentDescriptor* attachment) {
35 VALIDATION_LOG <<
"Resolve store action specified on attachment but no "
36 "resolve texture was specified.";
41 VALIDATION_LOG <<
"A resolve texture was specified even though the store "
42 "action doesn't require it.";
50 attachment.resolveTexture =
57 MTLRenderPassAttachmentDescriptor* attachment) {
75 MTLRenderPassColorAttachmentDescriptor* attachment) {
85 MTLRenderPassDepthAttachmentDescriptor* attachment) {
95 MTLRenderPassStencilAttachmentDescriptor* attachment) {
106 auto result = [MTLRenderPassDescriptor renderPassDescriptor];
110 for (
const auto& color : colors) {
112 result.colorAttachments[color.first])) {
113 VALIDATION_LOG <<
"Could not configure color attachment at index "
121 if (depth.has_value() &&
129 if (stencil.has_value() &&
138 RenderPassMTL::RenderPassMTL(std::shared_ptr<const Context> context,
139 const RenderTarget& target,
140 id<MTLCommandBuffer> buffer)
141 : RenderPass(
std::move(context), target),
144 if (!buffer_ || !desc_ || !render_target_.IsValid()) {
147 encoder_ = [buffer_ renderCommandEncoderWithDescriptor:desc_];
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(
163 RenderPassMTL::~RenderPassMTL() {
164 if (!did_finish_encoding_) {
165 [encoder_ endEncoding];
166 did_finish_encoding_ =
true;
170 bool RenderPassMTL::IsValid()
const {
174 void RenderPassMTL::OnSetLabel(std::string label) {
175 #ifdef IMPELLER_DEBUG
179 encoder_.label = @(std::string(label).c_str());
180 #endif // IMPELLER_DEBUG
183 bool RenderPassMTL::OnEncodeCommands(
const Context& context)
const {
184 did_finish_encoding_ =
true;
185 [encoder_ endEncoding];
197 auto device_buffer = view.
buffer;
198 if (!device_buffer) {
202 auto buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
214 const std::unique_ptr<const Sampler>& sampler,
216 if (!sampler || !texture.
IsValid()) {
224 <<
"Texture at binding index " << bind_index
225 <<
" has a mip count > 1, but the mipmap has not been generated.";
227 #endif // !FML_OS_IOS
231 TextureMTL::Cast(texture).GetMTLTexture()) &&
233 SamplerMTL::Cast(*sampler).GetMTLSamplerState());
237 void 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());
246 [encoder_ setFrontFacingWinding:pipeline_desc.GetWindingOrder() ==
247 WindingOrder::kClockwise
248 ? MTLWindingClockwise
249 : MTLWindingCounterClockwise];
250 [encoder_ setCullMode:
ToMTLCullMode(pipeline_desc.GetCullMode())];
252 pipeline_desc.GetPolygonMode())];
253 has_valid_pipeline_ =
true;
257 void RenderPassMTL::SetCommandLabel(std::string_view label) {
258 #ifdef IMPELLER_DEBUG
259 if (is_metal_trace_active_) {
261 std::string label_copy(label);
262 [encoder_ pushDebugGroup:@(label_copy.c_str())];
264 #endif // IMPELLER_DEBUG
268 void RenderPassMTL::SetStencilReference(uint32_t value) {
269 [encoder_ setStencilReferenceValue:value];
273 void RenderPassMTL::SetBaseVertex(uint64_t value) {
274 base_vertex_ = value;
278 void RenderPassMTL::SetViewport(Viewport viewport) {
279 pass_bindings_.SetViewport(viewport);
283 void RenderPassMTL::SetScissor(
IRect scissor) {
284 pass_bindings_.SetScissor(scissor);
288 void RenderPassMTL::SetInstanceCount(
size_t count) {
289 instance_count_ = count;
293 bool RenderPassMTL::SetVertexBuffer(VertexBuffer buffer) {
294 if (buffer.index_type == IndexType::kUnknown) {
298 if (!
Bind(pass_bindings_, ShaderStage::kVertex,
299 VertexDescriptor::kReservedVertexBufferIndex,
300 buffer.vertex_buffer)) {
304 vertex_count_ = buffer.vertex_count;
305 if (buffer.index_type != IndexType::kNone) {
307 index_buffer_ = std::move(buffer.index_buffer);
313 fml::Status RenderPassMTL::Draw() {
314 if (!has_valid_pipeline_) {
315 return fml::Status(fml::StatusCode::kCancelled,
"Invalid pipeline.");
318 if (!index_buffer_) {
319 if (instance_count_ != 1u) {
321 vertexStart:base_vertex_
322 vertexCount:vertex_count_
323 instanceCount:instance_count_
327 vertexStart:base_vertex_
328 vertexCount:vertex_count_];
331 id<MTLBuffer> mtl_index_buffer =
332 DeviceBufferMTL::Cast(*index_buffer_.buffer).GetMTLBuffer();
333 if (instance_count_ != 1u) {
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_
344 indexCount:vertex_count_
345 indexType:index_type_
346 indexBuffer:mtl_index_buffer
347 indexBufferOffset:index_buffer_.range.offset];
351 #ifdef IMPELLER_DEBUG
353 [encoder_ popDebugGroup];
355 #endif // IMPELLER_DEBUG
359 instance_count_ = 1u;
361 has_valid_pipeline_ =
false;
364 return fml::Status();
368 bool RenderPassMTL::BindResource(
ShaderStage stage,
370 const ShaderUniformSlot& slot,
371 const ShaderMetadata& metadata,
373 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
377 bool RenderPassMTL::BindResource(
380 const ShaderUniformSlot& slot,
381 const std::shared_ptr<const ShaderMetadata>& metadata,
383 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
387 bool RenderPassMTL::BindResource(
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);