<commit_before>#include <wayfire/plugin.hpp>
#include <wayfire/view.hpp>
#include <wayfire/output.hpp>
#include <wayfire/view-transform.hpp>
#include <wayfire/workspace-stream.hpp>
#include <wayfire/workspace-manager.hpp>
#include <wayfire/signal-definitions.hpp>

#include "blur.hpp"

using blur_algorithm_provider = std::function<nonstd::observer_ptr<wf_blur_base>()>;
class wf_blur_transformer : public wf::view_transformer_t
{
    blur_algorithm_provider provider;
    wf::output_t *output;
    wayfire_view view;
  public:
    wf_blur_transformer(blur_algorithm_provider blur_algorithm_provider,
        wf::output_t *output, wayfire_view view)
    {
        provider = blur_algorithm_provider;
        this->output = output;
        this->view = view;
    }

    wf::pointf_t transform_point(wf::geometry_t view,
        wf::pointf_t point) override
    {
        return point;
    }

    wf::pointf_t untransform_point(wf::geometry_t view,
        wf::pointf_t point) override
    {
        return point;
    }

    wlr_box get_bounding_box(wf::geometry_t view, wlr_box region) override
    {
        return region;
    }

    wf::region_t transform_opaque_region(
        wf::geometry_t bbox, wf::region_t region) override
    {
        return region;
    }

    uint32_t get_z_order() override { return wf::TRANSFORMER_BLUR; }

    void render_with_damage(wf::texture_t src_tex, wlr_box src_box,
        const wf::region_t& damage, const wf::framebuffer_t& target_fb) override
    {
        wf::region_t clip_damage = damage & src_box;

        /* We want to check if the opaque region completely occludes
         * the bounding box. If this is the case, we can skip blurring
         * altogether and just render the surface. First we disable
         * shrinking and get the opaque region without padding */
        wf::surface_interface_t::set_opaque_shrink_constraint("blur", 0);
        wf::region_t full_opaque = view->get_transformed_opaque_region();

        /* Shrink the opaque region by the padding amount since the render
         * chain expects this, as we have applied padding to damage in
         * frame_pre_paint for this frame already */
        int padding = std::ceil(provider()->calculate_blur_radius() /
            output->render->get_target_framebuffer().scale);
        wf::surface_interface_t::set_opaque_shrink_constraint("blur", padding);

        wf::region_t bbox_region{src_box};
        if ((bbox_region ^ full_opaque).empty())
        {
            /* In case the whole surface is opaque, we can simply skip blurring */
            OpenGL::render_begin(target_fb);
            for (auto& rect : damage)
            {
                target_fb.logic_scissor(wlr_box_from_pixman_box(rect));
                OpenGL::render_texture(src_tex, target_fb, src_box);
            }

            OpenGL::render_end();
            return;
        }

        wf::region_t opaque_region = view->get_transformed_opaque_region();
        provider()->pre_render(src_tex, src_box, clip_damage ^ opaque_region, target_fb);
        wf::view_transformer_t::render_with_damage(src_tex, src_box, clip_damage, target_fb);
    }

    void render_box(wf::texture_t src_tex, wlr_box src_box, wlr_box scissor_box,
        const wf::framebuffer_t& target_fb) override
    {
        provider()->render(src_tex, src_box, scissor_box, target_fb);
    }
};

class wayfire_blur : public wf::plugin_interface_t
{
    wf::button_callback button_toggle;

    wf::effect_hook_t frame_pre_paint;
    wf::signal_callback_t workspace_stream_pre, workspace_stream_post,
        view_attached, view_detached;

    const std::string normal_mode = "normal";
    std::string last_mode;

