diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 3eac20da37..38bfdf7e5c 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -1,5 +1,4 @@ --- - name: Release Windows "on": @@ -9,7 +8,7 @@ name: Release Windows jobs: build: - runs-on: windows-2022 + runs-on: windows-2025 permissions: # needed for uploading release artifact contents: write @@ -17,6 +16,16 @@ jobs: run: shell: msys2 {0} steps: + - name: Install Inno 6 + id: install_inno + shell: pwsh + run: | + winget install -e --id JRSoftware.InnoSetup -v 6.4.3 --accept-package-agreements --accept-source-agreements --disable-interactivity --scope machine + if (Test-Path "C:\Program Files (x86)\Inno Setup 6\") { + echo "inno installed successfully" + } else { + throw "could not find inno's installation folder" + } - name: Set installer name id: set_installer_name diff --git a/crates/rnote-engine/src/engine/rendering.rs b/crates/rnote-engine/src/engine/rendering.rs index 55066bbec1..79945d59b4 100644 --- a/crates/rnote-engine/src/engine/rendering.rs +++ b/crates/rnote-engine/src/engine/rendering.rs @@ -5,12 +5,14 @@ use p2d::bounding_volume::Aabb; use piet::RenderContext; use rnote_compose::color; use tracing::error; +use std::time::Instant; impl Engine { /// Update the background rendering for the current viewport. /// /// If the background pattern or zoom has changed, the background pattern needs to be regenerated first. pub fn update_background_rendering_current_viewport(&mut self) -> WidgetFlags { + let start_time = Instant::now(); let mut widget_flags = WidgetFlags::default(); #[cfg(feature = "ui")] @@ -85,11 +87,17 @@ impl Engine { } widget_flags.redraw = true; + let elapsed = start_time.elapsed(); + println!( + "update_background_rendering_current_viewport completed in {:.2?}", + elapsed + ); widget_flags } /// Update the content rendering for the current viewport. pub fn update_content_rendering_current_viewport(&mut self) -> WidgetFlags { + let start_time = Instant::now(); let mut widget_flags = WidgetFlags::default(); self.store.regenerate_rendering_in_viewport_threaded( self.engine_tasks_tx(), @@ -98,6 +106,11 @@ impl Engine { self.camera.image_scale(), ); widget_flags.redraw = true; + let elapsed = start_time.elapsed(); + println!( + "update_content_rendering_current_viewport completed in {:.2?}", + elapsed + ); widget_flags } @@ -126,6 +139,7 @@ impl Engine { /// Regenerate the background tile image, origin indicator and updates the background rendering. pub fn background_rendering_regenerate(&mut self) -> WidgetFlags { + let start_time = Instant::now(); let mut widget_flags = WidgetFlags::default(); let image_scale = self.camera.image_scale(); let scale_factor = self.camera.scale_factor(); @@ -153,6 +167,11 @@ impl Engine { widget_flags |= self.update_background_rendering_current_viewport(); widget_flags.redraw = true; + let elapsed = start_time.elapsed(); + println!( + "background_rendering_regenerate completed in {:.2?}", + elapsed + ); widget_flags } @@ -163,6 +182,7 @@ impl Engine { snapshot: >k4::Snapshot, surface_bounds: p2d::bounding_volume::Aabb, ) -> anyhow::Result<()> { + let start_time = Instant::now(); use crate::drawable::DrawableOnDoc; use crate::engine::visual_debug; use crate::engine_view; @@ -204,6 +224,11 @@ impl Engine { visual_debug::draw_statistics_to_gtk_snapshot(snapshot, self, surface_bounds)?; } + let elapsed = start_time.elapsed(); + println!( + "draw_to_gtk_snapshot completed in {:.2?}", + elapsed + ); Ok(()) } diff --git a/crates/rnote-engine/src/pens/penholder.rs b/crates/rnote-engine/src/pens/penholder.rs index 1b80b2e1ce..fe5c97b934 100644 --- a/crates/rnote-engine/src/pens/penholder.rs +++ b/crates/rnote-engine/src/pens/penholder.rs @@ -460,7 +460,7 @@ impl PenHolder { .current_style_w_override(&engine_view.config.pens_config); self.backlog_policy = match current_style { - PenStyle::Brush => BacklogPolicy::Limit(Duration::from_millis(4)), + PenStyle::Brush => BacklogPolicy::Disable, PenStyle::Shaper => BacklogPolicy::Limit(Duration::from_millis(8)), PenStyle::Typewriter => BacklogPolicy::Limit(Duration::from_millis(33)), PenStyle::Eraser => BacklogPolicy::Limit(Duration::from_millis(33)), diff --git a/crates/rnote-engine/src/store/render_comp.rs b/crates/rnote-engine/src/store/render_comp.rs index 013c0d825a..4faec46ca0 100644 --- a/crates/rnote-engine/src/store/render_comp.rs +++ b/crates/rnote-engine/src/store/render_comp.rs @@ -8,6 +8,7 @@ use p2d::bounding_volume::{Aabb, BoundingVolume}; use rnote_compose::ext::AabbExt; use rnote_compose::shapes::Shapeable; use tracing::error; +use std::time::{Duration, Instant}; /// The tolerance where check between scale-factors are considered "equal". pub(crate) const RENDER_IMAGE_SCALE_TOLERANCE: f64 = 0.01; @@ -242,19 +243,46 @@ impl StrokeStore { viewport: Aabb, image_scale: f64, ) { + let t0 = Instant::now(); let keys = self.render_components.keys().collect::>(); - + println!( + "render_component completed in {:.2?}", + t0.elapsed() + ); + + let t1 = Instant::now(); + let mut total_t2 = Duration::ZERO; + let mut total_t3 = Duration::ZERO; + let mut total_t4 = Duration::ZERO; + let mut total_t5 = Duration::ZERO; + let mut total_t6 = Duration::ZERO; + let mut cycle_count = 0; for key in keys { if let (Some(stroke), Some(render_comp)) = ( self.stroke_components.get(key), self.render_components.get_mut(key), ) { + cycle_count += 1; + + let t2 = Instant::now(); let tasks_tx = tasks_tx.clone(); + let elapsed_t2 = t2.elapsed(); + total_t2 += elapsed_t2; + //println!("task_tx completed in {:.2?}", elapsed_t2); + + let t3 = Instant::now(); let stroke_bounds = stroke.bounds(); + let elapsed_t3 = t3.elapsed(); + total_t3 += elapsed_t3; + //println!("stroke_bounds completed in {:.2?}", elapsed_t3); + + let t4 = Instant::now(); let viewport_extended = viewport.extend_by(viewport.extents() * render::VIEWPORT_EXTENTS_MARGIN_FACTOR); - - // skip and clear image buffer if stroke is not in viewport + let elapsed_t4 = t4.elapsed(); + total_t4 += elapsed_t4; + //println!("viewport_extend completed in {:.2?}", elapsed_t4); + if !viewport_extended.intersects(&stroke_bounds) { #[cfg(feature = "ui")] { @@ -264,19 +292,15 @@ impl StrokeStore { render_comp.state = RenderCompState::Dirty; continue; } - - // only check if rerendering is not forced + if !force_regenerate { match render_comp.state { RenderCompState::Complete | RenderCompState::BusyRenderingInTask => { continue; } RenderCompState::ForViewport(old_viewport) => { - /// This factor is applied on top of the viewport extents margin factor, - /// so that rerendering is started a bit earlier to reaching - /// the edges of the viewport of the current rendered images. const VIEWPORT_EXTENTS_MARGIN_RERENDER_THRESHOLD: f64 = 0.7; - + if old_viewport.contains( &(viewport.extend_by( viewport.extents() @@ -290,12 +314,15 @@ impl StrokeStore { RenderCompState::Dirty => {} } } - - // indicates that a task has now started to render the stroke + + let t5 = Instant::now(); render_comp.state = RenderCompState::BusyRenderingInTask; let stroke = stroke.clone(); - - // Spawn a new thread for image rendering + let elapsed_t5 = t5.elapsed(); + total_t5 += elapsed_t5; + //println!("clone completed in {:.2?}", elapsed_t5); + + let t6 = Instant::now(); rayon::spawn( move || match stroke.gen_images(viewport_extended, image_scale) { Ok(images) => { @@ -312,8 +339,23 @@ impl StrokeStore { } }, ); + let elapsed_t6 = t6.elapsed(); + total_t6 += elapsed_t6; + //println!("spawn completed in {:.2?}", elapsed_t6); } } + + println!("\nSummary for {} cycle(s):", cycle_count); + println!("Total task_tx time: {:.2?}", total_t2); + println!("Total stroke_bounds time: {:.2?}", total_t3); + println!("Total viewport_extend time:{:.2?}", total_t4); + println!("Total clone time: {:.2?}", total_t5); + println!("Total spawn time: {:.2?}", total_t6); + println!(); + println!( + "for keys completed in {:.2?}", + t1.elapsed() + ); } /// Clear all rendering for all strokes. diff --git a/justfile b/justfile index afaf0abab6..d36ea80937 100644 --- a/justfile +++ b/justfile @@ -2,15 +2,13 @@ # Either 'true' or 'false' ci := "false" +linux_distr := `lsb_release -ds | tr '[:upper:]' '[:lower:]'` log_level := "debug" build_folder := "_mesonbuild" flatpak_app_folder := "_flatpak_app" flatpak_repo_folder := "_flatpak_repo" mingw64_prefix_path := "C:/msys64/mingw64" -[private] -linux_distr := `lsb_release -ds | tr '[:upper:]' '[:lower:]'` -[private] sudo_cmd := "sudo" export LANG := "C" @@ -28,7 +26,8 @@ default: prerequisites: #!/usr/bin/env bash set -euxo pipefail - if [[ ('{{linux_distr}}' =~ 'fedora') ]]; then + + if [[ ('{{linux_distr}}' =~ 'fedora') || ('{{linux_distr}}' =~ 'rhel') || ('{{linux_distr}}' =~ 'alma') ]]; then {{sudo_cmd}} dnf install -y \ gcc gcc-c++ clang clang-devel python3 make cmake meson just git appstream gettext desktop-file-utils \ shared-mime-info kernel-devel gtk4-devel libadwaita-devel poppler-glib-devel poppler-data alsa-lib-devel \ @@ -42,13 +41,15 @@ prerequisites: echo "Unable to install system dependencies, unsupported distro." exit 1 fi + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y export PATH="$HOME/.cargo/bin:$PATH" prerequisites-flatpak: prerequisites #!/usr/bin/env bash set -euxo pipefail - if [[ ('{{linux_distr}}' =~ 'fedora') ]]; then + + if [[ ('{{linux_distr}}' =~ 'fedora') || ('{{linux_distr}}' =~ 'rhel') || ('{{linux_distr}}' =~ 'alma') ]]; then {{sudo_cmd}} dnf install -y \ flatpak flatpak-builder elif [[ '{{linux_distr}}' =~ 'debian' || '{{linux_distr}}' =~ 'ubuntu' ]]; then @@ -59,6 +60,7 @@ prerequisites-flatpak: prerequisites echo "Unable to install system dependencies, unsupported distro." exit 1 fi + flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo flatpak install -y org.gnome.Platform//48 org.gnome.Sdk//48 org.freedesktop.Sdk.Extension.rust-stable//24.08 \ org.freedesktop.Sdk.Extension.llvm19//24.08 @@ -66,7 +68,8 @@ prerequisites-flatpak: prerequisites prerequisites-dev: prerequisites #!/usr/bin/env bash set -euxo pipefail - if [[ ('{{linux_distr}}' =~ 'fedora') ]]; then + + if [[ ('{{linux_distr}}' =~ 'fedora') || ('{{linux_distr}}' =~ 'rhel') || ('{{linux_distr}}' =~ 'alma') ]]; then {{sudo_cmd}} dnf install -y \ yamllint yq opencc-tools elif [[ '{{linux_distr}}' =~ 'debian' || '{{linux_distr}}' =~ 'ubuntu' ]]; then @@ -77,9 +80,11 @@ prerequisites-dev: prerequisites echo "Unable to install system dependencies, unsupported distro." exit 1 fi + if [[ "{{ci}}" != "true" ]]; then ln -sf build-aux/git-hooks/pre-commit.hook .git/hooks/pre-commit fi + curl -L --proto '=https' --tlsv1.2 -sSf \ https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash cargo binstall -y cargo-nextest cargo-edit cargo-deny @@ -92,7 +97,9 @@ prerequisites-win: mingw-w64-x86_64-meson mingw-w64-x86_64-diffutils mingw-w64-x86_64-desktop-file-utils \ mingw-w64-x86_64-appstream mingw-w64-x86_64-gtk4 mingw-w64-x86_64-libadwaita mingw-w64-x86_64-poppler \ mingw-w64-x86_64-poppler-data mingw-w64-x86_64-angleproject + mv /mingw64/lib/libpthread.dll.a /mingw64/lib/libpthread.dll.a.bak + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y export PATH="$HOME/.cargo/bin:$PATH" @@ -116,7 +123,7 @@ setup-win-installer installer_name="rnote-win-installer": meson setup \ --prefix={{ mingw64_prefix_path }} \ -Dprofile=default \ - -Dcli=false \ + -Dcli=true \ -Dwin-installer-name={{ installer_name }} \ -Dci={{ ci }} \ {{ build_folder }}