From 33a27b055cf5ac6bd610864afd51ef3e33cd98b1 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Fri, 13 Mar 2026 10:49:41 +0800 Subject: [PATCH 1/8] render: introduce wlr_render_rect_pass Split rectangle rendering out of wlr_render_pass and add a dedicated wlr_render_rect_pass interface. Remove the add_rect hook from wlr_render_pass_impl and implement rectangle rendering separately in the pixman, GLES2 and Vulkan renderers. --- include/render/gles2.h | 8 ++++ include/render/pixman.h | 8 ++++ include/render/vulkan.h | 8 ++++ include/wlr/render/interface.h | 29 +++++++++++-- include/wlr/render/wlr_renderer.h | 4 ++ include/wlr/types/wlr_output.h | 2 + render/gles2/pass.c | 42 +++++++++++++++++- render/pass.c | 72 ++++++++++++++++++++++++++++++- render/pixman/pass.c | 44 ++++++++++++++++++- render/vulkan/pass.c | 42 +++++++++++++++++- render/wlr_renderer.c | 1 + types/output/output.c | 2 + types/output/render.c | 5 +++ 13 files changed, 258 insertions(+), 9 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 6b852dcb7..d1a8b0aba 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -173,4 +173,12 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer, struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point); +struct wlr_gles2_render_rect_pass { + struct wlr_render_rect_pass base; +}; + +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); + #endif diff --git a/include/render/pixman.h b/include/render/pixman.h index 098421447..6d58ed0b6 100644 --- a/include/render/pixman.h +++ b/include/render/pixman.h @@ -61,4 +61,12 @@ bool begin_pixman_data_ptr_access(struct wlr_buffer *buffer, pixman_image_t **im struct wlr_pixman_render_pass *begin_pixman_render_pass( struct wlr_pixman_buffer *buffer); +struct wlr_pixman_render_rect_pass { + struct wlr_render_rect_pass base; +}; + +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); + #endif diff --git a/include/render/vulkan.h b/include/render/vulkan.h index c5d571ef7..b4e1a28bd 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -592,4 +592,12 @@ void vulkan_change_layout(VkCommandBuffer cb, VkImage img, #endif +struct wlr_vk_render_rect_pass { + struct wlr_render_rect_pass base; +}; + +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); + #endif // RENDER_VULKAN_H diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 89f6de970..45b15f0e0 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -50,6 +50,7 @@ void wlr_texture_init(struct wlr_texture *texture, struct wlr_renderer *rendener struct wlr_render_pass { const struct wlr_render_pass_impl *impl; + struct wlr_renderer *renderer; }; void wlr_render_pass_init(struct wlr_render_pass *pass, @@ -59,9 +60,6 @@ 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); - /* Implementers are also guaranteed that options->box is nonempty */ - void (*add_rect)(struct wlr_render_pass *pass, - const struct wlr_render_rect_options *options); }; struct wlr_render_timer { @@ -87,4 +85,29 @@ void wlr_texture_read_pixels_options_get_src_box( void *wlr_texture_read_pixel_options_get_data( const struct wlr_texture_read_pixels_options *options); +struct wlr_render_rect_pass; + +struct wlr_render_rect_pass_impl { + void (*destroy)(struct wlr_render_rect_pass *pass); + void (*render)(struct wlr_render_pass *pass, + const struct wlr_render_rect_options *options); +}; + +struct wlr_render_rect_pass { + const struct wlr_render_rect_pass_impl *impl; + struct { + struct wl_signal destroy; + } events; +}; + +void wlr_render_rect_pass_init(struct wlr_render_rect_pass *pass, + const struct wlr_render_rect_pass_impl *impl); +void wlr_render_rect_pass_destroy(struct wlr_render_rect_pass *pass); + +struct wlr_render_rect_pass *get_or_create_render_rect_pass( + struct wlr_renderer *renderer); +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); + #endif diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 902d7564d..f1d761e5a 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -26,6 +26,10 @@ struct wlr_fbox; * A renderer for basic 2D operations. */ struct wlr_renderer { + struct wlr_render_rect_pass *rect_pass; + + void *data; + // Capabilities required for the buffer used as a render target (bitmask of // enum wlr_buffer_cap) uint32_t render_buffer_caps; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index c8e44b0e6..d8a8e9965 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -250,6 +250,8 @@ struct wlr_output { struct wl_signal description; struct wl_signal request_state; // struct wlr_output_event_request_state struct wl_signal destroy; + // Emitted when the output's rendering subsystem is initialized or reinitialized + struct wl_signal render_inited; } events; struct wl_event_source *idle_frame; diff --git a/render/gles2/pass.c b/render/gles2/pass.c index a70ea1320..e207743ce 100644 --- a/render/gles2/pass.c +++ b/render/gles2/pass.c @@ -287,7 +287,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, - .add_rect = render_pass_add_rect, }; static const char *reset_status_str(GLenum status) { @@ -330,6 +329,7 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b wlr_render_pass_init(&pass->base, &render_pass_impl); wlr_buffer_lock(wlr_buffer); + pass->base.renderer = &renderer->wlr_renderer; pass->buffer = buffer; pass->timer = timer; pass->prev_ctx = *prev_ctx; @@ -351,3 +351,43 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b return pass; } + +static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { + struct wlr_gles2_render_rect_pass *gles2_pass = + wlr_gles2_render_rect_pass_from_pass(pass); + free(gles2_pass); +} + +static const struct wlr_render_rect_pass_impl render_rect_pass_impl = { + .destroy = render_rect_pass_destroy, + .render = render_pass_add_rect, +}; + +struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create(void) { + struct wlr_gles2_render_rect_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_gles2_render_rect_pass"); + return NULL; + } + + wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + + return &pass->base; +} + +bool wlr_render_rect_pass_is_gles2(const struct wlr_render_rect_pass *rect_pass) { + return rect_pass != NULL && rect_pass->impl == &render_rect_pass_impl; +} + +struct wlr_gles2_render_rect_pass *wlr_gles2_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass) { + if (!wlr_render_rect_pass_is_gles2(rect_pass)) { + return NULL; + } + + struct wlr_gles2_render_rect_pass *pass = + wl_container_of(rect_pass, pass, base); + + return pass; +} + diff --git a/render/pass.c b/render/pass.c index 23bdf96dd..ef51c3b66 100644 --- a/render/pass.c +++ b/render/pass.c @@ -1,10 +1,23 @@ #include #include +#include #include +#include +#include + +#include + +#if WLR_HAS_GLES2_RENDERER +#include +#endif + +#if WLR_HAS_VULKAN_RENDERER +#include +#endif void wlr_render_pass_init(struct wlr_render_pass *render_pass, const struct wlr_render_pass_impl *impl) { - assert(impl->submit && impl->add_texture && impl->add_rect); + assert(impl->submit && impl->add_texture); *render_pass = (struct wlr_render_pass){ .impl = impl, }; @@ -31,7 +44,7 @@ void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass, void wlr_render_pass_add_rect(struct wlr_render_pass *render_pass, const struct wlr_render_rect_options *options) { assert(options->box.width >= 0 && options->box.height >= 0); - render_pass->impl->add_rect(render_pass, options); + render_pass->renderer->rect_pass->impl->render(render_pass, options); } void wlr_render_texture_options_get_src_box(const struct wlr_render_texture_options *options, @@ -74,3 +87,58 @@ void wlr_render_rect_options_get_box(const struct wlr_render_rect_options *optio *box = options->box; } + +void wlr_render_rect_pass_init(struct wlr_render_rect_pass *render_pass, + const struct wlr_render_rect_pass_impl *impl) { + assert(impl->render); + *render_pass = (struct wlr_render_rect_pass){ + .impl = impl, + }; + wl_signal_init(&render_pass->events.destroy); +} + +void wlr_render_rect_pass_destroy(struct wlr_render_rect_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); + } else { + free(render_pass); + } +} + +struct wlr_render_rect_pass *get_or_create_render_rect_pass( + struct wlr_renderer *renderer) { + if (renderer == NULL) { + return NULL; + } + + if (renderer->rect_pass == NULL) { + struct wlr_render_rect_pass *pass = NULL; + if (wlr_renderer_is_pixman(renderer)) { + pass = wlr_pixman_render_rect_pass_create(); + } + +#if WLR_HAS_GLES2_RENDERER + else if (wlr_renderer_is_gles2(renderer)) { + pass = wlr_gles2_render_rect_pass_create(); + } +#endif + +#if WLR_HAS_VULKAN_RENDERER + else if (wlr_renderer_is_vk(renderer)) { + pass = wlr_vk_render_rect_pass_create(); + } +#endif + + renderer->rect_pass = pass; + return pass; + } else { + return renderer->rect_pass; + } +} diff --git a/render/pixman/pass.c b/render/pixman/pass.c index d3ee17dca..f5c55a577 100644 --- a/render/pixman/pass.c +++ b/render/pixman/pass.c @@ -1,5 +1,8 @@ #include #include + +#include + #include "render/pixman.h" static const struct wlr_render_pass_impl render_pass_impl; @@ -228,9 +231,47 @@ 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, - .add_rect = render_pass_add_rect, }; +static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { + struct wlr_pixman_render_rect_pass *pixman_pass = + wlr_pixman_render_rect_pass_from_pass(pass); + free(pixman_pass); +} + +static const struct wlr_render_rect_pass_impl render_rect_pass_impl = { + .destroy = render_rect_pass_destroy, + .render = render_pass_add_rect, +}; + +struct wlr_render_rect_pass *wlr_pixman_render_rect_pass_create(void) { + struct wlr_pixman_render_rect_pass *pass = malloc(sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_pixman_render_rect_pass"); + return NULL; + } + + wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + + return &pass->base; +} + +bool wlr_render_rect_pass_is_pixman(const struct wlr_render_rect_pass *rect_pass) { + return rect_pass->impl == &render_rect_pass_impl; +} + +struct wlr_pixman_render_rect_pass *wlr_pixman_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass) { + if (!wlr_render_rect_pass_is_pixman(rect_pass)) { + return NULL; + } + + struct wlr_pixman_render_rect_pass *pass = + wl_container_of(rect_pass, pass, base); + + return 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)); @@ -247,6 +288,7 @@ struct wlr_pixman_render_pass *begin_pixman_render_pass( } wlr_buffer_lock(buffer->buffer); + pass->base.renderer = &buffer->renderer->wlr_renderer; pass->buffer = buffer; return pass; diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 503e37c07..6cd06f343 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -983,11 +983,9 @@ 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_rect = render_pass_add_rect, .add_texture = render_pass_add_texture, }; - void vk_color_transform_destroy(struct wlr_addon *addon) { struct wlr_vk_renderer *renderer = (struct wlr_vk_renderer *)addon->owner; struct wlr_vk_color_transform *transform = wl_container_of(addon, transform, addon); @@ -1289,6 +1287,7 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend wlr_render_pass_init(&pass->base, &render_pass_impl); pass->renderer = renderer; + pass->base.renderer = &renderer->wlr_renderer; pass->two_pass = using_two_pass_pathway; if (options != NULL && options->color_transform != NULL) { pass->color_transform = wlr_color_transform_ref(options->color_transform); @@ -1355,3 +1354,42 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend pass->command_buffer = cb; return pass; } + +static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { + struct wlr_vk_render_rect_pass *vk_pass = + wlr_vk_render_rect_pass_from_pass(pass); + free(vk_pass); +} + +static const struct wlr_render_rect_pass_impl render_rect_pass_impl = { + .destroy = render_rect_pass_destroy, + .render = render_pass_add_rect, +}; + +struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create(void) { + struct wlr_vk_render_rect_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_vk_render_rect_pass"); + return NULL; + } + + wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + + return &pass->base; +} + +bool wlr_render_rect_pass_is_vk(const struct wlr_render_rect_pass *rect_pass) { + return rect_pass->impl == &render_rect_pass_impl; +} + +struct wlr_vk_render_rect_pass *wlr_vk_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass) { + if (!wlr_render_rect_pass_is_vk(rect_pass)) { + return NULL; + } + + struct wlr_vk_render_rect_pass *pass = + wl_container_of(rect_pass, pass, base); + + return pass; +} diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index e65314ccc..493add6b3 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -53,6 +53,7 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { assert(wl_list_empty(&r->events.destroy.listener_list)); assert(wl_list_empty(&r->events.lost.listener_list)); + wlr_render_rect_pass_destroy(r->rect_pass); if (r->impl && r->impl->destroy) { r->impl->destroy(r); } else { diff --git a/types/output/output.c b/types/output/output.c index 46da1f425..80fc0680b 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -377,6 +377,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.description); wl_signal_init(&output->events.request_state); wl_signal_init(&output->events.destroy); + wl_signal_init(&output->events.render_inited); output->software_cursor_locks = env_parse_bool("WLR_NO_HARDWARE_CURSORS"); if (output->software_cursor_locks) { @@ -407,6 +408,7 @@ void wlr_output_finish(struct wlr_output *output) { assert(wl_list_empty(&output->events.description.listener_list)); assert(wl_list_empty(&output->events.request_state.listener_list)); assert(wl_list_empty(&output->events.destroy.listener_list)); + assert(wl_list_empty(&output->events.render_inited.listener_list)); wlr_output_destroy_global(output); diff --git a/types/output/render.c b/types/output/render.c index 155da5cf8..bbba26718 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "render/drm_format_set.h" @@ -35,6 +36,10 @@ bool wlr_output_init_render(struct wlr_output *output, output->allocator = allocator; output->renderer = renderer; + get_or_create_render_rect_pass(renderer); + + wl_signal_emit_mutable(&output->events.render_inited, output); + return true; } From fee962af3620652e60312e446bafee3f3a2a2adc Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Fri, 13 Mar 2026 12:36:51 +0800 Subject: [PATCH 2/8] 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); From fb6cfcf809a6ae5b2852d926688a4fced71e0efe Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Fri, 13 Mar 2026 13:50:09 +0800 Subject: [PATCH 3/8] render: introduce wlr_render_submit_pass Move pass submission out of wlr_render_pass_impl and introduce wlr_render_submit_pass, mirroring the existing rect/texture pass abstractions. --- include/render/gles2.h | 8 +++ include/render/pixman.h | 8 +++ include/render/vulkan.h | 8 +++ include/wlr/render/interface.h | 38 +++++++++++-- include/wlr/render/wlr_renderer.h | 1 + render/gles2/pass.c | 53 +++++++++++++++++- render/pass.c | 91 +++++++++++++++++++++++++++++-- render/pixman/pass.c | 54 +++++++++++++++++- render/vulkan/pass.c | 53 +++++++++++++++++- render/wlr_renderer.c | 1 + types/output/render.c | 1 + 11 files changed, 299 insertions(+), 17 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 1ca875c6d..38c93b943 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -189,4 +189,12 @@ bool wlr_render_texture_pass_is_gles2(const struct wlr_render_texture_pass *text struct wlr_gles2_render_texture_pass *wlr_gles2_render_texture_pass_from_pass( struct wlr_render_texture_pass *texture_pass); +struct wlr_gles2_render_submit_pass { + struct wlr_render_submit_pass base; +}; + +bool wlr_render_submit_pass_is_gles2(const struct wlr_render_submit_pass *submit_pass); +struct wlr_gles2_render_submit_pass *wlr_gles2_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass); + #endif diff --git a/include/render/pixman.h b/include/render/pixman.h index aaf97c66f..3fd9ceb3b 100644 --- a/include/render/pixman.h +++ b/include/render/pixman.h @@ -77,4 +77,12 @@ bool wlr_render_texture_pass_is_pixman(const struct wlr_render_texture_pass *tex struct wlr_pixman_render_texture_pass *wlr_pixman_render_texture_pass_from_pass( struct wlr_render_texture_pass *texture_pass); +struct wlr_pixman_render_submit_pass { + struct wlr_render_submit_pass base; +}; + +bool wlr_render_submit_pass_is_pixman(const struct wlr_render_submit_pass *submit_pass); +struct wlr_pixman_render_submit_pass *wlr_pixman_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass); + #endif diff --git a/include/render/vulkan.h b/include/render/vulkan.h index e91e0e258..b42f657a8 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -608,4 +608,12 @@ bool wlr_render_texture_pass_is_vk(const struct wlr_render_texture_pass *texture struct wlr_vk_render_texture_pass *wlr_vk_render_texture_pass_from_pass( const struct wlr_render_texture_pass *texture_pass); +struct wlr_vk_render_submit_pass { + struct wlr_render_submit_pass base; +}; + +bool wlr_render_submit_pass_is_vk(const struct wlr_render_submit_pass *submit_pass); +struct wlr_vk_render_submit_pass *wlr_vk_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass); + #endif // RENDER_VULKAN_H diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 589c23d41..fd3bb1df8 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -48,17 +48,22 @@ struct wlr_texture_impl { void wlr_texture_init(struct wlr_texture *texture, struct wlr_renderer *rendener, const struct wlr_texture_impl *impl, uint32_t width, uint32_t height); +struct wlr_render_pass; + +struct wlr_render_pass_impl { + void (*destroy)(struct wlr_render_pass *pass); + struct wlr_renderer *(*get_renderer)(struct wlr_render_pass *pass); +}; + struct wlr_render_pass { const struct wlr_render_pass_impl *impl; - struct wlr_renderer *renderer; }; void wlr_render_pass_init(struct wlr_render_pass *pass, const struct wlr_render_pass_impl *impl); - -struct wlr_render_pass_impl { - bool (*submit)(struct wlr_render_pass *pass); -}; +void wlr_render_pass_destroy(struct wlr_render_pass *pass); +struct wlr_renderer *wlr_get_wlr_renderer_from_render_pass( + struct wlr_render_pass *wlr_pass); struct wlr_render_timer { const struct wlr_render_timer_impl *impl; @@ -133,4 +138,27 @@ 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); +struct wlr_render_submit_pass; + +struct wlr_render_submit_pass_impl { + void (*destroy)(struct wlr_render_submit_pass *pass); + bool (*render)(struct wlr_render_pass *pass); +}; + +struct wlr_render_submit_pass { + const struct wlr_render_submit_pass_impl *impl; + struct { + struct wl_signal destroy; + } events; +}; + +void wlr_render_submit_pass_init(struct wlr_render_submit_pass *pass, + const struct wlr_render_submit_pass_impl *impl); +void wlr_render_submit_pass_destroy(struct wlr_render_submit_pass *pass); +struct wlr_render_submit_pass *get_or_create_render_submit_pass( + struct wlr_renderer *renderer); +struct wlr_render_submit_pass *wlr_pixman_render_submit_pass_create(void); +struct wlr_render_submit_pass *wlr_gles2_render_submit_pass_create(void); +struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create(void); + #endif diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index e993d8842..259bfc5a9 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -28,6 +28,7 @@ struct wlr_fbox; struct wlr_renderer { struct wlr_render_rect_pass *rect_pass; struct wlr_render_texture_pass *texture_pass; + struct wlr_render_submit_pass *submit_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 48855e993..c5b7e00c7 100644 --- a/render/gles2/pass.c +++ b/render/gles2/pass.c @@ -284,8 +284,20 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, pop_gles2_debug(renderer); } +static void render_pass_destory(struct wlr_render_pass *wlr_pass) { + (void)wlr_pass; +} + +static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { + struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_gles2_renderer *renderer = pass->buffer->renderer; + + return &renderer->wlr_renderer; +} + static const struct wlr_render_pass_impl render_pass_impl = { - .submit = render_pass_submit, + .destroy = render_pass_destory, + .get_renderer = render_pass_get_renderer, }; static const char *reset_status_str(GLenum status) { @@ -328,7 +340,6 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b wlr_render_pass_init(&pass->base, &render_pass_impl); wlr_buffer_lock(wlr_buffer); - pass->base.renderer = &renderer->wlr_renderer; pass->buffer = buffer; pass->timer = timer; pass->prev_ctx = *prev_ctx; @@ -428,3 +439,41 @@ struct wlr_gles2_render_texture_pass *wlr_gles2_render_texture_pass_from_pass( return pass; } +static void render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { + struct wlr_gles2_render_submit_pass *gles2_pass = + wlr_gles2_render_submit_pass_from_pass(pass); + free(gles2_pass); +} + +static const struct wlr_render_submit_pass_impl gles2_render_submit_pass_impl = { + .destroy = render_submit_pass_destroy, + .render = render_pass_submit, +}; + +struct wlr_render_submit_pass *wlr_gles2_render_submit_pass_create(void) { + struct wlr_gles2_render_submit_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_gles2_render_submit_pass"); + return NULL; + } + + wlr_render_submit_pass_init(&pass->base, &gles2_render_submit_pass_impl); + + return &pass->base; +} + +bool wlr_render_submit_pass_is_gles2(const struct wlr_render_submit_pass *submit_pass) { + return submit_pass->impl == &gles2_render_submit_pass_impl; +} + +struct wlr_gles2_render_submit_pass *wlr_gles2_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass) { + if (!wlr_render_submit_pass_is_gles2(submit_pass)) { + return NULL; + } + + struct wlr_gles2_render_submit_pass *pass = + wl_container_of(submit_pass, pass, base); + + return pass; +} diff --git a/render/pass.c b/render/pass.c index ce585ca5d..ee2f9dbdc 100644 --- a/render/pass.c +++ b/render/pass.c @@ -15,16 +15,32 @@ #include #endif -void wlr_render_pass_init(struct wlr_render_pass *render_pass, +void wlr_render_pass_init(struct wlr_render_pass *pass, const struct wlr_render_pass_impl *impl) { - assert(impl->submit); - *render_pass = (struct wlr_render_pass){ + assert(impl->destroy); + *pass = (struct wlr_render_pass){ .impl = impl, }; } +void wlr_render_pass_destroy(struct wlr_render_pass *pass) { + if (pass == NULL) { + return; + } + + pass->impl->destroy(pass); +} + +struct wlr_renderer *wlr_get_wlr_renderer_from_render_pass( + struct wlr_render_pass *wlr_pass) { + return wlr_pass->impl->get_renderer(wlr_pass); +} + bool wlr_render_pass_submit(struct wlr_render_pass *render_pass) { - return render_pass->impl->submit(render_pass); + struct wlr_renderer *renderer = + wlr_get_wlr_renderer_from_render_pass(render_pass); + + return renderer->submit_pass->impl->render(render_pass); } void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass, @@ -38,13 +54,19 @@ void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass, (uint32_t)(box->y + box->height) <= options->texture->height); } - render_pass->renderer->texture_pass->impl->render(render_pass, options); + struct wlr_renderer *renderer = + wlr_get_wlr_renderer_from_render_pass(render_pass); + + renderer->texture_pass->impl->render(render_pass, options); } void wlr_render_pass_add_rect(struct wlr_render_pass *render_pass, const struct wlr_render_rect_options *options) { assert(options->box.width >= 0 && options->box.height >= 0); - render_pass->renderer->rect_pass->impl->render(render_pass, options); + struct wlr_renderer *renderer = + wlr_get_wlr_renderer_from_render_pass(render_pass); + + renderer->rect_pass->impl->render(render_pass, options); } void wlr_render_texture_options_get_src_box(const struct wlr_render_texture_options *options, @@ -195,3 +217,60 @@ struct wlr_render_texture_pass *get_or_create_render_texture_pass( } } +void wlr_render_submit_pass_init(struct wlr_render_submit_pass *pass, + const struct wlr_render_submit_pass_impl *impl) { + assert(impl->render); + *pass = (struct wlr_render_submit_pass){ + .impl = impl, + }; + wl_signal_init(&pass->events.destroy); +} + +void wlr_render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { + if (pass == NULL) { + return; + } + + wl_signal_emit_mutable(&pass->events.destroy, NULL); + assert(wl_list_empty(&pass->events.destroy.listener_list)); + + if (pass->impl->destroy != NULL) { + pass->impl->destroy(pass); + } +} + +struct wlr_render_submit_pass *get_or_create_render_submit_pass( + struct wlr_renderer *renderer) { + if (renderer == NULL) { + return NULL; + } + + if (renderer->submit_pass == NULL) { + struct wlr_render_submit_pass *pass = NULL; + if (wlr_renderer_is_pixman(renderer)) { + pass = wlr_pixman_render_submit_pass_create(); + } + +#if WLR_HAS_GLES2_RENDERER + else if (wlr_renderer_is_gles2(renderer)) { + pass = wlr_gles2_render_submit_pass_create(); + } +#endif + +#if WLR_HAS_VULKAN_RENDERER + else if (wlr_renderer_is_vk(renderer)) { + pass = wlr_vk_render_submit_pass_create(); + } +#endif + + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "Failed to allocate wlr_render_submit_pass"); + return NULL; + } + + renderer->submit_pass = pass; + return pass; + } else { + return renderer->submit_pass; + } +} diff --git a/render/pixman/pass.c b/render/pixman/pass.c index a12795ff7..736e6d553 100644 --- a/render/pixman/pass.c +++ b/render/pixman/pass.c @@ -228,8 +228,20 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, pixman_image_unref(fill); } +static void render_pass_destory(struct wlr_render_pass *wlr_pass) { + (void)wlr_pass; +} + +static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { + struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_renderer *renderer = pass->buffer->renderer; + + return &renderer->wlr_renderer; +} + static const struct wlr_render_pass_impl render_pass_impl = { - .submit = render_pass_submit, + .destroy = render_pass_destory, + .get_renderer = render_pass_get_renderer, }; static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { @@ -326,8 +338,46 @@ struct wlr_pixman_render_pass *begin_pixman_render_pass( } wlr_buffer_lock(buffer->buffer); - pass->base.renderer = &buffer->renderer->wlr_renderer; pass->buffer = buffer; return pass; } + +static void render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { + struct wlr_pixman_render_submit_pass *pixman_pass = + wlr_pixman_render_submit_pass_from_pass(pass); + free(pixman_pass); +} + +static const struct wlr_render_submit_pass_impl pixman_render_submit_pass_impl = { + .destroy = render_submit_pass_destroy, + .render = render_pass_submit, +}; + +struct wlr_render_submit_pass *wlr_pixman_render_submit_pass_create(void) { + struct wlr_pixman_render_submit_pass *pass = malloc(sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_pixman_render_submit_pass"); + return NULL; + } + + wlr_render_submit_pass_init(&pass->base, &pixman_render_submit_pass_impl); + + return &pass->base; +} + +bool wlr_render_submit_pass_is_pixman(const struct wlr_render_submit_pass *submit_pass) { + return submit_pass->impl == &pixman_render_submit_pass_impl; +} + +struct wlr_pixman_render_submit_pass *wlr_pixman_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass) { + if (!wlr_render_submit_pass_is_pixman(submit_pass)) { + return NULL; + } + + struct wlr_pixman_render_submit_pass *pass = + wl_container_of(submit_pass, pass, base); + + return pass; +} diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 828ea89eb..67838f820 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -981,8 +981,20 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, } } +static void render_pass_destory(struct wlr_render_pass *wlr_pass) { + (void)wlr_pass; +} + +static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { + struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_renderer *renderer = pass->renderer; + + return &renderer->wlr_renderer; +} + static const struct wlr_render_pass_impl render_pass_impl = { - .submit = render_pass_submit, + .destroy = render_pass_destory, + .get_renderer = render_pass_get_renderer, }; void vk_color_transform_destroy(struct wlr_addon *addon) { @@ -1286,7 +1298,6 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend wlr_render_pass_init(&pass->base, &render_pass_impl); pass->renderer = renderer; - pass->base.renderer = &renderer->wlr_renderer; pass->two_pass = using_two_pass_pathway; if (options != NULL && options->color_transform != NULL) { pass->color_transform = wlr_color_transform_ref(options->color_transform); @@ -1430,3 +1441,41 @@ struct wlr_vk_render_texture_pass *wlr_vk_render_texture_pass_from_pass( return vk_pass; } +static void render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { + struct wlr_vk_render_submit_pass *vk_pass = + wlr_vk_render_submit_pass_from_pass(pass); + free(vk_pass); +} + +static const struct wlr_render_submit_pass_impl vk_render_submit_pass_impl = { + .destroy = render_submit_pass_destroy, + .render = render_pass_submit, +}; + +struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create(void) { + struct wlr_vk_render_submit_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_vk_render_submit_pass"); + return NULL; + } + + wlr_render_submit_pass_init(&pass->base, &vk_render_submit_pass_impl); + + return &pass->base; +} + +bool wlr_render_submit_pass_is_vk(const struct wlr_render_submit_pass *submit_pass) { + return submit_pass->impl == &vk_render_submit_pass_impl; +} + +struct wlr_vk_render_submit_pass *wlr_vk_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass) { + if (!wlr_render_submit_pass_is_vk(submit_pass)) { + return NULL; + } + + struct wlr_vk_render_submit_pass *pass = + wl_container_of(submit_pass, pass, base); + + return pass; +} diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index dcec642b1..296c276df 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -55,6 +55,7 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { wlr_render_rect_pass_destroy(r->rect_pass); wlr_render_texture_pass_destroy(r->texture_pass); + wlr_render_submit_pass_destroy(r->submit_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 095d36c2b..78daa3d48 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -38,6 +38,7 @@ bool wlr_output_init_render(struct wlr_output *output, get_or_create_render_rect_pass(renderer); get_or_create_render_texture_pass(renderer); + get_or_create_render_submit_pass(renderer); wl_signal_emit_mutable(&output->events.render_inited, output); From e78131f3d39ad875bea9906ab02db62421762da6 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Wed, 18 Mar 2026 15:08:47 +0800 Subject: [PATCH 4/8] render/gles2: move shaders to render_xxx_pass Stop storing the shader on the renderer and instead create a dedicated shader per wlr_render_xxx_pass. --- include/render/gles2.h | 28 ++++---- include/wlr/render/interface.h | 6 +- render/gles2/pass.c | 121 +++++++++++++++++++++++++++++---- render/gles2/renderer.c | 84 +---------------------- render/pass.c | 4 +- 5 files changed, 132 insertions(+), 111 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 38c93b943..efdb6599d 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -73,18 +73,6 @@ struct wlr_gles2_renderer { PFNGLGETINTEGER64VEXTPROC glGetInteger64vEXT; } procs; - struct { - struct { - GLuint program; - GLint proj; - GLint color; - GLint pos_attrib; - } quad; - struct wlr_gles2_tex_shader tex_rgba; - struct wlr_gles2_tex_shader tex_rgbx; - struct wlr_gles2_tex_shader tex_ext; - } shaders; - struct wl_list buffers; // wlr_gles2_buffer.link struct wl_list textures; // wlr_gles2_texture.link }; @@ -175,6 +163,13 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b struct wlr_gles2_render_rect_pass { struct wlr_render_rect_pass base; + struct wlr_gles2_renderer *renderer; + struct { + GLuint program; + GLint proj; + GLint color; + GLint pos_attrib; + } shader; }; bool wlr_render_rect_pass_is_gles2(const struct wlr_render_rect_pass *rect_pass); @@ -183,6 +178,12 @@ struct wlr_gles2_render_rect_pass *wlr_gles2_render_rect_pass_from_pass( struct wlr_gles2_render_texture_pass { struct wlr_render_texture_pass base; + struct wlr_gles2_renderer *renderer; + struct { + struct wlr_gles2_tex_shader tex_rgba; + struct wlr_gles2_tex_shader tex_rgbx; + struct wlr_gles2_tex_shader tex_ext; + } shaders; }; bool wlr_render_texture_pass_is_gles2(const struct wlr_render_texture_pass *texture_pass); @@ -197,4 +198,7 @@ bool wlr_render_submit_pass_is_gles2(const struct wlr_render_submit_pass *submit struct wlr_gles2_render_submit_pass *wlr_gles2_render_submit_pass_from_pass( struct wlr_render_submit_pass *submit_pass); +GLuint gles2_link_program(struct wlr_gles2_renderer *renderer, + const GLchar *vert_src, const GLchar *frag_src); + #endif diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index fd3bb1df8..3d61aab40 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -110,7 +110,8 @@ void wlr_render_rect_pass_destroy(struct wlr_render_rect_pass *pass); struct wlr_render_rect_pass *get_or_create_render_rect_pass( struct wlr_renderer *renderer); 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_gles2_render_rect_pass_create( + struct wlr_renderer *wlr_renderer); struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create(void); struct wlr_render_texture_pass; @@ -135,7 +136,8 @@ 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_gles2_render_texture_pass_create( + struct wlr_renderer *wlr_renderer); struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create(void); struct wlr_render_submit_pass; diff --git a/render/gles2/pass.c b/render/gles2/pass.c index c5b7e00c7..a33d9a73b 100644 --- a/render/gles2/pass.c +++ b/render/gles2/pass.c @@ -9,6 +9,12 @@ #include "render/gles2.h" #include "util/matrix.h" +#include "common_vert_src.h" +#include "quad_frag_src.h" +#include "tex_rgba_frag_src.h" +#include "tex_rgbx_frag_src.h" +#include "tex_external_frag_src.h" + #define MAX_QUADS 86 // 4kb static const struct wlr_render_pass_impl render_pass_impl; @@ -169,22 +175,23 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; struct wlr_gles2_texture *texture = gles2_get_texture(options->texture); - + struct wlr_gles2_render_texture_pass *texture_pass = + wlr_gles2_render_texture_pass_from_pass(renderer->wlr_renderer.texture_pass); struct wlr_gles2_tex_shader *shader = NULL; switch (texture->target) { case GL_TEXTURE_2D: if (texture->has_alpha) { - shader = &renderer->shaders.tex_rgba; + shader = &texture_pass->shaders.tex_rgba; } else { - shader = &renderer->shaders.tex_rgbx; + shader = &texture_pass->shaders.tex_rgbx; } break; case GL_TEXTURE_EXTERNAL_OES: // EGL_EXT_image_dma_buf_import_modifiers requires // GL_OES_EGL_image_external assert(renderer->exts.OES_egl_image_external); - shader = &renderer->shaders.tex_ext; + shader = &texture_pass->shaders.tex_ext; break; default: abort(); @@ -257,6 +264,8 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, const struct wlr_render_rect_options *options) { struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; + struct wlr_gles2_render_rect_pass *rect_pass = + wlr_gles2_render_rect_pass_from_pass(renderer->wlr_renderer.rect_pass); const struct wlr_render_color *color = &options->color; struct wlr_box box; @@ -275,10 +284,10 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, glClear(GL_COLOR_BUFFER_BIT); } else { setup_blending(blend_mode); - glUseProgram(renderer->shaders.quad.program); - set_proj_matrix(renderer->shaders.quad.proj, pass->projection_matrix, &box); - glUniform4f(renderer->shaders.quad.color, color->r, color->g, color->b, color->a); - render(&box, options->clip, renderer->shaders.quad.pos_attrib); + glUseProgram(rect_pass->shader.program); + set_proj_matrix(rect_pass->shader.proj, pass->projection_matrix, &box); + glUniform4f(rect_pass->shader.color, color->r, color->g, color->b, color->a); + render(&box, options->clip, rect_pass->shader.pos_attrib); } pop_gles2_debug(renderer); @@ -365,6 +374,9 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { struct wlr_gles2_render_rect_pass *gles2_pass = wlr_gles2_render_rect_pass_from_pass(pass); + push_gles2_debug(gles2_pass->renderer); + glDeleteProgram(gles2_pass->shader.program); + pop_gles2_debug(gles2_pass->renderer); free(gles2_pass); } @@ -373,16 +385,43 @@ static const struct wlr_render_rect_pass_impl render_rect_pass_impl = { .render = render_pass_add_rect, }; -struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create(void) { +struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create( + struct wlr_renderer *wlr_renderer) { struct wlr_gles2_render_rect_pass *pass = calloc(1, sizeof(*pass)); if (pass == NULL) { wlr_log_errno(WLR_ERROR, "failed to allocate wlr_gles2_render_rect_pass"); return NULL; } - wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + if (!wlr_egl_make_current(renderer->egl, NULL)) { + free(pass); + return NULL; + } + wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + push_gles2_debug(renderer); + GLuint prog; + pass->shader.program = prog = + gles2_link_program(renderer, common_vert_src, quad_frag_src); + if (!pass->shader.program) { + goto error; + } + + pass->shader.proj = glGetUniformLocation(pass->shader.program, "proj"); + pass->shader.color = glGetUniformLocation(pass->shader.program, "color"); + pass->shader.pos_attrib = glGetAttribLocation(pass->shader.program, "pos"); + pop_gles2_debug(renderer); + wlr_egl_unset_current(renderer->egl); + pass->renderer = renderer; return &pass->base; + +error: + render_rect_pass_destroy(&pass->base); + pop_gles2_debug(renderer); + wlr_egl_unset_current(renderer->egl); + + return NULL; } bool wlr_render_rect_pass_is_gles2(const struct wlr_render_rect_pass *rect_pass) { @@ -404,6 +443,11 @@ struct wlr_gles2_render_rect_pass *wlr_gles2_render_rect_pass_from_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); + push_gles2_debug(gles2_pass->renderer); + glDeleteProgram(gles2_pass->shaders.tex_rgba.program); + glDeleteProgram(gles2_pass->shaders.tex_rgbx.program); + glDeleteProgram(gles2_pass->shaders.tex_ext.program); + pop_gles2_debug(gles2_pass->renderer); free(gles2_pass); } @@ -412,17 +456,70 @@ static const struct wlr_render_texture_pass_impl render_texture_pass_impl = { .render = render_pass_add_texture, }; -struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create(void) { +struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( + struct wlr_renderer *wlr_renderer) { 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); + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + if (!wlr_egl_make_current(renderer->egl, NULL)) { + free(pass); + return NULL; + } + push_gles2_debug(renderer); + GLuint prog; + pass->shaders.tex_rgba.program = prog = + gles2_link_program(renderer, common_vert_src, tex_rgba_frag_src); + if (!pass->shaders.tex_rgba.program) { + goto error; + } + pass->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj"); + pass->shaders.tex_rgba.tex_proj = glGetUniformLocation(prog, "tex_proj"); + pass->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex"); + pass->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha"); + pass->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); + pass->shaders.tex_rgbx.program = prog = + gles2_link_program(renderer, common_vert_src, tex_rgbx_frag_src); + if (!pass->shaders.tex_rgbx.program) { + goto error; + } + pass->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj"); + pass->shaders.tex_rgbx.tex_proj = glGetUniformLocation(prog, "tex_proj"); + pass->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); + pass->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); + pass->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos"); + + if (renderer->exts.OES_egl_image_external) { + pass->shaders.tex_ext.program = prog = + gles2_link_program(renderer, common_vert_src, tex_external_frag_src); + if (!pass->shaders.tex_ext.program) { + goto error; + } + pass->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj"); + pass->shaders.tex_ext.tex_proj = glGetUniformLocation(prog, "tex_proj"); + pass->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex"); + pass->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha"); + pass->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos"); + } + + pop_gles2_debug(renderer); + + wlr_egl_unset_current(renderer->egl); + pass->renderer = renderer; return &pass->base; + +error: + render_texture_pass_destroy(&pass->base); + pop_gles2_debug(renderer); + wlr_egl_unset_current(renderer->egl); + + return NULL; } + 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; } diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 7f01b8acd..010623354 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -20,12 +20,6 @@ #include "render/pixel_format.h" #include "util/time.h" -#include "common_vert_src.h" -#include "quad_frag_src.h" -#include "tex_rgba_frag_src.h" -#include "tex_rgbx_frag_src.h" -#include "tex_external_frag_src.h" - static const struct wlr_renderer_impl renderer_impl; static const struct wlr_render_timer_impl render_timer_impl; @@ -214,13 +208,6 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { destroy_buffer(buffer); } - push_gles2_debug(renderer); - glDeleteProgram(renderer->shaders.quad.program); - glDeleteProgram(renderer->shaders.tex_rgba.program); - glDeleteProgram(renderer->shaders.tex_rgbx.program); - glDeleteProgram(renderer->shaders.tex_ext.program); - pop_gles2_debug(renderer); - if (renderer->exts.KHR_debug) { glDisable(GL_DEBUG_OUTPUT_KHR); renderer->procs.glDebugMessageCallbackKHR(NULL, NULL); @@ -425,7 +412,7 @@ static GLuint compile_shader(struct wlr_gles2_renderer *renderer, return shader; } -static GLuint link_program(struct wlr_gles2_renderer *renderer, +GLuint gles2_link_program(struct wlr_gles2_renderer *renderer, const GLchar *vert_src, const GLchar *frag_src) { push_gles2_debug(renderer); @@ -630,57 +617,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); } - push_gles2_debug(renderer); - - GLuint prog; - renderer->shaders.quad.program = prog = - link_program(renderer, common_vert_src, quad_frag_src); - if (!renderer->shaders.quad.program) { - goto error; - } - renderer->shaders.quad.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.quad.color = glGetUniformLocation(prog, "color"); - renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos"); - - renderer->shaders.tex_rgba.program = prog = - link_program(renderer, common_vert_src, tex_rgba_frag_src); - if (!renderer->shaders.tex_rgba.program) { - goto error; - } - renderer->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgba.tex_proj = glGetUniformLocation(prog, "tex_proj"); - renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); - - renderer->shaders.tex_rgbx.program = prog = - link_program(renderer, common_vert_src, tex_rgbx_frag_src); - if (!renderer->shaders.tex_rgbx.program) { - goto error; - } - renderer->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgbx.tex_proj = glGetUniformLocation(prog, "tex_proj"); - renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos"); - - if (renderer->exts.OES_egl_image_external) { - renderer->shaders.tex_ext.program = prog = - link_program(renderer, common_vert_src, tex_external_frag_src); - if (!renderer->shaders.tex_ext.program) { - goto error; - } - renderer->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_ext.tex_proj = glGetUniformLocation(prog, "tex_proj"); - renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos"); - } - - pop_gles2_debug(renderer); - - wlr_egl_unset_current(renderer->egl); - get_gles2_shm_formats(renderer, &renderer->shm_texture_formats); int drm_fd = wlr_renderer_get_drm_fd(&renderer->wlr_renderer); @@ -691,24 +627,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { } return &renderer->wlr_renderer; - -error: - glDeleteProgram(renderer->shaders.quad.program); - glDeleteProgram(renderer->shaders.tex_rgba.program); - glDeleteProgram(renderer->shaders.tex_rgbx.program); - glDeleteProgram(renderer->shaders.tex_ext.program); - - pop_gles2_debug(renderer); - - if (renderer->exts.KHR_debug) { - glDisable(GL_DEBUG_OUTPUT_KHR); - renderer->procs.glDebugMessageCallbackKHR(NULL, NULL); - } - - wlr_egl_unset_current(renderer->egl); - - free(renderer); - return NULL; } bool wlr_gles2_renderer_check_ext(struct wlr_renderer *wlr_renderer, diff --git a/render/pass.c b/render/pass.c index ee2f9dbdc..4aedd9337 100644 --- a/render/pass.c +++ b/render/pass.c @@ -148,7 +148,7 @@ struct wlr_render_rect_pass *get_or_create_render_rect_pass( #if WLR_HAS_GLES2_RENDERER else if (wlr_renderer_is_gles2(renderer)) { - pass = wlr_gles2_render_rect_pass_create(); + pass = wlr_gles2_render_rect_pass_create(renderer); } #endif @@ -200,7 +200,7 @@ struct wlr_render_texture_pass *get_or_create_render_texture_pass( #if WLR_HAS_GLES2_RENDERER else if (wlr_renderer_is_gles2(renderer)) { - pass = wlr_gles2_render_texture_pass_create(); + pass = wlr_gles2_render_texture_pass_create(renderer); } #endif From 64733653614c1c7d7f31ef3e811d054d2150c4f3 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Thu, 19 Mar 2026 10:39:12 +0800 Subject: [PATCH 5/8] render/vulkan: move blend-to-output resources to render_xxx_pass --- include/render/vulkan.h | 63 +++++++---- include/wlr/render/interface.h | 9 +- render/pass.c | 6 +- render/vulkan/pass.c | 145 +++++++++++++++++++++--- render/vulkan/renderer.c | 201 ++++++++++++++------------------- 5 files changed, 264 insertions(+), 160 deletions(-) diff --git a/include/render/vulkan.h b/include/render/vulkan.h index b42f657a8..0f65b277e 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -302,31 +302,8 @@ struct wlr_vk_renderer { VkCommandPool command_pool; - VkShaderModule vert_module; - VkShaderModule tex_frag_module; - VkShaderModule quad_frag_module; - VkShaderModule output_module; - struct wl_list pipeline_layouts; // struct wlr_vk_pipeline_layout.link - // for blend->output subpass - VkPipelineLayout output_pipe_layout; - VkDescriptorSetLayout output_ds_srgb_layout; - VkDescriptorSetLayout output_ds_lut3d_layout; - VkSampler output_sampler_lut3d; - // descriptor set indicating dummy 1x1x1 image, for use in the lut3d slot - VkDescriptorSet output_ds_lut3d_dummy; - struct wlr_vk_descriptor_pool *output_ds_lut3d_dummy_pool; - - size_t last_output_pool_size; - struct wl_list output_descriptor_pools; // wlr_vk_descriptor_pool.link - - // dummy sampler to bind when output shader is not using a lookup table - VkImage dummy3d_image; - VkDeviceMemory dummy3d_mem; - VkImageView dummy3d_image_view; - bool dummy3d_image_transitioned; - VkSemaphore timeline_semaphore; uint64_t timeline_point; @@ -392,7 +369,8 @@ struct wlr_vk_texture_view { struct wlr_vk_pipeline *setup_get_or_create_pipeline( struct wlr_vk_render_format_setup *setup, - const struct wlr_vk_pipeline_key *key); + const struct wlr_vk_pipeline_key *key, + VkShaderModule vert_module, VkShaderModule frag_module); struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout( struct wlr_vk_renderer *renderer, const struct wlr_vk_pipeline_layout_key *key); @@ -468,6 +446,7 @@ void vulkan_free_ds(struct wlr_vk_renderer *renderer, struct wlr_vk_format_props *vulkan_format_props_from_drm( struct wlr_vk_device *dev, uint32_t drm_format); struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *r); +VkShaderModule vulkan_create_common_vert_module(struct wlr_vk_renderer *renderer); struct wlr_vk_command_buffer *vulkan_acquire_command_buffer( struct wlr_vk_renderer *renderer); @@ -594,6 +573,11 @@ void vulkan_change_layout(VkCommandBuffer cb, VkImage img, struct wlr_vk_render_rect_pass { struct wlr_render_rect_pass base; + struct wlr_vk_renderer *renderer; + struct { + VkShaderModule vert_module; + VkShaderModule frag_module; + } shader; }; bool wlr_render_rect_pass_is_vk(const struct wlr_render_rect_pass *rect_pass); @@ -602,6 +586,11 @@ struct wlr_vk_render_rect_pass *wlr_vk_render_rect_pass_from_pass( struct wlr_vk_render_texture_pass { struct wlr_render_texture_pass base; + struct wlr_vk_renderer *renderer; + struct { + VkShaderModule vert_module; + VkShaderModule frag_module; + } shader; }; bool wlr_render_texture_pass_is_vk(const struct wlr_render_texture_pass *texture_pass); @@ -610,10 +599,36 @@ struct wlr_vk_render_texture_pass *wlr_vk_render_texture_pass_from_pass( struct wlr_vk_render_submit_pass { struct wlr_render_submit_pass base; + struct wlr_vk_renderer *renderer; + + struct { + VkShaderModule vert_module; + VkShaderModule frag_module; + + VkPipelineLayout pipe_layout; + VkDescriptorSetLayout ds_srgb_layout; + VkDescriptorSetLayout ds_lut3d_layout; + VkSampler sampler_lut3d; + // descriptor set indicating dummy 1x1x1 image, for use in the lut3d slot + VkDescriptorSet ds_lut3d_dummy; + struct wlr_vk_descriptor_pool *ds_lut3d_dummy_pool; + + size_t last_pool_size; + struct wl_list descriptor_pools; // wlr_vk_descriptor_pool.link + + // dummy sampler to bind when output shader is not using a lookup table + VkImage dummy3d_image; + VkDeviceMemory dummy3d_mem; + VkImageView dummy3d_image_view; + bool dummy3d_image_transitioned; + } output; }; bool wlr_render_submit_pass_is_vk(const struct wlr_render_submit_pass *submit_pass); struct wlr_vk_render_submit_pass *wlr_vk_render_submit_pass_from_pass( struct wlr_render_submit_pass *submit_pass); +bool vulkan_init_submit_pass_output(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass); + #endif // RENDER_VULKAN_H diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 3d61aab40..13b34a70e 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -112,7 +112,8 @@ struct wlr_render_rect_pass *get_or_create_render_rect_pass( struct wlr_render_rect_pass *wlr_pixman_render_rect_pass_create(void); struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create( struct wlr_renderer *wlr_renderer); -struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create(void); +struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create( + struct wlr_renderer *wlr_renderer); struct wlr_render_texture_pass; @@ -138,7 +139,8 @@ struct wlr_render_texture_pass *get_or_create_render_texture_pass( struct wlr_render_texture_pass *wlr_pixman_render_texture_pass_create(void); struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( struct wlr_renderer *wlr_renderer); -struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create(void); +struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create( + struct wlr_renderer *wlr_renderer); struct wlr_render_submit_pass; @@ -161,6 +163,7 @@ struct wlr_render_submit_pass *get_or_create_render_submit_pass( struct wlr_renderer *renderer); struct wlr_render_submit_pass *wlr_pixman_render_submit_pass_create(void); struct wlr_render_submit_pass *wlr_gles2_render_submit_pass_create(void); -struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create(void); +struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create( + struct wlr_renderer *wlr_renderer); #endif diff --git a/render/pass.c b/render/pass.c index 4aedd9337..35f467eb1 100644 --- a/render/pass.c +++ b/render/pass.c @@ -154,7 +154,7 @@ struct wlr_render_rect_pass *get_or_create_render_rect_pass( #if WLR_HAS_VULKAN_RENDERER else if (wlr_renderer_is_vk(renderer)) { - pass = wlr_vk_render_rect_pass_create(); + pass = wlr_vk_render_rect_pass_create(renderer); } #endif @@ -206,7 +206,7 @@ struct wlr_render_texture_pass *get_or_create_render_texture_pass( #if WLR_HAS_VULKAN_RENDERER else if (wlr_renderer_is_vk(renderer)) { - pass = wlr_vk_render_texture_pass_create(); + pass = wlr_vk_render_texture_pass_create(renderer); } #endif @@ -259,7 +259,7 @@ struct wlr_render_submit_pass *get_or_create_render_submit_pass( #if WLR_HAS_VULKAN_RENDERER else if (wlr_renderer_is_vk(renderer)) { - pass = wlr_vk_render_submit_pass_create(); + pass = wlr_vk_render_submit_pass_create(renderer); } #endif diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 67838f820..7373e935f 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -3,16 +3,35 @@ #include #include #include -#include #include #include "render/color.h" #include "render/vulkan.h" +#include "render/vulkan/shaders/quad.frag.h" +#include "render/vulkan/shaders/texture.frag.h" #include "util/matrix.h" static const struct wlr_render_pass_impl render_pass_impl; static const struct wlr_addon_interface vk_color_transform_impl; +static bool create_shader_module(VkDevice dev, const uint32_t *code, + size_t code_size, const char *name, VkShaderModule *out) { + VkShaderModuleCreateInfo sinfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = code_size, + .pCode = code, + }; + + VkResult res = vkCreateShaderModule(dev, &sinfo, NULL, out); + if (res != VK_SUCCESS) { + wlr_log(WLR_ERROR, "Failed to create %s shader module: %s (%d)", + name, vulkan_strerror(res), res); + return false; + } + + return true; +} + static struct wlr_vk_render_pass *get_render_pass(struct wlr_render_pass *wlr_pass) { assert(wlr_pass->impl == &render_pass_impl); struct wlr_vk_render_pass *pass = wl_container_of(wlr_pass, pass, base); @@ -223,6 +242,9 @@ static bool unwrap_color_transform(struct wlr_color_transform *transform, static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); struct wlr_vk_renderer *renderer = pass->renderer; + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass); + assert(submit_pass != NULL); struct wlr_vk_command_buffer *render_cb = pass->command_buffer; struct wlr_vk_render_buffer *render_buffer = pass->render_buffer; struct wlr_vk_command_buffer *stage_cb = NULL; @@ -306,9 +328,9 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { } } bind_pipeline(pass, pipeline); - vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout, + vkCmdPushConstants(render_cb->vk, submit_pass->output.pipe_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); - vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout, + vkCmdPushConstants(render_cb->vk, submit_pass->output.pipe_layout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(frag_pcr_data), &frag_pcr_data); @@ -316,7 +338,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { if (need_lut) { lut_ds = transform->lut_3d.ds; } else { - lut_ds = renderer->output_ds_lut3d_dummy; + lut_ds = submit_pass->output.ds_lut3d_dummy; } VkDescriptorSet ds[] = { render_buffer->two_pass.blend_descriptor_set, // set 0 @@ -324,7 +346,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { }; size_t ds_len = sizeof(ds) / sizeof(ds[0]); vkCmdBindDescriptorSets(render_cb->vk, - VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->output_pipe_layout, + VK_PIPELINE_BIND_POINT_GRAPHICS, submit_pass->output.pipe_layout, 0, ds_len, ds, 0, NULL); const pixman_region32_t *clip = rect_union_evaluate(&pass->updated_region); @@ -684,6 +706,9 @@ static void render_pass_mark_box_updated(struct wlr_vk_render_pass *pass, static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, const struct wlr_render_rect_options *options) { struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_render_rect_pass *rect_pass = + wlr_vk_render_rect_pass_from_pass(pass->renderer->wlr_renderer.rect_pass); + assert(rect_pass != NULL); VkCommandBuffer cb = pass->command_buffer->vk; // Input color values are given in sRGB space, shader expects @@ -733,7 +758,9 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, &(struct wlr_vk_pipeline_key) { .source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR, .layout = {0}, - }); + }, + rect_pass->shader.vert_module, + rect_pass->shader.frag_module); if (!pipe) { pass->failed = true; break; @@ -787,6 +814,9 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, const struct wlr_render_texture_options *options) { struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); struct wlr_vk_renderer *renderer = pass->renderer; + struct wlr_vk_render_texture_pass *texture_pass = + wlr_vk_render_texture_pass_from_pass(renderer->wlr_renderer.texture_pass); + assert(texture_pass != NULL); VkCommandBuffer cb = pass->command_buffer->vk; struct wlr_vk_texture *texture = vulkan_get_texture(options->texture); @@ -884,7 +914,9 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, .texture_transform = tex_transform, .blend_mode = !texture->has_alpha && alpha == 1.0 ? WLR_RENDER_BLEND_MODE_NONE : options->blend_mode, - }); + }, + texture_pass->shader.vert_module, + texture_pass->shader.frag_module); if (!pipe) { pass->failed = true; return; @@ -1019,6 +1051,12 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer, VkImage *image, VkImageView *image_view, VkDeviceMemory *memory, VkDescriptorSet *ds, struct wlr_vk_descriptor_pool **ds_pool) { + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass);; + if (submit_pass == NULL) { + return false; + } + VkDevice dev = renderer->dev->dev; VkResult res; @@ -1157,7 +1195,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT); *ds_pool = vulkan_alloc_texture_ds(renderer, - renderer->output_ds_lut3d_layout, ds); + submit_pass->output.ds_lut3d_layout, ds); if (!*ds_pool) { wlr_log(WLR_ERROR, "Failed to allocate descriptor"); goto fail_imageview; @@ -1326,9 +1364,12 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend return NULL; } - if (!renderer->dummy3d_image_transitioned) { - renderer->dummy3d_image_transitioned = true; - vulkan_change_layout(cb->vk, renderer->dummy3d_image, + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass); + assert(submit_pass != NULL); + if (!submit_pass->output.dummy3d_image_transitioned) { + submit_pass->output.dummy3d_image_transitioned = true; + vulkan_change_layout(cb->vk, submit_pass->output.dummy3d_image, VK_IMAGE_LAYOUT_UNDEFINED, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT); @@ -1368,6 +1409,14 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { struct wlr_vk_render_rect_pass *vk_pass = wlr_vk_render_rect_pass_from_pass(pass); + if (vk_pass->shader.vert_module != VK_NULL_HANDLE) { + vkDestroyShaderModule(vk_pass->renderer->dev->dev, + vk_pass->shader.vert_module, NULL); + } + if (vk_pass->shader.frag_module != VK_NULL_HANDLE) { + vkDestroyShaderModule(vk_pass->renderer->dev->dev, + vk_pass->shader.frag_module, NULL); + } free(vk_pass); } @@ -1376,15 +1425,30 @@ static const struct wlr_render_rect_pass_impl render_rect_pass_impl = { .render = render_pass_add_rect, }; -struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create(void) { +struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create( + struct wlr_renderer *wlr_renderer) { struct wlr_vk_render_rect_pass *pass = calloc(1, sizeof(*pass)); if (pass == NULL) { wlr_log_errno(WLR_ERROR, "failed to allocate wlr_vk_render_rect_pass"); return NULL; } - wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); + pass->renderer = renderer; + pass->shader.vert_module = vulkan_create_common_vert_module(renderer); + if (pass->shader.vert_module == VK_NULL_HANDLE) { + render_rect_pass_destroy(&pass->base); + return NULL; + } + + VkDevice dev = renderer->dev->dev; + if (!create_shader_module(dev, quad_frag_data, sizeof(quad_frag_data), + "quad fragment", &pass->shader.frag_module)) { + render_rect_pass_destroy(&pass->base); + return NULL; + } + return &pass->base; } @@ -1407,6 +1471,14 @@ struct wlr_vk_render_rect_pass *wlr_vk_render_rect_pass_from_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); + if (vk_pass->shader.vert_module != VK_NULL_HANDLE) { + vkDestroyShaderModule(vk_pass->renderer->dev->dev, + vk_pass->shader.vert_module, NULL); + } + if (vk_pass->shader.frag_module != VK_NULL_HANDLE) { + vkDestroyShaderModule(vk_pass->renderer->dev->dev, + vk_pass->shader.frag_module, NULL); + } free(vk_pass); } @@ -1415,15 +1487,30 @@ static const struct wlr_render_texture_pass_impl render_texture_pass_impl = { .render = render_pass_add_texture, }; -struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create(void) { +struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create( + struct wlr_renderer *wlr_renderer) { 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); + struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); + pass->renderer = renderer; + pass->shader.vert_module = vulkan_create_common_vert_module(renderer); + if (pass->shader.vert_module == VK_NULL_HANDLE) { + render_texture_pass_destroy(&pass->base); + return NULL; + } + + VkDevice dev = renderer->dev->dev; + if (!create_shader_module(dev, texture_frag_data, sizeof(texture_frag_data), + "texture fragment", &pass->shader.frag_module)) { + render_texture_pass_destroy(&pass->base); + return NULL; + } + return &pass->base; } bool wlr_render_texture_pass_is_vk(const struct wlr_render_texture_pass *texture_pass) { @@ -1444,6 +1531,24 @@ struct wlr_vk_render_texture_pass *wlr_vk_render_texture_pass_from_pass( static void render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { struct wlr_vk_render_submit_pass *vk_pass = wlr_vk_render_submit_pass_from_pass(pass); + VkDevice dev = vk_pass->renderer->dev->dev; + + struct wlr_vk_descriptor_pool *pool, *tmp_pool; + wl_list_for_each_safe(pool, tmp_pool, &vk_pass->output.descriptor_pools, link) { + vkDestroyDescriptorPool(dev, pool->pool, NULL); + free(pool); + } + + vkDestroyShaderModule(dev, vk_pass->output.vert_module, NULL); + vkDestroyShaderModule(dev, vk_pass->output.frag_module, NULL); + vkDestroyImageView(dev, vk_pass->output.dummy3d_image_view, NULL); + vkDestroyImage(dev, vk_pass->output.dummy3d_image, NULL); + vkFreeMemory(dev, vk_pass->output.dummy3d_mem, NULL); + vkDestroyPipelineLayout(dev, vk_pass->output.pipe_layout, NULL); + vkDestroyDescriptorSetLayout(dev, vk_pass->output.ds_srgb_layout, NULL); + vkDestroyDescriptorSetLayout(dev, vk_pass->output.ds_lut3d_layout, NULL); + vkDestroySampler(dev, vk_pass->output.sampler_lut3d, NULL); + free(vk_pass); } @@ -1452,7 +1557,8 @@ static const struct wlr_render_submit_pass_impl vk_render_submit_pass_impl = { .render = render_pass_submit, }; -struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create(void) { +struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create( + struct wlr_renderer *wlr_renderer) { struct wlr_vk_render_submit_pass *pass = calloc(1, sizeof(*pass)); if (pass == NULL) { wlr_log_errno(WLR_ERROR, "failed to allocate wlr_vk_render_submit_pass"); @@ -1460,6 +1566,13 @@ struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create(void) { } wlr_render_submit_pass_init(&pass->base, &vk_render_submit_pass_impl); + pass->renderer = vulkan_get_renderer(wlr_renderer); + wl_list_init(&pass->output.descriptor_pools); + + if (!vulkan_init_submit_pass_output(pass->renderer, pass)) { + render_submit_pass_destroy(&pass->base); + return NULL; + } return &pass->base; } diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 52c87e9e2..4b13dc047 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -23,8 +23,6 @@ #include "render/pixel_format.h" #include "render/vulkan.h" #include "render/vulkan/shaders/common.vert.h" -#include "render/vulkan/shaders/texture.frag.h" -#include "render/vulkan/shaders/quad.frag.h" #include "render/vulkan/shaders/output.frag.h" #include "types/wlr_buffer.h" #include "util/time.h" @@ -56,6 +54,23 @@ struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *wlr_renderer) { return renderer; } +VkShaderModule vulkan_create_common_vert_module(struct wlr_vk_renderer *renderer) { + VkShaderModuleCreateInfo sinfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = sizeof(common_vert_data), + .pCode = common_vert_data, + }; + + VkShaderModule module = VK_NULL_HANDLE; + VkResult res = vkCreateShaderModule(renderer->dev->dev, &sinfo, NULL, &module); + if (res != VK_SUCCESS) { + wlr_vk_error("Failed to create vertex shader module", res); + return VK_NULL_HANDLE; + } + + return module; +} + static struct wlr_vk_render_format_setup *find_or_create_render_setup( struct wlr_vk_renderer *renderer, const struct wlr_vk_format *format, bool has_blending_buffer, bool srgb); @@ -152,9 +167,14 @@ struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds( struct wlr_vk_descriptor_pool *vulkan_alloc_blend_ds( struct wlr_vk_renderer *renderer, VkDescriptorSet *ds) { + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass);; + assert(submit_pass != NULL); + return alloc_ds(renderer, ds, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - &renderer->output_ds_srgb_layout, &renderer->output_descriptor_pools, - &renderer->last_output_pool_size); + &submit_pass->output.ds_srgb_layout, + &submit_pass->output.descriptor_pools, + &submit_pass->output.last_pool_size); } void vulkan_free_ds(struct wlr_vk_renderer *renderer, @@ -1172,15 +1192,6 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) { vkDestroyDescriptorPool(dev->dev, pool->pool, NULL); free(pool); } - wl_list_for_each_safe(pool, tmp_pool, &renderer->output_descriptor_pools, link) { - vkDestroyDescriptorPool(dev->dev, pool->pool, NULL); - free(pool); - } - - vkDestroyShaderModule(dev->dev, renderer->vert_module, NULL); - vkDestroyShaderModule(dev->dev, renderer->tex_frag_module, NULL); - vkDestroyShaderModule(dev->dev, renderer->quad_frag_module, NULL); - vkDestroyShaderModule(dev->dev, renderer->output_module, NULL); struct wlr_vk_pipeline_layout *pipeline_layout, *pipeline_layout_tmp; wl_list_for_each_safe(pipeline_layout, pipeline_layout_tmp, @@ -1192,16 +1203,8 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) { free(pipeline_layout); } - vkDestroyImageView(dev->dev, renderer->dummy3d_image_view, NULL); - vkDestroyImage(dev->dev, renderer->dummy3d_image, NULL); - vkFreeMemory(dev->dev, renderer->dummy3d_mem, NULL); - vkDestroySemaphore(dev->dev, renderer->timeline_semaphore, NULL); - vkDestroyPipelineLayout(dev->dev, renderer->output_pipe_layout, NULL); - vkDestroyDescriptorSetLayout(dev->dev, renderer->output_ds_srgb_layout, NULL); - vkDestroyDescriptorSetLayout(dev->dev, renderer->output_ds_lut3d_layout, NULL); vkDestroyCommandPool(dev->dev, renderer->command_pool, NULL); - vkDestroySampler(dev->dev, renderer->output_sampler_lut3d, NULL); if (renderer->read_pixels_cache.initialized) { vkFreeMemory(dev->dev, renderer->read_pixels_cache.dst_img_memory, NULL); @@ -1551,7 +1554,8 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer, return true; } -static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { +static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass) { VkResult res; VkDevice dev = renderer->dev->dev; @@ -1569,7 +1573,8 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { .pBindings = &ds_binding_input, }; - res = vkCreateDescriptorSetLayout(dev, &ds_info, NULL, &renderer->output_ds_srgb_layout); + res = vkCreateDescriptorSetLayout(dev, &ds_info, NULL, + &submit_pass->output.ds_srgb_layout); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateDescriptorSetLayout", res); return false; @@ -1588,7 +1593,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { }; res = vkCreateSampler(renderer->dev->dev, &sampler_create_info, NULL, - &renderer->output_sampler_lut3d); + &submit_pass->output.sampler_lut3d); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateSampler", res); return false; @@ -1599,7 +1604,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = &renderer->output_sampler_lut3d, + .pImmutableSamplers = &submit_pass->output.sampler_lut3d, }; VkDescriptorSetLayoutCreateInfo ds_lut3d_info = { @@ -1609,7 +1614,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { }; res = vkCreateDescriptorSetLayout(dev, &ds_lut3d_info, NULL, - &renderer->output_ds_lut3d_layout); + &submit_pass->output.ds_lut3d_layout); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateDescriptorSetLayout", res); return false; @@ -1630,8 +1635,8 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { }; VkDescriptorSetLayout out_ds_layouts[] = { - renderer->output_ds_srgb_layout, - renderer->output_ds_lut3d_layout, + submit_pass->output.ds_srgb_layout, + submit_pass->output.ds_lut3d_layout, }; VkPipelineLayoutCreateInfo pl_info = { @@ -1642,7 +1647,8 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { .pPushConstantRanges = pc_ranges, }; - res = vkCreatePipelineLayout(dev, &pl_info, NULL, &renderer->output_pipe_layout); + res = vkCreatePipelineLayout(dev, &pl_info, NULL, + &submit_pass->output.pipe_layout); if (res != VK_SUCCESS) { wlr_vk_error("vkCreatePipelineLayout", res); return false; @@ -1696,7 +1702,8 @@ static bool pipeline_key_equals(const struct wlr_vk_pipeline_key *a, // VkRenderPass and VkPipelineLayout. struct wlr_vk_pipeline *setup_get_or_create_pipeline( struct wlr_vk_render_format_setup *setup, - const struct wlr_vk_pipeline_key *key) { + const struct wlr_vk_pipeline_key *key, + VkShaderModule vert_module, VkShaderModule frag_module) { struct wlr_vk_pipeline *pipeline; wl_list_for_each(pipeline, &setup->pipelines, link) { if (pipeline_key_equals(&pipeline->key, key)) { @@ -1743,7 +1750,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline( stages[0] = (VkPipelineShaderStageCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = renderer->vert_module, + .module = vert_module, .pName = "main", }; @@ -1752,7 +1759,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline( stages[1] = (VkPipelineShaderStageCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = renderer->quad_frag_module, + .module = frag_module, .pName = "main", }; break; @@ -1760,7 +1767,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline( stages[1] = (VkPipelineShaderStageCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = renderer->tex_frag_module, + .module = frag_module, .pName = "main", .pSpecializationInfo = &specialization, }; @@ -1857,6 +1864,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline( } static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass, VkRenderPass rp, VkPipelineLayout pipe_layout, VkPipeline *pipe, enum wlr_vk_output_transform transform) { VkResult res; @@ -1879,13 +1887,13 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer, { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = renderer->vert_module, + .module = submit_pass->output.vert_module, .pName = "main", }, { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = renderer->output_module, + .module = submit_pass->output.frag_module, .pName = "main", .pSpecializationInfo = &specialization, }, @@ -2089,7 +2097,8 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout( * the sampler, a valid descriptor set should be bound. Create that here, linked to * a 1x1x1 image. */ -static bool init_dummy_images(struct wlr_vk_renderer *renderer) { +static bool init_dummy_images(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass) { VkResult res; VkDevice dev = renderer->dev->dev; @@ -2108,14 +2117,14 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) { .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = VK_IMAGE_USAGE_SAMPLED_BIT, }; - res = vkCreateImage(dev, &img_info, NULL, &renderer->dummy3d_image); + res = vkCreateImage(dev, &img_info, NULL, &submit_pass->output.dummy3d_image); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateImage failed", res); return false; } VkMemoryRequirements mem_reqs = {0}; - vkGetImageMemoryRequirements(dev, renderer->dummy3d_image, &mem_reqs); + vkGetImageMemoryRequirements(dev, submit_pass->output.dummy3d_image, &mem_reqs); int mem_type_index = vulkan_find_mem_type(renderer->dev, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_reqs.memoryTypeBits); if (mem_type_index == -1) { @@ -2127,12 +2136,13 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) { .allocationSize = mem_reqs.size, .memoryTypeIndex = mem_type_index, }; - res = vkAllocateMemory(dev, &mem_info, NULL, &renderer->dummy3d_mem); + res = vkAllocateMemory(dev, &mem_info, NULL, &submit_pass->output.dummy3d_mem); if (res != VK_SUCCESS) { wlr_vk_error("vkAllocateMemory failed", res); return false; } - res = vkBindImageMemory(dev, renderer->dummy3d_image, renderer->dummy3d_mem, 0); + res = vkBindImageMemory(dev, submit_pass->output.dummy3d_image, + submit_pass->output.dummy3d_mem, 0); if (res != VK_SUCCESS) { wlr_vk_error("vkBindMemory failed", res); return false; @@ -2153,29 +2163,31 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) { .baseArrayLayer = 0, .layerCount = 1, }, - .image = renderer->dummy3d_image, + .image = submit_pass->output.dummy3d_image, }; - res = vkCreateImageView(dev, &view_info, NULL, &renderer->dummy3d_image_view); + res = vkCreateImageView(dev, &view_info, NULL, + &submit_pass->output.dummy3d_image_view); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateImageView failed", res); return false; } - renderer->output_ds_lut3d_dummy_pool = vulkan_alloc_texture_ds(renderer, - renderer->output_ds_lut3d_layout, &renderer->output_ds_lut3d_dummy); - if (!renderer->output_ds_lut3d_dummy_pool) { + submit_pass->output.ds_lut3d_dummy_pool = vulkan_alloc_texture_ds(renderer, + submit_pass->output.ds_lut3d_layout, + &submit_pass->output.ds_lut3d_dummy); + if (!submit_pass->output.ds_lut3d_dummy_pool) { wlr_log(WLR_ERROR, "Failed to allocate descriptor"); return false; } VkDescriptorImageInfo ds_img_info = { - .imageView = renderer->dummy3d_image_view, + .imageView = submit_pass->output.dummy3d_image_view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; VkWriteDescriptorSet ds_write = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .dstSet = renderer->output_ds_lut3d_dummy, + .dstSet = submit_pass->output.ds_lut3d_dummy, .pImageInfo = &ds_img_info, }; vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL); @@ -2183,53 +2195,30 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) { return true; } -// Creates static render data, such as sampler, layouts and shader modules -// for the given renderer. -// Cleanup is done by destroying the renderer. -static bool init_static_render_data(struct wlr_vk_renderer *renderer) { +// Creates static blend->output render data for the given submit pass. +// Cleanup is done by destroying the submit pass. +bool vulkan_init_submit_pass_output(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass) { + VkResult res; VkDevice dev = renderer->dev->dev; - if (!init_blend_to_output_layouts(renderer)) { + if (!init_blend_to_output_layouts(renderer, submit_pass)) { return false; } - if (!init_dummy_images(renderer)) { + if (!init_dummy_images(renderer, submit_pass)) { return false; } - // load vert module and tex frag module since they are needed to - // initialize the tex pipeline VkShaderModuleCreateInfo sinfo = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .codeSize = sizeof(common_vert_data), .pCode = common_vert_data, }; - res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->vert_module); + res = vkCreateShaderModule(dev, &sinfo, NULL, &submit_pass->output.vert_module); if (res != VK_SUCCESS) { - wlr_vk_error("Failed to create vertex shader module", res); - return false; - } - - sinfo = (VkShaderModuleCreateInfo){ - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = sizeof(texture_frag_data), - .pCode = texture_frag_data, - }; - res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->tex_frag_module); - if (res != VK_SUCCESS) { - wlr_vk_error("Failed to create tex fragment shader module", res); - return false; - } - - sinfo = (VkShaderModuleCreateInfo){ - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = sizeof(quad_frag_data), - .pCode = quad_frag_data, - }; - res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->quad_frag_module); - if (res != VK_SUCCESS) { - wlr_vk_error("Failed to create quad fragment shader module", res); + wlr_vk_error("Failed to create blend->output vertex shader module", res); return false; } @@ -2238,7 +2227,7 @@ static bool init_static_render_data(struct wlr_vk_renderer *renderer) { .codeSize = sizeof(output_frag_data), .pCode = output_frag_data, }; - res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->output_module); + res = vkCreateShaderModule(dev, &sinfo, NULL, &submit_pass->output.frag_module); if (res != VK_SUCCESS) { wlr_vk_error("Failed to create blend->output fragment shader module", res); return false; @@ -2275,6 +2264,12 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( VkResult res; if (use_blending_buffer) { + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass);; + if (submit_pass == NULL) { + goto error; + } + VkAttachmentDescription attachments[] = { { .format = VK_FORMAT_R16G16B16A16_SFLOAT, @@ -2386,32 +2381,38 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( // this is only well defined if render pass has a 2nd subpass if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_identity, WLR_VK_OUTPUT_TRANSFORM_IDENTITY)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_lut3d, WLR_VK_OUTPUT_TRANSFORM_LUT3D)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_srgb, WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_pq, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_gamma22, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_bt1886, WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886)) { goto error; } @@ -2488,29 +2489,6 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( } } - if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ - .source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR, - .layout = {0}, - })) { - goto error; - } - - if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ - .source = WLR_VK_SHADER_SOURCE_TEXTURE, - .texture_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY, - .layout = {0}, - })) { - goto error; - } - - if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ - .source = WLR_VK_SHADER_SOURCE_TEXTURE, - .texture_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB, - .layout = {0}, - })) { - goto error; - } - wl_list_insert(&renderer->render_format_setups, &setup->link); return setup; @@ -2535,7 +2513,6 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev wl_list_init(&renderer->foreign_textures); wl_list_init(&renderer->textures); wl_list_init(&renderer->descriptor_pools); - wl_list_init(&renderer->output_descriptor_pools); wl_list_init(&renderer->render_format_setups); wl_list_init(&renderer->render_buffers); wl_list_init(&renderer->color_transforms); @@ -2551,10 +2528,6 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev renderer->wlr_renderer.features.timeline = dev->sync_file_import_export && cap_syncobj_timeline != 0; } - if (!init_static_render_data(renderer)) { - goto error; - } - VkCommandPoolCreateInfo cpool_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, From a1861c8295b700eee882a85504260c15d5cbd7c0 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Fri, 20 Mar 2026 10:37:22 +0800 Subject: [PATCH 6/8] include: install internal render headers for external consumers --- include/meson.build | 23 +++++++++++++++++++++++ tinywl/Makefile | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/meson.build b/include/meson.build index 165166c33..2881b97c1 100644 --- a/include/meson.build +++ b/include/meson.build @@ -29,6 +29,29 @@ install_subdir('wlr', exclude_files: exclude_files, ) +internal_render_headers = [ + 'render/pixman.h', + 'render/pixel_format.h', +] +if features.get('gles2-renderer') + internal_render_headers += [ + 'render/egl.h', + 'render/gles2.h', + ] +endif +if features.get('vulkan-renderer') + internal_render_headers += 'render/vulkan.h' +endif + +install_headers(internal_render_headers, + subdir: versioned_name, + preserve_path: true, +) + +install_headers('util/rect_union.h', + subdir: versioned_name / 'util', +) + foreach name, have : internal_features internal_config.set10('HAVE_' + name.underscorify().to_upper(), have) endforeach diff --git a/tinywl/Makefile b/tinywl/Makefile index 0f1c4cb13..c8f38d999 100644 --- a/tinywl/Makefile +++ b/tinywl/Makefile @@ -1,8 +1,9 @@ PKG_CONFIG?=pkg-config PKGS="wlroots-0.21" wayland-server xkbcommon +CFLAGS_PIXMAN!=$(PKG_CONFIG) --cflags pixman-1 CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS) -CFLAGS+=$(CFLAGS_PKG_CONFIG) +CFLAGS+=$(CFLAGS_PIXMAN) $(CFLAGS_PKG_CONFIG) LIBS!=$(PKG_CONFIG) --libs $(PKGS) all: tinywl From 53630a0a6086739187970ff4dcea351530474cf2 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Mon, 23 Mar 2026 21:04:32 +0800 Subject: [PATCH 7/8] render: unify render pass accessors Introduce helper functions to retrieve backend-specific render passes from struct wlr_render_pass and replace ad-hoc internal accessors. --- include/render/gles2.h | 14 +++++--- include/render/pixman.h | 2 ++ include/wlr/render/interface.h | 2 ++ render/gles2/pass.c | 65 +++++++++++++++++----------------- render/gles2/renderer.c | 44 +++++++++++------------ render/gles2/texture.c | 28 +++++++-------- render/pixman/pass.c | 11 +++--- render/vulkan/pass.c | 11 +++--- 8 files changed, 94 insertions(+), 83 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index efdb6599d..a2479e82e 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -139,7 +139,7 @@ void get_gles2_shm_formats(const struct wlr_gles2_renderer *renderer, GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer); -struct wlr_gles2_renderer *gles2_get_renderer( +struct wlr_gles2_renderer *wlr_gles2_renderer_from_renderer( struct wlr_renderer *wlr_renderer); struct wlr_gles2_render_timer *gles2_get_render_timer( struct wlr_render_timer *timer); @@ -152,10 +152,10 @@ struct wlr_texture *gles2_texture_from_buffer(struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer); void gles2_texture_destroy(struct wlr_gles2_texture *texture); -void push_gles2_debug_(struct wlr_gles2_renderer *renderer, +void wlr_gles2_push_debug_(struct wlr_gles2_renderer *renderer, const char *file, const char *func); -#define push_gles2_debug(renderer) push_gles2_debug_(renderer, _WLR_FILENAME, __func__) -void pop_gles2_debug(struct wlr_gles2_renderer *renderer); +#define wlr_gles2_push_debug(renderer) wlr_gles2_push_debug_(renderer, _WLR_FILENAME, __func__) +void wlr_gles2_pop_debug(struct wlr_gles2_renderer *renderer); struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer, struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer, @@ -198,7 +198,11 @@ bool wlr_render_submit_pass_is_gles2(const struct wlr_render_submit_pass *submit struct wlr_gles2_render_submit_pass *wlr_gles2_render_submit_pass_from_pass( struct wlr_render_submit_pass *submit_pass); -GLuint gles2_link_program(struct wlr_gles2_renderer *renderer, +GLuint wlr_gles2_link_program(struct wlr_gles2_renderer *renderer, const GLchar *vert_src, const GLchar *frag_src); +struct wlr_gles2_render_pass *wlr_gles2_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass); +void wlr_gles_set_proj_matrix(GLint loc, float proj[9], const struct wlr_box *box); + #endif diff --git a/include/render/pixman.h b/include/render/pixman.h index 3fd9ceb3b..7e60b5f4a 100644 --- a/include/render/pixman.h +++ b/include/render/pixman.h @@ -84,5 +84,7 @@ struct wlr_pixman_render_submit_pass { bool wlr_render_submit_pass_is_pixman(const struct wlr_render_submit_pass *submit_pass); struct wlr_pixman_render_submit_pass *wlr_pixman_render_submit_pass_from_pass( struct wlr_render_submit_pass *submit_pass); +struct wlr_pixman_render_pass *wlr_pixman_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass); #endif diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 13b34a70e..89ce62171 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -165,5 +165,7 @@ struct wlr_render_submit_pass *wlr_pixman_render_submit_pass_create(void); struct wlr_render_submit_pass *wlr_gles2_render_submit_pass_create(void); struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create( struct wlr_renderer *wlr_renderer); +struct wlr_vk_render_pass *wlr_vk_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass); #endif diff --git a/render/gles2/pass.c b/render/gles2/pass.c index a33d9a73b..b832ad11f 100644 --- a/render/gles2/pass.c +++ b/render/gles2/pass.c @@ -19,19 +19,20 @@ static const struct wlr_render_pass_impl render_pass_impl; -static struct wlr_gles2_render_pass *get_render_pass(struct wlr_render_pass *wlr_pass) { +struct wlr_gles2_render_pass *wlr_gles2_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass) { assert(wlr_pass->impl == &render_pass_impl); struct wlr_gles2_render_pass *pass = wl_container_of(wlr_pass, pass, base); return pass; } static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { - struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_gles2_render_pass *pass = wlr_gles2_render_pass_from_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; struct wlr_gles2_render_timer *timer = pass->timer; bool ok = false; - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); if (timer) { // clear disjoint flag @@ -71,7 +72,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { out: glBindFramebuffer(GL_FRAMEBUFFER, 0); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); wlr_egl_restore_context(&pass->prev_ctx); wlr_drm_syncobj_timeline_unref(pass->signal_timeline); @@ -130,7 +131,7 @@ static void render(const struct wlr_box *box, const pixman_region32_t *clip, GLi pixman_region32_fini(®ion); } -static void set_proj_matrix(GLint loc, float proj[9], const struct wlr_box *box) { +void wlr_gles_set_proj_matrix(GLint loc, float proj[9], const struct wlr_box *box) { float gl_matrix[9]; wlr_matrix_identity(gl_matrix); wlr_matrix_translate(gl_matrix, box->x, box->y); @@ -172,7 +173,7 @@ static void setup_blending(enum wlr_render_blend_mode mode) { static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, const struct wlr_render_texture_options *options) { - struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_gles2_render_pass *pass = wlr_gles2_render_pass_from_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; struct wlr_gles2_texture *texture = gles2_get_texture(options->texture); struct wlr_gles2_render_texture_pass *texture_pass = @@ -208,7 +209,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, src_fbox.width /= options->texture->width; src_fbox.height /= options->texture->height; - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); if (options->wait_timeline != NULL) { int sync_file_fd = @@ -251,18 +252,18 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, glUniform1i(shader->tex, 0); glUniform1f(shader->alpha, alpha); - set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box); + wlr_gles_set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box); set_tex_matrix(shader->tex_proj, options->transform, &src_fbox); render(&dst_box, options->clip, shader->pos_attrib); glBindTexture(texture->target, 0); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); } static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, const struct wlr_render_rect_options *options) { - struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_gles2_render_pass *pass = wlr_gles2_render_pass_from_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; struct wlr_gles2_render_rect_pass *rect_pass = wlr_gles2_render_rect_pass_from_pass(renderer->wlr_renderer.rect_pass); @@ -272,7 +273,7 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, struct wlr_buffer *wlr_buffer = pass->buffer->buffer; wlr_render_rect_options_get_box(options, wlr_buffer, &box); - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); enum wlr_render_blend_mode blend_mode = color->a == 1.0 ? WLR_RENDER_BLEND_MODE_NONE : options->blend_mode; if (blend_mode == WLR_RENDER_BLEND_MODE_NONE && @@ -285,12 +286,12 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, } else { setup_blending(blend_mode); glUseProgram(rect_pass->shader.program); - set_proj_matrix(rect_pass->shader.proj, pass->projection_matrix, &box); + wlr_gles_set_proj_matrix(rect_pass->shader.proj, pass->projection_matrix, &box); glUniform4f(rect_pass->shader.color, color->r, color->g, color->b, color->a); render(&box, options->clip, rect_pass->shader.pos_attrib); } - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); } static void render_pass_destory(struct wlr_render_pass *wlr_pass) { @@ -298,7 +299,7 @@ static void render_pass_destory(struct wlr_render_pass *wlr_pass) { } static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { - struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_gles2_render_pass *pass = wlr_gles2_render_pass_from_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; return &renderer->wlr_renderer; @@ -360,13 +361,13 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b matrix_projection(pass->projection_matrix, wlr_buffer->width, wlr_buffer->height, WL_OUTPUT_TRANSFORM_FLIPPED_180); - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, wlr_buffer->width, wlr_buffer->height); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_SCISSOR_TEST); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); return pass; } @@ -374,9 +375,9 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { struct wlr_gles2_render_rect_pass *gles2_pass = wlr_gles2_render_rect_pass_from_pass(pass); - push_gles2_debug(gles2_pass->renderer); + wlr_gles2_push_debug(gles2_pass->renderer); glDeleteProgram(gles2_pass->shader.program); - pop_gles2_debug(gles2_pass->renderer); + wlr_gles2_pop_debug(gles2_pass->renderer); free(gles2_pass); } @@ -393,17 +394,17 @@ struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create( return NULL; } - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); if (!wlr_egl_make_current(renderer->egl, NULL)) { free(pass); return NULL; } wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); GLuint prog; pass->shader.program = prog = - gles2_link_program(renderer, common_vert_src, quad_frag_src); + wlr_gles2_link_program(renderer, common_vert_src, quad_frag_src); if (!pass->shader.program) { goto error; } @@ -411,14 +412,14 @@ struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create( pass->shader.proj = glGetUniformLocation(pass->shader.program, "proj"); pass->shader.color = glGetUniformLocation(pass->shader.program, "color"); pass->shader.pos_attrib = glGetAttribLocation(pass->shader.program, "pos"); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); wlr_egl_unset_current(renderer->egl); pass->renderer = renderer; return &pass->base; error: render_rect_pass_destroy(&pass->base); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); wlr_egl_unset_current(renderer->egl); return NULL; @@ -443,11 +444,11 @@ struct wlr_gles2_render_rect_pass *wlr_gles2_render_rect_pass_from_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); - push_gles2_debug(gles2_pass->renderer); + wlr_gles2_push_debug(gles2_pass->renderer); glDeleteProgram(gles2_pass->shaders.tex_rgba.program); glDeleteProgram(gles2_pass->shaders.tex_rgbx.program); glDeleteProgram(gles2_pass->shaders.tex_ext.program); - pop_gles2_debug(gles2_pass->renderer); + wlr_gles2_pop_debug(gles2_pass->renderer); free(gles2_pass); } @@ -464,15 +465,15 @@ struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( return NULL; } wlr_render_texture_pass_init(&pass->base, &render_texture_pass_impl); - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); if (!wlr_egl_make_current(renderer->egl, NULL)) { free(pass); return NULL; } - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); GLuint prog; pass->shaders.tex_rgba.program = prog = - gles2_link_program(renderer, common_vert_src, tex_rgba_frag_src); + wlr_gles2_link_program(renderer, common_vert_src, tex_rgba_frag_src); if (!pass->shaders.tex_rgba.program) { goto error; } @@ -483,7 +484,7 @@ struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( pass->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); pass->shaders.tex_rgbx.program = prog = - gles2_link_program(renderer, common_vert_src, tex_rgbx_frag_src); + wlr_gles2_link_program(renderer, common_vert_src, tex_rgbx_frag_src); if (!pass->shaders.tex_rgbx.program) { goto error; } @@ -495,7 +496,7 @@ struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( if (renderer->exts.OES_egl_image_external) { pass->shaders.tex_ext.program = prog = - gles2_link_program(renderer, common_vert_src, tex_external_frag_src); + wlr_gles2_link_program(renderer, common_vert_src, tex_external_frag_src); if (!pass->shaders.tex_ext.program) { goto error; } @@ -506,7 +507,7 @@ struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( pass->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos"); } - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); wlr_egl_unset_current(renderer->egl); pass->renderer = renderer; @@ -514,7 +515,7 @@ struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( error: render_texture_pass_destroy(&pass->base); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); wlr_egl_unset_current(renderer->egl); return NULL; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 010623354..9c8a4955c 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -27,7 +27,7 @@ bool wlr_renderer_is_gles2(const struct wlr_renderer *wlr_renderer) { return wlr_renderer->impl == &renderer_impl; } -struct wlr_gles2_renderer *gles2_get_renderer( +struct wlr_gles2_renderer *wlr_gles2_renderer_from_renderer( struct wlr_renderer *wlr_renderer) { assert(wlr_renderer_is_gles2(wlr_renderer)); struct wlr_gles2_renderer *renderer = wl_container_of(wlr_renderer, renderer, wlr_renderer); @@ -51,13 +51,13 @@ static void destroy_buffer(struct wlr_gles2_buffer *buffer) { struct wlr_egl_context prev_ctx; wlr_egl_make_current(buffer->renderer->egl, &prev_ctx); - push_gles2_debug(buffer->renderer); + wlr_gles2_push_debug(buffer->renderer); glDeleteFramebuffers(1, &buffer->fbo); glDeleteRenderbuffers(1, &buffer->rbo); glDeleteTextures(1, &buffer->tex); - pop_gles2_debug(buffer->renderer); + wlr_gles2_pop_debug(buffer->renderer); wlr_egl_destroy_image(buffer->renderer->egl, buffer->image); @@ -87,7 +87,7 @@ GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer) { return buffer->fbo; } - push_gles2_debug(buffer->renderer); + wlr_gles2_push_debug(buffer->renderer); if (!buffer->rbo) { glGenRenderbuffers(1, &buffer->rbo); @@ -110,7 +110,7 @@ GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer) { buffer->fbo = 0; } - pop_gles2_debug(buffer->renderer); + wlr_gles2_pop_debug(buffer->renderer); return buffer->fbo; } @@ -160,7 +160,7 @@ error_buffer: static const struct wlr_drm_format_set *gles2_get_texture_formats( struct wlr_renderer *wlr_renderer, uint32_t buffer_caps) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); if (buffer_caps & WLR_BUFFER_CAP_DMABUF) { return wlr_egl_get_dmabuf_texture_formats(renderer->egl); } else if (buffer_caps & WLR_BUFFER_CAP_DATA_PTR) { @@ -172,13 +172,13 @@ static const struct wlr_drm_format_set *gles2_get_texture_formats( static const struct wlr_drm_format_set *gles2_get_render_formats( struct wlr_renderer *wlr_renderer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); return wlr_egl_get_dmabuf_render_formats(renderer->egl); } static int gles2_get_drm_fd(struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = - gles2_get_renderer(wlr_renderer); + wlr_gles2_renderer_from_renderer(wlr_renderer); if (renderer->drm_fd < 0) { renderer->drm_fd = wlr_egl_dup_drm_fd(renderer->egl); @@ -189,12 +189,12 @@ static int gles2_get_drm_fd(struct wlr_renderer *wlr_renderer) { struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = - gles2_get_renderer(wlr_renderer); + wlr_gles2_renderer_from_renderer(wlr_renderer); return renderer->egl; } static void gles2_destroy(struct wlr_renderer *wlr_renderer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); wlr_egl_make_current(renderer->egl, NULL); @@ -227,7 +227,7 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { static struct wlr_render_pass *gles2_begin_buffer_pass(struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer, const struct wlr_buffer_pass_options *options) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); struct wlr_egl_context prev_ctx = {0}; if (!wlr_egl_make_current(renderer->egl, &prev_ctx)) { @@ -255,7 +255,7 @@ static struct wlr_render_pass *gles2_begin_buffer_pass(struct wlr_renderer *wlr_ GLuint wlr_gles2_renderer_get_buffer_fbo(struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); GLuint fbo = 0; struct wlr_egl_context prev_ctx = {0}; @@ -273,7 +273,7 @@ GLuint wlr_gles2_renderer_get_buffer_fbo(struct wlr_renderer *wlr_renderer, } static struct wlr_render_timer *gles2_render_timer_create(struct wlr_renderer *wlr_renderer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); if (!renderer->exts.EXT_disjoint_timer_query) { wlr_log(WLR_ERROR, "can't create timer, EXT_disjoint_timer_query not available"); return NULL; @@ -354,7 +354,7 @@ static const struct wlr_render_timer_impl render_timer_impl = { .destroy = gles2_render_timer_destroy, }; -void push_gles2_debug_(struct wlr_gles2_renderer *renderer, +void wlr_gles2_push_debug_(struct wlr_gles2_renderer *renderer, const char *file, const char *func) { if (!renderer->procs.glPushDebugGroupKHR) { return; @@ -366,7 +366,7 @@ void push_gles2_debug_(struct wlr_gles2_renderer *renderer, renderer->procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); } -void pop_gles2_debug(struct wlr_gles2_renderer *renderer) { +void wlr_gles2_pop_debug(struct wlr_gles2_renderer *renderer) { if (renderer->procs.glPopDebugGroupKHR) { renderer->procs.glPopDebugGroupKHR(); } @@ -394,7 +394,7 @@ static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity, static GLuint compile_shader(struct wlr_gles2_renderer *renderer, GLenum type, const GLchar *src) { - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &src, NULL); @@ -408,13 +408,13 @@ static GLuint compile_shader(struct wlr_gles2_renderer *renderer, shader = 0; } - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); return shader; } -GLuint gles2_link_program(struct wlr_gles2_renderer *renderer, +GLuint wlr_gles2_link_program(struct wlr_gles2_renderer *renderer, const GLchar *vert_src, const GLchar *frag_src) { - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); GLuint vert = compile_shader(renderer, GL_VERTEX_SHADER, vert_src); if (!vert) { @@ -445,11 +445,11 @@ GLuint gles2_link_program(struct wlr_gles2_renderer *renderer, goto error; } - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); return prog; error: - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); return 0; } @@ -631,6 +631,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { bool wlr_gles2_renderer_check_ext(struct wlr_renderer *wlr_renderer, const char *ext) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); return check_gl_ext(renderer->exts_str, ext); } diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 7460755cd..780978206 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -69,7 +69,7 @@ static bool gles2_texture_update_from_buffer(struct wlr_texture *wlr_texture, struct wlr_egl_context prev_ctx; wlr_egl_make_current(texture->renderer->egl, &prev_ctx); - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); glBindTexture(GL_TEXTURE_2D, texture->tex); @@ -95,7 +95,7 @@ static bool gles2_texture_update_from_buffer(struct wlr_texture *wlr_texture, glBindTexture(GL_TEXTURE_2D, 0); - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); wlr_egl_restore_context(&prev_ctx); @@ -112,12 +112,12 @@ void gles2_texture_destroy(struct wlr_gles2_texture *texture) { struct wlr_egl_context prev_ctx; wlr_egl_make_current(texture->renderer->egl, &prev_ctx); - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); glDeleteTextures(1, &texture->tex); glDeleteFramebuffers(1, &texture->fbo); - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); wlr_egl_restore_context(&prev_ctx); } @@ -191,7 +191,7 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture, return false; } - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); struct wlr_egl_context prev_ctx; if (!wlr_egl_make_current(texture->renderer->egl, &prev_ctx)) { return false; @@ -226,7 +226,7 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture, } wlr_egl_restore_context(&prev_ctx); - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); return glGetError() == GL_NO_ERROR; } @@ -234,7 +234,7 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture, static uint32_t gles2_texture_preferred_read_format(struct wlr_texture *wlr_texture) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); uint32_t fmt = DRM_FORMAT_INVALID; @@ -253,7 +253,7 @@ static uint32_t gles2_texture_preferred_read_format(struct wlr_texture *wlr_text glGetIntegerv(GL_ALPHA_BITS, &alpha_size); glBindFramebuffer(GL_FRAMEBUFFER, 0); - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); const struct wlr_gles2_pixel_format *pix_fmt = get_gles2_format_from_gl(gl_format, gl_type, alpha_size > 0); @@ -297,7 +297,7 @@ static struct wlr_texture *gles2_texture_from_pixels( struct wlr_renderer *wlr_renderer, uint32_t drm_format, uint32_t stride, uint32_t width, uint32_t height, const void *data) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_drm(drm_format); @@ -335,7 +335,7 @@ static struct wlr_texture *gles2_texture_from_pixels( struct wlr_egl_context prev_ctx; wlr_egl_make_current(renderer->egl, &prev_ctx); - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); glGenTextures(1, &texture->tex); glBindTexture(GL_TEXTURE_2D, texture->tex); @@ -349,7 +349,7 @@ static struct wlr_texture *gles2_texture_from_pixels( glBindTexture(GL_TEXTURE_2D, 0); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); wlr_egl_restore_context(&prev_ctx); @@ -381,7 +381,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf( struct wlr_egl_context prev_ctx; wlr_egl_make_current(renderer->egl, &prev_ctx); - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); bool invalid; if (!buffer->tex) { @@ -400,7 +400,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf( glBindTexture(texture->target, 0); } - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); wlr_egl_restore_context(&prev_ctx); texture->tex = buffer->tex; @@ -410,7 +410,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf( struct wlr_texture *gles2_texture_from_buffer(struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); void *data; uint32_t format; diff --git a/render/pixman/pass.c b/render/pixman/pass.c index 736e6d553..80660f412 100644 --- a/render/pixman/pass.c +++ b/render/pixman/pass.c @@ -7,7 +7,8 @@ static const struct wlr_render_pass_impl render_pass_impl; -static struct wlr_pixman_render_pass *get_render_pass(struct wlr_render_pass *wlr_pass) { +struct wlr_pixman_render_pass *wlr_pixman_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass) { assert(wlr_pass->impl == &render_pass_impl); struct wlr_pixman_render_pass *pass = wl_container_of(wlr_pass, pass, base); return pass; @@ -20,7 +21,7 @@ static struct wlr_pixman_texture *get_texture(struct wlr_texture *wlr_texture) { } static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { - struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_render_pass *pass = wlr_pixman_render_pass_from_render_pass(wlr_pass); wlr_buffer_end_data_ptr_access(pass->buffer->buffer); wlr_buffer_unlock(pass->buffer->buffer); @@ -41,7 +42,7 @@ static pixman_op_t get_pixman_blending(enum wlr_render_blend_mode mode) { static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, const struct wlr_render_texture_options *options) { - struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_render_pass *pass = wlr_pixman_render_pass_from_render_pass(wlr_pass); struct wlr_pixman_texture *texture = get_texture(options->texture); struct wlr_pixman_buffer *buffer = pass->buffer; @@ -203,7 +204,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, const struct wlr_render_rect_options *options) { - struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_render_pass *pass = wlr_pixman_render_pass_from_render_pass(wlr_pass); struct wlr_pixman_buffer *buffer = pass->buffer; struct wlr_box box; wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box); @@ -233,7 +234,7 @@ static void render_pass_destory(struct wlr_render_pass *wlr_pass) { } static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { - struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_render_pass *pass = wlr_pixman_render_pass_from_render_pass(wlr_pass); struct wlr_pixman_renderer *renderer = pass->buffer->renderer; return &renderer->wlr_renderer; diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 7373e935f..ceab5aae8 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -32,7 +32,8 @@ static bool create_shader_module(VkDevice dev, const uint32_t *code, return true; } -static struct wlr_vk_render_pass *get_render_pass(struct wlr_render_pass *wlr_pass) { +struct wlr_vk_render_pass *wlr_vk_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass) { assert(wlr_pass->impl == &render_pass_impl); struct wlr_vk_render_pass *pass = wl_container_of(wlr_pass, pass, base); return pass; @@ -240,7 +241,7 @@ static bool unwrap_color_transform(struct wlr_color_transform *transform, } static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { - struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_render_pass *pass = wlr_vk_render_pass_from_render_pass(wlr_pass); struct wlr_vk_renderer *renderer = pass->renderer; struct wlr_vk_render_submit_pass *submit_pass = wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass); @@ -705,7 +706,7 @@ static void render_pass_mark_box_updated(struct wlr_vk_render_pass *pass, static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, const struct wlr_render_rect_options *options) { - struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_render_pass *pass = wlr_vk_render_pass_from_render_pass(wlr_pass); struct wlr_vk_render_rect_pass *rect_pass = wlr_vk_render_rect_pass_from_pass(pass->renderer->wlr_renderer.rect_pass); assert(rect_pass != NULL); @@ -812,7 +813,7 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, const struct wlr_render_texture_options *options) { - struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_render_pass *pass = wlr_vk_render_pass_from_render_pass(wlr_pass); struct wlr_vk_renderer *renderer = pass->renderer; struct wlr_vk_render_texture_pass *texture_pass = wlr_vk_render_texture_pass_from_pass(renderer->wlr_renderer.texture_pass); @@ -1018,7 +1019,7 @@ static void render_pass_destory(struct wlr_render_pass *wlr_pass) { } static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { - struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_render_pass *pass = wlr_vk_render_pass_from_render_pass(wlr_pass); struct wlr_vk_renderer *renderer = pass->renderer; return &renderer->wlr_renderer; From 393f96274a79c65d6cbcc29e52db5adc300c1463 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Mon, 23 Mar 2026 21:09:13 +0800 Subject: [PATCH 8/8] examples: add render-pass-ext exmaple --- examples/meson.build | 2 + examples/render-pass-ext/gles2/meson.build | 6 + .../render-pass-ext/gles2/shaders/meson.build | 22 ++ .../gles2/shaders/triangle.frag | 11 + .../gles2/shaders/triangle.vert | 8 + .../render-pass-ext/gles2/triangle_pass.c | 135 ++++++++++++ .../render-pass-ext/gles2/triangle_pass.h | 27 +++ examples/render-pass-ext/meson.build | 26 +++ examples/render-pass-ext/pixman/meson.build | 3 + .../render-pass-ext/pixman/triangle_pass.c | 107 +++++++++ .../render-pass-ext/pixman/triangle_pass.h | 16 ++ examples/render-pass-ext/render-pass-ext.c | 206 ++++++++++++++++++ examples/render-pass-ext/triangle_pass.c | 95 ++++++++ examples/render-pass-ext/triangle_pass.h | 41 ++++ 14 files changed, 705 insertions(+) create mode 100644 examples/render-pass-ext/gles2/meson.build create mode 100644 examples/render-pass-ext/gles2/shaders/meson.build create mode 100644 examples/render-pass-ext/gles2/shaders/triangle.frag create mode 100644 examples/render-pass-ext/gles2/shaders/triangle.vert create mode 100644 examples/render-pass-ext/gles2/triangle_pass.c create mode 100644 examples/render-pass-ext/gles2/triangle_pass.h create mode 100644 examples/render-pass-ext/meson.build create mode 100644 examples/render-pass-ext/pixman/meson.build create mode 100644 examples/render-pass-ext/pixman/triangle_pass.c create mode 100644 examples/render-pass-ext/pixman/triangle_pass.h create mode 100644 examples/render-pass-ext/render-pass-ext.c create mode 100644 examples/render-pass-ext/triangle_pass.c create mode 100644 examples/render-pass-ext/triangle_pass.h diff --git a/examples/meson.build b/examples/meson.build index 28a83cccc..524c91d2d 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -49,6 +49,8 @@ compositors = { }, } +subdir('render-pass-ext') + foreach name, info : compositors extra_src = [] foreach p : info.get('proto', []) diff --git a/examples/render-pass-ext/gles2/meson.build b/examples/render-pass-ext/gles2/meson.build new file mode 100644 index 000000000..b317d51c6 --- /dev/null +++ b/examples/render-pass-ext/gles2/meson.build @@ -0,0 +1,6 @@ +subdir('shaders') + +gles2_sources = [ + files('triangle_pass.c'), + gles2_shader_sources, +] diff --git a/examples/render-pass-ext/gles2/shaders/meson.build b/examples/render-pass-ext/gles2/shaders/meson.build new file mode 100644 index 000000000..96a52bfca --- /dev/null +++ b/examples/render-pass-ext/gles2/shaders/meson.build @@ -0,0 +1,22 @@ +custom_pass_embed = find_program('../../../../render/gles2/shaders/embed.sh', native: true) +triangle_vert = custom_target( + 'custom-render-pass-triangle-vert', + command: [custom_pass_embed, 'custom_triangle_vert'], + input: 'triangle.vert', + output: 'triangle_vert.h', + feed: true, + capture: true, +) +triangle_frag = custom_target( + 'custom-render-pass-triangle-frag', + command: [custom_pass_embed, 'custom_triangle_frag'], + input: 'triangle.frag', + output: 'triangle_frag.h', + feed: true, + capture: true, +) + +gles2_shader_sources = [ + triangle_vert, + triangle_frag, +] diff --git a/examples/render-pass-ext/gles2/shaders/triangle.frag b/examples/render-pass-ext/gles2/shaders/triangle.frag new file mode 100644 index 000000000..0b0cbc968 --- /dev/null +++ b/examples/render-pass-ext/gles2/shaders/triangle.frag @@ -0,0 +1,11 @@ +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif + +varying vec3 v_color; + +void main() { + gl_FragColor = vec4(v_color, 1.0); +} diff --git a/examples/render-pass-ext/gles2/shaders/triangle.vert b/examples/render-pass-ext/gles2/shaders/triangle.vert new file mode 100644 index 000000000..e0c51f3c0 --- /dev/null +++ b/examples/render-pass-ext/gles2/shaders/triangle.vert @@ -0,0 +1,8 @@ +attribute vec2 pos; +attribute vec3 color; +varying vec3 v_color; + +void main() { + gl_Position = vec4(pos, 0.0, 1.0); + v_color = color; +} diff --git a/examples/render-pass-ext/gles2/triangle_pass.c b/examples/render-pass-ext/gles2/triangle_pass.c new file mode 100644 index 000000000..c7e53062f --- /dev/null +++ b/examples/render-pass-ext/gles2/triangle_pass.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include + +#include "triangle_pass.h" + +#include "triangle_vert.h" +#include "triangle_frag.h" + +static void custom_triangle_render(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options) { + struct wlr_gles2_render_pass *wlr_gles2_pass = + wlr_gles2_render_pass_from_render_pass(render_pass); + struct render_triangle_pass *base = + wlr_gles2_pass->buffer->renderer->wlr_renderer.data; + struct gles2_render_triangle_pass *triangle_pass = + gles2_render_triangle_pass_from_pass(base); + struct wlr_gles2_renderer *renderer = wlr_gles2_pass->buffer->renderer; + + struct wlr_box box; + struct wlr_buffer *wlr_buffer = wlr_gles2_pass->buffer->buffer; + custom_render_triangle_options_get_box(options, wlr_buffer, &box); + + int width = wlr_gles2_pass->buffer->buffer->width; + int height = wlr_gles2_pass->buffer->buffer->height; + + float x0 = options->box.x + options->box.width * 0.50f; + float y0 = options->box.y + options->box.height * 0.10f; + float x1 = options->box.x + options->box.width * 0.10f; + float y1 = options->box.y + options->box.height * 0.90f; + float x2 = options->box.x + options->box.width * 0.90f; + float y2 = options->box.y + options->box.height * 0.90f; + + GLfloat verts[3][5] = { + { x0 / width * 2.0f - 1.0f, 1.0f - y0 / height * 2.0f, 1.0f, 0.1f, 0.1f }, + { x1 / width * 2.0f - 1.0f, 1.0f - y1 / height * 2.0f, 0.1f, 1.0f, 0.1f }, + { x2 / width * 2.0f - 1.0f, 1.0f - y2 / height * 2.0f, 0.1f, 0.2f, 1.0f }, + }; + + wlr_gles2_push_debug(renderer); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + glUseProgram(triangle_pass->shader.program); + wlr_gles_set_proj_matrix(triangle_pass->shader.proj, wlr_gles2_pass->projection_matrix, &box); + glEnableVertexAttribArray(triangle_pass->shader.pos_attrib); + glVertexAttribPointer(triangle_pass->shader.pos_attrib, 2, GL_FLOAT, GL_FALSE, + 5 * sizeof(GLfloat), verts); + glEnableVertexAttribArray(triangle_pass->shader.color_attrib); + glVertexAttribPointer(triangle_pass->shader.color_attrib, 3, GL_FLOAT, GL_FALSE, + 5 * sizeof(GLfloat), &verts[0][2]); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(triangle_pass->shader.pos_attrib); + glDisableVertexAttribArray(triangle_pass->shader.color_attrib); + wlr_gles2_pop_debug(renderer); +} + +static void custom_triangle_destroy(struct render_triangle_pass *pass) { + struct gles2_render_triangle_pass *gles2_pass = + gles2_render_triangle_pass_from_pass(pass); + if (gles2_pass->shader.program != 0) { + glDeleteProgram(gles2_pass->shader.program); + } + + free(gles2_pass); +} + +static const struct render_triangle_pass_impl custom_triangle_impl = { + .destroy = custom_triangle_destroy, + .render = custom_triangle_render, +}; + +struct render_triangle_pass *gles2_render_triangle_pass_create( + struct wlr_renderer *wlr_renderer) { + struct gles2_render_triangle_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate gles2_render_triangle_pass"); + return NULL; + } + + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); + if (!wlr_egl_make_current(renderer->egl, NULL)) { + free(pass); + return NULL; + } + + render_triangle_pass_init(&pass->base, &custom_triangle_impl); + wlr_gles2_push_debug(renderer); + GLuint prog; + pass->shader.program = prog = + wlr_gles2_link_program(renderer, custom_triangle_vert, custom_triangle_frag); + if (!pass->shader.program) { + goto error; + } + + pass->shader.proj = -1; + pass->shader.color_attrib = glGetAttribLocation(pass->shader.program, "color"); + pass->shader.pos_attrib = glGetAttribLocation(pass->shader.program, "pos"); + if (pass->shader.pos_attrib < 0 || pass->shader.color_attrib < 0) { + wlr_log(WLR_ERROR, "triangle shader attribute lookup failed: pos=%d color=%d", + pass->shader.pos_attrib, pass->shader.color_attrib); + goto error; + } + wlr_gles2_pop_debug(renderer); + wlr_egl_unset_current(renderer->egl); + pass->renderer = renderer; + return &pass->base; + +error: + render_triangle_pass_destroy(&pass->base); + wlr_gles2_pop_debug(renderer); + wlr_egl_unset_current(renderer->egl); + + return NULL; +} + +bool render_triangle_pass_is_gles2(const struct render_triangle_pass *triangle_pass) { + return triangle_pass->impl == & custom_triangle_impl; +} + +struct gles2_render_triangle_pass *gles2_render_triangle_pass_from_pass( + struct render_triangle_pass *triangle_pass) { + if (!render_triangle_pass_is_gles2(triangle_pass)) { + return NULL; + } + + struct gles2_render_triangle_pass *gles2_pass = + wl_container_of(triangle_pass, gles2_pass, base); + + return gles2_pass; +} diff --git a/examples/render-pass-ext/gles2/triangle_pass.h b/examples/render-pass-ext/gles2/triangle_pass.h new file mode 100644 index 000000000..2e22339cc --- /dev/null +++ b/examples/render-pass-ext/gles2/triangle_pass.h @@ -0,0 +1,27 @@ +#ifndef GLES2_TRIANGLE_PASS_PASS_H +#define GLES2_TRIANGLE_PASS_PASS_H + +#include "../triangle_pass.h" + +#include + +#include + +struct gles2_render_triangle_pass { + struct render_triangle_pass base; + struct wlr_gles2_renderer *renderer; + struct { + GLuint program; + GLint proj; + GLint pos_attrib; + GLint color_attrib; + } shader; +}; + +struct render_triangle_pass *gles2_render_triangle_pass_create( + struct wlr_renderer *wlr_renderer); +bool render_triangle_pass_is_gles2(const struct render_triangle_pass *triangle_pass); +struct gles2_render_triangle_pass *gles2_render_triangle_pass_from_pass( + struct render_triangle_pass *triangle_pass); + +#endif // GLES2_TRIANGLE_PASS_PASS_H diff --git a/examples/render-pass-ext/meson.build b/examples/render-pass-ext/meson.build new file mode 100644 index 000000000..0ae142af6 --- /dev/null +++ b/examples/render-pass-ext/meson.build @@ -0,0 +1,26 @@ +gles2_sources = [] +pixman_sources = [] +vulkan_sources = [] + + if features.get('gles2-renderer') + subdir('gles2') + endif + +subdir('pixman') + +# if features.get('vulkan-renderer') +# subdir('vulkan') +# endif + +executable( + 'render-pass-ext', + [ + 'triangle_pass.c', + 'render-pass-ext.c', + gles2_sources, + pixman_sources, + vulkan_sources, + ], + dependencies: [wlroots, libdrm_header], + build_by_default: get_option('examples'), +) diff --git a/examples/render-pass-ext/pixman/meson.build b/examples/render-pass-ext/pixman/meson.build new file mode 100644 index 000000000..cdcd0763f --- /dev/null +++ b/examples/render-pass-ext/pixman/meson.build @@ -0,0 +1,3 @@ +pixman_sources = [ + files('triangle_pass.c'), +] diff --git a/examples/render-pass-ext/pixman/triangle_pass.c b/examples/render-pass-ext/pixman/triangle_pass.c new file mode 100644 index 000000000..3d4fada44 --- /dev/null +++ b/examples/render-pass-ext/pixman/triangle_pass.c @@ -0,0 +1,107 @@ +#include +#include + +#include +#include + +#include "render/pixman.h" +#include "triangle_pass.h" + +static bool triangle_contains(float px, float py, + float x0, float y0, float x1, float y1, float x2, float y2, + float *w0, float *w1, float *w2) { + float denom = (y1 - y2) * (x0 - x2) + (x2 - x1) * (y0 - y2); + if (denom == 0.0f) { + return false; + } + + *w0 = ((y1 - y2) * (px - x2) + (x2 - x1) * (py - y2)) / denom; + *w1 = ((y2 - y0) * (px - x2) + (x0 - x2) * (py - y2)) / denom; + *w2 = 1.0f - *w0 - *w1; + return *w0 >= 0.0f && *w1 >= 0.0f && *w2 >= 0.0f; +} + +static void custom_triangle_pixman_render(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options) { + struct wlr_pixman_render_pass *pixman_pass = + wlr_pixman_render_pass_from_render_pass(render_pass); + pixman_image_t *dst = pixman_pass->buffer->image; + int w = options->box.width; + int h = options->box.height; + if (w <= 0 || h <= 0) { + pixman_image_set_clip_region32(dst, NULL); + return; + } + + uint32_t *pixels = calloc((size_t)w * (size_t)h, sizeof(uint32_t)); + if (pixels == NULL) { + pixman_image_set_clip_region32(dst, NULL); + return; + } + + float x0 = w * 0.50f, y0 = h * 0.10f; + float x1 = w * 0.10f, y1 = h * 0.90f; + float x2 = w * 0.90f, y2 = h * 0.90f; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + float w0, w1, w2; + if (!triangle_contains(x + 0.5f, y + 0.5f, + x0, y0, x1, y1, x2, y2, &w0, &w1, &w2)) { + continue; + } + + uint8_t r = (uint8_t)(w0 * 255.0f); + uint8_t g = (uint8_t)(w1 * 255.0f); + uint8_t b = (uint8_t)(w2 * 255.0f); + pixels[y * w + x] = 0xFF000000u | ((uint32_t)r << 16) | + ((uint32_t)g << 8) | (uint32_t)b; + } + } + + pixman_image_t *triangle = pixman_image_create_bits(PIXMAN_a8r8g8b8, + w, h, pixels, w * sizeof(uint32_t)); + pixman_image_composite32(PIXMAN_OP_OVER, triangle, NULL, dst, + 0, 0, 0, 0, options->box.x, options->box.y, w, h); + pixman_image_unref(triangle); + pixman_image_set_clip_region32(dst, NULL); + free(pixels); +} + +static void custom_triangle_pixman_destroy(struct render_triangle_pass *pass) { + struct pixman_render_triangle_pass *pixman_pass = + pixman_render_triangle_pass_from_pass(pass); + free(pixman_pass); +} + +static const struct render_triangle_pass_impl render_triangle_pass_impl = { + .destroy = custom_triangle_pixman_destroy, + .render = custom_triangle_pixman_render, +}; + +struct render_triangle_pass *pixman_render_triangle_pass_create( + struct wlr_renderer *renderer) { + struct pixman_render_triangle_pass *pass = malloc(sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_pixman_render_submit_pass"); + return NULL; + } + + render_triangle_pass_init(&pass->base, &render_triangle_pass_impl); + + return &pass->base; +} + +bool render_triangle_pass_is_pixman(const struct render_triangle_pass *triangle_pass) { + return triangle_pass->impl == &render_triangle_pass_impl; +} + +struct pixman_render_triangle_pass *pixman_render_triangle_pass_from_pass( + struct render_triangle_pass *triangle_pass) { + assert(render_triangle_pass_is_pixman(triangle_pass)); + struct pixman_render_triangle_pass *pixman_pass = + wl_container_of(triangle_pass, pixman_pass, base); + + return pixman_pass; +} + diff --git a/examples/render-pass-ext/pixman/triangle_pass.h b/examples/render-pass-ext/pixman/triangle_pass.h new file mode 100644 index 000000000..5267799a8 --- /dev/null +++ b/examples/render-pass-ext/pixman/triangle_pass.h @@ -0,0 +1,16 @@ +#ifndef PIXMAN_TRIANGLE_PASS_PASS_H +#define PIXMAN_TRIANGLE_PASS_PASS_H + +#include "../triangle_pass.h" + +struct pixman_render_triangle_pass { + struct render_triangle_pass base; +}; + +struct render_triangle_pass *pixman_render_triangle_pass_create( + struct wlr_renderer *renderer); +bool render_triangle_pass_is_pixman(const struct render_triangle_pass *triangle_pass); +struct pixman_render_triangle_pass *pixman_render_triangle_pass_from_pass( + struct render_triangle_pass *triangle_pass); + +#endif // PIXMAN_TRIANGLE_PASS_PASS_H diff --git a/examples/render-pass-ext/render-pass-ext.c b/examples/render-pass-ext/render-pass-ext.c new file mode 100644 index 000000000..eb09abd55 --- /dev/null +++ b/examples/render-pass-ext/render-pass-ext.c @@ -0,0 +1,206 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "triangle_pass.h" + +struct sample_state { + struct wl_display *display; + struct wl_listener new_output; + struct wl_listener new_input; + struct wl_listener renderer_destroy; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; +}; + +struct sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_keyboard *wlr_keyboard; + struct wl_listener key; + struct wl_listener destroy; +}; + +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = + wl_container_of(listener, sample_output, frame); + struct wlr_output *wlr_output = sample_output->output; + + struct wlr_output_state state; + wlr_output_state_init(&state); + struct wlr_render_pass *pass = + wlr_output_begin_render_pass(wlr_output, &state, NULL); + + int size = wlr_output->height < wlr_output->width ? + (wlr_output->height * 3) / 4 : (wlr_output->width * 3) / 4; + struct wlr_box triangle_box = { + .x = (wlr_output->width - size) / 2, + .y = (wlr_output->height - size) / 2, + .width = size, + .height = size, + }; + render_triangle_pass_add(pass, + &(struct custom_render_triangle_options){ + .box = triangle_box, + }); + + wlr_render_pass_submit(pass); + wlr_output_commit_state(wlr_output, &state); + wlr_output_state_finish(&state); +} + +static void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = + wl_container_of(listener, sample_output, destroy); + wlr_log(WLR_DEBUG, "Output removed"); + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + free(sample_output); +} + +static void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = + wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + sample->renderer->data = get_or_create_render_triangle_pass(sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(*sample_output)); + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; + + struct wlr_output_state state; + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, true); + struct wlr_output_mode *mode = wlr_output_preferred_mode(output); + if (mode != NULL) { + wlr_output_state_set_mode(&state, mode); + } + wlr_output_commit_state(output, &state); + wlr_output_state_finish(&state); +} + +static void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_keyboard_key_event *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + } +} + +static void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = + wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +static void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = calloc(1, sizeof(*keyboard)); + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + default: + break; + } +} + +static void renderer_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, renderer_destroy); + render_triangle_pass_destroy(sample->renderer->data); +} + +int main(void) { + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .display = display, + }; + + struct wlr_backend *backend = wlr_backend_autocreate( + wl_display_get_event_loop(display), NULL); + if (backend == NULL) { + return 1; + } + + state.renderer = wlr_renderer_autocreate(backend); + if (state.renderer == NULL) { + wlr_log(WLR_ERROR, "Failed to create renderer"); + wlr_backend_destroy(backend); + return 1; + } + + wl_signal_add(&state.renderer->events.destroy, &state.renderer_destroy); + state.renderer_destroy.notify = renderer_destroy_notify; + + state.allocator = wlr_allocator_autocreate(backend, state.renderer); + if (state.allocator == NULL) { + wlr_log(WLR_ERROR, "Failed to create allocator"); + wlr_backend_destroy(backend); + return 1; + } + + wl_signal_add(&backend->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&backend->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + + if (!wlr_backend_start(backend)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(backend); + return 1; + } + + wl_display_run(display); + wl_display_destroy(display); + return 0; +} diff --git a/examples/render-pass-ext/triangle_pass.c b/examples/render-pass-ext/triangle_pass.c new file mode 100644 index 000000000..404e3e00e --- /dev/null +++ b/examples/render-pass-ext/triangle_pass.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#if WLR_HAS_GLES2_RENDERER +#include +#endif +#if WLR_HAS_VULKAN_RENDERER +#include +#endif +#include +#include + +#include "triangle_pass.h" +#include "pixman/triangle_pass.h" +#if WLR_HAS_GLES2_RENDERER +#include "gles2/triangle_pass.h" +#endif + +void render_triangle_pass_init(struct render_triangle_pass *pass, + const struct render_triangle_pass_impl *impl) { + assert(impl->render); + *pass = (struct render_triangle_pass){ + .impl = impl, + }; + + wl_signal_init(&pass->events.destroy); +} + +void render_triangle_pass_destroy(struct render_triangle_pass *pass) { + if (pass == NULL) { + return; + } + + pass->impl->destroy(pass); +} + +struct render_triangle_pass *get_or_create_render_triangle_pass( + struct wlr_renderer *renderer) { + if (renderer == NULL) { + return NULL; + } + + if (renderer->data == NULL) { + struct render_triangle_pass *pass = NULL; + if (wlr_renderer_is_pixman(renderer)) { + pass = pixman_render_triangle_pass_create(renderer); + } + +#if WLR_HAS_GLES2_RENDERER + else if (wlr_renderer_is_gles2(renderer)) { + pass = gles2_render_triangle_pass_create(renderer); + } +#endif + +// #if WLR_HAS_VULKAN_RENDERER +// else if (wlr_renderer_is_vk(renderer)) { +// pass = wlr_vk_render_triangle_pass_create(renderer); +// } +// #endif + + renderer->data = pass; + return pass; + } else { + return renderer->data; + } +} + +void render_triangle_pass_add(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options) { + struct wlr_renderer *renderer = + wlr_get_wlr_renderer_from_render_pass(render_pass); + + struct render_triangle_pass *pass = renderer->data; + if (pass == NULL) { + wlr_log(WLR_ERROR, "No triangle pass is available for this renderer"); + return; + } + return pass->impl->render(render_pass, options); +} + +void custom_render_triangle_options_get_box(const struct custom_render_triangle_options *options, + const struct wlr_buffer *buffer, struct wlr_box *box) { + if (wlr_box_empty(&options->box)) { + *box = (struct wlr_box){ + .width = buffer->width, + .height = buffer->height, + }; + + return; + } + + *box = options->box; +} + diff --git a/examples/render-pass-ext/triangle_pass.h b/examples/render-pass-ext/triangle_pass.h new file mode 100644 index 000000000..f3ecfb040 --- /dev/null +++ b/examples/render-pass-ext/triangle_pass.h @@ -0,0 +1,41 @@ +#ifndef RENDER_PASS_EXT_H +#define RENDER_PASS_EXT_H + +#include + +#include +#include + +#include + +struct custom_render_triangle_options { + struct wlr_box box; +}; + +struct render_triangle_pass; + +struct render_triangle_pass_impl { + void (*destroy)(struct render_triangle_pass *pass); + void (*render)(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options); +}; + +struct render_triangle_pass { + const struct render_triangle_pass_impl *impl; + struct { + struct wl_signal destroy; + } events; +}; + +void render_triangle_pass_init(struct render_triangle_pass *pass, + const struct render_triangle_pass_impl *impl); +void render_triangle_pass_destroy(struct render_triangle_pass *pass); + +struct render_triangle_pass *get_or_create_render_triangle_pass( + struct wlr_renderer *renderer); +void render_triangle_pass_add(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options); +void custom_render_triangle_options_get_box(const struct custom_render_triangle_options *options, + const struct wlr_buffer *buffer, struct wlr_box *box); + +#endif // RENDER_PASS_EXT_H