Blender V5.0
mtl_debug.mm
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "BLI_compiler_attrs.h"
12#include "BLI_string.h"
13#include "BLI_system.h"
14#include "BLI_utildefines.h"
15
16#include "BKE_global.hh"
17
18#include "GPU_debug.hh"
19#include "GPU_platform.hh"
20
21#include "mtl_context.hh"
22#include "mtl_debug.hh"
23
24#include "CLG_log.h"
25
26#include "gpu_profile_report.hh"
27
28#include <utility>
29
30namespace blender::gpu::debug {
31
32CLG_LogRef LOG = {"gpu.debug.metal"};
33
35{
37}
38
39} // namespace blender::gpu::debug
40
41namespace blender::gpu {
42
43/* -------------------------------------------------------------------- */
49
50void MTLContext::debug_group_begin(const char *name, int index)
51{
52 if (G.debug & G_DEBUG_GPU) {
53 this->main_command_buffer.push_debug_group(name, index);
54 }
55
56 if (!G.profile_gpu) {
57 return;
58 }
59
60 ScopeTimings timings = {};
61 timings.name = name;
62 timings.finished = false;
63 timings.cpu_start = ScopeTimings::Clock::now();
64
65 scope_timings.append(timings);
66}
67
69{
70 if (G.debug & G_DEBUG_GPU) {
71 this->main_command_buffer.pop_debug_group();
72 }
73
74 if (!G.profile_gpu) {
75 return;
76 }
77
78 for (int i = scope_timings.size() - 1; i >= 0; i--) {
79 ScopeTimings &query = scope_timings[i];
80 if (!query.finished) {
81 query.finished = true;
82 query.cpu_end = ScopeTimings::Clock::now();
83 break;
84 }
85 if (i == 0) {
86 CLOG_ERROR(&debug::LOG, "Profile GPU error: Extra GPU_debug_group_end() call.");
87 }
88 }
89}
90
91MTLContext::ScopeTimings::TimePoint MTLContext::ScopeTimings::epoch =
92 MTLContext::ScopeTimings::Clock::now();
93
94void MTLContext::process_frame_timings()
95{
96 if (!G.profile_gpu) {
97 return;
98 }
99
100 Vector<ScopeTimings> &queries = scope_timings;
101
102 bool frame_is_valid = !queries.is_empty();
103
104 for (int i = queries.size() - 1; i >= 0; i--) {
105 if (!queries[i].finished) {
106 frame_is_valid = false;
107 CLOG_ERROR(&debug::LOG, "Profile GPU error: Missing GPU_debug_group_end() call");
108 }
109 break;
110 }
111
112 if (!frame_is_valid) {
113 return;
114 }
115
116 for (ScopeTimings &query : queries) {
117 ScopeTimings::Nanoseconds begin = query.cpu_start - ScopeTimings::epoch;
118 ScopeTimings::Nanoseconds end = query.cpu_end - ScopeTimings::epoch;
119 ProfileReport::get().add_group_cpu(query.name, begin.count(), end.count());
120 }
121
122 queries.clear();
123}
124
125bool MTLContext::debug_capture_begin(const char * /*title*/)
126{
127 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
128 if (!capture_manager) {
129 /* Early exit if frame capture is disabled. */
130 return false;
131 }
132 MTLCaptureDescriptor *capture_descriptor = [[MTLCaptureDescriptor alloc] init];
133 capture_descriptor.captureObject = this->device;
134 NSError *error;
135 if (![capture_manager startCaptureWithDescriptor:capture_descriptor error:&error]) {
136 NSLog(@"Failed to start Metal frame capture, error %@", error);
137 return false;
138 }
139 return true;
140}
141
143{
144 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
145 if (!capture_manager) {
146 /* Early exit if frame capture is disabled. */
147 return;
148 }
149 [capture_manager stopCapture];
150}
151
153{
154 /* Create a capture scope visible to xCode Metal Frame capture utility. */
155 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
156 if (!capture_manager) {
157 /* Early exit if frame capture is disabled. */
158 return nullptr;
159 }
160 id<MTLCaptureScope> capture_scope = [capture_manager newCaptureScopeWithDevice:this->device];
161 capture_scope.label = [NSString stringWithUTF8String:name];
162 [capture_scope retain];
163
164 return reinterpret_cast<void *>(capture_scope);
165}
166
168{
169 /* Declare opening boundary of scope.
170 * When scope is selected for capture, GPU commands between begin/end scope will be captured. */
171 [(id<MTLCaptureScope>)scope beginScope];
172
173 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
174 return [capture_manager isCapturing];
175}
176
178{
179 [(id<MTLCaptureScope>)scope endScope];
180}
181
183
184} // namespace blender::gpu
@ G_DEBUG_GPU
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define CLOG_ENSURE(clg_ref)
Definition CLG_log.h:144
iter begin(iter)
int64_t size() const
bool is_empty() const
bool debug_capture_begin(const char *title) override
Definition mtl_debug.mm:125
void * debug_capture_scope_create(const char *name) override
Definition mtl_debug.mm:152
void debug_capture_scope_end(void *scope) override
Definition mtl_debug.mm:177
void debug_group_begin(const char *name, int index) override
Definition mtl_debug.mm:50
bool debug_capture_scope_begin(void *scope) override
Definition mtl_debug.mm:167
MTLCommandBufferManager main_command_buffer
void debug_group_end() override
Definition mtl_debug.mm:68
void debug_capture_end() override
Definition mtl_debug.mm:142
static ProfileReport & get()
void add_group_cpu(StringRefNull name, uint64_t cpu_start, uint64_t cpu_end)
#define G(x, y, z)
static void error(const char *str)
static void init(bNodeTree *, bNode *node)
const char * name
i
Definition text_draw.cc:230