From 7102812900baf441a4d38b904548c2a90f785d1c Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 5 Oct 2023 16:38:16 -0700 Subject: [PATCH] optimize for speed --- rust_voxels_game/Cargo.toml | 1 + rust_voxels_game/Makefile | 5 ++- rust_voxels_game/src/console.rs | 9 +++++- rust_voxels_game/src/fixed.rs | 14 ++++----- rust_voxels_game/src/lib.rs | 12 +++++-- rust_voxels_game/src/world.rs | 56 +++++++++++++++++++++++---------- 6 files changed, 69 insertions(+), 28 deletions(-) diff --git a/rust_voxels_game/Cargo.toml b/rust_voxels_game/Cargo.toml index 53f75fc..4c35063 100644 --- a/rust_voxels_game/Cargo.toml +++ b/rust_voxels_game/Cargo.toml @@ -19,6 +19,7 @@ minetest-schematic = { path = "minetest-schematic" } embedded = [] hosted = ["dep:termios", "dep:libc"] default = ["hosted"] +hosted_full_speed = ["hosted"] [profile.release] panic = "abort" diff --git a/rust_voxels_game/Makefile b/rust_voxels_game/Makefile index b01ac3c..c8f17ff 100644 --- a/rust_voxels_game/Makefile +++ b/rust_voxels_game/Makefile @@ -1,4 +1,4 @@ -.PHONY: all run size dump emu clean +.PHONY: all run size dump emu emu_full_speed clean ARCH = $(shell uname -m) ifneq ("$(ARCH)", "ppc64") @@ -47,6 +47,9 @@ rust_voxels_game.hex: rust_voxels_game.bin emu: cargo run --release +emu_full_speed: + cargo run --release --features=hosted_full_speed + clean: cargo clean @rm -f *.o rust_voxels_game.elf rust_voxels_game.bin rust_voxels_game.hex diff --git a/rust_voxels_game/src/console.rs b/rust_voxels_game/src/console.rs index 18f443c..64444d8 100644 --- a/rust_voxels_game/src/console.rs +++ b/rust_voxels_game/src/console.rs @@ -78,7 +78,7 @@ fn console_write(b: u8) { } } -#[cfg(feature = "hosted")] +#[cfg(all(feature = "hosted", not(feature = "hosted_full_speed")))] fn console_write(b: u8) { use core::{ sync::atomic::{AtomicU32, Ordering}, @@ -113,6 +113,13 @@ fn console_write(b: u8) { let _ = std::io::stdout().write_all(&[b]); } +#[cfg(feature = "hosted_full_speed")] +fn console_write(b: u8) { + use std::io::Write; + + let _ = std::io::stdout().write_all(&[b]); +} + pub struct Console(()); impl Console { diff --git a/rust_voxels_game/src/fixed.rs b/rust_voxels_game/src/fixed.rs index fc20794..9b32c98 100644 --- a/rust_voxels_game/src/fixed.rs +++ b/rust_voxels_game/src/fixed.rs @@ -1,8 +1,9 @@ -#[cfg(feature = "hosted")] -use core::fmt; -use core::ops::{ - Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr, - ShrAssign, Sub, SubAssign, +use core::{ + fmt, + ops::{ + Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr, + ShrAssign, Sub, SubAssign, + }, }; macro_rules! impl_assign_op { @@ -21,7 +22,6 @@ macro_rules! impl_assign_op { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct Fix64(i64); -#[cfg(feature = "hosted")] impl fmt::Display for Fix64 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let frac_digits = (Fix64::FRAC_BITS + 3) / 4; @@ -40,7 +40,6 @@ impl fmt::Display for Fix64 { } } -#[cfg(feature = "hosted")] impl fmt::Debug for Fix64 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) @@ -184,6 +183,7 @@ impl_assign_op!(MulAssign::mul_assign => Mul::mul); impl Div for Fix64 { type Output = Self; + #[inline(always)] fn div(self, rhs: Fix64) -> Self::Output { Fix64((((self.0 as i128) << Self::FRAC_BITS) / rhs.0 as i128) as i64) } diff --git a/rust_voxels_game/src/lib.rs b/rust_voxels_game/src/lib.rs index 0f59e9f..5247722 100644 --- a/rust_voxels_game/src/lib.rs +++ b/rust_voxels_game/src/lib.rs @@ -114,8 +114,16 @@ pub extern "C" fn main() -> ! { world.render(screen, pos, forward, right, down); restore_cursor.map(|f| f(world)); screen.display(console); - writeln!(console, "Press WASD to move, IJKL to change look dir, F to move down, R to move up").unwrap(); - writeln!(console, "0-9 to place a block, - to delete a block, ESC to exit.").unwrap(); + writeln!( + console, + "Press WASD to move, IJKL to change look dir, F to move down, R to move up" + ) + .unwrap(); + writeln!( + console, + "0-9 to place a block, - to delete a block, ESC to exit." + ) + .unwrap(); loop { let (prev_pos, hit_pos) = world.get_hit_pos(pos, forward); let mut new_pos = pos; diff --git a/rust_voxels_game/src/world.rs b/rust_voxels_game/src/world.rs index 812e77a..a07eb1b 100644 --- a/rust_voxels_game/src/world.rs +++ b/rust_voxels_game/src/world.rs @@ -24,6 +24,7 @@ pub struct World { pub blocks: [[[Block; Self::SIZE]; Self::SIZE]; Self::SIZE], } +#[derive(Copy, Clone, Debug)] struct RayCastDimension { next_pos: i64, next_t: Fix64, @@ -32,6 +33,18 @@ struct RayCastDimension { } impl RayCastDimension { + const fn at_inf(pos: i64) -> Self { + Self { + next_pos: pos, + next_t: Fix64::from_bits(i64::MAX), + t_step: Fix64::from_int(0), + pos_step: 0, + } + } + const fn is_at_inf(self) -> bool { + self.pos_step == 0 + } + #[inline(always)] fn new(start: Fix64, dir: Fix64) -> Option { let pos_step = dir.signum(); if pos_step == 0 { @@ -259,6 +272,7 @@ impl World { let array_pos = Self::array_pos(pos); self.get_array_mut(array_pos) } + #[inline(always)] pub fn get(&self, pos: Vec3D) -> Option<&Block> { let array_pos = Self::array_pos(pos); self.get_array(array_pos) @@ -271,6 +285,7 @@ impl World { pub fn positions() -> impl Iterator> { Self::array_positions().map(Self::from_array_pos) } + #[inline(never)] fn cast_ray_impl( &self, start: Vec3D, @@ -283,30 +298,37 @@ impl World { }; f(pos, block) }; - let mut pos = start.map(Fix64::floor).into_array(); + let pos = start.map(Fix64::floor); let mut ray_casters = start .zip(dir) - .map(|(start, dir)| RayCastDimension::new(start, dir)) + .zip(pos) + .map( + #[inline(always)] + |((start, dir), pos)| { + RayCastDimension::new(start, dir).unwrap_or(RayCastDimension::at_inf(pos)) + }, + ) .into_array(); + let mut pos = pos.into_array(); + if ray_casters[0].is_at_inf() && ray_casters[1].is_at_inf() && ray_casters[2].is_at_inf() { + return ControlFlow::Break(()); + } loop { f(Vec3D::from_array(pos))?; - let mut min_index = None; - let mut min_t = Fix64::from_bits(i64::MAX); - for (index, ray_caster) in ray_casters.iter().enumerate() { - let Some(ray_caster) = ray_caster else { - continue; + macro_rules! do_step_at_min { + ($ray_casters:ident, $pos:ident, [$index:literal]) => { + $pos[$index] = $ray_casters[$index].next_pos; + $ray_casters[$index].step(); + }; + ($ray_casters:ident, $pos:ident, [$index0:literal, $index1:literal $(, $rest:literal)*]) => { + if $ray_casters[$index1].next_t < $ray_casters[$index0].next_t { + do_step_at_min!($ray_casters, $pos, [$index1 $(, $rest)*]); + } else { + do_step_at_min!($ray_casters, $pos, [$index0 $(, $rest)*]); + } }; - if ray_caster.next_t < min_t { - min_t = ray_caster.next_t; - min_index = Some(index); - } } - let Some(min_index) = min_index else { - return ControlFlow::Break(()); - }; - let ray_caster = ray_casters[min_index].as_mut().unwrap(); - pos[min_index] = ray_caster.next_pos; - ray_caster.step(); + do_step_at_min!(ray_casters, pos, [0, 1, 2]); } } pub fn cast_ray( -- 2.30.2