From fee962af3620652e60312e446bafee3f3a2a2adc Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Fri, 13 Mar 2026 12:36:51 +0800 Subject: [PATCH] render: introduce wlr_render_texture_pass Split texture rendering out of wlr_render_pass and introduce a dedicated wlr_render_texture_pass interface. Remove the add_texture hook from wlr_render_pass_impl and route texture rendering through renderer->texture_pass instead. --- include/render/gles2.h | 8 +++++ include/render/pixman.h | 8 +++++ include/render/vulkan.h | 8 +++++ include/wlr/render/interface.h | 27 +++++++++++++-- include/wlr/render/wlr_renderer.h | 2 +- render/gles2/pass.c | 39 ++++++++++++++++++++- render/pass.c | 57 +++++++++++++++++++++++++++++-- render/pixman/pass.c | 40 +++++++++++++++++++++- render/vulkan/pass.c | 39 ++++++++++++++++++++- render/wlr_renderer.c | 1 + types/output/render.c | 1 + 11 files changed, 222 insertions(+), 8 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index d1a8b0aba..1ca875c6d 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -181,4 +181,12 @@ bool wlr_render_rect_pass_is_gles2(const struct wlr_render_rect_pass *rect_pass) struct wlr_gles2_render_rect_pass *wlr_gles2_render_rect_pass_from_pass( struct wlr_render_rect_pass *rect_pass); +struct wlr_gles2_render_texture_pass { + struct wlr_render_texture_pass base; +}; + +bool wlr_render_texture_pass_is_gles2(const struct wlr_render_texture_pass *texture_pass); +struct wlr_gles2_render_texture_pass *wlr_gles2_render_texture_pass_from_pass( + struct wlr_render_texture_pass *texture_pass); + #endif diff --git a/include/render/pixman.h b/include/render/pixman.h index 6d58ed0b6..aaf97c66f 100644 --- a/include/render/pixman.h +++ b/include/render/pixman.h @@ -69,4 +69,12 @@ bool wlr_render_rect_pass_is_pixman(const struct wlr_render_rect_pass *rect_pass struct wlr_pixman_render_rect_pass *wlr_pixman_render_rect_pass_from_pass( struct wlr_render_rect_pass *rect_pass); +struct wlr_pixman_render_texture_pass { + struct wlr_render_texture_pass base; +}; + +bool wlr_render_texture_pass_is_pixman(const struct wlr_render_texture_pass *texture_pass); +struct wlr_pixman_render_texture_pass *wlr_pixman_render_texture_pass_from_pass( + struct wlr_render_texture_pass *texture_pass); + #endif diff --git a/include/render/vulkan.h b/include/render/vulkan.h index b4e1a28bd..e91e0e258 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -600,4 +600,12 @@ bool wlr_render_rect_pass_is_vk(const struct wlr_render_rect_pass *rect_pass); struct wlr_vk_render_rect_pass *wlr_vk_render_rect_pass_from_pass( struct wlr_render_rect_pass *rect_pass); +struct wlr_vk_render_texture_pass { + struct wlr_render_texture_pass base; +}; + +bool wlr_render_texture_pass_is_vk(const struct wlr_render_texture_pass *texture_pass); +struct wlr_vk_render_texture_pass *wlr_vk_render_texture_pass_from_pass( + const struct wlr_render_texture_pass *texture_pass); + #endif // RENDER_VULKAN_H diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 45b15f0e0..589c23d41 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -58,8 +58,6 @@ void wlr_render_pass_init(struct wlr_render_pass *pass, struct wlr_render_pass_impl { bool (*submit)(struct wlr_render_pass *pass); - void (*add_texture)(struct wlr_render_pass *pass, - const struct wlr_render_texture_options *options); }; struct wlr_render_timer { @@ -110,4 +108,29 @@ struct wlr_render_rect_pass *wlr_pixman_render_rect_pass_create(void); struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create(void); struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create(void); +struct wlr_render_texture_pass; + +struct wlr_render_texture_pass_impl { + void (*destroy)(struct wlr_render_texture_pass *pass); + void (*render)(struct wlr_render_pass *pass, + const struct wlr_render_texture_options *options); +}; + +struct wlr_render_texture_pass { + const struct wlr_render_texture_pass_impl *impl; + struct { + struct wl_signal destroy; + } events; +}; + +void wlr_render_texture_pass_init(struct wlr_render_texture_pass *pass, + const struct wlr_render_texture_pass_impl *impl); +void wlr_render_texture_pass_destroy(struct wlr_render_texture_pass *pass); + +struct wlr_render_texture_pass *get_or_create_render_texture_pass( + struct wlr_renderer *renderer); +struct wlr_render_texture_pass *wlr_pixman_render_texture_pass_create(void); +struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create(void); +struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create(void); + #endif diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index f1d761e5a..e993d8842 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -27,7 +27,7 @@ struct wlr_fbox; */ struct wlr_renderer { struct wlr_render_rect_pass *rect_pass; - + struct wlr_render_texture_pass *texture_pass; void *data; // Capabilities required for the buffer used as a render target (bitmask of diff --git a/render/gles2/pass.c b/render/gles2/pass.c index e207743ce..48855e993 100644 --- a/render/gles2/pass.c +++ b/render/gles2/pass.c @@ -286,7 +286,6 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, static const struct wlr_render_pass_impl render_pass_impl = { .submit = render_pass_submit, - .add_texture = render_pass_add_texture, }; static const char *reset_status_str(GLenum status) { @@ -391,3 +390,41 @@ struct wlr_gles2_render_rect_pass *wlr_gles2_render_rect_pass_from_pass( return pass; } +static void render_texture_pass_destroy(struct wlr_render_texture_pass *pass) { + struct wlr_gles2_render_texture_pass *gles2_pass = + wlr_gles2_render_texture_pass_from_pass(pass); + free(gles2_pass); +} + +static const struct wlr_render_texture_pass_impl render_texture_pass_impl = { + .destroy = render_texture_pass_destroy, + .render = render_pass_add_texture, +}; + +struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create(void) { + struct wlr_gles2_render_texture_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_gles2_render_texture_pass"); + return NULL; + } + + wlr_render_texture_pass_init(&pass->base, &render_texture_pass_impl); + + return &pass->base; +} +bool wlr_render_texture_pass_is_gles2(const struct wlr_render_texture_pass *texture_pass) { + return texture_pass != NULL && texture_pass->impl == &render_texture_pass_impl; +} + +struct wlr_gles2_render_texture_pass *wlr_gles2_render_texture_pass_from_pass( + struct wlr_render_texture_pass *texture_pass) { + if (!wlr_render_texture_pass_is_gles2(texture_pass)) { + return NULL; + } + + struct wlr_gles2_render_texture_pass *pass = + wl_container_of(texture_pass, pass, base); + + return pass; +} + diff --git a/render/pass.c b/render/pass.c index ef51c3b66..ce585ca5d 100644 --- a/render/pass.c +++ b/render/pass.c @@ -17,7 +17,7 @@ void wlr_render_pass_init(struct wlr_render_pass *render_pass, const struct wlr_render_pass_impl *impl) { - assert(impl->submit && impl->add_texture); + assert(impl->submit); *render_pass = (struct wlr_render_pass){ .impl = impl, }; @@ -38,7 +38,7 @@ void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass, (uint32_t)(box->y + box->height) <= options->texture->height); } - render_pass->impl->add_texture(render_pass, options); + render_pass->renderer->texture_pass->impl->render(render_pass, options); } void wlr_render_pass_add_rect(struct wlr_render_pass *render_pass, @@ -142,3 +142,56 @@ struct wlr_render_rect_pass *get_or_create_render_rect_pass( return renderer->rect_pass; } } + +void wlr_render_texture_pass_init(struct wlr_render_texture_pass *render_pass, + const struct wlr_render_texture_pass_impl *impl) { + assert(impl->render); + *render_pass = (struct wlr_render_texture_pass){ + .impl = impl, + }; + wl_signal_init(&render_pass->events.destroy); +} +void wlr_render_texture_pass_destroy(struct wlr_render_texture_pass *render_pass) { + if (render_pass == NULL) { + return; + } + + wl_signal_emit_mutable(&render_pass->events.destroy, NULL); + assert(wl_list_empty(&render_pass->events.destroy.listener_list)); + + if (render_pass->impl->destroy != NULL) { + render_pass->impl->destroy(render_pass); + } +} + +struct wlr_render_texture_pass *get_or_create_render_texture_pass( + struct wlr_renderer *renderer) { + if (renderer == NULL) { + return NULL; + } + + if (renderer->texture_pass == NULL) { + struct wlr_render_texture_pass *pass = NULL; + if (wlr_renderer_is_pixman(renderer)) { + pass = wlr_pixman_render_texture_pass_create(); + } + +#if WLR_HAS_GLES2_RENDERER + else if (wlr_renderer_is_gles2(renderer)) { + pass = wlr_gles2_render_texture_pass_create(); + } +#endif + +#if WLR_HAS_VULKAN_RENDERER + else if (wlr_renderer_is_vk(renderer)) { + pass = wlr_vk_render_texture_pass_create(); + } +#endif + + renderer->texture_pass = pass; + return pass; + } else { + return renderer->texture_pass; + } +} + diff --git a/render/pixman/pass.c b/render/pixman/pass.c index f5c55a577..a12795ff7 100644 --- a/render/pixman/pass.c +++ b/render/pixman/pass.c @@ -230,7 +230,6 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, static const struct wlr_render_pass_impl render_pass_impl = { .submit = render_pass_submit, - .add_texture = render_pass_add_texture, }; static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { @@ -272,6 +271,45 @@ struct wlr_pixman_render_rect_pass *wlr_pixman_render_rect_pass_from_pass( return pass; } +static void render_texture_pass_destroy(struct wlr_render_texture_pass *pass) { + struct wlr_pixman_render_texture_pass *pixman_pass = + wlr_pixman_render_texture_pass_from_pass(pass); + free(pixman_pass); +} + +static const struct wlr_render_texture_pass_impl render_texture_pass_impl = { + .destroy = render_texture_pass_destroy, + .render = render_pass_add_texture, +}; + +struct wlr_render_texture_pass *wlr_pixman_render_texture_pass_create(void) { + struct wlr_pixman_render_texture_pass *pass = malloc(sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_pixman_render_texture_pass"); + return NULL; + } + + wlr_render_texture_pass_init(&pass->base, &render_texture_pass_impl); + + return &pass->base; +} + +bool wlr_render_texture_pass_is_pixman(const struct wlr_render_texture_pass *texture_pass) { + return texture_pass->impl == &render_texture_pass_impl; +} + +struct wlr_pixman_render_texture_pass *wlr_pixman_render_texture_pass_from_pass( + struct wlr_render_texture_pass *texture_pass) { + if (!wlr_render_texture_pass_is_pixman(texture_pass)) { + return NULL; + } + + struct wlr_pixman_render_texture_pass *pixman_pass = + wl_container_of(texture_pass, pixman_pass, base); + + return pixman_pass; +} + struct wlr_pixman_render_pass *begin_pixman_render_pass( struct wlr_pixman_buffer *buffer) { struct wlr_pixman_render_pass *pass = calloc(1, sizeof(*pass)); diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 6cd06f343..828ea89eb 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -983,7 +983,6 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, static const struct wlr_render_pass_impl render_pass_impl = { .submit = render_pass_submit, - .add_texture = render_pass_add_texture, }; void vk_color_transform_destroy(struct wlr_addon *addon) { @@ -1393,3 +1392,41 @@ struct wlr_vk_render_rect_pass *wlr_vk_render_rect_pass_from_pass( return pass; } + +static void render_texture_pass_destroy(struct wlr_render_texture_pass *pass) { + struct wlr_vk_render_texture_pass *vk_pass = + wlr_vk_render_texture_pass_from_pass(pass); + free(vk_pass); +} + +static const struct wlr_render_texture_pass_impl render_texture_pass_impl = { + .destroy = render_texture_pass_destroy, + .render = render_pass_add_texture, +}; + +struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create(void) { + struct wlr_vk_render_texture_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_vk_render_texture_pass"); + return NULL; + } + + wlr_render_texture_pass_init(&pass->base, &render_texture_pass_impl); + + return &pass->base; +} +bool wlr_render_texture_pass_is_vk(const struct wlr_render_texture_pass *texture_pass) { + return texture_pass->impl == &render_texture_pass_impl; +} + +struct wlr_vk_render_texture_pass *wlr_vk_render_texture_pass_from_pass( + const struct wlr_render_texture_pass *texture_pass) { + if (!wlr_render_texture_pass_is_vk(texture_pass)) { + return NULL; + } + + struct wlr_vk_render_texture_pass *vk_pass = wl_container_of(texture_pass, vk_pass, base); + + return vk_pass; +} + diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 493add6b3..dcec642b1 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -54,6 +54,7 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { assert(wl_list_empty(&r->events.lost.listener_list)); wlr_render_rect_pass_destroy(r->rect_pass); + wlr_render_texture_pass_destroy(r->texture_pass); if (r->impl && r->impl->destroy) { r->impl->destroy(r); } else { diff --git a/types/output/render.c b/types/output/render.c index bbba26718..095d36c2b 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -37,6 +37,7 @@ bool wlr_output_init_render(struct wlr_output *output, output->renderer = renderer; get_or_create_render_rect_pass(renderer); + get_or_create_render_texture_pass(renderer); wl_signal_emit_mutable(&output->events.render_inited, output);