    wf::option_wrapper_t<std::string> method_opt{"blur/method"}, mode_opt{"blur/mode"};<commit_msg>blur: do not blend opaque regions<commit_after>#include <wayfire/plugin.hpp>
#include <wayfire/view.hpp>
#include <wayfire/output.hpp>
#include <wayfire/view-transform.hpp>
#include <wayfire/workspace-stream.hpp>
#include <wayfire/workspace-manager.hpp>
#include <wayfire/signal-definitions.hpp>

#include "blur.hpp"

using blur_algorithm_provider = std::function<nonstd::observer_ptr<wf_blur_base>()>;
class wf_blur_transformer : public wf::view_transformer_t
{
    blur_algorithm_provider provider;
    wf::output_t *output;
    wayfire_view view;
  public:
    wf_blur_transformer(blur_algorithm_provider blur_algorithm_provider,
        wf::output_t *output, wayfire_view view)
    {
        provider = blur_algorithm_provider;
        this->output = output;
        this->view = view;
    }

    wf::pointf_t transform_point(wf::geometry_t view,
        wf::pointf_t point) override
    {
        return point;
    }

    wf::pointf_t untransform_point(wf::geometry_t view,
        wf::pointf_t point) override
    {
        return point;
    }

    wlr_box get_bounding_box(wf::geometry_t view, wlr_box region) override
    {
        return region;
    }

    wf::region_t transform_opaque_region(
        wf::geometry_t bbox, wf::region_t region) override
    {
        return region;
    }

    uint32_t get_z_order() override { return wf::TRANSFORMER_BLUR; }

    /* Render without blending */
    void direct_render(wf::texture_t src_tex, wlr_box src_box,
        const wf::region_t& damage, const wf::framebuffer_t& target_fb)
    {
        OpenGL::render_begin(target_fb);
        for (auto& rect : damage)
        {
            target_fb.logic_scissor(wlr_box_from_pixman_box(rect));
            OpenGL::render_texture(src_tex, target_fb, src_box);
        }

        OpenGL::render_end();
    }

    void render_with_damage(wf::texture_t src_tex, wlr_box src_box,
        const wf::region_t& damage, const wf::framebuffer_t& target_fb) override
    {
        wf::region_t clip_damage = damage & src_box;

        /* We want to check if the opaque region completely occludes
         * the bounding box. If this is the case, we can skip blurring
         * altogether and just render the surface. First we disable
         * shrinking and get the opaque region without padding */
        wf::surface_interface_t::set_opaque_shrink_constraint("blur", 0);
        wf::region_t full_opaque = view->get_transformed_opaque_region();

        /* Shrink the opaque region by the padding amount since the render
         * chain expects this, as we have applied padding to damage in
         * frame_pre_paint for this frame already */
        int padding = std::ceil(provider()->calculate_blur_radius() /
            output->render->get_target_framebuffer().scale);
        wf::surface_interface_t::set_opaque_shrink_constraint("blur", padding);

        wf::region_t bbox_region{src_box};
        if ((bbox_region ^ full_opaque).empty())
        {
            /* In case the whole surface is opaque, we can simply skip blurring */
            direct_render(src_tex, src_box, damage, target_fb);
            return;
        }

        wf::region_t opaque_region = view->get_transformed_opaque_region();
        wf::region_t blurred_region = clip_damage ^ opaque_region;

        provider()->pre_render(src_tex, src_box, blurred_region, target_fb);
        wf::view_transformer_t::render_with_damage(src_tex, src_box, blurred_region, target_fb);

        /* Opaque non-blurred regions can be rendered directly without blending */
        direct_render(src_tex, src_box, opaque_region & clip_damage, target_fb);
    }

    void render_box(wf::texture_t src_tex, wlr_box src_box, wlr_box scissor_box,
        const wf::framebuffer_t& target_fb) override
    {
        provider()->render(src_tex, src_box, scissor_box, target_fb);
    }
};

class wayfire_blur : public wf::plugin_interface_t
{
    wf::button_callback button_toggle;

    wf::effect_hook_t frame_pre_paint;
    wf::signal_callback_t workspace_stream_pre, workspace_stream_post,
        view_attached, view_detached;

    const std::string normal_mode = "normal";
    std::string last_mode;

    wf::option_wrapper_t<std::string> method_opt{"blur/method"}, mode_opt{"blur/mode"};
{'fraction_non_alphanumeric': 0.09737268086166107, 'fraction_numerical': 0.0007471049682480389, 'mean_word_length': 3.2974852862493313, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '315166', 'n_tokens_mistral': 2646, 'n_tokens_neox': 2492, 'n_words': 539}