mirror of
https://github.com/itsjunetime/tdf.git
synced 2026-06-02 08:01:47 -04:00
- Add profiling with --profile-time
- Update ratatui_image to get improvements from parallelization and removing unnecessary hashing - Add benchmarks for only converting pages (not rendering) - Add option to define number of pages to prerender on converter
This commit is contained in:
Generated
+24
-1
@@ -378,6 +378,17 @@ dependencies = [
|
|||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpuprofiler"
|
||||||
|
version = "0.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43f8479dbcfd2bbaa0c0c26779b913052b375981cdf533091f2127ea3d42e52b"
|
||||||
|
dependencies = [
|
||||||
|
"error-chain",
|
||||||
|
"lazy_static",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
@@ -519,6 +530,16 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "error-chain"
|
||||||
|
version = "0.12.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
@@ -1470,7 +1491,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "ratatui-image"
|
name = "ratatui-image"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "git+https://github.com/itsjunetime/ratatui-image.git?branch=vb64_on_personal#88876c749898cce7801379345eb4e0bc69111b8a"
|
source = "git+https://github.com/itsjunetime/ratatui-image.git?branch=vb64_on_personal#8d368ca87c9b817811ba47d04d188a334e5da5a6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
@@ -1478,6 +1499,7 @@ dependencies = [
|
|||||||
"image",
|
"image",
|
||||||
"rand",
|
"rand",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
|
"rayon",
|
||||||
"rustix",
|
"rustix",
|
||||||
"vb64",
|
"vb64",
|
||||||
]
|
]
|
||||||
@@ -1809,6 +1831,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cairo-rs",
|
"cairo-rs",
|
||||||
"console-subscriber",
|
"console-subscriber",
|
||||||
|
"cpuprofiler",
|
||||||
"criterion",
|
"criterion",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"flume",
|
"flume",
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ tracing = ["tokio/tracing", "dep:console-subscriber"]
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = { version = "0.5.1", features = ["async_tokio"] }
|
criterion = { version = "0.5.1", features = ["async_tokio"] }
|
||||||
|
cpuprofiler = "0.0.4"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "rendering"
|
name = "rendering"
|
||||||
|
|||||||
+145
-5
@@ -1,7 +1,21 @@
|
|||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
use std::{
|
||||||
use utils::{render_doc, render_first_page};
|
hint::black_box,
|
||||||
|
path::Path,
|
||||||
|
time::{SystemTime, UNIX_EPOCH}
|
||||||
|
};
|
||||||
|
|
||||||
|
use criterion::{criterion_group, criterion_main, profiler::Profiler, BenchmarkId, Criterion};
|
||||||
|
use futures_util::StreamExt;
|
||||||
|
use tdf::{
|
||||||
|
converter::{ConvertedPage, ConverterMsg},
|
||||||
|
renderer::{fill_default, PageInfo, RenderInfo}
|
||||||
|
};
|
||||||
|
use utils::{
|
||||||
|
handle_converter_msg, handle_renderer_msg, render_doc, start_all_rendering,
|
||||||
|
start_converting_loop, start_rendering_loop, RenderState
|
||||||
|
};
|
||||||
|
|
||||||
const FILES: [&str; 2] = [
|
const FILES: [&str; 2] = [
|
||||||
"benches/example_dictionary.pdf",
|
"benches/example_dictionary.pdf",
|
||||||
@@ -18,7 +32,7 @@ fn render_full(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_to_first_page(c: &mut Criterion) {
|
fn render_to_first_page(c: &mut Criterion) {
|
||||||
for file in FILES {
|
for file in &FILES[..1] {
|
||||||
c.bench_with_input(
|
c.bench_with_input(
|
||||||
BenchmarkId::new("render_first_page", file),
|
BenchmarkId::new("render_first_page", file),
|
||||||
&file,
|
&file,
|
||||||
@@ -30,9 +44,135 @@ fn render_to_first_page(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn only_converting(c: &mut Criterion) {
|
||||||
|
for file in FILES {
|
||||||
|
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
let all_rendered = runtime.block_on(render_all_files(file));
|
||||||
|
|
||||||
|
c.bench_with_input(
|
||||||
|
BenchmarkId::new("only_converting", file),
|
||||||
|
&(all_rendered, file),
|
||||||
|
|b, (rendered, _)| {
|
||||||
|
b.to_async(tokio::runtime::Runtime::new().unwrap())
|
||||||
|
.iter(|| convert_all_files(rendered.clone()))
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn render_first_page(path: impl AsRef<Path>) {
|
||||||
|
let RenderState {
|
||||||
|
mut from_render_rx,
|
||||||
|
mut from_converter_rx,
|
||||||
|
mut pages,
|
||||||
|
mut to_converter_tx,
|
||||||
|
to_render_tx
|
||||||
|
} = start_all_rendering(path);
|
||||||
|
|
||||||
|
// we only want to render until the first page is ready to be printed
|
||||||
|
while pages.is_empty() {
|
||||||
|
tokio::select! {
|
||||||
|
Some(renderer_msg) = from_render_rx.next() => {
|
||||||
|
handle_renderer_msg(renderer_msg, &mut pages, &mut to_converter_tx);
|
||||||
|
},
|
||||||
|
Some(converter_msg) = from_converter_rx.next() => {
|
||||||
|
handle_converter_msg(converter_msg, &mut pages, &mut to_converter_tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
black_box(pages);
|
||||||
|
// we want to make sure this is kept around until the end of this function, or else the other
|
||||||
|
// thread will see that this is disconnected and think that we're done communicating with them
|
||||||
|
drop(to_render_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn render_all_files(path: &'static str) -> Vec<PageInfo> {
|
||||||
|
let (mut from_render_rx, to_render_tx) = start_rendering_loop(path);
|
||||||
|
let mut pages = Vec::<Option<PageInfo>>::new();
|
||||||
|
|
||||||
|
while let Some(info) = from_render_rx.next().await {
|
||||||
|
match info.expect("Renderer ran into an error while rendering") {
|
||||||
|
RenderInfo::NumPages(num) => fill_default(&mut pages, num),
|
||||||
|
RenderInfo::Page(page) => {
|
||||||
|
let num = page.page;
|
||||||
|
pages[num] = Some(page);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if pages.iter().all(|p| p.is_some()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(to_render_tx);
|
||||||
|
pages.into_iter().flatten().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn convert_all_files(files: Vec<PageInfo>) {
|
||||||
|
let num_files = files.len();
|
||||||
|
let (mut from_converter_rx, to_converter_tx) = start_converting_loop(num_files);
|
||||||
|
|
||||||
|
to_converter_tx
|
||||||
|
.send(ConverterMsg::NumPages(num_files))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut converted = Vec::<Option<ConvertedPage>>::new();
|
||||||
|
fill_default(&mut converted, num_files);
|
||||||
|
|
||||||
|
for page in files {
|
||||||
|
to_converter_tx.send(ConverterMsg::AddImg(page)).unwrap();
|
||||||
|
|
||||||
|
if !from_converter_rx.is_empty() {
|
||||||
|
let page = from_converter_rx
|
||||||
|
.next()
|
||||||
|
.await
|
||||||
|
.expect("Converter ended stream before expected")
|
||||||
|
.expect("Converter ran into an error while converting page");
|
||||||
|
|
||||||
|
let num = page.num;
|
||||||
|
converted[num] = Some(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while converted.iter().any(|p| p.is_none()) {
|
||||||
|
let page = from_converter_rx
|
||||||
|
.next()
|
||||||
|
.await
|
||||||
|
.expect("Converted ended stream before expected")
|
||||||
|
.expect("Converted ran into an error while converting page");
|
||||||
|
|
||||||
|
let num = page.num;
|
||||||
|
converted[num] = Some(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(to_converter_tx);
|
||||||
|
black_box(converted);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CpuProfiler;
|
||||||
|
|
||||||
|
impl Profiler for CpuProfiler {
|
||||||
|
fn start_profiling(&mut self, benchmark_id: &str, _: &std::path::Path) {
|
||||||
|
let file = format!(
|
||||||
|
"./{}-{}.profile",
|
||||||
|
benchmark_id.replace("/", "-"),
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis()
|
||||||
|
);
|
||||||
|
|
||||||
|
cpuprofiler::PROFILER.lock().unwrap().start(file).unwrap()
|
||||||
|
}
|
||||||
|
fn stop_profiling(&mut self, _: &str, _: &std::path::Path) {
|
||||||
|
cpuprofiler::PROFILER.lock().unwrap().stop().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
criterion_group!(
|
criterion_group!(
|
||||||
name = benches;
|
name = benches;
|
||||||
config = Criterion::default().sample_size(40);
|
config = Criterion::default().sample_size(40).with_profiler(CpuProfiler);
|
||||||
targets = render_full, render_to_first_page
|
targets = render_full, render_to_first_page, only_converting
|
||||||
);
|
);
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|||||||
+48
-50
@@ -10,7 +10,7 @@ use tdf::{
|
|||||||
renderer::{fill_default, start_rendering, RenderError, RenderInfo, RenderNotif}
|
renderer::{fill_default, start_rendering, RenderError, RenderInfo, RenderNotif}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn handle_renderer_msg(
|
pub fn handle_renderer_msg(
|
||||||
msg: Result<RenderInfo, RenderError>,
|
msg: Result<RenderInfo, RenderError>,
|
||||||
pages: &mut Vec<Option<ConvertedPage>>,
|
pages: &mut Vec<Option<ConvertedPage>>,
|
||||||
to_converter_tx: &mut Sender<tdf::converter::ConverterMsg>
|
to_converter_tx: &mut Sender<tdf::converter::ConverterMsg>
|
||||||
@@ -25,7 +25,7 @@ fn handle_renderer_msg(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_converter_msg(
|
pub fn handle_converter_msg(
|
||||||
msg: Result<ConvertedPage, RenderError>,
|
msg: Result<ConvertedPage, RenderError>,
|
||||||
pages: &mut [Option<ConvertedPage>],
|
pages: &mut [Option<ConvertedPage>],
|
||||||
to_converter_tx: &mut Sender<ConverterMsg>
|
to_converter_tx: &mut Sender<ConverterMsg>
|
||||||
@@ -44,43 +44,39 @@ fn handle_converter_msg(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RenderState {
|
pub struct RenderState {
|
||||||
from_render_rx: RecvStream<'static, Result<RenderInfo, RenderError>>,
|
pub from_render_rx: RecvStream<'static, Result<RenderInfo, RenderError>>,
|
||||||
from_converter_rx: RecvStream<'static, Result<ConvertedPage, RenderError>>,
|
pub from_converter_rx: RecvStream<'static, Result<ConvertedPage, RenderError>>,
|
||||||
pages: Vec<Option<ConvertedPage>>,
|
pub pages: Vec<Option<ConvertedPage>>,
|
||||||
to_converter_tx: Sender<ConverterMsg>,
|
pub to_converter_tx: Sender<ConverterMsg>,
|
||||||
to_render_tx: Sender<RenderNotif>
|
pub to_render_tx: Sender<RenderNotif>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_all_rendering(path: impl AsRef<Path>) -> RenderState {
|
const FONT_SIZE: (u16, u16) = (8, 14);
|
||||||
|
|
||||||
|
pub fn start_rendering_loop(
|
||||||
|
path: impl AsRef<Path>
|
||||||
|
) -> (
|
||||||
|
RecvStream<'static, Result<RenderInfo, RenderError>>,
|
||||||
|
Sender<RenderNotif>
|
||||||
|
) {
|
||||||
let pathbuf = path.as_ref().canonicalize().unwrap();
|
let pathbuf = path.as_ref().canonicalize().unwrap();
|
||||||
let str_path = format!("file://{}", pathbuf.into_os_string().to_string_lossy());
|
let str_path = format!("file://{}", pathbuf.into_os_string().to_string_lossy());
|
||||||
|
|
||||||
let (to_render_tx, from_main_rx) = unbounded();
|
let (to_render_tx, from_main_rx) = unbounded();
|
||||||
let (to_main_tx, from_render_rx) = unbounded();
|
let (to_main_tx, from_render_rx) = unbounded();
|
||||||
|
|
||||||
let font_size = (8, 14);
|
|
||||||
let (columns, rows) = (60, 180);
|
let (columns, rows) = (60, 180);
|
||||||
|
|
||||||
let size = WindowSize {
|
let size = WindowSize {
|
||||||
columns,
|
columns,
|
||||||
rows,
|
rows,
|
||||||
height: rows * font_size.1,
|
height: rows * FONT_SIZE.1,
|
||||||
width: columns * font_size.0
|
width: columns * FONT_SIZE.0
|
||||||
};
|
};
|
||||||
|
|
||||||
std::thread::spawn(move || start_rendering(str_path, to_main_tx, from_main_rx, size));
|
std::thread::spawn(move || start_rendering(str_path, to_main_tx, from_main_rx, size));
|
||||||
|
|
||||||
let (to_converter_tx, from_main_rx) = unbounded();
|
|
||||||
let (to_main_tx, from_converter_rx) = unbounded();
|
|
||||||
|
|
||||||
let mut picker = Picker::new(font_size);
|
|
||||||
picker.protocol_type = ProtocolType::Kitty;
|
|
||||||
|
|
||||||
tokio::spawn(run_conversion_loop(to_main_tx, from_main_rx, picker));
|
|
||||||
|
|
||||||
let pages: Vec<Option<ConvertedPage>> = Vec::new();
|
|
||||||
|
|
||||||
let main_area = Rect {
|
let main_area = Rect {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
@@ -90,7 +86,37 @@ fn start_all_rendering(path: impl AsRef<Path>) -> RenderState {
|
|||||||
to_render_tx.send(RenderNotif::Area(main_area)).unwrap();
|
to_render_tx.send(RenderNotif::Area(main_area)).unwrap();
|
||||||
|
|
||||||
let from_render_rx = from_render_rx.into_stream();
|
let from_render_rx = from_render_rx.into_stream();
|
||||||
|
(from_render_rx, to_render_tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_converting_loop(
|
||||||
|
prerender: usize
|
||||||
|
) -> (
|
||||||
|
RecvStream<'static, Result<ConvertedPage, RenderError>>,
|
||||||
|
Sender<ConverterMsg>
|
||||||
|
) {
|
||||||
|
let (to_converter_tx, from_main_rx) = unbounded();
|
||||||
|
let (to_main_tx, from_converter_rx) = unbounded();
|
||||||
|
|
||||||
|
let mut picker = Picker::new(FONT_SIZE);
|
||||||
|
picker.protocol_type = ProtocolType::Kitty;
|
||||||
|
|
||||||
|
tokio::spawn(run_conversion_loop(
|
||||||
|
to_main_tx,
|
||||||
|
from_main_rx,
|
||||||
|
picker,
|
||||||
|
prerender
|
||||||
|
));
|
||||||
|
|
||||||
let from_converter_rx = from_converter_rx.into_stream();
|
let from_converter_rx = from_converter_rx.into_stream();
|
||||||
|
(from_converter_rx, to_converter_tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_all_rendering(path: impl AsRef<Path>) -> RenderState {
|
||||||
|
let (from_render_rx, to_render_tx) = start_rendering_loop(path);
|
||||||
|
let (from_converter_rx, to_converter_tx) = start_converting_loop(20);
|
||||||
|
|
||||||
|
let pages: Vec<Option<ConvertedPage>> = Vec::new();
|
||||||
|
|
||||||
RenderState {
|
RenderState {
|
||||||
from_render_rx,
|
from_render_rx,
|
||||||
@@ -126,31 +152,3 @@ pub async fn render_doc(path: impl AsRef<Path>) {
|
|||||||
// thread will see that this is disconnected and think that we're done communicating with them
|
// thread will see that this is disconnected and think that we're done communicating with them
|
||||||
drop(to_render_tx);
|
drop(to_render_tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub async fn render_first_page(path: impl AsRef<Path>) {
|
|
||||||
let RenderState {
|
|
||||||
mut from_render_rx,
|
|
||||||
mut from_converter_rx,
|
|
||||||
mut pages,
|
|
||||||
mut to_converter_tx,
|
|
||||||
to_render_tx
|
|
||||||
} = start_all_rendering(path);
|
|
||||||
|
|
||||||
// we only want to render until the first page is ready to be printed
|
|
||||||
while pages.is_empty() {
|
|
||||||
tokio::select! {
|
|
||||||
Some(renderer_msg) = from_render_rx.next() => {
|
|
||||||
handle_renderer_msg(renderer_msg, &mut pages, &mut to_converter_tx);
|
|
||||||
},
|
|
||||||
Some(converter_msg) = from_converter_rx.next() => {
|
|
||||||
handle_converter_msg(converter_msg, &mut pages, &mut to_converter_tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
black_box(pages);
|
|
||||||
// we want to make sure this is kept around until the end of this function, or else the other
|
|
||||||
// thread will see that this is disconnected and think that we're done communicating with them
|
|
||||||
drop(to_render_tx);
|
|
||||||
}
|
|
||||||
|
|||||||
+1
-1
Submodule ratatui-image updated: 88876c7498...8d368ca87c
+8
-8
@@ -6,8 +6,6 @@ use ratatui_image::{picker::Picker, protocol::Protocol, Resize};
|
|||||||
|
|
||||||
use crate::renderer::{fill_default, PageInfo, RenderError};
|
use crate::renderer::{fill_default, PageInfo, RenderError};
|
||||||
|
|
||||||
const MAX_ITER: usize = 20;
|
|
||||||
|
|
||||||
pub struct ConvertedPage {
|
pub struct ConvertedPage {
|
||||||
pub page: Box<dyn Protocol>,
|
pub page: Box<dyn Protocol>,
|
||||||
pub num: usize,
|
pub num: usize,
|
||||||
@@ -23,7 +21,8 @@ pub enum ConverterMsg {
|
|||||||
pub async fn run_conversion_loop(
|
pub async fn run_conversion_loop(
|
||||||
sender: Sender<Result<ConvertedPage, RenderError>>,
|
sender: Sender<Result<ConvertedPage, RenderError>>,
|
||||||
receiver: Receiver<ConverterMsg>,
|
receiver: Receiver<ConverterMsg>,
|
||||||
mut picker: Picker
|
mut picker: Picker,
|
||||||
|
prerender: usize
|
||||||
) -> Result<(), SendError<Result<ConvertedPage, RenderError>>> {
|
) -> Result<(), SendError<Result<ConvertedPage, RenderError>>> {
|
||||||
let mut images = vec![];
|
let mut images = vec![];
|
||||||
let mut page: usize = 0;
|
let mut page: usize = 0;
|
||||||
@@ -32,16 +31,17 @@ pub async fn run_conversion_loop(
|
|||||||
images: &mut [Option<PageInfo>],
|
images: &mut [Option<PageInfo>],
|
||||||
picker: &mut Picker,
|
picker: &mut Picker,
|
||||||
page: usize,
|
page: usize,
|
||||||
iteration: &mut usize
|
iteration: &mut usize,
|
||||||
|
prerender: usize
|
||||||
) -> Result<Option<ConvertedPage>, RenderError> {
|
) -> Result<Option<ConvertedPage>, RenderError> {
|
||||||
if images.is_empty() || *iteration >= MAX_ITER {
|
if images.is_empty() || *iteration >= prerender {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This kinda mimics the way the renderer alternates between going above and below the
|
// This kinda mimics the way the renderer alternates between going above and below the
|
||||||
// current page (within the bounds of how many pages there are) until we've done 20
|
// current page (within the bounds of how many pages there are) until we've done 20
|
||||||
let idx_start = page.saturating_sub(MAX_ITER / 2);
|
let idx_start = page.saturating_sub(prerender / 2);
|
||||||
let idx_end = idx_start.saturating_add(MAX_ITER).min(images.len());
|
let idx_end = idx_start.saturating_add(prerender).min(images.len());
|
||||||
|
|
||||||
// then we go through all the indices available to us and find the first one that has an
|
// then we go through all the indices available to us and find the first one that has an
|
||||||
// image available to steal
|
// image available to steal
|
||||||
@@ -111,7 +111,7 @@ pub async fn run_conversion_loop(
|
|||||||
Err(TryRecvError::Disconnected) => return Ok(())
|
Err(TryRecvError::Disconnected) => return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
match next_page(&mut images, &mut picker, page, &mut iteration) {
|
match next_page(&mut images, &mut picker, page, &mut iteration, prerender) {
|
||||||
Ok(None) => break,
|
Ok(None) => break,
|
||||||
Ok(Some(img)) => sender.send(Ok(img))?,
|
Ok(Some(img)) => sender.send(Ok(img))?,
|
||||||
Err(e) => sender.send(Err(e))?
|
Err(e) => sender.send(Err(e))?
|
||||||
|
|||||||
+1
-1
@@ -141,7 +141,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let (to_converter, from_main) = flume::unbounded();
|
let (to_converter, from_main) = flume::unbounded();
|
||||||
let (to_main, from_converter) = flume::unbounded();
|
let (to_main, from_converter) = flume::unbounded();
|
||||||
|
|
||||||
tokio::spawn(run_conversion_loop(to_main, from_main, picker));
|
tokio::spawn(run_conversion_loop(to_main, from_main, picker, 20));
|
||||||
|
|
||||||
let file_name = path
|
let file_name = path
|
||||||
.file_name()
|
.file_name()
|
||||||
|
|||||||
@@ -27,12 +27,14 @@ pub enum RenderInfo {
|
|||||||
Page(PageInfo)
|
Page(PageInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct PageInfo {
|
pub struct PageInfo {
|
||||||
pub img_data: ImageData,
|
pub img_data: ImageData,
|
||||||
pub page: usize,
|
pub page: usize,
|
||||||
pub search_results: usize
|
pub search_results: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ImageData {
|
pub struct ImageData {
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
pub area: Rect
|
pub area: Rect
|
||||||
|
|||||||
Reference in New Issue
Block a user