much improved paint and reflow scheduling

This commit is contained in:
hippoz 2022-10-15 21:35:00 +03:00
parent 002318c213
commit dd894d1024
Signed by: hippoz
GPG key ID: 7C52899193467641
6 changed files with 63 additions and 20 deletions

View file

@ -95,4 +95,28 @@ double Box::clamp_for_dimension(Direction direction, double value) {
} }
} }
Box Box::united(const Box &other) {
if (is_null()) {
return other;
}
if (other.is_null()) {
return *this;
}
Box rect;
rect.set_left(std::min(left(), other.left()));
rect.set_top(std::min(top(), other.top()));
rect.set_right(std::max(right(), other.right()));
rect.set_bottom(std::max(bottom(), other.bottom()));
return rect;
}
bool Box::is_null() const {
return !(m_x && m_y && m_width && m_height);
}
std::string Box::debug() {
return "Box(" + std::to_string(m_x) + ", " + std::to_string(m_y) + ", " + std::to_string(m_width) + ", " + std::to_string(m_height) + ")";
}
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Point.hpp" #include "Point.hpp"
#include <string>
namespace Raven { namespace Raven {
@ -51,6 +52,11 @@ public:
double min_height() const { return m_min_height; } double min_height() const { return m_min_height; }
double max_width() const { return m_max_width; } double max_width() const { return m_max_width; }
double max_height() const { return m_max_height; } double max_height() const { return m_max_height; }
double top() const { return y(); }
double bottom() const { return y() + height() - 1; }
double left() const { return x(); }
double right() const { return x() + width() - 1; }
bool is_null() const;
double dimension_at(Direction direction) { return direction == Direction::Horizontal ? width() : height(); } double dimension_at(Direction direction) { return direction == Direction::Horizontal ? width() : height(); }
double max_dimension_at(Direction direction) { return direction == Direction::Horizontal ? max_width() : max_height(); } double max_dimension_at(Direction direction) { return direction == Direction::Horizontal ? max_width() : max_height(); }
double min_dimension_at(Direction direction) { return direction == Direction::Horizontal ? min_width() : min_height(); } double min_dimension_at(Direction direction) { return direction == Direction::Horizontal ? min_width() : min_height(); }
@ -60,6 +66,10 @@ public:
void set_y(double y) { m_y = y; } void set_y(double y) { m_y = y; }
void set_width(double width); void set_width(double width);
void set_height(double height); void set_height(double height);
void set_top(double top) { set_y(top); }
void set_bottom(double bottom) { set_height(bottom - y() + 1); }
void set_right(double right) { set_width(right - x() + 1); }
void set_left(double left) { set_x(left); }
void set_max_width(double max_width) { m_max_width = max_width; set_width(m_width); } void set_max_width(double max_width) { m_max_width = max_width; set_width(m_width); }
void set_max_height(double max_height) { m_max_height = max_height; set_height(m_height); } void set_max_height(double max_height) { m_max_height = max_height; set_height(m_height); }
@ -73,6 +83,9 @@ public:
bool contains_box(const Box &other) const; bool contains_box(const Box &other) const;
Box offset(double x, double y); Box offset(double x, double y);
Box united(const Box &other);
std::string debug();
}; };
} }

View file

@ -192,18 +192,18 @@ void Widget::handle_repaint_rect(RepaintRectEvent &event) {
} }
void Widget::handle_relayout_subtree(RelayoutSubtreeEvent &event) { void Widget::handle_relayout_subtree(RelayoutSubtreeEvent &event) {
on_layout(); // hack on_layout();
m_window_relative = compute_window_relative(); m_window_relative = compute_window_relative();
for (auto child : m_children) {
child->dispatch_event(event);
}
if (m_layout) { if (m_layout) {
m_layout->run(); m_layout->run();
} }
for (auto child : m_children) {
child->dispatch_event(event);
}
on_after_layout(); on_after_layout();
} }

View file

