From 414e85c22d288d35d3b39fd36a189b26035a78de Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Wed, 11 Mar 2026 21:53:26 +0200 Subject: [PATCH 1/6] renderer-gl: Be consistent with Perfetto regarding GPU activity Rename 'timeline' to 'activity' and 'elapsed' to 'active'. Feels like this it would more familiar to people when analysing traces and uses the Perfetto naming for consistency. Otherwise I'd rename 'activity' to 'timeline' for Perfetto track names. Signed-off-by: Marius Vlad --- libweston/renderer-gl/gl-renderer.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 50bc4c142..9173060a6 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -730,13 +730,11 @@ timeline_render_point_handler(int fd, uint32_t mask, void *data) TLP_GPU(&end), TLP_OUTPUT(trp->output), TLP_END); weston_log_scope_printf(gr->paint_node_scope, - "\tGPU Timeline:\n\t\tbegin: %" PRId64 ".%09ld" - " - end: %" PRId64 ".%09ld - elapsed: %.2f us\n", + "\tGPU activity:\n\t\tbegin: %" PRId64 ".%09ld" + " - end: %" PRId64 ".%09ld - active: %.2f us\n", (int64_t) begin.tv_sec, begin.tv_nsec, (int64_t) end.tv_sec, end.tv_nsec, (float) (elapsed / 1000.0f)); - - } timeline_render_point_destroy(trp); From 940a2b03d94cfe5faf84070d8e737fbaa676a3f5 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 28 Apr 2026 09:41:57 +0300 Subject: [PATCH 2/6] libweston: Introduce Perfetto debug annotations Introduce a bunch of helper macros and flush function that allow in-situ debug annotation of Perfetto tracks. This introduces a STR, INT and FLOAT variants to stack debug annotations into a temporary array and have COMMIT to push that to Perfetto. There's a maximum imposed limit of 128 entries in the array. Users shouldn't be concerned with allocating char string arrays as COMMIT will basically flush all the data in the temporary array to Perfetto. Signed-off-by: Marius Vlad --- libweston/perfetto/u_perfetto.cc | 77 +++++++++++++++++ libweston/perfetto/u_perfetto.h | 46 +++++++++++ libweston/weston-trace.h | 137 +++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) diff --git a/libweston/perfetto/u_perfetto.cc b/libweston/perfetto/u_perfetto.cc index 9d0a2eb99..b7a96fd2a 100644 --- a/libweston/perfetto/u_perfetto.cc +++ b/libweston/perfetto/u_perfetto.cc @@ -151,6 +151,83 @@ util_perfetto_next_id(void) return p_atomic_inc_return(&util_perfetto_unique_id); } +static void +util_perfetto_flush_debug_annotation(perfetto::EventContext *ctx, + unsigned int nr_entries, + struct weston_debug_annotation *annots) +{ + if (nr_entries == 0) + return; + + for (unsigned int idx = 0; idx < nr_entries; idx++) { + switch (annots[idx].type) { + case WESTON_DEBUG_ANNOTATION_INT_VAL: + ctx->AddDebugAnnotation(annots[idx].key, annots[idx].ivalue); + break; + case WESTON_DEBUG_ANNOTATION_FLOAT_VAL: + ctx->AddDebugAnnotation(annots[idx].key, annots[idx].fvalue); + break; + case WESTON_DEBUG_ANNOTATION_STR_VAL: + ctx->AddDebugAnnotation(annots[idx].key, annots[idx].svalue); + break; + default: + break; + } + } + +} + +void +util_perfetto_trace_commit_debug_annots(uint64_t id, const char *name, + unsigned int nr_entries, + struct weston_debug_annotation *annots) +{ + if (id) { + TRACE_EVENT_INSTANT(UTIL_PERFETTO_CATEGORY_DEFAULT_STR, + nullptr, + perfetto::Flow::ProcessScoped(id), + [&](perfetto::EventContext ctx) { + ctx.event()->set_name(name); + util_perfetto_flush_debug_annotation(&ctx, nr_entries, annots); + }); + return; + } + + TRACE_EVENT_INSTANT(UTIL_PERFETTO_CATEGORY_DEFAULT_STR, + nullptr, + [&](perfetto::EventContext ctx) { + ctx.event()->set_name(name); + util_perfetto_flush_debug_annotation(&ctx, nr_entries, annots); + }); +} + +void +util_perfetto_trace_commit_annotate_func(const char *name, unsigned int nr_entries, + struct weston_debug_annotation *annots) +{ + TRACE_EVENT_BEGIN(UTIL_PERFETTO_CATEGORY_DEFAULT_STR, + nullptr, + [&](perfetto::EventContext ctx) { + ctx.event()->set_name(name); + util_perfetto_flush_debug_annotation(&ctx, nr_entries, annots); + }); +} + +void +util_perfetto_trace_commit_annotate_func_flow(uint64_t id, const char *name, + unsigned int nr_entries, + struct weston_debug_annotation *annots) +{ + TRACE_EVENT_BEGIN(UTIL_PERFETTO_CATEGORY_DEFAULT_STR, + nullptr, + perfetto::Flow::ProcessScoped(id), + [&](perfetto::EventContext ctx) { + ctx.event()->set_name(name); + util_perfetto_flush_debug_annotation(&ctx, nr_entries, annots); + }); +} + + class UtilPerfettoObserver : public perfetto::TrackEventSessionObserver { public: UtilPerfettoObserver() { perfetto::TrackEvent::AddSessionObserver(this); } diff --git a/libweston/perfetto/u_perfetto.h b/libweston/perfetto/u_perfetto.h index 576348fce..4c84b7250 100644 --- a/libweston/perfetto/u_perfetto.h +++ b/libweston/perfetto/u_perfetto.h @@ -39,6 +39,22 @@ extern "C" { #endif +enum weston_debug_annotation_type { + WESTON_DEBUG_ANNOTATION_INT_VAL, + WESTON_DEBUG_ANNOTATION_FLOAT_VAL, + WESTON_DEBUG_ANNOTATION_STR_VAL, +}; + +struct weston_debug_annotation { + const char *key; + enum weston_debug_annotation_type type; + union { + int ivalue; + float fvalue; + const char *svalue; + }; +}; + #ifdef HAVE_PERFETTO extern int util_perfetto_tracing_state; @@ -63,6 +79,15 @@ void util_perfetto_trace_full_begin(const char *name, uint64_t track_id, uint64_ void util_perfetto_trace_full_end(const char *name, uint64_t track_id, clockid_t clock, uint64_t timestamp); +void util_perfetto_trace_commit_debug_annots(uint64_t id, const char *name, + unsigned int entries, struct weston_debug_annotation *annots); + +void util_perfetto_trace_commit_annotate_func(const char *name, + unsigned int entries, struct weston_debug_annotation *annots); + +void util_perfetto_trace_commit_annotate_func_flow(uint64_t id, const char *name, + unsigned int entries, struct weston_debug_annotation *annots); + uint64_t util_perfetto_next_id(void); uint64_t util_perfetto_new_track(const char *name); @@ -104,6 +129,27 @@ util_perfetto_trace_full_end(const char *name, uint64_t track_id, clockid_t cloc { } +static inline void +util_perfetto_trace_commit_debug_annots(uint64_t id, const char *name, + unsigned int entries, + struct weston_debug_annotation *annots) +{ +} + +static inline void +util_perfetto_trace_commit_annotate_func(const char *name, + unsigned int entries, + struct weston_debug_annotation *annots) +{ +} + +static inline void +util_perfetto_trace_commit_annotate_func_flow(uint64_t id, const char *name, + unsigned int entries, + struct weston_debug_annotation *annots) +{ +} + static inline void util_perfetto_counter_set(const char *name, double value) { } diff --git a/libweston/weston-trace.h b/libweston/weston-trace.h index 154663157..b2ba55492 100644 --- a/libweston/weston-trace.h +++ b/libweston/weston-trace.h @@ -11,6 +11,7 @@ #define WESTON_TRACE_H #include "perfetto/u_perfetto.h" +#include #if defined(HAVE_PERFETTO) @@ -28,6 +29,9 @@ # endif #endif +/* maximum allowed debug annotations */ +#define WESTON_MAX_DEBUG_ANNOTS 128 + /* note that util_perfetto_is_tracing_enabled always returns false until * util_perfetto_init is called */ @@ -69,6 +73,53 @@ clock, timestamp); \ } while (0) +#define _WESTON_TRACE_BEGIN_ANNOTATION() \ + struct weston_debug_annotation __pd_annots[WESTON_MAX_DEBUG_ANNOTS]; \ + unsigned int __pd_i = 0 + +#define _WESTON_TRACE_ANNOTATE_ADD_INT(k, v) \ + weston_assert_u32_gt(NULL, WESTON_MAX_DEBUG_ANNOTS, __pd_i); \ + __pd_annots[__pd_i].type = WESTON_DEBUG_ANNOTATION_INT_VAL; \ + __pd_annots[__pd_i].ivalue = v; \ + __pd_annots[__pd_i].key = k; \ + __pd_i++ + +#define _WESTON_TRACE_ANNOTATE_ADD_FLOAT(k, v) \ + weston_assert_u32_gt(NULL, WESTON_MAX_DEBUG_ANNOTS, __pd_i); \ + __pd_annots[__pd_i].type = WESTON_DEBUG_ANNOTATION_FLOAT_VAL; \ + __pd_annots[__pd_i].fvalue = v; \ + __pd_annots[__pd_i].key = k; \ + __pd_i++ + +#define _WESTON_TRACE_ANNOTATE_ADD_STR(k, v) \ + weston_assert_u32_gt(NULL, WESTON_MAX_DEBUG_ANNOTS, __pd_i); \ + __pd_annots[__pd_i].type = WESTON_DEBUG_ANNOTATION_STR_VAL; \ + __pd_annots[__pd_i].svalue = v; \ + __pd_annots[__pd_i].key = k; \ + __pd_i++ + +#define _WESTON_TRACE_COMMIT_ANNOTATION(id, name) \ + do { \ + if (unlikely(util_perfetto_is_tracing_enabled())) { \ + _weston_trace_scope_annotate_commit(id, name, &__pd_i, __pd_annots); \ + } \ + } while (0) + +/* annotated funcs */ +#define _WESTON_TRACE_ANNOTATE_FUNC_BEGIN(name, nr_entries, annots) \ + do { \ + if (unlikely(util_perfetto_is_tracing_enabled())) { \ + util_perfetto_trace_commit_annotate_func(name, *nr_entries, annots); \ + } \ + } while (0) + +#define _WESTON_TRACE_ANNOTATE_FUNC_BEGIN_FLOW(name, id, nr_entries, annots) \ + do { \ + if (unlikely(util_perfetto_is_tracing_enabled())) { \ + util_perfetto_trace_commit_annotate_func_flow(id, name, *nr_entries, annots); \ + } \ + } while (0) + #if __has_attribute(cleanup) && __has_attribute(unused) #define _WESTON_TRACE_SCOPE_VAR_CONCAT(name, suffix) name##suffix @@ -92,6 +143,16 @@ __attribute__((cleanup(_weston_trace_scope_end), unused)) = \ _weston_trace_scope_flow_begin(name, id) +#define _WESTON_TRACE_ANNOTATE_FUNC(name) \ + int _WESTON_TRACE_SCOPE_VAR(__LINE__) \ + __attribute__((cleanup(_weston_trace_scope_end), unused)) = \ + _weston_trace_annotate_func_begin(name, &__pd_i, __pd_annots) + +#define _WESTON_TRACE_ANNOTATE_FUNC_FLOW(id, name) \ + int _WESTON_TRACE_SCOPE_VAR(__LINE__) \ + __attribute__((cleanup(_weston_trace_scope_end), unused)) = \ + _weston_trace_annotate_func_begin_flow(name, id, &__pd_i, __pd_annots) + static inline int _weston_trace_scope_begin(const char *name) { @@ -108,6 +169,53 @@ _weston_trace_scope_flow_begin(const char *name, uint64_t *id) return 0; } +static inline void +_weston_trace_scope_annotate_commit(uint64_t *id, const char *name, + unsigned int *nr_entries, + struct weston_debug_annotation *annots) +{ + if (id && *id == 0) { + *id = util_perfetto_next_id(); + util_perfetto_trace_commit_debug_annots(*id, name, *nr_entries, annots); + goto reset_entries; + } + + util_perfetto_trace_commit_debug_annots(0, name, *nr_entries, annots); + + /* reset the array and counter */ +reset_entries: + memset(annots, 0, sizeof(struct weston_debug_annotation) * *nr_entries); + *nr_entries = 0; +} + +static inline int +_weston_trace_annotate_func_begin(const char *name, unsigned int *nr_entries, + struct weston_debug_annotation *annots) +{ + _WESTON_TRACE_ANNOTATE_FUNC_BEGIN(name, nr_entries, annots); + + /* reset the array and counter */ + memset(annots, 0, sizeof(struct weston_debug_annotation) * *nr_entries); + *nr_entries = 0; + return 0; +} + +static inline int +_weston_trace_annotate_func_begin_flow(const char *name, uint64_t *id, + unsigned int *nr_entries, + struct weston_debug_annotation *annots) +{ + if (*id == 0) + *id = util_perfetto_next_id(); + + _WESTON_TRACE_ANNOTATE_FUNC_BEGIN_FLOW(name, *id, nr_entries, annots); + + /* reset the array and counter */ + memset(annots, 0, sizeof(struct weston_debug_annotation) * *nr_entries); + *nr_entries = 0; + return 0; +} + static inline void _weston_trace_scope_end(int *scope) { @@ -130,6 +238,14 @@ _weston_trace_scope_end(int *scope) #define _WESTON_TRACE_TIMESTAMP_BEGIN(name, track_id, flow_id, clock, timestamp) #define _WESTON_TRACE_TIMESTAMP_END(name, track_id, clock, timestamp) +#define _WESTON_TRACE_BEGIN_ANNOTATION() +#define _WESTON_TRACE_COMMIT_ANNOTATION(id, name) +#define _WESTON_TRACE_ANNOTATE_ADD_INT(k, v) +#define _WESTON_TRACE_ANNOTATE_ADD_FLOAT(k, v) +#define _WESTON_TRACE_ANNOTATE_ADD_STR(k, v) +#define _WESTON_TRACE_ANNOTATE_FUNC() +#define _WESTON_TRACE_ANNOTATE_FUNC_FLOW(id, name) + #endif /* HAVE_PERFETTO */ #define WESTON_TRACE_SCOPE(name) _WESTON_TRACE_SCOPE(name) @@ -142,4 +258,25 @@ _weston_trace_scope_end(int *scope) #define WESTON_TRACE_TIMESTAMP_END(name, track_id, clock, timestamp) \ _WESTON_TRACE_TIMESTAMP_END(name, track_id, clock, timestamp) +#define WESTON_TRACE_BEGIN_ANNOTATION() \ + _WESTON_TRACE_BEGIN_ANNOTATION() + +#define WESTON_TRACE_ANNOTATE_ADD_INT(k, v) \ + _WESTON_TRACE_ANNOTATE_ADD_INT(k, v) + +#define WESTON_TRACE_ANNOTATE_ADD_FLOAT(k, v) \ + _WESTON_TRACE_ANNOTATE_ADD_FLOAT(k, v) + +#define WESTON_TRACE_ANNOTATE_ADD_STR(k, v) \ + _WESTON_TRACE_ANNOTATE_ADD_STR(k, v) + +#define WESTON_TRACE_COMMIT_ANNOTATION(id) \ + _WESTON_TRACE_COMMIT_ANNOTATION(id, __func__) + +#define WESTON_TRACE_ANNOTATE_FUNC() \ + _WESTON_TRACE_ANNOTATE_FUNC(__func__) + +#define WESTON_TRACE_ANNOTATE_FUNC_FLOW(id) \ + _WESTON_TRACE_ANNOTATE_FUNC_FLOW(id, __func__) + #endif /* WESTON_TRACE_H */ From 64ef093397fc5138508c28e669ed7f3a2512c41b Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 10 Mar 2026 23:36:24 +0200 Subject: [PATCH 3/6] libweston: Add Perfetto debug annotation for buffer info This adds annotation at surface attach time. Signed-off-by: Marius Vlad --- libweston/surface-state.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libweston/surface-state.c b/libweston/surface-state.c index 59643dc76..1513655d4 100644 --- a/libweston/surface-state.c +++ b/libweston/surface-state.c @@ -200,11 +200,20 @@ weston_surface_attach(struct weston_surface *surface, struct weston_surface_state *state, enum weston_surface_status status) { - WESTON_TRACE_FUNC_FLOW(&surface->flow_id); struct weston_buffer *buffer = state->buffer_ref.buffer; struct weston_buffer *old_buffer = surface->buffer_ref.buffer; enum weston_paint_node_status pnode_changes = WESTON_PAINT_NODE_CLEAN; + WESTON_TRACE_BEGIN_ANNOTATION(); + if (buffer) { + WESTON_TRACE_ANNOTATE_ADD_STR("surface", surface->internal_name); + WESTON_TRACE_ANNOTATE_ADD_STR("format", buffer->pixel_format->drm_format_name); + WESTON_TRACE_ANNOTATE_ADD_STR("modifier", buffer->format_modifier_name); + WESTON_TRACE_ANNOTATE_ADD_INT("width", buffer->width); + WESTON_TRACE_ANNOTATE_ADD_INT("height", buffer->height); + } + WESTON_TRACE_ANNOTATE_FUNC_FLOW(&surface->flow_id); + if (!buffer) { if (weston_surface_is_mapped(surface)) { weston_surface_unmap(surface); From 9a708994d5de091999586f676b7efa09bab11931 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 28 Apr 2026 14:02:23 +0300 Subject: [PATCH 4/6] renderer-gl: Don't compute rects if log scope is not enabled Signed-off-by: Marius Vlad --- libweston/renderer-gl/gl-renderer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 9173060a6..f986e5904 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -419,12 +419,12 @@ gl_log_paint_node_bbox_and_region(struct gl_renderer *gr, const char *str, int32_t box_x, box_y; uint32_t box_width, box_height; int n_rects = 0; - const pixman_box32_t *rects = - pixman_region32_rectangles(damage, &n_rects); + const pixman_box32_t *rects; if (!weston_log_scope_is_enabled(gr->paint_node_scope)) return; + rects = pixman_region32_rectangles(damage, &n_rects); box = pixman_region32_extents(damage); box_x = box->x1; From b43cc0a5d48205f383ca33b7523572620bea7a31 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 28 Apr 2026 15:46:27 +0300 Subject: [PATCH 5/6] renderer-gl: Add Perfetto debug annotations This adds Perfetto debug annotations for printing and paint (damage, blended, opaque) regions. Signed-off-by: Marius Vlad --- libweston/renderer-gl/gl-renderer.c | 87 +++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 17 deletions(-) diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index f986e5904..e4e2de61a 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -58,6 +58,7 @@ #include "linux-explicit-synchronization.h" #include "output-capture.h" #include "pixel-formats.h" +#include "weston-trace.h" #include "shared/fd-util.h" #include "shared/helpers.h" @@ -412,8 +413,8 @@ gl_log_paint_node_start(struct gl_renderer *gr, struct weston_paint_node *pnode) } static void -gl_log_paint_node_bbox_and_region(struct gl_renderer *gr, const char *str, - pixman_region32_t *damage) +gl_log_paint_node_bbox_and_region(struct gl_renderer *gr, struct weston_paint_node *pnode, + const char *str, pixman_region32_t *damage) { pixman_box32_t *box; int32_t box_x, box_y; @@ -421,7 +422,8 @@ gl_log_paint_node_bbox_and_region(struct gl_renderer *gr, const char *str, int n_rects = 0; const pixman_box32_t *rects; - if (!weston_log_scope_is_enabled(gr->paint_node_scope)) + if (!weston_log_scope_is_enabled(gr->paint_node_scope) && + !util_perfetto_is_tracing_enabled()) return; rects = pixman_region32_rectangles(damage, &n_rects); @@ -432,6 +434,20 @@ gl_log_paint_node_bbox_and_region(struct gl_renderer *gr, const char *str, box_width = box->x2 - box->x1; box_height = box->y2 - box->y1; + WESTON_TRACE_BEGIN_ANNOTATION(); + + WESTON_TRACE_ANNOTATE_ADD_STR("paint node", pnode->internal_name); + WESTON_TRACE_ANNOTATE_ADD_STR("type", str); + WESTON_TRACE_ANNOTATE_ADD_INT("x", box_x); + WESTON_TRACE_ANNOTATE_ADD_INT("y", box_y); + WESTON_TRACE_ANNOTATE_ADD_INT("box_width", box_width); + WESTON_TRACE_ANNOTATE_ADD_INT("box_height", box_height); + + WESTON_TRACE_COMMIT_ANNOTATION(&pnode->flow_id); + + if (!weston_log_scope_is_enabled(gr->paint_node_scope)) + return; + weston_log_scope_printf(gr->paint_node_scope, "\t\t%s bounding box: ", str); weston_log_scope_printf(gr->paint_node_scope, "x: %5d, y: %5d, width: " "%d, height: %d\n", box_x, box_y, box_width, box_height); @@ -2338,19 +2354,30 @@ set_debug_mode(struct gl_renderer *gr, } static void -set_blend_state(struct gl_renderer *gr, - bool state) +set_blend_state(struct gl_renderer *gr, struct weston_paint_node *pnode, bool state) { if (gr->blend_state == state) return; + WESTON_TRACE_BEGIN_ANNOTATION(); + if (state) { glEnable(GL_BLEND); gl_log_paint_node(gr, "\t\tblending enabled\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("blending", "enabled"); } else { glDisable(GL_BLEND); gl_log_paint_node(gr, "\t\tblending disabled\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("blending", "disabled"); } + + if (pnode) { + WESTON_TRACE_ANNOTATE_ADD_STR("paint node", pnode->internal_name); + WESTON_TRACE_COMMIT_ANNOTATION(&pnode->flow_id); + } else { + WESTON_TRACE_COMMIT_ANNOTATION(NULL); + } + gr->blend_state = state; } @@ -2371,7 +2398,7 @@ draw_mesh(struct gl_renderer *gr, assert(nidx > 0); - set_blend_state(gr, (!opaque || pnode->view_alpha < 1.0) && !go->shader_blender); + set_blend_state(gr, pnode, (!opaque || pnode->view_alpha < 1.0) && !go->shader_blender); /* Prevent translucent surfaces from punching holes through the * renderbuffer. */ @@ -2499,7 +2526,7 @@ weston_output_cvd_type_to_str(struct weston_cvd_correction cvd) } static void -apply_color_effect(struct gl_renderer *gr, struct weston_output *output, +apply_color_effect(struct gl_renderer *gr, struct weston_paint_node *pnode, struct weston_output *output, float *r, float *g, float *b, const float a) { struct weston_compositor *compositor = output->compositor; @@ -2516,6 +2543,11 @@ apply_color_effect(struct gl_renderer *gr, struct weston_output *output, if (!output->color_effect || a == 0.0f) { return; } + + WESTON_TRACE_FUNC_FLOW(&pnode->flow_id); + WESTON_TRACE_BEGIN_ANNOTATION(); + WESTON_TRACE_ANNOTATE_ADD_STR("paint node", pnode->internal_name); + weston_assert_f32_eq(compositor, a, 1.0f); switch (effect->type) { @@ -2524,12 +2556,16 @@ apply_color_effect(struct gl_renderer *gr, struct weston_output *output, *g = 1.0f - *g; *b = 1.0f - *b; gl_log_paint_node(gr, "\t\tcolor effect: inversion\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("color effect", "inversion"); + WESTON_TRACE_COMMIT_ANNOTATION(&pnode->flow_id); return; case WESTON_OUTPUT_COLOR_EFFECT_TYPE_GRAYSCALE: *r = 0.2126f * (*r) + 0.7152f * (*g) + 0.0722f * (*b); *g = *r; *b = *r; gl_log_paint_node(gr, "\t\tcolor effect: grayscale\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("color effect", "greyscale"); + WESTON_TRACE_COMMIT_ANNOTATION(&pnode->flow_id); return; case WESTON_OUTPUT_COLOR_EFFECT_TYPE_CVD_CORRECTION: /** @@ -2543,8 +2579,12 @@ apply_color_effect(struct gl_renderer *gr, struct weston_output *output, weston_log_scope_printf(gr->paint_node_scope, "\t\tcolor effect: cvd - %s\n", weston_output_cvd_type_to_str(effect->u.cvd)); + WESTON_TRACE_ANNOTATE_ADD_STR("color effect", + weston_output_cvd_type_to_str(effect->u.cvd)); + WESTON_TRACE_COMMIT_ANNOTATION(&pnode->flow_id); return; }; + weston_assert_not_reached(compositor, "unknown color effect type"); } @@ -2566,13 +2606,13 @@ clear_region(struct gl_renderer *gr, struct weston_paint_node *pnode, /* We must be either fully transparent - punching a hole for an * underlay - or fully opaque, to use clear rather than blending. */ assert(pnode->solid.a == 0.0f || pnode->solid.a == 1.0f); - set_blend_state(gr, false); + set_blend_state(gr, pnode, false); r = pnode->solid.r; g = pnode->solid.g; b = pnode->solid.b; a = pnode->solid.a; - apply_color_effect(gr, output, &r, &g, &b, a); + apply_color_effect(gr, pnode, output, &r, &g, &b, a); glClearColor(r, g, b, a); glEnable(GL_SCISSOR_TEST); @@ -2589,6 +2629,7 @@ static void draw_paint_node(struct weston_paint_node *pnode, pixman_region32_t *damage /* in global coordinates */) { + WESTON_TRACE_FUNC_FLOW(&pnode->flow_id); struct gl_renderer *gr = get_renderer(pnode->surface->compositor); struct gl_surface_state *gs = get_surface_state(pnode->surface); /* repaint bounding region in global coordinates: */ @@ -2600,20 +2641,27 @@ draw_paint_node(struct weston_paint_node *pnode, struct gl_shader_config sconf; struct clipper_quad *quads = NULL; int nquads; + WESTON_TRACE_BEGIN_ANNOTATION(); pixman_region32_init(&repaint); pixman_region32_intersect(&repaint, &pnode->visible, damage); + WESTON_TRACE_ANNOTATE_ADD_STR("paint node", pnode->internal_name); + WESTON_TRACE_ANNOTATE_ADD_STR("label", pnode->surface->label); + WESTON_TRACE_ANNOTATE_ADD_INT("surface id", pnode->surface->s_id); + gl_log_paint_node_start(gr, pnode); if (!pixman_region32_not_empty(&repaint)) { gl_log_paint_node(gr, "\t\tskipped repaint: repaint region empty\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("skipped repaint", "repaint region empty"); goto out; } if (pnode->is_fully_transparent) { gl_log_paint_node(gr, "\t\tskipped repaint: paint node transparent\n"); gs->used_in_output_repaint = true; /* sort of */ + WESTON_TRACE_ANNOTATE_ADD_STR("skipped repaint", "paint node transparent"); goto out; } @@ -2621,18 +2669,21 @@ draw_paint_node(struct weston_paint_node *pnode, pnode->valid_transform && (pnode->surf_xform_valid && !pnode->surf_xform.transform)) { gl_log_paint_node(gr, "\t\toptimize: using glClear\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("optimization", "using glClear"); clear_region(gr, pnode, &repaint); gs->used_in_output_repaint = true; goto out; } if (ensure_surface_buffer_is_ready(gr, gs, pnode) < 0) { - gl_log_paint_node(gr, "\t\tskip repaint: buffer not ready\n"); + gl_log_paint_node(gr, "\t\tskipped repaint: buffer not ready\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("skipped repaint", "buffer not ready"); goto out; } if (!gl_shader_config_init_for_paint_node(&sconf, pnode)) { - gl_log_paint_node(gr, "\t\tskip repaint: shader config failure\n"); + gl_log_paint_node(gr, "\t\tskipped repaint: shader config failure\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("skipped repaint", "shader config failure"); goto out; } @@ -2659,18 +2710,18 @@ draw_paint_node(struct weston_paint_node *pnode, pixman_region32_subtract(&surface_blend, &surface_blend, &surface_opaque); - gl_log_paint_node_bbox_and_region(gr, "repaint region", &repaint); + gl_log_paint_node_bbox_and_region(gr, pnode, "repaint region", &repaint); transform_damage(pnode, &repaint, &quads, &nquads); if (pixman_region32_not_empty(&surface_opaque)) { - gl_log_paint_node_bbox_and_region(gr, "opaque region", &surface_opaque); + gl_log_paint_node_bbox_and_region(gr, pnode, "opaque region", &surface_opaque); repaint_region(gr, pnode, quads, nquads, &surface_opaque, &sconf, true); gs->used_in_output_repaint = true; } if (pixman_region32_not_empty(&surface_blend)) { - gl_log_paint_node_bbox_and_region(gr, "blended region", &surface_blend); + gl_log_paint_node_bbox_and_region(gr, pnode, "blended region", &surface_blend); repaint_region(gr, pnode, quads, nquads, &surface_blend, &sconf, false); gs->used_in_output_repaint = true; @@ -2681,6 +2732,8 @@ draw_paint_node(struct weston_paint_node *pnode, pixman_region32_fini(&surface_blend); pixman_region32_fini(&surface_opaque); + WESTON_TRACE_COMMIT_ANNOTATION(&pnode->flow_id); + out: pixman_region32_fini(&repaint); } @@ -2950,7 +3003,7 @@ draw_output_borders(struct weston_output *output, return; } - set_blend_state(gr, false); + set_blend_state(gr, NULL, false); glViewport(0, 0, fb->width, fb->height); weston_matrix_init(&sconf.projection); @@ -3023,7 +3076,7 @@ blit_shadow_to_output(struct weston_output *output, gl_log_paint_node(gr, "\t\tdrawing shadow output\n"); gl_renderer_use_program(gr, &sconf); - set_blend_state(gr, false); + set_blend_state(gr, NULL, false); /* output_damage is in global coordinates */ pixman_region32_intersect(&translated_damage, output_damage, @@ -4504,7 +4557,7 @@ gl_renderer_surface_copy_content(struct weston_surface *surface, } glViewport(0, 0, cw, ch); - set_blend_state(gr, false); + set_blend_state(gr, NULL, false); if (buffer->buffer_origin == ORIGIN_TOP_LEFT) ARRAY_COPY(sconf.projection.M.colmaj, projmat_normal); else From f4ba4f49bbb556e8b850f4ca922c7c18de5ceb22 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 28 Apr 2026 17:40:03 +0300 Subject: [PATCH 6/6] renderer-gl: Add Perfetto debug annotations for shader configs This adds Perfetto debug annotations for printing optimizations, color vision deficiencies, alpha. Signed-off-by: Marius Vlad --- libweston/renderer-gl/gl-renderer-internal.h | 2 +- libweston/renderer-gl/gl-renderer.c | 8 ++--- libweston/renderer-gl/gl-shaders.c | 31 ++++++++++++++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h index a15574f05..87bd70132 100644 --- a/libweston/renderer-gl/gl-renderer-internal.h +++ b/libweston/renderer-gl/gl-renderer-internal.h @@ -765,7 +765,7 @@ void gl_renderer_garbage_collect_programs(struct gl_renderer *gr); bool -gl_renderer_use_program(struct gl_renderer *gr, +gl_renderer_use_program(struct gl_renderer *gr, struct weston_paint_node *pnode, const struct gl_shader_config *sconf); struct weston_log_scope * diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index e4e2de61a..5eb45f6cd 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -2414,7 +2414,7 @@ draw_mesh(struct gl_renderer *gr, set_debug_mode(gr, sconf, barycentrics, opaque); gl_log_paint_node(gr, "\t\tdrawing paint node mesh\n"); - if (!gl_renderer_use_program(gr, sconf)) + if (!gl_renderer_use_program(gr, pnode, sconf)) gl_renderer_send_shader_error(pnode); /* Use fallback shader. */ glVertexAttribPointer(SHADER_ATTRIB_LOC_POSITION, 2, GL_FLOAT, GL_FALSE, @@ -2954,7 +2954,7 @@ draw_output_border_texture(struct gl_renderer *gr, sconf->input_num = 1; gl_log_paint_node(gr, "\t\tdrawing output border texture\n"); - gl_renderer_use_program(gr, sconf); + gl_renderer_use_program(gr, NULL, sconf); GLfloat texcoord[] = { 0.0f, 0.0f, @@ -3075,7 +3075,7 @@ blit_shadow_to_output(struct weston_output *output, pixman_region32_init(&translated_damage); gl_log_paint_node(gr, "\t\tdrawing shadow output\n"); - gl_renderer_use_program(gr, &sconf); + gl_renderer_use_program(gr, NULL, &sconf); set_blend_state(gr, NULL, false); /* output_damage is in global coordinates */ @@ -4566,7 +4566,7 @@ gl_renderer_surface_copy_content(struct weston_surface *surface, WESTON_MATRIX_TRANSFORM_TRANSLATE; gl_log_paint_node(gr, "\t\tcopying surface\n"); - if (!gl_renderer_use_program(gr, &sconf)) + if (!gl_renderer_use_program(gr, NULL, &sconf)) goto use_program_error; glEnableVertexAttribArray(SHADER_ATTRIB_LOC_POSITION); diff --git a/libweston/renderer-gl/gl-shaders.c b/libweston/renderer-gl/gl-shaders.c index 02ba41c7d..8861a69b4 100644 --- a/libweston/renderer-gl/gl-shaders.c +++ b/libweston/renderer-gl/gl-shaders.c @@ -46,6 +46,7 @@ #include "shared/helpers.h" #include "shared/timespec-util.h" #include "shared/weston-assert.h" +#include "weston-trace.h" /* static const char vertex_shader[]; vertex.glsl */ #include "vertex-shader.h" @@ -843,7 +844,7 @@ gl_shader_texture_variant_get_target(enum gl_shader_texture_variant v) } static void -gl_shader_load_config(struct gl_renderer *gr, +gl_shader_load_config(struct gl_renderer *gr, struct weston_paint_node *pnode, struct gl_shader *shader, const struct gl_shader_config *sconf) { @@ -853,6 +854,11 @@ gl_shader_load_config(struct gl_renderer *gr, float swizzle_sub[4]; int i, j; + WESTON_TRACE_BEGIN_ANNOTATION(); + if (pnode) { + WESTON_TRACE_ANNOTATE_ADD_STR("paint node", pnode->internal_name); + } + glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, sconf->projection.M.colmaj); @@ -865,6 +871,10 @@ gl_shader_load_config(struct gl_renderer *gr, "\t\tcolor: r: %.2f, g: %.2f, b: %.2f, a: %.2f\n", sconf->unicolor[0], sconf->unicolor[1], sconf->unicolor[2], sconf->unicolor[3]); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("color r", sconf->unicolor[0]); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("color g", sconf->unicolor[1]); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("color b", sconf->unicolor[2]); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("color a", sconf->unicolor[3]); glUniform4fv(shader->color_uniform, 1, sconf->unicolor); } if (shader->tint_uniform != -1) { @@ -872,10 +882,15 @@ gl_shader_load_config(struct gl_renderer *gr, "\t\ttint: r: %.2f, g: %.2f, b: %.2f, a: %.2f\n", sconf->tint[0], sconf->tint[1], sconf->tint[2], sconf->tint[3]); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("tint r", sconf->tint[0]); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("tint g", sconf->tint[1]); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("tint b", sconf->tint[2]); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("tint a", sconf->tint[3]); glUniform4fv(shader->tint_uniform, 1, sconf->tint); } weston_log_scope_printf(gr->paint_node_scope, "\t\talpha: %.2f\n", sconf->view_alpha); + WESTON_TRACE_ANNOTATE_ADD_FLOAT("alpha", sconf->view_alpha); glUniform1f(shader->view_alpha_uniform, sconf->view_alpha); assert(sconf->input_num <= SHADER_INPUT_TEX_MAX); @@ -920,9 +935,11 @@ gl_shader_load_config(struct gl_renderer *gr, break; case SHADER_COLOR_EFFECT_INVERSION: weston_log_scope_printf(gr->paint_node_scope, "\t\tcolor effect: inversion\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("color effect", "inversion"); break; case SHADER_COLOR_EFFECT_GRAYSCALE: weston_log_scope_printf(gr->paint_node_scope, "\t\tcolor effect: grayscale\n"); + WESTON_TRACE_ANNOTATE_ADD_STR("color effect", "greyscale"); break; case SHADER_COLOR_EFFECT_CVD_CORRECTION: weston_assert_int_ne(gr->compositor, shader->cvd_correction_uniform, -1); @@ -931,6 +948,8 @@ gl_shader_load_config(struct gl_renderer *gr, glUniformMatrix3fv(shader->cvd_correction_uniform, 1, GL_FALSE, sconf->color_effect.cvd.correction.colmaj); + WESTON_TRACE_ANNOTATE_ADD_STR("color effect", + weston_output_cvd_type_to_str(sconf->color_effect.cvd)); break; } @@ -958,11 +977,17 @@ gl_shader_load_config(struct gl_renderer *gr, TEX_UNIT_FB_STORE_CURVE); } + if (pnode) { + WESTON_TRACE_COMMIT_ANNOTATION(&pnode->flow_id); + } else { + WESTON_TRACE_COMMIT_ANNOTATION(NULL); + } + glActiveTexture(GL_TEXTURE0); } bool -gl_renderer_use_program(struct gl_renderer *gr, +gl_renderer_use_program(struct gl_renderer *gr, struct weston_paint_node *pnode, const struct gl_shader_config *sconf) { static const GLfloat fallback_shader_color[4] = { 0.2, 0.1, 0.0, 1.0 }; @@ -1004,7 +1029,7 @@ gl_renderer_use_program(struct gl_renderer *gr, weston_log_scope_printf(gr->paint_node_scope, "\t\t\tshader id: %d\n", gr->current_shader->program); - gl_shader_load_config(gr, shader, sconf); + gl_shader_load_config(gr, pnode, shader, sconf); return true; }