Skip to content

Commit

Permalink
mesh: Add no_std support by making the dynamic module optional.
Browse files Browse the repository at this point in the history
I wrote that I wasn't going to bother doing this until I found a use
case, but it turns out it's really simple if we cut at the right spot.
And it makes sense to make the `dynamic` part optional since some
applications really are one-shot and have no need for it.

Also made the dep of `all-is-cubes-desktop` on `all-is-cubes-mesh`
optional since it is only used directly via `all-is-cubes-gpu`.
  • Loading branch information
kpreid committed Sep 21, 2024
1 parent 1c7375f commit 8316066
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 45 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -467,13 +467,13 @@ jobs:

- name: no_std lint
run: |
cargo clippy --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render
cargo clippy --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render -p all-is-cubes-mesh
- name: no_std build
# This is `cargo build`, not `cargo check`, because `cargo check` won't detect problems like
# use of undefined linker symbols. Not sure if that matters.
run: |
cargo build --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render
cargo build --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render -p all-is-cubes-mesh
fuzz:
# Don't spend time on fuzzing if the build failed indicating the code is bad other ways
Expand Down
16 changes: 13 additions & 3 deletions all-is-cubes-desktop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ required-features = ["record"]
# builds.
default = ["audio", "import", "record", "terminal"]
# Producing image or video recording, or any exported/saved data.
record = ["dep:png", "all-is-cubes-port/export", "all-is-cubes-port/all-formats"]
record = [
"dep:png",
"all-is-cubes-mesh", # used in glTF recording
"all-is-cubes-port/export",
"all-is-cubes-port/all-formats",
]
# Importing non-native data formats.
import = ["all-is-cubes-port/import", "all-is-cubes-port/all-formats"]
# Required for `--graphics=terminal` and `--graphics=print`;
Expand All @@ -47,15 +52,20 @@ terminal = ["dep:ratatui", "dep:unicode-width"]
# Game audio output support.
audio = ["dep:kira"]
# Adds rerun logging support. Intended mainly for development of All is Cubes itself.
rerun = ["dep:re_sdk", "all-is-cubes/rerun", "all-is-cubes-gpu/rerun"]
rerun = [
"dep:re_sdk",
"all-is-cubes/rerun",
"all-is-cubes-gpu/rerun",
"all-is-cubes-mesh",
]
# TODO: Define a feature with which to turn off windowing & GPU support.

