diff --git a/include/render/pass.h b/include/render/pass.h new file mode 100644 index 000000000..2cbd6db7e --- /dev/null +++ b/include/render/pass.h @@ -0,0 +1,9 @@ +#ifndef RENDER_PASS_H +#define RENDER_PASS_H + +#include + +struct wlr_render_pass *begin_legacy_buffer_render_pass(struct wlr_renderer *renderer, + struct wlr_buffer *buffer); + +#endif diff --git a/render/pass.c b/render/pass.c index f33096681..17c5d247d 100644 --- a/render/pass.c +++ b/render/pass.c @@ -1,7 +1,16 @@ #include +#include #include #include #include +#include +#include "render/pass.h" + +struct wlr_render_pass_legacy { + struct wlr_render_pass base; + struct wlr_renderer *renderer; + int width, height; +}; void wlr_render_pass_init(struct wlr_render_pass *render_pass, const struct wlr_render_pass_impl *impl) { @@ -50,3 +59,126 @@ float wlr_render_texture_options_get_alpha(const struct wlr_render_texture_optio } return *options->alpha; } + +static const struct wlr_render_pass_impl legacy_impl; + +static struct wlr_render_pass_legacy *legacy_pass_from_pass(struct wlr_render_pass *pass) { + assert(pass->impl == &legacy_impl); + struct wlr_render_pass_legacy *legacy = wl_container_of(pass, legacy, base); + return legacy; +} + +static bool legacy_submit(struct wlr_render_pass *wlr_pass) { + struct wlr_render_pass_legacy *pass = legacy_pass_from_pass(wlr_pass); + wlr_renderer_end(pass->renderer); + free(pass); + return true; +} + +static void get_clip_region(struct wlr_render_pass_legacy *pass, + const pixman_region32_t *in, pixman_region32_t *out) { + if (in != NULL) { + pixman_region32_init(out); + pixman_region32_copy(out, in); + } else { + pixman_region32_init_rect(out, 0, 0, pass->width, pass->height); + } +} + +static void scissor(struct wlr_renderer *renderer, const pixman_box32_t *rect) { + struct wlr_box box = { + .x = rect->x1, + .y = rect->y1, + .width = rect->x2 - rect->x1, + .height = rect->y2 - rect->y1, + }; + wlr_renderer_scissor(renderer, &box); +} + +static void legacy_add_texture(struct wlr_render_pass *wlr_pass, + const struct wlr_render_texture_options *options) { + struct wlr_render_pass_legacy *pass = legacy_pass_from_pass(wlr_pass); + struct wlr_texture *texture = options->texture; + + struct wlr_fbox src_box; + wlr_render_texture_options_get_src_box(options, &src_box); + struct wlr_box dst_box; + wlr_render_texture_options_get_dst_box(options, &dst_box); + float alpha = wlr_render_texture_options_get_alpha(options); + + float proj[9], matrix[9]; + wlr_matrix_identity(proj); + wlr_matrix_project_box(matrix, &dst_box, options->transform, 0.0, proj); + + pixman_region32_t clip; + get_clip_region(pass, options->clip, &clip); + + int rects_len = 0; + const pixman_box32_t *rects = pixman_region32_rectangles(&clip, &rects_len); + for (int i = 0; i < rects_len; i++) { + scissor(pass->renderer, &rects[i]); + wlr_render_subtexture_with_matrix(pass->renderer, texture, &src_box, matrix, alpha); + } + + wlr_renderer_scissor(pass->renderer, NULL); + pixman_region32_fini(&clip); +} + +static void legacy_add_rect(struct wlr_render_pass *wlr_pass, + const struct wlr_render_rect_options *options) { + struct wlr_render_pass_legacy *pass = legacy_pass_from_pass(wlr_pass); + + float proj[9], matrix[9]; + wlr_matrix_identity(proj); + wlr_matrix_project_box(matrix, &options->box, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, proj); + + pixman_region32_t clip; + get_clip_region(pass, options->clip, &clip); + + float color[4] = { + options->color.r, + options->color.g, + options->color.b, + options->color.a, + }; + + int rects_len = 0; + const pixman_box32_t *rects = pixman_region32_rectangles(&clip, &rects_len); + for (int i = 0; i < rects_len; i++) { + scissor(pass->renderer, &rects[i]); + wlr_render_quad_with_matrix(pass->renderer, color, matrix); + } + + wlr_renderer_scissor(pass->renderer, NULL); + pixman_region32_fini(&clip); +} + +static const struct wlr_render_pass_impl legacy_impl = { + .submit = legacy_submit, + .add_texture = legacy_add_texture, + .add_rect = legacy_add_rect, +}; + +struct wlr_render_pass *begin_legacy_buffer_render_pass(struct wlr_renderer *renderer, + struct wlr_buffer *buffer) { + if (renderer->rendering) { + return NULL; + } + + struct wlr_render_pass_legacy *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + return NULL; + } + + wlr_render_pass_init(&pass->base, &legacy_impl); + pass->renderer = renderer; + pass->width = buffer->width; + pass->height = buffer->height; + + if (!wlr_renderer_begin_with_buffer(renderer, buffer)) { + free(pass); + return NULL; + } + + return &pass->base; +} diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 459016b66..cfddca884 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -27,6 +27,7 @@ #endif // WLR_HAS_VULKAN_RENDERER #include "backend/backend.h" +#include "render/pass.h" #include "render/pixel_format.h" #include "render/wlr_renderer.h" #include "util/env.h" @@ -415,7 +416,7 @@ int wlr_renderer_get_drm_fd(struct wlr_renderer *r) { struct wlr_render_pass *wlr_renderer_begin_buffer_pass( struct wlr_renderer *renderer, struct wlr_buffer *buffer) { if (!renderer->impl->begin_buffer_pass) { - return NULL; + return begin_legacy_buffer_render_pass(renderer, buffer); } return renderer->impl->begin_buffer_pass(renderer, buffer); }