Skip to content

Commit 2dd3797

Browse files
chinmaygardednfield
authored andcommitted
Wire up enhanced command buffer error reporting. (#113)
1 parent f2bf47d commit 2dd3797

File tree

2 files changed

+118
-1
lines changed

2 files changed

+118
-1
lines changed

impeller/renderer/backend/metal/command_buffer_mtl.mm

+116-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,19 @@
88

99
namespace impeller {
1010

11+
id<MTLCommandBuffer> CreateCommandBuffer(id<MTLCommandQueue> queue) {
12+
if (@available(iOS 14.0, macOS 11.0, *)) {
13+
auto desc = [[MTLCommandBufferDescriptor alloc] init];
14+
// Degrades CPU performance slightly but is well worth the cost for typical
15+
// Impeller workloads.
16+
desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
17+
return [queue commandBufferWithDescriptor:desc];
18+
}
19+
return [queue commandBuffer];
20+
}
21+
1122
CommandBufferMTL::CommandBufferMTL(id<MTLCommandQueue> queue)
12-
: buffer_([queue commandBuffer]) {
23+
: buffer_(CreateCommandBuffer(queue)) {
1324
if (!buffer_) {
1425
return;
1526
}
@@ -42,6 +53,109 @@
4253
return CommandBufferMTL::Status::kError;
4354
}
4455

56+
API_AVAILABLE(ios(14.0), macos(11.0))
57+
NSString* MTLCommandEncoderErrorStateToString(
58+
MTLCommandEncoderErrorState state) {
59+
switch (state) {
60+
case MTLCommandEncoderErrorStateUnknown:
61+
return @"unknown";
62+
case MTLCommandEncoderErrorStateCompleted:
63+
return @"completed";
64+
case MTLCommandEncoderErrorStateAffected:
65+
return @"affected";
66+
case MTLCommandEncoderErrorStatePending:
67+
return @"pending";
68+
case MTLCommandEncoderErrorStateFaulted:
69+
return @"faulted";
70+
}
71+
return @"unknown";
72+
}
73+
74+
static NSString* MTLCommandBufferErrorToString(MTLCommandBufferError code) {
75+
switch (code) {
76+
case MTLCommandBufferErrorNone:
77+
return @"none";
78+
case MTLCommandBufferErrorInternal:
79+
return @"internal";
80+
case MTLCommandBufferErrorTimeout:
81+
return @"timeout";
82+
case MTLCommandBufferErrorPageFault:
83+
return @"page fault";
84+
case MTLCommandBufferErrorAccessRevoked:
85+
return @"access revoked / blacklisted";
86+
case MTLCommandBufferErrorNotPermitted:
87+
return @"not permitted";
88+
case MTLCommandBufferErrorOutOfMemory:
89+
return @"out of memory";
90+
case MTLCommandBufferErrorInvalidResource:
91+
return @"invalid resource";
92+
case MTLCommandBufferErrorMemoryless:
93+
return @"memory-less";
94+
case MTLCommandBufferErrorStackOverflow:
95+
return @"stack overflow";
96+
default:
97+
break;
98+
}
99+
100+
return [NSString stringWithFormat:@"<unknown> %zu", code];
101+
}
102+
103+
static void LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
104+
if (!buffer) {
105+
return;
106+
}
107+
108+
if (buffer.status == MTLCommandBufferStatusCompleted) {
109+
return;
110+
}
111+
112+
std::stringstream stream;
113+
stream << ">>>>>>>" << std::endl;
114+
stream << "Impeller command buffer could not be committed!" << std::endl;
115+
116+
if (auto desc = buffer.error.localizedDescription) {
117+
stream << desc.UTF8String << std::endl;
118+
}
119+
120+
if (buffer.error) {
121+
stream << "Domain: "
122+
<< (buffer.error.domain.length > 0u ? buffer.error.domain.UTF8String
123+
: "<unknown>")
124+
<< " Code: "
125+
<< MTLCommandBufferErrorToString(
126+
static_cast<MTLCommandBufferError>(buffer.error.code))
127+
.UTF8String
128+
<< std::endl;
129+
}
130+
131+
if (@available(iOS 14.0, macOS 11.0, *)) {
132+
NSArray<id<MTLCommandBufferEncoderInfo>>* infos =
133+
buffer.error.userInfo[MTLCommandBufferEncoderInfoErrorKey];
134+
for (id<MTLCommandBufferEncoderInfo> info in infos) {
135+
stream << (info.label.length > 0u ? info.label.UTF8String
136+
: "<Unlabelled Render Pass>")
137+
<< ": "
138+
<< MTLCommandEncoderErrorStateToString(info.errorState).UTF8String
139+
<< std::endl;
140+
141+
auto signposts = [info.debugSignposts componentsJoinedByString:@", "];
142+
if (signposts.length > 0u) {
143+
stream << signposts.UTF8String << std::endl;
144+
}
145+
}
146+
147+
for (id<MTLFunctionLog> log in buffer.logs) {
148+
auto desc = log.description;
149+
if (desc.length > 0u) {
150+
stream << desc.UTF8String << std::endl;
151+
}
152+
}
153+
}
154+
155+
stream << "<<<<<<<";
156+
VALIDATION_LOG << stream.str();
157+
}
158+
45159
bool CommandBufferMTL::SubmitCommands(CompletionCallback callback) {
46160
if (!buffer_) {
47161
// Already committed. This is caller error.
@@ -53,6 +167,7 @@
53167

54168
if (callback) {
55169
[buffer_ addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
170+
LogMTLCommandBufferErrorIfPresent(buffer);
56171
callback(ToCommitResult(buffer.status));
57172
}];
58173
}

impeller/renderer/renderer.cc

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ bool Renderer::Render(std::unique_ptr<Surface> surface,
5757
return false;
5858
}
5959

60+
render_pass->SetLabel("Onscreen Render Pass");
61+
6062
if (render_callback && !render_callback(*render_pass)) {
6163
return false;
6264
}

0 commit comments

Comments
 (0)