7 #include "flutter/fml/make_copyable.h"
8 #include "flutter/fml/synchronization/semaphore.h"
9 #include "flutter/fml/trace_event.h"
19 static NSString* MTLCommandEncoderErrorStateToString(
20 MTLCommandEncoderErrorState state) {
22 case MTLCommandEncoderErrorStateUnknown:
24 case MTLCommandEncoderErrorStateCompleted:
26 case MTLCommandEncoderErrorStateAffected:
28 case MTLCommandEncoderErrorStatePending:
30 case MTLCommandEncoderErrorStateFaulted:
38 case MTLCommandBufferErrorNone:
40 case MTLCommandBufferErrorInternal:
42 case MTLCommandBufferErrorTimeout:
44 case MTLCommandBufferErrorPageFault:
46 case MTLCommandBufferErrorNotPermitted:
47 return @"not permitted";
48 case MTLCommandBufferErrorOutOfMemory:
49 return @"out of memory";
50 case MTLCommandBufferErrorInvalidResource:
51 return @"invalid resource";
52 case MTLCommandBufferErrorMemoryless:
53 return @"memory-less";
58 return [NSString stringWithFormat:
@"<unknown> %zu", code];
66 if (buffer.status == MTLCommandBufferStatusCompleted) {
70 std::stringstream stream;
71 stream <<
">>>>>>>" << std::endl;
72 stream <<
"Impeller command buffer could not be committed!" << std::endl;
74 if (
auto desc = buffer.error.localizedDescription) {
75 stream << desc.UTF8String << std::endl;
80 << (buffer.error.domain.length > 0u ? buffer.error.domain.UTF8String
84 static_cast<MTLCommandBufferError
>(buffer.error.code))
89 if (@available(iOS 14.0, macOS 11.0, *)) {
90 NSArray<id<MTLCommandBufferEncoderInfo>>* infos =
91 buffer.error.userInfo[MTLCommandBufferEncoderInfoErrorKey];
92 for (id<MTLCommandBufferEncoderInfo> info in infos) {
93 stream << (info.label.length > 0u ? info.label.UTF8String
94 :
"<Unlabelled Render Pass>")
96 << MTLCommandEncoderErrorStateToString(info.errorState).UTF8String
99 auto signposts = [info.debugSignposts componentsJoinedByString:
@", "];
100 if (signposts.length > 0u) {
101 stream << signposts.UTF8String << std::endl;
105 for (id<MTLFunctionLog> log in buffer.logs) {
106 auto desc = log.description;
107 if (desc.length > 0u) {
108 stream << desc.UTF8String << std::endl;
119 #ifndef FLUTTER_RELEASE
120 if (@available(iOS 14.0, macOS 11.0, *)) {
121 auto desc = [[MTLCommandBufferDescriptor alloc] init];
124 desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
125 return [queue commandBufferWithDescriptor:desc];
127 #endif // FLUTTER_RELEASE
128 return [queue commandBuffer];
131 CommandBufferMTL::CommandBufferMTL(
const std::weak_ptr<const Context>& context,
132 id<MTLCommandQueue> queue)
135 CommandBufferMTL::~CommandBufferMTL() =
default;
137 bool CommandBufferMTL::IsValid()
const {
138 return buffer_ != nil;
141 void CommandBufferMTL::SetLabel(
const std::string& label)
const {
146 [buffer_ setLabel:@(label.data())];
151 case MTLCommandBufferStatusCompleted:
152 return CommandBufferMTL::Status::kCompleted;
153 case MTLCommandBufferStatusEnqueued:
154 return CommandBufferMTL::Status::kPending;
158 return CommandBufferMTL::Status::kError;
161 bool CommandBufferMTL::OnSubmitCommands(CompletionCallback callback) {
164 addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
165 [[maybe_unused]]
auto result =
168 <<
"Must not have errors during command buffer submission.";
179 bool CommandBufferMTL::SubmitCommandsAsync(
180 std::shared_ptr<RenderPass> render_pass) {
181 TRACE_EVENT0(
"impeller",
"CommandBufferMTL::SubmitCommandsAsync");
182 if (!IsValid() || !render_pass->IsValid()) {
185 auto context = context_.lock();
190 auto buffer = buffer_;
193 auto worker_task_runner = ContextMTL::Cast(*context).GetWorkerTaskRunner();
194 auto mtl_render_pass =
static_cast<RenderPassMTL*
>(render_pass.get());
199 auto render_command_encoder =
200 [buffer renderCommandEncoderWithDescriptor:mtl_render_pass->desc_];
201 if (!render_command_encoder) {
205 auto task = fml::MakeCopyable(
206 [render_pass, buffer, render_command_encoder, weak_context = context_]() {
207 auto context = weak_context.lock();
209 [render_command_encoder endEncoding];
213 auto mtl_render_pass =
static_cast<RenderPassMTL*
>(render_pass.get());
214 if (!mtl_render_pass->label_.empty()) {
215 [render_command_encoder setLabel:@(mtl_render_pass->label_.c_str())];
218 auto result = mtl_render_pass->EncodeCommands(
219 context->GetResourceAllocator(), render_command_encoder);
220 [render_command_encoder endEncoding];
227 worker_task_runner->PostTask(task);
231 void CommandBufferMTL::OnWaitUntilScheduled() {}
233 std::shared_ptr<RenderPass> CommandBufferMTL::OnCreateRenderPass(
234 RenderTarget target) {
239 auto pass = std::shared_ptr<RenderPassMTL>(
240 new RenderPassMTL(context_, target, buffer_));
241 if (!pass->IsValid()) {
248 std::shared_ptr<BlitPass> CommandBufferMTL::OnCreateBlitPass() {
253 auto pass = std::shared_ptr<BlitPassMTL>(
new BlitPassMTL(buffer_));
254 if (!pass->IsValid()) {
261 std::shared_ptr<ComputePass> CommandBufferMTL::OnCreateComputePass() {
267 std::shared_ptr<ComputePassMTL>(
new ComputePassMTL(context_, buffer_));
268 if (!pass->IsValid()) {