use crate::wgpu;
use crate::log;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, Mutex, OnceLock};
use crate::layers::bitmap_layer::NumericData;
use crate::zarr::AsyncZarritaStore;
static ZARR_STORES: OnceLock<Mutex<HashMap<String, Arc<AsyncZarritaStore>>>> = OnceLock::new();
#[derive(Clone)]
pub struct CachedInternalTextLayerData {
pub atlas_data: Vec<u8>,
pub all_instance_data: Vec<f32>,
pub atlas_width: usize,
pub atlas_height: usize,
}
thread_local! {
static GPU_CONTEXT: RefCell<Option<(wgpu::Device, wgpu::Queue)>> = const { RefCell::new(None) };
static USE_MEMO_CACHE_VEC_F32: RefCell<Option<HashMap<Vec<String>, Arc<Vec<f32>>>>> = const { RefCell::new(None) };
static USE_MEMO_CACHE_VEC_I32: RefCell<Option<HashMap<Vec<String>, Arc<Vec<i32>>>>> = const { RefCell::new(None) };
static USE_MEMO_CACHE_VEC_STRING: RefCell<Option<HashMap<Vec<String>, Arc<Vec<String>>>>> = const { RefCell::new(None) };
static USE_MEMO_CACHE_INTERNAL_TEXT_LAYER_DATA: RefCell<Option<HashMap<Vec<String>, Arc<CachedInternalTextLayerData>>>> = const { RefCell::new(None) };
static USE_MEMO_CACHE_NUMERIC_DATA: RefCell<Option<HashMap<Vec<String>, Arc<NumericData>>>> = const { RefCell::new(None) };
}
async fn init_gpu_context() -> Option<(wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions::default())
.await
.ok()?;
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor::default())
.await
.ok()?;
Some((device, queue))
}
#[cfg(target_arch = "wasm32")]
pub async fn get_or_init_gpu_context() -> Option<(wgpu::Device, wgpu::Queue)> {
let existing = GPU_CONTEXT.with(|ctx| ctx.borrow().clone());
if let Some(context) = existing {
return Some(context);
}
let (device, queue) = init_gpu_context().await?;
GPU_CONTEXT.with(|ctx| {
*ctx.borrow_mut() = Some((device.clone(), queue.clone()));
});
Some((device, queue))
}
#[cfg(not(target_arch = "wasm32"))]
pub async fn get_or_init_gpu_context() -> Option<(wgpu::Device, wgpu::Queue)> {
init_gpu_context().await
}
pub fn get_or_init_store(name: &str, wait_for_store_gets: bool) -> Arc<AsyncZarritaStore> {
let map_mutex = ZARR_STORES.get_or_init(|| Mutex::new(HashMap::new()));
let map = map_mutex.lock().unwrap();
if let Some(store) = map.get(name) {
store.clone()
} else {
drop(map);
let mut map = map_mutex.lock().unwrap();
map.entry(name.to_string())
.or_insert_with(|| Arc::new(AsyncZarritaStore::new(name.to_string(), wait_for_store_gets)))
.clone()
}
}
pub async fn use_memo_vec_f32<E>(initializer: impl AsyncFnOnce() -> Result<Vec<f32>, E>, keys: &[String], cache_enabled: bool) -> Result<Arc<Vec<f32>>, E> {
if !cache_enabled {
return Ok(Arc::new(initializer().await?));
}
let buffer_exists = USE_MEMO_CACHE_VEC_F32.with(|map| {
map.borrow()
.as_ref()
.and_then(|m| m.get(keys).cloned())
});
if let Some(buffer) = buffer_exists {
return Ok(buffer);
}
let buffer = Arc::new(initializer().await?);
USE_MEMO_CACHE_VEC_F32.with(|map| {
let mut map_ref = map.borrow_mut();
if map_ref.is_none() {
*map_ref = Some(HashMap::new());
}
map_ref.as_mut().unwrap().insert(keys.to_vec(), buffer.clone());
});
Ok(buffer)
}
pub async fn use_memo_vec_i32<E>(initializer: impl AsyncFnOnce() -> Result<Vec<i32>, E>, keys: &[String], cache_enabled: bool) -> Result<Arc<Vec<i32>>, E> {
if !cache_enabled {
return Ok(Arc::new(initializer().await?));
}
let buffer_exists = USE_MEMO_CACHE_VEC_I32.with(|map| {
map.borrow()
.as_ref()
.and_then(|m| m.get(keys).cloned())
});
if let Some(buffer) = buffer_exists {
return Ok(buffer);
}
let buffer = Arc::new(initializer().await?);
USE_MEMO_CACHE_VEC_I32.with(|map| {
let mut map_ref = map.borrow_mut();
if map_ref.is_none() {
*map_ref = Some(HashMap::new());
}
map_ref.as_mut().unwrap().insert(keys.to_vec(), buffer.clone());
});
Ok(buffer)
}
pub async fn use_memo_vec_string<E>(initializer: impl AsyncFnOnce() -> Result<Vec<String>, E>, keys: &[String], cache_enabled: bool) -> Result<Arc<Vec<String>>, E> {
if !cache_enabled {
return Ok(Arc::new(initializer().await?));
}
let buffer_exists = USE_MEMO_CACHE_VEC_STRING.with(|map| {
map.borrow()
.as_ref()
.and_then(|m| m.get(keys).cloned())
});
if let Some(buffer) = buffer_exists {
return Ok(buffer);
}
let buffer = Arc::new(initializer().await?);
USE_MEMO_CACHE_VEC_STRING.with(|map| {
let mut map_ref = map.borrow_mut();
if map_ref.is_none() {
*map_ref = Some(HashMap::new());
}
map_ref.as_mut().unwrap().insert(keys.to_vec(), buffer.clone());
});
Ok(buffer)
}
pub async fn use_memo_internal_text_layer_data(
initializer: impl AsyncFnOnce() -> CachedInternalTextLayerData,
keys: &[String],
cache_enabled: bool
) -> Arc<CachedInternalTextLayerData> {
if !cache_enabled {
return Arc::new(initializer().await);
}
let data_exists = USE_MEMO_CACHE_INTERNAL_TEXT_LAYER_DATA.with(|map| {
map.borrow()
.as_ref()
.and_then(|m| m.get(keys).cloned())
});
if let Some(data) = data_exists {
return data;
}
let data = Arc::new(initializer().await);
USE_MEMO_CACHE_INTERNAL_TEXT_LAYER_DATA.with(|map| {
let mut map_ref = map.borrow_mut();
if map_ref.is_none() {
*map_ref = Some(HashMap::new());
}
map_ref.as_mut().unwrap().insert(keys.to_vec(), data.clone());
});
data
}
pub async fn use_memo_numeric_data<E>(
initializer: impl AsyncFnOnce() -> Result<NumericData, E>,
keys: &[String],
cache_enabled: bool
) -> Result<Arc<NumericData>, E> {
if !cache_enabled {
return Ok(Arc::new(initializer().await?));
}
let data_exists = USE_MEMO_CACHE_NUMERIC_DATA.with(|map| {
map.borrow()
.as_ref()
.and_then(|m| m.get(keys).cloned())
});
if let Some(data) = data_exists {
return Ok(data);
}
let data = Arc::new(initializer().await?);
USE_MEMO_CACHE_NUMERIC_DATA.with(|map| {
let mut map_ref = map.borrow_mut();
if map_ref.is_none() {
*map_ref = Some(HashMap::new());
}
map_ref.as_mut().unwrap().insert(keys.to_vec(), data.clone());
});
Ok(data)
}