From 9839535691005f6637ab28be79714058860e153a Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Wed, 11 Mar 2026 15:13:08 -0400 Subject: [PATCH 1/3] render/gles2: scissor region on render pass The scissor step in the rendering has been drop when moving from the legacy rendering API to the current render pass API. Clipping on the CPU allows smaller draws, which can improve both GPU and IO bandwidth on tiled renderer GPUs like on the Raspberry PI. --- render/gles2/pass.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/render/gles2/pass.c b/render/gles2/pass.c index a70ea1320..cce989a5e 100644 --- a/render/gles2/pass.c +++ b/render/gles2/pass.c @@ -90,6 +90,10 @@ static void render(const struct wlr_box *box, const pixman_region32_t *clip, GLi return; } + glEnable(GL_SCISSOR_TEST); + glScissor(region.extents.x1, region.extents.y1, region.extents.x2 - region.extents.x1, + region.extents.y2 - region.extents.y1); + glEnableVertexAttribArray(attrib); for (int i = 0; i < rects_len;) { @@ -120,6 +124,7 @@ static void render(const struct wlr_box *box, const pixman_region32_t *clip, GLi } glDisableVertexAttribArray(attrib); + glDisable(GL_SCISSOR_TEST); pixman_region32_fini(®ion); } From a5c87484c2e3d94a0d373e5e78bb473d61fc2152 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 7 Apr 2026 10:24:00 -0400 Subject: [PATCH 2/3] render/gles2: remove error log when timer isnt ready This line was spamming the log when trying to retrieve a timer in a loop until ready. --- render/gles2/renderer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 7f01b8acd..f1740dcf1 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -326,7 +326,6 @@ static int gles2_get_render_time(struct wlr_render_timer *wlr_timer) { renderer->procs.glGetQueryObjectivEXT(timer->id, GL_QUERY_RESULT_AVAILABLE_EXT, &available); if (!available) { - wlr_log(WLR_ERROR, "timer was read too early, gpu isn't done!"); wlr_egl_restore_context(&prev_ctx); return -1; } From 2a3b42d4a4ae4564eee3d2df4b5f7642ee5c4efb Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Thu, 12 Mar 2026 11:41:34 -0400 Subject: [PATCH 3/3] test: add render pass benchmark This file is based on https://ozal.ski/bench.c which was previously use to provide benchmarks when we moved from the legacy rendering API to the current render pass architecture. --- test/bench_render_pass.c | 94 ++++++++++++++++++++++++++++++++++++++++ test/meson.build | 6 +++ 2 files changed, 100 insertions(+) create mode 100644 test/bench_render_pass.c diff --git a/test/bench_render_pass.c b/test/bench_render_pass.c new file mode 100644 index 000000000..7f9a92518 --- /dev/null +++ b/test/bench_render_pass.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + struct wl_event_loop *ev = wl_event_loop_create(); + assert(ev); + + wlr_log_init(WLR_INFO, NULL); + + struct wlr_backend *backend = wlr_headless_backend_create(ev); + assert(backend); + + struct wlr_renderer *renderer = wlr_renderer_autocreate(backend); + assert(renderer); + + struct wlr_allocator *allocator = wlr_allocator_autocreate(backend, renderer); + assert(allocator); + + const struct wlr_drm_format_set *formats = wlr_renderer_get_texture_formats(renderer, + allocator->buffer_caps); + + // TODO: swapchain size from argument + // TODO: swapchain format from argument? + struct wlr_swapchain *swapchain = wlr_swapchain_create(allocator, 1920, 1080, + wlr_drm_format_set_get(formats, DRM_FORMAT_ARGB8888)); + assert(swapchain); + + const int iters = 16; + for (int i = 1; i <= iters; ++i) { + pixman_region32_t clip; + pixman_region32_init(&clip); + + for (int ii = 0; ii < i * 10; ++ii) { + pixman_region32_union_rect(&clip, &clip, 0, ii, ii, 1); + } + + struct wlr_render_timer *timer = wlr_render_timer_create(renderer); + assert(timer); + + const struct wlr_buffer_pass_options options = { + .timer = timer, + }; + + struct wlr_buffer *buffer = wlr_swapchain_acquire(swapchain); + assert(buffer); + + struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, buffer, &options); + + struct wlr_render_rect_options data = { + .box = { + .x = 0, .y = 0, + .width = i * 10, .height = i * 10, + }, + .clip = &clip, + .color = { .r = 1, .g = 0.5, .b = 0.1, .a = 0.5 }, + }; + + const int rects = 1 << i; + + for (int j = 0; j < rects; ++j) { + wlr_render_pass_add_rect(pass, &data); + } + + wlr_render_pass_submit(pass); + + wlr_buffer_unlock(buffer); + + int duration = -1; + while ((duration = wlr_render_timer_get_duration_ns(timer)) == -1); + + wlr_log(WLR_INFO, "wlr_render_pass iteration %d/%d (%d rects): %d ns", i, iters, rects, + duration); + + wlr_render_timer_destroy(timer); + + pixman_region32_fini(&clip); + } + + wlr_swapchain_destroy(swapchain); + wlr_allocator_destroy(allocator); + wlr_renderer_destroy(renderer); + wlr_backend_destroy(backend); + + wl_event_loop_destroy(ev); + + return 0; +} diff --git a/test/meson.build b/test/meson.build index f51b2c02c..bae6ceb81 100644 --- a/test/meson.build +++ b/test/meson.build @@ -8,3 +8,9 @@ benchmark( executable('bench-scene', 'bench_scene.c', dependencies: wlroots), timeout: 30, ) + +benchmark( + 'render-pass', + executable('bench-render-pass', 'bench_render_pass.c', dependencies: wlroots), + timeout: 30, +)