Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for blur and expo #1840

Merged
merged 9 commits into from
Jul 30, 2023
6 changes: 3 additions & 3 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ project(
'cpp',
version: '0.8.0',
license: 'MIT',
meson_version: '>=0.53.0',
meson_version: '>=0.56.0',
default_options: [
'cpp_std=c++17',
'c_std=c11',
Expand Down Expand Up @@ -61,8 +61,8 @@ conf_data = configuration_data()
version = '"@0@"'.format(meson.project_version())
git = find_program('git', native: true, required: false)
if git.found()
git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'])
git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'])
git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: true)
git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: true)
if git_commit.returncode() == 0 and git_branch.returncode() == 0
version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format(
meson.project_version(),
Expand Down
90 changes: 52 additions & 38 deletions plugins/blur/blur-base.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "blur.hpp"
#include "wayfire/core.hpp"
#include "wayfire/geometry.hpp"
#include "wayfire/region.hpp"
#include "wayfire/scene-render.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <wayfire/output.hpp>
#include <wayfire/workspace-set.hpp>
#include <wayfire/util/log.hpp>
Expand All @@ -15,13 +18,13 @@ attribute mediump vec2 uv_in;
varying mediump vec2 uvpos[2];

uniform mat4 mvp;
uniform mat4 background_inverse;
uniform mat4 background_uv_matrix;

void main() {

gl_Position = mvp * vec4(position, 0.0, 1.0);
uvpos[0] = uv_in;
uvpos[1] = vec4(background_inverse * vec4(uv_in - 0.5, 0.0, 1.0)).xy + 0.5;
uvpos[1] = vec4(background_uv_matrix * vec4(uv_in - 0.5, 0.0, 1.0)).xy + 0.5;
})";

static const char *blur_blend_fragment_shader =
Expand All @@ -46,9 +49,9 @@ vec3 saturation(vec3 rgb, float adjustment)

void main()
{
vec4 bp = texture2D(bg_texture, uvpos[0]);
vec4 bp = texture2D(bg_texture, uvpos[1]);
bp = vec4(saturation(bp.rgb, sat), bp.a);
vec4 wp = get_pixel(uvpos[1]);
vec4 wp = get_pixel(uvpos[0]);
vec4 c = clamp(4.0 * wp.a, 0.0, 1.0) * bp;
gl_FragColor = wp + (1.0 - wp.a) * c;
})";
Expand Down Expand Up @@ -174,8 +177,7 @@ wlr_box wf_blur_base::copy_region(wf::framebuffer_t& result,
return subbox;
}

