From fde17bd67c9939fffba60d809a5ea6883048d163 Mon Sep 17 00:00:00 2001 From: Schell Carl Scivally Date: Thu, 25 Sep 2025 09:53:37 +1200 Subject: [PATCH 1/3] don't require CARGO_WORKSPACE_DIR --- crates/renderling-build/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/renderling-build/src/lib.rs b/crates/renderling-build/src/lib.rs index 64a1a2dd..01625daa 100644 --- a/crates/renderling-build/src/lib.rs +++ b/crates/renderling-build/src/lib.rs @@ -138,8 +138,11 @@ fn wgsl(spv_filepath: impl AsRef, destination: impl AsRef std::path::PathBuf { - std::path::PathBuf::from(std::env!("CARGO_WORKSPACE_DIR")) + std::path::PathBuf::from(std::env::var("CARGO_WORKSPACE_DIR").unwrap()) } /// The test_output directory. From c5a71bff92366ec13d00c2790f7d32fd043a1345 Mon Sep 17 00:00:00 2001 From: Schell Carl Scivally Date: Thu, 25 Sep 2025 10:21:39 +1200 Subject: [PATCH 2/3] fix test paths --- Cargo.lock | 1 + crates/img-diff/Cargo.toml | 1 + crates/img-diff/src/lib.rs | 16 ++++++---------- crates/renderling-build/src/lib.rs | 19 +++++++++++++++++++ crates/xtask/src/server.rs | 6 +++--- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba56abfc..124b80a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2097,6 +2097,7 @@ dependencies = [ "glam", "image 0.25.6", "log", + "renderling_build", "snafu 0.7.5", ] diff --git a/crates/img-diff/Cargo.toml b/crates/img-diff/Cargo.toml index 94531c38..d216d56e 100644 --- a/crates/img-diff/Cargo.toml +++ b/crates/img-diff/Cargo.toml @@ -9,4 +9,5 @@ edition = "2021" glam = { workspace = true, features = ["std"] } image.workspace = true log.workspace = true +renderling_build = { path = "../renderling-build" } snafu = "^0.7" diff --git a/crates/img-diff/src/lib.rs b/crates/img-diff/src/lib.rs index e3cd62c8..4074bcc7 100644 --- a/crates/img-diff/src/lib.rs +++ b/crates/img-diff/src/lib.rs @@ -1,13 +1,9 @@ //! Provides image diffing for testing. use glam::{Vec3, Vec4, Vec4Swizzles}; use image::{DynamicImage, Luma, Rgb, Rgb32FImage, Rgba32FImage}; +use renderling_build::{test_img_dir, test_output_dir}; use snafu::prelude::*; -use std::path::Path; -pub const TEST_IMG_DIR: &str = concat!(std::env!("CARGO_WORKSPACE_DIR"), "test_img"); -pub const TEST_OUTPUT_DIR: &str = concat!(std::env!("CARGO_WORKSPACE_DIR"), "test_output"); -pub const WASM_TEST_OUTPUT_DIR: &str = - concat!(std::env!("CARGO_WORKSPACE_DIR"), "test_output/wasm"); const PIXEL_MAGNITUDE_THRESHOLD: f32 = 0.1; pub const LOW_PIXEL_THRESHOLD: f32 = 0.02; const IMAGE_DIFF_THRESHOLD: f32 = 0.05; @@ -44,7 +40,7 @@ pub struct DiffCfg { /// The name of the test. pub test_name: Option<&'static str>, /// The output directory to store comparisons in. - pub output_dir: &'static str, + pub output_dir: std::path::PathBuf, } impl Default for DiffCfg { @@ -53,7 +49,7 @@ impl Default for DiffCfg { pixel_threshold: PIXEL_MAGNITUDE_THRESHOLD, image_threshold: IMAGE_DIFF_THRESHOLD, test_name: None, - output_dir: TEST_OUTPUT_DIR, + output_dir: test_output_dir(), } } } @@ -143,7 +139,7 @@ pub fn save_to( } pub fn save(filename: impl AsRef, seen: impl Into) { - save_to(TEST_OUTPUT_DIR, filename, seen).unwrap() + save_to(test_output_dir(), filename, seen).unwrap() } pub fn assert_eq_cfg( @@ -185,7 +181,7 @@ pub fn assert_eq_cfg( return Ok(()); } - let mut dir = Path::new(output_dir).join(test_name.unwrap_or(filename)); + let mut dir = output_dir.join(test_name.unwrap_or(filename)); dir.set_extension(""); std::fs::create_dir_all(&dir).expect("cannot create test output dir"); let expected = dir.join("expected.png"); @@ -228,7 +224,7 @@ pub fn assert_img_eq_cfg_result( seen: impl Into, cfg: DiffCfg, ) -> Result<(), String> { - let path = Path::new(TEST_IMG_DIR).join(filename); + let path = test_img_dir().join(filename); let lhs = image::open(&path) .unwrap_or_else(|e| panic!("can't open expected image '{}': {e}", path.display(),)); assert_eq_cfg(filename, lhs, seen, cfg) diff --git a/crates/renderling-build/src/lib.rs b/crates/renderling-build/src/lib.rs index 01625daa..3248b3ae 100644 --- a/crates/renderling-build/src/lib.rs +++ b/crates/renderling-build/src/lib.rs @@ -145,11 +145,30 @@ pub fn workspace_dir() -> std::path::PathBuf { std::path::PathBuf::from(std::env::var("CARGO_WORKSPACE_DIR").unwrap()) } +/// The test_img directory. +/// +/// ## Panics +/// Panics if not called from a checkout of the renderling repo. +pub fn test_img_dir() -> std::path::PathBuf { + workspace_dir().join("test_img") +} + /// The test_output directory. +/// +/// ## Panics +/// Panics if not called from a checkout of the renderling repo. pub fn test_output_dir() -> std::path::PathBuf { workspace_dir().join("test_output") } +/// The WASM test_output directory. +/// +/// ## Panics +/// Panics if not called from a checkout of the renderling repo. +pub fn wasm_test_output_dir() -> std::path::PathBuf { + test_output_dir().join("wasm") +} + #[derive(Debug)] pub struct RenderlingPaths { /// `cargo_workspace` is not available when building outside of the project directory. diff --git a/crates/xtask/src/server.rs b/crates/xtask/src/server.rs index f1b54c27..d549d71d 100644 --- a/crates/xtask/src/server.rs +++ b/crates/xtask/src/server.rs @@ -117,7 +117,7 @@ async fn assert_img_eq_inner( filename, seen, DiffCfg { - output_dir: img_diff::WASM_TEST_OUTPUT_DIR, + output_dir: renderling_build::wasm_test_output_dir(), ..Default::default() }, ) @@ -149,7 +149,7 @@ async fn assert_img_eq( async fn save_inner(filename: &str, img: wire_types::Image) -> Result<(), Error> { let img = image_from_wire(img)?; - img_diff::save_to(img_diff::WASM_TEST_OUTPUT_DIR, filename, img) + img_diff::save_to(renderling_build::wasm_test_output_dir(), filename, img) .map_err(|description| Error { description }) } @@ -197,7 +197,7 @@ async fn artifact_inner(filename: impl AsRef, body: Body) -> Re } async fn artifact(Path(parts): Path>, body: Body) -> Response { - let filename = std::path::PathBuf::from(img_diff::WASM_TEST_OUTPUT_DIR).join(parts.join("/")); + let filename = renderling_build::wasm_test_output_dir().join(parts.join("/")); log::info!("saving artifact to {filename:?}"); let result = artifact_inner(filename, body).await; Response::builder() From f92b3519558759f5525990f1e9673bf79acc2571 Mon Sep 17 00:00:00 2001 From: Schell Carl Scivally Date: Sat, 27 Sep 2025 08:16:27 +1200 Subject: [PATCH 3/3] move BlockFuture to lib and gate with 'test-utils' feature flag --- crates/renderling/Cargo.toml | 5 ++-- crates/renderling/src/lib.rs | 49 ++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/crates/renderling/Cargo.toml b/crates/renderling/Cargo.toml index 8c9e6b81..6e13bc77 100644 --- a/crates/renderling/Cargo.toml +++ b/crates/renderling/Cargo.toml @@ -26,7 +26,7 @@ crate-type = ["rlib", "cdylib"] default = ["gltf", "ui", "winit"] gltf = ["dep:gltf", "dep:serde_json"] test_i8_i16_extraction = [] -test-utils = ["dep:metal", "dep:wgpu-core"] +test-utils = ["dep:metal", "dep:wgpu-core", "dep:futures-lite"] ui = ["dep:glyph_brush", "dep:loading-bytes", "dep:lyon"] wasm = ["wgpu/fragile-send-sync-non-atomic-wasm"] debug-slab = [] @@ -57,8 +57,9 @@ async-channel = {workspace = true} bytemuck = {workspace = true} craballoc.workspace = true crabslab = { workspace = true, features = ["default"] } -dagga = {workspace=true} crunch = "0.5" +dagga = {workspace=true} +futures-lite = { workspace = true, optional = true } glam = { workspace = true, features = ["std"] } gltf = {workspace = true, optional = true} glyph_brush = {workspace = true, optional = true} diff --git a/crates/renderling/src/lib.rs b/crates/renderling/src/lib.rs index 4cb8eaf3..e8b2bcec 100644 --- a/crates/renderling/src/lib.rs +++ b/crates/renderling/src/lib.rs @@ -304,6 +304,31 @@ pub fn capture_gpu_frame( } } +#[cfg(all(cpu, any(test, feature = "test-utils")))] +#[allow(unused, reason = "Used in sync tests in userland")] +/// Marker trait to block on futures in synchronous code. +/// +/// This is a simple convenience. +/// Many of the tests in this crate render something and then read a +/// texture in order to perform a diff on the result using a known image. +/// Since reading from the GPU is async, this trait helps cut down +/// boilerplate. +pub trait BlockOnFuture { + type Output; + + /// Block on the future using [`futures_util::future::block_on`]. + fn block(self) -> Self::Output; +} + +#[cfg(all(cpu, any(test, feature = "test-utils")))] +impl BlockOnFuture for T { + type Output = ::Output; + + fn block(self) -> Self::Output { + futures_lite::future::block_on(self) + } +} + #[cfg(test)] mod test { use super::*; @@ -318,6 +343,8 @@ mod test { #[allow(unused_imports)] pub use renderling_build::{test_output_dir, workspace_dir}; + pub use super::BlockOnFuture; + #[cfg_attr(not(target_arch = "wasm32"), ctor::ctor)] fn init_logging() { let _ = env_logger::builder().is_test(true).try_init(); @@ -334,28 +361,6 @@ mod test { super::capture_gpu_frame(ctx, path, f) } - /// Marker trait to block on futures in synchronous code. - /// - /// This is a simple convenience. - /// Many of the tests in this crate render something and then read a - /// texture in order to perform a diff on the result using a known image. - /// Since reading from the GPU is async, this trait helps cut down - /// boilerplate. - pub trait BlockOnFuture { - type Output; - - /// Block on the future using [`futures_util::future::block_on`]. - fn block(self) -> Self::Output; - } - - impl BlockOnFuture for T { - type Output = ::Output; - - fn block(self) -> Self::Output { - futures_lite::future::block_on(self) - } - } - pub fn make_two_directional_light_setup(stage: &Stage) -> (AnalyticalLight, AnalyticalLight) { let sunlight_a = stage .new_directional_light()