Blender V4.3
gpu_shader_log.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "BLI_dynstr.h"
12#include "BLI_string.h"
13#include "BLI_string_utils.hh"
14#include "BLI_vector.hh"
15
16#include "GPU_storage_buffer.hh"
17
20#include "gpu_shader_private.hh"
21
22#include "CLG_log.h"
23
24static CLG_LogRef LOG = {"gpu.shader"};
25
26namespace blender::gpu {
27
28/* -------------------------------------------------------------------- */
32/* Number of lines before and after the error line to print for compilation errors. */
33#define DEBUG_CONTEXT_LINES 0
38#define DEBUG_DEPENDENCIES 0
39
41 const char *log,
42 const char *stage,
43 const bool error,
44 GPULogParser *parser)
45{
46 const char line_prefix[] = " | ";
47 char err_col[] = "\033[31;1m";
48 char warn_col[] = "\033[33;1m";
49 char info_col[] = "\033[0;2m";
50 char reset_col[] = "\033[0;0m";
51 char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size());
52 DynStr *dynstr = BLI_dynstr_new();
53
55 err_col[0] = warn_col[0] = info_col[0] = reset_col[0] = '\0';
56 }
57
58 BLI_dynstr_appendf(dynstr, "\n");
59
60#if DEBUG_DEPENDENCIES
62 dynstr, "%s%sIncluded files (in order):%s\n", info_col, line_prefix, reset_col);
63#endif
64
65 Vector<int64_t> sources_end_line;
66 for (StringRefNull src : sources) {
67 int64_t cursor = 0, line_count = 0;
68 while ((cursor = src.find('\n', cursor) + 1)) {
69 line_count++;
70 }
71 if (sources_end_line.is_empty() == false) {
72 line_count += sources_end_line.last();
73 }
74 sources_end_line.append(line_count);
75#if DEBUG_DEPENDENCIES
77 if (!filename.is_empty()) {
79 dynstr, "%s%s %s%s\n", info_col, line_prefix, filename.c_str(), reset_col);
80 }
81#endif
82 }
83 if (sources_end_line.is_empty()) {
84 sources_end_line.append(0);
85 }
86
87 const char *log_line = log, *line_end;
88
89 LogCursor previous_location;
90
91 bool found_line_id = false;
92 while ((line_end = strchr(log_line, '\n'))) {
93 /* Skip empty lines. */
94 if (line_end == log_line) {
95 log_line++;
96 continue;
97 }
98
99 /* Silence not useful lines. */
100 StringRef logref = StringRefNull(log_line).substr(0, size_t(line_end) - size_t(log_line));
101 if (logref.endswith(" shader failed to compile with the following errors:") ||
102 logref.endswith(" No code generated"))
103 {
104 log_line += size_t(line_end) - size_t(log_line);
105 continue;
106 }
107
108 GPULogItem log_item;
109 log_line = parser->parse_line(sources_combined, log_line, log_item);
110
111 /* Empty line, skip. */
112 if ((log_item.cursor.row == -1) && ELEM(log_line[0], '\n', '\0')) {
113 continue;
114 }
115
116 /* Sanitize output. Really bad values can happen when the error line is buggy. */
117 if (log_item.cursor.source >= sources.size()) {
118 log_item.cursor.source = -1;
119 }
120 if (log_item.cursor.row >= sources_end_line.last()) {
121 log_item.cursor.source = -1;
122 log_item.cursor.row = -1;
123 }
124
125 if (log_item.cursor.row == -1) {
126 found_line_id = false;
127 }
128 else if (log_item.source_base_row && log_item.cursor.source > 0) {
129 log_item.cursor.row += sources_end_line[log_item.cursor.source - 1];
130 }
131
132 const char *src_line = sources_combined;
133
134 /* Separate from previous block. */
135 if (previous_location.source != log_item.cursor.source ||
136 previous_location.row != log_item.cursor.row)
137 {
138 BLI_dynstr_appendf(dynstr, "%s%s%s\n", info_col, line_prefix, reset_col);
139 }
140 else if (log_item.cursor.column != previous_location.column) {
141 BLI_dynstr_appendf(dynstr, "%s\n", line_prefix);
142 }
143 /* Print line from the source file that is producing the error. */
144 if ((log_item.cursor.row != -1) && (log_item.cursor.row != previous_location.row ||
145 log_item.cursor.column != previous_location.column))
146 {
147 const char *src_line_end;
148 found_line_id = false;
149 /* error_line is 1 based in this case. */
150 int src_line_index = 1;
151 while ((src_line_end = strchr(src_line, '\n'))) {
152 if (src_line_index >= log_item.cursor.row) {
153 found_line_id = true;
154 break;
155 }
156 if (src_line_index >= log_item.cursor.row - DEBUG_CONTEXT_LINES) {
157 BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index);
158 BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line);
159 }
160 /* Continue to next line. */
161 src_line = src_line_end + 1;
162 src_line_index++;
163 }
164 /* Print error source. */
165 if (found_line_id) {
166 if (log_item.cursor.row != previous_location.row) {
167 BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index);
168 }
169 else {
170 BLI_dynstr_appendf(dynstr, line_prefix);
171 }
172 BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line);
173 /* Print char offset. */
174 BLI_dynstr_appendf(dynstr, line_prefix);
175 if (log_item.cursor.column != -1) {
176 for (int i = 0; i < log_item.cursor.column; i++) {
177 BLI_dynstr_appendf(dynstr, " ");
178 }
179 BLI_dynstr_appendf(dynstr, "^");
180 }
181 BLI_dynstr_appendf(dynstr, "\n");
182
183 /* Skip the error line. */
184 src_line = src_line_end + 1;
185 src_line_index++;
186 while ((src_line_end = strchr(src_line, '\n'))) {
187 if (src_line_index > log_item.cursor.row + DEBUG_CONTEXT_LINES) {
188 break;
189 }
190 BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index);
191 BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line);
192 /* Continue to next line. */
193 src_line = src_line_end + 1;
194 src_line_index++;
195 }
196 }
197 }
198 BLI_dynstr_appendf(dynstr, line_prefix);
199
200 /* Search the correct source index. */
201 int row_in_file = log_item.cursor.row;
202 int source_index = log_item.cursor.source;
203 if (source_index <= 0) {
204 for (auto i : sources_end_line.index_range()) {
205 if (log_item.cursor.row <= sources_end_line[i]) {
206 source_index = i;
207 break;
208 }
209 }
210 }
211 if (source_index > 0) {
212 row_in_file -= sources_end_line[source_index - 1];
213 }
214 /* Print the filename the error line is coming from. */
215 if (!log_item.cursor.file_name_and_error_line.is_empty()) {
216 char name_buf[256];
217 log_item.cursor.file_name_and_error_line.substr(0, sizeof(name_buf) - 1).copy(name_buf);
218 BLI_dynstr_appendf(dynstr, "%s%s: %s", info_col, name_buf, reset_col);
219 }
220 else if (source_index > 0) {
222 sources[source_index]);
223 if (!filename.is_empty()) {
224 BLI_dynstr_appendf(dynstr,
225 "%s%s:%d:%d: %s",
226 info_col,
227 filename.c_str(),
228 row_in_file,
229 log_item.cursor.column + 1,
230 reset_col);
231 }
232 }
233
234 if (log_item.severity == Severity::Error) {
235 BLI_dynstr_appendf(dynstr, "%s%s%s: ", err_col, "Error", info_col);
236 }
237 else if (log_item.severity == Severity::Warning) {
238 BLI_dynstr_appendf(dynstr, "%s%s%s: ", warn_col, "Warning", info_col);
239 }
240 else if (log_item.severity == Severity::Note) {
241 BLI_dynstr_appendf(dynstr, "%s%s%s: ", warn_col, "Note", info_col);
242 }
243 /* Print the error itself. */
244 BLI_dynstr_append(dynstr, info_col);
245 BLI_dynstr_nappend(dynstr, log_line, (line_end + 1) - log_line);
246 BLI_dynstr_append(dynstr, reset_col);
247 /* Continue to next line. */
248 log_line = line_end + 1;
249 previous_location = log_item.cursor;
250 }
251
253
254 if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= 0)) ||
255 (severity >= CLG_SEVERITY_WARN))
256 {
258 CLG_log_str(LOG.type, severity, this->name, stage, sources_combined);
259 }
260 const char *_str = BLI_dynstr_get_cstring(dynstr);
261 CLG_log_str(LOG.type, severity, this->name, stage, _str);
262 MEM_freeN((void *)_str);
263 }
264
265 MEM_freeN(sources_combined);
266 BLI_dynstr_free(dynstr);
267}
268
269const char *GPULogParser::skip_severity(const char *log_line,
270 GPULogItem &log_item,
271 const char *error_msg,
272 const char *warning_msg,
273 const char *note_msg) const
274{
275 if (STREQLEN(log_line, error_msg, strlen(error_msg))) {
276 log_line += strlen(error_msg);
277 log_item.severity = Severity::Error;
278 }
279 else if (STREQLEN(log_line, warning_msg, strlen(warning_msg))) {
280 log_line += strlen(warning_msg);
281 log_item.severity = Severity::Warning;
282 }
283 else if (STREQLEN(log_line, note_msg, strlen(note_msg))) {
284 log_line += strlen(note_msg);
285 log_item.severity = Severity::Note;
286 }
287 return log_line;
288}
289
290const char *GPULogParser::skip_separators(const char *log_line, const StringRef separators) const
291{
292 while (at_any(log_line, separators)) {
293 log_line++;
294 }
295 return log_line;
296}
297
298const char *GPULogParser::skip_until(const char *log_line, char stop_char) const
299{
300 const char *cursor = log_line;
301 while (!ELEM(cursor[0], '\n', '\0')) {
302 if (cursor[0] == stop_char) {
303 return cursor;
304 }
305 cursor++;
306 }
307 return log_line;
308}
309
310bool GPULogParser::at_number(const char *log_line) const
311{
312 return log_line[0] >= '0' && log_line[0] <= '9';
313}
314
315bool GPULogParser::at_any(const char *log_line, const StringRef chars) const
316{
317 return chars.find(log_line[0]) != StringRef::not_found;
318}
319
320int GPULogParser::parse_number(const char *log_line, const char **r_new_position) const
321{
322 return int(strtol(log_line, const_cast<char **>(r_new_position), 10));
323}
324
327/* -------------------------------------------------------------------- */
332{
333 if (ctx == nullptr) {
334 return;
335 }
337 return;
338 }
339 BLI_assert(ctx->printf_buf == nullptr);
342}
343
345{
346 if (ctx == nullptr) {
347 return;
348 }
349 if (ctx->printf_buf == nullptr) {
350 return;
351 }
352
354 GPU_storagebuf_read(ctx->printf_buf, data.data());
356 ctx->printf_buf = nullptr;
357
358 uint32_t data_len = data[0];
359 if (data_len == 0) {
360 return;
361 }
362 if (data_len >= GPU_SHADER_PRINTF_MAX_CAPACITY) {
363 printf("Printf buffer overflow.\n");
364 /* TODO(fclem): We can still read the uncorrupted part. */
365 return;
366 }
367
368 int cursor = 1;
369 while (cursor < data_len + 1) {
370 uint32_t format_hash = data[cursor++];
371
373 format_hash);
374
375 for (const shader::PrintfFormat::Block &block : format.format_blocks) {
376 switch (block.type) {
378 printf("%s", block.fmt.c_str());
379 break;
381 printf(block.fmt.c_str(), *reinterpret_cast<uint32_t *>(&data[cursor++]));
382 break;
384 printf(block.fmt.c_str(), *reinterpret_cast<int32_t *>(&data[cursor++]));
385 break;
387 printf(block.fmt.c_str(), *reinterpret_cast<float *>(&data[cursor++]));
388 break;
389 default:
391 break;
392 }
393 }
394 }
395}
396
399} // namespace blender::gpu
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
A dynamically sized string ADT.
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition BLI_dynstr.c:149
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL()
Definition BLI_dynstr.c:81
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:37
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition BLI_dynstr.c:174
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition BLI_dynstr.c:62
char * BLI_string_join_arrayN(const char *strings[], uint strings_num) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define STREQLEN(a, b, n)
#define ELEM(...)
void CLG_log_str(const CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn, const char *message) _CLOG_ATTR_NONNULL(1
CLG_Severity
Definition CLG_log.h:87
@ CLG_SEVERITY_WARN
Definition CLG_log.h:89
@ CLG_SEVERITY_ERROR
Definition CLG_log.h:90
@ CLG_FLAG_USE
Definition CLG_log.h:84
int CLG_color_support_get(CLG_LogRef *clg_ref)
Definition clog.c:790
void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo)
void GPU_storagebuf_free(GPUStorageBuf *ssbo)
void GPU_storagebuf_read(GPUStorageBuf *ssbo, void *data)
#define GPU_storagebuf_create(size)
Read Guarded memory(de)allocation.
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
static constexpr int64_t not_found
constexpr int64_t find(char c, int64_t pos=0) const
constexpr bool is_empty() const
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr bool endswith(StringRef suffix) const
constexpr const char * c_str() const
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
IndexRange index_range() const
int parse_number(const char *log_line, const char **r_new_position) const
const char * skip_separators(const char *log_line, const StringRef separators) const
bool at_number(const char *log_line) const
bool at_any(const char *log_line, const StringRef chars) const
virtual const char * parse_line(const char *source_combined, const char *log_line, GPULogItem &log_item)=0
const char * skip_until(const char *log_line, char stop_char) const
const char * skip_severity(const char *log_line, GPULogItem &log_item, const char *error_msg, const char *warning_msg, const char *note_msg) const
void print_log(Span< const char * > sources, const char *log, const char *stage, bool error, GPULogParser *parser)
#define printf
EvaluationStage stage
Definition deg_eval.cc:83
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define GPU_SHADER_PRINTF_MAX_CAPACITY
#define DEBUG_CONTEXT_LINES
static CLG_LogRef LOG
#define DEBUG_LOG_SHADER_SRC_ON_ERROR
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float3 log(float3 v)
static void error(const char *str)
StringRefNull gpu_shader_dependency_get_filename_from_source_string(const StringRefNull source_string)
Find the name of the file from which the given string was generated.
const PrintfFormat & gpu_shader_dependency_get_printf_format(uint32_t format_hash)
bool gpu_shader_dependency_has_printf()
static CLG_LogRef LOG
void printf_begin(Context *ctx)
void printf_end(Context *ctx)
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
signed int int32_t
Definition stdint.h:77
CLG_LogType * type
Definition CLG_log.h:108
enum CLG_LogFlag flag
Definition CLG_log.h:103