diff options
author | William McKinnon <[email protected]> | 2024-04-15 01:32:22 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2024-04-15 01:32:22 -0400 |
commit | e1f4bc5996b1c77c7fa8536b7c03d9eb4140227d (patch) | |
tree | 3fa8045ca37131acc96c88cec4a2f920de6113fb /render/fx_renderer | |
parent | 7e723f983b074e62e676caffe21cd5527b524587 (diff) |
feat: add functions required by SwayFX (#35)
Diffstat (limited to 'render/fx_renderer')
-rw-r--r-- | render/fx_renderer/fx_effect_framebuffers.c | 55 | ||||
-rw-r--r-- | render/fx_renderer/fx_pass.c | 280 | ||||
-rw-r--r-- | render/fx_renderer/fx_renderer.c | 47 | ||||
-rw-r--r-- | render/fx_renderer/fx_texture.c | 1 | ||||
-rw-r--r-- | render/fx_renderer/gles2/shaders/meson.build | 2 | ||||
-rw-r--r-- | render/fx_renderer/gles2/shaders/quad_round.frag | 39 | ||||
-rw-r--r-- | render/fx_renderer/gles2/shaders/rounded_border_corner.frag | 36 | ||||
-rw-r--r-- | render/fx_renderer/gles2/shaders/tex.frag | 18 | ||||
-rw-r--r-- | render/fx_renderer/meson.build | 1 | ||||
-rw-r--r-- | render/fx_renderer/shaders.c | 51 |
10 files changed, 442 insertions, 88 deletions
diff --git a/render/fx_renderer/fx_effect_framebuffers.c b/render/fx_renderer/fx_effect_framebuffers.c new file mode 100644 index 0000000..4589b21 --- /dev/null +++ b/render/fx_renderer/fx_effect_framebuffers.c @@ -0,0 +1,55 @@ +#include <stdio.h> +#include <stdlib.h> +#include <wlr/types/wlr_output.h> +#include <wlr/util/addon.h> +#include <wlr/util/log.h> + +#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" + +static void addon_handle_destroy(struct wlr_addon *addon) { + struct fx_effect_framebuffers *fbos = wl_container_of(addon, fbos, addon); + wlr_addon_finish(&fbos->addon); + free(fbos); +} + +static const struct wlr_addon_interface fbos_addon_impl = { + .name = "fx_effect_framebuffers", + .destroy = addon_handle_destroy, +}; + +static bool fx_effect_framebuffers_assign(struct wlr_output *output, + struct fx_effect_framebuffers *fbos) { + wlr_addon_init(&fbos->addon, &output->addons, output, &fbos_addon_impl); + return true; +} + +struct fx_effect_framebuffers *fx_effect_framebuffers_try_get(struct wlr_output *output) { + struct fx_effect_framebuffers *fbos = NULL; + + struct wlr_addon *addon = wlr_addon_find(&output->addons, output, + &fbos_addon_impl); + if (!addon) { + goto create_new; + return NULL; + } + + if (!(fbos = wl_container_of(addon, fbos, addon))) { + goto create_new; + } + return fbos; + +create_new:; + fbos = calloc(1, sizeof(*fbos)); + if (!fbos) { + wlr_log(WLR_ERROR, "Could not allocate a fx_effect_framebuffers"); + abort(); + } + fbos->blur_buffer_dirty = false; + + if (!fx_effect_framebuffers_assign(output, fbos)) { + wlr_log(WLR_ERROR, "Could not assign fx_effect_framebuffers to output: '%s'", + output->name); + abort(); + } + return fbos; +} diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index f12eda5..f3a9485 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -13,6 +13,8 @@ #include "render/fx_renderer/fx_renderer.h" #include "render/fx_renderer/matrix.h" #include "render/pass.h" +#include "scenefx/render/fx_renderer/fx_renderer.h" +#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" #include "scenefx/types/fx/blur_data.h" #include "scenefx/types/fx/shadow_data.h" @@ -22,8 +24,10 @@ struct fx_render_texture_options fx_render_texture_options_default( const struct wlr_render_texture_options *base) { struct fx_render_texture_options options = { .corner_radius = 0, + .has_titlebar = false, .discard_transparent = false, - .scale = 1.0f, + .dim = 0.0f, + .dim_color = { 1, 1, 1, 1 }, .clip_box = NULL, }; memcpy(&options.base, base, sizeof(*base)); @@ -33,12 +37,16 @@ struct fx_render_texture_options fx_render_texture_options_default( struct fx_render_rect_options fx_render_rect_options_default( const struct wlr_render_rect_options *base) { struct fx_render_rect_options options = { - .scale = 1.0f, + .base = *base, }; - memcpy(&options.base, base, sizeof(*base)); return options; } +// Gets a non-transformed wlr_box +static struct wlr_box get_monitor_box(struct wlr_output *output) { + return (struct wlr_box) { 0, 0, output->width, output->height }; +} + /// /// Base Wlroots pass functions /// @@ -278,7 +286,7 @@ void fx_render_pass_add_texture(struct fx_gles_render_pass *pass, wlr_render_texture_options_get_dst_box(options, &dst_box); float alpha = wlr_render_texture_options_get_alpha(options); - struct wlr_box *clip_box = &dst_box; + const struct wlr_box *clip_box = &dst_box; if (!wlr_box_empty(fx_options->clip_box)) { clip_box = fx_options->clip_box; } @@ -289,8 +297,12 @@ void fx_render_pass_add_texture(struct fx_gles_render_pass *pass, src_fbox.height /= options->texture->height; push_fx_debug(renderer); - setup_blending(!texture->has_alpha && alpha == 1.0 ? - WLR_RENDER_BLEND_MODE_NONE : options->blend_mode); + bool has_alpha = texture->has_alpha + || alpha < 1.0 + || fx_options->corner_radius > 0 + || fx_options->discard_transparent + || (fx_options->dim && fx_options->dim_color.a < 1.0); + setup_blending(!has_alpha ? WLR_RENDER_BLEND_MODE_NONE : options->blend_mode); glUseProgram(shader->program); @@ -313,7 +325,11 @@ void fx_render_pass_add_texture(struct fx_gles_render_pass *pass, glUniform2f(shader->size, clip_box->width, clip_box->height); glUniform2f(shader->position, clip_box->x, clip_box->y); glUniform1f(shader->radius, fx_options->corner_radius); + glUniform1f(shader->has_titlebar, fx_options->has_titlebar); glUniform1f(shader->discard_transparent, fx_options->discard_transparent); + glUniform1f(shader->dim, fx_options->dim); + struct wlr_render_color dim_color = fx_options->dim_color; + glUniform4f(shader->dim_color, dim_color.r, dim_color.g, dim_color.b, dim_color.a); set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box); set_tex_matrix(shader->tex_proj, options->transform, &src_fbox); @@ -347,15 +363,95 @@ void fx_render_pass_add_rect(struct fx_gles_render_pass *pass, pop_fx_debug(renderer); } -void fx_render_pass_add_stencil_mask(struct fx_gles_render_pass *pass, - const struct fx_render_rect_options *fx_options, int corner_radius) { +void fx_render_pass_add_rounded_rect(struct fx_gles_render_pass *pass, + const struct fx_render_rounded_rect_options *fx_options) { const struct wlr_render_rect_options *options = &fx_options->base; struct fx_renderer *renderer = pass->buffer->renderer; + struct quad_round_shader *shader = NULL; + switch (fx_options->corner_location) { + case ALL: + shader = &renderer->shaders.quad_round; + break; + case TOP_LEFT: + shader = &renderer->shaders.quad_round_tl; + break; + case TOP_RIGHT: + shader = &renderer->shaders.quad_round_tr; + break; + case BOTTOM_LEFT: + shader = &renderer->shaders.quad_round_bl; + break; + case BOTTOM_RIGHT: + shader = &renderer->shaders.quad_round_br; + break; + default: + wlr_log(WLR_ERROR, "Invalid Corner Location. Aborting render"); + abort(); + } + const struct wlr_render_color *color = &options->color; struct wlr_box box; wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box); + + push_fx_debug(renderer); + setup_blending(WLR_RENDER_BLEND_MODE_PREMULTIPLIED); + + glUseProgram(shader->program); + + set_proj_matrix(shader->proj, pass->projection_matrix, &box); + glUniform4f(shader->color, color->r, color->g, color->b, color->a); + + glUniform2f(shader->size, box.width, box.height); + glUniform2f(shader->position, box.x, box.y); + glUniform1f(shader->radius, fx_options->corner_radius); + + render(&box, options->clip, shader->pos_attrib); + + pop_fx_debug(renderer); +} + +void fx_render_pass_add_rounded_border_corner(struct fx_gles_render_pass *pass, + const struct fx_render_rounded_border_corner_options *fx_options) { + const struct wlr_render_rect_options *options = &fx_options->base; + + struct fx_renderer *renderer = pass->buffer->renderer; + + const struct wlr_render_color *color = &options->color; + struct wlr_box box; + wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box); + assert(box.width > 0 && box.width == box.height); // should be a perfect square since we are drawing a circle + + push_fx_debug(renderer); + setup_blending(WLR_RENDER_BLEND_MODE_PREMULTIPLIED); + + glUseProgram(renderer->shaders.rounded_border_corner.program); + + set_proj_matrix(renderer->shaders.rounded_border_corner.proj, pass->projection_matrix, &box); + glUniform4f(renderer->shaders.rounded_border_corner.color, color->r, color->g, color->b, color->a); + + glUniform1f(renderer->shaders.rounded_border_corner.is_top_left, fx_options->corner_location == TOP_LEFT); + glUniform1f(renderer->shaders.rounded_border_corner.is_top_right, fx_options->corner_location == TOP_RIGHT); + glUniform1f(renderer->shaders.rounded_border_corner.is_bottom_left, fx_options->corner_location == BOTTOM_LEFT); + glUniform1f(renderer->shaders.rounded_border_corner.is_bottom_right, fx_options->corner_location == BOTTOM_RIGHT); + + glUniform2f(renderer->shaders.rounded_border_corner.position, box.x, box.y); + glUniform1f(renderer->shaders.rounded_border_corner.radius, fx_options->corner_radius); + glUniform2f(renderer->shaders.rounded_border_corner.half_size, box.width / 2.0, box.height / 2.0); + glUniform1f(renderer->shaders.rounded_border_corner.half_thickness, fx_options->border_thickness / 2.0); + + render(&box, options->clip, renderer->shaders.rounded_border_corner.pos_attrib); + + pop_fx_debug(renderer); +} + +void fx_render_pass_add_stencil_mask(struct fx_gles_render_pass *pass, + const struct fx_render_stencil_box_options *options) { + + struct fx_renderer *renderer = pass->buffer->renderer; + + struct wlr_box box = options->box; assert(box.width > 0 && box.height > 0); push_fx_debug(renderer); @@ -364,10 +460,9 @@ void fx_render_pass_add_stencil_mask(struct fx_gles_render_pass *pass, glUseProgram(renderer->shaders.stencil_mask.program); set_proj_matrix(renderer->shaders.stencil_mask.proj, pass->projection_matrix, &box); - glUniform4f(renderer->shaders.stencil_mask.color, color->r, color->g, color->b, color->a); glUniform2f(renderer->shaders.stencil_mask.half_size, box.width * 0.5, box.height * 0.5); glUniform2f(renderer->shaders.stencil_mask.position, box.x, box.y); - glUniform1f(renderer->shaders.stencil_mask.radius, corner_radius); + glUniform1f(renderer->shaders.stencil_mask.radius, options->corner_radius); render(&box, options->clip, renderer->shaders.stencil_mask.pos_attrib); @@ -375,35 +470,25 @@ void fx_render_pass_add_stencil_mask(struct fx_gles_render_pass *pass, } void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, - const struct fx_render_rect_options *fx_options, - int corner_radius, struct shadow_data *shadow_data) { - const struct wlr_render_rect_options *options = &fx_options->base; - + const struct fx_render_box_shadow_options *options) { struct fx_renderer *renderer = pass->buffer->renderer; + struct shadow_data *shadow_data = options->shadow_data; const struct wlr_render_color *color = &shadow_data->color; - struct wlr_box box; - wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box); - assert(box.width > 0 && box.height > 0); - struct wlr_box surface_box = box; - float blur_sigma = shadow_data->blur_sigma * fx_options->scale; - - // Extend the size of the box - box.x -= blur_sigma; - box.y -= blur_sigma; - box.width += blur_sigma * 2; - box.height += blur_sigma * 2; + struct wlr_box shadow_box = options->shadow_box; + assert(shadow_box.width > 0 && shadow_box.height > 0); + struct wlr_box surface_box = options->clip_box; + float blur_sigma = shadow_data->blur_sigma; pixman_region32_t render_region; pixman_region32_init(&render_region); pixman_region32_t inner_region; - pixman_region32_init(&inner_region); - pixman_region32_union_rect(&inner_region, &inner_region, - surface_box.x + corner_radius * 0.5, - surface_box.y + corner_radius * 0.5, - surface_box.width - corner_radius, - surface_box.height - corner_radius); + pixman_region32_init_rect(&inner_region, + surface_box.x + options->corner_radius * 0.5, + surface_box.y + options->corner_radius * 0.5, + fmax(surface_box.width - options->corner_radius, 0), + fmax(surface_box.height - options->corner_radius, 0)); pixman_region32_subtract(&render_region, options->clip, &inner_region); pixman_region32_fini(&inner_region); @@ -412,7 +497,12 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, // Init stencil work stencil_mask_init(); // Draw the rounded rect as a mask - fx_render_pass_add_stencil_mask(pass, fx_options, corner_radius); + struct fx_render_stencil_box_options stencil_options = { + .box = options->clip_box, + .corner_radius = options->corner_radius, + .clip = options->clip, + }; + fx_render_pass_add_stencil_mask(pass, &stencil_options); stencil_mask_close(false); // blending will practically always be needed (unless we have a madman @@ -422,14 +512,15 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, glUseProgram(renderer->shaders.box_shadow.program); - set_proj_matrix(renderer->shaders.box_shadow.proj, pass->projection_matrix, &box); + set_proj_matrix(renderer->shaders.box_shadow.proj, pass->projection_matrix, &shadow_box); glUniform4f(renderer->shaders.box_shadow.color, color->r, color->g, color->b, color->a); glUniform1f(renderer->shaders.box_shadow.blur_sigma, blur_sigma); - glUniform1f(renderer->shaders.box_shadow.corner_radius, corner_radius); - glUniform2f(renderer->shaders.box_shadow.size, box.width, box.height); - glUniform2f(renderer->shaders.box_shadow.position, box.x, box.y); + glUniform1f(renderer->shaders.box_shadow.corner_radius, options->corner_radius); + glUniform2f(renderer->shaders.box_shadow.size, shadow_box.width, shadow_box.height); + glUniform2f(renderer->shaders.box_shadow.position, shadow_box.x, shadow_box.y); + + render(&shadow_box, &render_region, renderer->shaders.box_shadow.pos_attrib); - render(&box, &render_region, renderer->shaders.box_shadow.pos_attrib); pixman_region32_fini(&render_region); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -448,16 +539,18 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, struct blur_data *blur_data = fx_options->blur_data; // Swap fbo - if (fx_options->current_buffer == renderer->effects_buffer) { - fx_framebuffer_bind(renderer->effects_buffer_swapped); + if (fx_options->current_buffer == pass->fx_effect_framebuffers->effects_buffer) { + fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer_swapped); } else { - fx_framebuffer_bind(renderer->effects_buffer); + fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer); } options->texture = fx_texture_from_buffer(&renderer->wlr_renderer, fx_options->current_buffer->buffer); struct fx_texture *texture = fx_get_texture(options->texture); + check_tex_src_box(options); + /* * Render */ @@ -487,9 +580,7 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; case WLR_SCALE_FILTER_NEAREST: - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - break; + abort(); } glUniform1i(shader->tex, 0); @@ -516,10 +607,10 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, wlr_texture_destroy(options->texture); // Swap buffer. We don't want to draw to the same buffer - if (fx_options->current_buffer != renderer->effects_buffer) { - fx_options->current_buffer = renderer->effects_buffer; + if (fx_options->current_buffer != pass->fx_effect_framebuffers->effects_buffer) { + fx_options->current_buffer = pass->fx_effect_framebuffers->effects_buffer; } else { - fx_options->current_buffer = renderer->effects_buffer_swapped; + fx_options->current_buffer = pass->fx_effect_framebuffers->effects_buffer_swapped; } } @@ -562,9 +653,7 @@ static void render_blur_effects(struct fx_gles_render_pass *pass, glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; case WLR_SCALE_FILTER_NEAREST: - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - break; + abort(); } glUniform1i(shader.tex, 0); @@ -589,12 +678,13 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p struct fx_render_blur_pass_options *fx_options) { struct fx_renderer *renderer = pass->buffer->renderer; struct blur_data *blur_data = fx_options->blur_data; + struct wlr_box monitor_box = get_monitor_box(pass->output); pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_copy(&damage, fx_options->tex_options.base.clip); wlr_region_transform(&damage, &damage, fx_options->tex_options.base.transform, - fx_options->monitor_box.width, fx_options->monitor_box.height); + monitor_box.width, monitor_box.height); wlr_region_expand(&damage, &damage, blur_data_calc_size(fx_options->blur_data)); @@ -603,14 +693,16 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p pixman_region32_init(&scaled_damage); fx_options->tex_options.base.src_box = (struct wlr_fbox) { - fx_options->monitor_box.x, - fx_options->monitor_box.y, - fx_options->monitor_box.width, - fx_options->monitor_box.height, + monitor_box.x, + monitor_box.y, + monitor_box.width, + monitor_box.height, }; - fx_options->tex_options.base.dst_box = fx_options->monitor_box; + fx_options->tex_options.base.dst_box = monitor_box; // Clip the blur to the damage fx_options->tex_options.base.clip = &scaled_damage; + // Artifacts with NEAREST filter + fx_options->tex_options.base.filter_mode = WLR_SCALE_FILTER_BILINEAR; // Downscale for (int i = 0; i < blur_data->num_passes; ++i) { @@ -630,19 +722,19 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p // Render additional blur effects like saturation, noise, contrast, etc... if (blur_data_should_parameters_blur_effects(blur_data) && pixman_region32_not_empty(&damage)) { - if (fx_options->current_buffer == renderer->effects_buffer) { - fx_framebuffer_bind(renderer->effects_buffer_swapped); + if (fx_options->current_buffer == pass->fx_effect_framebuffers->effects_buffer) { + fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer_swapped); } else { - fx_framebuffer_bind(renderer->effects_buffer); + fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer); } fx_options->tex_options.base.clip = &damage; fx_options->tex_options.base.texture = fx_texture_from_buffer( &renderer->wlr_renderer, fx_options->current_buffer->buffer); render_blur_effects(pass, fx_options); - if (fx_options->current_buffer != renderer->effects_buffer) { - fx_options->current_buffer = renderer->effects_buffer; + if (fx_options->current_buffer != pass->fx_effect_framebuffers->effects_buffer) { + fx_options->current_buffer = pass->fx_effect_framebuffers->effects_buffer; } else { - fx_options->current_buffer = renderer->effects_buffer_swapped; + fx_options->current_buffer = pass->fx_effect_framebuffers->effects_buffer_swapped; } } @@ -656,6 +748,11 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, struct fx_render_blur_pass_options *fx_options) { + if (pass->buffer->renderer->basic_renderer) { + wlr_log(WLR_ERROR, "Please use 'fx_renderer_begin_buffer_pass' instead of " + "'wlr_renderer_begin_buffer_pass' to use advanced effects"); + abort(); + } struct fx_renderer *renderer = pass->buffer->renderer; struct fx_render_texture_options *tex_options = &fx_options->tex_options; const struct wlr_render_texture_options *options = &tex_options->base; @@ -674,7 +771,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, goto damage_finish; } - struct fx_framebuffer *buffer = renderer->optimized_blur_buffer; + struct fx_framebuffer *buffer = pass->fx_effect_framebuffers->optimized_blur_buffer; if (!buffer || !fx_options->use_optimized_blur) { pixman_region32_translate(&translucent_region, dst_box.x, dst_box.y); pixman_region32_intersect(&translucent_region, &translucent_region, options->clip); @@ -691,7 +788,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, blur_texture->has_alpha = true; // Get a stencil of the window ignoring transparent regions - if (fx_options->ignore_transparent) { + if (fx_options->ignore_transparent && fx_options->tex_options.base.texture) { stencil_mask_init(); struct fx_render_texture_options tex_options = fx_options->tex_options; @@ -702,7 +799,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, } // Draw the blurred texture - tex_options->base.dst_box = fx_options->monitor_box; + tex_options->base.dst_box = get_monitor_box(pass->output); tex_options->base.src_box = (struct wlr_fbox) { .x = 0, .y = 0, @@ -715,7 +812,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, wlr_texture_destroy(&blur_texture->wlr_texture); // Finish stenciling - if (fx_options->ignore_transparent) { + if (fx_options->ignore_transparent && fx_options->tex_options.base.texture) { stencil_mask_fini(); } @@ -725,8 +822,13 @@ damage_finish: void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, struct fx_render_blur_pass_options *fx_options) { + if (pass->buffer->renderer->basic_renderer) { + wlr_log(WLR_ERROR, "Please use 'fx_renderer_begin_buffer_pass' instead of " + "'wlr_renderer_begin_buffer_pass' to use advanced effects"); + abort(); + } struct fx_renderer *renderer = pass->buffer->renderer; - struct wlr_box monitor_box = fx_options->monitor_box; + struct wlr_box monitor_box = get_monitor_box(pass->output); pixman_region32_t fake_damage; pixman_region32_init_rect(&fake_damage, 0, 0, monitor_box.width, monitor_box.height); @@ -738,27 +840,42 @@ void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, struct fx_framebuffer *buffer = get_main_buffer_blur(pass, &blur_options); // Update the optimized blur buffer if invalid - fx_framebuffer_get_or_create_custom(renderer, fx_options->output, - &renderer->optimized_blur_buffer); + fx_framebuffer_get_or_create_custom(renderer, pass->output, + &pass->fx_effect_framebuffers->optimized_blur_buffer); // Render the newly blurred content into the blur_buffer - fx_renderer_read_to_buffer(pass, &fake_damage, renderer->optimized_blur_buffer, buffer); + fx_renderer_read_to_buffer(pass, &fake_damage, + pass->fx_effect_framebuffers->optimized_blur_buffer, buffer, false); pixman_region32_fini(&fake_damage); - renderer->blur_buffer_dirty = false; + pass->fx_effect_framebuffers->blur_buffer_dirty = false; } void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, - pixman_region32_t *region, struct fx_framebuffer *dst_buffer, - struct fx_framebuffer *src_buffer) { - if (!pixman_region32_not_empty(region)) { + pixman_region32_t *_region, struct fx_framebuffer *dst_buffer, + struct fx_framebuffer *src_buffer, bool transformed_region) { + if (!_region || !pixman_region32_not_empty(_region)) { return; } + pixman_region32_t region; + pixman_region32_init(®ion); + pixman_region32_copy(®ion, _region); + + // Restore the transformed region to normal + if (pass->output && transformed_region) { + int ow, oh; + wlr_output_transformed_resolution(pass->output, &ow, &oh); + enum wl_output_transform transform = + wlr_output_transform_invert(pass->output->transform); + wlr_region_transform(®ion, ®ion, transform, ow, oh); + } + struct wlr_texture *src_tex = fx_texture_from_buffer(&pass->buffer->renderer->wlr_renderer, src_buffer->buffer); if (src_tex == NULL) { + pixman_region32_fini(®ion); return; } @@ -766,7 +883,8 @@ void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, fx_framebuffer_bind(dst_buffer); wlr_render_pass_add_texture(&pass->base, &(struct wlr_render_texture_options) { .texture = src_tex, - .clip = region, + .clip = ®ion, + .transform = WL_OUTPUT_TRANSFORM_NORMAL, .blend_mode = WLR_RENDER_BLEND_MODE_NONE, .dst_box = (struct wlr_box){ .width = dst_buffer->buffer->width, @@ -783,6 +901,8 @@ void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, // Bind back to the main WLR buffer fx_framebuffer_bind(pass->buffer); + + pixman_region32_fini(®ion); } @@ -841,6 +961,7 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass( struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer, struct wlr_output *output, const struct wlr_buffer_pass_options *options) { struct fx_renderer *renderer = fx_get_renderer(wlr_renderer); + renderer->basic_renderer = false; if (!wlr_egl_make_current(renderer->egl)) { return NULL; } @@ -857,10 +978,13 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass( } // Update the buffers if needed + struct fx_effect_framebuffers *fbos = NULL; + // For per output framebuffers if (output) { - fx_framebuffer_get_or_create_custom(renderer, output, &renderer->blur_saved_pixels_buffer); - fx_framebuffer_get_or_create_custom(renderer, output, &renderer->effects_buffer); - fx_framebuffer_get_or_create_custom(renderer, output, &renderer->effects_buffer_swapped); + fbos = fx_effect_framebuffers_try_get(output); + fx_framebuffer_get_or_create_custom(renderer, output, &fbos->blur_saved_pixels_buffer); + fx_framebuffer_get_or_create_custom(renderer, output, &fbos->effects_buffer); + fx_framebuffer_get_or_create_custom(renderer, output, &fbos->effects_buffer_swapped); } pixman_region32_init(&renderer->blur_padding_region); @@ -869,5 +993,7 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass( if (!pass) { return NULL; } + pass->fx_effect_framebuffers = fbos; + pass->output = output; return pass; } diff --git a/render/fx_renderer/fx_renderer.c b/render/fx_renderer/fx_renderer.c index 0923555..0b9e1a4 100644 --- a/render/fx_renderer/fx_renderer.c +++ b/render/fx_renderer/fx_renderer.c @@ -3,6 +3,7 @@ https://gitlab.freedesktop.org/wlroots/wlroots/-/tree/master/render/gles2 */ +#include "render/fx_renderer/shaders.h" #define _POSIX_C_SOURCE 199309L #include <assert.h> #include <drm_fourcc.h> @@ -20,10 +21,11 @@ #include <wlr/util/log.h> #include "render/egl.h" +#include "scenefx/render/pass.h" #include "render/pixel_format.h" #include "render/fx_renderer/util.h" #include "render/fx_renderer/fx_renderer.h" -#include "scenefx/fx_renderer/fx_renderer.h" +#include "scenefx/render/fx_renderer/fx_renderer.h" #include "render/fx_renderer/matrix.h" #include "util/time.h" @@ -453,6 +455,8 @@ static void fx_renderer_destroy(struct wlr_renderer *wlr_renderer) { static struct wlr_render_pass *begin_buffer_pass(struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer, const struct wlr_buffer_pass_options *options) { + struct fx_renderer *renderer = fx_get_renderer(wlr_renderer); + renderer->basic_renderer = true; struct fx_gles_render_pass *pass = fx_renderer_begin_buffer_pass(wlr_renderer, wlr_buffer, NULL, options); if (!pass) { @@ -638,6 +642,33 @@ static bool link_shaders(struct fx_renderer *renderer) { wlr_log(WLR_ERROR, "Could not link quad shader"); goto error; } + + // rounded quad fragment shaders + if (!link_quad_round_program(&renderer->shaders.quad_round, SHADER_SOURCE_QUAD_ROUND)) { + wlr_log(WLR_ERROR, "Could not link quad shader"); + goto error; + } + // rounded quad fragment shaders + if (!link_quad_round_program(&renderer->shaders.quad_round_tl, SHADER_SOURCE_QUAD_ROUND_TOP_LEFT)) { + wlr_log(WLR_ERROR, "Could not link quad shader"); + goto error; + } + // rounded quad fragment shaders + if (!link_quad_round_program(&renderer->shaders.quad_round_tr, SHADER_SOURCE_QUAD_ROUND_TOP_RIGHT)) { + wlr_log(WLR_ERROR, "Could not link quad shader"); + goto error; + } + // rounded quad fragment shaders + if (!link_quad_round_program(&renderer->shaders.quad_round_bl, SHADER_SOURCE_QUAD_ROUND_BOTTOM_LEFT)) { + wlr_log(WLR_ERROR, "Could not link quad shader"); + goto error; + } + // rounded quad fragment shaders + if (!link_quad_round_program(&renderer->shaders.quad_round_br, SHADER_SOURCE_QUAD_ROUND_BOTTOM_RIGHT)) { + wlr_log(WLR_ERROR, "Could not link quad shader"); + goto error; + } + // fragment shaders if (!link_tex_program(&renderer->shaders.tex_rgba, SHADER_SOURCE_TEXTURE_RGBA)) { wlr_log(WLR_ERROR, "Could not link tex_RGBA shader"); @@ -652,6 +683,12 @@ static bool link_shaders(struct fx_renderer *renderer) { goto error; } + // border corner shader + if (!link_rounded_border_corner_program(&renderer->shaders.rounded_border_corner)) { + wlr_log(WLR_ERROR, "Could not link rounded border corner shader"); + goto error; + } + // stencil mask shader if (!link_stencil_mask_program(&renderer->shaders.stencil_mask)) { wlr_log(WLR_ERROR, "Could not link stencil mask shader"); @@ -681,9 +718,15 @@ static bool link_shaders(struct fx_renderer *renderer) { error: glDeleteProgram(renderer->shaders.quad.program); + glDeleteProgram(renderer->shaders.quad_round.program); + glDeleteProgram(renderer->shaders.quad_round_tl.program); + glDeleteProgram(renderer->shaders.quad_round_tr.program); + glDeleteProgram(renderer->shaders.quad_round_bl.program); + glDeleteProgram(renderer->shaders.quad_round_br.program); glDeleteProgram(renderer->shaders.tex_rgba.program); glDeleteProgram(renderer->shaders.tex_rgbx.program); glDeleteProgram(renderer->shaders.tex_ext.program); + glDeleteProgram(renderer->shaders.rounded_border_corner.program); glDeleteProgram(renderer->shaders.stencil_mask.program); glDeleteProgram(renderer->shaders.box_shadow.program); glDeleteProgram(renderer->shaders.blur1.program); @@ -816,8 +859,6 @@ struct wlr_renderer *fx_renderer_create_egl(struct wlr_egl *egl) { goto error; } - renderer->blur_buffer_dirty = false; - pop_fx_debug(renderer); wlr_log(WLR_INFO, "FX RENDERER: Shaders Initialized Successfully"); diff --git a/render/fx_renderer/fx_texture.c b/render/fx_renderer/fx_texture.c index 1952311..e22c0f9 100644 --- a/render/fx_renderer/fx_texture.c +++ b/render/fx_renderer/fx_texture.c @@ -5,6 +5,7 @@ #include <wlr/util/log.h> #include <drm_fourcc.h> +#include "scenefx/render/fx_renderer/fx_renderer.h" #include "render/fx_renderer/fx_renderer.h" #include "render/pixel_format.h" #include "render/egl.h" diff --git a/render/fx_renderer/gles2/shaders/meson.build b/render/fx_renderer/gles2/shaders/meson.build index a751e1a..fb83e0c 100644 --- a/render/fx_renderer/gles2/shaders/meson.build +++ b/render/fx_renderer/gles2/shaders/meson.build @@ -3,7 +3,9 @@ embed = find_program('./embed.sh', native: true) shaders = [ 'common.vert', 'quad.frag', + 'quad_round.frag', 'tex.frag', + 'rounded_border_corner.frag', 'box_shadow.frag', 'stencil_mask.frag', 'blur1.frag', diff --git a/render/fx_renderer/gles2/shaders/quad_round.frag b/render/fx_renderer/gles2/shaders/quad_round.frag new file mode 100644 index 0000000..02e9902 --- /dev/null +++ b/render/fx_renderer/gles2/shaders/quad_round.frag @@ -0,0 +1,39 @@ +#define SOURCE_QUAD_ROUND 1 +#define SOURCE_QUAD_ROUND_TOP_LEFT 2 +#define SOURCE_QUAD_ROUND_TOP_RIGHT 3 +#define SOURCE_QUAD_ROUND_BOTTOM_RIGHT 4 +#define SOURCE_QUAD_ROUND_BOTTOM_LEFT 5 + +#if !defined(SOURCE) +#error "Missing shader preamble" +#endif + +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform vec2 size; +uniform vec2 position; +uniform float radius; + +vec2 getCornerDist() { +#if SOURCE == SOURCE_QUAD_ROUND + vec2 half_size = size * 0.5; + return abs(gl_FragCoord.xy - position - half_size) - half_size + radius; +#elif SOURCE == SOURCE_QUAD_ROUND_TOP_LEFT + return abs(gl_FragCoord.xy - position - size) - size + radius; +#elif SOURCE == SOURCE_QUAD_ROUND_TOP_RIGHT + return abs(gl_FragCoord.xy - position - vec2(0, size.y)) - size + radius; +#elif SOURCE == SOURCE_QUAD_ROUND_BOTTOM_RIGHT + return abs(gl_FragCoord.xy - position) - size + radius; +#elif SOURCE == SOURCE_QUAD_ROUND_BOTTOM_LEFT + return abs(gl_FragCoord.xy - position - vec2(size.x, 0)) - size + radius; +#endif +} + +void main() { + vec2 q = getCornerDist(); + float dist = min(max(q.x,q.y), 0.0) + length(max(q, 0.0)) - radius; + float smoothedAlpha = 1.0 - smoothstep(-1.0, 0.5, dist); + gl_FragColor = mix(vec4(0), v_color, smoothedAlpha); +} diff --git a/render/fx_renderer/gles2/shaders/rounded_border_corner.frag b/render/fx_renderer/gles2/shaders/rounded_border_corner.frag new file mode 100644 index 0000000..7699299 --- /dev/null +++ b/render/fx_renderer/gles2/shaders/rounded_border_corner.frag @@ -0,0 +1,36 @@ +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform bool is_top_left; +uniform bool is_top_right; +uniform bool is_bottom_left; +uniform bool is_bottom_right; + +uniform vec2 position; +uniform float radius; +uniform vec2 half_size; +uniform float half_thickness; + +float roundedBoxSDF(vec2 center, vec2 size, float radius) { + return length(max(abs(center) - size + radius, 0.0)) - radius; +} + +void main() { + vec2 center = gl_FragCoord.xy - position - half_size; + float distance = roundedBoxSDF(center, half_size - half_thickness, radius + half_thickness); + float smoothedAlphaOuter = 1.0 - smoothstep(-1.0, 1.0, distance - half_thickness); + // Create an inner circle that isn't as anti-aliased as the outer ring + float smoothedAlphaInner = 1.0 - smoothstep(-1.0, 0.5, distance + half_thickness); + gl_FragColor = mix(vec4(0), v_color, smoothedAlphaOuter - smoothedAlphaInner); + + if (is_top_left && (center.y > 0.0 || center.x > 0.0)) { + discard; + } else if (is_top_right && (center.y > 0.0 || center.x < 0.0)) { + discard; + } else if (is_bottom_left && (center.y < 0.0 || center.x > 0.0)) { + discard; + } else if (is_bottom_right && (center.y < 0.0 || center.x < 0.0)) { + discard; + } +} diff --git a/render/fx_renderer/gles2/shaders/tex.frag b/render/fx_renderer/gles2/shaders/tex.frag index b7ba3fc..d08c95d 100644 --- a/render/fx_renderer/gles2/shaders/tex.frag +++ b/render/fx_renderer/gles2/shaders/tex.frag @@ -29,7 +29,10 @@ uniform float alpha; uniform vec2 size; uniform vec2 position; uniform float radius; +uniform bool has_titlebar; uniform bool discard_transparent; +uniform float dim; +uniform vec4 dim_color; vec4 sample_texture() { #if SOURCE == SOURCE_TEXTURE_RGBA || SOURCE == SOURCE_TEXTURE_EXTERNAL @@ -40,12 +43,15 @@ vec4 sample_texture() { } void main() { - gl_FragColor = sample_texture() * alpha; - vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); - if (max(corner_distance.x, corner_distance.y) < radius) { - float d = radius - distance(corner_distance, vec2(radius)); - float smooth = smoothstep(-1.0, 0.5, d); - gl_FragColor = mix(vec4(0), gl_FragColor, smooth); + gl_FragColor = mix(sample_texture(), dim_color, dim) * alpha; + + if (!has_titlebar || gl_FragCoord.y - position.y > radius) { + vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); + if (max(corner_distance.x, corner_distance.y) < radius) { + float d = radius - distance(corner_distance, vec2(radius)); + float smooth = smoothstep(-1.0, 0.5, d); + gl_FragColor = mix(vec4(0), gl_FragColor, smooth); + } } if (discard_transparent && gl_FragColor.a == 0.0) { diff --git a/render/fx_renderer/meson.build b/render/fx_renderer/meson.build index 10e757b..041fca7 100644 --- a/render/fx_renderer/meson.build +++ b/render/fx_renderer/meson.build @@ -11,6 +11,7 @@ wlr_files += files( 'pixel_format.c', 'fx_pass.c', 'fx_framebuffer.c', + 'fx_effect_framebuffers.c', 'fx_texture.c', 'fx_renderer.c', ) diff --git a/render/fx_renderer/shaders.c b/render/fx_renderer/shaders.c index cd15eea..ad8fb3c 100644 --- a/render/fx_renderer/shaders.c +++ b/render/fx_renderer/shaders.c @@ -3,13 +3,15 @@ #include <stdlib.h> #include <wlr/util/log.h> -#include "render/fx_renderer/fx_renderer.h" #include "render/fx_renderer/shaders.h" // shaders +#include "GLES2/gl2.h" #include "common_vert_src.h" #include "quad_frag_src.h" +#include "quad_round_frag_src.h" #include "tex_frag_src.h" +#include "rounded_border_corner_frag_src.h" #include "stencil_mask_frag_src.h" #include "box_shadow_frag_src.h" #include "blur1_frag_src.h" @@ -113,6 +115,27 @@ bool link_quad_program(struct quad_shader *shader) { return true; } +bool link_quad_round_program(struct quad_round_shader *shader, enum fx_rounded_quad_shader_source source) { + GLchar quad_src[2048]; + snprintf(quad_src, sizeof(quad_src), + "#define SOURCE %d\n%s", source, quad_round_frag_src); + + GLuint prog; + shader->program = prog = link_program(quad_src); + if (!shader->program) { + return false; + } + + shader->proj = glGetUniformLocation(prog, "proj"); + shader->color = glGetUniformLocation(prog, "color"); + shader->pos_attrib = glGetAttribLocation(prog, "pos"); + shader->size = glGetUniformLocation(prog, "size"); + shader->position = glGetUniformLocation(prog, "position"); + shader->radius = glGetUniformLocation(prog, "radius"); + + return true; +} + bool link_tex_program(struct tex_shader *shader, enum fx_tex_shader_source source) { GLchar frag_src[2048]; @@ -133,7 +156,32 @@ bool link_tex_program(struct tex_shader *shader, shader->size = glGetUniformLocation(prog, "size"); shader->position = glGetUniformLocation(prog, "position"); shader->radius = glGetUniformLocation(prog, "radius"); + shader->has_titlebar = glGetUniformLocation(prog, "has_titlebar"); shader->discard_transparent = glGetUniformLocation(prog, "discard_transparent"); + shader->dim = glGetUniformLocation(prog, "dim"); + shader->dim_color = glGetUniformLocation(prog, "dim_color"); + + return true; +} + +bool link_rounded_border_corner_program(struct rounded_border_corner_shader *shader) { + GLuint prog; + shader->program = prog = link_program(rounded_border_corner_frag_src); + if (!shader->program) { + return false; + } + + shader->proj = glGetUniformLocation(prog, "proj"); + shader->color = glGetUniformLocation(prog, "color"); + shader->pos_attrib = glGetAttribLocation(prog, "pos"); + shader->is_top_left = glGetUniformLocation(prog, "is_top_left"); + shader->is_top_right = glGetUniformLocation(prog, "is_top_right"); + shader->is_bottom_left = glGetUniformLocation(prog, "is_bottom_left"); + shader->is_bottom_right = glGetUniformLocation(prog, "is_bottom_right"); + shader->position = glGetUniformLocation(prog, "position"); + shader->radius = glGetUniformLocation(prog, "radius"); + shader->half_size = glGetUniformLocation(prog, "half_size"); + shader->half_thickness = glGetUniformLocation(prog, "half_thickness"); return true; } @@ -146,7 +194,6 @@ bool link_stencil_mask_program(struct stencil_mask_shader *shader) { } shader->proj = glGetUniformLocation(prog, "proj"); - shader->color = glGetUniformLocation(prog, "color"); shader->pos_attrib = glGetAttribLocation(prog, "pos"); shader->position = glGetUniformLocation(prog, "position"); shader->half_size = glGetUniformLocation(prog, "half_size"); |