valadaptive / ntsc-rs

Free, open-source analog TV + VHS effect. Standalone application + plugin (After Effects, Premiere, and OpenFX).
Other
237 stars 4 forks source link

Assertion error in simplex_32 in rust-simd-noise when using ntsc-rs as dependency #71

Closed johnzielke closed 3 months ago

johnzielke commented 3 months ago

I'm trying to develop a python binding for ntsc-rs. (Note: I'm a complete beginner in Rust, so the problem might be very obvious) I already got the plugin to kind of work, but am running into an issue that I can only fix by disabling the edge_wave filter in the vhs settings. For context: The plugin is supposed to work through interop with python numpy to send and receive frames. The relevant part of my code currently looks like this:

use image::RgbImage;
use ntscrs::settings::NtscEffect;
use numpy::ndarray::{Array4, ArrayView4};
use numpy::{IntoPyArray, PyArray4, PyReadonlyArray4};
use pyo3::prelude::*;
use pyo3::{pymodule, types::PyModule, PyResult, Python};
fn ntsc_rs(x: ArrayView4<'_, u8>) -> Array4<u8> {
    let mut output = Array4::<u8>::zeros((x.shape()[0], x.shape()[1], x.shape()[2], x.shape()[3]));
    let mut ntsc_effect = NtscEffect::default();

    // FIXME: Without setting the intensity to 0.0, the apply_effect function will panic
    // Set ntsc_effect.vhs_settings.edge_wave.intensity to 0.0 to disable the effect
    // ntsc_effect.vhs_settings = Some(settings::VHSSettings {
    //     edge_wave: Some(settings::VHSEdgeWaveSettings {
    //         intensity: 0.0,
    //         ..ntsc_effect.vhs_settings.clone().expect("").edge_wave.unwrap()
    //     }),
    //     ..ntsc_effect.vhs_settings.expect("")
    // });
    for i in 0..x.shape()[0] {
        let mut image = RgbImage::from_raw(
            x.shape()[1] as u32,
            x.shape()[2] as u32,
            x.to_owned().into_raw_vec(),
        )
        .unwrap();
        ntsc_effect.apply_effect(&mut image, i as usize);

        for j in 0..x.shape()[1] {
            for k in 0..x.shape()[2] {
                for l in 0..x.shape()[3] {
                    output[[i, j, k, l]] = image.get_pixel(j as u32, k as u32)[l];
                }
            }
        }
    }
    output
}

#[cfg(test)]
mod tests {
    use numpy::ndarray::Array4;

    #[test]
    fn it_works() {
        let image = Array4::<u8>::zeros((3, 400, 400, 3));
        let output = super::ntsc_rs(image.view());
    }
}

Running the test results in the following error, unless I uncomment the code where I disable the edge wave filter:

assertion failed: values.cmp_lt(S::Vi32::set1(PERM.len() as
                    i32)).iter().all(|is_less_than| is_less_than > 0)
thread 'tests::it_works' panicked at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/noise/simplex_32.rs:74:5:
assertion failed: values.cmp_lt(S::Vi32::set1(PERM.len() as
                    i32)).iter().all(|is_less_than| is_less_than > 0)
