diff --git a/metadata/workarounds.xml b/metadata/workarounds.xml
index 5a4c1b95f..036c245f3 100644
--- a/metadata/workarounds.xml
+++ b/metadata/workarounds.xml
@@ -57,6 +57,10 @@
+
diff --git a/src/api/wayfire/debug.hpp b/src/api/wayfire/debug.hpp
index 5bdf1ac7e..d1abe6f76 100644
--- a/src/api/wayfire/debug.hpp
+++ b/src/api/wayfire/debug.hpp
@@ -63,6 +63,8 @@ enum class logging_category : size_t
LSHELL = 9,
// Input-Method-related events
IM = 10,
+ // Rendering-related events
+ RENDER = 11,
TOTAL,
};
diff --git a/src/api/wayfire/plugin.hpp b/src/api/wayfire/plugin.hpp
index a113cb35e..c5441cf36 100644
--- a/src/api/wayfire/plugin.hpp
+++ b/src/api/wayfire/plugin.hpp
@@ -105,7 +105,7 @@ class plugin_interface_t
using wayfire_plugin_load_func = wf::plugin_interface_t * (*)();
/** The version of Wayfire's API/ABI */
-constexpr uint32_t WAYFIRE_API_ABI_VERSION = 2024'03'24'2;
+constexpr uint32_t WAYFIRE_API_ABI_VERSION = 2024'03'27;
/**
* Each plugin must also provide a function which returns the Wayfire API/ABI
diff --git a/src/api/wayfire/scene.hpp b/src/api/wayfire/scene.hpp
index 9ffcb0ba3..96cdd6207 100644
--- a/src/api/wayfire/scene.hpp
+++ b/src/api/wayfire/scene.hpp
@@ -94,6 +94,41 @@ enum class node_flags : int
using node_flags_bitmask_t = uint64_t;
+/**
+ * A list of bitmask flags which indicate what parts of the node state have
+ * changed. The information is useful when updating the scenegraph's state
+ * with wf::scene::update().
+ */
+namespace update_flag
+{
+enum update_flag
+{
+ /**
+ * The list of the node's children changed.
+ */
+ CHILDREN_LIST = (1 << 0),
+ /**
+ * The node's enabled or disabled state changed.
+ */
+ ENABLED = (1 << 1),
+ /**
+ * The node's input state changed, that is, the result of find_node_at()
+ * may have changed. Typically, this is triggered when a surface is mapped,
+ * unmapped or moved.
+ */
+ INPUT_STATE = (1 << 2),
+ /**
+ * The node's geometry changed. Changes include not just the bounding box
+ * of the view, but also things like opaque regions.
+ */
+ GEOMETRY = (1 << 3),
+ /**
+ * A keyboard refocus might be necessary (for example, node removed, keyboard input state changed, etc.).
+ */
+ REFOCUS = (1 << 4),
+};
+}
+
/**
* Used as a result of an intersection of the scenegraph with the user input.
*/
@@ -298,6 +333,22 @@ class node_t : public std::enable_shared_from_this,
return children;
}
+ /**
+ * When a scenegraph change happens, core or the plugin which modifies the scenegraph is supposed to call
+ * the @scene::update() function defined below, so that the scene graph can be updated properly, render
+ * instances regenerated, etc.
+ *
+ * However, in many cases a full update is not necessary. For example, when subsurfaces are being
+ * reordered, locally regenerating the render instances within the view render instances is enough.
+ * For such cases, nodes can override this function and change the information which is propagated for
+ * the update to their parent nodes. In the above example of subsurface reordering, the subsurface root
+ * will update all of its render instances manually and not propagate CHILDREN_LIST updates to its parent.
+ */
+ virtual uint32_t optimize_update(uint32_t update_flags)
+ {
+ return update_flags;
+ }
+
public:
node_t(const node_t&) = delete;
node_t(node_t&&) = delete;
@@ -421,41 +472,6 @@ enum class layer : size_t
ALL_LAYERS,
};
-/**
- * A list of bitmask flags which indicate what parts of the node state have
- * changed. The information is useful when updating the scenegraph's state
- * with wf::scene::update().
- */
-namespace update_flag
-{
-enum update_flag
-{
- /**
- * The list of the node's children changed.
- */
- CHILDREN_LIST = (1 << 0),
- /**
- * The node's enabled or disabled state changed.
- */
- ENABLED = (1 << 1),
- /**
- * The node's input state changed, that is, the result of find_node_at()
- * may have changed. Typically, this is triggered when a surface is mapped,
- * unmapped or moved.
- */
- INPUT_STATE = (1 << 2),
- /**
- * The node's geometry changed. Changes include not just the bounding box
- * of the view, but also things like opaque regions.
- */
- GEOMETRY = (1 << 3),
- /**
- * A keyboard refocus might be necessary (for example, node removed, keyboard input state changed, etc.).
- */
- REFOCUS = (1 << 4),
-};
-}
-
/**
* A signal that the root node has been updated.
*
diff --git a/src/api/wayfire/unstable/translation-node.hpp b/src/api/wayfire/unstable/translation-node.hpp
index 6c1e8ec97..1e1a86524 100644
--- a/src/api/wayfire/unstable/translation-node.hpp
+++ b/src/api/wayfire/unstable/translation-node.hpp
@@ -7,6 +7,14 @@ namespace wf
{
namespace scene
{
+/**
+ * Emitted on: translation node
+ * The signal means that the translation node wishes to optimize a scenegraph update, and render instances
+ * should update their internal state to match.
+ */
+struct translation_node_regen_instances_signal
+{};
+
/**
* A node which simply applies an offset to its children.
*/
@@ -34,6 +42,7 @@ class translation_node_t : public wf::scene::floating_inner_node_t
void gen_render_instances(std::vector& instances,
scene::damage_callback damage, wf::output_t *output) override;
wf::geometry_t get_bounding_box() override;
+ uint32_t optimize_update(uint32_t flags) override;
protected:
wf::point_t offset = {0, 0};
@@ -46,6 +55,9 @@ class translation_node_instance_t : public render_instance_t
damage_callback push_damage;
translation_node_t *self;
wf::signal::connection_t on_node_damage;
+ wf::signal::connection_t on_regen_instances;
+ wf::output_t *shown_on;
+ void regen_instances();
public:
translation_node_instance_t(translation_node_t *self,
diff --git a/src/api/wayfire/unstable/wlr-subsurface-controller.hpp b/src/api/wayfire/unstable/wlr-subsurface-controller.hpp
index 462043e76..e2ba05efd 100644
--- a/src/api/wayfire/unstable/wlr-subsurface-controller.hpp
+++ b/src/api/wayfire/unstable/wlr-subsurface-controller.hpp
@@ -16,7 +16,7 @@ class wlr_subsurface_root_node_t : public wf::scene::translation_node_t
public:
wlr_subsurface_root_node_t(wlr_subsurface *subsurface);
std::string stringify() const override;
- void update_offset();
+ bool update_offset(bool damage = true);
private:
wlr_subsurface *subsurface;
diff --git a/src/api/wayfire/unstable/wlr-surface-controller.hpp b/src/api/wayfire/unstable/wlr-surface-controller.hpp
index 046aa5b43..a3b226384 100644
--- a/src/api/wayfire/unstable/wlr-surface-controller.hpp
+++ b/src/api/wayfire/unstable/wlr-surface-controller.hpp
@@ -22,6 +22,8 @@ class wlr_surface_controller_t
wlr_surface_controller_t(wlr_surface *surface, scene::floating_inner_ptr root_node);
~wlr_surface_controller_t();
+ void update_subsurface_order_and_position();
+
scene::floating_inner_ptr root;
wlr_surface *surface;
diff --git a/src/api/wayfire/unstable/wlr-surface-node.hpp b/src/api/wayfire/unstable/wlr-surface-node.hpp
index bcaafc357..af65f9424 100644
--- a/src/api/wayfire/unstable/wlr-surface-node.hpp
+++ b/src/api/wayfire/unstable/wlr-surface-node.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "wayfire/geometry.hpp"
+#include "wayfire/signal-definitions.hpp"
#include "wayfire/util.hpp"
#include "wayfire/view-transform.hpp"
#include
@@ -72,8 +73,17 @@ class wlr_surface_node_t : public node_t, public zero_copy_texturable_node_t
std::unique_ptr ptr_interaction;
std::unique_ptr tch_interaction;
wlr_surface *surface;
+
std::map visibility;
+ std::map pending_visibility_delta;
+ wf::signal::connection_t on_output_remove;
+
class wlr_surface_render_instance_t;
+ void handle_enter(wf::output_t *output);
+ void handle_leave(wf::output_t *output);
+ void update_pending_outputs();
+ wf::wl_idle_call idle_update_outputs;
+
wf::wl_listener_wrapper on_surface_destroyed;
wf::wl_listener_wrapper on_surface_commit;
diff --git a/src/core/scene.cpp b/src/core/scene.cpp
index 3f935e229..fb5b6922e 100644
--- a/src/core/scene.cpp
+++ b/src/core/scene.cpp
@@ -3,18 +3,15 @@
#include
#include
#include
-#include
#include
#include "scene-priv.hpp"
-#include "wayfire/debug.hpp"
#include "wayfire/geometry.hpp"
#include "wayfire/opengl.hpp"
#include "wayfire/region.hpp"
#include "wayfire/scene-input.hpp"
#include "wayfire/scene-render.hpp"
#include "wayfire/signal-provider.hpp"
-#include "wayfire/util.hpp"
#include
namespace wf
@@ -503,6 +500,7 @@ void update(node_ptr changed_node, uint32_t flags)
if (changed_node->parent())
{
+ flags = changed_node->parent()->optimize_update(flags);
update(changed_node->parent()->shared_from_this(), flags);
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 6a764f121..1bfe8e56e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -227,6 +227,10 @@ void parse_extended_debugging(const std::vector& categories)
{
LOGD("Enabling extended debugging for input method events");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::IM, 1);
+ } else if (cat == "render")
+ {
+ LOGD("Enabling extended debugging for render events");
+ wf::log::enabled_categories.set((size_t)wf::log::logging_category::RENDER, 1);
} else
{
LOGE("Unrecognized debugging category \"", cat, "\"");
diff --git a/src/output/render-manager.cpp b/src/output/render-manager.cpp
index b2a19e013..8c52da6b3 100644
--- a/src/output/render-manager.cpp
+++ b/src/output/render-manager.cpp
@@ -42,6 +42,7 @@ struct swapchain_damage_manager_t
output_t *wo;
bool pending_gamma_lut = false;
+ wf::wl_idle_call idle_recompute_visibility;
void update_scenegraph(uint32_t update_mask)
{
@@ -51,6 +52,7 @@ struct swapchain_damage_manager_t
if (update_mask & recompute_instances_on)
{
+ LOGC(RENDER, "Output ", wo->to_string(), ": regenerating instances.");
auto root = wf::get_core().scene();
scene::damage_callback push_damage = [=] (wf::region_t region)
{
@@ -66,11 +68,15 @@ struct swapchain_damage_manager_t
if (update_mask & recompute_visibility_on)
{
- wf::region_t region = this->wo->get_layout_geometry();
- for (auto& inst : render_instances)
+ idle_recompute_visibility.run_once([=] ()
{
- inst->compute_visibility(wo, region);
- }
+ LOGC(RENDER, "Output ", wo->to_string(), ": recomputing visibility.");
+ wf::region_t region = this->wo->get_layout_geometry();
+ for (auto& inst : render_instances)
+ {
+ inst->compute_visibility(wo, region);
+ }
+ });
}
}
diff --git a/src/view/translation-node.cpp b/src/view/translation-node.cpp
index 44cfdd78b..e20e0f22d 100644
--- a/src/view/translation-node.cpp
+++ b/src/view/translation-node.cpp
@@ -46,12 +46,29 @@ void wf::scene::translation_node_t::set_offset(wf::point_t offset)
this->offset = offset;
}
+uint32_t wf::scene::translation_node_t::optimize_update(uint32_t flags)
+{
+ if (flags & (update_flag::CHILDREN_LIST | update_flag::ENABLED))
+ {
+ // If we update the list of children, there is no need to notify the whole scenegraph.
+ // Instead, we can do a local update, and only update visibility.
+ flags &= ~update_flag::CHILDREN_LIST;
+ flags &= ~update_flag::ENABLED;
+ flags |= update_flag::GEOMETRY | update_flag::INPUT_STATE;
+ translation_node_regen_instances_signal data;
+ emit(&data);
+ }
+
+ return flags;
+}
+
// ----------------------------------------- Render instance -------------------------------------------------
wf::scene::translation_node_instance_t::translation_node_instance_t(
translation_node_t *self, damage_callback push_damage, wf::output_t *shown_on)
{
this->self = self;
this->push_damage = push_damage;
+ this->shown_on = shown_on;
on_node_damage = [=] (wf::scene::node_damage_signal *data)
{
@@ -59,6 +76,17 @@ wf::scene::translation_node_instance_t::translation_node_instance_t(
};
self->connect(&on_node_damage);
+ on_regen_instances = [=] (auto)
+ {
+ regen_instances();
+ };
+ self->connect(&on_regen_instances);
+ regen_instances();
+}
+
+void wf::scene::translation_node_instance_t::regen_instances()
+{
+ children.clear();
auto push_damage_child = [=] (wf::region_t child_damage)
{
child_damage += self->get_offset();
diff --git a/src/view/view-impl.cpp b/src/view/view-impl.cpp
index 86062850f..6979255db 100644
--- a/src/view/view-impl.cpp
+++ b/src/view/view-impl.cpp
@@ -1,5 +1,4 @@
#include "wayfire/core.hpp"
-#include "../core/core-impl.hpp"
#include "view-impl.hpp"
#include "wayfire/scene-input.hpp"
#include "wayfire/scene-render.hpp"
@@ -8,15 +7,12 @@
#include "wayfire/unstable/wlr-surface-controller.hpp"
#include "wayfire/unstable/wlr-surface-node.hpp"
#include "wayfire/view.hpp"
-#include "wayfire/workspace-set.hpp"
#include "wayfire/output-layout.hpp"
#include
#include
#include
#include
-#include "xdg-shell.hpp"
-
void wf::view_implementation::emit_view_map_signal(wayfire_view view, bool has_position)
{
wf::view_mapped_signal data;
diff --git a/src/view/wlr-subsurface-controller.cpp b/src/view/wlr-subsurface-controller.cpp
index 120884a5b..b5ba23b24 100644
--- a/src/view/wlr-subsurface-controller.cpp
+++ b/src/view/wlr-subsurface-controller.cpp
@@ -1,14 +1,10 @@
-#include "view/view-impl.hpp"
#include "wayfire/geometry.hpp"
#include "wayfire/scene-operations.hpp"
#include "wayfire/scene.hpp"
-#include "wayfire/signal-definitions.hpp"
-#include "wayfire/unstable/translation-node.hpp"
#include "wayfire/unstable/wlr-subsurface-controller.hpp"
#include "wayfire/unstable/wlr-surface-node.hpp"
#include
#include
-#include
wf::wlr_subsurface_controller_t::wlr_subsurface_controller_t(wlr_subsurface *sub)
{
@@ -81,13 +77,20 @@ std::string wf::wlr_subsurface_root_node_t::stringify() const
return "subsurface root node";
}
-void wf::wlr_subsurface_root_node_t::update_offset()
+bool wf::wlr_subsurface_root_node_t::update_offset(bool apply_damage)
{
wf::point_t offset = {subsurface->current.x, subsurface->current.y};
- if (offset != get_offset())
+ const bool changed = offset != get_offset();
+
+ if (changed && apply_damage)
{
scene::damage_node(this, get_bounding_box());
set_offset(offset);
scene::damage_node(this, get_bounding_box());
+ } else if (changed)
+ {
+ set_offset(offset);
}
+
+ return changed;
}
diff --git a/src/view/wlr-surface-controller.cpp b/src/view/wlr-surface-controller.cpp
index 44e2de753..ec4744129 100644
--- a/src/view/wlr-surface-controller.cpp
+++ b/src/view/wlr-surface-controller.cpp
@@ -1,16 +1,9 @@
-#include
-#include