From 2dd37970828b8e641ca2dd9aff63bb8238ec7537 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 5 Apr 2022 13:22:12 -0700 Subject: [PATCH] Wire up enhanced command buffer error reporting. (#113) --- .../backend/metal/command_buffer_mtl.mm | 117 +++++++++++++++++- impeller/renderer/renderer.cc | 2 + 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.mm b/impeller/renderer/backend/metal/command_buffer_mtl.mm index 672edfa0a36d2..1f2b8576ca4a1 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/command_buffer_mtl.mm @@ -8,8 +8,19 @@ namespace impeller { +id CreateCommandBuffer(id queue) { + if (@available(iOS 14.0, macOS 11.0, *)) { + auto desc = [[MTLCommandBufferDescriptor alloc] init]; + // Degrades CPU performance slightly but is well worth the cost for typical + // Impeller workloads. + desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus; + return [queue commandBufferWithDescriptor:desc]; + } + return [queue commandBuffer]; +} + CommandBufferMTL::CommandBufferMTL(id queue) - : buffer_([queue commandBuffer]) { + : buffer_(CreateCommandBuffer(queue)) { if (!buffer_) { return; } @@ -42,6 +53,109 @@ return CommandBufferMTL::Status::kError; } +API_AVAILABLE(ios(14.0), macos(11.0)) +NSString* MTLCommandEncoderErrorStateToString( + MTLCommandEncoderErrorState state) { + switch (state) { + case MTLCommandEncoderErrorStateUnknown: + return @"unknown"; + case MTLCommandEncoderErrorStateCompleted: + return @"completed"; + case MTLCommandEncoderErrorStateAffected: + return @"affected"; + case MTLCommandEncoderErrorStatePending: + return @"pending"; + case MTLCommandEncoderErrorStateFaulted: + return @"faulted"; + } + return @"unknown"; +} + +static NSString* MTLCommandBufferErrorToString(MTLCommandBufferError code) { + switch (code) { + case MTLCommandBufferErrorNone: + return @"none"; + case MTLCommandBufferErrorInternal: + return @"internal"; + case MTLCommandBufferErrorTimeout: + return @"timeout"; + case MTLCommandBufferErrorPageFault: + return @"page fault"; + case MTLCommandBufferErrorAccessRevoked: + return @"access revoked / blacklisted"; + case MTLCommandBufferErrorNotPermitted: + return @"not permitted"; + case MTLCommandBufferErrorOutOfMemory: + return @"out of memory"; + case MTLCommandBufferErrorInvalidResource: + return @"invalid resource"; + case MTLCommandBufferErrorMemoryless: + return @"memory-less"; + case MTLCommandBufferErrorStackOverflow: + return @"stack overflow"; + default: + break; + } + + return [NSString stringWithFormat:@" %zu", code]; +} + +static void LogMTLCommandBufferErrorIfPresent(id buffer) { + if (!buffer) { + return; + } + + if (buffer.status == MTLCommandBufferStatusCompleted) { + return; + } + + std::stringstream stream; + stream << ">>>>>>>" << std::endl; + stream << "Impeller command buffer could not be committed!" << std::endl; + + if (auto desc = buffer.error.localizedDescription) { + stream << desc.UTF8String << std::endl; + } + + if (buffer.error) { + stream << "Domain: " + << (buffer.error.domain.length > 0u ? buffer.error.domain.UTF8String + : "") + << " Code: " + << MTLCommandBufferErrorToString( + static_cast(buffer.error.code)) + .UTF8String + << std::endl; + } + + if (@available(iOS 14.0, macOS 11.0, *)) { + NSArray>* infos = + buffer.error.userInfo[MTLCommandBufferEncoderInfoErrorKey]; + for (id info in infos) { + stream << (info.label.length > 0u ? info.label.UTF8String + : "") + << ": " + << MTLCommandEncoderErrorStateToString(info.errorState).UTF8String + << std::endl; + + auto signposts = [info.debugSignposts componentsJoinedByString:@", "]; + if (signposts.length > 0u) { + stream << signposts.UTF8String << std::endl; + } + } + + for (id log in buffer.logs) { + auto desc = log.description; + if (desc.length > 0u) { + stream << desc.UTF8String << std::endl; + } + } + } + + stream << "<<<<<<<"; + VALIDATION_LOG << stream.str(); +} + bool CommandBufferMTL::SubmitCommands(CompletionCallback callback) { if (!buffer_) { // Already committed. This is caller error. @@ -53,6 +167,7 @@ if (callback) { [buffer_ addCompletedHandler:^(id buffer) { + LogMTLCommandBufferErrorIfPresent(buffer); callback(ToCommitResult(buffer.status)); }]; } diff --git a/impeller/renderer/renderer.cc b/impeller/renderer/renderer.cc index 5507314fe87ef..fab86fcd8d9f6 100644 --- a/impeller/renderer/renderer.cc +++ b/impeller/renderer/renderer.cc @@ -57,6 +57,8 @@ bool Renderer::Render(std::unique_ptr surface, return false; } + render_pass->SetLabel("Onscreen Render Pass"); + if (render_callback && !render_callback(*render_pass)) { return false; }