From de39394258d198066d88e7ef528010ade6e95a34 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 16 Nov 2023 22:08:54 -0800 Subject: [PATCH 1/2] HDR textures support --- blade-render/Cargo.toml | 3 +- blade-render/src/texture/mod.rs | 69 +++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/blade-render/Cargo.toml b/blade-render/Cargo.toml index 8442c16e..e8d5265e 100644 --- a/blade-render/Cargo.toml +++ b/blade-render/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/kvark/blade" [features] default = ["asset"] -asset = ["gltf" , "base64", "exr", "mikktspace", "slab", "texpresso", "zune-core", "zune-jpeg", "zune-png", "zune-imageprocs"] +asset = ["gltf" , "base64", "exr", "mikktspace", "slab", "texpresso", "zune-core", "zune-jpeg", "zune-png", "zune-hdr", "zune-imageprocs"] [dependencies] base64 = { workspace = true, optional = true } @@ -37,4 +37,5 @@ texpresso = { version = "2.0", optional = true } zune-core = { git = "https://github.com/etemesi254/zune-image", optional = true } zune-jpeg = { git = "https://github.com/etemesi254/zune-image", optional = true } zune-png = { git = "https://github.com/etemesi254/zune-image", optional = true } +zune-hdr = { git = "https://github.com/etemesi254/zune-image", optional = true } zune-imageprocs = { git = "https://github.com/etemesi254/zune-image", optional = true } diff --git a/blade-render/src/texture/mod.rs b/blade-render/src/texture/mod.rs index eb63f110..4dcb9019 100644 --- a/blade-render/src/texture/mod.rs +++ b/blade-render/src/texture/mod.rs @@ -114,9 +114,12 @@ impl blade_asset::Baker for Baker { exe_context: &choir::ExecutionContext, ) { use blade_graphics::TextureFormat as Tf; + + type LdrTexel = [u8; 4]; + type HdrTexel = [f32; 3]; enum PlainData { - Ldr(Vec<[u8; 4]>), - Hdr(Vec<[f32; 4]>), + Ldr(Vec), + Hdr(Vec), } struct PlainImage { width: usize, @@ -134,9 +137,11 @@ impl blade_asset::Baker for Baker { decoder.decode_headers().unwrap(); let info = decoder.get_info().unwrap().clone(); let mut data = vec![[0u8; 4]; info.width * info.height]; + let count = data.len() * data[0].len(); + assert_eq!(count, decoder.output_buffer_size().unwrap()); decoder .decode_into(unsafe { - slice::from_raw_parts_mut(data.as_mut_ptr() as *mut u8, data.len() * 4) + slice::from_raw_parts_mut(data.as_mut_ptr() as *mut u8, count) }) .unwrap(); PlainImage { @@ -154,9 +159,11 @@ impl blade_asset::Baker for Baker { decoder.decode_headers().unwrap(); let info = decoder.info().unwrap(); let mut data = vec![[0u8; 4]; info.width as usize * info.height as usize]; + let count = data.len() * data[0].len(); + assert_eq!(count, decoder.output_buffer_size().unwrap()); decoder .decode_into(unsafe { - slice::from_raw_parts_mut(data.as_mut_ptr() as *mut u8, data.len() * 4) + slice::from_raw_parts_mut(data.as_mut_ptr() as *mut u8, count) }) .unwrap(); PlainImage { @@ -166,12 +173,35 @@ impl blade_asset::Baker for Baker { } } #[cfg(feature = "asset")] + "hdr" => { + profiling::scope!("decode hdr"); + let options = zune_core::options::DecoderOptions::default(); + let mut decoder = zune_hdr::HdrDecoder::new_with_options(source, options); + decoder.decode_headers().unwrap(); + let (width, height) = decoder.get_dimensions().unwrap(); + let colorspace = decoder.get_colorspace().unwrap(); + assert_eq!(colorspace, zune_core::colorspace::ColorSpace::RGB); + let mut data = vec![[0f32; 3]; width * height]; + let count = data.len() * data[0].len(); + assert_eq!(count, decoder.output_buffer_size().unwrap()); + decoder + .decode_into(unsafe { + slice::from_raw_parts_mut(data.as_mut_ptr() as *mut f32, count) + }) + .unwrap(); + PlainImage { + width, + height, + data: PlainData::Hdr(data), + } + } + #[cfg(feature = "asset")] "exr" => { use exr::prelude::{ReadChannels as _, ReadLayers as _}; profiling::scope!("decode exr"); struct RawImage { width: usize, - data: Vec<[f32; 4]>, + data: Vec, } let image = exr::image::read::read() .no_deep_data() @@ -179,10 +209,10 @@ impl blade_asset::Baker for Baker { .rgba_channels( |size, _| RawImage { width: size.width(), - data: vec![[0f32; 4]; size.width() * size.height()], + data: vec![[0f32; 3]; size.width() * size.height()], }, - |image, position, (r, g, b, a): (f32, f32, f32, f32)| { - image.data[position.y() * image.width + position.x()] = [r, g, b, a]; + |image, position, (r, g, b, _): (f32, f32, f32, f32)| { + image.data[position.y() * image.width + position.x()] = [r, g, b]; }, ) .first_valid_layer() @@ -262,7 +292,7 @@ impl blade_asset::Baker for Baker { } struct CompressTask { - src: Vec<[u8; 4]>, + src: Vec, dst_ptr: *mut u8, } unsafe impl Send for CompressTask {} @@ -321,15 +351,20 @@ impl blade_asset::Baker for Baker { } PlainData::Hdr(data) => { //TODO: compress as BC6E + //Note: we convert RGB32 to RGBA32 here, for now assert_eq!(meta.format, blade_graphics::TextureFormat::Rgba32Float); - let data_raw = unsafe { - slice::from_raw_parts( - data.as_ptr() as *const u8, - data.len() * data[0].len() * mem::size_of::(), - ) - }; - let mut buf = vec![0u8; data_raw.len()]; - buf.copy_from_slice(data_raw); + let in_texel_elements = data[0].len(); + let out_texel_size = 4 * mem::size_of::(); + let mut buf = vec![0u8; data.len() * out_texel_size]; + for (slice, texel) in buf.chunks_mut(out_texel_size).zip(data) { + unsafe { + ptr::copy_nonoverlapping( + texel.as_ptr(), + slice.as_mut_ptr() as *mut f32, + in_texel_elements, + ) + } + } cooker.finish(CookedImage { name: &[], extent: [src.width as u32, src.height as u32, 1], From 117743f1752dbd86d227a41e384f14a79cd74613 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 17 Nov 2023 22:27:45 -0800 Subject: [PATCH 2/2] All around version bumps --- Cargo.toml | 10 +++++----- blade-asset/Cargo.toml | 2 +- blade-egui/Cargo.toml | 4 ++-- blade-graphics/Cargo.toml | 2 +- blade-macros/Cargo.toml | 6 +++--- blade-render/Cargo.toml | 21 +++++++++------------ docs/CHANGELOG.md | 16 +++++++++++----- docs/README.md | 3 ++- examples/bunnymark/main.rs | 17 ++++++++++------- 9 files changed, 44 insertions(+), 37 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 763ab3f5..4bbe3869 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,13 +40,13 @@ readme = "docs/README.md" [features] [dependencies] -blade-asset = { version = "0.1.0", path = "blade-asset" } -blade-macros = { version = "0.2.0", path = "blade-macros" } -blade-graphics = { version = "0.2.0", path = "blade-graphics" } -blade-render = { version = "0.1.0", path = "blade-render" } +blade-asset = { version = "0.2.0", path = "blade-asset" } +blade-egui = { version = "0.2.0", path = "blade-egui" } +blade-macros = { version = "0.2.1", path = "blade-macros" } +blade-graphics = { version = "0.3.0", path = "blade-graphics" } +blade-render = { version = "0.2.0", path = "blade-render" } [dev-dependencies] -blade-egui = { version = "0.1.0", path = "blade-egui" } bytemuck = { workspace = true } choir = { workspace = true } egui = { workspace = true } diff --git a/blade-asset/Cargo.toml b/blade-asset/Cargo.toml index b1bc5cee..822d7dc7 100644 --- a/blade-asset/Cargo.toml +++ b/blade-asset/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blade-asset" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Asset manager for Blade" keywords = ["asset"] diff --git a/blade-egui/Cargo.toml b/blade-egui/Cargo.toml index d0e687e5..5be46426 100644 --- a/blade-egui/Cargo.toml +++ b/blade-egui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blade-egui" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "egui integration for Blade" keywords = ["graphics"] @@ -10,7 +10,7 @@ repository = "https://github.com/kvark/blade" [lib] [dependencies] -blade-graphics = { version = "0.2", path = "../blade-graphics"} +blade-graphics = { version = "0.3", path = "../blade-graphics"} blade-macros = { version = "0.2", path = "../blade-macros"} bytemuck = { workspace = true } egui = { workspace = true, features = ["bytemuck"] } diff --git a/blade-graphics/Cargo.toml b/blade-graphics/Cargo.toml index cb9739b6..8d3703f1 100644 --- a/blade-graphics/Cargo.toml +++ b/blade-graphics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blade-graphics" -version = "0.2.0" +version = "0.3.0" edition = "2021" description = "Graphics abstraction for Blade" keywords = ["graphics"] diff --git a/blade-macros/Cargo.toml b/blade-macros/Cargo.toml index a2f481e8..58f25e8e 100644 --- a/blade-macros/Cargo.toml +++ b/blade-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blade-macros" -version = "0.2.0" +version = "0.2.1" edition = "2021" description = "Macros helpers for Blade users" keywords = ["proc-macro"] @@ -16,6 +16,6 @@ proc-macro2 = "1" quote = "1.0" [dev-dependencies] -blade-graphics = { version = "0.2", path = "../blade-graphics" } -blade-asset = { version = "0.1", path = "../blade-asset" } +blade-graphics = { version = "0.3", path = "../blade-graphics" } +blade-asset = { version = "0.2", path = "../blade-asset" } bytemuck = { workspace = true } diff --git a/blade-render/Cargo.toml b/blade-render/Cargo.toml index e8d5265e..abad5b94 100644 --- a/blade-render/Cargo.toml +++ b/blade-render/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blade-render" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Renderer built on Blade" keywords = ["graphics", "engine"] @@ -16,9 +16,9 @@ asset = ["gltf" , "base64", "exr", "mikktspace", "slab", "texpresso", "zune-core [dependencies] base64 = { workspace = true, optional = true } bitflags = { workspace = true } -blade-graphics = { version = "0.2", path = "../blade-graphics" } -blade-asset = { version = "0.1", path = "../blade-asset" } -blade-macros = { version = "0.2", path = "../blade-macros" } +blade-graphics = { version = "0.3", path = "../blade-graphics" } +blade-asset = { version = "0.2", path = "../blade-asset" } +blade-macros = { version = "0.2.1", path = "../blade-macros" } bytemuck = { workspace = true } choir = { workspace = true } exr = { version = "1.6", optional = true } @@ -31,11 +31,8 @@ profiling = { workspace = true } slab = { workspace = true, optional = true } strum = { workspace = true } texpresso = { version = "2.0", optional = true } -#zune-core = { version = "0.2", optional = true } -#zune-jpeg = { version = "0.3", optional = true } -#zune-png = { version = "0.2", optional = true } -zune-core = { git = "https://github.com/etemesi254/zune-image", optional = true } -zune-jpeg = { git = "https://github.com/etemesi254/zune-image", optional = true } -zune-png = { git = "https://github.com/etemesi254/zune-image", optional = true } -zune-hdr = { git = "https://github.com/etemesi254/zune-image", optional = true } -zune-imageprocs = { git = "https://github.com/etemesi254/zune-image", optional = true } +zune-core = { version = "0.4", optional = true } +zune-jpeg = { version = "0.4", optional = true } +zune-png = { version = "0.4", optional = true } +zune-hdr = { version = "0.4", optional = true } +zune-imageprocs = { version = "0.4", optional = true } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 54991d0c..01a845ce 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,23 +1,29 @@ Changelog for Blade -## Unreleased +## blade-graphics-0.3, blade-render-0.2 (17 Nov 2023) - tangent space generation - spatio-temporal resampling +- SVGF de-noising +- environment map importance sampling - shaders as assets - with includes, enums, and bitflags - with hot reloading +- load textures: `exr`, `hdr` +- utility: `FramePacer` +- examples: scene editing in "scene" + - using egui-gizmo for manipulation -## 0.2 (31 May 2023) +## blade-graphics-0.2, blade-render-0.1 (31 May 2023) - ray tracing support -- examples: ray-query, scene +- examples: "ray-query", "scene" - crate: `blade-egui` for egui integration - crate: `blade-asset` for asset pipeline - crate: `blade-render` for ray-traced renderer - load models: `gltf` - load textures: `png`, `jpg` -## 0.1 (25 Jan 2023) +## blade-graphics-0.1 (25 Jan 2023) - backends: Vulkan, Metal, OpenGL ES + WebGL2 -- examples: mini, bunnymark, particle +- examples: "mini", "bunnymark", "particle" - crate `blade-graphics` for GPU abstracting GPU operations - crate `blade-macros` for `ShaderData` derivation diff --git a/docs/README.md b/docs/README.md index 07227365..e095a314 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,8 @@ [![Matrix](https://img.shields.io/static/v1?label=dev&message=%23blade&color=blueviolet&logo=matrix)](https://matrix.to/#/#blade-dev:matrix.org) [![Build Status](https://github.com/kvark/blade/workflows/check/badge.svg)](https://github.com/kvark/blade/actions) [![Docs](https://docs.rs/blade/badge.svg)](https://docs.rs/blade) -[![Crates.io](https://img.shields.io/crates/v/blade.svg?maxAge=2592000)](https://crates.io/crates/blade) +[![Crates.io](https://img.shields.io/crates/v/blade-graphics.svg?maxAge=2592000)](https://crates.io/crates/blade-graphics) +[![Crates.io](https://img.shields.io/crates/v/blade-render.svg?maxAge=2592000)](https://crates.io/crates/blade-render) ![](logo.png) diff --git a/examples/bunnymark/main.rs b/examples/bunnymark/main.rs index 9c6064ed..f8cf1835 100644 --- a/examples/bunnymark/main.rs +++ b/examples/bunnymark/main.rs @@ -39,7 +39,7 @@ struct Sprite { struct Example { pipeline: gpu::RenderPipeline, - command_encoder: gpu::CommandEncoder, + command_encoder: Option, prev_sync_point: Option, texture: gpu::Texture, view: gpu::TextureView, @@ -169,7 +169,7 @@ impl Example { Self { pipeline, - command_encoder, + command_encoder: Some(command_encoder), prev_sync_point: None, texture, view, @@ -223,10 +223,11 @@ impl Example { fn render(&mut self) { let frame = self.context.acquire_frame(); - self.command_encoder.start(); - self.command_encoder.init_texture(frame.texture()); + let encoder = self.command_encoder.as_mut().unwrap(); + encoder.start(); + encoder.init_texture(frame.texture()); - if let mut pass = self.command_encoder.render(gpu::RenderTargetSet { + if let mut pass = encoder.render(gpu::RenderTargetSet { colors: &[gpu::RenderTarget { view: frame.texture_view(), init_op: gpu::InitOp::Clear(gpu::TextureColor::TransparentBlack), @@ -258,8 +259,8 @@ impl Example { rc.draw(0, 4, 0, 1); } } - self.command_encoder.present(frame); - let sync_point = self.context.submit(&mut self.command_encoder); + encoder.present(frame); + let sync_point = self.context.submit(encoder); if let Some(sp) = self.prev_sync_point.take() { self.context.wait_for(&sp, !0); } @@ -271,6 +272,8 @@ impl Example { self.context.wait_for(&sp, !0); } self.context.destroy_texture(self.texture); + self.context + .destroy_command_encoder(self.command_encoder.take().unwrap()); } }