decoder/tiling: Make shared frame buffer a struct
This commit is contained in:
parent
6827a9c176
commit
139bd4ebb2
6 changed files with 52 additions and 68 deletions
|
|
@ -16,13 +16,13 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
//! Decode using glycin
|
//! Decode using glycin
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use arc_swap::ArcSwap;
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::decoder::tiling::{self, FrameBufferExt};
|
use crate::decoder::tiling::{self, SharedFrameBuffer};
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::metadata::{ImageFormat, Metadata};
|
use crate::metadata::{ImageFormat, Metadata};
|
||||||
|
|
||||||
|
|
@ -41,11 +41,7 @@ impl Drop for Glycin {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Glycin {
|
impl Glycin {
|
||||||
pub fn new(
|
pub fn new(file: gio::File, updater: UpdateSender, tiles: Arc<SharedFrameBuffer>) -> Self {
|
||||||
file: gio::File,
|
|
||||||
updater: UpdateSender,
|
|
||||||
tiles: Arc<ArcSwap<tiling::FrameBuffer>>,
|
|
||||||
) -> Self {
|
|
||||||
let cancellable = gio::Cancellable::new();
|
let cancellable = gio::Cancellable::new();
|
||||||
let cancellable_ = cancellable.clone();
|
let cancellable_ = cancellable.clone();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,15 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
//! Decode using librsvg
|
//! Decode using librsvg
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use arc_swap::ArcSwap;
|
|
||||||
use async_channel as mpsc;
|
use async_channel as mpsc;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::decoder::tiling::{self, FrameBufferExt};
|
use crate::decoder::tiling::SharedFrameBuffer;
|
||||||
use crate::decoder::TileRequest;
|
use crate::decoder::TileRequest;
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::metadata::ImageFormat;
|
use crate::metadata::ImageFormat;
|
||||||
|
|
@ -61,11 +61,7 @@ impl Drop for Svg {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Svg {
|
impl Svg {
|
||||||
pub fn new(
|
pub fn new(file: gio::File, updater: UpdateSender, tiles: Arc<SharedFrameBuffer>) -> Self {
|
||||||
file: gio::File,
|
|
||||||
updater: UpdateSender,
|
|
||||||
tiles: Arc<ArcSwap<tiling::FrameBuffer>>,
|
|
||||||
) -> Self {
|
|
||||||
let current_request: Arc<std::sync::RwLock<Request>> = Default::default();
|
let current_request: Arc<std::sync::RwLock<Request>> = Default::default();
|
||||||
let request_store = current_request.clone();
|
let request_store = current_request.clone();
|
||||||
let cancellable = gio::Cancellable::new();
|
let cancellable = gio::Cancellable::new();
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,18 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
//! Decodes several image formats
|
//! Decodes several image formats
|
||||||
|
|
||||||
pub mod formats;
|
pub mod formats;
|
||||||
pub mod tiling;
|
pub mod tiling;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use arc_swap::ArcSwap;
|
|
||||||
use formats::*;
|
use formats::*;
|
||||||
pub use formats::{ImageDimensionDetails, RSVG_MAX_SIZE};
|
pub use formats::{ImageDimensionDetails, RSVG_MAX_SIZE};
|
||||||
use futures_channel::mpsc;
|
use futures_channel::mpsc;
|
||||||
use tiling::FrameBufferExt;
|
|
||||||
|
|
||||||
|
use self::tiling::SharedFrameBuffer;
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::metadata::{ImageFormat, Metadata};
|
use crate::metadata::{ImageFormat, Metadata};
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ impl Decoder {
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
file: gio::File,
|
file: gio::File,
|
||||||
mime_type: Option<String>,
|
mime_type: Option<String>,
|
||||||
tiles: Arc<ArcSwap<tiling::FrameBuffer>>,
|
tiles: Arc<SharedFrameBuffer>,
|
||||||
) -> (Self, mpsc::UnboundedReceiver<DecoderUpdate>) {
|
) -> (Self, mpsc::UnboundedReceiver<DecoderUpdate>) {
|
||||||
let (sender, receiver) = mpsc::unbounded();
|
let (sender, receiver) = mpsc::unbounded();
|
||||||
|
|
||||||
|
|
@ -137,7 +137,7 @@ impl Decoder {
|
||||||
update_sender: UpdateSender,
|
update_sender: UpdateSender,
|
||||||
file: gio::File,
|
file: gio::File,
|
||||||
mime_type: Option<String>,
|
mime_type: Option<String>,
|
||||||
tiles: Arc<ArcSwap<tiling::FrameBuffer>>,
|
tiles: Arc<SharedFrameBuffer>,
|
||||||
) -> FormatDecoder {
|
) -> FormatDecoder {
|
||||||
if let Some(mime_type) = mime_type {
|
if let Some(mime_type) = mime_type {
|
||||||
// Known things we want to match here are
|
// Known things we want to match here are
|
||||||
|
|
|
||||||
|
|
@ -572,78 +572,68 @@ impl RectExt for graphene::Rect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We always store [`FrameBuffer`]s in an [`ArcSwap`].
|
#[derive(Debug, Default)]
|
||||||
/// This trait adds convenience functions for this.
|
pub struct SharedFrameBuffer {
|
||||||
pub trait FrameBufferExt {
|
buffer: ArcSwap<FrameBuffer>,
|
||||||
fn push(&self, tile: Tile);
|
|
||||||
fn push_tile(&self, tiling: Tiling, position: Coordinates, texture: gdk::Texture);
|
|
||||||
fn push_frame(&self, tile: Tile, dimensions: Coordinates, delay: Duration);
|
|
||||||
fn reset(&self);
|
|
||||||
fn get_layer_tiling_or_default(&self, zoom: f64, viewport: graphene::Rect) -> Tiling;
|
|
||||||
/// Return true if the next frame should be shown and removes the outdated
|
|
||||||
/// frame
|
|
||||||
fn frame_timeout(&self, elapsed: Duration) -> bool;
|
|
||||||
fn next_frame(&self);
|
|
||||||
/// Returns the number of currently buffered frames
|
|
||||||
fn n_frames(&self) -> usize;
|
|
||||||
fn set_original_dimensions(&self, size: Coordinates);
|
|
||||||
fn set_original_dimensions_full(
|
|
||||||
&self,
|
|
||||||
size: Coordinates,
|
|
||||||
dimension_details: ImageDimensionDetails,
|
|
||||||
);
|
|
||||||
fn set_update_sender(&self, sender: UpdateSender);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameBufferExt for ArcSwap<FrameBuffer> {
|
impl std::ops::Deref for SharedFrameBuffer {
|
||||||
fn push(&self, tile: Tile) {
|
type Target = ArcSwap<FrameBuffer>;
|
||||||
self.rcu(|tiling_store| {
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SharedFrameBuffer {
|
||||||
|
pub fn push(&self, tile: Tile) {
|
||||||
|
self.buffer.rcu(|tiling_store| {
|
||||||
let mut new_store = (**tiling_store).clone();
|
let mut new_store = (**tiling_store).clone();
|
||||||
new_store.current().push(tile.clone());
|
new_store.current().push(tile.clone());
|
||||||
Arc::new(new_store)
|
Arc::new(new_store)
|
||||||
});
|
});
|
||||||
if let Some(updater) = &self.load().update_sender {
|
if let Some(updater) = &self.buffer.load().update_sender {
|
||||||
updater.send(DecoderUpdate::Redraw);
|
updater.send(DecoderUpdate::Redraw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_tile(&self, tiling: Tiling, position: Coordinates, texture: gdk::Texture) {
|
pub fn push_tile(&self, tiling: Tiling, position: Coordinates, texture: gdk::Texture) {
|
||||||
self.rcu(|tiling_store| {
|
self.buffer.rcu(|tiling_store| {
|
||||||
let mut new_store = (**tiling_store).clone();
|
let mut new_store = (**tiling_store).clone();
|
||||||
new_store
|
new_store
|
||||||
.current()
|
.current()
|
||||||
.push_tile(tiling, position, texture.clone());
|
.push_tile(tiling, position, texture.clone());
|
||||||
Arc::new(new_store)
|
Arc::new(new_store)
|
||||||
});
|
});
|
||||||
if let Some(updater) = &self.load().update_sender {
|
if let Some(updater) = &self.buffer.load().update_sender {
|
||||||
updater.send(DecoderUpdate::Redraw);
|
updater.send(DecoderUpdate::Redraw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_frame(&self, tile: Tile, dimensions: Coordinates, delay: Duration) {
|
pub fn push_frame(&self, tile: Tile, dimensions: Coordinates, delay: Duration) {
|
||||||
let mut store = TiledImage::default();
|
let mut store = TiledImage::default();
|
||||||
store.push(tile);
|
store.push(tile);
|
||||||
store.original_dimensions = Some(dimensions);
|
store.original_dimensions = Some(dimensions);
|
||||||
store.delay = delay;
|
store.delay = delay;
|
||||||
|
|
||||||
self.rcu(|tiling_store| {
|
self.buffer.rcu(|tiling_store| {
|
||||||
let mut new_store = (**tiling_store).clone();
|
let mut new_store = (**tiling_store).clone();
|
||||||
new_store.images.push_back(store.clone());
|
new_store.images.push_back(store.clone());
|
||||||
Arc::new(new_store)
|
Arc::new(new_store)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&self) {
|
pub fn reset(&self) {
|
||||||
self.rcu(|tiling_store| {
|
self.buffer.rcu(|tiling_store| {
|
||||||
let mut new_store = (**tiling_store).clone();
|
let mut new_store = (**tiling_store).clone();
|
||||||
new_store.reset();
|
new_store.reset();
|
||||||
Arc::new(new_store)
|
Arc::new(new_store)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_layer_tiling_or_default(&self, zoom: f64, viewport: graphene::Rect) -> Tiling {
|
pub fn get_layer_tiling_or_default(&self, zoom: f64, viewport: graphene::Rect) -> Tiling {
|
||||||
let mut tiling = None;
|
let mut tiling = None;
|
||||||
self.rcu(|tiling_store| {
|
self.buffer.rcu(|tiling_store| {
|
||||||
let mut new_store = (**tiling_store).clone();
|
let mut new_store = (**tiling_store).clone();
|
||||||
tiling = Some(
|
tiling = Some(
|
||||||
new_store
|
new_store
|
||||||
|
|
@ -655,8 +645,11 @@ impl FrameBufferExt for ArcSwap<FrameBuffer> {
|
||||||
tiling.unwrap()
|
tiling.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_timeout(&self, elapsed: Duration) -> bool {
|
/// Return true if the next frame should be shown and removes the outdated
|
||||||
|
/// frame
|
||||||
|
pub fn frame_timeout(&self, elapsed: Duration) -> bool {
|
||||||
if self
|
if self
|
||||||
|
.buffer
|
||||||
.load()
|
.load()
|
||||||
.images
|
.images
|
||||||
.front()
|
.front()
|
||||||
|
|
@ -669,40 +662,41 @@ impl FrameBufferExt for ArcSwap<FrameBuffer> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_frame(&self) {
|
pub fn next_frame(&self) {
|
||||||
self.rcu(|tiling_store| {
|
self.buffer.rcu(|tiling_store| {
|
||||||
let mut new_store = (**tiling_store).clone();
|
let mut new_store = (**tiling_store).clone();
|
||||||
new_store.images.pop_front();
|
new_store.images.pop_front();
|
||||||
Arc::new(new_store)
|
Arc::new(new_store)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn n_frames(&self) -> usize {
|
/// Returns the number of currently buffered frames
|
||||||
self.load().images.len()
|
pub fn n_frames(&self) -> usize {
|
||||||
|
self.buffer.load().images.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_original_dimensions(&self, size: Coordinates) {
|
pub fn set_original_dimensions(&self, size: Coordinates) {
|
||||||
self.set_original_dimensions_full(size, Default::default());
|
self.set_original_dimensions_full(size, Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_original_dimensions_full(
|
pub fn set_original_dimensions_full(
|
||||||
&self,
|
&self,
|
||||||
size: Coordinates,
|
size: Coordinates,
|
||||||
dimension_details: ImageDimensionDetails,
|
dimension_details: ImageDimensionDetails,
|
||||||
) {
|
) {
|
||||||
self.rcu(|tiling_store| {
|
self.buffer.rcu(|tiling_store| {
|
||||||
let mut new_store = (**tiling_store).clone();
|
let mut new_store = (**tiling_store).clone();
|
||||||
new_store.current().original_dimensions = Some(size);
|
new_store.current().original_dimensions = Some(size);
|
||||||
Arc::new(new_store)
|
Arc::new(new_store)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(updater) = &self.load().update_sender {
|
if let Some(updater) = &self.buffer.load().update_sender {
|
||||||
updater.send(DecoderUpdate::Dimensions(dimension_details));
|
updater.send(DecoderUpdate::Dimensions(dimension_details));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_update_sender(&self, sender: UpdateSender) {
|
pub fn set_update_sender(&self, sender: UpdateSender) {
|
||||||
self.rcu(|tiling_store| {
|
self.buffer.rcu(|tiling_store| {
|
||||||
let mut new_store = (**tiling_store).clone();
|
let mut new_store = (**tiling_store).clone();
|
||||||
new_store.set_update_sender(sender.clone());
|
new_store.set_update_sender(sender.clone());
|
||||||
Arc::new(new_store)
|
Arc::new(new_store)
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,11 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use arc_swap::ArcSwap;
|
|
||||||
use futures_lite::StreamExt;
|
use futures_lite::StreamExt;
|
||||||
use glib::subclass::Signal;
|
use glib::subclass::Signal;
|
||||||
use glib::{Properties, SignalGroup};
|
use glib::{Properties, SignalGroup};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::decoder::tiling::FrameBufferExt;
|
|
||||||
use crate::decoder::{self, tiling, Decoder, DecoderUpdate};
|
use crate::decoder::{self, tiling, Decoder, DecoderUpdate};
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::metadata::Metadata;
|
use crate::metadata::Metadata;
|
||||||
|
|
@ -126,6 +124,7 @@ pub enum FitMode {
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::decoder::tiling::SharedFrameBuffer;
|
||||||
|
|
||||||
#[derive(Debug, Default, Properties)]
|
#[derive(Debug, Default, Properties)]
|
||||||
#[properties(wrapper_type = super::LpImage)]
|
#[properties(wrapper_type = super::LpImage)]
|
||||||
|
|
@ -148,7 +147,7 @@ mod imp {
|
||||||
|
|
||||||
/// Track changes to this image
|
/// Track changes to this image
|
||||||
pub(super) file_monitor: RefCell<Option<gio::FileMonitor>>,
|
pub(super) file_monitor: RefCell<Option<gio::FileMonitor>>,
|
||||||
pub(super) frame_buffer: Arc<ArcSwap<tiling::FrameBuffer>>,
|
pub(super) frame_buffer: Arc<SharedFrameBuffer>,
|
||||||
pub(super) decoder: RefCell<Option<Arc<Decoder>>>,
|
pub(super) decoder: RefCell<Option<Arc<Decoder>>>,
|
||||||
|
|
||||||
/// Rotation final value (can differ from `rotation` during animation)
|
/// Rotation final value (can differ from `rotation` during animation)
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,10 @@ use adw::subclass::prelude::*;
|
||||||
use glib::Properties;
|
use glib::Properties;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
|
use super::image;
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::widgets::LpPrint;
|
use crate::widgets::LpPrint;
|
||||||
|
|
||||||
use super::image;
|
|
||||||
|
|
||||||
mod imp_page {
|
mod imp_page {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue