Implement pre-caching with lower resolution

This commit is contained in:
Julian Mutter 2023-11-23 12:23:20 +01:00
parent 75e1da0097
commit 1a7f7498cd
3 changed files with 44 additions and 19 deletions

View File

@ -6,12 +6,12 @@ use log::{debug, error};
use poppler::Document; use poppler::Document;
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::BTreeMap, collections::{BTreeMap, VecDeque},
rc::Rc, rc::Rc,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
type PageNumber = usize; pub type PageNumber = usize;
pub type MyPageType = Texture; pub type MyPageType = Texture;
pub struct PageCache { pub struct PageCache {
@ -49,22 +49,29 @@ impl PageCache {
} }
} }
pub fn cache_page(&mut self, page_number: PageNumber, height: i32) -> bool { pub fn cache_page(&mut self, page_number: PageNumber, height: i32) -> Option<CacheResponse> {
debug!("Caching page {}", page_number); debug!("Caching page {}", page_number);
let begin_of_cashing = Instant::now(); let begin_of_cashing = Instant::now();
if let Some(page) = self.pages.get(&page_number) { if let Some(page) = self.pages.get(&page_number) {
if page.height() >= height { if page.height() >= height {
debug!("Page already in cache"); debug!("Page already in cache");
return false; return None;
} }
} }
let mut response = None;
if let Some(page) = self.document.page(page_number as i32) { if let Some(page) = self.document.page(page_number as i32) {
let pages = vec![Rc::new(page)]; let pages = vec![Rc::new(page)];
let texture = draw::draw_pages_to_texture(&pages, height); let texture = draw::draw_pages_to_texture(&pages, height);
let page = Rc::new(texture);
// Overwrite page with lower resolution if exists // Overwrite page with lower resolution if exists
self.pages.insert(page_number, Rc::new(texture)); let previous_page = self.pages.insert(page_number, Rc::clone(&page));
let page_resolution_upgraded = previous_page.is_some();
if page_resolution_upgraded {
response = Some(CacheResponse::PageResolutionUpgraded { page_number, page });
}
if self.pages.len() > self.max_num_stored_pages && self.pages.len() > 2 { if self.pages.len() > self.max_num_stored_pages && self.pages.len() > 2 {
let _result = self.remove_most_distant_page(); let _result = self.remove_most_distant_page();
@ -75,7 +82,7 @@ impl PageCache {
page_number, page_number,
begin_of_cashing.elapsed().as_millis() begin_of_cashing.elapsed().as_millis()
); );
true response
} }
fn remove_most_distant_page(&mut self) -> anyhow::Result<()> { fn remove_most_distant_page(&mut self) -> anyhow::Result<()> {
@ -114,10 +121,7 @@ impl PageCache {
fn process_command(&mut self, command: CacheCommand) -> Result<Option<CacheResponse>> { fn process_command(&mut self, command: CacheCommand) -> Result<Option<CacheResponse>> {
debug!("Processing command: {:?}...", command); debug!("Processing command: {:?}...", command);
match command { match command {
CacheCommand::Cache(command) => { CacheCommand::Cache(command) => Ok(self.cache_page(command.page, command.height)),
self.cache_page(command.page, command.height);
Ok(None)
}
CacheCommand::Retrieve(command) => match command { CacheCommand::Retrieve(command) => match command {
RetrievePagesCommand::GetCurrentTwoPages { page_left_number } => { RetrievePagesCommand::GetCurrentTwoPages { page_left_number } => {
let page_left = self.get_page_or_cache(page_left_number)?; let page_left = self.get_page_or_cache(page_left_number)?;
@ -162,11 +166,15 @@ pub enum CacheResponse {
page_left: Rc<MyPageType>, page_left: Rc<MyPageType>,
page_right: Rc<MyPageType>, page_right: Rc<MyPageType>,
}, },
PageResolutionUpgraded {
page_number: PageNumber,
page: Rc<MyPageType>,
},
} }
pub struct SyncCacheCommandChannel { pub struct SyncCacheCommandChannel {
retrieve_commands: Vec<RetrievePagesCommand>, retrieve_commands: Vec<RetrievePagesCommand>,
cache_commands: Vec<CachePageCommand>, cache_commands: VecDeque<CachePageCommand>,
} }
pub struct SyncCacheCommandSender { pub struct SyncCacheCommandSender {
@ -181,7 +189,7 @@ impl SyncCacheCommandChannel {
pub fn open() -> (SyncCacheCommandSender, SyncCacheCommandReceiver) { pub fn open() -> (SyncCacheCommandSender, SyncCacheCommandReceiver) {
let channel = SyncCacheCommandChannel { let channel = SyncCacheCommandChannel {
retrieve_commands: Vec::new(), retrieve_commands: Vec::new(),
cache_commands: Vec::new(), cache_commands: VecDeque::new(),
}; };
let channel = Rc::new(RefCell::new(channel)); let channel = Rc::new(RefCell::new(channel));
@ -205,11 +213,15 @@ impl SyncCacheCommandSender {
pub fn send_cache_commands(&self, pages: &[PageNumber], height: i32) { pub fn send_cache_commands(&self, pages: &[PageNumber], height: i32) {
for &page in pages { for &page in pages {
// Make newest message the most important // Make message in front the most important
self.channel self.channel
.borrow_mut() .borrow_mut()
.cache_commands .cache_commands
.push(CachePageCommand { page, height }); .push_front(CachePageCommand { page, height: 10 }); // Cache with lower resolution
self.channel
.borrow_mut()
.cache_commands
.push_back(CachePageCommand { page, height });
} }
} }
} }
@ -223,7 +235,7 @@ impl SyncCacheCommandReceiver {
let mut channel = self.channel.borrow_mut(); let mut channel = self.channel.borrow_mut();
if let Some(command) = channel.retrieve_commands.pop() { if let Some(command) = channel.retrieve_commands.pop() {
return Some(CacheCommand::Retrieve(command)); return Some(CacheCommand::Retrieve(command));
} else if let Some(command) = channel.cache_commands.pop() { } else if let Some(command) = channel.cache_commands.pop_front() {
return Some(CacheCommand::Cache(command)); return Some(CacheCommand::Cache(command));
} }
None None

View File

@ -7,7 +7,7 @@ use log::debug;
use poppler::Page; use poppler::Page;
pub fn draw_pages_to_texture(pages: &[Rc<Page>], area_height: i32) -> Texture { pub fn draw_pages_to_texture(pages: &[Rc<Page>], area_height: i32) -> Texture {
let area_height = i32::max(400, area_height); let area_height = i32::max(10, area_height);
let total_width_normalized: f64 = pages let total_width_normalized: f64 = pages
.iter() .iter()
.map(|page| page.size()) .map(|page| page.size())

View File

@ -10,7 +10,7 @@ use gtk::{
}; };
use log::debug; use log::debug;
use crate::cache::{self, SyncCacheCommandSender}; use crate::cache::{self, PageNumber, SyncCacheCommandSender};
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
@ -27,7 +27,7 @@ pub struct Ui {
} }
pub struct DocumentCanvas { pub struct DocumentCanvas {
current_page_number: usize, pub current_page_number: usize,
pub num_pages: Option<usize>, pub num_pages: Option<usize>,
page_cache_sender: SyncCacheCommandSender, page_cache_sender: SyncCacheCommandSender,
} }
@ -89,6 +89,13 @@ impl DocumentCanvas {
) )
} }
} }
pub fn is_left_page(&self, page_number: PageNumber) -> bool {
page_number == self.current_page_number
}
pub fn is_right_page(&self, page_number: PageNumber) -> bool {
page_number == self.current_page_number + 1
}
} }
pub fn toggle_fullscreen(ui: &Ui) { pub fn toggle_fullscreen(ui: &Ui) {
@ -299,8 +306,14 @@ pub fn load_document(file: impl AsRef<Path>, ui: Rc<RefCell<Ui>>) {
ui.borrow_mut().image_right.set_visible(true); ui.borrow_mut().image_right.set_visible(true);
let area_height = ui.borrow().image_left.height(); let area_height = ui.borrow().image_left.height();
ui.borrow().document_canvas.as_ref().unwrap().cache_surrounding_pages(area_height); ui.borrow().document_canvas.as_ref().unwrap().cache_surrounding_pages(area_height);
debug!("Image size: {}, {}", ui.borrow().image_left.width(), ui.borrow().image_left.height()); },
cache::CacheResponse::PageResolutionUpgraded { page_number, page } => {
if ui.borrow().document_canvas.as_ref().unwrap().is_left_page(page_number){
ui.borrow_mut().image_left.set_paintable(Some(page.as_ref()));
} else if ui.borrow().document_canvas.as_ref().unwrap().is_right_page(page_number){
ui.borrow_mut().image_right.set_paintable(Some(page.as_ref()));
} }
}
}), }),
); );