render: add support for clearing render passes

introduces a new `wlr_render_pass_clear` function, allowing
render passes to be cleared with a solid color.
This commit is contained in:
YaoBing Xiao 2026-01-31 21:45:12 +08:00
parent 7cb4e30bfd
commit eeecb382cc
8 changed files with 120 additions and 8 deletions

View file

@ -62,6 +62,8 @@ struct wlr_render_pass_impl {
/* Implementers are also guaranteed that options->box is nonempty */
void (*add_rect)(struct wlr_render_pass *pass,
const struct wlr_render_rect_options *options);
void (*clear)(struct wlr_render_pass *pass,
const struct wlr_render_clear_options *options);
};
struct wlr_render_timer {

View file

@ -157,4 +157,20 @@ struct wlr_render_rect_options {
void wlr_render_pass_add_rect(struct wlr_render_pass *render_pass,
const struct wlr_render_rect_options *options);
struct wlr_render_clear_options {
/* Clear color */
struct wlr_render_color color;
/* Clip region, leave NULL to disable clipping */
const pixman_region32_t *clip;
};
/**
* Clear the render target with a solid color.
*
* This is optimized for GPU hardware (e.g., glClear + glScissor) and is more
* efficient than drawing a rectangle.
*/
void wlr_render_pass_clear(struct wlr_render_pass *render_pass,
const struct wlr_render_clear_options *options);
#endif

View file

@ -275,10 +275,41 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
pop_gles2_debug(renderer);
}
static void render_pass_clear(struct wlr_render_pass *wlr_pass,
const struct wlr_render_clear_options *options) {
struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass);
struct wlr_gles2_renderer *renderer = pass->buffer->renderer;
push_gles2_debug(renderer);
const struct wlr_render_color *color = &options->color;
glClearColor(color->r, color->g, color->b, color->a);
if (options->clip) {
int rects_len;
const pixman_box32_t *rects = pixman_region32_rectangles(options->clip, &rects_len);
glEnable(GL_SCISSOR_TEST);
for (int i = 0; i < rects_len; i++) {
const pixman_box32_t *rect = &rects[i];
int height = pass->buffer->buffer->height;
glScissor(rect->x1, height - rect->y2,
rect->x2 - rect->x1, rect->y2 - rect->y1);
glClear(GL_COLOR_BUFFER_BIT);
}
glDisable(GL_SCISSOR_TEST);
} else {
glClear(GL_COLOR_BUFFER_BIT);
}
pop_gles2_debug(renderer);
}
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,
.clear = render_pass_clear,
};
static const char *reset_status_str(GLenum status) {

View file

@ -4,7 +4,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 && impl->add_rect);
assert(impl->submit && impl->add_texture && impl->add_rect && impl->clear);
*render_pass = (struct wlr_render_pass){
.impl = impl,
};
@ -34,6 +34,11 @@ void wlr_render_pass_add_rect(struct wlr_render_pass *render_pass,
render_pass->impl->add_rect(render_pass, options);
}
void wlr_render_pass_clear(struct wlr_render_pass *render_pass,
const struct wlr_render_clear_options *options) {
render_pass->impl->clear(render_pass, options);
}
void wlr_render_texture_options_get_src_box(const struct wlr_render_texture_options *options,
struct wlr_fbox *box) {
*box = options->src_box;

View file

@ -225,10 +225,23 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
pixman_image_unref(fill);
}
static void render_pass_clear(struct wlr_render_pass *wlr_pass,
const struct wlr_render_clear_options *options) {
struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass);
render_pass_add_rect(wlr_pass, &(struct wlr_render_rect_options){
.box = { .width = pass->buffer->buffer->width, .height = pass->buffer->buffer->height },
.color = options->color,
.clip = options->clip,
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
});
}
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,
.clear = render_pass_clear,
};
struct wlr_pixman_render_pass *begin_pixman_render_pass(

View file

@ -943,13 +943,60 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
}
}
static void render_pass_clear(struct wlr_render_pass *wlr_pass,
const struct wlr_render_clear_options *options) {
struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass);
VkCommandBuffer cb = pass->command_buffer->vk;
float linear_color[] = {
color_to_linear_premult(options->color.r, options->color.a),
color_to_linear_premult(options->color.g, options->color.a),
color_to_linear_premult(options->color.b, options->color.a),
options->color.a,
};
VkClearAttachment clear_att = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.colorAttachment = 0,
.clearValue.color.float32 = {
linear_color[0],
linear_color[1],
linear_color[2],
linear_color[3],
},
};
pixman_region32_t clip;
get_clip_region(pass, options->clip, &clip);
int clip_rects_len;
const pixman_box32_t *clip_rects = pixman_region32_rectangles(&clip, &clip_rects_len);
VkClearRect clear_rect = {
.layerCount = 1,
};
for (int i = 0; i < clip_rects_len; i++) {
convert_pixman_box_to_vk_rect(&clip_rects[i], &clear_rect.rect);
vkCmdClearAttachments(cb, 1, &clear_att, 1, &clear_rect);
struct wlr_box box = {
.x = clip_rects[i].x1,
.y = clip_rects[i].y1,
.width = clip_rects[i].x2 - clip_rects[i].x1,
.height = clip_rects[i].y2 - clip_rects[i].y1,
};
render_pass_mark_box_updated(pass, &box);
}
pixman_region32_fini(&clip);
}
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,
.clear = render_pass_clear,
};
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);

View file

@ -268,9 +268,8 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
enum wl_output_transform transform = wlr_output_transform_invert(cursor->transform);
transform = wlr_output_transform_compose(transform, output->transform);
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = { .width = buffer->width, .height = buffer->height },
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
wlr_render_pass_clear(pass, &(struct wlr_render_clear_options){
.color = { 0, 0, 0, 0 },
});
wlr_render_pass_add_texture(pass, &(struct wlr_render_texture_options){
.texture = texture,
@ -535,4 +534,4 @@ bool output_cursor_refresh_color_transform(struct wlr_output_cursor *output_curs
wlr_color_transform_unref(transforms[0]);
wlr_color_transform_unref(transforms[1]);
return output_cursor->color_transform != NULL;
}
}

View file

@ -63,9 +63,8 @@ static struct wlr_buffer *output_acquire_empty_buffer(struct wlr_output *output,
return NULL;
}
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
wlr_render_pass_clear(pass, &(struct wlr_render_clear_options){
.color = { 0, 0, 0, 0 },
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
});
if (!wlr_render_pass_submit(pass)) {