use besl::vm::{Buffer, DescriptorBindings, ExecutableProgram, ExecutionConfig, ResourceSlot, Texture, Value};
const TEST_INSTRUCTION_LIMIT: usize = 4_000_000;
const TEST_CALL_DEPTH_LIMIT: usize = 128;
pub(crate) fn compile(main: besl::NodeReference) -> ExecutableProgram {
ExecutableProgram::compile(main).expect(
"Failed to compile a production shader with the BESL VM. The most likely cause is missing VM support for shader syntax.",
)
}
pub(crate) fn texture_2d(width: u32, height: u32, texels: &[[f32; 4]]) -> Texture {
assert_eq!(
texels.len(),
width as usize * height as usize,
"Invalid VM texture fixture. The most likely cause is a texel count that does not match its extent."
);
let mut texture = Texture::new(width, height)
.expect("Failed to create a VM texture. The most likely cause is a zero-sized test fixture.");
for (index, texel) in texels.iter().copied().enumerate() {
let index = index as u32;
texture
.write([index % width, index / width], texel)
.expect("Failed to initialize a VM texture. The most likely cause is an invalid fixture coordinate.");
}
texture
}
pub(crate) fn empty_image(width: u32, height: u32) -> Texture {
Texture::new(width, height).expect("Failed to create a VM image. The most likely cause is a zero-sized test fixture.")
}
pub(crate) fn buffer(program: &ExecutableProgram, slot: ResourceSlot) -> Buffer {
let layout = program
.buffer_layout(slot)
.expect("Missing VM buffer layout. The most likely cause is that the production shader did not retain the expected binding.")
.clone();
Buffer::new(layout)
}
pub(crate) fn run_at(program: &ExecutableProgram, descriptors: &mut DescriptorBindings<'_>, thread_id: [u32; 2]) {
let config = ExecutionConfig::new(TEST_INSTRUCTION_LIMIT)
.with_call_depth_limit(TEST_CALL_DEPTH_LIMIT)
.with_thread_id(thread_id);
program.run_main_with_config(descriptors, &config).expect(
"Failed to execute a production shader with the BESL VM. The most likely cause is missing runtime support or an invalid fixture binding.",
);
}
pub(crate) fn rgba(texture: &Texture, coordinate: [u32; 2]) -> [f32; 4] {
match texture
.fetch(coordinate)
.expect("Failed to read a VM texel. The most likely cause is an out-of-bounds assertion coordinate.")
{
Value::Vec4F(value) => value,
_ => panic!("Unexpected VM texel type. The most likely cause is reading an integer image as float RGBA."),
}
}
pub(crate) fn assert_rgba_close(actual: [f32; 4], expected: [f32; 4], tolerance: f32) {
for (channel, (actual, expected)) in actual.into_iter().zip(expected).enumerate() {
assert!(
actual.is_finite() && (actual - expected).abs() <= tolerance,
"Unexpected VM shader output in channel {channel}: expected {expected}, found {actual}. The most likely cause is a shader regression or incorrect VM semantics."
);
}
}