From 4f1074526eae72abf7da433eac36988259bd7ee4 Mon Sep 17 00:00:00 2001 From: Ilya Zlobintsev Date: Sat, 8 Feb 2025 21:29:04 +0200 Subject: [PATCH] feat: wip plotters-gtk4 --- Cargo.lock | 38 ++++++++-- lact-gui/Cargo.toml | 3 +- lact-gui/src/app/graphs_window/plot/imp.rs | 73 ++++++++++++------- .../app/graphs_window/plot/render_thread.rs | 24 ++++-- lact/Cargo.toml | 1 + lact/benches/bench.rs | 2 + 6 files changed, 102 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9d0833..3a703bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1283,6 +1283,7 @@ version = "0.7.1" dependencies = [ "anyhow", "divan", + "gtk4", "lact-cli", "lact-daemon", "lact-gui", @@ -1366,7 +1367,7 @@ dependencies = [ "lact-schema", "libadwaita", "plotters", - "plotters-cairo", + "plotters-gtk4", "pretty_assertions", "relm4", "relm4-components", @@ -1776,6 +1777,32 @@ dependencies = [ "system-deps", ] +[[package]] +name = "pangocairo" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4690509a2fea2a6552a0ef8aa3e5f790c1365365ee0712afa1aedb39af3997b6" +dependencies = [ + "cairo-rs", + "glib", + "libc", + "pango", + "pangocairo-sys", +] + +[[package]] +name = "pangocairo-sys" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be6ac24147911a6a46783922fc288cf02f67570bc0d360e563b5b26aead6767" +dependencies = [ + "cairo-sys-rs", + "glib-sys", + "libc", + "pango-sys", + "system-deps", +] + [[package]] name = "parking" version = "2.2.1" @@ -1857,12 +1884,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] -name = "plotters-cairo" -version = "0.7.0" +name = "plotters-gtk4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e7a3a2567b691ed2f0670ea3cc39988add29c968228b474ec5fe8261b1ff2a5" +checksum = "2f18ee173b0c8e6d8cb01c1e32a9b41bf41d74b277a69f22277bab05870e13d7" dependencies = [ - "cairo-rs", + "gtk4", + "pangocairo", "plotters-backend", ] diff --git a/lact-gui/Cargo.toml b/lact-gui/Cargo.toml index d6e1ec6..fa050a9 100644 --- a/lact-gui/Cargo.toml +++ b/lact-gui/Cargo.toml @@ -32,13 +32,14 @@ plotters = { version = "0.3.5", default-features = false, features = [ "line_series", "full_palette", ] } -plotters-cairo = "0.7.0" +# plotters-cairo = "0.7.0" cairo-rs = { version = "0.20", default-features = false } itertools = "0.13.0" thread-priority = "1.1.0" divan = { workspace = true, optional = true } +plotters-gtk4 = "0.5.0" [dev-dependencies] pretty_assertions = "1.4.0" diff --git a/lact-gui/src/app/graphs_window/plot/imp.rs b/lact-gui/src/app/graphs_window/plot/imp.rs index 04864f7..b82eb39 100644 --- a/lact-gui/src/app/graphs_window/plot/imp.rs +++ b/lact-gui/src/app/graphs_window/plot/imp.rs @@ -2,6 +2,7 @@ use chrono::NaiveDateTime; use glib::Properties; use gtk::{glib, prelude::*, subclass::prelude::*}; +use plotters_gtk4::SnapshotBackend; use std::cell::Cell; use std::cell::RefCell; @@ -24,7 +25,7 @@ pub struct Plot { secondary_y_label_area_relative_size: Cell, pub(super) data: RefCell, pub(super) dirty: Cell, - render_thread: RenderThread, + // render_thread: RenderThread, #[property(get, set)] time_period_seconds: Cell, } @@ -50,42 +51,58 @@ impl ObjectImpl for Plot { impl WidgetImpl for Plot { fn snapshot(&self, snapshot: >k::Snapshot) { + snapshot.scale(0.25, 0.25); + let width = self.obj().width() as u32; let height = self.obj().height() as u32; if width == 0 || height == 0 { return; } + let request = RenderRequest { + data: self.data.borrow().clone(), + width, + height, + title: self.title.borrow().clone(), + value_suffix: self.value_suffix.borrow().clone(), + secondary_value_suffix: self.secondary_value_suffix.borrow().clone(), + y_label_area_relative_size: self.y_label_area_relative_size.get(), + secondary_y_label_relative_area_size: self.secondary_y_label_area_relative_size.get(), + supersample_factor: 4, + time_period_seconds: self.time_period_seconds.get(), + }; + let backend = SnapshotBackend::new(snapshot, (width * 4, height * 4)); + request.draw(backend).unwrap(); - let last_texture = self.render_thread.get_last_texture(); - let size_changed = last_texture - .as_ref() - .map(|texture| (texture.width() as u32, texture.height() as u32) != (width, height)) - .unwrap_or(true); + // let last_texture = self.render_thread.get_last_texture(); + // let size_changed = last_texture + // .as_ref() + // .map(|texture| (texture.width() as u32, texture.height() as u32) != (width, height)) + // .unwrap_or(true); - if self.dirty.replace(false) || size_changed { - self.render_thread.replace_render_request(RenderRequest { - data: self.data.borrow().clone(), - width, - height, - title: self.title.borrow().clone(), - value_suffix: self.value_suffix.borrow().clone(), - secondary_value_suffix: self.secondary_value_suffix.borrow().clone(), - y_label_area_relative_size: self.y_label_area_relative_size.get(), - secondary_y_label_relative_area_size: self - .secondary_y_label_area_relative_size - .get(), - supersample_factor: 4, - time_period_seconds: self.time_period_seconds.get(), - }); - } + // if self.dirty.replace(false) || size_changed { + // self.render_thread.replace_render_request(RenderRequest { + // data: self.data.borrow().clone(), + // width, + // height, + // title: self.title.borrow().clone(), + // value_suffix: self.value_suffix.borrow().clone(), + // secondary_value_suffix: self.secondary_value_suffix.borrow().clone(), + // y_label_area_relative_size: self.y_label_area_relative_size.get(), + // secondary_y_label_relative_area_size: self + // .secondary_y_label_area_relative_size + // .get(), + // supersample_factor: 4, + // time_period_seconds: self.time_period_seconds.get(), + // }); + // } - // Rendering is always behind by at least one frame, but it's not an issue - if let Some(texture) = last_texture { - let bounds = gtk::graphene::Rect::new(0.0, 0.0, width as f32, height as f32); - // Uses by default Trillinear texture filtering, which is quite good at 4x supersampling - snapshot.append_texture(&texture, &bounds); - } + // // Rendering is always behind by at least one frame, but it's not an issue + // if let Some(texture) = last_texture { + // let bounds = gtk::graphene::Rect::new(0.0, 0.0, width as f32, height as f32); + // // Uses by default Trillinear texture filtering, which is quite good at 4x supersampling + // snapshot.append_texture(&texture, &bounds); + // } } } diff --git a/lact-gui/src/app/graphs_window/plot/render_thread.rs b/lact-gui/src/app/graphs_window/plot/render_thread.rs index 67dd61e..fca05df 100644 --- a/lact-gui/src/app/graphs_window/plot/render_thread.rs +++ b/lact-gui/src/app/graphs_window/plot/render_thread.rs @@ -9,7 +9,6 @@ use itertools::Itertools; use plotters::prelude::*; use plotters::style::colors::full_palette::DEEPORANGE_100; use plotters::style::RelativeSize; -use plotters_cairo::CairoBackend; use std::cmp::{max, min}; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, Mutex}; @@ -131,7 +130,7 @@ impl RenderThread { } fn process_request(render_request: RenderRequest, last_texture: &Mutex>) { - // Create a new ImageSurface for Cairo rendering. + /*// Create a new ImageSurface for Cairo rendering. let mut surface = ImageSurface::create( cairo::Format::ARgb32, (render_request.width * render_request.supersample_factor) as i32, @@ -178,7 +177,7 @@ fn process_request(render_request: RenderRequest, last_texture: &Mutex { *last_texture = result; } - }; + };*/ } // Implement the default constructor for RenderThread using the `new` method. @@ -400,11 +399,13 @@ mod benches { use crate::app::graphs_window::plot::PlotData; use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; use divan::{counter::ItemsCount, Bencher}; + use gtk::prelude::SnapshotExt; + use plotters_gtk4::SnapshotBackend; use std::sync::Mutex; #[divan::bench] fn render_plot(bencher: Bencher) { - let last_texture = &Mutex::new(None); + // let last_texture = &Mutex::new(None); bencher .with_inputs(sample_plot_data) @@ -423,7 +424,20 @@ mod benches { time_period_seconds: 60, }; - process_request(request, last_texture) + let snapshot = gtk::Snapshot::new(); + snapshot.scale( + 1.0 / request.supersample_factor as f32, + 1.0 / request.supersample_factor as f32, + ); + let backend = SnapshotBackend::new( + &snapshot, + ( + request.width * request.supersample_factor, + request.height * request.supersample_factor, + ), + ); + request.draw(backend).unwrap(); + // process_request(request, last_texture) }); } diff --git a/lact/Cargo.toml b/lact/Cargo.toml index 5404dd6..e2d5f0e 100644 --- a/lact/Cargo.toml +++ b/lact/Cargo.toml @@ -18,6 +18,7 @@ anyhow = { workspace = true } divan = { workspace = true } lact-daemon = { path = "../lact-daemon", features = ["bench"] } lact-gui = { path = "../lact-gui", features = ["bench"] } +gtk = { version = "0.9", package = "gtk4" } [[bench]] name = "bench" diff --git a/lact/benches/bench.rs b/lact/benches/bench.rs index ac09dbe..74b196e 100644 --- a/lact/benches/bench.rs +++ b/lact/benches/bench.rs @@ -3,5 +3,7 @@ fn main() { let _ = lact_daemon::run; let _ = lact_gui::run; + let _ = gtk::init(); + divan::main(); }