Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remember to decode JPEGs #1884

Merged
merged 4 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/re_log_types/src/component_types/tensor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,9 @@ pub enum TensorDataMeaning {
Depth,
}

/// A Multi-dimensional Tensor
/// A Multi-dimensional Tensor.
///
/// All clones are shallow.
///
/// ## Examples
///
Expand Down
25 changes: 14 additions & 11 deletions crates/re_viewer/src/gpu_bridge/tensor_to_gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use re_renderer::{
RenderContext,
};

use crate::{gpu_bridge::get_or_create_texture, misc::caches::TensorStats};
use crate::{gpu_bridge::get_or_create_texture, misc::caches::TensorStats, DecodedTensor};

use super::try_get_or_create_texture;

Expand All @@ -28,7 +28,7 @@ use super::try_get_or_create_texture;
pub fn tensor_to_gpu(
render_ctx: &mut RenderContext,
debug_name: &str,
tensor: &Tensor,
tensor: &DecodedTensor,
tensor_stats: &TensorStats,
annotations: &crate::ui::Annotations,
) -> anyhow::Result<ColormappedTexture> {
Expand Down Expand Up @@ -60,7 +60,7 @@ pub fn tensor_to_gpu(
fn color_tensor_to_gpu(
render_ctx: &mut RenderContext,
debug_name: &str,
tensor: &Tensor,
tensor: &DecodedTensor,
tensor_stats: &TensorStats,
) -> anyhow::Result<ColormappedTexture> {
let texture_handle = try_get_or_create_texture(render_ctx, hash(tensor.id()), || {
Expand Down Expand Up @@ -132,7 +132,7 @@ fn color_tensor_to_gpu(
fn class_id_tensor_to_gpu(
render_ctx: &mut RenderContext,
debug_name: &str,
tensor: &Tensor,
tensor: &DecodedTensor,
tensor_stats: &TensorStats,
annotations: &crate::ui::Annotations,
) -> anyhow::Result<ColormappedTexture> {
Expand Down Expand Up @@ -200,7 +200,7 @@ fn class_id_tensor_to_gpu(
fn depth_tensor_to_gpu(
render_ctx: &mut RenderContext,
debug_name: &str,
tensor: &Tensor,
tensor: &DecodedTensor,
tensor_stats: &TensorStats,
) -> anyhow::Result<ColormappedTexture> {
let [_height, _width, depth] = height_width_depth(tensor)?;
Expand All @@ -223,7 +223,10 @@ fn depth_tensor_to_gpu(
})
}

fn depth_tensor_range(tensor: &Tensor, tensor_stats: &TensorStats) -> anyhow::Result<(f64, f64)> {
fn depth_tensor_range(
tensor: &DecodedTensor,
tensor_stats: &TensorStats,
) -> anyhow::Result<(f64, f64)> {
let range = tensor_stats.range.ok_or(anyhow::anyhow!(
"Tensor has no range!? Was this compressed?"
))?;
Expand Down Expand Up @@ -255,7 +258,7 @@ fn depth_tensor_range(tensor: &Tensor, tensor_stats: &TensorStats) -> anyhow::Re
/// Uses no `Unorm/Snorm` formats.
fn general_texture_creation_desc_from_tensor<'a>(
debug_name: &str,
tensor: &'a Tensor,
tensor: &'a DecodedTensor,
) -> anyhow::Result<Texture2DCreationDesc<'a>> {
let [height, width, depth] = height_width_depth(tensor)?;

Expand All @@ -277,7 +280,7 @@ fn general_texture_creation_desc_from_tensor<'a>(
TensorData::F64(buf) => (narrow_f64_to_f32s(buf), TextureFormat::R32Float), // narrowing to f32!

TensorData::JPEG(_) => {
anyhow::bail!("JPEGs should have been decoded at this point")
unreachable!("DecodedTensor cannot contain a JPEG")
}
}
}
Expand All @@ -299,7 +302,7 @@ fn general_texture_creation_desc_from_tensor<'a>(
TensorData::F64(buf) => (narrow_f64_to_f32s(buf), TextureFormat::Rg32Float), // narrowing to f32!

TensorData::JPEG(_) => {
anyhow::bail!("JPEGs should have been decoded at this point")
unreachable!("DecodedTensor cannot contain a JPEG")
}
}
}
Expand Down Expand Up @@ -336,7 +339,7 @@ fn general_texture_creation_desc_from_tensor<'a>(
),

TensorData::JPEG(_) => {
anyhow::bail!("JPEGs should have been decoded at this point")
unreachable!("DecodedTensor cannot contain a JPEG")
}
}
}
Expand All @@ -360,7 +363,7 @@ fn general_texture_creation_desc_from_tensor<'a>(
TensorData::F64(buf) => (narrow_f64_to_f32s(buf), TextureFormat::Rgba32Float), // narrowing to f32!

TensorData::JPEG(_) => {
anyhow::bail!("JPEGs should have been decoded at this point")
unreachable!("DecodedTensor cannot contain a JPEG")
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/re_viewer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ pub(crate) use misc::{mesh_loader, Item, TimeControl, TimeView, ViewerContext};
use re_log_types::PythonVersion;
pub(crate) use ui::{memory_panel, selection_panel, time_panel, UiVerbosity};

pub(crate) use misc::caches::DecodedTensor;

pub use app::{App, StartupOptions};
pub use remote_viewer_app::RemoteViewerApp;

Expand Down
2 changes: 2 additions & 0 deletions crates/re_viewer/src/misc/caches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ mod tensor_decode_cache;

use re_log_types::component_types::{self};

pub use tensor_decode_cache::DecodedTensor;

/// Does memoization of different things for the immediate mode UI.
#[derive(Default)]
pub struct Caches {
Expand Down
55 changes: 47 additions & 8 deletions crates/re_viewer/src/misc/caches/tensor_decode_cache.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
use re_log_types::component_types::{Tensor, TensorDimension, TensorId};

// ----------------------------------------------------------------------------

/// A thin wrapper around a [`Tensor`] that is guaranteed to not be compressed (never a jpeg).
///
/// All clones are shallow, like for [`Tensor`].
#[derive(Clone)]
pub struct DecodedTensor(Tensor);

impl DecodedTensor {
#[inline(always)]
pub fn inner(&self) -> &Tensor {
&self.0
}
}

impl AsRef<Tensor> for DecodedTensor {
#[inline(always)]
fn as_ref(&self) -> &Tensor {
&self.0
}
}

impl std::ops::Deref for DecodedTensor {
type Target = Tensor;

#[inline(always)]
fn deref(&self) -> &Tensor {
&self.0
}
}

impl std::borrow::Borrow<Tensor> for DecodedTensor {
#[inline(always)]
fn borrow(&self) -> &Tensor {
&self.0
}
}

// ----------------------------------------------------------------------------

#[derive(thiserror::Error, Clone, Debug)]
pub enum TensorDecodeError {
// TODO(jleibs): It would be nice to just transparently wrap
Expand All @@ -18,10 +58,9 @@ pub enum TensorDecodeError {
},
}

#[derive(Clone)]
struct DecodedTensor {
struct DecodedTensorResult {
/// Cached `Result` from decoding the `Tensor`
tensor: Result<Tensor, TensorDecodeError>,
tensor: Result<DecodedTensor, TensorDecodeError>,

/// Total memory used by this `Tensor`.
memory_used: u64,
Expand All @@ -33,7 +72,7 @@ struct DecodedTensor {
/// A cache of decoded [`Tensor`] entities, indexed by `TensorId`.
#[derive(Default)]
pub struct DecodeCache {
images: nohash_hasher::IntMap<TensorId, DecodedTensor>,
images: nohash_hasher::IntMap<TensorId, DecodedTensorResult>,
memory_used: u64,
generation: u64,
}
Expand All @@ -48,7 +87,7 @@ impl DecodeCache {
pub fn try_decode_tensor_if_necessary(
&mut self,
maybe_encoded_tensor: Tensor,
) -> Result<Tensor, TensorDecodeError> {
) -> Result<DecodedTensor, TensorDecodeError> {
crate::profile_function!();
match &maybe_encoded_tensor.data {
re_log_types::component_types::TensorData::JPEG(buf) => {
Expand All @@ -67,7 +106,7 @@ impl DecodeCache {
Ok(img) => match Tensor::from_image(img) {
Ok(tensor) => {
if tensor.shape() == maybe_encoded_tensor.shape() {
Ok(tensor)
Ok(DecodedTensor(tensor))
emilk marked this conversation as resolved.
Show resolved Hide resolved
} else {
Err(TensorDecodeError::InvalidMetaData {
expected: maybe_encoded_tensor.shape().into(),
Expand All @@ -86,7 +125,7 @@ impl DecodeCache {
};
self.memory_used += memory_used;
let last_use_generation = 0;
DecodedTensor {
DecodedTensorResult {
tensor,
memory_used,
last_use_generation,
Expand All @@ -96,7 +135,7 @@ impl DecodeCache {

lookup.tensor.clone()
}
_ => Ok(maybe_encoded_tensor),
_ => Ok(DecodedTensor(maybe_encoded_tensor)),
}
}

Expand Down
9 changes: 5 additions & 4 deletions crates/re_viewer/src/ui/data_ui/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use re_ui::ReUi;
use crate::{
misc::{caches::TensorStats, ViewerContext},
ui::annotations::AnnotationMap,
DecodedTensor,
};

use super::{EntityDataUi, UiVerbosity};
Expand Down Expand Up @@ -54,7 +55,7 @@ fn tensor_ui(
entity_path: &re_data_store::EntityPath,
query: &re_arrow_store::LatestAtQuery,
_encoded_tensor: &Tensor,
tensor: &Tensor,
tensor: &DecodedTensor,
) {
// See if we can convert the tensor to a GPU texture.
// Even if not, we will show info about the tensor.
Expand Down Expand Up @@ -328,7 +329,7 @@ fn show_zoomed_image_region_tooltip(
render_ctx: &mut re_renderer::RenderContext,
parent_ui: &mut egui::Ui,
response: egui::Response,
tensor: &Tensor,
tensor: &DecodedTensor,
tensor_stats: &TensorStats,
annotations: &crate::ui::Annotations,
meter: Option<f32>,
Expand Down Expand Up @@ -408,7 +409,7 @@ pub fn show_zoomed_image_region_area_outline(
pub fn show_zoomed_image_region(
render_ctx: &mut re_renderer::RenderContext,
ui: &mut egui::Ui,
tensor: &Tensor,
tensor: &DecodedTensor,
tensor_stats: &TensorStats,
annotations: &crate::ui::Annotations,
meter: Option<f32>,
Expand All @@ -434,7 +435,7 @@ pub fn show_zoomed_image_region(
fn try_show_zoomed_image_region(
render_ctx: &mut re_renderer::RenderContext,
ui: &mut egui::Ui,
tensor: &Tensor,
tensor: &DecodedTensor,
tensor_stats: &TensorStats,
annotations: &crate::ui::Annotations,
meter: Option<f32>,
Expand Down
9 changes: 6 additions & 3 deletions crates/re_viewer/src/ui/view_spatial/scene/mod.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
use std::sync::Arc;

use ahash::HashMap;

use re_data_store::{EntityPath, InstancePathHash};
use re_log_types::{
component_types::{ClassId, InstanceKey, KeypointId, Tensor},
component_types::{ClassId, InstanceKey, KeypointId},
MeshId,
};
use re_renderer::{Color32, OutlineMaskPreference, Size};

use super::{SpaceCamera3D, SpatialNavigationMode};
use crate::{
misc::{mesh_loader::LoadedMesh, SpaceViewHighlights, TransformCache, ViewerContext},
ui::{
annotations::{auto_color, AnnotationMap},
Annotations, SceneQuery,
},
DecodedTensor,
};

use super::{SpaceCamera3D, SpatialNavigationMode};

mod picking;
mod primitives;
mod scene_part;
Expand Down Expand Up @@ -59,7 +62,7 @@ pub struct Image {
/// Path to the image (note image instance ids would refer to pixels!)
pub ent_path: EntityPath,

pub tensor: Tensor,
pub tensor: DecodedTensor,

/// If this is a depth map, how long is a meter?
///
Expand Down
Loading