7 #include "flutter/fml/make_copyable.h"
8 #include "flutter/fml/synchronization/semaphore.h"
18 static NSString* MTLCommandEncoderErrorStateToString(
19 MTLCommandEncoderErrorState state) {
21 case MTLCommandEncoderErrorStateUnknown:
23 case MTLCommandEncoderErrorStateCompleted:
25 case MTLCommandEncoderErrorStateAffected:
27 case MTLCommandEncoderErrorStatePending:
29 case MTLCommandEncoderErrorStateFaulted:
37 case MTLCommandBufferErrorNone:
39 case MTLCommandBufferErrorInternal:
41 case MTLCommandBufferErrorTimeout:
43 case MTLCommandBufferErrorPageFault:
45 case MTLCommandBufferErrorNotPermitted:
46 return @"not permitted";
47 case MTLCommandBufferErrorOutOfMemory:
48 return @"out of memory";
49 case MTLCommandBufferErrorInvalidResource:
50 return @"invalid resource";
51 case MTLCommandBufferErrorMemoryless:
52 return @"memory-less";
57 return [NSString stringWithFormat:
@"<unknown> %zu", code];
65 if (buffer.status == MTLCommandBufferStatusCompleted) {
69 std::stringstream stream;
70 stream <<
">>>>>>>" << std::endl;
71 stream <<
"Impeller command buffer could not be committed!" << std::endl;
73 if (
auto desc = buffer.error.localizedDescription) {
74 stream << desc.UTF8String << std::endl;
79 << (buffer.error.domain.length > 0u ? buffer.error.domain.UTF8String
83 static_cast<MTLCommandBufferError
>(buffer.error.code))
88 if (@available(iOS 14.0, macOS 11.0, *)) {
89 NSArray<id<MTLCommandBufferEncoderInfo>>* infos =
90 buffer.error.userInfo[MTLCommandBufferEncoderInfoErrorKey];
91 for (id<MTLCommandBufferEncoderInfo> info in infos) {
92 stream << (info.label.length > 0u ? info.label.UTF8String
93 :
"<Unlabelled Render Pass>")
95 << MTLCommandEncoderErrorStateToString(info.errorState).UTF8String
98 auto signposts = [info.debugSignposts componentsJoinedByString:
@", "];
99 if (signposts.length > 0u) {
100 stream << signposts.UTF8String << std::endl;
104 for (id<MTLFunctionLog> log in buffer.logs) {
105 auto desc = log.description;
106 if (desc.length > 0u) {
107 stream << desc.UTF8String << std::endl;
118 #ifndef FLUTTER_RELEASE
119 if (@available(iOS 14.0, macOS 11.0, *)) {
120 auto desc = [[MTLCommandBufferDescriptor alloc] init];
123 desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
124 return [queue commandBufferWithDescriptor:desc];
127 return [queue commandBuffer];
130 CommandBufferMTL::CommandBufferMTL(
const std::weak_ptr<const Context>& context,
131 id<MTLDevice> device,
132 id<MTLCommandQueue> queue)
133 : CommandBuffer(context),
137 CommandBufferMTL::~CommandBufferMTL() =
default;
139 bool CommandBufferMTL::IsValid()
const {
140 return buffer_ != nil;
143 void CommandBufferMTL::SetLabel(std::string_view label)
const {
144 #ifdef IMPELLER_DEBUG
149 [buffer_ setLabel:@(label.data())];
155 case MTLCommandBufferStatusCompleted:
156 return CommandBufferMTL::Status::kCompleted;
157 case MTLCommandBufferStatusEnqueued:
158 return CommandBufferMTL::Status::kPending;
162 return CommandBufferMTL::Status::kError;
165 bool CommandBufferMTL::OnSubmitCommands(
bool block_on_schedule,
166 CompletionCallback callback) {
167 auto context = context_.lock();
171 #ifdef IMPELLER_DEBUG
172 ContextMTL::Cast(*context).GetGPUTracer()->RecordCmdBuffer(buffer_);
176 addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
177 [[maybe_unused]]
auto result =
180 <<
"Must not have errors during command buffer submission.";
186 if (block_on_schedule) {
187 [buffer_ waitUntilScheduled];
194 void CommandBufferMTL::OnWaitUntilCompleted() {}
196 void CommandBufferMTL::OnWaitUntilScheduled() {}
198 std::shared_ptr<RenderPass> CommandBufferMTL::OnCreateRenderPass(
199 RenderTarget target) {
204 auto context = context_.lock();
208 auto pass = std::shared_ptr<RenderPassMTL>(
209 new RenderPassMTL(context, target, buffer_));
210 if (!pass->IsValid()) {
217 std::shared_ptr<BlitPass> CommandBufferMTL::OnCreateBlitPass() {
222 auto pass = std::shared_ptr<BlitPassMTL>(
new BlitPassMTL(buffer_, device_));
223 if (!pass->IsValid()) {
230 std::shared_ptr<ComputePass> CommandBufferMTL::OnCreateComputePass() {
234 auto context = context_.lock();
240 std::shared_ptr<ComputePassMTL>(
new ComputePassMTL(context, buffer_));
241 if (!pass->IsValid()) {
static bool LogMTLCommandBufferErrorIfPresent(id< MTLCommandBuffer > buffer)
API_AVAILABLE(ios(14.0), macos(11.0)) static NSString *MTLCommandEncoderErrorStateToString(MTLCommandEncoderErrorState state)
static id< MTLCommandBuffer > CreateCommandBuffer(id< MTLCommandQueue > queue)
static NSString * MTLCommandBufferErrorToString(MTLCommandBufferError code)
static CommandBuffer::Status ToCommitResult(MTLCommandBufferStatus status)