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) {
105 auto result = [MTLRenderPassDescriptor renderPassDescriptor];
109 for (
const auto&
color : colors) {
111 result.colorAttachments[
color.first])) {
112 VALIDATION_LOG <<
"Could not configure color attachment at index "
120 if (depth.has_value() &&
128 if (stencil.has_value() &&
137 RenderPassMTL::RenderPassMTL(std::shared_ptr<const Context> context,
138 const RenderTarget& target,
139 id<MTLCommandBuffer> buffer)
140 : RenderPass(
std::move(context), target),
143 if (!buffer_ || !desc_ || !render_target_.IsValid()) {
146 encoder_ = [buffer_ renderCommandEncoderWithDescriptor:desc_];
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(
162 RenderPassMTL::~RenderPassMTL() {
163 if (!did_finish_encoding_) {
164 [encoder_ endEncoding];
165 did_finish_encoding_ =
true;
169 bool RenderPassMTL::IsValid()
const {
173 void RenderPassMTL::OnSetLabel(std::string label) {
174 #ifdef IMPELLER_DEBUG
178 encoder_.label = @(std::string(label).c_str());
179 #endif // IMPELLER_DEBUG
182 bool RenderPassMTL::OnEncodeCommands(
const Context& context)
const {
183 did_finish_encoding_ =
true;
184 [encoder_ endEncoding];
196 auto device_buffer = view.
buffer;
197 if (!device_buffer) {
201 auto buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
213 const std::unique_ptr<const Sampler>& sampler,
215 if (!sampler || !texture.
IsValid()) {
223 <<
"Texture at binding index " << bind_index
224 <<
" has a mip count > 1, but the mipmap has not been generated.";
226 #endif // !FML_OS_IOS
230 TextureMTL::Cast(texture).GetMTLTexture()) &&
232 SamplerMTL::Cast(*sampler).GetMTLSamplerState());
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());
245 [encoder_ setFrontFacingWinding:pipeline_desc.GetWindingOrder() ==
246 WindingOrder::kClockwise
247 ? MTLWindingClockwise
248 : MTLWindingCounterClockwise];
249 [encoder_ setCullMode:
ToMTLCullMode(pipeline_desc.GetCullMode())];
251 pipeline_desc.GetPolygonMode())];
252 has_valid_pipeline_ =
true;
256 void RenderPassMTL::SetCommandLabel(std::string_view label) {
257 #ifdef IMPELLER_DEBUG
258 if (is_metal_trace_active_) {
260 std::string label_copy(label);
261 [encoder_ pushDebugGroup:@(label_copy.c_str())];
263 #endif // IMPELLER_DEBUG
267 void RenderPassMTL::SetStencilReference(uint32_t value) {
268 [encoder_ setStencilReferenceValue:value];
272 void RenderPassMTL::SetBaseVertex(uint64_t value) {
273 base_vertex_ = value;
277 void RenderPassMTL::SetViewport(Viewport viewport) {
278 pass_bindings_.SetViewport(viewport);
282 void RenderPassMTL::SetScissor(
IRect scissor) {
283 pass_bindings_.SetScissor(scissor);
287 void RenderPassMTL::SetInstanceCount(
size_t count) {
288 instance_count_ = count;
292 bool RenderPassMTL::SetVertexBuffer(VertexBuffer buffer) {
293 if (buffer.index_type == IndexType::kUnknown) {
297 if (!
Bind(pass_bindings_, ShaderStage::kVertex,
298 VertexDescriptor::kReservedVertexBufferIndex,
299 buffer.vertex_buffer)) {
303 vertex_count_ = buffer.vertex_count;
304 if (buffer.index_type != IndexType::kNone) {
306 index_buffer_ = std::move(buffer.index_buffer);
312 fml::Status RenderPassMTL::Draw() {
313 if (!has_valid_pipeline_) {
314 return fml::Status(fml::StatusCode::kCancelled,
"Invalid pipeline.");
317 if (!index_buffer_) {
318 if (instance_count_ != 1u) {
320 vertexStart:base_vertex_
321 vertexCount:vertex_count_
322 instanceCount:instance_count_
326 vertexStart:base_vertex_
327 vertexCount:vertex_count_];
330 id<MTLBuffer> mtl_index_buffer =
331 DeviceBufferMTL::Cast(*index_buffer_.buffer).GetMTLBuffer();
332 if (instance_count_ != 1u) {
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_
343 indexCount:vertex_count_
344 indexType:index_type_
345 indexBuffer:mtl_index_buffer
346 indexBufferOffset:index_buffer_.range.offset];
350 #ifdef IMPELLER_DEBUG
352 [encoder_ popDebugGroup];
354 #endif // IMPELLER_DEBUG
358 instance_count_ = 1u;
360 has_valid_pipeline_ =
false;
363 return fml::Status();
367 bool RenderPassMTL::BindResource(
ShaderStage stage,
369 const ShaderUniformSlot& slot,
370 const ShaderMetadata& metadata,
372 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
376 bool RenderPassMTL::BindResource(
379 const ShaderUniformSlot& slot,
380 const std::shared_ptr<const ShaderMetadata>& metadata,
382 return Bind(pass_bindings_, stage, slot.ext_res_0, view);
386 bool RenderPassMTL::BindResource(
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);