Fix RNG transmutation
CI / cargo fmt (push) Failing after 12m32s
CI / cargo test (push) Successful in 14m31s
CI / cargo test (GPU) (push) Successful in 12m49s

This commit is contained in:
2026-06-29 20:40:12 -04:00
parent 3c5563c940
commit 86ef0887e3
3 changed files with 42 additions and 8 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ pub fn main() -> Result<()> {
main_chaos_game(
ITERATIONS_DISCARD,
&[4u8],
&[4u8; 32],
&transforms,
&weights,
&variations,
+5 -4
View File
@@ -110,7 +110,7 @@ impl<'a, R: Rng> Iterator for ChaosGame<'a, R> {
/// Shader entry point for running the chaos game to produce new IFS coordinates
pub mod entry {
use crate::chaos_game::ChaosGame;
use crate::rng::xoshiro_from_state;
use crate::rng::xoshiro256starstar_from_seed;
use crate::transform::Transform;
use crate::variation::Variation;
use glam::Vec2;
@@ -121,15 +121,16 @@ pub mod entry {
#[spirv(compute(entry_point_name = "main_chaos_game", threads(1)))]
pub fn main_chaos_game(
#[spirv(spec_constant(id = 1, default = 20))] iteration_discard: u32,
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] _rng_seed: &[u8],
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] rng_seed: &[u8],
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] transforms: &[Transform],
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] weights: &[f32],
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] variations: &[Variation],
#[spirv(storage_buffer, descriptor_set = 1, binding = 0)] output: &mut [Vec2],
) {
let rng_seed_actual = [0u8; 32];
let mut rng_seed_actual = [0u8; 32];
(0..32).for_each(|i| rng_seed_actual[i] = rng_seed[i]);
let mut rng = xoshiro_from_state(rng_seed_actual);
let mut rng = xoshiro256starstar_from_seed(rng_seed_actual);
let mut chaos_game = ChaosGame::new(&mut rng, transforms, weights, variations);
for _ in 0..iteration_discard {
+36 -3
View File
@@ -14,9 +14,42 @@ use rand_xoshiro::Xoshiro256StarStar;
/// This function assumes a properly-initialized state array;
/// output may silently degenerate if the initial state is all zeros,
/// so this module is private to the crate.
pub(crate) fn xoshiro_from_state(
_rng_state: <Xoshiro256StarStar as SeedableRng>::Seed,
pub(crate) fn xoshiro256starstar_from_seed(
rng_state: <Xoshiro256StarStar as SeedableRng>::Seed,
) -> Xoshiro256StarStar {
let rng_state_actual = [1u64, 2u64, 3u64, 4u64];
let mut rng_state_actual = [0u64; 4];
// NOTE: Bit shifting is bad, but we don't have great alternatives:
// - `chunks_exact` has issues with pointer casting
// - `u64::from_le_bytes` has issues with `OpBitcast` in SPIR-V validation
for i in 0..rng_state_actual.len() {
for j in 0..size_of::<u64>() {
rng_state_actual[i] |= (rng_state[i * size_of::<u64>() + j] as u64) << j * 8;
}
}
unsafe { core::mem::transmute(rng_state_actual) }
}
#[cfg(test)]
mod test {
use crate::rng::xoshiro256starstar_from_seed;
use core::iter::zip;
use rand::{RngExt, SeedableRng};
use rand_xoshiro::Xoshiro256StarStar;
#[test]
fn match_seeded() {
let mut seed: <Xoshiro256StarStar as SeedableRng>::Seed = [0u8; 32];
for i in 0..seed.len() {
seed[i] = i as u8;
}
let rng1 = Xoshiro256StarStar::from_seed(seed).random_iter::<u64>();
let rng2 = xoshiro256starstar_from_seed(seed).random_iter::<u64>();
zip(rng1, rng2)
.take(100)
.for_each(|(rng1_value, rng2_value)| assert_eq!(rng1_value, rng2_value));
}
}