mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-01 05:57:09 -06:00
180 lines
5.4 KiB
Rust
180 lines
5.4 KiB
Rust
use super::model::{Loader, default_loader};
|
|
use super::products::{Active, Progress};
|
|
use super::settings::Settings;
|
|
use super::{Arc, Downloads, HashMap, Mutex, PathBuf, PhotoId, Serialize, VecDeque};
|
|
|
|
/// Most photos waiting in the queue.
|
|
pub(super) const MAX_QUEUE: usize = 5000;
|
|
|
|
/// Most selected photos the automatic queue looks at in one pump.
|
|
pub(super) const AUTO_LOOK: usize = 64;
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
// the session's state
|
|
|
|
/// How hard the background work may go (the app picks it from what the user is doing, like the face scan).
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub enum Pace {
|
|
/// Start nothing new.
|
|
Pause,
|
|
/// Two tiles at once.
|
|
Light,
|
|
/// Half the machine.
|
|
Normal,
|
|
/// Most of the machine: the user is watching the progress.
|
|
Full,
|
|
}
|
|
|
|
impl Pace {
|
|
/// `pause`, `light`, `normal` or `full`; anything else is `normal`.
|
|
pub fn parse(name: Option<&str>) -> Pace {
|
|
match name {
|
|
Some("pause") => Pace::Pause,
|
|
Some("light") => Pace::Light,
|
|
Some("full") => Pace::Full,
|
|
_ => Pace::Normal,
|
|
}
|
|
}
|
|
|
|
/// Tiles to run at once on a machine with `cores` threads (`cap`: the user's own limit).
|
|
pub fn parallel(self, cores: usize, cap: Option<u32>) -> usize {
|
|
let n = match self {
|
|
Pace::Pause | Pace::Light => 2,
|
|
Pace::Normal => cores / 2,
|
|
Pace::Full => cores * 4 / 5,
|
|
}
|
|
.clamp(1, 16);
|
|
cap.map_or(n, |c| n.min(c.max(1) as usize))
|
|
}
|
|
}
|
|
|
|
/// How a photo stands, for the interface.
|
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
|
#[serde(tag = "state", rename_all = "camelCase")]
|
|
pub enum PhotoState {
|
|
/// Not a photo denoise applies to (not a raw, offline, a demo).
|
|
NotApplicable,
|
|
/// No model is chosen: nothing can be made.
|
|
NoModel,
|
|
/// Its picture is made: the Amount slider works.
|
|
Ready,
|
|
Queued {
|
|
/// Photos ahead of it (0 = next).
|
|
ahead: usize,
|
|
},
|
|
Running {
|
|
done: usize,
|
|
total: usize,
|
|
},
|
|
/// Making it failed (`why`), or denoise does not apply to this file (`unsupported`).
|
|
Failed {
|
|
why: String,
|
|
unsupported: bool,
|
|
},
|
|
/// Nothing has asked for it yet.
|
|
Idle,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub(super) struct Failure {
|
|
pub(super) key: String,
|
|
pub(super) why: String,
|
|
pub(super) unsupported: bool,
|
|
}
|
|
|
|
pub(super) enum Outcome {
|
|
Done,
|
|
Failed(String, bool),
|
|
Cancelled,
|
|
}
|
|
|
|
pub(super) struct Running {
|
|
pub(super) photo: PhotoId,
|
|
pub(super) key: String,
|
|
pub(super) product: PathBuf,
|
|
pub(super) progress: Arc<Progress>,
|
|
pub(super) outcome: Arc<Mutex<Option<Outcome>>>,
|
|
pub(super) started: web_time::Instant,
|
|
}
|
|
|
|
pub(crate) struct State {
|
|
/// Where the models are kept (`None` where there is no file system).
|
|
pub models_dir: Option<PathBuf>,
|
|
/// Models being downloaded at the user's request.
|
|
pub downloads: Downloads,
|
|
pub(crate) install: Option<crate::cmd::denoise::InstallJob>,
|
|
/// How a model is loaded (tests put another in).
|
|
pub loader: Loader,
|
|
pub(crate) active: Option<Active>,
|
|
pub(super) active_seen: Option<web_time::Instant>,
|
|
/// `settings.json` as last read (with the model choice).
|
|
pub(crate) settings: Settings,
|
|
/// The index must be made again (the library, the model or the cache changed).
|
|
pub(super) dirty: bool,
|
|
/// The catalog revision and time of the last index, to look again when photos changed.
|
|
pub(super) reindexed: Option<(u64, web_time::Instant)>,
|
|
pub(super) queue: VecDeque<PhotoId>,
|
|
pub(super) running: Option<Running>,
|
|
pub(super) failed: HashMap<PhotoId, Failure>,
|
|
/// Counts every change of what is ready, so the interface knows to draw again.
|
|
pub generation: u64,
|
|
/// Photos made since the session started.
|
|
pub(super) made: u64,
|
|
/// AI Denoise's row in the activity stack, while a photo is being made or waits its turn.
|
|
pub(super) task: Option<crate::activity::TaskGuard>,
|
|
}
|
|
|
|
impl Default for State {
|
|
fn default() -> Self {
|
|
State {
|
|
models_dir: None,
|
|
downloads: Downloads::default(),
|
|
install: None,
|
|
loader: default_loader(),
|
|
active: None,
|
|
active_seen: None,
|
|
settings: Settings::default(),
|
|
dirty: true,
|
|
reindexed: None,
|
|
queue: VecDeque::new(),
|
|
running: None,
|
|
failed: HashMap::new(),
|
|
generation: 0,
|
|
made: 0,
|
|
task: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for State {
|
|
/// Quitting stops the job instead of leaving it to finish a photo nobody will see.
|
|
fn drop(&mut self) {
|
|
if let Some(r) = &self.running {
|
|
r.progress.cancel_now();
|
|
}
|
|
}
|
|
}
|
|
|
|
impl State {
|
|
/// The library was replaced: nothing carries over (photo ids are per library).
|
|
pub fn library_changed(&mut self) {
|
|
if let Some(r) = self.running.take() {
|
|
r.progress.cancel_now();
|
|
}
|
|
self.queue.clear();
|
|
self.failed.clear();
|
|
self.dirty = true;
|
|
self.generation += 1;
|
|
}
|
|
|
|
/// The model choice or the cache changed on disk: look again at the next pump.
|
|
pub fn touch(&mut self) {
|
|
self.active_seen = None;
|
|
self.dirty = true;
|
|
}
|
|
|
|
pub fn queued(&self) -> usize {
|
|
self.queue.len()
|
|
}
|
|
}
|