void wf_blur_base::pre_render(wlr_box src_box,
const wf::region_t& damage, const wf::render_target_t& target_fb)
void wf_blur_base::prepare_blur(const wf::render_target_t& target_fb, const wf::region_t& damage)
{
if (damage.empty())
{
Expand All @@ -201,50 +203,33 @@ void wf_blur_base::pre_render(wlr_box src_box,

int r = blur_fb0(blur_damage, fb[0].viewport_width, fb[0].viewport_height);

/* Make sure the result is always fb[1], because that's what is used in render()
/* Make sure the result is always fb[0], because that's what is used in render()
* */
if (r != 0)
{
std::swap(fb[0], fb[1]);
}

/* we subtract target_fb's position to so that
* view box is relative to framebuffer */
auto view_box = target_fb.framebuffer_box_from_geometry_box(src_box);
prepared_geometry = damage_box;
}

OpenGL::render_begin();
fb[1].allocate(view_box.width, view_box.height);
fb[1].bind();
GL_CALL(glBindFramebuffer(GL_READ_FRAMEBUFFER, fb[0].fb));

/* Blit the blurred texture into an fb which has the size of the view,
* so that the view texture and the blurred background can be combined
* together in render()
*
* local_geometry is damage_box relative to view box */
wlr_box local_box = damage_box + wf::point_t{-view_box.x, -view_box.y};
GL_CALL(glBlitFramebuffer(0, 0, fb[0].viewport_width, fb[0].viewport_height,
local_box.x,
view_box.height - local_box.y - local_box.height,
local_box.x + local_box.width,
view_box.height - local_box.y,
GL_COLOR_BUFFER_BIT, GL_LINEAR));
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
OpenGL::render_end();
static wf::pointf_t get_center(wf::geometry_t g)
{
return {g.x + g.width / 2.0, g.y + g.height / 2.0};
}

void wf_blur_base::render(wf::texture_t src_tex, wlr_box src_box,
wlr_box scissor_box, const wf::render_target_t& target_fb)
void wf_blur_base::render(wf::texture_t src_tex, wlr_box src_box, const wf::region_t& damage,
const wf::render_target_t& background_source_fb, const wf::render_target_t& target_fb)
{
OpenGL::render_begin(target_fb);
blend_program.use(src_tex.type);

/* Use shader and enable vertex and texcoord data */
static const float vertex_data_uv[] = {
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
};

const float vertex_data_pos[] = {
Expand All @@ -257,21 +242,50 @@ void wf_blur_base::render(wf::texture_t src_tex, wlr_box src_box,
blend_program.attrib_pointer("position", 2, 0, vertex_data_pos);
blend_program.attrib_pointer("uv_in", 2, 0, vertex_data_uv);

// The blurred background is contained in a framebuffer with dimensions equal to the projected damage.
// We need to calculate a mapping between the uv coordinates of the view (which may be bigger than the
// damage) and the uv coordinates used for sampling the blurred background.

// How it works:
// 1. translate UV coordinates to (-0.5, -0.5) ~ (0.5, 0.5) range
// 2. apply inverse framebuffer transform (needed because on rotated outputs, the framebuffer box includes
// rotation).
// 3. Scale to match the view size
// 4. Translate to match the view
auto view_box = background_source_fb.framebuffer_box_from_geometry_box(src_box); // Projected view
auto blurred_box = prepared_geometry;
// prepared_geometry is the projected damage bounding box

glm::mat4 fb_fix = target_fb.transform;
const auto scale_x = 1.0 * view_box.width / blurred_box.width;
const auto scale_y = 1.0 * view_box.height / blurred_box.height;
glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3{scale_x, scale_y, 1.0});

const wf::pointf_t center_view = get_center(view_box);
const wf::pointf_t center_prepared = get_center(blurred_box);
const auto translate_x = 1.0 * (center_view.x - center_prepared.x) / view_box.width;
const auto translate_y = -1.0 * (center_view.y - center_prepared.y) / view_box.height;
glm::mat4 fix_center = glm::translate(glm::mat4(1.0), glm::vec3{translate_x, translate_y, 0.0});
glm::mat4 composite = scale * fix_center * fb_fix;
blend_program.uniformMatrix4f("background_uv_matrix", composite);

/* Blend blurred background with window texture src_tex */
blend_program.uniformMatrix4f("background_inverse", glm::inverse(target_fb.transform));
blend_program.uniformMatrix4f("mvp", target_fb.get_orthographic_projection());
/* XXX: core should give us the number of texture units used */
blend_program.uniform1i("bg_texture", 1);
blend_program.uniform1f("sat", saturation_opt);

blend_program.set_active_texture(src_tex);
GL_CALL(glActiveTexture(GL_TEXTURE0 + 1));
GL_CALL(glBindTexture(GL_TEXTURE_2D, fb[1].tex));
GL_CALL(glBindTexture(GL_TEXTURE_2D, fb[0].tex));
/* Render it to target_fb */
target_fb.bind();

target_fb.scissor(scissor_box);
GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
for (const auto& box : damage)
{
target_fb.logic_scissor(wlr_box_from_pixman_box(box));
GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
}

/*
* Disable stuff
Expand Down
10 changes: 2 additions & 8 deletions plugins/blur/blur.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,8 @@ class blur_render_instance_t : public transformer_render_instance_t<blur_node_t>
if (!damage.empty())
{
auto translucent_damage = calculate_translucent_damage(target, damage);
self->provider()->pre_render(bounding_box, translucent_damage, target);
auto reg = target.framebuffer_region_from_geometry_region(damage);

for (const auto& rect : reg)
{
auto damage_box = wlr_box_from_pixman_box(rect);
self->provider()->render(tex, bounding_box, damage_box, target);
}
self->provider()->prepare_blur(target, translucent_damage);
self->provider()->render(tex, bounding_box, damage, target, target);
}

OpenGL::render_begin(target);
Expand Down
25 changes: 21 additions & 4 deletions plugins/blur/blur.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "wayfire/geometry.hpp"
#include <wayfire/core.hpp>
#include <wayfire/opengl.hpp>
#include <wayfire/render-manager.hpp>
Expand Down Expand Up @@ -92,6 +93,8 @@ class wf_blur_base
/* used to store temporary results in blur algorithms, cleaned up in base
* destructor */
wf::framebuffer_t fb[2];
wf::geometry_t prepared_geometry;

/* the program created by the given algorithm, cleaned up in base destructor */
OpenGL::program_t program[2];
/* the program used by wf_blur_base to combine the blurred, unblurred and
Expand Down Expand Up @@ -129,11 +132,25 @@ class wf_blur_base

virtual int calculate_blur_radius();

virtual void pre_render(wlr_box src_box,
const wf::region_t& damage, const wf::render_target_t& target_fb);
/**
* Calculate the blurred background region.
*
* @param target_fb A render target containing the background to be blurred.
* @param damage The region to be blurred.
*/
void prepare_blur(const wf::render_target_t& target_fb, const wf::region_t& damage);

virtual void render(wf::texture_t src_tex, wlr_box src_box,
wlr_box scissor_box, const wf::render_target_t& target_fb);
/**
* Render a view with a blended background as prepared from @prepare_blur.
*
* @param src_tex The texture of the view to render.
* @param src_box The geometry of the view in framebuffer logical coordinates.
* @param damage The region to repaint, in logical coordinates.
* @param background_source_fb The framebuffer used to prepare the background blur.
* @param target_fb The target to draw to.
*/
void render(wf::texture_t src_tex, wlr_box src_box, const wf::region_t& damage,
const wf::render_target_t& background_source_fb, const wf::render_target_t& target_fb);
};

std::unique_ptr<wf_blur_base> create_box_blur();
Expand Down
20 changes: 13 additions & 7 deletions plugins/blur/meson.build
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
blur = shared_module('blur',
['blur.cpp', 'blur-base.cpp', 'box.cpp', 'gaussian.cpp',
'kawase.cpp', 'bokeh.cpp'],
include_directories: [wayfire_api_inc, wayfire_conf_inc],
dependencies: [wlroots, pixman, wfconfig],
install: true,
install_dir: join_paths(get_option('libdir'), 'wayfire'))
blur_base = shared_library('wayfire-blur-base',
['blur-base.cpp', 'box.cpp', 'gaussian.cpp', 'kawase.cpp', 'bokeh.cpp'],
include_directories: [wayfire_api_inc, wayfire_conf_inc],
dependencies: [wlroots, pixman, wfconfig],
override_options: ['b_lundef=false'],
install: true)
install_headers(['blur.hpp'], subdir: 'wayfire/plugins/blur')

blur = shared_module('blur', ['blur.cpp'],
link_with: blur_base,
include_directories: [wayfire_api_inc, wayfire_conf_inc],
dependencies: [wlroots, pixman, wfconfig],
install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))
5 changes: 0 additions & 5 deletions plugins/common/wayfire/plugins/common/workspace-wall.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ class workspace_wall_t : public wf::signal::provider_t
*/
void set_viewport(const wf::geometry_t& viewport_geometry)
{
if (viewport_geometry == viewport)
{
return;
}

this->viewport = viewport_geometry;
if (render_node)
{
Expand Down
53 changes: 38 additions & 15 deletions plugins/single_plugins/expo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar
return;
}

handle_input_press(position.x, position.y, WLR_BUTTON_PRESSED);
auto og = output->get_layout_geometry();
handle_input_press(position.x - og.x, position.y - og.y, WLR_BUTTON_PRESSED);
}

void handle_touch_up(uint32_t time_ms, int finger_id, wf::pointf_t lift_off_position) override
Expand Down Expand Up @@ -290,7 +291,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar
start_zoom(true);

wall->start_output_renderer();
output->render->add_effect(&post_frame, wf::OUTPUT_EFFECT_POST);
output->render->add_effect(&pre_frame, wf::OUTPUT_EFFECT_PRE);
output->render->schedule_redraw();

auto cws = output->wset()->get_current_workspace();
Expand Down Expand Up @@ -366,9 +367,14 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar
}

wf::point_t input_grab_origin;
/**
* Handle an input press event.
*
* @param x, y The position of the event in output-local coordinates.
*/
void handle_input_press(int32_t x, int32_t y, uint32_t state)
{
if (zoom_animation.running())
if (zoom_animation.running() || !this->state.active)
{
return;
}
Expand Down Expand Up @@ -627,21 +633,38 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar

for (int i = int(wf::scene::layer::ALL_LAYERS) - 1; i >= 0; i--)
{
auto isec = output->node_for_layer((wf::scene::layer)i)->find_node_at(localf);
auto node = isec ? isec->node.get() : nullptr;
auto output_root = output->node_for_layer((wf::scene::layer)i);
if (!output_root->is_enabled())
{
continue;
}

if (auto view = wf::toplevel_cast(wf::node_to_view(node)))
// We start the search directly from the output node's children. This is because the output nodes
// usually reject all queries outside of their current visible geometry, but we want to be able to
// query views from all workspaces, not just the current (and the only visible) one.
for (auto& ch : output_root->get_children())
{
auto all_views = output->wset()->get_views();
if (std::find(all_views.begin(), all_views.end(), view) != all_views.end())
if (!ch->is_enabled())
{
return view;
continue;
}
}

if (node)
{
return nullptr;
auto isec = ch->find_node_at(localf);
auto node = isec ? isec->node.get() : nullptr;

if (auto view = wf::toplevel_cast(wf::node_to_view(node)))
{
auto all_views = output->wset()->get_views();
if (std::find(all_views.begin(), all_views.end(), view) != all_views.end())
{
return view;
}
}

if (node)
{
return nullptr;
}
}
}

Expand Down Expand Up @@ -670,7 +693,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar
}
}

wf::effect_hook_t post_frame = [=] ()
wf::effect_hook_t pre_frame = [=] ()
{
if (zoom_animation.running())
{
Expand Down Expand Up @@ -743,7 +766,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar
output->deactivate_plugin(&grab_interface);
input_grab->ungrab_input();
wall->stop_output_renderer(true);
output->render->rem_effect(&post_frame);
output->render->rem_effect(&pre_frame);
key_repeat.disconnect();
key_pressed = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion proto/meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
wl_protocol_dir = wayland_protos.get_variable(pkgconfig: 'pkgdatadir')

wayland_scanner = find_program('wayland-scanner', native: true)

Expand Down
Loading
Loading