From 64b14deaabc99f6e4c76f5d16e79786821e7372c Mon Sep 17 00:00:00 2001 From: Patrick Monaghan <0x5f.manpat@gmail.com> Date: Sun, 29 Sep 2024 22:58:31 +0100 Subject: [PATCH] Fix Core::upload_image_raw for multi-layer uploads; Implement basic image array loading in resource manager --- toybox-gfx/src/core/image.rs | 2 +- toybox-gfx/src/resource_manager.rs | 7 +++ toybox-gfx/src/resource_manager/image.rs | 46 ++++++++++++++++++- .../src/resource_manager/image/load_image.rs | 27 +++++++++++ 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/toybox-gfx/src/core/image.rs b/toybox-gfx/src/core/image.rs index 7fe809a..802b6f3 100644 --- a/toybox-gfx/src/core/image.rs +++ b/toybox-gfx/src/core/image.rs @@ -223,7 +223,7 @@ impl super::Core { let ImageRange {offset, size} = range.into().unwrap_or(ImageRange::from_size(image_info.size)); - let expected_size = format.texel_byte_size() * (size.x * size.y) as usize; + let expected_size = format.texel_byte_size() * (size.x * size.y * size.z) as usize; assert_eq!(data_size, expected_size, "Core::upload_image_raw not passed expected amount of data"); // TODO(pat.m): assert that size + offset < image_info.size diff --git a/toybox-gfx/src/resource_manager.rs b/toybox-gfx/src/resource_manager.rs index 74faf8f..6381cfc 100644 --- a/toybox-gfx/src/resource_manager.rs +++ b/toybox-gfx/src/resource_manager.rs @@ -37,6 +37,7 @@ pub struct ResourceManager { pub shaders: ResourceStorage, load_image_requests: ResourceRequestMap, + load_image_array_requests: ResourceRequestMap, create_image_requests: ResourceRequestMap, pub images: ResourceStorage, @@ -135,6 +136,7 @@ impl ResourceManager { shaders, load_image_requests: ResourceRequestMap::new(), + load_image_array_requests: ResourceRequestMap::new(), create_image_requests: ResourceRequestMap::new(), images: ResourceStorage::new(), @@ -210,6 +212,11 @@ impl ResourceManager { .with_context(|| format!("Loading image '{}'", def.path.display())) })?; + self.load_image_array_requests.process_requests(&mut self.images, |def| { + ImageResource::array_from_vfs(core, vfs, &def.paths, def.label.clone()) + .with_context(|| format!("Loading image array '{}'", def.label)) + })?; + self.create_image_requests.process_requests(&mut self.images, |def| { Ok(ImageResource::from_create_request(core, def)) })?; diff --git a/toybox-gfx/src/resource_manager/image.rs b/toybox-gfx/src/resource_manager/image.rs index cc06c9c..14e356e 100644 --- a/toybox-gfx/src/resource_manager/image.rs +++ b/toybox-gfx/src/resource_manager/image.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::core::*; @@ -84,6 +84,50 @@ impl ImageResource { }) } + pub fn array_from_vfs(core: &mut Core, vfs: &vfs::Vfs, virtual_paths: &[PathBuf], label: String) -> anyhow::Result { + if virtual_paths.is_empty() { + anyhow::bail!("Trying to create empty image array") + } + + let mut image_data = Vec::new(); + + let mut common_size = None; + + for virtual_path in virtual_paths { + // TODO(pat.m): use a BufReader instead so that image can read only what it needs + let file_data = vfs.load_resource_data(virtual_path)?; + + let image = ::image::load_from_memory(&file_data)?.flipv().into_rgba8(); + let size = image.dimensions(); + + if *common_size.get_or_insert(size) != size { + let (w, h) = common_size.unwrap(); + let (w2, h2) = size; + let path = virtual_path.display(); + anyhow::bail!("Size mismatch while loading image array '{label}'. Expected {w}x{h}, but {path} was {w2}x{h2}"); + } + + image_data.extend(image.into_vec()); + } + + let (width, height) = common_size.unwrap(); + let num_layers = virtual_paths.len() as u32; + let size = Vec2i::new(width as i32, height as i32); + + // TODO(pat.m): allow diff texel formats + let name = core.create_image_2d_array(ImageFormat::Srgba8, size, num_layers); + core.upload_image(name, None, ImageFormat::Srgba8, &image_data); + core.set_debug_label(name, &label); + + Ok(ImageResource { + name, + image_info: core.get_image_info(name).unwrap(), + resize_policy: ImageResizePolicy::Fixed, + clear_policy: ImageClearPolicy::Never, + label, + }) + } + pub fn from_create_request(core: &mut Core, req: &CreateImageRequest) -> ImageResource { let mut image_info = req.image_info.clone(); diff --git a/toybox-gfx/src/resource_manager/image/load_image.rs b/toybox-gfx/src/resource_manager/image/load_image.rs index 2da32e5..87e1192 100644 --- a/toybox-gfx/src/resource_manager/image/load_image.rs +++ b/toybox-gfx/src/resource_manager/image/load_image.rs @@ -20,4 +20,31 @@ impl ResourceRequest for LoadImageRequest { fn register(self, rm: &mut ResourceManager) -> ImageHandle { rm.load_image_requests.request_handle(&mut rm.images, self) } +} + + + +#[derive(Hash, Clone, Debug, Eq, PartialEq)] +pub struct LoadImageArrayRequest { + pub paths: Vec, + pub label: String, +} + + +impl LoadImageArrayRequest { + pub fn from>(label: impl Into, paths: impl IntoIterator) -> LoadImageArrayRequest { + LoadImageArrayRequest { + label: label.into(), + paths: paths.into_iter().map(Into::into).collect() + } + } +} + + +impl ResourceRequest for LoadImageArrayRequest { + type Resource = ImageResource; + + fn register(self, rm: &mut ResourceManager) -> ImageHandle { + rm.load_image_array_requests.request_handle(&mut rm.images, self) + } } \ No newline at end of file