stack backtrace:
   0: rust_begin_unwind
             at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/panicking.rs:647:5
   1: core::panicking::panic_fmt
             at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/panicking.rs:72:14
   2: core::panicking::panic
             at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/panicking.rs:144:5
   3: simdnoise::noise::simplex_32::assert_in_perm_range
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/noise/simplex_32.rs:74:5
   4: simdnoise::noise::simplex_32::simplex_2d_deriv
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/noise/simplex_32.rs:171:9
   5: simdnoise::noise::simplex_32::simplex_2d
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/noise/simplex_32.rs:135:5
   6: simdnoise::noise::fbm_32::fbm_2d
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/noise/fbm_32.rs:34:22
   7: <simdnoise::settings::fbm_settings::FbmSettings as simdnoise::noise_helpers_32::Sample32<S>>::sample_2d
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/settings/fbm_settings.rs:169:9
   8: simdnoise::noise_helpers_32::get_2d_noise_helper_f32
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/noise_helpers_32.rs:108:21
   9: simdnoise::noise_helpers_32::get_2d_noise
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/noise_helpers_32.rs:321:30
  10: simdnoise::__get_2d_noise_generic::{{closure}}
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/lib.rs:118:9
  11: <simdeez::engines::avx2::simd::Avx2 as simdeez::Simd>::invoke::inner
             at /home/john/.cargo/registry/src/index.crates.io-6f17d22bba15001f/simdeez-2.0.0-dev3/src/engines/avx2/simd.rs:20:13
  12: <simdeez::engines::avx2::simd::Avx2 as simdeez::Simd>::invoke
             at /home/john/.cargo/registry/src/index.crates.io-6f17d22bba15001f/simdeez-2.0.0-dev3/src/engines/avx2/simd.rs:23:18
  13: simdnoise::__get_2d_noise_generic
             at /home/john/.cargo/registry/src/index.crates.io-6f17d22bba15001f/simdeez-2.0.0-dev3/src/invoking.rs:29:17
  14: <simdnoise::__get_2d_noise_dispatch_struct as simdeez::invoking::__SimdRunner<(&simdnoise::noise_type::NoiseType,),(alloc::vec::Vec<f32>,f32,f32)>>::run
             at /home/john/.cargo/registry/src/index.crates.io-6f17d22bba15001f/simdeez-2.0.0-dev3/src/invoking.rs:43:21
  15: simdeez::invoking::__run_simd_runtime_decide
             at /home/john/.cargo/registry/src/index.crates.io-6f17d22bba15001f/simdeez-2.0.0-dev3/src/invoking.rs:166:29
  16: simdnoise::get_2d_noise
             at /home/john/.cargo/registry/src/index.crates.io-6f17d22bba15001f/simdeez-2.0.0-dev3/src/invoking.rs:61:17
  17: <simdnoise::settings::fbm_settings::FbmSettings as simdnoise::settings::Settings>::generate
             at /home/john/.cargo/git/checkouts/rust-simd-noise-0db9e0e49c498d51/84ec75d/src/settings/fbm_settings.rs:116:18
  18: ntscrs::ntsc::vhs_edge_wave
             at /home/john/.cargo/git/checkouts/ntsc-rs-3e518e9b8bfd57d8/6cbb5c6/crates/ntscrs/src/ntsc.rs:907:9
  19: ntscrs::ntsc::<impl ntscrs::settings::NtscEffect>::apply_effect_to_yiq_field
             at /home/john/.cargo/git/checkouts/ntsc-rs-3e518e9b8bfd57d8/6cbb5c6/crates/ntscrs/src/ntsc.rs:1119:21
  20: ntscrs::ntsc::<impl ntscrs::settings::NtscEffect>::apply_effect_to_yiq
             at /home/john/.cargo/git/checkouts/ntsc-rs-3e518e9b8bfd57d8/6cbb5c6/crates/ntscrs/src/ntsc.rs:1208:17
  21: ntscrs::ntsc::<impl ntscrs::settings::NtscEffect>::apply_effect
             at /home/john/.cargo/git/checkouts/ntsc-rs-3e518e9b8bfd57d8/6cbb5c6/crates/ntscrs/src/ntsc.rs:1237:9
  22: ntsc_rs_py::ntsc_rs
             at ./src/lib.rs:32:9
  23: ntsc_rs_py::tests::it_works
             at ./src/lib.rs:66:22
  24: ntsc_rs_py::tests::it_works::{{closure}}
             at ./src/lib.rs:64:18
  25: core::ops::function::FnOnce::call_once
             at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/ops/function.rs:250:5
  26: core::ops::function::FnOnce::call_once
             at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

error: test failed, to rerun pass `-p ntsc-rs-py --lib`
error: 1 target failed:
    `-p ntsc-rs-py --lib`

Do you know why this error happens?

valadaptive commented 3 months ago

I accidentally introduced an off-by-one error into a bounds check in the simdnoise library. I fixed it a while back but apparently forgot to update the version of the library used in ntsc-rs. I just pushed that update; try pulling the latest change and trying again.

(PS: you can use unwrap() instead of expect(""))

johnzielke commented 3 months ago

Thank you very much, that fixed it for me! And thanks for the tip!