[dependencies]
all-is-cubes = { workspace = true, features = ["auto-threads", "save"] }
# TODO: make template support an optional feature, and this dependency with it
all-is-cubes-content = { workspace = true }
all-is-cubes-gpu = { workspace = true, features = ["auto-threads", "wgpu"] }
all-is-cubes-mesh = { workspace = true }
all-is-cubes-mesh = { workspace = true, optional = true, features = ["dynamic"] } # TODO: make this optional
# TODO: make all file access an optional feature
all-is-cubes-port = { workspace = true, features = ["import", "native"] }
# TODO: make raytracer optional
Expand Down
2 changes: 1 addition & 1 deletion all-is-cubes-gpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ auto-threads = [

[dependencies]
all-is-cubes = { workspace = true, features = ["std"] }
all-is-cubes-mesh = { workspace = true }
all-is-cubes-mesh = { workspace = true, features = ["dynamic"] }
all-is-cubes-render = { workspace = true, features = ["raytracer"] }
bytemuck = { workspace = true, features = ["derive"] }
cfg-if = { workspace = true }
Expand Down
20 changes: 14 additions & 6 deletions all-is-cubes-mesh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ categories = ["games", "graphics", "rendering"]
keywords = ["all-is-cubes", "voxel", "mesh"]

[package.metadata.docs.rs]
features = ["_full-documentation"]
features = ["_full-documentation", "arbitrary", "dynamic"]

[lib]
# Disable running as benchmark so that the default doesn't interfere with Criterion usage.
Expand All @@ -31,6 +31,14 @@ required-features = ["rerun"]

[features]
default = []
# Updating meshes as their data sources change. Requires std.
dynamic = [
"dep:flume",
"dep:futures-channel",
"dep:futures-util",
"dep:hashbrown",
"dep:log",
]
# Adds support for mesh generation performance logging to Rerun.
rerun = ["all-is-cubes/rerun"]
# Adds `impl arbitrary::Arbitrary for ...`
Expand All @@ -52,13 +60,13 @@ bitvec = { workspace = true }
bytemuck = { workspace = true }
cfg-if = { workspace = true }
either = { workspace = true }
flume = { workspace = true }
futures-channel = { workspace = true }
futures-util = { workspace = true }
hashbrown = { workspace = true }
flume = { workspace = true, optional = true }
futures-channel = { workspace = true, optional = true }
futures-util = { workspace = true, optional = true }
hashbrown = { workspace = true, optional = true }
indoc = { workspace = true }
itertools = { workspace = true }
log = { workspace = true }
log = { workspace = true, optional = true }
mutants = { workspace = true }
num-traits = { workspace = true }
ordered-float = { workspace = true }
Expand Down
41 changes: 22 additions & 19 deletions all-is-cubes-mesh/benches/mesh.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
#![allow(missing_docs)]

use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use criterion::{criterion_main, BatchSize, Criterion};

use all_is_cubes::block::{Block, Resolution::R16, AIR};
use all_is_cubes::color_block;
use all_is_cubes::content::make_some_voxel_blocks;
use all_is_cubes::math::{GridAab, Rgba};
use all_is_cubes::space::Space;
use all_is_cubes::time;
use all_is_cubes::universe::{Handle, Name, Universe};
use all_is_cubes_render::camera::{Camera, GraphicsOptions, Viewport};
use all_is_cubes_render::Flaws;

use all_is_cubes_mesh::testing::Allocator;
use all_is_cubes_mesh::testing::TextureMt as Mt;
use all_is_cubes_mesh::{
block_meshes_for_space, dynamic, BlockMesh, BlockMeshes, MeshOptions, SpaceMesh,
};

criterion_group!(
benches,
block_mesh_benches,
space_mesh_benches,
slow_mesh_benches,
dynamic_benches,
);
use all_is_cubes::universe::Universe;
use all_is_cubes_render::camera::GraphicsOptions;

use all_is_cubes_mesh::testing::{Allocator, TextureMt as Mt};
use all_is_cubes_mesh::{block_meshes_for_space, BlockMesh, BlockMeshes, MeshOptions, SpaceMesh};

criterion_main!(benches);
fn benches() {
let mut c = Criterion::default().configure_from_args();
block_mesh_benches(&mut c);
space_mesh_benches(&mut c);
slow_mesh_benches(&mut c);
#[cfg(feature = "dynamic")]
dynamic_benches(&mut c);
}

fn block_mesh_benches(c: &mut Criterion) {
let mut g = c.benchmark_group("block");
Expand Down Expand Up @@ -172,7 +168,14 @@ fn slow_mesh_benches(c: &mut Criterion) {
});
}

