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);