Skip to content

Commit

Permalink
Merge branch 'main' of github.com:podusowski/walkers into main
Browse files Browse the repository at this point in the history
  • Loading branch information
podusowski committed Jul 5, 2023
2 parents 8d2b666 + 778888c commit c3fa96e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 45 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to this project will be documented in this file.

## Unreleased

* Optimized how GUI and IO thread talk to each other.

## 0.4.0

### Breaking
Expand Down
99 changes: 54 additions & 45 deletions src/tiles.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::sync::Mutex;
use std::collections::hash_map::Entry;
use std::{collections::HashMap, sync::Arc};

use egui::{pos2, Color32, Context, Mesh, Rect, Vec2};
Expand Down Expand Up @@ -41,30 +41,68 @@ impl Tile {

/// Downloads and keeps cache of the tiles. It must persist between frames.
pub struct Tiles {
cache: Arc<Mutex<HashMap<TileId, Tile>>>,
cache: HashMap<TileId, Option<Tile>>,

/// Tiles to be downloaded by the IO thread.
requests: tokio::sync::mpsc::Sender<TileId>,
request_tx: tokio::sync::mpsc::Sender<TileId>,

/// Tiles that got downloaded and should be put in the cache.
tile_rx: tokio::sync::mpsc::Receiver<(TileId, Tile)>,

#[allow(dead_code)] // Significant Drop
tokio_runtime_thread: TokioRuntimeThread,
}

impl Tiles {
pub fn new(egui_ctx: Context) -> Self {
let tokio_runtime_thread = TokioRuntimeThread::new();

// Minimum value which didn't cause any stalls while testing.
let channel_size = 20;

let (request_tx, request_rx) = tokio::sync::mpsc::channel(channel_size);
let (tile_tx, tile_rx) = tokio::sync::mpsc::channel(channel_size);
tokio_runtime_thread
.runtime
.spawn(download(request_rx, tile_tx, egui_ctx));
Self {
cache: Default::default(),
request_tx,
tile_rx,
tokio_runtime_thread,
}
}

pub fn at(&mut self, tile_id: TileId) -> Option<Tile> {
// Just take one at the time.
if let Ok((tile_id, tile)) = self.tile_rx.try_recv() {
self.cache.insert(tile_id, Some(tile));
}

match self.cache.entry(tile_id) {
Entry::Occupied(entry) => entry.get().clone(),
Entry::Vacant(entry) => {
if let Ok(()) = self.request_tx.try_send(tile_id) {
log::debug!("Requested tile: {:?}", tile_id);
entry.insert(None);
} else {
log::debug!("Request queue is full.");
}
None
}
}
}
}

async fn download(
mut requests: tokio::sync::mpsc::Receiver<TileId>,
cache: Arc<Mutex<HashMap<TileId, Tile>>>,
tile_tx: tokio::sync::mpsc::Sender<(TileId, Tile)>,
egui_ctx: Context,
) {
let client = reqwest::Client::new();
loop {
if let Some(requested) = requests.recv().await {
log::debug!("Tile requested: {:?}.", requested);

// Might have been downloaded before this request was received from
// the requests queue.
if cache.lock().unwrap().contains_key(&requested) {
continue;
}
log::debug!("Starting the download of {:?}.", requested);

let url = format!(
"https://tile.openstreetmap.org/{}/{}/{}.png",
Expand All @@ -77,45 +115,16 @@ async fn download(
.await
.unwrap();

log::debug!("Tile downloaded: {:?}.", image.status());
log::debug!("Downloaded {:?}.", image.status());

if image.status().is_success() {
let image = image.bytes().await.unwrap();
cache.lock().unwrap().insert(requested, Tile::new(&image));
if tile_tx.send((requested, Tile::new(&image))).await.is_err() {
// GUI thread died.
break;
}
egui_ctx.request_repaint();
}
}
}
}

impl Tiles {
pub fn new(egui_ctx: Context) -> Self {
let tokio_runtime_thread = TokioRuntimeThread::new();
let (tx, rx) = tokio::sync::mpsc::channel(5);
let cache = Arc::new(Mutex::new(HashMap::<TileId, Tile>::new()));
tokio_runtime_thread
.runtime
.spawn(download(rx, cache.clone(), egui_ctx));
Self {
cache,
requests: tx,
tokio_runtime_thread,
}
}

pub fn at(&self, tile_id: TileId) -> Option<Tile> {
self.cache
.lock()
.unwrap()
.get(&tile_id)
.cloned()
.or_else(|| {
if let Err(error) = self.requests.try_send(tile_id) {
log::debug!("Could not request a tile: {:?}, reason: {}", tile_id, error);
};

// Tile was requested, but we don't have it yet.
None
})
}
}

0 comments on commit c3fa96e

Please sign in to comment.