@ -76,9 +76,10 @@ bool Window::dispatch_to_main_widget(Event &event) {
} }
void Window::repaint(Box geometry) { void Window::repaint(Box geometry) {
m_did_repaint_during_batch = true; if (m_batches) {
if (m_batches) m_invalidated_area = m_invalidated_area.united(geometry);
return; return;
}
auto event = RepaintRectEvent(true, geometry); auto event = RepaintRectEvent(true, geometry);
dispatch_to_main_widget(event); dispatch_to_main_widget(event);
@ -116,7 +117,6 @@ void Window::reflow() {
} }
void Window::start_batch() { void Window::start_batch() {
//INFO << "New batch started. Current count: " << m_batches << std::endl;
m_batches++; m_batches++;
} }
@ -127,7 +127,6 @@ void Window::end_batch() {
// we are only interested in performing batch operations for the last batch // we are only interested in performing batch operations for the last batch
if (m_batches > 1) { if (m_batches > 1) {
m_batches--; m_batches--;
//INFO << "Consumed batch. Current count: " << m_batches << std::endl;
return; return;
} }
@ -135,17 +134,17 @@ void Window::end_batch() {
if (m_did_relayout_during_batch) { if (m_did_relayout_during_batch) {
reflow(); reflow();
} else if (m_did_repaint_during_batch) { } else if (!m_invalidated_area.is_null()) {
repaint(); repaint(m_invalidated_area);
} }
m_did_relayout_during_batch = false; m_did_relayout_during_batch = false;
m_did_repaint_during_batch = false; m_invalidated_area = {0, 0, 0, 0};
INFO << "Performed all batch actions." << std::endl;
} }
void Window::run(bool block) { void Window::run(bool block) {
XEvent e; XEvent e;
bool is_loop_batch_started = false;
for (;;) { for (;;) {
if (block || XPending(m_x_display)) if (block || XPending(m_x_display))
@ -153,10 +152,13 @@ void Window::run(bool block) {
else else
break; break;
if (!is_loop_batch_started) {
start_batch();
is_loop_batch_started = true;
}
switch (e.type) { switch (e.type) {
case MapNotify: { case MapNotify: {
INFO << "[X11 EVENT] MapNotify" << std::endl; INFO << "[X11 EVENT] MapNotify" << std::endl;
end_batch();
break; break;
} }
case ConfigureNotify: { case ConfigureNotify: {
@ -210,14 +212,16 @@ void Window::run(bool block) {
} }
} }
if (XPending(m_x_display) == 0 && !m_microtasks.empty()) { if (XPending(m_x_display) == 0) {
start_batch();
while (!m_microtasks.empty()) { while (!m_microtasks.empty()) {
auto callback = m_microtasks.front(); auto callback = m_microtasks.front();
callback(); callback();
m_microtasks.pop(); m_microtasks.pop();
} }
end_batch(); if (is_loop_batch_started) {
end_batch();
is_loop_batch_started = false;
}
} }
} }
} }

View file

@ -59,8 +59,8 @@ private:
Box m_rect { 0, 0, 800, 600 }; Box m_rect { 0, 0, 800, 600 };
Painter m_painter {}; Painter m_painter {};
Cairo::RefPtr<Cairo::XlibSurface> m_xlib_surface { nullptr }; Cairo::RefPtr<Cairo::XlibSurface> m_xlib_surface { nullptr };
int m_batches { 1 }; int m_batches { 0 };
bool m_did_repaint_during_batch { false }; Box m_invalidated_area {0, 0, 0, 0};
bool m_did_relayout_during_batch { false }; bool m_did_relayout_during_batch { false };
std::queue<std::function<void()>> m_microtasks; std::queue<std::function<void()>> m_microtasks;

View file

@ -21,6 +21,7 @@
int main() { int main() {
Raven::Window window {}; Raven::Window window {};
window.spawn_window(); window.spawn_window();
window.start_batch();
auto main_widget = window.set_main_widget<Raven::Widget>(); auto main_widget = window.set_main_widget<Raven::Widget>();
auto main_widget_layout = main_widget->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal); auto main_widget_layout = main_widget->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
@ -66,6 +67,7 @@ int main() {
} }
list_view->elements_updated(); list_view->elements_updated();
window.end_batch();
window.run(true); window.run(true);
return 0; return 0;
} }