diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f4d3e4b..82ee76f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -13,7 +13,7 @@ jobs: test: name: Test Suite runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 10 strategy: matrix: crate: ['bevy_gpu_compute_macro', 'bevy_gpu_compute_core', 'bevy_gpu_compute'] @@ -41,7 +41,7 @@ jobs: clippy_check: name: Clippy runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 10 strategy: matrix: crate: ['bevy_gpu_compute_macro', 'bevy_gpu_compute_core', 'bevy_gpu_compute'] @@ -71,7 +71,7 @@ jobs: format: name: Format runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 5 strategy: matrix: crate: ['bevy_gpu_compute_macro', 'bevy_gpu_compute_core', 'bevy_gpu_compute'] @@ -84,4 +84,32 @@ jobs: components: rustfmt - name: Run cargo fmt run: cargo fmt -- --check - working-directory: ${{ matrix.crate }} \ No newline at end of file + working-directory: ${{ matrix.crate }} + + # examples: + # name: Run examples + # runs-on: ubuntu-latest + # timeout-minutes: 10 + # strategy: + # matrix: + # example: ['collision_detection_demonstration'] + # steps: + # - name: Checkout sources + # uses: actions/checkout@v4 + # - name: Cache + # uses: actions/cache@v4 + # with: + # path: | + # ~/.cargo/bin/ + # ~/.cargo/registry/index/ + # ~/.cargo/registry/cache/ + # ~/.cargo/git/db/ + # target/ + # key: ${{ runner.os }}-cargo-example-bevy_gpu_compute-${{ hashFiles('**/Cargo.toml') }} + # - name: Install nightly toolchain + # uses: dtolnay/rust-toolchain@nightly + # - name: Install Dependencies + # run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev + # - name: Run cargo examples + # run: cargo run --example ${{ matrix.example }} + # working-directory: bevy_gpu_compute \ No newline at end of file diff --git a/bevy_gpu_compute/examples/collision_detection_barebones/main.rs b/bevy_gpu_compute/examples/collision_detection_barebones/main.rs index fc27971..132f770 100644 --- a/bevy_gpu_compute/examples/collision_detection_barebones/main.rs +++ b/bevy_gpu_compute/examples/collision_detection_barebones/main.rs @@ -26,16 +26,20 @@ fn main() { .add_systems(Update, (handle_task_results, exit_and_show_results).chain()) .run(); } - +// constants used to produce predictable collision results const SPAWN_RANGE_MIN: i32 = -2; const SPAWN_RANGE_MAX: i32 = 2; const ENTITY_RADIUS: f32 = 1.1; -const EXIT_AFTER_FRAMES: u32 = 2; +const EXIT_AFTER_FRAMES: u32 = 3; +// expected results +const EXPECTED_NUM_ENTITIES: u32 = 16; +// 16 entities 100% intersecting should produce 120 collisions +const EXPECTED_COLLISIONS_PER_FRAME: usize = 58; #[derive(Resource, Default)] struct State { pub num_entities: u32, - pub collision_count: usize, + pub collisions_per_frame: Vec, } #[wgsl_shader_module] @@ -75,7 +79,7 @@ mod collision_detection_module { let current_pos = WgslVecInput::vec_val::(current_entity); let other_pos = WgslVecInput::vec_val::(other_entity); let dist_squared = calculate_distance_squared(current_pos.v, other_pos.v); - let radius_sum = (current_radius + other_radius); + let radius_sum = current_radius + other_radius; let rad_sum_sq = radius_sum * radius_sum; let is_collision = dist_squared < rad_sum_sq; if is_collision { @@ -141,15 +145,18 @@ fn handle_task_results(mut gpu_task_reader: GpuTaskReader, mut state: ResMut, state: Res, mut exit: EventWriter) { if *count > EXIT_AFTER_FRAMES { - log::info!("collisions count: {}", state.collision_count); + let total_collisions = state.collisions_per_frame.iter().sum::(); + log::trace!("total collisions count at exit: {}", total_collisions); + log::info!("Example completed successfully"); exit.send(AppExit::Success); } *count += 1; diff --git a/bevy_gpu_compute/examples/collision_detection_barebones/visuals.rs b/bevy_gpu_compute/examples/collision_detection_barebones/visuals.rs index edd0f7b..e28d8d0 100644 --- a/bevy_gpu_compute/examples/collision_detection_barebones/visuals.rs +++ b/bevy_gpu_compute/examples/collision_detection_barebones/visuals.rs @@ -13,7 +13,7 @@ use bevy::{ utils::default, }; -use crate::{ENTITY_RADIUS, SPAWN_RANGE_MAX, SPAWN_RANGE_MIN, State}; +use crate::{ENTITY_RADIUS, EXPECTED_NUM_ENTITIES, SPAWN_RANGE_MAX, SPAWN_RANGE_MIN, State}; #[derive(Debug, Component)] pub struct BoundingCircleComponent(pub BoundingCircle); @@ -46,6 +46,7 @@ pub fn spawn_entities( } } log::info!("total of {} entities spawned", count); + assert!(count == EXPECTED_NUM_ENTITIES); state.num_entities = count; } diff --git a/bevy_gpu_compute/examples/collision_detection_demonstration/main.rs b/bevy_gpu_compute/examples/collision_detection_demonstration/main.rs index ed7e3c3..9056586 100644 --- a/bevy_gpu_compute/examples/collision_detection_demonstration/main.rs +++ b/bevy_gpu_compute/examples/collision_detection_demonstration/main.rs @@ -4,8 +4,8 @@ Demonstrates all features of the BevyGpuCompute library use bevy::{ DefaultPlugins, - app::{App, AppExit, Startup, Update}, - log, + app::{App, AppExit, PluginGroup, Startup, Update}, + log::{self, LogPlugin}, prelude::{EventWriter, IntoSystemConfigs, Local, Query, Res, ResMut, Resource}, }; use bevy_gpu_compute::prelude::*; @@ -15,7 +15,10 @@ use visuals::{BoundingCircleComponent, ColorHandles, spawn_camera, spawn_entitie fn main() { let mut binding = App::new(); let _app = binding - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(LogPlugin { + level: log::Level::INFO, + ..Default::default() + })) .add_plugins(BevyGpuComputePlugin::default()) .init_resource::() .init_resource::() @@ -28,15 +31,25 @@ fn main() { .run(); } +// constants used to produce predictable collision results const SPAWN_RANGE_MIN: i32 = -2; const SPAWN_RANGE_MAX: i32 = 2; -const ENTITY_RADIUS: f32 = 1.1; -const EXIT_AFTER_FRAMES: u32 = 2; +const ENTITY_RADIUS: f32 = 100.1; +const RADIUS_MULTIPLIER_FRAME_0: f32 = 1.0; +const RADIUS_MULTIPLIER_FRAME_1: f32 = 0.01; +const RADIUS_MULTIPLIER_FRAME_2: f32 = 0.002; +const EXIT_AFTER_FRAMES: u32 = 3; +// expected results +const EXPECTED_NUM_ENTITIES: u32 = 16; +// 16 entities 100% intersecting should produce 120 collisions +const EXPECTED_COLLISIONS_FRAME_0: usize = 120; +const EXPECTED_COLLISIONS_FRAME_1: usize = 58; +const EXPECTED_COLLISIONS_FRAME_2: usize = 0; #[derive(Resource, Default)] struct State { pub num_entities: u32, - pub collision_count: usize, + pub collisions_per_frame: Vec, } #[wgsl_shader_module] @@ -161,13 +174,13 @@ fn modify_task(mut gpu_tasks: GpuTaskRunner, state: Res) { gpu_tasks.run_commands(pending_commands); } fn modify_task_config_inputs(mut count: Local, mut gpu_tasks: GpuTaskRunner) { - let radius_multiplier = - (EXIT_AFTER_FRAMES as i32 - *count as i32) as f32 / EXIT_AFTER_FRAMES as f32; - log::info!("rad_mult: {}", radius_multiplier); - // below needs to simplify - // let mut config = ConfigInputData::::empty(); - // config.set_input0(collision_detection_module::Config { radius_multiplier }); - + let radius_multiplier = if *count <= 0 { + RADIUS_MULTIPLIER_FRAME_0 + } else if *count == 1 { + RADIUS_MULTIPLIER_FRAME_1 + } else { + RADIUS_MULTIPLIER_FRAME_2 + }; let configs = collision_detection_module::ConfigInputDataBuilder::new() .set_config(collision_detection_module::Config { radius_multiplier }) .finish(); @@ -202,25 +215,42 @@ fn handle_task_results(mut gpu_task_reader: GpuTaskReader, mut state: ResMut("collision_detection"); - // log::info!("results: {:?}", results);c if let Ok(results) = results { #[allow(unused_variables)] let debug_results = results.my_debug_info.unwrap(); - // log::info!("debug results: {:?}", debug_results); + log::debug!("debug results: {:?}", debug_results); //fully type-safe results let collision_results = results.collision_result.unwrap(); // your logic here let count = collision_results.len(); log::info!("collisions this frame: {}", count); - log::info!("collision_results: {:?}", collision_results); - state.collision_count += count; + log::trace!("collision_results: {:?}", collision_results); + state.collisions_per_frame.push(count); } } // when the local variable "count" goes above a certain number (representing frame count), exit the app fn exit_and_show_results(mut count: Local, state: Res, mut exit: EventWriter) { if *count > EXIT_AFTER_FRAMES { - log::info!("collisions count: {}", state.collision_count); + let total_collisions = state.collisions_per_frame.iter().sum::(); + log::trace!("total collisions count at exit: {}", total_collisions); + // verify results are what we expect + assert_eq!( + state.collisions_per_frame[0], EXPECTED_COLLISIONS_FRAME_0, + "unexpected collision count for frame 0: {}", + state.collisions_per_frame[0] + ); + assert_eq!( + state.collisions_per_frame[1], EXPECTED_COLLISIONS_FRAME_1, + "unexpected collision count for frame 1: {}", + state.collisions_per_frame[1] + ); + assert_eq!( + state.collisions_per_frame[2], EXPECTED_COLLISIONS_FRAME_2, + "unexpected collision count for frame 2: {}", + state.collisions_per_frame[2] + ); + log::info!("Example completed successfully"); exit.send(AppExit::Success); } *count += 1; diff --git a/bevy_gpu_compute/examples/collision_detection_demonstration/visuals.rs b/bevy_gpu_compute/examples/collision_detection_demonstration/visuals.rs index edd0f7b..e28d8d0 100644 --- a/bevy_gpu_compute/examples/collision_detection_demonstration/visuals.rs +++ b/bevy_gpu_compute/examples/collision_detection_demonstration/visuals.rs @@ -13,7 +13,7 @@ use bevy::{ utils::default, }; -use crate::{ENTITY_RADIUS, SPAWN_RANGE_MAX, SPAWN_RANGE_MIN, State}; +use crate::{ENTITY_RADIUS, EXPECTED_NUM_ENTITIES, SPAWN_RANGE_MAX, SPAWN_RANGE_MIN, State}; #[derive(Debug, Component)] pub struct BoundingCircleComponent(pub BoundingCircle); @@ -46,6 +46,7 @@ pub fn spawn_entities( } } log::info!("total of {} entities spawned", count); + assert!(count == EXPECTED_NUM_ENTITIES); state.num_entities = count; } diff --git a/bevy_gpu_compute/src/spawn_fallback_camera.rs b/bevy_gpu_compute/src/spawn_fallback_camera.rs index 7985aca..eed7df8 100644 --- a/bevy_gpu_compute/src/spawn_fallback_camera.rs +++ b/bevy_gpu_compute/src/spawn_fallback_camera.rs @@ -21,7 +21,7 @@ pub fn spawn_fallback_camera( let len = cameras.iter().len(); match len { 0 => { - log::info!( + log::debug!( "GPU Compute: Spawning fallback camera in order to improve gpu performance." ); commands.spawn(( @@ -42,7 +42,7 @@ pub fn spawn_fallback_camera( // do nothing } _ => { - log::info!("GPU Compute: Despawning extra fallback cameras."); + log::trace!("GPU Compute: Despawning extra fallback cameras."); let fallback_cam_len = fallback_cameras.iter().len(); if fallback_cam_len > 0 { fallback_cameras.iter().for_each(|(e, _)| { diff --git a/bevy_gpu_compute/src/system_params/task_runner.rs b/bevy_gpu_compute/src/system_params/task_runner.rs index 3e91116..512291e 100644 --- a/bevy_gpu_compute/src/system_params/task_runner.rs +++ b/bevy_gpu_compute/src/system_params/task_runner.rs @@ -54,7 +54,7 @@ impl GpuTaskRunner<'_, '_> { .expect("Task entity not found"); let mut should_recompute_memory = false; for cmd in commands.commands { - log::info!("Running command: {}", cmd); + log::trace!("Running command: {}", cmd); match cmd { GpuTaskCommand::SetConfigInputs(inputs) => { task.current_data_mut().set_config_input(*inputs); diff --git a/bevy_gpu_compute/src/task/buffers/create_config_input_buffers.rs b/bevy_gpu_compute/src/task/buffers/create_config_input_buffers.rs index 61cf83d..248ce73 100644 --- a/bevy_gpu_compute/src/task/buffers/create_config_input_buffers.rs +++ b/bevy_gpu_compute/src/task/buffers/create_config_input_buffers.rs @@ -1,5 +1,5 @@ use bevy::{ - log::{self, info}, + log::{self}, render::renderer::RenderDevice, }; use wgpu::{BufferUsages, util::BufferInitDescriptor}; @@ -7,7 +7,7 @@ use wgpu::{BufferUsages, util::BufferInitDescriptor}; use crate::task::lib::BevyGpuComputeTask; pub fn update_config_input_buffers(task: &mut BevyGpuComputeTask, render_device: &RenderDevice) { - log::info!("Creating config input buffers for task {}", task.name()); + log::trace!("Creating config input buffers for task {}", task.name()); task.buffers_mut().config.clear(); let mut new_buffers = Vec::new(); for s in task.configuration().inputs().configs().iter() { @@ -23,7 +23,7 @@ pub fn update_config_input_buffers(task: &mut BevyGpuComputeTask, render_device: .unwrap(), usage: BufferUsages::UNIFORM, }); - info!( + log::trace!( "Created config input buffer for task {} with label {}", task.name(), label diff --git a/bevy_gpu_compute/src/task/buffers/create_input_buffers.rs b/bevy_gpu_compute/src/task/buffers/create_input_buffers.rs index 2d2e86c..e1d2b3c 100644 --- a/bevy_gpu_compute/src/task/buffers/create_input_buffers.rs +++ b/bevy_gpu_compute/src/task/buffers/create_input_buffers.rs @@ -1,4 +1,7 @@ -use bevy::{log::info, render::renderer::RenderDevice}; +use bevy::{ + log::{self}, + render::renderer::RenderDevice, +}; use wgpu::{BufferUsages, util::BufferInitDescriptor}; use crate::task::lib::BevyGpuComputeTask; @@ -20,7 +23,7 @@ pub fn update_input_buffers(task: &mut BevyGpuComputeTask, render_device: &Rende usage: BufferUsages::STORAGE | BufferUsages::COPY_DST, }); new_buffers.push(buffer); - info!( + log::trace!( "Created input buffer for task {} with label {}", task.name(), label diff --git a/bevy_gpu_compute/src/task/compute_pipeline/update_on_pipeline_const_change.rs b/bevy_gpu_compute/src/task/compute_pipeline/update_on_pipeline_const_change.rs index 10f8f53..20e3f78 100644 --- a/bevy_gpu_compute/src/task/compute_pipeline/update_on_pipeline_const_change.rs +++ b/bevy_gpu_compute/src/task/compute_pipeline/update_on_pipeline_const_change.rs @@ -10,7 +10,7 @@ pub fn update_compute_pipeline(task: &mut BevyGpuComputeTask, render_device: &Re if task.current_data().input_lengths().is_none() { return; } - log::info!("Updating pipeline for task {}", task.name()); + log::trace!("Updating pipeline for task {}", task.name()); let key = PipelineKey { pipeline_consts_version: task.configuration().version(), }; @@ -21,8 +21,11 @@ pub fn update_compute_pipeline(task: &mut BevyGpuComputeTask, render_device: &Re .contains_key(&key) { } else { - log::info!("Creating new pipeline for task {}", task.name()); - log::info!(" layout {:?}", task.runtime_state().pipeline_layout()); + log::trace!("Creating new pipeline for task {}", task.name()); + log::trace!( + "pipeline layout {:?}", + task.runtime_state().pipeline_layout() + ); let compute_pipeline = render_device.create_compute_pipeline(&ComputePipelineDescriptor { label: Some(task.name()), layout: Some(task.runtime_state().pipeline_layout()), diff --git a/bevy_gpu_compute/src/task/dispatch/create_bind_group.rs b/bevy_gpu_compute/src/task/dispatch/create_bind_group.rs index 5b56bfc..08723aa 100644 --- a/bevy_gpu_compute/src/task/dispatch/create_bind_group.rs +++ b/bevy_gpu_compute/src/task/dispatch/create_bind_group.rs @@ -19,7 +19,7 @@ For example, this might be the wgsl code: The numbers in the `@binding` are the bind group entry numbers. The `@group` is the bind group number. We are only using a single bind group in the current library version. */ pub fn create_bind_group(task: &mut BevyGpuComputeTask, render_device: &RenderDevice) { - log::info!("Creating bind group for task {}", task.name()); + log::trace!("Creating bind group for task {}", task.name()); let mut bindings = Vec::new(); for (i, s) in task.configuration().inputs().configs().iter().enumerate() { if let Some(conf_in_buff) = task.buffers().config.get(i) { diff --git a/bevy_gpu_compute/src/task/lib.rs b/bevy_gpu_compute/src/task/lib.rs index 3689e56..2dcdcda 100644 --- a/bevy_gpu_compute/src/task/lib.rs +++ b/bevy_gpu_compute/src/task/lib.rs @@ -73,8 +73,8 @@ impl BevyGpuComputeTask { max_output_vector_lengths: MaxOutputLengths, ) -> Self { let full_module = WgslShaderModule::new(wgsl_shader_module); - log::info!( - "wgsl: {}", + log::debug!( + "generated wgsl code : {}", full_module.wgsl_code(iteration_space.num_dimmensions()) ); Self::create_manually::( @@ -164,7 +164,7 @@ impl BevyGpuComputeTask { .unwrap() .get(metadata.name.name()); let name = metadata.name.input_array_length(); - log::info!("input_array_lengths = {:?}, for {}", length, name); + log::debug!("input_array_lengths = {:?}, for {}", length, name); assert!( length.is_some(), "input_array_lengths not set for input array {}, {}", @@ -182,7 +182,7 @@ impl BevyGpuComputeTask { .get_by_name(&metadata.name) as f64, ); } - log::info!("pipeline consts = {:?}", n); + log::debug!("pipeline consts = {:?}", n); n } diff --git a/bevy_gpu_compute/src/task/outputs/helpers/get_gpu_output_counter_value.rs b/bevy_gpu_compute/src/task/outputs/helpers/get_gpu_output_counter_value.rs index 8e762c0..aeac2b8 100644 --- a/bevy_gpu_compute/src/task/outputs/helpers/get_gpu_output_counter_value.rs +++ b/bevy_gpu_compute/src/task/outputs/helpers/get_gpu_output_counter_value.rs @@ -14,7 +14,7 @@ pub fn get_gpu_output_counter_value( staging_buffer: &Buffer, total_byte_size: u64, ) -> Option { - log::info!("Reading GPU output counter value"); + log::trace!("Reading GPU output counter value"); let mut encoder = render_device.create_command_encoder(&Default::default()); encoder.copy_buffer_to_buffer(output_buffer, 0, staging_buffer, 0, total_byte_size); render_queue.submit(std::iter::once(encoder.finish())); @@ -25,19 +25,16 @@ pub fn get_gpu_output_counter_value( sender.send(result).unwrap(); }); render_device.poll(wgpu::Maintain::Wait); - log::info!("Reading GPU output counter value - waiting for map to complete"); let result = if receiver.block_on().unwrap().is_ok() { let data = slice.get_mapped_range(); let transformed_data = &*data; - log::info!("Raw counter value: {:?}", transformed_data); + log::trace!("Raw counter value: {:?}", transformed_data); if transformed_data.len() != std::mem::size_of::() { return None; } let result = Some(bytemuck::pod_read_unaligned(transformed_data)); drop(data); - log::info!("Reading GPU output counter value - map completed"); staging_buffer.unmap(); - log::info!("Reading GPU output counter value - unmap staging completed"); result } else { None @@ -47,6 +44,6 @@ pub fn get_gpu_output_counter_value( encoder2.clear_buffer(output_buffer, 0, None); render_queue.submit(std::iter::once(encoder2.finish())); - log::info!("Gpu counter result: {:?}", result); + log::trace!("Gpu counter result: {:?}", result); result } diff --git a/bevy_gpu_compute/src/task/outputs/read_gpu_output_counts.rs b/bevy_gpu_compute/src/task/outputs/read_gpu_output_counts.rs index 5250187..120937f 100644 --- a/bevy_gpu_compute/src/task/outputs/read_gpu_output_counts.rs +++ b/bevy_gpu_compute/src/task/outputs/read_gpu_output_counts.rs @@ -26,7 +26,7 @@ pub fn read_gpu_output_counts( .enumerate() .for_each(|(i, metadata)| { if metadata.include_count { - log::info!("Reading count for output {}", i); + log::trace!("Reading count for output {}", i); let count = read_gpu_output_counts_single_output_type( render_device, render_queue, @@ -55,6 +55,6 @@ fn read_gpu_output_counts_single_output_type( std::mem::size_of::() as u64, ); let r = count.unwrap().count; - log::info!("Read count: {}", r); + log::debug!("Read length of output vec on gpu: {}", r); r } diff --git a/bevy_gpu_compute/src/task/outputs/read_gpu_task_outputs.rs b/bevy_gpu_compute/src/task/outputs/read_gpu_task_outputs.rs index 0287d51..1672ae7 100644 --- a/bevy_gpu_compute/src/task/outputs/read_gpu_task_outputs.rs +++ b/bevy_gpu_compute/src/task/outputs/read_gpu_task_outputs.rs @@ -32,7 +32,7 @@ pub fn read_gpu_outputs( let total_byte_size = min( if let Some(Some(c)) = output_counts.get(i) { let size = c * metadata.bytes; - log::info!("using output count to size buffer, size: {}", size); + log::trace!("using output count to size buffer, size: {}", size); size } else { usize::MAX @@ -43,7 +43,7 @@ pub fn read_gpu_outputs( .get_by_name(&metadata.name) * metadata.bytes, ); - log::info!("total_byte_size: {}", total_byte_size); + log::trace!("total_byte_size: {}", total_byte_size); if total_byte_size < 1 { bytes_per_wgsl_output_type_name .insert(metadata.name.name().to_string(), Vec::new()); @@ -55,7 +55,6 @@ pub fn read_gpu_outputs( staging_buffer, total_byte_size as u64, ); - // log::info!("raw_bytes: {:?}", raw_bytes); if let Some(raw_bytes) = raw_bytes { bytes_per_wgsl_output_type_name .insert(metadata.name.name().to_string(), raw_bytes); diff --git a/bevy_gpu_compute/src/task/task_components/runtime_state/lib.rs b/bevy_gpu_compute/src/task/task_components/runtime_state/lib.rs index 12766b7..dcc8c84 100644 --- a/bevy_gpu_compute/src/task/task_components/runtime_state/lib.rs +++ b/bevy_gpu_compute/src/task/task_components/runtime_state/lib.rs @@ -183,9 +183,7 @@ impl<'a> TaskRuntimeStateBuilder<'a> { )); } }); - log::info!("Layouts: {:?}", layouts); - // Create bind group layout once - + log::debug!("Bind group layouts: {:?}", layouts); self.render_device .create_bind_group_layout(Some(self.task_name), &layouts) } diff --git a/bevy_gpu_compute/src/task/verify_enough_memory.rs b/bevy_gpu_compute/src/task/verify_enough_memory.rs index 7e587db..2ea6aa4 100644 --- a/bevy_gpu_compute/src/task/verify_enough_memory.rs +++ b/bevy_gpu_compute/src/task/verify_enough_memory.rs @@ -10,15 +10,12 @@ pub fn verify_have_enough_memory(tasks: &Vec<&BevyGpuComputeTask>, ram_limit: &R }); let available_memory = ram_limit.total_mem; if total_bytes as f32 > available_memory as f32 * 0.9 { - log::error!("Not enough memory to store all gpu compute task outputs"); - log::info!( - "Available memory: {} GB", - available_memory as f32 / 1024.0 / 1024.0 / 1024.0 - ); - log::info!( - "Max Output size: {} GB", + log::error!( + "Not enough memory to store all gpu compute task outputs. Available memory: {} GB, Max Output size: {} GB", + available_memory as f32 / 1024.0 / 1024.0 / 1024.0, total_bytes as f32 / 1024.0 / 1024.0 / 1024.0 ); + panic!("Not enough memory to store all gpu compute task outputs"); } } diff --git a/bevy_gpu_compute_core.code-workspace b/bevy_gpu_compute_core.code-workspace index 28db01d..d04662e 100644 --- a/bevy_gpu_compute_core.code-workspace +++ b/bevy_gpu_compute_core.code-workspace @@ -1,10 +1,7 @@ { "folders": [ - { - "path": "bevy_gpu_compute_core" - }, - { - "path": "bevy_gpu_compute_macro" - } -] + { + "path": "bevy_gpu_compute_macro" + } + ] } diff --git a/bevy_gpu_compute_core/src/wgsl/shader_module/derived_portion.rs b/bevy_gpu_compute_core/src/wgsl/shader_module/derived_portion.rs index 8de42dc..55e9d3b 100644 --- a/bevy_gpu_compute_core/src/wgsl/shader_module/derived_portion.rs +++ b/bevy_gpu_compute_core/src/wgsl/shader_module/derived_portion.rs @@ -93,14 +93,7 @@ mod tests { #[test] fn test_wgsl_shader_module_library_portion_from_user_portion() { - let user_portion = WgslShaderModuleUserPortion { static_consts: vec![WgslConstAssignment { code: WgslShaderModuleSectionCode { rust_code: "const example_module_const : u32 = 42;".to_string(), - wgsl_code: "const example_module_const : u32 = 42;".to_string() } }], helper_types: vec![], uniforms: vec![WgslType { name: ShaderCustomTypeName::new("Uniforms"), code: WgslShaderModuleSectionCode { rust_code: "#[wgsl_config] struct Uniforms { time : f32, resolution : Vec2F32, }".to_string(), - wgsl_code: "struct Uniforms { time : f32, resolution : vec2 < f32 > , }".to_string() } }], input_arrays: vec![WgslInputArray { item_type: WgslType { name: ShaderCustomTypeName::new("Position"), code: WgslShaderModuleSectionCode { rust_code: "#[wgsl_input_array] type Position = [f32; 2];".to_string(), - wgsl_code: "alias Position = array < f32, 2 > ;".to_string() } } }, WgslInputArray { item_type: WgslType { name: ShaderCustomTypeName::new("Radius") , code: WgslShaderModuleSectionCode { rust_code: "#[wgsl_input_array] type Radius = f32;".to_string(), - wgsl_code: "alias Radius = f32;".to_string() } }}], output_arrays: vec![WgslOutputArray { item_type: WgslType { name: ShaderCustomTypeName::new("CollisionResult"), code: WgslShaderModuleSectionCode { rust_code: "#[wgsl_output_vec] struct CollisionResult { entity1 : u32, entity2 : u32, }".to_string(), - wgsl_code: "struct CollisionResult { entity1 : u32, entity2 : u32, }".to_string() } }, atomic_counter_name: Some("collisionresult_counter".to_string()) }], helper_functions: vec![WgslFunction { name: "calculate_distance_squared".to_string(), code: WgslShaderModuleSectionCode { rust_code: "fn calculate_distance_squared(p1 : [f32; 2], p2 : [f32; 2]) -> f32\n{\n let dx = p1 [0] - p2 [0]; let dy = p1 [1] - p2 [1]; return dx * dx + dy *\n dy;\n}".to_string(), - wgsl_code: "fn calculate_distance_squared(p1 : array < f32, 2 > , p2 : array < f32, 2 >)\n-> f32\n{\n let dx = p1 [0] - p2 [0]; let dy = p1 [1] - p2 [1]; return dx * dx + dy *\n dy;\n}".to_string() } }], main_function: Some(WgslFunction { name: "main".to_owned(), code: WgslShaderModuleSectionCode { rust_code: "fn main(iter_pos : WgslIterationPosition)\n{\n let current_entity = iter_pos.x; let other_entity = iter_pos.y; if\n current_entity >= POSITION_INPUT_ARRAY_LENGTH || other_entity >=\n POSITION_INPUT_ARRAY_LENGTH || current_entity == other_entity ||\n current_entity >= other_entity { return; } let current_radius =\n radius_input_array [current_entity]; let other_radius = radius_input_array\n [other_entity]; if current_radius <= 0.0 || other_radius <= 0.0\n { return; } let current_pos = position_input_array [current_entity]; let\n other_pos = position_input_array [other_entity]; let dist_squared =\n calculate_distance_squared(current_pos, other_pos); let radius_sum =\n current_radius + other_radius; if dist_squared < radius_sum * radius_sum\n {\n {\n let collisionresult_output_array_index =\n atomicAdd(& collisionresult_counter, 1u); if\n collisionresult_output_array_index <\n COLLISIONRESULT_OUTPUT_ARRAY_LENGTH\n {\n collisionresult_output_array\n [collisionresult_output_array_index] = CollisionResult\n { entity1 : current_entity, entity2 : other_entity, };\n }\n };\n }\n}".to_owned(), - wgsl_code: "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{\n let current_entity = iter_pos.x; let other_entity = iter_pos.y; if\n current_entity >= POSITION_INPUT_ARRAY_LENGTH || other_entity >=\n POSITION_INPUT_ARRAY_LENGTH || current_entity == other_entity ||\n current_entity >= other_entity { return; } let current_radius =\n radius_input_array [current_entity]; let other_radius = radius_input_array\n [other_entity]; if current_radius <= 0.0 || other_radius <= 0.0\n { return; } let current_pos = position_input_array [current_entity]; let\n other_pos = position_input_array [other_entity]; let dist_squared =\n calculate_distance_squared(current_pos, other_pos); let radius_sum =\n current_radius + other_radius; if dist_squared < radius_sum * radius_sum\n {\n {\n let collisionresult_output_array_index =\n atomicAdd(& collisionresult_counter, 1u); if\n collisionresult_output_array_index <\n COLLISIONRESULT_OUTPUT_ARRAY_LENGTH\n {\n collisionresult_output_array\n [collisionresult_output_array_index] = CollisionResult\n { entity1 : current_entity, entity2 : other_entity, };\n }\n };\n }\n}".to_owned() } }), binding_numbers_by_variable_name: Some(HashMap::from([(String::from("uniforms"), 0), (String::from("position_input_array"), 1), (String::from("radius_input_array"), 2), (String::from("collisionresult_output_array"), 3), (String::from("collisionresult_counter"), 4)])) + let user_portion = WgslShaderModuleUserPortion { static_consts: vec![WgslConstAssignment { code: WgslShaderModuleSectionCode { wgsl_code: "const example_module_const : u32 = 42;".to_string() } }], helper_types: vec![], uniforms: vec![WgslType { name: ShaderCustomTypeName::new("Uniforms"), code: WgslShaderModuleSectionCode { wgsl_code: "struct Uniforms { time : f32, resolution : vec2 < f32 > , }".to_string() } }], input_arrays: vec![WgslInputArray { item_type: WgslType { name: ShaderCustomTypeName::new("Position"), code: WgslShaderModuleSectionCode { wgsl_code: "alias Position = array < f32, 2 > ;".to_string() } } }, WgslInputArray { item_type: WgslType { name: ShaderCustomTypeName::new("Radius") , code: WgslShaderModuleSectionCode { wgsl_code: "alias Radius = f32;".to_string() } }}], output_arrays: vec![WgslOutputArray { item_type: WgslType { name: ShaderCustomTypeName::new("CollisionResult"), code: WgslShaderModuleSectionCode { wgsl_code: "struct CollisionResult { entity1 : u32, entity2 : u32, }".to_string() } }, atomic_counter_name: Some("collisionresult_counter".to_string()) }], helper_functions: vec![WgslFunction { name: "calculate_distance_squared".to_string(), code: WgslShaderModuleSectionCode { wgsl_code: "fn calculate_distance_squared(p1 : array < f32, 2 > , p2 : array < f32, 2 >)\n-> f32\n{\n let dx = p1 [0] - p2 [0]; let dy = p1 [1] - p2 [1]; return dx * dx + dy *\n dy;\n}".to_string() } }], main_function: Some(WgslFunction { name: "main".to_owned(), code: WgslShaderModuleSectionCode { wgsl_code: "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{\n let current_entity = iter_pos.x; let other_entity = iter_pos.y; if\n current_entity >= POSITION_INPUT_ARRAY_LENGTH || other_entity >=\n POSITION_INPUT_ARRAY_LENGTH || current_entity == other_entity ||\n current_entity >= other_entity { return; } let current_radius =\n radius_input_array [current_entity]; let other_radius = radius_input_array\n [other_entity]; if current_radius <= 0.0 || other_radius <= 0.0\n { return; } let current_pos = position_input_array [current_entity]; let\n other_pos = position_input_array [other_entity]; let dist_squared =\n calculate_distance_squared(current_pos, other_pos); let radius_sum =\n current_radius + other_radius; if dist_squared < radius_sum * radius_sum\n {\n {\n let collisionresult_output_array_index =\n atomicAdd(& collisionresult_counter, 1u); if\n collisionresult_output_array_index <\n COLLISIONRESULT_OUTPUT_ARRAY_LENGTH\n {\n collisionresult_output_array\n [collisionresult_output_array_index] = CollisionResult\n { entity1 : current_entity, entity2 : other_entity, };\n }\n };\n }\n}".to_owned() } }), binding_numbers_by_variable_name: Some(HashMap::from([(String::from("uniforms"), 0), (String::from("position_input_array"), 1), (String::from("radius_input_array"), 2), (String::from("collisionresult_output_array"), 3), (String::from("collisionresult_counter"), 4)])) }; let expected_wgsl_code = "const example_module_const : u32 = 42; diff --git a/bevy_gpu_compute_core/src/wgsl/shader_sections/code.rs b/bevy_gpu_compute_core/src/wgsl/shader_sections/code.rs index bb1c824..f898643 100644 --- a/bevy_gpu_compute_core/src/wgsl/shader_sections/code.rs +++ b/bevy_gpu_compute_core/src/wgsl/shader_sections/code.rs @@ -2,6 +2,5 @@ #[derive(Debug, Clone, PartialEq)] pub struct WgslShaderModuleSectionCode { - pub rust_code: String, pub wgsl_code: String, } diff --git a/bevy_gpu_compute_core/src/wgsl/shader_sections/const_assignment.rs b/bevy_gpu_compute_core/src/wgsl/shader_sections/const_assignment.rs index bbb92a8..afe7449 100644 --- a/bevy_gpu_compute_core/src/wgsl/shader_sections/const_assignment.rs +++ b/bevy_gpu_compute_core/src/wgsl/shader_sections/const_assignment.rs @@ -9,7 +9,6 @@ impl WgslConstAssignment { pub fn new(name: &str, scalar_type: &str, value: &str) -> Self { Self { code: WgslShaderModuleSectionCode { - rust_code: format!("const {}: {} = {};", name, scalar_type, value), wgsl_code: format!("override {}: {} = {};", name, scalar_type, value), }, } @@ -17,7 +16,6 @@ impl WgslConstAssignment { pub fn no_default(name: &str, scalar_type: &str) -> Self { Self { code: WgslShaderModuleSectionCode { - rust_code: format!("const {}: {};", name, scalar_type), wgsl_code: format!("override {}: {};", name, scalar_type), }, } diff --git a/bevy_gpu_compute_macro/flow_planning.graphml b/bevy_gpu_compute_macro/flow_planning.graphml new file mode 100644 index 0000000..3c13983 --- /dev/null +++ b/bevy_gpu_compute_macro/flow_planning.graphml @@ -0,0 +1,748 @@ + + + + + + + + + + + + + + + + + + + + + + + + remove_internal_attributes + Needs to come after custom type detection + + + + + + + + + + + + make_types_public + Used when re exporting the user's initial types for use by the user + + + + + + + + + + + + make_types_pod + Used when re exporting the user's initial types for use by the user + + + + + + + + + + + + Buffer Data Typed Builders + + + + + + + + + + + + Input Rust Module + + + + + + + + + + + + Functions + + + + + + + + + + + + Main Function + + + + + + + + + + + + Helper Functions + + + + + + + + + + + + convert WGSL helpers for gpu + + + + + + + + + + + + convert WGSL helpers for cpu + + + + + + + + + + + + Types + + + + + + + + + + + + Parse Custom Types + + + + + + + + + + + + + + + Public API + + + + + + + + + + Folder 1 + + + + + + + + + + + + + + + + + Builders + + + + + + + + + + + + Parsed for wgpu and bevy and wgsl + + + + + + + + + + + + Types for generic in create task + + + + + + + + + + + + + + + For Rust Usage By User + + + + + + + + + + Folder 2 + + + + + + + + + + + + + + + + + Custom Types for re-use by user wherever they want + + + + + + + + + + + + Functions for re-use by user on the CPU + + + + + + + + + + + + + + + + Alter signature to remove buffer dependence + + + + + + + + + + + + Constants + + + + + + + + + + + + Convert to WGSL Syntax + + + + + + + + + + + + WGSL Code + + + + + + + + + + + + Validate rust use statements + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bevy_gpu_compute_macro/src/lib.rs b/bevy_gpu_compute_macro/src/lib.rs index c01a4d5..1e82085 100644 --- a/bevy_gpu_compute_macro/src/lib.rs +++ b/bevy_gpu_compute_macro/src/lib.rs @@ -1,16 +1,10 @@ #![feature(allocator_api)] +use pipeline::lib::CompilerPipeline; use proc_macro::TokenStream; use proc_macro_error::{proc_macro_error, set_dummy}; -use state::ModuleTransformState; -use syn::{parse_macro_input, visit::Visit}; -use transformer::{ - custom_types::get_all_custom_types::get_custom_types, module_parser::lib::parse_shader_module, - output::produce_expanded_output, remove_doc_comments::DocCommentRemover, - transform_wgsl_helper_methods::run::transform_wgsl_helper_methods, -}; -mod state; -mod transformer; +use syn::parse_macro_input; +mod pipeline; /** ## *Please read this documentation carefully, especially if you are getting errors that you don't understand!* @@ -63,23 +57,10 @@ let x = my_vec3.x(); #[proc_macro_attribute] #[proc_macro_error] pub fn wgsl_shader_module(_attr: TokenStream, item: TokenStream) -> TokenStream { - // println!("Entered shader_module proc macro"); set_dummy(item.clone().into()); - let content = item.to_string(); let module = parse_macro_input!(item as syn::ItemMod); - DocCommentRemover {}.visit_item_mod(&module); - let mut state = ModuleTransformState::empty(module, content); - get_custom_types(&mut state); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module_for_cpu, true); - parse_shader_module(&mut state); - let output = produce_expanded_output(&mut state); - output.into() - - // let out_s = initialization.to_string(); - // quote!(struct S {};#out_s).into() - // output the original rust as well, to allow for correct syntax/ compile checking on it - // quote!({}).into() + let compiler_pipeline = CompilerPipeline::default(); + compiler_pipeline.compile(module).into() } /// used to help this library figure out what to do with user-defined types diff --git a/bevy_gpu_compute_macro/src/transformer/allowed_types.rs b/bevy_gpu_compute_macro/src/pipeline/allowed_types.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/allowed_types.rs rename to bevy_gpu_compute_macro/src/pipeline/allowed_types.rs diff --git a/bevy_gpu_compute_macro/src/pipeline/compilation_metadata.rs b/bevy_gpu_compute_macro/src/pipeline/compilation_metadata.rs new file mode 100644 index 0000000..8135334 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/compilation_metadata.rs @@ -0,0 +1,9 @@ +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; +use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; +use proc_macro2::TokenStream; + +pub struct CompilationMetadata { + pub custom_types: Option>, + pub wgsl_module_user_portion: Option, + pub typesafe_buffer_builders: Option, +} diff --git a/bevy_gpu_compute_macro/src/pipeline/compilation_unit.rs b/bevy_gpu_compute_macro/src/pipeline/compilation_unit.rs new file mode 100644 index 0000000..90cc65a --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/compilation_unit.rs @@ -0,0 +1,89 @@ +use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; +use proc_macro2::TokenStream; + +use super::{ + compilation_metadata::CompilationMetadata, + phases::custom_type_collector::custom_type::CustomType, +}; + +pub struct CompilationUnit { + original_rust_module: syn::ItemMod, + rust_module_for_cpu: Option, + rust_module_for_gpu: Option, + compiled_tokens: Option, + metadata: CompilationMetadata, +} + +impl CompilationUnit { + pub fn new(original_rust_module: syn::ItemMod) -> Self { + CompilationUnit { + original_rust_module, + rust_module_for_cpu: None, + rust_module_for_gpu: None, + compiled_tokens: None, + metadata: CompilationMetadata { + custom_types: None, + wgsl_module_user_portion: None, + typesafe_buffer_builders: None, + }, + } + } + pub fn rust_module_for_gpu(&self) -> &syn::ItemMod { + if self.rust_module_for_gpu.is_none() { + panic!("rust_module_for_gpu is not set"); + } + self.rust_module_for_gpu.as_ref().unwrap() + } + pub fn rust_module_for_cpu(&self) -> &syn::ItemMod { + if self.rust_module_for_cpu.is_none() { + panic!("rust_module_for_cpu is not set"); + } + self.rust_module_for_cpu.as_ref().unwrap() + } + pub fn set_custom_types(&mut self, custom_types: Vec) { + self.metadata.custom_types = Some(custom_types); + } + pub fn custom_types(&self) -> &Vec { + if self.metadata.custom_types.is_none() { + panic!("custom_types is not set"); + } + self.metadata.custom_types.as_ref().unwrap() + } + pub fn original_rust_module(&self) -> &syn::ItemMod { + &self.original_rust_module + } + pub fn set_rust_module_for_gpu(&mut self, rust_module_for_gpu: syn::ItemMod) { + self.rust_module_for_gpu = Some(rust_module_for_gpu); + } + pub fn compiled_tokens(&self) -> &Option { + &self.compiled_tokens + } + pub fn set_compiled_tokens(&mut self, compiled_tokens: TokenStream) { + self.compiled_tokens = Some(compiled_tokens); + } + pub fn set_rust_module_for_cpu(&mut self, rust_module_for_cpu: syn::ItemMod) { + self.rust_module_for_cpu = Some(rust_module_for_cpu); + } + pub fn set_wgsl_module_user_portion( + &mut self, + wgsl_module_user_portion: WgslShaderModuleUserPortion, + ) { + self.metadata.wgsl_module_user_portion = Some(wgsl_module_user_portion); + } + pub fn wgsl_module_user_portion(&self) -> &WgslShaderModuleUserPortion { + if self.metadata.wgsl_module_user_portion.is_none() { + panic!("wgsl_module_user_portion is not set"); + } + self.metadata.wgsl_module_user_portion.as_ref().unwrap() + } + + pub fn set_typesafe_buffer_builders(&mut self, typesafe_buffer_builders: TokenStream) { + self.metadata.typesafe_buffer_builders = Some(typesafe_buffer_builders); + } + pub fn typesafe_buffer_builders(&self) -> &TokenStream { + if self.metadata.typesafe_buffer_builders.is_none() { + panic!("typesafe_buffer_builders is not set"); + } + self.metadata.typesafe_buffer_builders.as_ref().unwrap() + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/lib.rs b/bevy_gpu_compute_macro/src/pipeline/lib.rs new file mode 100644 index 0000000..446830f --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/lib.rs @@ -0,0 +1,45 @@ +use proc_macro2::TokenStream; + +use super::phases::{ + compiler_phase::CompilerPhase, custom_type_collector::compiler_phase::CustomTypeCollector, + final_structure_generator::compiler_phase::FinalStructureGenerator, + gpu_resource_mngmnt_and_wgsl_generator::compiler_phase::GpuResourceMngmntAndWgslGenerator, + module_for_rust_usage_cleaner::compiler_phase::ModuleForRustUsageCleaner, + non_mutating_tree_validation::compiler_phase::NonMutatingTreeValidation, + typesafe_buffer_builders_generator::compiler_phase::TypesafeBufferBuildersGenerator, + wgsl_helper_transformer::compiler_phase::WgslHelperTransformer, +}; +use crate::pipeline::compilation_unit::CompilationUnit; + +pub struct CompilerPipeline { + phases: Vec>, +} + +impl Default for CompilerPipeline { + fn default() -> Self { + Self { + phases: vec![ + Box::new(NonMutatingTreeValidation {}), + Box::new(CustomTypeCollector {}), + Box::new(TypesafeBufferBuildersGenerator {}), + Box::new(WgslHelperTransformer {}), + Box::new(GpuResourceMngmntAndWgslGenerator {}), + Box::new(ModuleForRustUsageCleaner {}), + Box::new(FinalStructureGenerator {}), + ], + } + } +} +impl CompilerPipeline { + pub fn compile(&self, module: syn::ItemMod) -> TokenStream { + let mut unit = CompilationUnit::new(module); + for phase in &self.phases { + phase.execute(&mut unit); + } + if let Some(compiled) = unit.compiled_tokens() { + compiled.clone() + } else { + panic!("No compiled tokens found, missing a compile phase that produces them"); + } + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/mod.rs b/bevy_gpu_compute_macro/src/pipeline/mod.rs new file mode 100644 index 0000000..540afd8 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/mod.rs @@ -0,0 +1,5 @@ +mod allowed_types; +mod compilation_metadata; +mod compilation_unit; +pub mod lib; +mod phases; diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/compiler_phase.rs b/bevy_gpu_compute_macro/src/pipeline/phases/compiler_phase.rs new file mode 100644 index 0000000..34225ea --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/compiler_phase.rs @@ -0,0 +1,7 @@ +use crate::pipeline::compilation_unit::CompilationUnit; + +pub trait CompilerPhase { + /// using mutation for performance reasons + /// Also not returning a result since we should try to use macro_error abort to give proper span info when possible + fn execute(&self, input: &mut CompilationUnit); +} diff --git a/bevy_gpu_compute_macro/src/transformer/custom_types/get_all_custom_types.rs b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/collect.rs similarity index 65% rename from bevy_gpu_compute_macro/src/transformer/custom_types/get_all_custom_types.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/collect.rs index addb816..5933bef 100644 --- a/bevy_gpu_compute_macro/src/transformer/custom_types/get_all_custom_types.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/collect.rs @@ -5,15 +5,13 @@ use quote::ToTokens; use syn::visit::Visit; -use crate::state::ModuleTransformState; - use super::custom_type::{CustomType, CustomTypeKind}; -struct CustomTypesLister { +struct CustomTypesCollector { custom_types: Vec, } -impl<'ast> Visit<'ast> for CustomTypesLister { +impl<'ast> Visit<'ast> for CustomTypesCollector { fn visit_item_struct(&mut self, i: &'ast syn::ItemStruct) { syn::visit::visit_item_struct(self, i); @@ -34,17 +32,16 @@ impl<'ast> Visit<'ast> for CustomTypesLister { } } -impl CustomTypesLister { +impl CustomTypesCollector { pub fn new() -> Self { - CustomTypesLister { + CustomTypesCollector { custom_types: vec![], } } } -pub fn get_custom_types(state: &mut ModuleTransformState) { - let mut types_lister = CustomTypesLister::new(); - types_lister.visit_item_mod(&state.rust_module); - // println!("allowed types {:?}", types_lister.allowed_types); - state.custom_types = Some(types_lister.custom_types); +pub fn collect_custom_types(original_rust_module: &syn::ItemMod) -> Vec { + let mut types_collector = CustomTypesCollector::new(); + types_collector.visit_item_mod(original_rust_module); + types_collector.custom_types } diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/compiler_phase.rs b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/compiler_phase.rs new file mode 100644 index 0000000..ca7a6f2 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/compiler_phase.rs @@ -0,0 +1,11 @@ +use crate::pipeline::phases::custom_type_collector::collect::collect_custom_types; +use crate::pipeline::{compilation_unit::CompilationUnit, phases::compiler_phase::CompilerPhase}; + +pub struct CustomTypeCollector; + +impl CompilerPhase for CustomTypeCollector { + fn execute(&self, input: &mut CompilationUnit) { + let custom_types = collect_custom_types(input.original_rust_module()); + input.set_custom_types(custom_types); + } +} diff --git a/bevy_gpu_compute_macro/src/transformer/custom_types/custom_type.rs b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/custom_type.rs similarity index 81% rename from bevy_gpu_compute_macro/src/transformer/custom_types/custom_type.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/custom_type.rs index 6fd2605..7a18f21 100644 --- a/bevy_gpu_compute_macro/src/transformer/custom_types/custom_type.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/custom_type.rs @@ -4,7 +4,7 @@ use bevy_gpu_compute_core::wgsl::shader_sections::{WgslShaderModuleSectionCode, use proc_macro2::TokenStream; use syn::{Attribute, Ident}; -use crate::{state::ModuleTransformState, transformer::to_wgsl_syntax::convert_file_to_wgsl}; +use crate::pipeline::phases::gpu_resource_mngmnt_and_wgsl_generator::to_wgsl_syntax::convert_file_to_wgsl; use super::custom_type_idents::CustomTypeIdents; @@ -48,12 +48,15 @@ impl CustomType { rust_code: type_def_code, } } - pub fn into_wgsl_type(self, state: &ModuleTransformState) -> WgslType { + pub fn into_wgsl_type(self, custom_types: &Vec) -> WgslType { WgslType { name: self.name.into(), code: WgslShaderModuleSectionCode { - rust_code: self.rust_code.to_string(), - wgsl_code: convert_file_to_wgsl(self.rust_code, state, "custom_type".to_string()), + wgsl_code: convert_file_to_wgsl( + self.rust_code, + custom_types, + "custom_type".to_string(), + ), }, } } diff --git a/bevy_gpu_compute_macro/src/transformer/custom_types/custom_type_idents.rs b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/custom_type_idents.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/custom_types/custom_type_idents.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/custom_type_idents.rs diff --git a/bevy_gpu_compute_macro/src/transformer/custom_types/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/mod.rs similarity index 54% rename from bevy_gpu_compute_macro/src/transformer/custom_types/mod.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/mod.rs index f1b5647..0757b00 100644 --- a/bevy_gpu_compute_macro/src/transformer/custom_types/mod.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/custom_type_collector/mod.rs @@ -1,3 +1,4 @@ +pub mod collect; +pub mod compiler_phase; pub mod custom_type; pub mod custom_type_idents; -pub mod get_all_custom_types; diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/compiler_phase.rs b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/compiler_phase.rs new file mode 100644 index 0000000..35194c5 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/compiler_phase.rs @@ -0,0 +1,24 @@ +use crate::pipeline::{compilation_unit::CompilationUnit, phases::compiler_phase::CompilerPhase}; +use quote::quote; + +use super::{ + unaltered_module::generate_unaltered_module, user_facing_module::generate_user_facing_module, +}; +pub struct FinalStructureGenerator; + +impl CompilerPhase for FinalStructureGenerator { + fn execute(&self, input: &mut CompilationUnit) { + let unaltered_module_to_ensure_complete_rust_compiler_checks = + generate_unaltered_module(input.original_rust_module()); + let user_facing_module = generate_user_facing_module( + &mut input.wgsl_module_user_portion().clone(), + input.rust_module_for_cpu(), + input.typesafe_buffer_builders(), + ); + input.set_compiled_tokens(quote! { + #unaltered_module_to_ensure_complete_rust_compiler_checks + + #user_facing_module + }); + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/generate_required_imports.rs b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/generate_required_imports.rs new file mode 100644 index 0000000..b80f3e1 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/generate_required_imports.rs @@ -0,0 +1,13 @@ +use proc_macro2::TokenStream; +use quote::quote; + +pub fn generate_required_imports() -> TokenStream { + quote! { + use bevy_gpu_compute_core::wgsl::shader_sections::*; //todo, make this less brittle, how? + use bevy_gpu_compute_core::wgsl::shader_custom_type_name::*; + use bevy_gpu_compute_core::wgsl_helpers::*; + use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; + use bevy_gpu_compute_core::*; + use std::collections::HashMap; + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/mod.rs new file mode 100644 index 0000000..4b8a26f --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/mod.rs @@ -0,0 +1,7 @@ +pub mod compiler_phase; +mod generate_required_imports; +mod per_component_expansion; +mod shader_module_object; +mod types_for_rust_usage; +mod unaltered_module; +mod user_facing_module; diff --git a/bevy_gpu_compute_macro/src/transformer/output/per_component_expansion.rs b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/per_component_expansion.rs similarity index 69% rename from bevy_gpu_compute_macro/src/transformer/output/per_component_expansion.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/per_component_expansion.rs index 2022190..5ee3bd4 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/per_component_expansion.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/per_component_expansion.rs @@ -13,20 +13,18 @@ use quote::quote; pub struct ToStructInitializer {} impl ToStructInitializer { - pub fn wgsl_shader_module_component(c: WgslShaderModuleSectionCode) -> TokenStream { - let r = c.rust_code; - let w = c.wgsl_code; + pub fn wgsl_shader_module_component(c: &WgslShaderModuleSectionCode) -> TokenStream { + let w = &c.wgsl_code; quote!( WgslShaderModuleSectionCode { - rust_code: (#r).to_string(), wgsl_code: (#w).to_string(), } ) } - pub fn wgsl_type(c: WgslType) -> TokenStream { - let n = ToStructInitializer::custom_type_name(c.name); - let c = ToStructInitializer::wgsl_shader_module_component(c.code); + pub fn wgsl_type(c: &WgslType) -> TokenStream { + let n = ToStructInitializer::custom_type_name(&c.name); + let c = ToStructInitializer::wgsl_shader_module_component(&c.code); quote!( WgslType { name: #n, @@ -35,16 +33,16 @@ impl ToStructInitializer { ) } - pub fn custom_type_name(c: ShaderCustomTypeName) -> TokenStream { + pub fn custom_type_name(c: &ShaderCustomTypeName) -> TokenStream { let n = c.name(); quote!( ShaderCustomTypeName::new(#n) ) } - pub fn wgsl_function(c: WgslFunction) -> TokenStream { - let n = c.name; - let c = ToStructInitializer::wgsl_shader_module_component(c.code); + pub fn wgsl_function(c: &WgslFunction) -> TokenStream { + let n = &c.name; + let c = ToStructInitializer::wgsl_shader_module_component(&c.code); quote!( WgslFunction { name: (#n).to_string(), @@ -53,8 +51,8 @@ impl ToStructInitializer { ) } - pub fn wgsl_const_assignment(c: WgslConstAssignment) -> TokenStream { - let c = ToStructInitializer::wgsl_shader_module_component(c.code); + pub fn wgsl_const_assignment(c: &WgslConstAssignment) -> TokenStream { + let c = ToStructInitializer::wgsl_shader_module_component(&c.code); quote!( WgslConstAssignment { code: #c, @@ -62,8 +60,8 @@ impl ToStructInitializer { ) } - pub fn wgsl_input_array(c: WgslInputArray) -> TokenStream { - let i = ToStructInitializer::wgsl_type(c.item_type); + pub fn wgsl_input_array(c: &WgslInputArray) -> TokenStream { + let i = ToStructInitializer::wgsl_type(&c.item_type); quote!( WgslInputArray { item_type: #i, @@ -71,8 +69,8 @@ impl ToStructInitializer { ) } - pub fn wgsl_output_array(c: WgslOutputArray) -> TokenStream { - let i = ToStructInitializer::wgsl_type(c.item_type); + pub fn wgsl_output_array(c: &WgslOutputArray) -> TokenStream { + let i = ToStructInitializer::wgsl_type(&c.item_type); let ac: TokenStream = c .atomic_counter_name .as_ref() @@ -90,7 +88,7 @@ impl ToStructInitializer { } ) } - pub fn hash_map(c: HashMap) -> TokenStream { + pub fn hash_map(c: &HashMap) -> TokenStream { let entries: TokenStream = c .iter() .map(|(k, v)| { diff --git a/bevy_gpu_compute_macro/src/transformer/output/shader_module_object.rs b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/shader_module_object.rs similarity index 69% rename from bevy_gpu_compute_macro/src/transformer/output/shader_module_object.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/shader_module_object.rs index a3c6cac..18f76bd 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/shader_module_object.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/shader_module_object.rs @@ -1,73 +1,80 @@ -use crate::{ - state::ModuleTransformState, transformer::output::per_component_expansion::ToStructInitializer, -}; use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; use proc_macro2::TokenStream; use quote::quote; -pub fn generate_shader_module_object(state: &ModuleTransformState) -> TokenStream { - let obj: WgslShaderModuleUserPortion = state.result.clone(); +use crate::pipeline::phases::final_structure_generator::per_component_expansion::ToStructInitializer; - let static_consts: TokenStream = obj +pub fn generate_shader_module_object( + wgsl_shader_module: &WgslShaderModuleUserPortion, +) -> TokenStream { + let static_consts: TokenStream = wgsl_shader_module .static_consts - .into_iter() + .iter() .map(|const_assignment| { let ts = ToStructInitializer::wgsl_const_assignment(const_assignment); quote!(#ts,) }) .collect(); - let helper_types: TokenStream = obj + let helper_types: TokenStream = wgsl_shader_module .helper_types - .into_iter() + .iter() .map(|type_def| { let ts = ToStructInitializer::wgsl_type(type_def); quote!(#ts,) }) .collect(); - let uniforms2: TokenStream = obj + let uniforms2: TokenStream = wgsl_shader_module .uniforms - .into_iter() + .iter() .map(|uniform| { let ts = ToStructInitializer::wgsl_type(uniform); quote!(#ts,) }) .collect(); - let input_arrays: TokenStream = obj + let input_arrays: TokenStream = wgsl_shader_module .input_arrays - .into_iter() + .iter() .map(|array| { let ts = ToStructInitializer::wgsl_input_array(array); quote!(#ts,) }) .collect(); - let output_arrays: TokenStream = obj + let output_arrays: TokenStream = wgsl_shader_module .output_arrays - .into_iter() + .iter() .map(|output_array| { let ts = ToStructInitializer::wgsl_output_array(output_array); quote!(#ts,) }) .collect(); - let helper_functions: TokenStream = obj + let helper_functions: TokenStream = wgsl_shader_module .helper_functions - .into_iter() + .iter() .map(|func| { let ts = ToStructInitializer::wgsl_function(func); quote!(#ts,) }) .collect(); - let main_function: TokenStream = obj.main_function.map_or(quote!(None), |func| { - let ts = ToStructInitializer::wgsl_function(func); - quote!(Some(#ts)) - }); - let bindings_map: TokenStream = - ToStructInitializer::hash_map(obj.binding_numbers_by_variable_name.unwrap()); + let main_function: TokenStream = + wgsl_shader_module + .main_function + .as_ref() + .map_or(quote!(None), |func| { + let ts = ToStructInitializer::wgsl_function(func); + quote!(Some(#ts)) + }); + let bindings_map: TokenStream = ToStructInitializer::hash_map( + wgsl_shader_module + .binding_numbers_by_variable_name + .as_ref() + .unwrap(), + ); quote!( pub fn parsed() -> WgslShaderModuleUserPortion { @@ -95,7 +102,6 @@ pub fn generate_shader_module_object(state: &ModuleTransformState) -> TokenStrea #helper_functions ] .into(), - // main_function: None, main_function: #main_function, binding_numbers_by_variable_name: Some(#bindings_map), } diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/types.rs b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/types_for_rust_usage.rs similarity index 62% rename from bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/types.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/types_for_rust_usage.rs index 10b6726..9d624d7 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/types.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/types_for_rust_usage.rs @@ -4,59 +4,34 @@ use bevy_gpu_compute_core::wgsl::{ shader_custom_type_name::ShaderCustomTypeName, shader_module::user_defined_portion::WgslShaderModuleUserPortion, }; -use proc_macro_error::abort; use proc_macro2::{Span, TokenStream}; -use quote::{ToTokens, quote}; -use syn::{Ident, parse2, visit_mut::VisitMut}; - -use crate::{ - state::ModuleTransformState, - transformer::{ - custom_types::custom_type::CustomTypeKind, - output::types_for_rust_usage::{ - config_input_data_builder::create_config_input_data_builder, - input_data_builder::create_input_data_builder, - make_types_public::MakeTypesPublicTransformer, - max_output_lengths_builder::create_max_output_lengths_builder, - output_data_builder::create_output_data_builder, - }, - }, -}; - -use super::{ - make_types_pod::MakeTypesPodTransformer, remove_internal_attributes::remove_internal_attributes, -}; +use quote::quote; +use syn::Ident; pub fn define_types_for_use_in_rust_and_set_binding_numbers( - state: &mut ModuleTransformState, + wgsl_shader_module: &mut WgslShaderModuleUserPortion, ) -> TokenStream { - let user_types = user_defined_types(state); // order needs to be consistent -> input_configs -> input_arrays -> output_arrays let mut binding_num_counter: u32 = 0; let mut binding_numbers_by_variable_name: HashMap = HashMap::new(); let uniforms: TokenStream = uniform_types( &mut binding_num_counter, &mut binding_numbers_by_variable_name, - state, + wgsl_shader_module, ); let input_arrays = input_array_types( &mut binding_num_counter, &mut binding_numbers_by_variable_name, - state, + wgsl_shader_module, ); let output_arrays = output_array_types( &mut binding_num_counter, &mut binding_numbers_by_variable_name, - state, + wgsl_shader_module, ); - let max_output_lengths_builder = create_max_output_lengths_builder(state); - let config_input_data_builder = create_config_input_data_builder(state); - let input_data_builder = create_input_data_builder(state); - let output_data_builder = create_output_data_builder(state); - state.result.binding_numbers_by_variable_name = Some(binding_numbers_by_variable_name); + + wgsl_shader_module.binding_numbers_by_variable_name = Some(binding_numbers_by_variable_name); quote!( - /// user types - #user_types /// uniforms #uniforms /// input arrays @@ -64,9 +39,6 @@ pub fn define_types_for_use_in_rust_and_set_binding_numbers( /// output types #output_arrays /// public facing types for use by library - - - /// For passing as a generic argument in the user-facing api, the user should not need to know anything about what "Types" contains pub struct Types; impl TypesSpec for Types { @@ -75,62 +47,15 @@ pub fn define_types_for_use_in_rust_and_set_binding_numbers( type OutputArrayTypes = _OutputArrayTypes; } - #max_output_lengths_builder - - #config_input_data_builder - - #input_data_builder - - #output_data_builder - - ) } -pub fn user_defined_types(state: &ModuleTransformState) -> TokenStream { - let mut publicifier = MakeTypesPublicTransformer {}; - let mut podifier = MakeTypesPodTransformer {}; - let custom_types = remove_internal_attributes( - state - .custom_types - .as_ref() - .unwrap() - .iter() - .map(|c| { - // get item - if c.kind == CustomTypeKind::ArrayLengthVariable { - return "".to_string(); - } - let s = c.rust_code.clone(); - let mut item = parse2::(s); - if let Err(e) = item { - let message = format!( - "Error parsing custom type: {:?}, with custom type: {:?}", - e, c - ); - abort!(Span::call_site(), message); - } - // make public - publicifier.visit_item_mut(item.as_mut().unwrap()); - podifier.visit_item_mut(item.as_mut().unwrap()); - // stringify - let string: String = item.unwrap().to_token_stream().to_string(); - string - }) - .collect::>() - .join("\n"), - ); - custom_types.parse().unwrap() -} - pub fn uniform_types( binding_num_counter: &mut u32, binding_numbers_by_variable_name: &mut HashMap, - - state: &ModuleTransformState, + wgsl_shader_module: &WgslShaderModuleUserPortion, ) -> TokenStream { - let obj: WgslShaderModuleUserPortion = state.result.clone(); - let uniforms = obj.uniforms; + let uniforms = &wgsl_shader_module.uniforms; let uniforms_token_streams: TokenStream = uniforms .iter() .map(|uniform| { @@ -191,11 +116,9 @@ fn get_single_output_type_metadata( pub fn input_array_types( binding_num_counter: &mut u32, binding_numbers_by_variable_name: &mut HashMap, - - state: &ModuleTransformState, + wgsl_shader_module: &WgslShaderModuleUserPortion, ) -> TokenStream { - let obj: WgslShaderModuleUserPortion = state.result.clone(); - let input_arrays = obj.input_arrays; + let input_arrays = &wgsl_shader_module.input_arrays; let input_array_token_streams: TokenStream = input_arrays .iter() .map(|in_arr| { @@ -222,11 +145,9 @@ pub fn input_array_types( pub fn output_array_types( binding_num_counter: &mut u32, binding_numbers_by_variable_name: &mut HashMap, - - state: &ModuleTransformState, + shader: &WgslShaderModuleUserPortion, ) -> TokenStream { - let obj: WgslShaderModuleUserPortion = state.result.clone(); - let output_arrays = obj.output_arrays; + let output_arrays = &shader.output_arrays; let output_array_token_streams: TokenStream = output_arrays .iter() .map(|out_arr| { diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/unaltered_module.rs b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/unaltered_module.rs new file mode 100644 index 0000000..4b9801f --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/unaltered_module.rs @@ -0,0 +1,30 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, format_ident, quote}; +use syn::ItemMod; + +/// make a module that is not intended to be viewed or accessed just to allow the rust compiler to run and find any potential errors in the original code that might be missed elsewhere in our macro if we remove or alter parts of the original code. +pub fn generate_unaltered_module(original_module: &ItemMod) -> TokenStream { + let original_ident = &original_module.ident; + let content: Vec = if let Some(content) = &original_module.content { + content + .1 + .iter() + .map(|item| { + let item = item.to_token_stream(); + quote! { + #item + } + }) + .collect() + } else { + vec![quote! {}] + }; + let content_combined: TokenStream = content.into_iter().collect(); + let new_ident = format_ident!("_internal_{}", original_ident); + quote! { + #[allow(dead_code, unused_variables, unused_imports)] + mod #new_ident { + #content_combined + } + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/user_facing_module.rs b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/user_facing_module.rs new file mode 100644 index 0000000..13fad03 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/final_structure_generator/user_facing_module.rs @@ -0,0 +1,46 @@ +use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; +use syn::ItemMod; + +use crate::pipeline::phases::final_structure_generator::generate_required_imports::generate_required_imports; + +use super::{ + shader_module_object::generate_shader_module_object, + types_for_rust_usage::define_types_for_use_in_rust_and_set_binding_numbers, +}; + +pub fn generate_user_facing_module( + wgsl_shader_module: &mut WgslShaderModuleUserPortion, + rust_module_for_cpu: &ItemMod, + builders: &TokenStream, +) -> TokenStream { + let generated_types = define_types_for_use_in_rust_and_set_binding_numbers(wgsl_shader_module); + let generated_shader_module_object = generate_shader_module_object(wgsl_shader_module); + let required_imports = generate_required_imports(); + let user_module_content: TokenStream = rust_module_for_cpu + .content + .as_ref() + .unwrap() + .1 + .iter() + .map(|item| item.to_token_stream()) + .collect(); + let vis = &rust_module_for_cpu.vis; + let ident = &rust_module_for_cpu.ident; + /* this may produce an error, if things aren't working, restructure this... since it may not be able to parse all these items into a single syn::Item */ + quote! { + #[allow(dead_code, unused_variables, unused_imports)] + #vis mod #ident { + #required_imports + + #user_module_content + + #generated_types + + #generated_shader_module_object + + #builders + } + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/compiler_phase.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/compiler_phase.rs new file mode 100644 index 0000000..8d9ebbc --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/compiler_phase.rs @@ -0,0 +1,14 @@ +use crate::pipeline::{compilation_unit::CompilationUnit, phases::compiler_phase::CompilerPhase}; + +use super::lib::parse_shader_module_for_gpu; + +pub struct GpuResourceMngmntAndWgslGenerator; + +impl CompilerPhase for GpuResourceMngmntAndWgslGenerator { + fn execute(&self, input: &mut CompilationUnit) { + let (shader_module, custom_types) = + parse_shader_module_for_gpu(input.rust_module_for_gpu(), input.custom_types()); + input.set_wgsl_module_user_portion(shader_module); + input.set_custom_types(custom_types); + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/constants.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/constants.rs new file mode 100644 index 0000000..f8f4174 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/constants.rs @@ -0,0 +1,56 @@ +use bevy_gpu_compute_core::wgsl::shader_sections::{ + WgslConstAssignment, WgslShaderModuleSectionCode, +}; +use quote::ToTokens; +use syn::{ItemConst, ItemMod, visit::Visit}; + +use super::to_wgsl_syntax::convert_file_to_wgsl; +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; + +// todo ensure this only searches the module level, right now its searching within functions as well + +pub fn extract_constants( + rust_module_transformed_for_gpu: &ItemMod, + custom_types: &Vec, +) -> Vec { + let mut extractor = ConstantsExtractor::new(custom_types); + extractor.visit_item_mod(rust_module_transformed_for_gpu); + extractor.results +} + +struct ConstantsExtractor<'a> { + custom_types: &'a Vec, + results: Vec, +} + +impl<'ast> Visit<'ast> for ConstantsExtractor<'ast> { + fn visit_item_const(&mut self, c: &'ast syn::ItemConst) { + syn::visit::visit_item_const(self, c); + self.results + .push(parse_const_assignment(c, self.custom_types)); + } +} + +impl<'ast> ConstantsExtractor<'ast> { + pub fn new(custom_types: &'ast Vec) -> Self { + ConstantsExtractor { + custom_types, + results: Vec::new(), + } + } +} + +fn parse_const_assignment( + constant: &ItemConst, + custom_types: &Vec, +) -> WgslConstAssignment { + WgslConstAssignment { + code: WgslShaderModuleSectionCode { + wgsl_code: convert_file_to_wgsl( + constant.to_token_stream(), + custom_types, + "const".to_string(), + ), + }, + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/divide_custom_types.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/divide_custom_types.rs new file mode 100644 index 0000000..0ce8673 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/divide_custom_types.rs @@ -0,0 +1,68 @@ +use bevy_gpu_compute_core::wgsl::{ + shader_module::user_defined_portion::WgslShaderModuleUserPortion, + shader_sections::{WgslInputArray, WgslOutputArray}, +}; + +use crate::pipeline::phases::custom_type_collector::custom_type::{CustomType, CustomTypeKind}; +use quote::quote; + +pub fn generate_helper_types_inputs_and_outputs_for_wgsl_module_def( + custom_types: &Vec, + wgsl_module_def: &mut WgslShaderModuleUserPortion, +) -> Vec { + let mut additional_custom_types: Vec = Vec::new(); + for custom_type in custom_types.iter() { + match custom_type.kind { + CustomTypeKind::GpuOnlyHelperType => { + wgsl_module_def + .helper_types + .push(custom_type.clone().into_wgsl_type(custom_types)); + } + CustomTypeKind::InputArray => { + additional_custom_types.push(CustomType::new( + &custom_type.name.input_array_length(), + CustomTypeKind::ArrayLengthVariable, + quote!(), + )); + wgsl_module_def.input_arrays.push(WgslInputArray { + item_type: custom_type.clone().into_wgsl_type(custom_types), + }); + } + CustomTypeKind::OutputArray => { + additional_custom_types.push(CustomType::new( + &custom_type.name.output_array_length(), + CustomTypeKind::ArrayLengthVariable, + quote!(), + )); + wgsl_module_def.output_arrays.push(WgslOutputArray { + item_type: custom_type.clone().into_wgsl_type(custom_types), + atomic_counter_name: None, + }); + } + CustomTypeKind::OutputVec => { + additional_custom_types.push(CustomType::new( + &custom_type.name.output_array_length(), + CustomTypeKind::ArrayLengthVariable, + quote!(), + )); + wgsl_module_def.output_arrays.push(WgslOutputArray { + item_type: custom_type.clone().into_wgsl_type(custom_types), + atomic_counter_name: Some(custom_type.name.counter().to_string()), + }); + } + CustomTypeKind::Uniform => { + wgsl_module_def + .uniforms + .push(custom_type.clone().into_wgsl_type(custom_types)); + } + CustomTypeKind::ArrayLengthVariable => { + // do nothing + } + } + } + + // add the additional custom types to the custom types list + let mut out = custom_types.clone(); + out.extend(additional_custom_types); + out +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/helper_functions.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/helper_functions.rs new file mode 100644 index 0000000..e35a03a --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/helper_functions.rs @@ -0,0 +1,54 @@ +use super::to_wgsl_syntax::convert_file_to_wgsl; +use bevy_gpu_compute_core::wgsl::shader_sections::{WgslFunction, WgslShaderModuleSectionCode}; +use quote::ToTokens; +use syn::{ItemFn, ItemMod, visit::Visit}; + +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; + +pub fn extract_helper_functions( + rust_module_transformed_for_gpu: &ItemMod, + custom_types: &Vec, +) -> Vec { + let mut extractor = HelperFunctionsExtractor::new(custom_types); + extractor.visit_item_mod(rust_module_transformed_for_gpu); + extractor.results +} + +struct HelperFunctionsExtractor<'a> { + custom_types: &'a Vec, + results: Vec, +} + +impl<'ast> Visit<'ast> for HelperFunctionsExtractor<'ast> { + fn visit_item_fn(&mut self, c: &'ast syn::ItemFn) { + syn::visit::visit_item_fn(self, c); + if c.sig.ident == "main" { + return; + } + // ident from string + + self.results.push(parse_fn(c, self.custom_types)); + } +} + +impl<'ast> HelperFunctionsExtractor<'ast> { + pub fn new(custom_types: &'ast Vec) -> Self { + HelperFunctionsExtractor { + custom_types, + results: Vec::new(), + } + } +} + +fn parse_fn(func: &ItemFn, custom_types: &Vec) -> WgslFunction { + WgslFunction { + code: WgslShaderModuleSectionCode { + wgsl_code: convert_file_to_wgsl( + func.to_token_stream(), + custom_types, + "helper fn".to_string(), + ), + }, + name: func.sig.ident.to_string(), + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/lib.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/lib.rs new file mode 100644 index 0000000..6f91d68 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/lib.rs @@ -0,0 +1,26 @@ +use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; + +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; + +use super::constants::extract_constants; +use super::divide_custom_types::generate_helper_types_inputs_and_outputs_for_wgsl_module_def; +use super::helper_functions::extract_helper_functions; +use super::main_function::parse_main_function; + +/// This will also change custom_types +pub fn parse_shader_module_for_gpu( + rust_module_transformed_for_gpu: &syn::ItemMod, + custom_types: &Vec, +) -> (WgslShaderModuleUserPortion, Vec) { + let mut out_module: WgslShaderModuleUserPortion = WgslShaderModuleUserPortion::empty(); + out_module.main_function = Some(parse_main_function( + rust_module_transformed_for_gpu, + custom_types, + )); + out_module.static_consts = extract_constants(rust_module_transformed_for_gpu, custom_types); + out_module.helper_functions = + extract_helper_functions(rust_module_transformed_for_gpu, custom_types); + let new_custom_types = + generate_helper_types_inputs_and_outputs_for_wgsl_module_def(custom_types, &mut out_module); + (out_module, new_custom_types) +} diff --git a/bevy_gpu_compute_macro/src/transformer/module_parser/main_function.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/main_function.rs similarity index 62% rename from bevy_gpu_compute_macro/src/transformer/module_parser/main_function.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/main_function.rs index 457297e..6c74873 100644 --- a/bevy_gpu_compute_macro/src/transformer/module_parser/main_function.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/main_function.rs @@ -1,31 +1,30 @@ -use crate::{state::ModuleTransformState, transformer::to_wgsl_syntax::convert_file_to_wgsl}; +use super::to_wgsl_syntax::convert_file_to_wgsl; +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; use bevy_gpu_compute_core::wgsl::shader_sections::{WgslFunction, WgslShaderModuleSectionCode}; use proc_macro::Span; use proc_macro_error::abort; use quote::ToTokens; -use syn::{ItemFn, spanned::Spanned, visit::Visit}; +use syn::{ItemFn, ItemMod, spanned::Spanned, visit::Visit}; -pub fn parse_main_function(state: &mut ModuleTransformState) { - let module = state.rust_module.clone(); - let mut extractor = MainFunctionsExtractor::new(state, false); - extractor.visit_item_mod(&module); - let module_for_cpu = state.rust_module_for_cpu.clone(); - let mut extractor_for_cpu = MainFunctionsExtractor::new(state, true); - extractor_for_cpu.visit_item_mod(&module_for_cpu); - let main_func = if let Some(mf) = &state.result.main_function { +/// 0: for gpu, 1: for cpu +pub fn parse_main_function( + rust_module_transformed_for_gpu: &ItemMod, + custom_types: &Vec, +) -> WgslFunction { + let mut extractor = MainFunctionsExtractor::new(custom_types); + extractor.visit_item_mod(rust_module_transformed_for_gpu); + + if let Some(mf) = extractor.result { mf } else { - abort!(state.rust_module.ident.span(), "No main function found"); - }; - let r_code = main_func.code.rust_code.clone(); - validate_main_function(r_code); - state.rust_module = module; + abort!(Span::call_site(), "No main function found"); + } } struct MainFunctionsExtractor<'a> { count: usize, - state: &'a mut ModuleTransformState, - for_cpu: bool, + custom_types: &'a Vec, + result: Option, } impl<'ast> Visit<'ast> for MainFunctionsExtractor<'ast> { @@ -39,40 +38,32 @@ impl<'ast> Visit<'ast> for MainFunctionsExtractor<'ast> { if self.count > 1 { abort!(c.sig.ident.span(), "Only one main function is allowed"); } - if self.for_cpu { - self.state.result_for_cpu.main_function = - Some(parse_main_fn(c, self.state, self.for_cpu)); - } else { - self.state.result.main_function = Some(parse_main_fn(c, self.state, self.for_cpu)); - } + + self.result = Some(parse_main_fn(c, self.custom_types)); } } impl<'ast> MainFunctionsExtractor<'ast> { - pub fn new(state: &'ast mut ModuleTransformState, for_cpu: bool) -> Self { + pub fn new(custom_types: &'ast Vec) -> Self { MainFunctionsExtractor { count: 0, - state, - for_cpu, + custom_types, + result: None, } } } -fn parse_main_fn(func: &ItemFn, state: &ModuleTransformState, for_cpu: bool) -> WgslFunction { +fn parse_main_fn(func: &ItemFn, custom_types: &Vec) -> WgslFunction { + validate_main_function(func); let func_clone = func.clone(); // alter the main function argument WgslFunction { code: WgslShaderModuleSectionCode { - rust_code: func_clone.to_token_stream().to_string(), - wgsl_code: if for_cpu { - "".to_string() - } else { - alter_global_id_argument(convert_file_to_wgsl( - func_clone.to_token_stream(), - state, - "main".to_string(), - )) - }, + wgsl_code: alter_global_id_argument(convert_file_to_wgsl( + func_clone.to_token_stream(), + custom_types, + "main".to_string(), + )), }, name: func_clone.sig.ident.to_string(), } @@ -104,13 +95,7 @@ fn alter_global_id_argument(func_string: String) -> String { new_func } -fn validate_main_function(function_string: String) { - let function = if let Ok(f) = syn::parse_str::(&function_string) { - f - } else { - let message = format!("Failed to parse main function: {}", function_string); - abort!(Span::call_site(), message); - }; +fn validate_main_function(function: &ItemFn) { // Check that main has exactly one parameter if function.sig.inputs.len() != 1 { abort!( diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/mod.rs new file mode 100644 index 0000000..35c096a --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/mod.rs @@ -0,0 +1,7 @@ +pub mod compiler_phase; +mod constants; +mod divide_custom_types; +mod helper_functions; +mod lib; +mod main_function; +pub mod to_wgsl_syntax; diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/array.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/array.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/array.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/array.rs diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/expr.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/expr.rs similarity index 79% rename from bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/expr.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/expr.rs index b355cd5..7e07e1c 100644 --- a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/expr.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/expr.rs @@ -1,8 +1,8 @@ use proc_macro_error::abort; use quote::ToTokens; -use syn::{Expr, ExprCall, parse_quote, parse2, spanned::Spanned, visit_mut::VisitMut}; +use syn::{Expr, ExprCall, LitFloat, parse_quote, parse2, spanned::Spanned, visit_mut::VisitMut}; -use crate::transformer::allowed_types::WGSL_NATIVE_TYPES; +use crate::pipeline::allowed_types::WGSL_NATIVE_TYPES; pub struct ExprToWgslTransformer {} @@ -20,7 +20,46 @@ impl VisitMut for ExprToWgslTransformer { pub fn expr_to_wgsl(expr: &syn::Expr) -> Option { #[allow(unused_variables)] match expr { - syn::Expr::Lit(lit) => None, + syn::Expr::Lit(lit) => match &lit.lit { + // to handle things like 3.4_f32 + // if the suffix is u32 then write it as a type cast like u32(digits), same for f32, and i32 and f16 + syn::Lit::Float(l) => { + // must either have no suffix, in which case we do nothing, or have f32 as the suffix + let suffix = l.suffix(); + if suffix.is_empty() || suffix == "f" { + None + } else if suffix == "f32" { + let value = l.base10_digits(); + let value = LitFloat::new(value, l.span()); + return Some(parse_quote!(f32(#value))); + } else { + abort!( + l.span(), + "Unsupported float suffix in WGSL: ".to_owned() + suffix + ); + } + } + syn::Lit::Int(l) => { + let suffix = l.suffix(); + if suffix.is_empty() || suffix == "u" || suffix == "i" { + None + } else if suffix == "u32" { + let value = l.base10_digits(); + let value = LitFloat::new(value, l.span()); + return Some(parse_quote!(u32(#value))); + } else if suffix == "i32" { + let value = l.base10_digits(); + let value = LitFloat::new(value, l.span()); + return Some(parse_quote!(i32(#value))); + } else { + abort!( + l.span(), + "Unsupported integer suffix in WGSL: ".to_owned() + suffix + ); + } + } + _ => None, + }, syn::Expr::Array(array) => { abort!(array.span(), "Array literals are not supported in WGSL") } diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/implicit_to_explicit_return.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/implicit_to_explicit_return.rs new file mode 100644 index 0000000..bbd3aef --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/implicit_to_explicit_return.rs @@ -0,0 +1,52 @@ +use syn::visit_mut::VisitMut; +use syn::{Block, Expr, Stmt, parse_quote, visit_mut}; + +/** + Rust implicit returns like + ```rust + fn foo() -> i32 { + 42 + } + ``` + must be converted to explicit returns like + ```rust + fn foo() -> i32 { + return 42; + } + ``` + for WGSL +* */ +pub struct ImplicitToExplicitReturnTransformer; + +impl VisitMut for ImplicitToExplicitReturnTransformer { + // we can identify an implicit return by... + // must be a Stmt::Expr + // must NOT be a Stmt::Semi + // must be the last statement in the block + // for now we'll say it can be any non semi expression + fn visit_block_mut(&mut self, block: &mut Block) { + visit_mut::visit_block_mut(self, block); + let last_idx = block.stmts.len().checked_sub(1); + if let Some(idx) = last_idx { + if let Stmt::Expr(expr, semi) = &block.stmts[idx] { + if semi.is_none() + && !matches!( + expr, + Expr::If(_) + | Expr::Match(_) + | Expr::Loop(_) + | Expr::ForLoop(_) + | Expr::While(_) + ) + { + // is probably an implicit return + block.stmts[idx] = parse_quote!(return #expr;); + } + } + } + } + fn visit_item_fn_mut(&mut self, item_fn: &mut syn::ItemFn) { + visit_mut::visit_item_fn_mut(self, item_fn); + self.visit_block_mut(&mut item_fn.block); + } +} diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/local_var.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/local_var.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/local_var.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/local_var.rs diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/mod.rs similarity index 92% rename from bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/mod.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/mod.rs index ce82963..8e290d9 100644 --- a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/mod.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/mod.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use array::ArrayToWgslTransformer; use expr::ExprToWgslTransformer; +use implicit_to_explicit_return::ImplicitToExplicitReturnTransformer; use local_var::replace_let_mut_with_var; use proc_macro_error::abort; use proc_macro2::{Span, TokenStream}; @@ -13,7 +14,7 @@ use r#type::TypeToWgslTransformer; use type_def::TypeDefToWgslTransformer; use wgsl_builtin_constructors::convert_wgsl_builtin_constructors; -use crate::state::ModuleTransformState; +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; /** # Notes about conversions (all syntax not mentioned is either the same or not supported in wgsl) @@ -59,6 +60,7 @@ use crate::state::ModuleTransformState; */ mod array; mod expr; +mod implicit_to_explicit_return; mod local_var; pub mod remove_attributes; mod remove_pub_from_struct_def; @@ -68,7 +70,7 @@ mod wgsl_builtin_constructors; /// called_from is for debug messages pub fn convert_file_to_wgsl( input: TokenStream, - state: &ModuleTransformState, + custom_types: &Vec, called_from: String, ) -> String { let unprocessed_string = input.to_string(); @@ -86,18 +88,11 @@ pub fn convert_file_to_wgsl( abort!(Span::call_site(), message); }; - let custom_types = if let Some(ct) = &state.custom_types { - ct - } else { - abort!( - state.rust_module.ident.span(), - "Allowed types must be set before converting to wgsl" - ); - }; PubRemover {}.visit_file_mut(&mut file); TypeToWgslTransformer { custom_types }.visit_file_mut(&mut file); ArrayToWgslTransformer {}.visit_file_mut(&mut file); ExprToWgslTransformer {}.visit_file_mut(&mut file); + ImplicitToExplicitReturnTransformer {}.visit_file_mut(&mut file); let mut type_def_transformer = TypeDefToWgslTransformer { replacements: HashMap::new(), }; diff --git a/bevy_gpu_compute_macro/src/transformer/output/remove_attributes.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/remove_attributes.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/output/remove_attributes.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/remove_attributes.rs diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/remove_pub_from_struct_def.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/remove_pub_from_struct_def.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/remove_pub_from_struct_def.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/remove_pub_from_struct_def.rs diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/type.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/type.rs similarity index 98% rename from bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/type.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/type.rs index 1e6edc0..28a1815 100644 --- a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/type.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/type.rs @@ -1,7 +1,7 @@ use proc_macro_error::abort; use syn::{PathSegment, parse_quote, visit_mut::VisitMut}; -use crate::transformer::custom_types::custom_type::CustomType; +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; pub struct TypeToWgslTransformer<'a> { pub custom_types: &'a Vec, diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/type_def.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/type_def.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/type_def.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/type_def.rs diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/wgsl_builtin_constructors.rs b/bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/wgsl_builtin_constructors.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/wgsl_builtin_constructors.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/gpu_resource_mngmnt_and_wgsl_generator/to_wgsl_syntax/wgsl_builtin_constructors.rs diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/mod.rs new file mode 100644 index 0000000..47c51d0 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/mod.rs @@ -0,0 +1,8 @@ +pub mod compiler_phase; +pub mod custom_type_collector; +pub mod final_structure_generator; +pub mod gpu_resource_mngmnt_and_wgsl_generator; +pub mod module_for_rust_usage_cleaner; +pub mod non_mutating_tree_validation; +pub mod typesafe_buffer_builders_generator; +pub mod wgsl_helper_transformer; diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/alter_main_function_for_cpu_usage.rs b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/alter_main_function_for_cpu_usage.rs new file mode 100644 index 0000000..a04a6b8 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/alter_main_function_for_cpu_usage.rs @@ -0,0 +1,123 @@ +use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; +use proc_macro2::Span; +use syn::{FnArg, Ident, ItemFn, visit_mut::VisitMut}; + +pub fn mutate_main_function_for_cpu_usage( + wgsl_shader_module_parsed: &WgslShaderModuleUserPortion, + rust_module_for_cpu: &mut syn::ItemMod, +) { + let mut main_func_mutator = MainFunctionMutator { + wgsl_shader_module_parsed, + }; + main_func_mutator.visit_item_mod_mut(rust_module_for_cpu); +} + +struct MainFunctionMutator<'a> { + wgsl_shader_module_parsed: &'a WgslShaderModuleUserPortion, +} +impl VisitMut for MainFunctionMutator<'_> { + fn visit_item_fn_mut(&mut self, c: &mut syn::ItemFn) { + syn::visit_mut::visit_item_fn_mut(self, c); + let name = c.sig.ident.to_string(); + if name != "main" { + return; + } + alter_main_function_for_cpu_usage(self.wgsl_shader_module_parsed, c); + } +} + +fn alter_main_function_for_cpu_usage( + wgsl_shader_module_parsed: &WgslShaderModuleUserPortion, + main_func: &mut ItemFn, +) { + add_params_to_main(wgsl_shader_module_parsed, main_func); + add_array_lengths_to_main(wgsl_shader_module_parsed, main_func); +} + +fn add_params_to_main( + wgsl_shader_module_parsed: &WgslShaderModuleUserPortion, + + main_func: &mut ItemFn, +) { + // add the uniform and array inputs and outputs to the main function parameters + wgsl_shader_module_parsed + .uniforms + .iter() + .for_each(|uniform| { + // turn into a PatType + let param_name = Ident::new(uniform.name.uniform().as_str(), Span::call_site()); + let param_type = Ident::new(uniform.name.name().as_str(), Span::call_site()); + // let r: FnArg = syn::parse_quote!(#param_name : #param_type); + let r: FnArg = syn::parse_quote!( #param_name : #param_type ); + + main_func.sig.inputs.push(r); + }); + wgsl_shader_module_parsed + .input_arrays + .iter() + .for_each(|array| { + // turn into a PatType + let param_name = Ident::new( + array.item_type.name.input_array().as_str(), + Span::call_site(), + ); + let param_type = Ident::new(array.item_type.name.name().as_str(), Span::call_site()); + let r: FnArg = syn::parse_quote!(#param_name : Vec<#param_type>); + main_func.sig.inputs.push(r); + }); + wgsl_shader_module_parsed + .output_arrays + .iter() + .for_each(|array| { + // turn into a PatType + let param_name = Ident::new( + array.item_type.name.output_array().as_str(), + Span::call_site(), + ); + let param_type = Ident::new(array.item_type.name.name().as_str(), Span::call_site()); + let r: FnArg = syn::parse_quote!(mut #param_name : &mut Vec<#param_type>); + main_func.sig.inputs.push(r); + }); +} + +fn add_array_lengths_to_main( + wgsl_shader_module_parsed: &WgslShaderModuleUserPortion, + + main_func: &mut ItemFn, +) { + // add the array lengths to the main function body before anything else + wgsl_shader_module_parsed + .input_arrays + .iter() + .for_each(|array| { + let var_name = Ident::new( + array.item_type.name.input_array_length().as_str(), + Span::call_site(), + ); + let input_array_name = Ident::new( + array.item_type.name.input_array().as_str(), + Span::call_site(), + ); + main_func.block.stmts.insert( + 0, + syn::parse_quote!(let #var_name = #input_array_name .len();), + ); + }); + wgsl_shader_module_parsed + .output_arrays + .iter() + .for_each(|array| { + let var_name = Ident::new( + array.item_type.name.output_array_length().as_str(), + Span::call_site(), + ); + let output_array_name = Ident::new( + array.item_type.name.output_array().as_str(), + Span::call_site(), + ); + main_func.block.stmts.insert( + 0, + syn::parse_quote!(let #var_name = #output_array_name .len();), + ); + }) +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/compiler_phase.rs b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/compiler_phase.rs new file mode 100644 index 0000000..e14573d --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/compiler_phase.rs @@ -0,0 +1,21 @@ +use crate::pipeline::{compilation_unit::CompilationUnit, phases::compiler_phase::CompilerPhase}; + +use super::{ + alter_main_function_for_cpu_usage::mutate_main_function_for_cpu_usage, + make_types_pod::make_types_pod, make_types_public::make_types_public, + remove_internal_attributes::remove_internal_attributes, +}; + +/// alter the original rust code slightly to ensure it can be safely used by the user without interferring with the GPU side of the library +pub struct ModuleForRustUsageCleaner; + +impl CompilerPhase for ModuleForRustUsageCleaner { + fn execute(&self, input: &mut CompilationUnit) { + let mut m = input.rust_module_for_cpu().clone(); + mutate_main_function_for_cpu_usage(input.wgsl_module_user_portion(), &mut m); + remove_internal_attributes(&mut m); + make_types_pod(&mut m); + make_types_public(&mut m); + input.set_rust_module_for_cpu(m.clone()); + } +} diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/make_types_pod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/make_types_pod.rs similarity index 58% rename from bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/make_types_pod.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/make_types_pod.rs index 132a403..c5baeaa 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/make_types_pod.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/make_types_pod.rs @@ -1,13 +1,18 @@ use syn::{ItemStruct, parse_quote, visit_mut::VisitMut}; -pub struct MakeTypesPodTransformer; +pub fn make_types_pod(input: &mut syn::ItemMod) { + let mut transformer = MakeTypesPodTransformer; + transformer.visit_item_mod_mut(input); +} + +/** +Add the following as attributes: +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +*/ +struct MakeTypesPodTransformer; impl VisitMut for MakeTypesPodTransformer { - /** - Add the following as attributes: - #[repr(C)] - #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] - */ fn visit_item_struct_mut(&mut self, i: &mut ItemStruct) { syn::visit_mut::visit_item_struct_mut(self, i); i.attrs.push(parse_quote! { diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/make_types_public.rs b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/make_types_public.rs similarity index 73% rename from bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/make_types_public.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/make_types_public.rs index fb6fcba..5ed179a 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/make_types_public.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/make_types_public.rs @@ -1,6 +1,11 @@ use syn::{ItemStruct, ItemType, Visibility, spanned::Spanned, token::Pub, visit_mut::VisitMut}; -pub struct MakeTypesPublicTransformer; +pub fn make_types_public(input: &mut syn::ItemMod) { + let mut transformer = MakeTypesPublicTransformer; + transformer.visit_item_mod_mut(input); +} + +struct MakeTypesPublicTransformer; impl VisitMut for MakeTypesPublicTransformer { fn visit_item_type_mut(&mut self, i: &mut ItemType) { diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/mod.rs new file mode 100644 index 0000000..e5b4d5e --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/mod.rs @@ -0,0 +1,5 @@ +mod alter_main_function_for_cpu_usage; +pub mod compiler_phase; +mod make_types_pod; +mod make_types_public; +mod remove_internal_attributes; diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/remove_internal_attributes.rs b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/remove_internal_attributes.rs new file mode 100644 index 0000000..fcea047 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/module_for_rust_usage_cleaner/remove_internal_attributes.rs @@ -0,0 +1,115 @@ +use syn::visit_mut::VisitMut; +const INTERNAL_ATTRIBUTE_NAMES: [&str; 4] = [ + "wgsl_config", + "wgsl_input_array", + "wgsl_output_array", + "wgsl_output_vec", +]; + +pub fn remove_internal_attributes(input: &mut syn::ItemMod) { + let mut transformer = InternalAttributesRemover; + transformer.visit_item_mod_mut(input); +} +struct InternalAttributesRemover; + +impl VisitMut for InternalAttributesRemover { + fn visit_item_mut(&mut self, i: &mut syn::Item) { + syn::visit_mut::visit_item_mut(self, i); + match i { + syn::Item::Struct(item_struct) => { + item_struct.attrs.retain(|attr| { + !INTERNAL_ATTRIBUTE_NAMES + .iter() + .any(|name| attr.path().is_ident(name)) + }); + } + syn::Item::Fn(item_fn) => { + item_fn.attrs.retain(|attr| { + !INTERNAL_ATTRIBUTE_NAMES + .iter() + .any(|name| attr.path().is_ident(name)) + }); + } + syn::Item::Enum(item_enum) => { + item_enum.attrs.retain(|attr| { + !INTERNAL_ATTRIBUTE_NAMES + .iter() + .any(|name| attr.path().is_ident(name)) + }); + } + syn::Item::Type(item_type) => { + item_type.attrs.retain(|attr| { + !INTERNAL_ATTRIBUTE_NAMES + .iter() + .any(|name| attr.path().is_ident(name)) + }); + } + syn::Item::Const(item_const) => { + item_const.attrs.retain(|attr| { + !INTERNAL_ATTRIBUTE_NAMES + .iter() + .any(|name| attr.path().is_ident(name)) + }); + } + syn::Item::Trait(item_trait) => { + item_trait.attrs.retain(|attr| { + !INTERNAL_ATTRIBUTE_NAMES + .iter() + .any(|name| attr.path().is_ident(name)) + }); + } + syn::Item::Impl(item_impl) => { + item_impl.attrs.retain(|attr| { + !INTERNAL_ATTRIBUTE_NAMES + .iter() + .any(|name| attr.path().is_ident(name)) + }); + } + syn::Item::Mod(item_mod) => { + item_mod.attrs.retain(|attr| { + !INTERNAL_ATTRIBUTE_NAMES + .iter() + .any(|name| attr.path().is_ident(name)) + }); + } + + _ => {} + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use quote::ToTokens; + use syn::parse_quote; + #[test] + fn test_remove_internal_attributes() { + let mut input: syn::ItemMod = parse_quote! { + pub mod m{ + #[wgsl_config] + #[wgsl_input_array] + #[wgsl_output_array] + #[wgsl_output_vec] + #[valid] + #[wgsl_config] + #[wgsl_input_array] + #[wgsl_output_array] + #[wgsl_output_vec] + struct Something {} + } + }; + let expected: syn::ItemMod = parse_quote! { + pub mod m{ + #[valid] + struct Something {} + } + }; + let mut transformer = InternalAttributesRemover; + transformer.visit_item_mod_mut(&mut input); + assert_eq!( + input.to_token_stream().to_string(), + expected.to_token_stream().to_string() + ); + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/compiler_phase.rs b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/compiler_phase.rs new file mode 100644 index 0000000..32151e6 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/compiler_phase.rs @@ -0,0 +1,16 @@ +use crate::pipeline::{compilation_unit::CompilationUnit, phases::compiler_phase::CompilerPhase}; + +use super::validate_no_doc_comments::validate_no_doc_comments; +use super::validate_no_iter_pos_assignments::validate_no_iter_pos_assignments; +use super::validate_use_statements::validate_use_statements; + +/// any sort of input validation that can be done on the original tree that doesn't require mutation +pub struct NonMutatingTreeValidation; + +impl CompilerPhase for NonMutatingTreeValidation { + fn execute(&self, input: &mut CompilationUnit) { + validate_no_doc_comments(input.original_rust_module()); + validate_no_iter_pos_assignments(input.original_rust_module()); + validate_use_statements(input.original_rust_module()); + } +} diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/mod.rs new file mode 100644 index 0000000..9577b8f --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/mod.rs @@ -0,0 +1,4 @@ +pub mod compiler_phase; +mod validate_no_doc_comments; +mod validate_no_iter_pos_assignments; +mod validate_use_statements; diff --git a/bevy_gpu_compute_macro/src/transformer/remove_doc_comments.rs b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_no_doc_comments.rs similarity index 67% rename from bevy_gpu_compute_macro/src/transformer/remove_doc_comments.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_no_doc_comments.rs index 7b9f095..7d0b4a3 100644 --- a/bevy_gpu_compute_macro/src/transformer/remove_doc_comments.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_no_doc_comments.rs @@ -1,8 +1,12 @@ use proc_macro_error::abort; use syn::{spanned::Spanned, visit::Visit}; -pub struct DocCommentRemover {} -impl Visit<'_> for DocCommentRemover { +pub fn validate_no_doc_comments(original_rust_module: &syn::ItemMod) { + let mut checker = DocCommentChecker {}; + checker.visit_item_mod(original_rust_module); +} +struct DocCommentChecker {} +impl Visit<'_> for DocCommentChecker { fn visit_attribute(&mut self, attr: &syn::Attribute) { syn::visit::visit_attribute(self, attr); if let Some(ident) = attr.path().get_ident() { diff --git a/bevy_gpu_compute_macro/src/transformer/module_parser/validate_no_global_id_assignments.rs b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_no_iter_pos_assignments.rs similarity index 61% rename from bevy_gpu_compute_macro/src/transformer/module_parser/validate_no_global_id_assignments.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_no_iter_pos_assignments.rs index 7a67133..874cf3f 100644 --- a/bevy_gpu_compute_macro/src/transformer/module_parser/validate_no_global_id_assignments.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_no_iter_pos_assignments.rs @@ -1,23 +1,21 @@ use proc_macro_error::abort; use syn::{ExprAssign, spanned::Spanned, visit::Visit}; -use crate::state::ModuleTransformState; - -pub fn check_module_for_global_id_assignment(state: &mut ModuleTransformState) { - let mut checker = GlobalIdAssignmentChecker {}; - checker.visit_item_mod(&state.rust_module); +pub fn validate_no_iter_pos_assignments(original_rust_module: &syn::ItemMod) { + let mut checker = IterPosAssignmentChecker {}; + checker.visit_item_mod(original_rust_module); } -struct GlobalIdAssignmentChecker {} -impl<'ast> Visit<'ast> for GlobalIdAssignmentChecker { +struct IterPosAssignmentChecker {} +impl<'ast> Visit<'ast> for IterPosAssignmentChecker { fn visit_expr_assign(&mut self, c: &'ast syn::ExprAssign) { syn::visit::visit_expr_assign(self, c); - check_for_global_id_assignment(c); + check_for_iter_pos_assignment(c); } } -fn check_for_global_id_assignment(assign: &ExprAssign) { - // Check direct assignments to global_id +fn check_for_iter_pos_assignment(assign: &ExprAssign) { + // Check direct assignments to iter_pos if let syn::Expr::Path(path) = &*assign.left { if let Some(ident) = path.path.segments.last() { if ident.ident == "iter_pos" { @@ -25,7 +23,7 @@ fn check_for_global_id_assignment(assign: &ExprAssign) { } } } - // Check field assignments like global_id.x + // Check field assignments like iter_pos.x if let syn::Expr::Field(field) = &*assign.left { if let syn::Expr::Path(path) = &*field.base { if let Some(ident) = path.path.segments.last() { diff --git a/bevy_gpu_compute_macro/src/transformer/module_parser/use_statements.rs b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_use_statements.rs similarity index 71% rename from bevy_gpu_compute_macro/src/transformer/module_parser/use_statements.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_use_statements.rs index 5c9ca98..b26f49b 100644 --- a/bevy_gpu_compute_macro/src/transformer/module_parser/use_statements.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/non_mutating_tree_validation/validate_use_statements.rs @@ -1,27 +1,22 @@ use proc_macro_error::abort; -use quote::{ToTokens, quote}; -use syn::{Item, ItemUse, spanned::Spanned, visit::Visit, visit_mut::VisitMut}; - -use crate::state::ModuleTransformState; +use quote::ToTokens; +use syn::{Item, ItemMod, ItemUse, spanned::Spanned, visit::Visit}; const VALID_USE_STATEMENT_PATHS: [&str; 3] = ["wgsl_helpers", "bevy_gpu_compute", "bevy_gpu_compute_macro"]; -pub fn handle_use_statements(state: &mut ModuleTransformState) { +pub fn validate_use_statements(original_rust_module: &ItemMod) { let mut handler = UseStatementHandler {}; - handler.visit_item_mod_mut(&mut state.rust_module); - handler.visit_item_mod_mut(&mut state.rust_module_for_cpu); + handler.visit_item_mod(original_rust_module); } struct UseStatementHandler {} -impl VisitMut for UseStatementHandler { - fn visit_item_mut(&mut self, i: &mut Item) { - syn::visit_mut::visit_item_mut(self, i); +impl Visit<'_> for UseStatementHandler { + fn visit_item(&mut self, i: &Item) { + syn::visit::visit_item(self, i); if let Item::Use(use_stmt) = i { validate_use_statement(use_stmt); - // remove the use statement - *i = Item::Verbatim(quote! {}) } } } diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/compiler_phase.rs b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/compiler_phase.rs new file mode 100644 index 0000000..5995e9e --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/compiler_phase.rs @@ -0,0 +1,26 @@ +use crate::pipeline::{compilation_unit::CompilationUnit, phases::compiler_phase::CompilerPhase}; +use quote::quote; + +use super::{ + config_input_data_builder::create_config_input_data_builder, + input_data_builder::create_input_data_builder, + max_output_lengths_builder::create_max_output_lengths_builder, + output_data_builder::create_output_data_builder, +}; + +pub struct TypesafeBufferBuildersGenerator; + +impl CompilerPhase for TypesafeBufferBuildersGenerator { + fn execute(&self, input: &mut CompilationUnit) { + let config_input = create_config_input_data_builder(input.custom_types()); + let array_input = create_input_data_builder(input.custom_types()); + let array_output = create_output_data_builder(input.custom_types()); + let output_lengths = create_max_output_lengths_builder(input.custom_types()); + input.set_typesafe_buffer_builders(quote! { + #config_input + #array_input + #array_output + #output_lengths + }); + } +} diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/config_input_data_builder.rs b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/config_input_data_builder.rs similarity index 84% rename from bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/config_input_data_builder.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/config_input_data_builder.rs index 6dd54a4..56460f9 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/config_input_data_builder.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/config_input_data_builder.rs @@ -2,15 +2,15 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::Ident; -use crate::{ - state::ModuleTransformState, - transformer::custom_types::{ +use crate::pipeline::{ + phases::custom_type_collector::custom_type::CustomType, + phases::custom_type_collector::{ custom_type::CustomTypeKind, custom_type_idents::CustomTypeIdents, }, }; -pub fn create_config_input_data_builder(state: &ModuleTransformState) -> TokenStream { - let methods = get_methods(state); +pub fn create_config_input_data_builder(custom_types: &[CustomType]) -> TokenStream { + let methods = get_methods(custom_types); quote! { pub struct ConfigInputDataBuilder { bytes_per_wgsl_config_type_name: HashMap>, @@ -40,11 +40,8 @@ pub fn create_config_input_data_builder(state: &ModuleTransformState) -> TokenSt } } } -fn get_methods(state: &ModuleTransformState) -> TokenStream { - state - .custom_types - .as_ref() - .unwrap() +fn get_methods(custom_types: &[CustomType]) -> TokenStream { + custom_types .iter() .filter(|c| c.kind == CustomTypeKind::Uniform) .map(|c| single_method(c.name.clone())) diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/input_data_builder.rs b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/input_data_builder.rs similarity index 86% rename from bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/input_data_builder.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/input_data_builder.rs index 7a0b811..4c0a426 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/input_data_builder.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/input_data_builder.rs @@ -2,15 +2,15 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::Ident; -use crate::{ - state::ModuleTransformState, - transformer::custom_types::{ +use crate::pipeline::{ + phases::custom_type_collector::custom_type::CustomType, + phases::custom_type_collector::{ custom_type::CustomTypeKind, custom_type_idents::CustomTypeIdents, }, }; -pub fn create_input_data_builder(state: &ModuleTransformState) -> TokenStream { - let methods = get_methods(state); +pub fn create_input_data_builder(custom_types: &[CustomType]) -> TokenStream { + let methods = get_methods(custom_types); quote! { pub struct InputDataBuilder { bytes_per_wgsl_input_type_name: HashMap>, @@ -42,11 +42,8 @@ pub fn create_input_data_builder(state: &ModuleTransformState) -> TokenStream { } } } -fn get_methods(state: &ModuleTransformState) -> TokenStream { - state - .custom_types - .as_ref() - .unwrap() +fn get_methods(custom_types: &[CustomType]) -> TokenStream { + custom_types .iter() .filter(|c| c.kind == CustomTypeKind::InputArray) .map(|c| single_method(c.name.clone())) diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/max_output_lengths_builder.rs b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/max_output_lengths_builder.rs similarity index 79% rename from bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/max_output_lengths_builder.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/max_output_lengths_builder.rs index c186fc4..8a2be9f 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/max_output_lengths_builder.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/max_output_lengths_builder.rs @@ -2,15 +2,13 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::Ident; -use crate::{ - state::ModuleTransformState, - transformer::custom_types::{ - custom_type::CustomTypeKind, custom_type_idents::CustomTypeIdents, - }, +use crate::pipeline::phases::custom_type_collector::{ + custom_type::{CustomType, CustomTypeKind}, + custom_type_idents::CustomTypeIdents, }; -pub fn create_max_output_lengths_builder(state: &ModuleTransformState) -> TokenStream { - let methods = get_methods(state); +pub fn create_max_output_lengths_builder(custom_types: &[CustomType]) -> TokenStream { + let methods = get_methods(custom_types); quote! { pub struct MaxOutputLengthsBuilder { length_per_wgsl_output_type_name: HashMap, @@ -39,11 +37,8 @@ pub fn create_max_output_lengths_builder(state: &ModuleTransformState) -> TokenS } } } -fn get_methods(state: &ModuleTransformState) -> TokenStream { - state - .custom_types - .as_ref() - .unwrap() +fn get_methods(custom_types: &[CustomType]) -> TokenStream { + custom_types .iter() .filter(|c| c.kind == CustomTypeKind::OutputArray || c.kind == CustomTypeKind::OutputVec) .map(|c| single_method(c.name.clone())) diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/mod.rs new file mode 100644 index 0000000..31705ee --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/mod.rs @@ -0,0 +1,8 @@ +/** +These builders are compiled to allow the user to more easily create the required inputs for their gpu task, where everything is completely type safe according to the custom types they have defined +*/ +pub mod compiler_phase; +mod config_input_data_builder; +mod input_data_builder; +mod max_output_lengths_builder; +mod output_data_builder; diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/output_data_builder.rs b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/output_data_builder.rs similarity index 85% rename from bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/output_data_builder.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/output_data_builder.rs index ed6134f..fe9b3cb 100644 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/output_data_builder.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/typesafe_buffer_builders_generator/output_data_builder.rs @@ -2,15 +2,13 @@ use proc_macro2::TokenStream; use quote::quote; use syn::Ident; -use crate::{ - state::ModuleTransformState, - transformer::custom_types::{ - custom_type::CustomTypeKind, custom_type_idents::CustomTypeIdents, - }, +use crate::pipeline::phases::custom_type_collector::{ + custom_type::{CustomType, CustomTypeKind}, + custom_type_idents::CustomTypeIdents, }; -pub fn create_output_data_builder(state: &ModuleTransformState) -> TokenStream { - let (fields, init_fields, converters) = get_fields_init_fields_and_converters(state); +pub fn create_output_data_builder(custom_types: &[CustomType]) -> TokenStream { + let (fields, init_fields, converters) = get_fields_init_fields_and_converters(custom_types); quote! { pub struct OutputDataBuilder { #fields @@ -36,12 +34,9 @@ pub fn create_output_data_builder(state: &ModuleTransformState) -> TokenStream { } } fn get_fields_init_fields_and_converters( - state: &ModuleTransformState, + custom_types: &[CustomType], ) -> (TokenStream, TokenStream, TokenStream) { - state - .custom_types - .as_ref() - .unwrap() + custom_types .iter() .filter(|c| c.kind == CustomTypeKind::OutputArray || c.kind == CustomTypeKind::OutputVec) .map(|c| single_field_init_field_and_converter(c.name.clone())) diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/category.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/category.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/category.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/category.rs diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/compiler_phase.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/compiler_phase.rs new file mode 100644 index 0000000..b4839a2 --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/compiler_phase.rs @@ -0,0 +1,16 @@ +use crate::pipeline::{compilation_unit::CompilationUnit, phases::compiler_phase::CompilerPhase}; + +use super::run::transform_wgsl_helper_methods; + +pub struct WgslHelperTransformer; + +impl CompilerPhase for WgslHelperTransformer { + fn execute(&self, input: &mut CompilationUnit) { + let mut mod_for_gpu = input.original_rust_module().clone(); + let mut mod_for_cpu = input.original_rust_module().clone(); + transform_wgsl_helper_methods(input.custom_types(), &mut mod_for_gpu, false); + transform_wgsl_helper_methods(input.custom_types(), &mut mod_for_cpu, true); + input.set_rust_module_for_cpu(mod_for_cpu); + input.set_rust_module_for_gpu(mod_for_gpu); + } +} diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/erroneous_usage_finder.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/erroneous_usage_finder.rs similarity index 93% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/erroneous_usage_finder.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/erroneous_usage_finder.rs index 18ae21c..a3178cf 100644 --- a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/erroneous_usage_finder.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/erroneous_usage_finder.rs @@ -3,7 +3,7 @@ use syn::{ visit::{self, Visit}, }; -use crate::transformer::custom_types::custom_type::CustomType; +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; use super::parse::parse_possible_wgsl_helper; diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/helper_method.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/helper_method.rs similarity index 84% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/helper_method.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/helper_method.rs index 47114b6..8c5c00a 100644 --- a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/helper_method.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/helper_method.rs @@ -1,6 +1,6 @@ use syn::Expr; -use crate::transformer::custom_types::custom_type::CustomType; +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; use super::{ category::WgslHelperCategory, method_name::WgslHelperMethodName, diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/matcher.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/matcher.rs similarity index 97% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/matcher.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/matcher.rs index b72c964..916f04e 100644 --- a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/matcher.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/matcher.rs @@ -1,6 +1,6 @@ -use crate::transformer::{ - custom_types::custom_type::CustomTypeKind, - transform_wgsl_helper_methods::to_expanded_format::ToExpandedFormatMethodKind, +use crate::pipeline::phases::{ + custom_type_collector::custom_type::CustomTypeKind, + wgsl_helper_transformer::to_expanded_format::ToExpandedFormatMethodKind, }; use super::{ diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/method_name.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/method_name.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/method_name.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/method_name.rs diff --git a/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/mod.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/mod.rs new file mode 100644 index 0000000..d3ddf4f --- /dev/null +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/mod.rs @@ -0,0 +1,12 @@ +mod category; +pub mod compiler_phase; +mod erroneous_usage_finder; +mod helper_method; +mod matcher; +mod method_name; +mod parse; +mod run; +mod test; +mod test_for_cpu; +mod to_expanded_format; +mod to_expanded_format_for_cpu; diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/parse.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/parse.rs similarity index 93% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/parse.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/parse.rs index d600c63..d82cf3e 100644 --- a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/parse.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/parse.rs @@ -1,9 +1,7 @@ use syn::{Expr, ExprCall, GenericArgument, PathArguments, Type}; -use crate::transformer::{ - custom_types::custom_type::CustomType, - transform_wgsl_helper_methods::helper_method::WgslHelperMethod, -}; +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; +use crate::pipeline::phases::wgsl_helper_transformer::helper_method::WgslHelperMethod; use super::{ category::WgslHelperCategory, matcher::WgslHelperMethodMatcher, diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/run.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/run.rs similarity index 86% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/run.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/run.rs index d16eb16..578db70 100644 --- a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/run.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/run.rs @@ -6,30 +6,20 @@ use syn::{ visit_mut::{self, VisitMut}, }; -use crate::transformer::{ - custom_types::custom_type::CustomType, - transform_wgsl_helper_methods::{ - helper_method::WgslHelperMethod, to_expanded_format::ToExpandedFormat, - }, -}; +use crate::pipeline::phases::custom_type_collector::custom_type::CustomType; use super::{ - erroneous_usage_finder::ErroneousUsageFinder, parse::parse_possible_wgsl_helper, + erroneous_usage_finder::ErroneousUsageFinder, helper_method::WgslHelperMethod, + parse::parse_possible_wgsl_helper, to_expanded_format::ToExpandedFormat, to_expanded_format_for_cpu::ToExpandedFormatForCpu, }; /// Rust's normal type checking will ensure that these helper functions are using correctly defined types pub fn transform_wgsl_helper_methods( - custom_types: &Option>, + custom_types: &[CustomType], rust_module: &mut ItemMod, for_cpu: bool, ) { - assert!(custom_types.is_some(), "Allowed types must be defined"); - let custom_types = if let Some(ct) = &custom_types { - ct - } else { - panic!("Allowed types must be set before transforming helper functions"); - }; let mut converter = WgslHelperExpressionConverter::new(custom_types, for_cpu); converter.visit_item_mod_mut(rust_module); if !for_cpu { diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/test.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/test.rs similarity index 70% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/test.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/test.rs index e94d7b0..cbb7a86 100644 --- a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/test.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/test.rs @@ -1,11 +1,8 @@ #[cfg(test)] mod tests { - use crate::{ - state::ModuleTransformState, - transformer::{ - custom_types::custom_type::{CustomType, CustomTypeKind}, - transform_wgsl_helper_methods::run::transform_wgsl_helper_methods, - }, + use crate::pipeline::phases::{ + custom_type_collector::custom_type::{CustomType, CustomTypeKind}, + wgsl_helper_transformer::run::transform_wgsl_helper_methods, }; use proc_macro2::TokenStream; @@ -14,7 +11,7 @@ mod tests { #[test] fn test_vec_len() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn main() { let x = WgslVecInput::vec_len::(); @@ -22,15 +19,15 @@ mod tests { } }; let expected_output = "mod test { fn main () { let x = POSITION_INPUT_ARRAY_LENGTH ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); + let custom_types = vec![CustomType::new( &format_ident!("Position"), CustomTypeKind::InputArray, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); - let result = state.rust_module.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( result, expected_output, @@ -44,7 +41,7 @@ mod tests { expected = "WGSL helpers that read from inputs or write to outputs (`bevy_gpu_compute_core::wgsl_helpers`) can only be used inside the main function. It is technically possible to pass in entire input arrays, configs, or output arrays to helper functions, but considering the performance implications, it is not recommended. Instead interact with your inputs and outputs in the main function and pass in only the necessary data to the helper functions." )] fn test_vec_val_only_in_main() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { @@ -52,19 +49,19 @@ mod tests { } } }; - let mut state = ModuleTransformState::empty(input, "".to_string()); + let custom_types = vec![CustomType::new( &format_ident!("Radius"), CustomTypeKind::InputArray, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); } #[test] fn test_vec_val() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn main() { @@ -74,15 +71,14 @@ mod tests { }; let expected_output = "mod test { fn main () { let x = radius_input_array [5] ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("Radius"), CustomTypeKind::InputArray, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); - let result = state.rust_module.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( result, expected_output, @@ -96,7 +92,7 @@ mod tests { expected = "WGSL helpers that read from inputs or write to outputs (`bevy_gpu_compute_core::wgsl_helpers`) can only be used inside the main function. It is technically possible to pass in entire input arrays, configs, or output arrays to helper functions, but considering the performance implications, it is not recommended. Instead interact with your inputs and outputs in the main function and pass in only the necessary data to the helper functions." )] fn test_push_only_in_main() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { WgslOutput::push::(value); @@ -104,18 +100,17 @@ mod tests { } }; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputVec, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); } #[test] fn test_push() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn main() { WgslOutput::push::(value); @@ -124,15 +119,15 @@ mod tests { }; let expected_output = "mod test { fn main () { { let collisionresult_output_array_index = atomicAdd (& collisionresult_counter , 1u) ; if collisionresult_output_array_index < COLLISIONRESULT_OUTPUT_ARRAY_LENGTH { collisionresult_output_array [collisionresult_output_array_index] = value ; } } ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); + let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputVec, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); - let result = state.rust_module.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( @@ -144,7 +139,7 @@ mod tests { #[test] fn test_output_max_len() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { let x = WgslOutput::max_len::(); @@ -154,15 +149,14 @@ mod tests { let expected_output = "mod test { fn example () { let x = COLLISIONRESULT_OUTPUT_ARRAY_LENGTH ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputVec, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); - let result = state.rust_module.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( @@ -174,7 +168,7 @@ mod tests { #[test] fn test_output_len() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { let x = WgslOutput::len::(); @@ -183,15 +177,14 @@ mod tests { }; let expected_output = "mod test { fn example () { let x = collisionresult_counter ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputVec, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); - let result = state.rust_module.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( @@ -206,26 +199,26 @@ mod tests { expected = "WGSL helpers that read from inputs or write to outputs (`bevy_gpu_compute_core::wgsl_helpers`) can only be used inside the main function. It is technically possible to pass in entire input arrays, configs, or output arrays to helper functions, but considering the performance implications, it is not recommended. Instead interact with your inputs and outputs in the main function and pass in only the necessary data to the helper functions." )] fn test_output_set_not_in_main() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { WgslOutput::set::(idx, val); } } }; - let mut state = ModuleTransformState::empty(input, "".to_string()); + let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputArray, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); } #[test] fn test_output_set() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn main() { WgslOutput::set::(idx, val); @@ -235,15 +228,14 @@ mod tests { let expected_output = "mod test { fn main () { collisionresult_output_array [idx] = val ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputArray, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); - let result = state.rust_module.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( @@ -257,7 +249,7 @@ mod tests { expected = "WGSL helpers that read from inputs or write to outputs (`bevy_gpu_compute_core::wgsl_helpers`) can only be used inside the main function. It is technically possible to pass in entire input arrays, configs, or output arrays to helper functions, but considering the performance implications, it is not recommended. Instead interact with your inputs and outputs in the main function and pass in only the necessary data to the helper functions." )] fn test_config_get_outside_main() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { let t = WgslConfigInput::get::(); @@ -265,18 +257,17 @@ mod tests { } }; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("Position"), CustomTypeKind::Uniform, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); } #[test] fn test_config_get() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn main() { let t = WgslConfigInput::get::(); @@ -285,15 +276,14 @@ mod tests { }; let expected_output = "mod test { fn main () { let t = position ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("Position"), CustomTypeKind::Uniform, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module, false); - let result = state.rust_module.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, false); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/test_for_cpu.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/test_for_cpu.rs similarity index 64% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/test_for_cpu.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/test_for_cpu.rs index be1a491..3a68fd7 100644 --- a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/test_for_cpu.rs +++ b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/test_for_cpu.rs @@ -1,11 +1,8 @@ #[cfg(test)] mod tests { - use crate::{ - state::ModuleTransformState, - transformer::{ - custom_types::custom_type::{CustomType, CustomTypeKind}, - transform_wgsl_helper_methods::run::transform_wgsl_helper_methods, - }, + use crate::pipeline::phases::{ + custom_type_collector::custom_type::{CustomType, CustomTypeKind}, + wgsl_helper_transformer::run::transform_wgsl_helper_methods, }; use proc_macro2::TokenStream; @@ -14,7 +11,7 @@ mod tests { #[test] fn test_vec_len() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { let x = WgslVecInput::vec_len::(); @@ -23,15 +20,13 @@ mod tests { }; let expected_output = "mod test { fn example () { let x = position_input_array . len () as u32 ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("Position"), CustomTypeKind::InputArray, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module_for_cpu, true); - let result = state.rust_module_for_cpu.to_token_stream().to_string(); + transform_wgsl_helper_methods(&custom_types, &mut input, true); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( result, expected_output, @@ -42,7 +37,7 @@ mod tests { #[test] fn test_vec_val() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { @@ -53,15 +48,14 @@ mod tests { let expected_output = "mod test { fn example () { let x = radius_input_array [5 as usize] ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("Radius"), CustomTypeKind::InputArray, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module_for_cpu, true); - let result = state.rust_module_for_cpu.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, true); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( result, expected_output, @@ -72,7 +66,7 @@ mod tests { #[test] fn test_push() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { WgslOutput::push::(value); @@ -82,15 +76,15 @@ mod tests { let expected_output = "mod test { fn example () { collisionresult_output_array . push (value) ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); + let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputVec, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module_for_cpu, true); - let result = state.rust_module_for_cpu.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, true); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( @@ -102,7 +96,7 @@ mod tests { #[test] fn test_output_max_len() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { let x = WgslOutput::max_len::(); @@ -112,15 +106,14 @@ mod tests { let expected_output = "mod test { fn example () { let x = collisionresult_output_array . len () as u32 ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputVec, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module_for_cpu, true); - let result = state.rust_module_for_cpu.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, true); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( @@ -132,7 +125,7 @@ mod tests { #[test] fn test_output_len() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { let x = WgslOutput::len::(); @@ -142,15 +135,14 @@ mod tests { let expected_output = "mod test { fn example () { let x = collisionresult_output_array . len () as u32 ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputVec, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module_for_cpu, true); - let result = state.rust_module_for_cpu.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, true); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( @@ -162,7 +154,7 @@ mod tests { #[test] fn test_output_set() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { WgslOutput::set::(idx, val); @@ -172,15 +164,14 @@ mod tests { let expected_output = "mod test { fn example () { collisionresult_output_array [idx as usize] = val ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("CollisionResult"), CustomTypeKind::OutputArray, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module_for_cpu, true); - let result = state.rust_module_for_cpu.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, true); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( @@ -191,7 +182,7 @@ mod tests { } #[test] fn test_config_get() { - let input: ItemMod = parse_quote! { + let mut input: ItemMod = parse_quote! { mod test { fn example() { let t = WgslConfigInput::get::(); @@ -200,15 +191,14 @@ mod tests { }; let expected_output = "mod test { fn example () { let t = position ; } }"; - let mut state = ModuleTransformState::empty(input, "".to_string()); let custom_types = vec![CustomType::new( &format_ident!("Position"), CustomTypeKind::Uniform, TokenStream::new(), )]; - state.custom_types = Some(custom_types); - transform_wgsl_helper_methods(&state.custom_types, &mut state.rust_module_for_cpu, true); - let result = state.rust_module_for_cpu.to_token_stream().to_string(); + + transform_wgsl_helper_methods(&custom_types, &mut input, true); + let result = input.to_token_stream().to_string(); println!("{}", result); assert_eq!( diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/to_expanded_format.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/to_expanded_format.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/to_expanded_format.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/to_expanded_format.rs diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/to_expanded_format_for_cpu.rs b/bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/to_expanded_format_for_cpu.rs similarity index 100% rename from bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/to_expanded_format_for_cpu.rs rename to bevy_gpu_compute_macro/src/pipeline/phases/wgsl_helper_transformer/to_expanded_format_for_cpu.rs diff --git a/bevy_gpu_compute_macro/src/state.rs b/bevy_gpu_compute_macro/src/state.rs deleted file mode 100644 index 2c997b4..0000000 --- a/bevy_gpu_compute_macro/src/state.rs +++ /dev/null @@ -1,32 +0,0 @@ -use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; -use syn::ItemMod; - -use crate::transformer::custom_types::custom_type::CustomType; - -pub struct ModuleTransformState { - _original_content: String, - pub rust_module: ItemMod, - pub rust_module_for_cpu: ItemMod, - pub custom_types: Option>, - pub module_visibility: Option, - pub module_ident: Option, - pub result: WgslShaderModuleUserPortion, - pub result_for_cpu: WgslShaderModuleUserPortion, -} -impl ModuleTransformState { - pub fn empty(rust_module: ItemMod, content: String) -> Self { - Self { - _original_content: content, - rust_module: rust_module.clone(), - rust_module_for_cpu: rust_module.clone(), - custom_types: None, - module_visibility: None, - module_ident: None, - result: WgslShaderModuleUserPortion::empty(), - result_for_cpu: WgslShaderModuleUserPortion::empty(), - } - } - pub fn get_original_content(&self) -> String { - self._original_content.clone() - } -} diff --git a/bevy_gpu_compute_macro/src/transformer/mod.rs b/bevy_gpu_compute_macro/src/transformer/mod.rs deleted file mode 100644 index ccc2f12..0000000 --- a/bevy_gpu_compute_macro/src/transformer/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod allowed_types; -pub mod custom_types; -pub mod module_parser; -pub mod output; -pub mod remove_doc_comments; -pub mod to_wgsl_syntax; -pub mod transform_wgsl_helper_methods; diff --git a/bevy_gpu_compute_macro/src/transformer/module_parser/constants.rs b/bevy_gpu_compute_macro/src/transformer/module_parser/constants.rs deleted file mode 100644 index bdcba24..0000000 --- a/bevy_gpu_compute_macro/src/transformer/module_parser/constants.rs +++ /dev/null @@ -1,72 +0,0 @@ -use bevy_gpu_compute_core::wgsl::shader_sections::{ - WgslConstAssignment, WgslShaderModuleSectionCode, -}; -use quote::ToTokens; -use syn::{ItemConst, visit::Visit}; - -use crate::{state::ModuleTransformState, transformer::to_wgsl_syntax::convert_file_to_wgsl}; - -pub fn find_constants(state: &mut ModuleTransformState) { - let rust_module = state.rust_module.clone(); - let mut extractor = ConstantsExtractor::new(state, false); - extractor.visit_item_mod(&rust_module); - let module_for_cpu = state.rust_module_for_cpu.clone(); - let mut extractor_for_cpu = ConstantsExtractor::new(state, true); - extractor_for_cpu.visit_item_mod(&module_for_cpu); - state.rust_module = rust_module; -} - -struct ConstantsExtractor<'a> { - state: &'a mut ModuleTransformState, - for_cpu: bool, -} - -impl<'ast> Visit<'ast> for ConstantsExtractor<'ast> { - fn visit_item_const(&mut self, c: &'ast syn::ItemConst) { - syn::visit::visit_item_const(self, c); - if self.for_cpu { - self.state - .result_for_cpu - .static_consts - .push(parse_const_assignment(c, self.state, self.for_cpu)); - } else { - self.state.result.static_consts.push(parse_const_assignment( - c, - self.state, - self.for_cpu, - )); - } - } -} - -impl<'ast> ConstantsExtractor<'ast> { - pub fn new(state: &'ast mut ModuleTransformState, for_cpu: bool) -> Self { - ConstantsExtractor { state, for_cpu } - } -} - -fn parse_const_assignment( - constant: &ItemConst, - state: &ModuleTransformState, - for_cpu: bool, -) -> WgslConstAssignment { - if !for_cpu { - WgslConstAssignment { - code: WgslShaderModuleSectionCode { - rust_code: constant.to_token_stream().to_string(), - wgsl_code: convert_file_to_wgsl( - constant.to_token_stream(), - state, - "const".to_string(), - ), - }, - } - } else { - WgslConstAssignment { - code: WgslShaderModuleSectionCode { - rust_code: constant.to_token_stream().to_string(), - wgsl_code: "".to_string(), - }, - } - } -} diff --git a/bevy_gpu_compute_macro/src/transformer/module_parser/divide_custom_types.rs b/bevy_gpu_compute_macro/src/transformer/module_parser/divide_custom_types.rs deleted file mode 100644 index ceb03b2..0000000 --- a/bevy_gpu_compute_macro/src/transformer/module_parser/divide_custom_types.rs +++ /dev/null @@ -1,89 +0,0 @@ -use bevy_gpu_compute_core::wgsl::shader_sections::{WgslInputArray, WgslOutputArray}; -use proc_macro_error::abort; - -use crate::{ - state::ModuleTransformState, - transformer::custom_types::custom_type::{CustomType, CustomTypeKind}, -}; -use quote::quote; - -pub fn divide_custom_types_by_category(state: &mut ModuleTransformState) { - let custom_types = if let Some(ct) = state.custom_types.clone() { - ct - } else { - abort!( - state.rust_module.ident.span(), - "Allowed types must be set before dividing custom types" - ); - }; - for custom_type in custom_types.iter() { - match custom_type.kind { - CustomTypeKind::GpuOnlyHelperType => { - state - .result - .helper_types - .push(custom_type.clone().into_wgsl_type(state)); - state - .result_for_cpu - .helper_types - .push(custom_type.clone().into_wgsl_type(state)); - } - CustomTypeKind::InputArray => { - state.custom_types.as_mut().unwrap().push(CustomType::new( - &custom_type.name.input_array_length(), - CustomTypeKind::ArrayLengthVariable, - quote!(), - )); - state.result.input_arrays.push(WgslInputArray { - item_type: custom_type.clone().into_wgsl_type(state), - }); - state.result_for_cpu.input_arrays.push(WgslInputArray { - item_type: custom_type.clone().into_wgsl_type(state), - }); - } - CustomTypeKind::OutputArray => { - state.custom_types.as_mut().unwrap().push(CustomType::new( - &custom_type.name.output_array_length(), - CustomTypeKind::ArrayLengthVariable, - quote!(), - )); - state.result.output_arrays.push(WgslOutputArray { - item_type: custom_type.clone().into_wgsl_type(state), - atomic_counter_name: None, - }); - state.result_for_cpu.output_arrays.push(WgslOutputArray { - item_type: custom_type.clone().into_wgsl_type(state), - atomic_counter_name: None, - }); - } - CustomTypeKind::OutputVec => { - state.custom_types.as_mut().unwrap().push(CustomType::new( - &custom_type.name.output_array_length(), - CustomTypeKind::ArrayLengthVariable, - quote!(), - )); - state.result.output_arrays.push(WgslOutputArray { - item_type: custom_type.clone().into_wgsl_type(state), - atomic_counter_name: Some(custom_type.name.counter().to_string()), - }); - state.result_for_cpu.output_arrays.push(WgslOutputArray { - item_type: custom_type.clone().into_wgsl_type(state), - atomic_counter_name: Some(custom_type.name.counter().to_string()), - }); - } - CustomTypeKind::Uniform => { - state - .result - .uniforms - .push(custom_type.clone().into_wgsl_type(state)); - state - .result_for_cpu - .uniforms - .push(custom_type.clone().into_wgsl_type(state)); - } - CustomTypeKind::ArrayLengthVariable => { - // do nothing - } - } - } -} diff --git a/bevy_gpu_compute_macro/src/transformer/module_parser/helper_functions.rs b/bevy_gpu_compute_macro/src/transformer/module_parser/helper_functions.rs deleted file mode 100644 index 1928958..0000000 --- a/bevy_gpu_compute_macro/src/transformer/module_parser/helper_functions.rs +++ /dev/null @@ -1,61 +0,0 @@ -use bevy_gpu_compute_core::wgsl::shader_sections::{WgslFunction, WgslShaderModuleSectionCode}; -use quote::ToTokens; -use syn::{ItemFn, visit::Visit}; - -use crate::{state::ModuleTransformState, transformer::to_wgsl_syntax::convert_file_to_wgsl}; - -pub fn find_helper_functions(state: &mut ModuleTransformState) { - let module = state.rust_module.clone(); - let mut extractor = HelperFunctionsExtractor::new(state, false); - extractor.visit_item_mod(&module); - let module_for_cpu = state.rust_module_for_cpu.clone(); - let mut extractor_for_cpu = HelperFunctionsExtractor::new(state, true); - extractor_for_cpu.visit_item_mod(&module_for_cpu); - state.rust_module = module; -} - -struct HelperFunctionsExtractor<'a> { - state: &'a mut ModuleTransformState, - for_cpu: bool, -} - -impl<'ast> Visit<'ast> for HelperFunctionsExtractor<'ast> { - fn visit_item_fn(&mut self, c: &'ast syn::ItemFn) { - syn::visit::visit_item_fn(self, c); - if c.sig.ident == "main" { - return; - } - // ident from string - if self.for_cpu { - self.state - .result_for_cpu - .helper_functions - .push(parse_fn(c, self.state, self.for_cpu)); - } else { - self.state - .result - .helper_functions - .push(parse_fn(c, self.state, self.for_cpu)); - } - } -} - -impl<'ast> HelperFunctionsExtractor<'ast> { - pub fn new(state: &'ast mut ModuleTransformState, for_cpu: bool) -> Self { - HelperFunctionsExtractor { state, for_cpu } - } -} - -fn parse_fn(func: &ItemFn, state: &ModuleTransformState, for_cpu: bool) -> WgslFunction { - WgslFunction { - code: WgslShaderModuleSectionCode { - rust_code: func.to_token_stream().to_string(), - wgsl_code: if !for_cpu { - convert_file_to_wgsl(func.to_token_stream(), state, "helper fn".to_string()) - } else { - "".to_string() - }, - }, - name: func.sig.ident.to_string(), - } -} diff --git a/bevy_gpu_compute_macro/src/transformer/module_parser/lib.rs b/bevy_gpu_compute_macro/src/transformer/module_parser/lib.rs deleted file mode 100644 index d65fd8a..0000000 --- a/bevy_gpu_compute_macro/src/transformer/module_parser/lib.rs +++ /dev/null @@ -1,28 +0,0 @@ -use proc_macro_error::abort; -use quote::ToTokens; - -use crate::state::ModuleTransformState; - -use super::constants::find_constants; -use super::divide_custom_types::divide_custom_types_by_category; -use super::helper_functions::find_helper_functions; -use super::main_function::parse_main_function; -use super::use_statements::handle_use_statements; -use super::validate_no_global_id_assignments::check_module_for_global_id_assignment; - -pub fn parse_shader_module(state: &mut ModuleTransformState) { - if state.rust_module.content.is_none() { - abort!( - state.rust_module.ident.span(), - "Shader module must have a body" - ); - } - parse_main_function(state); - handle_use_statements(state); - state.module_ident = Some(state.rust_module.ident.to_string()); - state.module_visibility = Some(state.rust_module.vis.to_token_stream().to_string()); - check_module_for_global_id_assignment(state); - find_constants(state); - divide_custom_types_by_category(state); - find_helper_functions(state); -} diff --git a/bevy_gpu_compute_macro/src/transformer/module_parser/mod.rs b/bevy_gpu_compute_macro/src/transformer/module_parser/mod.rs deleted file mode 100644 index 5475aad..0000000 --- a/bevy_gpu_compute_macro/src/transformer/module_parser/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod constants; -pub mod divide_custom_types; -pub mod helper_functions; -pub mod lib; -pub mod main_function; -pub mod use_statements; -pub mod validate_no_global_id_assignments; diff --git a/bevy_gpu_compute_macro/src/transformer/output/expanded_module.rs b/bevy_gpu_compute_macro/src/transformer/output/expanded_module.rs deleted file mode 100644 index aead021..0000000 --- a/bevy_gpu_compute_macro/src/transformer/output/expanded_module.rs +++ /dev/null @@ -1,50 +0,0 @@ -use proc_macro_error::abort; -use proc_macro2::TokenStream; -use quote::quote; - -use crate::{ - state::ModuleTransformState, - transformer::output::{ - module_for_cpu::lib::generate_module_for_cpu_usage, - shader_module_object::generate_shader_module_object, - types_for_rust_usage::types::define_types_for_use_in_rust_and_set_binding_numbers, - }, -}; -pub fn generate_expanded_module(state: &mut ModuleTransformState) -> TokenStream { - let module_ident: TokenStream = if let Some(c) = &state.module_ident { - c.parse().unwrap() - } else { - abort!( - state.rust_module.ident.span(), - "No module ident found in transform state" - ); - }; - let module_visibility: TokenStream = if let Some(c) = &state.module_visibility { - c.parse().unwrap() - } else { - abort!( - state.rust_module.ident.span(), - "No module visibility found in transform state" - ); - }; - let types = define_types_for_use_in_rust_and_set_binding_numbers(state); - let object = generate_shader_module_object(state); - let module_for_cpu = generate_module_for_cpu_usage(state); - quote!( - #module_visibility mod #module_ident { - use bevy_gpu_compute_core::wgsl::shader_sections::*; //todo, make this less brittle, how? - use bevy_gpu_compute_core::wgsl::shader_custom_type_name::*; - use bevy_gpu_compute_core::wgsl_helpers::*; - use bevy_gpu_compute_core::wgsl::shader_module::user_defined_portion::WgslShaderModuleUserPortion; - use bevy_gpu_compute_core::*; - use std::collections::HashMap; - - - #types - - #object - - #module_for_cpu - } - ) -} diff --git a/bevy_gpu_compute_macro/src/transformer/output/mod.rs b/bevy_gpu_compute_macro/src/transformer/output/mod.rs deleted file mode 100644 index 6d8e594..0000000 --- a/bevy_gpu_compute_macro/src/transformer/output/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::state::ModuleTransformState; -use expanded_module::generate_expanded_module; -use proc_macro2::TokenStream; -use quote::quote; -use unaltered_module::generate_unaltered_module; - -mod expanded_module; -mod module_for_cpu; -mod per_component_expansion; -mod shader_module_object; -mod types_for_rust_usage; -mod unaltered_module; -pub fn produce_expanded_output(state: &mut ModuleTransformState) -> TokenStream { - let unaltered_module = generate_unaltered_module(state); - let expanded_module = generate_expanded_module(state); - quote!( - #unaltered_module - - #expanded_module - ) -} diff --git a/bevy_gpu_compute_macro/src/transformer/output/module_for_cpu/lib.rs b/bevy_gpu_compute_macro/src/transformer/output/module_for_cpu/lib.rs deleted file mode 100644 index 1aed2d0..0000000 --- a/bevy_gpu_compute_macro/src/transformer/output/module_for_cpu/lib.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::state::ModuleTransformState; -use proc_macro2::{Span, TokenStream}; -use quote::{ToTokens, quote}; -use syn::{FnArg, Ident, ItemFn}; - -pub fn generate_module_for_cpu_usage(state: &ModuleTransformState) -> TokenStream { - // all helper functions need to be publicly exposed here - // and the main function needs to be rewritten to use parameter inputs, and then exposed here as well - let helper_funcs = generate_helper_funcs(state); - let main_func = generate_main_func(state); - let consts = generate_module_level_consts(state); - quote!( - pub use on_cpu::*; - pub mod on_cpu { - use super::*; - use bevy_gpu_compute_core::wgsl_helpers::*; - #consts - #helper_funcs - #main_func - } - ) -} - -fn generate_helper_funcs(state: &ModuleTransformState) -> TokenStream { - state - .result_for_cpu - .helper_functions - .iter() - .map(|func| { - // the original rust code is stored as a string, convert it back to TokenStream - let code: TokenStream = func.code.rust_code.parse().unwrap(); - code - }) - .collect() -} -fn generate_module_level_consts(state: &ModuleTransformState) -> TokenStream { - let mut consts = TokenStream::new(); - state - .result_for_cpu - .static_consts - .iter() - .for_each(|constant| { - let rust_code: TokenStream = constant.code.rust_code.parse().unwrap(); - consts.extend(quote!( - #rust_code - )); - }); - consts -} - -fn generate_main_func(state: &ModuleTransformState) -> TokenStream { - // the original rust code is stored as a string, convert it back to TokenStream - let original_tokens: TokenStream = state - .result_for_cpu - .main_function - .as_ref() - .unwrap() - .code - .rust_code - .parse() - .unwrap(); - let mut main_func: ItemFn = syn::parse2(original_tokens).unwrap(); - add_params_to_main(state, &mut main_func); - add_array_lengths_to_main(state, &mut main_func); - main_func.to_token_stream() -} - -fn add_params_to_main(state: &ModuleTransformState, main_func: &mut ItemFn) { - // add the uniform and array inputs and outputs to the main function parameters - state.result_for_cpu.uniforms.iter().for_each(|uniform| { - // turn into a PatType - let param_name = Ident::new(uniform.name.uniform().as_str(), Span::call_site()); - let param_type = Ident::new(uniform.name.name().as_str(), Span::call_site()); - // let r: FnArg = syn::parse_quote!(#param_name : #param_type); - let r: FnArg = syn::parse_quote!( #param_name : #param_type ); - - main_func.sig.inputs.push(r); - }); - state.result_for_cpu.input_arrays.iter().for_each(|array| { - // turn into a PatType - let param_name = Ident::new( - array.item_type.name.input_array().as_str(), - Span::call_site(), - ); - let param_type = Ident::new(array.item_type.name.name().as_str(), Span::call_site()); - let r: FnArg = syn::parse_quote!(#param_name : Vec<#param_type>); - main_func.sig.inputs.push(r); - }); - state.result_for_cpu.output_arrays.iter().for_each(|array| { - // turn into a PatType - let param_name = Ident::new( - array.item_type.name.output_array().as_str(), - Span::call_site(), - ); - let param_type = Ident::new(array.item_type.name.name().as_str(), Span::call_site()); - let r: FnArg = syn::parse_quote!(mut #param_name : &mut Vec<#param_type>); - main_func.sig.inputs.push(r); - }); -} - -fn add_array_lengths_to_main(state: &ModuleTransformState, main_func: &mut ItemFn) { - // add the array lengths to the main function body before anything else - state.result_for_cpu.input_arrays.iter().for_each(|array| { - let var_name = Ident::new( - array.item_type.name.input_array_length().as_str(), - Span::call_site(), - ); - let input_array_name = Ident::new( - array.item_type.name.input_array().as_str(), - Span::call_site(), - ); - main_func.block.stmts.insert( - 0, - syn::parse_quote!(let #var_name = #input_array_name .len();), - ); - }); - state.result_for_cpu.output_arrays.iter().for_each(|array| { - let var_name = Ident::new( - array.item_type.name.output_array_length().as_str(), - Span::call_site(), - ); - let output_array_name = Ident::new( - array.item_type.name.output_array().as_str(), - Span::call_site(), - ); - main_func.block.stmts.insert( - 0, - syn::parse_quote!(let #var_name = #output_array_name .len();), - ); - }) -} diff --git a/bevy_gpu_compute_macro/src/transformer/output/module_for_cpu/mod.rs b/bevy_gpu_compute_macro/src/transformer/output/module_for_cpu/mod.rs deleted file mode 100644 index 965f28e..0000000 --- a/bevy_gpu_compute_macro/src/transformer/output/module_for_cpu/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod lib; diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/mod.rs b/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/mod.rs deleted file mode 100644 index 1d1a442..0000000 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod config_input_data_builder; -pub mod input_data_builder; -pub mod make_types_pod; -pub mod make_types_public; -pub mod max_output_lengths_builder; -pub mod output_data_builder; -pub mod remove_internal_attributes; -pub mod types; diff --git a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/remove_internal_attributes.rs b/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/remove_internal_attributes.rs deleted file mode 100644 index c6872dc..0000000 --- a/bevy_gpu_compute_macro/src/transformer/output/types_for_rust_usage/remove_internal_attributes.rs +++ /dev/null @@ -1,30 +0,0 @@ -/// whenever `#[` is detected, remove everything up to the next `]` using regex, also remove the hash+square brackets -/// remove these specific strings: `#[wgsl_config]`, `#[wgsl_input_array]`, `#[wgsl_output_array]` and `#[wgsl_output_vec]`, but allow any number of whitespaces or newlines between the square brackets and the attribute name -pub fn remove_internal_attributes(file: String) -> String { - let re = regex::Regex::new(r"#\[\s*wgsl_config\s*\]|\s*#\[\s*wgsl_input_array\s*\]|\s*#\[\s*wgsl_output_array\s*\]|\s*#\[\s*wgsl_output_vec\s*\]").unwrap(); - re.replace_all(&file, "").to_string() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_remove_internal_attributes() { - let input = r#" - #[wgsl_config] - #[wgsl_input_array] - #[wgsl_output_array] - #[wgsl_output_vec] - #[valid] - #[wgsl_config]#[wgsl_input_array]#[wgsl_output_array]#[wgsl_output_vec] - "#; - let expected = r#" - - #[valid] - - "#; - let result = remove_internal_attributes(input.to_string()); - assert_eq!(result, expected); - } -} diff --git a/bevy_gpu_compute_macro/src/transformer/output/unaltered_module.rs b/bevy_gpu_compute_macro/src/transformer/output/unaltered_module.rs deleted file mode 100644 index 8f51148..0000000 --- a/bevy_gpu_compute_macro/src/transformer/output/unaltered_module.rs +++ /dev/null @@ -1,28 +0,0 @@ -use proc_macro_error::abort; -use proc_macro2::TokenStream; -use quote::quote; - -use crate::state::ModuleTransformState; -pub fn generate_unaltered_module(state: &ModuleTransformState) -> TokenStream { - let module_ident: TokenStream = if let Some(c) = &state.module_ident { - format!("{}_for_syntax_check", c).parse().unwrap() - } else { - abort!( - state.rust_module.ident.span(), - "No module ident found in transform state" - ); - }; - let module_visibility: TokenStream = if let Some(c) = &state.module_visibility { - c.parse().unwrap() - } else { - abort!( - state.rust_module.ident.span(), - "No module visibility found in transform state" - ); - }; - let content: TokenStream = state.get_original_content().parse().unwrap(); - quote!( - #module_visibility mod #module_ident { - #content - }) -} diff --git a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/remove_attributes.rs b/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/remove_attributes.rs deleted file mode 100644 index 85907a4..0000000 --- a/bevy_gpu_compute_macro/src/transformer/to_wgsl_syntax/remove_attributes.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// whenever `#[` is detected, remove everything up to the next `]` using regex, also remove the hash+square brackets -pub fn remove_attributes(file: String) -> String { - let re = regex::Regex::new(r"#\[[^\]]*\]").unwrap(); - re.replace_all(&file, "").to_string() -} diff --git a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/mod.rs b/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/mod.rs deleted file mode 100644 index 14894a6..0000000 --- a/bevy_gpu_compute_macro/src/transformer/transform_wgsl_helper_methods/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod category; -mod erroneous_usage_finder; -pub mod helper_method; -pub mod matcher; -pub mod method_name; -mod parse; -pub mod run; -pub mod test; -mod test_for_cpu; -pub mod to_expanded_format; -mod to_expanded_format_for_cpu; diff --git a/bevy_gpu_compute_macro/tests/components.rs b/bevy_gpu_compute_macro/tests/components.rs index 008790f..c0a3615 100644 --- a/bevy_gpu_compute_macro/tests/components.rs +++ b/bevy_gpu_compute_macro/tests/components.rs @@ -1,4 +1,5 @@ #![feature(f16)] +#![allow(clippy::all)] use std::collections::HashMap; use bevy_gpu_compute_core::{ @@ -26,11 +27,8 @@ fn test_simple_struct() { x: f32, y: f32, } - fn main(iter_pos: WgslIterationPosition) { - return; - } + fn main(iter_pos: WgslIterationPosition) {} } - let t2 = test_module::parsed(); assert!(t2.output_arrays.is_empty()); assert!(t2.input_arrays.is_empty()); @@ -40,7 +38,7 @@ fn test_simple_struct() { assert!(t2.helper_types.len() == 1); assert_eq!( t2.main_function.unwrap().code.wgsl_code, - "fn main(@builtin(global_invocation_id) iter_pos: vec3) { return; }" + "fn main(@builtin(global_invocation_id) iter_pos: vec3) {}" ); } @@ -56,7 +54,6 @@ fn test_struct_creation() { } fn main(iter_pos: WgslIterationPosition) { let obj = TStruct { x: 1.0, y: 2.0 }; - return; } } @@ -69,7 +66,7 @@ fn test_struct_creation() { assert!(t2.helper_types.len() == 1); assert_eq!( t2.main_function.unwrap().code.wgsl_code, - "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{ let obj = TStruct(1.0, 2.0); return; }" + "fn main(@builtin(global_invocation_id) iter_pos: vec3) { let obj = TStruct(1.0, 2.0); }" ); } @@ -88,7 +85,6 @@ fn test_struct_creation_with_nested_transforms() { x: 1.0, y: Vec3F32::new(2.0, 3.0, 4.0), }; - return; } } @@ -103,7 +99,7 @@ fn test_struct_creation_with_nested_transforms() { assert!(t2.helper_types.len() == 1); assert_eq!( t2.main_function.unwrap().code.wgsl_code, - "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{ let obj = TStruct(1.0,vec3(2.0, 3.0, 4.0)); return; }" + "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{ let obj = TStruct(1.0,vec3(2.0, 3.0, 4.0)); }" ); } #[test] @@ -193,7 +189,7 @@ fn test_helper_functions() { fn calculate_distance_squared(p1: [f32; 2], p2: [f32; 2]) -> f32 { let dx = p1[0] - p2[0]; let dy = p1[1] - p2[1]; - return dx * dx + dy * dy; + dx * dx + dy * dy } fn main(iter_pos: WgslIterationPosition) {} } @@ -278,27 +274,30 @@ fn test_doc_comments() { assert!(t2.helper_types.is_empty()); } #[test] -fn test_type_casting() { +fn test_type_casting_and_implicit_returns() { #[wgsl_shader_module] pub mod test_module { use bevy_gpu_compute_core::wgsl_helpers::*; - fn main(iter_pos: WgslIterationPosition) { - let x = 1.0 as i32; - let y = 1 as f32; - return; + #[allow(clippy::unnecessary_cast)] + fn helper() -> f32 { + let x = 1 as f32; + let y = 3.5_f32; + let z = 54.4f32; + if true { y + z } else { x } } + #[allow(unused_variables)] + fn main(iter_pos: WgslIterationPosition) {} } let t2 = test_module::parsed(); assert!(t2.output_arrays.is_empty()); assert!(t2.input_arrays.is_empty()); assert!(t2.uniforms.is_empty()); - assert!(t2.helper_functions.is_empty()); assert!(t2.main_function.is_some()); assert!(t2.static_consts.is_empty()); assert!(t2.helper_types.is_empty()); assert_eq!( - t2.main_function.unwrap().code.wgsl_code, - "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{ let x = i32(1.0); let y = f32(1); return; }" + t2.helper_functions.first().unwrap().code.wgsl_code, + "fn helper() -> f32\n{\n let x = f32(1); let y = f32(3.5); let z = f32(54.4); if true\n { return y + z; } else { return x; }\n}" ); } #[test] @@ -306,11 +305,11 @@ fn test_mutable_variables() { #[wgsl_shader_module] pub mod test_module { use bevy_gpu_compute_core::wgsl_helpers::*; + #[allow(unused_assignments)] fn main(iter_pos: WgslIterationPosition) { let mut x = 1; - let mut x1 = 2; + let x1 = x; x = 2; - return; } } let t2 = test_module::parsed(); @@ -323,7 +322,7 @@ fn test_mutable_variables() { assert!(t2.helper_types.is_empty()); assert_eq!( t2.main_function.unwrap().code.wgsl_code, - "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{ var x = 1; var x1 = 2; x = 2; return; }" + "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{ var x = 1; let x1 = x; x = 2; }" ); } @@ -458,7 +457,7 @@ fn test_entire_collision_shader() { use bevy_gpu_compute_core::wgsl_helpers::*; use bevy_gpu_compute_macro::*; - const example_module_const: u32 = 42; + const EXAMPLE_MODULE_CONST: u32 = 42; #[wgsl_config] struct Uniforms { time: f32, @@ -477,7 +476,7 @@ fn test_entire_collision_shader() { fn calculate_distance_squared(p1: [f32; 2], p2: [f32; 2]) -> f32 { let dx = p1[0] - p2[0]; let dy = p1[1] - p2[1]; - return dx * dx + dy * dy; + dx * dx + dy * dy } fn main(iter_pos: WgslIterationPosition) { //* USER GENERATED LOGIC @@ -511,7 +510,7 @@ fn test_entire_collision_shader() { } let t2 = collision_shader::parsed(); - let user_portion = WgslShaderModuleUserPortion { static_consts: vec![WgslConstAssignment { code: WgslShaderModuleSectionCode { rust_code: "const example_module_const : u32 = 42;".to_string(), wgsl_code: "const example_module_const : u32 = 42;".to_string() } }], helper_types: vec![], uniforms: vec![WgslType { name: ShaderCustomTypeName::new("Uniforms"), code: WgslShaderModuleSectionCode { rust_code: "#[wgsl_config] struct Uniforms { time : f32, resolution : Vec2F32, }".to_string(), wgsl_code: "struct Uniforms { time : f32, resolution : vec2 < f32 > , }".to_string() } }], input_arrays: vec![WgslInputArray { item_type: WgslType { name: ShaderCustomTypeName::new("Position"), code: WgslShaderModuleSectionCode { rust_code: "#[wgsl_input_array] type Position = [f32; 2];".to_string(), wgsl_code: "alias Position = array < f32, 2 > ;".to_string() } } }, WgslInputArray { item_type: WgslType { name: ShaderCustomTypeName::new("Radius") , code: WgslShaderModuleSectionCode { rust_code: "#[wgsl_input_array] type Radius = f32;".to_string(), wgsl_code: "alias Radius = f32;".to_string() } } }], output_arrays: vec![WgslOutputArray { item_type: WgslType { name: ShaderCustomTypeName::new("CollisionResult"), code: WgslShaderModuleSectionCode { rust_code: "#[wgsl_output_vec] struct CollisionResult { entity1 : u32, entity2 : u32, }".to_string(), wgsl_code: "struct CollisionResult { entity1 : u32, entity2 : u32, }".to_string() } }, atomic_counter_name: Some("collisionresult_counter".to_string()) }], helper_functions: vec![WgslFunction { name: "calculate_distance_squared".to_string(), code: WgslShaderModuleSectionCode { rust_code: "fn calculate_distance_squared(p1 : [f32; 2], p2 : [f32; 2]) -> f32\n{\n let dx = p1 [0] - p2 [0]; let dy = p1 [1] - p2 [1]; return dx * dx + dy *\n dy;\n}".to_string(), wgsl_code: "fn calculate_distance_squared(p1 : array < f32, 2 > , p2 : array < f32, 2 >)\n-> f32\n{\n let dx = p1 [0] - p2 [0]; let dy = p1 [1] - p2 [1]; return dx * dx + dy *\n dy;\n}".to_string() } }], main_function: Some(WgslFunction { name: "main".to_owned(), code: WgslShaderModuleSectionCode { rust_code: "fn main(iter_pos : WgslIterationPosition)\n{\n let current_entity = iter_pos.x; let other_entity = iter_pos.y; if\n current_entity >= POSITION_INPUT_ARRAY_LENGTH || other_entity >=\n POSITION_INPUT_ARRAY_LENGTH || current_entity == other_entity ||\n current_entity >= other_entity { return; } let current_radius =\n radius_input_array [current_entity]; let other_radius = radius_input_array\n [other_entity]; if current_radius <= 0.0 || other_radius <= 0.0\n { return; } let current_pos = position_input_array [current_entity]; let\n other_pos = position_input_array [other_entity]; let dist_squared =\n calculate_distance_squared(current_pos, other_pos); let radius_sum =\n current_radius + other_radius; if dist_squared < radius_sum * radius_sum\n {\n {\n let collisionresult_output_array_index =\n atomicAdd(& collisionresult_counter, 1u); if\n collisionresult_output_array_index <\n COLLISIONRESULT_OUTPUT_ARRAY_LENGTH\n {\n collisionresult_output_array\n [collisionresult_output_array_index] = CollisionResult\n { entity1 : current_entity, entity2 : other_entity, };\n }\n };\n }\n}".to_owned(), wgsl_code: "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{\n let current_entity = iter_pos.x; let other_entity = iter_pos.y; if\n current_entity >= POSITION_INPUT_ARRAY_LENGTH || other_entity >=\n POSITION_INPUT_ARRAY_LENGTH || current_entity == other_entity ||\n current_entity >= other_entity { return; } let current_radius =\n radius_input_array [current_entity]; let other_radius = radius_input_array\n [other_entity]; if current_radius <= 0.0 || other_radius <= 0.0\n { return; } let current_pos = position_input_array [current_entity]; let\n other_pos = position_input_array [other_entity]; let dist_squared =\n calculate_distance_squared(current_pos, other_pos); let radius_sum =\n current_radius + other_radius; if dist_squared < radius_sum * radius_sum\n {\n {\n let collisionresult_output_array_index =\n atomicAdd(& collisionresult_counter, 1u); if\n collisionresult_output_array_index <\n COLLISIONRESULT_OUTPUT_ARRAY_LENGTH\n {\n collisionresult_output_array\n [collisionresult_output_array_index] = + let user_portion = WgslShaderModuleUserPortion { static_consts: vec![WgslConstAssignment { code: WgslShaderModuleSectionCode { wgsl_code: "const EXAMPLE_MODULE_CONST : u32 = 42;".to_string() } }], helper_types: vec![], uniforms: vec![WgslType { name: ShaderCustomTypeName::new("Uniforms"), code: WgslShaderModuleSectionCode { wgsl_code: "struct Uniforms { time : f32, resolution : vec2 < f32 > , }".to_string() } }], input_arrays: vec![WgslInputArray { item_type: WgslType { name: ShaderCustomTypeName::new("Position"), code: WgslShaderModuleSectionCode { wgsl_code: "alias Position = array < f32, 2 > ;".to_string() } } }, WgslInputArray { item_type: WgslType { name: ShaderCustomTypeName::new("Radius") , code: WgslShaderModuleSectionCode { wgsl_code: "alias Radius = f32;".to_string() } } }], output_arrays: vec![WgslOutputArray { item_type: WgslType { name: ShaderCustomTypeName::new("CollisionResult"), code: WgslShaderModuleSectionCode { wgsl_code: "struct CollisionResult { entity1 : u32, entity2 : u32, }".to_string() } }, atomic_counter_name: Some("collisionresult_counter".to_string()) }], helper_functions: vec![WgslFunction { name: "calculate_distance_squared".to_string(), code: WgslShaderModuleSectionCode { wgsl_code: "fn calculate_distance_squared(p1 : array < f32, 2 > , p2 : array < f32, 2 >)\n-> f32\n{\n let dx = p1 [0] - p2 [0]; let dy = p1 [1] - p2 [1]; return dx * dx + dy *\n dy;\n}".to_string() } }], main_function: Some(WgslFunction { name: "main".to_owned(), code: WgslShaderModuleSectionCode { wgsl_code: "fn main(@builtin(global_invocation_id) iter_pos: vec3)\n{\n let current_entity = iter_pos.x; let other_entity = iter_pos.y; if\n current_entity >= POSITION_INPUT_ARRAY_LENGTH || other_entity >=\n POSITION_INPUT_ARRAY_LENGTH || current_entity == other_entity ||\n current_entity >= other_entity { return; } let current_radius =\n radius_input_array [current_entity]; let other_radius = radius_input_array\n [other_entity]; if current_radius <= 0.0 || other_radius <= 0.0\n { return; } let current_pos = position_input_array [current_entity]; let\n other_pos = position_input_array [other_entity]; let dist_squared =\n calculate_distance_squared(current_pos, other_pos); let radius_sum =\n current_radius + other_radius; if dist_squared < radius_sum * radius_sum\n {\n {\n let collisionresult_output_array_index =\n atomicAdd(& collisionresult_counter, 1u); if\n collisionresult_output_array_index <\n COLLISIONRESULT_OUTPUT_ARRAY_LENGTH\n {\n collisionresult_output_array\n [collisionresult_output_array_index] = CollisionResult(current_entity, other_entity);\n }\n };\n }\n}".to_owned() } }), binding_numbers_by_variable_name: Some(HashMap::from([ ("uniforms".to_string(), 1), @@ -599,7 +598,7 @@ fn test_functions_exposed_for_rust() { pub mod example_shader_module { use bevy_gpu_compute_core::wgsl_helpers::*; use bevy_gpu_compute_macro::*; - const example_module_const: u32 = 42; + const EXAMPLE_MODULE_CONST: u32 = 42; #[wgsl_config] struct Config { pub example_value: f32, @@ -618,7 +617,61 @@ fn test_functions_exposed_for_rust() { pub fn calculate_distance_squared(p1: [f32; 2], p2: [f32; 2]) -> f32 { let dx = p1[0] - p2[0]; let dy = p1[1] - p2[1]; - return dx * dx + dy * dy; + dx * dx + dy * dy + } + pub fn main(iter_pos: WgslIterationPosition) { + //* USER GENERATED LOGIC + let current_entity = iter_pos.x; + let other_entity = iter_pos.y; + // Early exit if invalid entity or zero radius + if current_entity >= WgslVecInput::vec_len::() + || other_entity >= WgslVecInput::vec_len::() + || current_entity == other_entity + || current_entity >= other_entity + { + return; + } + let current_radius = + WgslVecInput::vec_val::(current_entity) + EXAMPLE_MODULE_CONST as f32; + let other_radius = WgslVecInput::vec_val::(other_entity) + + WgslConfigInput::get::().example_value; + if current_radius <= 0.0 || other_radius <= 0.0 { + return; + } + let current_pos = WgslVecInput::vec_val::(current_entity); + let other_pos = WgslVecInput::vec_val::(other_entity); + let dist_squared = calculate_distance_squared(current_pos, other_pos); + let radius_sum = current_radius + other_radius; + // Compare squared distances to avoid sqrt + if dist_squared < radius_sum * radius_sum { + WgslOutput::push::(CollisionResult { + entity1: current_entity, + entity2: other_entity, + }); + } + } + } + + #[allow(dead_code, unused_variables, unused_imports)] + pub mod example_shader_module2 { + use bevy_gpu_compute_core::wgsl_helpers::*; + use bevy_gpu_compute_macro::*; + const EXAMPLE_MODULE_CONST: u32 = 42; + struct Config { + pub example_value: f32, + } + type Position = [f32; 2]; + type Radius = f32; + //* user output vectors + #[derive(PartialEq)] + struct CollisionResult { + pub entity1: u32, + pub entity2: u32, + } + pub fn calculate_distance_squared(p1: [f32; 2], p2: [f32; 2]) -> f32 { + let dx = p1[0] - p2[0]; + let dy = p1[1] - p2[1]; + dx * dx + dy * dy } pub fn main(iter_pos: WgslIterationPosition) { //* USER GENERATED LOGIC @@ -633,9 +686,9 @@ fn test_functions_exposed_for_rust() { return; } let current_radius = - WgslVecInput::vec_val::(current_entity) + example_module_const as f32; + WgslVecInput::vec_val::(current_entity) + EXAMPLE_MODULE_CONST as f32; let other_radius = WgslVecInput::vec_val::(other_entity) - + WgslConfigInput::get::().example_value as f32; + + WgslConfigInput::get::().example_value; if current_radius <= 0.0 || other_radius <= 0.0 { return; } @@ -664,7 +717,7 @@ fn test_functions_exposed_for_rust() { let input_radii: Vec = vec![10.0, 10.0]; let mut output_collisions: Vec = vec![]; // run the main function, you can see that its signature has been changed to include all the stuff that would normally be in GPU buffers as direct function parameters - example_shader_module::on_cpu::main( + example_shader_module::main( WgslIterationPosition { x: 0, y: 1, z: 1 }, config, input_positions, diff --git a/bevy_gpu_compute_macro/tests/ui/incorrect_vec_constructor_in_macro.stderr b/bevy_gpu_compute_macro/tests/ui/incorrect_vec_constructor_in_macro.stderr index 48f1115..45eb3a5 100644 --- a/bevy_gpu_compute_macro/tests/ui/incorrect_vec_constructor_in_macro.stderr +++ b/bevy_gpu_compute_macro/tests/ui/incorrect_vec_constructor_in_macro.stderr @@ -1,7 +1,10 @@ error[E0639]: cannot create non-exhaustive struct using struct expression - --> tests/ui/incorrect_vec_constructor_in_macro.rs:3:1 - | -3 | #[wgsl_shader_module] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `wgsl_shader_module` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/ui/incorrect_vec_constructor_in_macro.rs:6:32 + | +6 | const MY_CONST: Vec3Bool = Vec3Bool { + | ________________________________^ +7 | | x: true, +8 | | y: false, +9 | | z: true, +10 | | }; + | |_____^ diff --git a/pre-commit-tasks.bash b/pre-commit-tasks.bash index 299e6f0..78ffc5b 100644 --- a/pre-commit-tasks.bash +++ b/pre-commit-tasks.bash @@ -15,7 +15,14 @@ for crate in "${crates[@]}"; do echo "Running cargo test..." cargo test + + cd .. done +cd bevy_gpu_compute +echo "Running example ..." +cargo run --example collision_detection_demonstration +cd .. + echo "All checks completed!" \ No newline at end of file