mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2026-04-28 11:53:18 -07:00
wip: optimisation retrieving tiles from blob + imagebitmap when supported by the browser
This commit is contained in:
committed by
Matthieu Baumann
parent
c6c17f0ba2
commit
a91b2154a1
@@ -1,3 +1,4 @@
|
||||
use crate::browser_support::BrowserFeaturesSupport;
|
||||
use crate::downloader::request::moc::MOCRequest;
|
||||
use crate::math::angle::ToAngle;
|
||||
use crate::math::spectra::Freq;
|
||||
@@ -6,6 +7,7 @@ use crate::renderable::image::Image;
|
||||
use crate::renderable::ImageLayer;
|
||||
use crate::tile_fetcher::HiPSLocalFiles;
|
||||
use crate::Abort;
|
||||
use al_core::image::bitmap::Bitmap;
|
||||
use crate::{
|
||||
camera::CameraViewPort,
|
||||
downloader::Downloader,
|
||||
@@ -108,6 +110,8 @@ pub struct App {
|
||||
//img_send: async_channel::Sender<ImageLayer>,
|
||||
img_recv: async_channel::Receiver<ImageLayer>,
|
||||
ack_img_send: async_channel::Sender<ImageParams>,
|
||||
|
||||
browser_features_support: BrowserFeaturesSupport,
|
||||
//ack_img_recv: async_channel::Receiver<ImageParams>,
|
||||
// callbacks
|
||||
//callback_position_changed: js_sys::Function,
|
||||
@@ -204,6 +208,8 @@ impl App {
|
||||
let dragging = false;
|
||||
let time_mouse_high_vel = Time::now();
|
||||
|
||||
let browser_features_support = BrowserFeaturesSupport::new();
|
||||
|
||||
Ok(App {
|
||||
gl,
|
||||
//ui,
|
||||
@@ -255,6 +261,8 @@ impl App {
|
||||
//img_send,
|
||||
img_recv,
|
||||
ack_img_send,
|
||||
|
||||
browser_features_support
|
||||
//ack_img_recv,
|
||||
})
|
||||
}
|
||||
@@ -278,7 +286,7 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
hips.look_for_new_tiles(&mut self.tile_fetcher, &self.camera);
|
||||
hips.look_for_new_tiles(&mut self.tile_fetcher, &self.camera, &self.browser_features_support);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -575,12 +583,12 @@ impl App {
|
||||
|
||||
match rsc {
|
||||
RequestType::Tile(tile) => {
|
||||
if self.camera.has_moved() {
|
||||
/*if self.camera.has_moved() {
|
||||
self.downloader
|
||||
.borrow_mut()
|
||||
.delay(RequestType::Tile(tile));
|
||||
continue;
|
||||
}
|
||||
}*/
|
||||
|
||||
if let Some(hips) = self.layers.get_mut_hips_from_cdid(&tile.hips_cdid) {
|
||||
let cfg = hips.get_config();
|
||||
@@ -742,6 +750,77 @@ impl App {
|
||||
tile.request.time_request,
|
||||
)?;
|
||||
}
|
||||
ImageType::ImageRgba8u {
|
||||
image: Bitmap { image, .. },
|
||||
}
|
||||
| ImageType::ImageRgb8u {
|
||||
image: Bitmap { image, .. },
|
||||
} => {
|
||||
let document = web_sys::window()
|
||||
.unwrap_abort()
|
||||
.document()
|
||||
.unwrap_abort();
|
||||
let canvas = document
|
||||
.create_element("canvas")?
|
||||
.dyn_into::<web_sys::HtmlCanvasElement>()?;
|
||||
canvas.set_width(image.width());
|
||||
canvas.set_height(image.height());
|
||||
let context = canvas
|
||||
.get_context("2d")?
|
||||
.unwrap_abort()
|
||||
.dyn_into::<web_sys::CanvasRenderingContext2d>()?;
|
||||
// Get the data once for all for the whole image
|
||||
// This takes time so better do it once and not repeatly
|
||||
context.draw_image_with_image_bitmap(image, 0.0, 0.0)?;
|
||||
|
||||
// Cut the png in several tile images. See page 3 of
|
||||
// https://aladin.cds.unistra.fr/java/DocTechHiPS3D.pdf
|
||||
let tile_depth = *tile_depth;
|
||||
let num_cols =
|
||||
(tile_depth as f32).sqrt().floor() as u32;
|
||||
let num_rows = ((tile_depth as f32)
|
||||
/ (num_cols as f32))
|
||||
.ceil()
|
||||
as u32;
|
||||
|
||||
debug_assert_eq!(num_rows * num_cols, tile_depth);
|
||||
|
||||
let tile_size = *tile_size;
|
||||
|
||||
let bytes = context
|
||||
.get_image_data(0_f64, 0_f64, (num_cols * tile_size) as f64, (num_rows * tile_size) as f64)?
|
||||
.data().0;
|
||||
|
||||
let mut decoded_bytes = vec![0_u8;
|
||||
(tile_size * tile_size * tile_depth)
|
||||
as usize
|
||||
];
|
||||
|
||||
let mut k = 0;
|
||||
for y in 0..num_rows {
|
||||
let sy = y * tile_size;
|
||||
|
||||
for x in 0..num_cols {
|
||||
let sx = x * tile_size;
|
||||
|
||||
for i in sy..(sy + tile_size) {
|
||||
for j in sx..(sx + tile_size) {
|
||||
let id_byte = (j + i * num_cols * tile_size) * 4;
|
||||
|
||||
decoded_bytes[k] = bytes[id_byte as usize];
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hips.push_tile_from_jpeg(
|
||||
cell,
|
||||
decoded_bytes.into_boxed_slice(),
|
||||
(tile_size, tile_size, tile_depth),
|
||||
tile.request.time_request,
|
||||
)?;
|
||||
}
|
||||
ImageType::FitsRawBytes { raw_bytes, size } => hips
|
||||
.push_tile_from_fits(
|
||||
cell,
|
||||
@@ -770,7 +849,7 @@ impl App {
|
||||
// The allsky image is missing so we donwload all the tiles contained into
|
||||
// the 0's cell
|
||||
for base_hpx_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||
let query = hips.build_tile_query(base_hpx_cell);
|
||||
let query = query::Tile::new(base_hpx_cell, hips.get_config(), &self.browser_features_support);
|
||||
self.tile_fetcher.append_base_tile(query);
|
||||
}
|
||||
} else {
|
||||
|
||||
19
src/core/src/browser_support.rs
Normal file
19
src/core/src/browser_support.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{window};
|
||||
use js_sys::Reflect;
|
||||
|
||||
pub struct BrowserFeaturesSupport {
|
||||
pub create_image_bitmap: bool,
|
||||
}
|
||||
|
||||
impl BrowserFeaturesSupport {
|
||||
pub fn new() -> Self {
|
||||
let window = window().expect("no global `window` exists");
|
||||
let create_image_bitmap = Reflect::has(&window, &JsValue::from_str("createImageBitmap"))
|
||||
.unwrap_or(false);
|
||||
|
||||
Self {
|
||||
create_image_bitmap
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ pub trait Query: Sized {
|
||||
}
|
||||
pub type QueryId = String;
|
||||
|
||||
use crate::browser_support::BrowserFeaturesSupport;
|
||||
use crate::healpix::cell::HEALPixFreqCell;
|
||||
use al_api::hips::DataproductType;
|
||||
use al_core::image::format::ImageFormatType;
|
||||
@@ -72,6 +73,7 @@ pub struct Tile {
|
||||
pub credentials: RequestCredentials,
|
||||
pub mode: RequestMode,
|
||||
pub id: QueryId,
|
||||
pub create_bitmap_support: bool,
|
||||
}
|
||||
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
@@ -80,7 +82,7 @@ use crate::renderable::CreatorDid;
|
||||
use crate::tile_fetcher::HiPSLocalFiles;
|
||||
use web_sys::{RequestCredentials, RequestMode};
|
||||
impl Tile {
|
||||
pub fn new(cell: &HEALPixCell, cfg: &HiPSConfig) -> Self {
|
||||
pub fn new(cell: &HEALPixCell, cfg: &HiPSConfig, browser_support: &BrowserFeaturesSupport) -> Self {
|
||||
let hips_cdid = cfg.get_creator_did();
|
||||
let hips_url = cfg.get_root_url();
|
||||
let format = cfg.get_format();
|
||||
@@ -109,10 +111,11 @@ impl Tile {
|
||||
credentials,
|
||||
mode,
|
||||
id,
|
||||
create_bitmap_support: browser_support.create_image_bitmap,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_channel(cell: &HEALPixCell, channel: u32, cfg: &HiPSConfig) -> Self {
|
||||
pub fn new_with_channel(cell: &HEALPixCell, channel: u32, cfg: &HiPSConfig, browser_support: &BrowserFeaturesSupport) -> Self {
|
||||
let hips_cdid = cfg.get_creator_did();
|
||||
let hips_url = cfg.get_root_url();
|
||||
let format = cfg.get_format();
|
||||
@@ -142,10 +145,11 @@ impl Tile {
|
||||
credentials,
|
||||
mode,
|
||||
id,
|
||||
create_bitmap_support: browser_support.create_image_bitmap,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_cubic(hpx_f_cell: &HEALPixFreqCell, cfg: &HiPSConfig) -> Self {
|
||||
pub fn new_cubic(hpx_f_cell: &HEALPixFreqCell, cfg: &HiPSConfig, browser_support: &BrowserFeaturesSupport) -> Self {
|
||||
let hips_cdid = cfg.get_creator_did();
|
||||
let hips_url = cfg.get_root_url();
|
||||
let format = cfg.get_format();
|
||||
@@ -183,6 +187,7 @@ impl Tile {
|
||||
credentials,
|
||||
mode,
|
||||
id,
|
||||
create_bitmap_support: browser_support.create_image_bitmap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,3 +151,41 @@ async fn query_html_image(
|
||||
|
||||
Ok(image)
|
||||
}
|
||||
|
||||
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::Response;
|
||||
use web_sys::window;
|
||||
use web_sys::RequestInit;
|
||||
use web_sys::RequestMode;
|
||||
async fn query_bitmap_from_blob(
|
||||
url: &str,
|
||||
mode: RequestMode,
|
||||
credentials: RequestCredentials
|
||||
) -> Result<web_sys::ImageBitmap, JsValue> {
|
||||
let window = web_sys::window().unwrap_abort();
|
||||
|
||||
|
||||
let mut opts = RequestInit::new();
|
||||
opts.method("GET");
|
||||
opts.mode(mode);
|
||||
opts.credentials(credentials);
|
||||
|
||||
let request =
|
||||
web_sys::Request::new_with_str_and_init(url, &opts).unwrap_abort();
|
||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
||||
// `resp_value` is a `Response` object.
|
||||
debug_assert!(resp_value.is_instance_of::<Response>());
|
||||
let resp: Response = resp_value.dyn_into()?;
|
||||
|
||||
if resp.ok() {
|
||||
let blob = JsFuture::from(resp.blob()?).await?.dyn_into::<web_sys::Blob>()?;
|
||||
let image_bitmap = JsFuture::from(window.create_image_bitmap_with_blob(&blob)?).await?;
|
||||
|
||||
Ok(image_bitmap.into())
|
||||
} else {
|
||||
Err(JsValue::from_str(
|
||||
"Response status code not between 200-299.",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen::JsValue;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::{RequestInit, Response};
|
||||
use al_core::image::bitmap::Bitmap;
|
||||
use crate::downloader::request::query_bitmap_from_blob;
|
||||
|
||||
impl From<query::Tile> for TileRequest {
|
||||
// Create a tile request associated to a HiPS
|
||||
fn from(query: query::Tile) -> Self {
|
||||
@@ -43,6 +46,7 @@ impl From<query::Tile> for TileRequest {
|
||||
credentials,
|
||||
mode,
|
||||
id,
|
||||
create_bitmap_support,
|
||||
} = query;
|
||||
|
||||
let url_clone = url.clone();
|
||||
@@ -59,26 +63,43 @@ impl From<query::Tile> for TileRequest {
|
||||
} => (tile_size, tile_size, tile_depth),
|
||||
};
|
||||
|
||||
let window = web_sys::window().unwrap_abort();
|
||||
let request = match pixel_format {
|
||||
PixelType::RGB8U => Request::new(async move {
|
||||
// HTMLImageElement
|
||||
let image = query_html_image(&url_clone, credentials).await?;
|
||||
// The image has been resolved
|
||||
Ok(ImageType::HTMLImageRgb8u {
|
||||
image: HTMLImage::<RGB8U>::new(image),
|
||||
})
|
||||
if create_bitmap_support {
|
||||
// optimized download of tile for GPU (using Blob + Bitmap) without creating any DOM structure
|
||||
let image_bitmap = query_bitmap_from_blob(&url_clone, mode, credentials).await?;
|
||||
Ok(ImageType::ImageRgb8u {
|
||||
image: Bitmap::new(image_bitmap),
|
||||
})
|
||||
} else {
|
||||
// HTMLImageElement
|
||||
let image = query_html_image(&url_clone, credentials).await?;
|
||||
// The image has been resolved
|
||||
Ok(ImageType::HTMLImageRgb8u {
|
||||
image: HTMLImage::new(image),
|
||||
})
|
||||
}
|
||||
}),
|
||||
PixelType::RGBA8U => Request::new(async move {
|
||||
// HTMLImageElement
|
||||
let image = query_html_image(&url_clone, credentials).await?;
|
||||
// The image has been resolved
|
||||
Ok(ImageType::HTMLImageRgba8u {
|
||||
image: HTMLImage::<RGBA8U>::new(image),
|
||||
})
|
||||
if create_bitmap_support {
|
||||
// optimized download of tile for GPU (using Blob + Bitmap) without creating any DOM structure
|
||||
let image_bitmap = query_bitmap_from_blob(&url_clone, mode, credentials).await?;
|
||||
Ok(ImageType::ImageRgba8u {
|
||||
image: Bitmap::new(image_bitmap),
|
||||
})
|
||||
} else {
|
||||
// HTMLImageElement
|
||||
let image = query_html_image(&url_clone, credentials).await?;
|
||||
// The image has been resolved
|
||||
Ok(ImageType::HTMLImageRgba8u {
|
||||
image: HTMLImage::new(image),
|
||||
})
|
||||
}
|
||||
}),
|
||||
PixelType::R32F | PixelType::R32I | PixelType::R16I | PixelType::R8U => {
|
||||
Request::new(async move {
|
||||
let window = web_sys::window().unwrap_abort();
|
||||
|
||||
let mut opts = RequestInit::new();
|
||||
opts.method("GET");
|
||||
opts.mode(mode);
|
||||
|
||||
@@ -111,6 +111,7 @@ pub mod renderable;
|
||||
mod shader;
|
||||
mod tile_fetcher;
|
||||
mod time;
|
||||
mod browser_support;
|
||||
|
||||
use crate::{
|
||||
camera::CameraViewPort, healpix::moc::SpaceMoc, math::lonlat::LonLatT, shader::ShaderManager,
|
||||
|
||||
@@ -2,6 +2,7 @@ pub mod buffer;
|
||||
pub mod texture;
|
||||
|
||||
use crate::app::BLENDING_ANIM_DURATION;
|
||||
use crate::browser_support::BrowserFeaturesSupport;
|
||||
use crate::downloader::query;
|
||||
use crate::downloader::query::CellDesc;
|
||||
use crate::downloader::request::allsky::AllskyRequest;
|
||||
@@ -331,6 +332,7 @@ impl HiPS2D {
|
||||
&mut self,
|
||||
tile_fetcher: &mut TileFetcherQueue,
|
||||
camera: &CameraViewPort,
|
||||
browser_features_support: &BrowserFeaturesSupport
|
||||
) {
|
||||
// do not add tiles if the view is already at depth 0
|
||||
let cfg = self.get_config();
|
||||
@@ -353,7 +355,7 @@ impl HiPS2D {
|
||||
};
|
||||
|
||||
if make_query {
|
||||
Some(query::Tile::new(&tile_cell, self.get_config()))
|
||||
Some(query::Tile::new(&tile_cell, self.get_config(), browser_features_support))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -383,7 +385,7 @@ impl HiPS2D {
|
||||
|
||||
for ancestor in ancestors {
|
||||
if !self.update_priority_tile(&ancestor) {
|
||||
tile_fetcher.append(query::Tile::new(&ancestor, self.get_config()));
|
||||
tile_fetcher.append(query::Tile::new(&ancestor, self.get_config(), browser_features_support));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -392,11 +394,6 @@ impl HiPS2D {
|
||||
self.buffer.contains_tile(cell)
|
||||
}
|
||||
|
||||
pub fn build_tile_query(&self, cell: &HEALPixCell) -> query::Tile {
|
||||
let cfg = self.get_config();
|
||||
query::Tile::new(cell, cfg)
|
||||
}
|
||||
|
||||
pub fn update(&mut self, camera: &mut CameraViewPort, projection: &ProjectionType) {
|
||||
let raytracing = camera.is_raytracing(projection);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod cube;
|
||||
pub mod texture;
|
||||
|
||||
use crate::browser_support::BrowserFeaturesSupport;
|
||||
use crate::healpix::moc::FreqSpaceMoc;
|
||||
use crate::math::angle::ToAngle;
|
||||
use crate::math::lonlat::LonLatT;
|
||||
@@ -288,38 +289,11 @@ impl HiPS3D {
|
||||
})
|
||||
}
|
||||
|
||||
/*pub fn build_tile_query(&self, cell: &HEALPixCell) -> query::Tile {
|
||||
let cfg = self.get_config();
|
||||
match cfg.dataproduct_type {
|
||||
DataproductType::SpectralCube => {
|
||||
// Determination of the f_order from the s_order
|
||||
// From https://aladin.cds.unistra.fr/java/DocTechHiPS3D.pdf page 3
|
||||
let f_max_order = cfg.max_depth_freq.unwrap_abort();
|
||||
let s_max_order = cfg.max_depth_tile;
|
||||
let s_order = cell.depth();
|
||||
|
||||
let f_order = f_max_order - (s_max_order - s_order);
|
||||
let f_hash = self.freq.hash(f_order);
|
||||
let cell = HEALPixFreqCell::new(*cell, f_hash, f_order);
|
||||
|
||||
query::Tile::new_cubic(&cell, cfg)
|
||||
}
|
||||
DataproductType::Cube => {
|
||||
let channel_idx = (((self.freq.0 - cfg.em_min.unwrap_abort().0)
|
||||
/ (cfg.em_max.unwrap_abort().0 - cfg.em_min.unwrap_abort().0))
|
||||
* (cfg.get_cube_depth().unwrap_abort() as f64))
|
||||
as u32;
|
||||
|
||||
query::Tile::new_with_channel(&cell, channel_idx, cfg)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}*/
|
||||
|
||||
pub fn look_for_new_tiles(
|
||||
&mut self,
|
||||
tile_fetcher: &mut TileFetcherQueue,
|
||||
camera: &CameraViewPort,
|
||||
browser_features_support: &BrowserFeaturesSupport
|
||||
) {
|
||||
// update the cursor center before downloading new tiles
|
||||
self.set_cursor_location(camera.get_center().into(), camera);
|
||||
@@ -368,6 +342,7 @@ impl HiPS3D {
|
||||
&tile_cell,
|
||||
channel_idx as u32,
|
||||
cfg,
|
||||
browser_features_support
|
||||
));
|
||||
|
||||
// check if we are starting aladin lite or not.
|
||||
@@ -386,6 +361,7 @@ impl HiPS3D {
|
||||
&ancestor,
|
||||
channel_idx as u32,
|
||||
cfg,
|
||||
browser_features_support
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -440,7 +416,7 @@ impl HiPS3D {
|
||||
});
|
||||
|
||||
for cubic_tile in cubic_tiles_iter {
|
||||
tile_fetcher.append(query::Tile::new_cubic(&cubic_tile, cfg));
|
||||
tile_fetcher.append(query::Tile::new_cubic(&cubic_tile, cfg, browser_features_support));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
||||
@@ -9,6 +9,7 @@ pub mod uv;
|
||||
|
||||
pub use d2::HiPS2D;
|
||||
|
||||
use crate::browser_support::BrowserFeaturesSupport;
|
||||
use crate::renderable::HiPSConfig;
|
||||
use crate::tile_fetcher::TileFetcherQueue;
|
||||
use crate::CameraViewPort;
|
||||
@@ -66,10 +67,11 @@ impl HiPS {
|
||||
&mut self,
|
||||
tile_fetcher: &mut TileFetcherQueue,
|
||||
camera: &CameraViewPort,
|
||||
browser_features_support: &BrowserFeaturesSupport
|
||||
) {
|
||||
match self {
|
||||
D2(hips) => hips.look_for_new_tiles(tile_fetcher, camera),
|
||||
D3(hips) => hips.look_for_new_tiles(tile_fetcher, camera),
|
||||
D2(hips) => hips.look_for_new_tiles(tile_fetcher, camera, browser_features_support),
|
||||
D3(hips) => hips.look_for_new_tiles(tile_fetcher, camera, browser_features_support),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,22 +113,6 @@ impl HiPS {
|
||||
}
|
||||
}
|
||||
|
||||
/*#[inline]
|
||||
pub fn set_moc(&mut self, moc: SpaceMoc) {
|
||||
match self {
|
||||
D2(hips) => hips.set_moc(moc),
|
||||
D3(hips) => hips.set_moc(moc),
|
||||
}
|
||||
}*/
|
||||
|
||||
/*#[inline]
|
||||
pub fn build_tile_query(&self, cell: &HEALPixCell) -> query::Tile {
|
||||
match self {
|
||||
HiPS::D2(hips) => hips.build_tile_query(cell),
|
||||
HiPS::D3(hips) => hips.build_tile_query(cell),
|
||||
}
|
||||
}*/
|
||||
|
||||
pub fn is_allsky(&self) -> bool {
|
||||
self.get_config().is_allsky
|
||||
}
|
||||
|
||||
@@ -227,6 +227,7 @@ impl TileFetcherQueue {
|
||||
HiPS::D3(_) => (),
|
||||
}
|
||||
|
||||
// FIXME: this still might be important to keep but for HiPS2D only
|
||||
/*if cfg.get_min_depth_tile() == 0 {
|
||||
for tile_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||
if let Ok(query) = self.check_in_file_list(hips.build_tile_query(tile_cell)) {
|
||||
|
||||
Reference in New Issue
Block a user