#[cfg(feature = "dynamic")]
fn dynamic_benches(c: &mut Criterion) {
use all_is_cubes::time;
use all_is_cubes::universe::{Handle, Name};
use all_is_cubes_mesh::dynamic;
use all_is_cubes_render::camera::{Camera, Viewport};
use all_is_cubes_render::Flaws;

let mut g = c.benchmark_group("dynamic");
let graphics_options = GraphicsOptions::default();
let camera = Camera::new(graphics_options, Viewport::with_scale(1.0, [100, 100]));
Expand Down
2 changes: 2 additions & 0 deletions all-is-cubes-mesh/src/block_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ impl<M: MeshTypes + 'static> BlockMesh<M> {
// chunk meshes. That's implemented but not fully settled yet. Think about whether this should
// be public and whether it should count indices or whole triangles.
// Whatever is decided, also update `MeshMeta::count_indices()`.
#[cfg_attr(not(feature = "dynamic"), allow(dead_code))]
pub(crate) fn count_indices(&self) -> usize {
self.all_face_meshes()
.map(|(_, fm)| fm.indices_opaque.len() + fm.indices_transparent.len())
Expand All @@ -160,6 +161,7 @@ impl<M: MeshTypes + 'static> BlockMesh<M> {
/// Update this mesh's textures in-place to the given new block data, if this is
/// possible without changing the vertices.
// TODO: non-public while we decide whether it's a good interface
#[cfg_attr(not(feature = "dynamic"), allow(dead_code))]
#[must_use]
#[mutants::skip] // optimization, doesn't change things if it fails
pub(crate) fn try_update_texture_only(&mut self, block: &EvaluatedBlock) -> bool {
Expand Down
6 changes: 3 additions & 3 deletions all-is-cubes-mesh/src/block_mesh/viz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use {
all_is_cubes::math::{Cube, GridAab, GridVector},
all_is_cubes::rerun_glue as rg,
alloc::vec::Vec,
core::iter,
itertools::Itertools as _,
};

Expand Down Expand Up @@ -213,11 +214,10 @@ impl Viz {
.mesh_vertex_positions
.extend(vertex_positions.iter().copied());
state.mesh_vertex_colors.extend(
std::iter::repeat(rg::components::Color(color_fn().into()))
.take(vertex_positions.len()),
iter::repeat(rg::components::Color(color_fn().into())).take(vertex_positions.len()),
);
state.mesh_vertex_normals.extend(
std::iter::repeat(rg::components::Vector3D(rg::convert_vec(
iter::repeat(rg::components::Vector3D(rg::convert_vec(
normal.normal_vector::<f32, ()>(),
)))
.take(vertex_positions.len()),
Expand Down
12 changes: 4 additions & 8 deletions all-is-cubes-mesh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,14 @@
//! [`GfxVertex`] and [`texture::Allocator`] traits, then implement [`MeshTypes`] to bundle them
//! together.

// This crate is *almost* `no_std` compatible; the tricky parts are synchronization stuff:
// * the `Mutex` that `chunked_mesh::CsmTodo` uses.
// * the `flume` channels used for background mesh calculation.
// We could address that by exporting `all_is_cubes::util::maybe_sync::Mutex` and using some
// non-Sync channel implementation, but I don't want to do that (and switch hash maps to
// `hashbrown`) until I have some imaginable use case for mesh building on a `no_std` target.
// So for now, the code is just in a state of “reveal how close it is”, hence using `core` and
// `alloc` imports.
#![no_std]
// Crate-specific lint settings. (General settings can be found in the workspace manifest.)
#![forbid(unsafe_code)]
#![cfg_attr(test, allow(clippy::large_stack_arrays))]

extern crate alloc;

#[cfg(any(test, feature = "dynamic"))]
#[macro_use]
extern crate std;

Expand All @@ -48,7 +42,9 @@ mod block_vertex;
pub use block_vertex::*;
mod block_mesh;
pub use block_mesh::*;
#[cfg(feature = "dynamic")]
mod cache;
#[cfg(feature = "dynamic")]
pub mod dynamic;
mod index_vec;
pub use index_vec::*;
Expand Down
6 changes: 3 additions & 3 deletions all-is-cubes-mesh/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use all_is_cubes::space::Space;
use all_is_cubes::util::{ConciseDebug, Fmt};
use all_is_cubes_render::camera::GraphicsOptions;

use crate::dynamic::DynamicMeshTypes;
use crate::{block_meshes_for_space, texture, BlockMeshes, BlockVertex, MeshTypes, SpaceMesh};

/// Generic [`MeshTypes`] implementor for tests to use.
Expand All @@ -30,8 +29,9 @@ where
type Alloc = Alloc;
type Tile = Alloc::Tile;
}
impl<Alloc: texture::Allocator + fmt::Debug + 'static, const MBM: usize> DynamicMeshTypes
for Mt<Alloc, MBM>
#[cfg(feature = "dynamic")]
impl<Alloc: texture::Allocator + fmt::Debug + 'static, const MBM: usize>
crate::dynamic::DynamicMeshTypes for Mt<Alloc, MBM>
where
Alloc::Point: Fmt<ConciseDebug>, // TODO: clunky bound
{
Expand Down

0 comments on commit 8316066

Please sign in to comment.