[librsvg: 5/9] Reimplement pixbuf_from_surface() in terms of iterators and .as_pixels()



commit 950c45c352ba7efb2e511486dd23cf41412cfa7a
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu May 28 19:41:55 2020 -0500

    Reimplement pixbuf_from_surface() in terms of iterators and .as_pixels()
    
    This gets rid of the calculation and checking of the offset of each
    pixel.
    
    Baseline:
    pixbuf_from_surface     time:   [1.5888 ms 1.5899 ms 1.5911 ms]
    
    Use SharedImageSurface.rows():
    pixbuf_from_surface     time:   [1.4434 ms 1.4514 ms 1.4592 ms]
                            change: [-9.5490% -9.2322% -8.8676%] (p = 0.00 < 0.05)
    
    Use as_pixels() and iterators for GdkPixbuf:
    pixbuf_from_surface     time:   [672.70 us 673.20 us 673.75 us]
                            change: [-53.489% -53.329% -53.174%] (p = 0.00 < 0.05)
    
    This is part of https://gitlab.gnome.org/GNOME/librsvg/-/issues/585

 Cargo.lock                |  7 ++---
 librsvg/Cargo.toml        |  1 +
 librsvg/pixbuf_utils.rs   | 66 +++++++++++++++++++----------------------------
 rsvg_internals/src/lib.rs |  2 +-
 4 files changed, 32 insertions(+), 44 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 9eee9350..c549c804 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -202,7 +202,7 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-queue"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
  "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -704,6 +704,7 @@ dependencies = [
  "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rgb 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "rsvg_internals 0.0.1",
  "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1258,7 +1259,7 @@ version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
  "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-queue 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1767,7 +1768,7 @@ dependencies = [
 "checksum criterion-plot 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"ddeaf7989f00f2e1d871a26a110f3ed713632feac17f65f03ca938c542618b60"
 "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = 
"9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
 "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
-"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
+"checksum crossbeam-queue 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"ab6bffe714b6bb07e42f201352c34f51fefd355ace793f9e638ebd52d23f98d2"
 "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
 "checksum cssparser 0.27.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
 "checksum cssparser-macros 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"
diff --git a/librsvg/Cargo.toml b/librsvg/Cargo.toml
index 669ec866..cb2c9f19 100644
--- a/librsvg/Cargo.toml
+++ b/librsvg/Cargo.toml
@@ -23,6 +23,7 @@ gio = { version="0.8.0", features=["v2_50"] } # per configure.ac
 gio-sys = "0.9.0"
 gobject-sys = "0.9.0"
 libc = "0.2"
+rgb = "0.8.17"
 rsvg_internals = { path = "../rsvg_internals" }
 url = "2"
 
diff --git a/librsvg/pixbuf_utils.rs b/librsvg/pixbuf_utils.rs
index e6dcef7c..6d5df5a7 100644
--- a/librsvg/pixbuf_utils.rs
+++ b/librsvg/pixbuf_utils.rs
@@ -4,6 +4,7 @@ use std::ptr;
 use gdk_pixbuf::{Colorspace, Pixbuf};
 use gio::prelude::*;
 use glib::translate::*;
+use rgb::{AsPixels, RGBA8};
 use url::Url;
 
 use crate::c_api::checked_i32;
@@ -36,61 +37,46 @@ pub fn pixbuf_from_surface(surface: &SharedImageSurface) -> Result<Pixbuf, Rende
     let height = surface.height();
 
     let pixbuf = pixbuf_new(width, height)?;
+    assert!(pixbuf.get_colorspace() == Colorspace::Rgb);
+    assert!(pixbuf.get_bits_per_sample() == 8);
+    assert!(pixbuf.get_n_channels() == 4);
 
-    for (y, row) in surface.rows().enumerate() {
-        for (x, pixel) in row.iter().enumerate() {
-            let (r, g, b, a) = if pixel.a == 0 {
+    let pixels = unsafe { pixbuf.get_pixels() };
+    let width = width as usize;
+    let height = height as usize;
+    let stride = pixbuf.get_rowstride() as usize;
+    let width_in_bytes = width * 4;
+    assert!(width_in_bytes <= stride);
+
+    let pixbuf_rows = pixels.chunks_exact_mut(stride).take(height);
+
+    for (src_row, dest_row) in surface.rows().zip(pixbuf_rows) {
+        let row: &mut [RGBA8] = dest_row[..width_in_bytes].as_pixels_mut();
+
+        for (src, dest) in src_row.iter().zip(row.iter_mut()) {
+            let (r, g, b, a) = if src.a == 0 {
                 (0, 0, 0, 0)
             } else {
                 let pixel = Pixel {
-                    r: pixel.r,
-                    g: pixel.g,
-                    b: pixel.b,
-                    a: pixel.a,
+                    r: src.r,
+                    g: src.g,
+                    b: src.b,
+                    a: src.a,
                 }.unpremultiply();
 
                 (pixel.r, pixel.g, pixel.b, pixel.a)
             };
 
-            // FIXME: Use pixbuf.put_pixel when
-            // https://github.com/gtk-rs/gdk-pixbuf/issues/147
-            // is integrated
-            my_put_pixel(&pixbuf, x as i32, y as i32, r, g, b, a);
+            dest.r = r;
+            dest.g = g;
+            dest.b = b;
+            dest.a = a;
         }
     }
 
     Ok(pixbuf)
 }
 
-// Copied from gtk-rs/gdk-pixbuf
-//
-// See the following:
-//   https://gitlab.gnome.org/GNOME/librsvg/-/issues/584
-//   https://github.com/gtk-rs/gdk-pixbuf/issues/147
-//
-// Arithmetic can overflow in the computation of `pos` if it is not done with usize
-// values (everything coming out of a Pixbuf is i32).
-//
-// When this fix appears in a gtk-rs release, we can remove this.
-fn my_put_pixel(pixbuf: &Pixbuf, x: i32, y: i32, red: u8, green: u8, blue: u8, alpha: u8) {
-    unsafe {
-        let x = x as usize;
-        let y = y as usize;
-        let n_channels = pixbuf.get_n_channels() as usize;
-        assert!(n_channels == 3 || n_channels == 4);
-        let rowstride = pixbuf.get_rowstride() as usize;
-        let pixels = pixbuf.get_pixels();
-        let pos = y * rowstride + x * n_channels;
-
-        pixels[pos] = red;
-        pixels[pos + 1] = green;
-        pixels[pos + 2] = blue;
-        if n_channels == 4 {
-            pixels[pos + 3] = alpha;
-        }
-    }
-}
-
 enum SizeKind {
     Zoom,
     WidthHeight,
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 0c5f2784..84aa67fd 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -66,7 +66,7 @@ pub use crate::structure::IntrinsicDimensions;
 pub use crate::surface_utils::{
     iterators::Pixels,
     shared_surface::{SharedImageSurface, SurfaceType},
-    Pixel,
+    CairoARGB, Pixel,
 };
 
 pub use crate::viewbox::ViewBox;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]