render: add direct buffer mapping/unmapping
This commit is contained in:
		
							parent
							
								
									cb1ffb42c4
								
							
						
					
					
						commit
						6d58a5a033
					
				@ -58,10 +58,8 @@ impl SystemNode for LightsNode {
 | 
			
		||||
            LightsNodeSystemState {
 | 
			
		||||
                command_queue: self.command_queue.clone(),
 | 
			
		||||
                max_lights: self.max_lights,
 | 
			
		||||
                tmp_count_buffer: None,
 | 
			
		||||
                tmp_light_buffer: None,
 | 
			
		||||
                light_buffer: None,
 | 
			
		||||
                lights_are_dirty: true,
 | 
			
		||||
                staging_buffer: None,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        system
 | 
			
		||||
@ -71,10 +69,7 @@ impl SystemNode for LightsNode {
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct LightsNodeSystemState {
 | 
			
		||||
    light_buffer: Option<BufferId>,
 | 
			
		||||
    lights_are_dirty: bool,
 | 
			
		||||
    // TODO: merge these
 | 
			
		||||
    tmp_count_buffer: Option<BufferId>,
 | 
			
		||||
    tmp_light_buffer: Option<BufferId>,
 | 
			
		||||
    staging_buffer: Option<BufferId>,
 | 
			
		||||
    command_queue: CommandQueue,
 | 
			
		||||
    max_lights: usize,
 | 
			
		||||
}
 | 
			
		||||
@ -82,22 +77,30 @@ pub struct LightsNodeSystemState {
 | 
			
		||||
pub fn lights_node_system(
 | 
			
		||||
    mut state: Local<LightsNodeSystemState>,
 | 
			
		||||
    render_resource_context: Res<Box<dyn RenderResourceContext>>,
 | 
			
		||||
    // TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
 | 
			
		||||
    // TODO: this write on RenderResourceBindings will prevent this system from running in parallel with other systems that do the same
 | 
			
		||||
    mut render_resource_bindings: ResMut<RenderResourceBindings>,
 | 
			
		||||
    mut query: Query<(&Light, &Transform, &Translation)>,
 | 
			
		||||
) {
 | 
			
		||||
    let state = &mut state;
 | 
			
		||||
    if !state.lights_are_dirty {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let render_resource_context = &**render_resource_context;
 | 
			
		||||
    if state.light_buffer.is_none() {
 | 
			
		||||
        let light_uniform_size =
 | 
			
		||||
            std::mem::size_of::<LightCount>() + state.max_lights * std::mem::size_of::<LightRaw>();
 | 
			
		||||
 | 
			
		||||
    let light_count = query.iter().iter().count();
 | 
			
		||||
    let size = std::mem::size_of::<LightRaw>();
 | 
			
		||||
    let light_count_size = std::mem::size_of::<LightCount>();
 | 
			
		||||
    let light_array_size = size * light_count;
 | 
			
		||||
    let light_array_max_size = size * state.max_lights;
 | 
			
		||||
    let current_light_uniform_size = light_count_size + light_array_size;
 | 
			
		||||
    let max_light_uniform_size = light_count_size + light_array_max_size;
 | 
			
		||||
 | 
			
		||||
    if let Some(staging_buffer) = state.staging_buffer {
 | 
			
		||||
        if light_count == 0 {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        render_resource_context.map_buffer(staging_buffer);
 | 
			
		||||
    } else {
 | 
			
		||||
        let buffer = render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
            size: light_uniform_size,
 | 
			
		||||
            size: max_light_uniform_size,
 | 
			
		||||
            buffer_usage: BufferUsage::UNIFORM | BufferUsage::COPY_SRC | BufferUsage::COPY_DST,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        });
 | 
			
		||||
@ -105,74 +108,45 @@ pub fn lights_node_system(
 | 
			
		||||
            uniform::LIGHTS,
 | 
			
		||||
            RenderResourceBinding::Buffer {
 | 
			
		||||
                buffer,
 | 
			
		||||
                range: 0..light_uniform_size as u64,
 | 
			
		||||
                range: 0..max_light_uniform_size as u64,
 | 
			
		||||
                dynamic_index: None,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        state.light_buffer = Some(buffer);
 | 
			
		||||
 | 
			
		||||
        let staging_buffer = render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
            size: max_light_uniform_size,
 | 
			
		||||
            buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
 | 
			
		||||
            mapped_at_creation: true,
 | 
			
		||||
        });
 | 
			
		||||
        state.staging_buffer = Some(staging_buffer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let light_count = query.iter().iter().count();
 | 
			
		||||
 | 
			
		||||
    if light_count == 0 {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    state.lights_are_dirty = false;
 | 
			
		||||
    let size = std::mem::size_of::<LightRaw>();
 | 
			
		||||
    let total_size = size * light_count;
 | 
			
		||||
    let light_count_size = std::mem::size_of::<LightCount>();
 | 
			
		||||
 | 
			
		||||
    if let Some(old_tmp_light_buffer) = state.tmp_light_buffer {
 | 
			
		||||
        render_resource_context.remove_buffer(old_tmp_light_buffer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if let Some(old_tmp_count_buffer) = state.tmp_count_buffer {
 | 
			
		||||
        render_resource_context.remove_buffer(old_tmp_count_buffer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    state.tmp_light_buffer = Some(render_resource_context.create_buffer_mapped(
 | 
			
		||||
        BufferInfo {
 | 
			
		||||
            size: total_size,
 | 
			
		||||
            buffer_usage: BufferUsage::COPY_SRC,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        },
 | 
			
		||||
    let staging_buffer = state.staging_buffer.unwrap();
 | 
			
		||||
    render_resource_context.write_mapped_buffer(
 | 
			
		||||
        staging_buffer,
 | 
			
		||||
        0..current_light_uniform_size as u64,
 | 
			
		||||
        &mut |data, _renderer| {
 | 
			
		||||
            // light count
 | 
			
		||||
            data[0..light_count_size].copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
 | 
			
		||||
 | 
			
		||||
            // light array
 | 
			
		||||
            for ((light, transform, translation), slot) in
 | 
			
		||||
                query.iter().iter().zip(data.chunks_exact_mut(size))
 | 
			
		||||
                query.iter().iter().zip(data[light_count_size..current_light_uniform_size].chunks_exact_mut(size))
 | 
			
		||||
            {
 | 
			
		||||
                slot.copy_from_slice(
 | 
			
		||||
                    LightRaw::from(&light, &transform.value, &translation).as_bytes(),
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    ));
 | 
			
		||||
    state.tmp_count_buffer = Some(render_resource_context.create_buffer_mapped(
 | 
			
		||||
        BufferInfo {
 | 
			
		||||
            size: light_count_size,
 | 
			
		||||
            buffer_usage: BufferUsage::COPY_SRC,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        },
 | 
			
		||||
        &mut |data, _renderer| {
 | 
			
		||||
            data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
 | 
			
		||||
        },
 | 
			
		||||
    ));
 | 
			
		||||
    let tmp_count_buffer = state.tmp_count_buffer.unwrap();
 | 
			
		||||
    );
 | 
			
		||||
    render_resource_context.unmap_buffer(staging_buffer);
 | 
			
		||||
    let light_buffer = state.light_buffer.unwrap();
 | 
			
		||||
    state.command_queue.copy_buffer_to_buffer(
 | 
			
		||||
        tmp_count_buffer,
 | 
			
		||||
        staging_buffer,
 | 
			
		||||
        0,
 | 
			
		||||
        light_buffer,
 | 
			
		||||
        0,
 | 
			
		||||
        light_count_size as u64,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let tmp_light_buffer = state.tmp_light_buffer.unwrap();
 | 
			
		||||
    state.command_queue.copy_buffer_to_buffer(
 | 
			
		||||
        tmp_light_buffer,
 | 
			
		||||
        0,
 | 
			
		||||
        light_buffer,
 | 
			
		||||
        light_count_size as u64,
 | 
			
		||||
        total_size as u64,
 | 
			
		||||
        max_light_uniform_size as u64,
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -51,6 +51,7 @@ impl SystemNode for CameraNode {
 | 
			
		||||
                camera_name: self.camera_name.clone(),
 | 
			
		||||
                command_queue: self.command_queue.clone(),
 | 
			
		||||
                camera_buffer: None,
 | 
			
		||||
                staging_buffer: None,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        system
 | 
			
		||||
@ -62,6 +63,7 @@ pub struct CameraNodeState {
 | 
			
		||||
    command_queue: CommandQueue,
 | 
			
		||||
    camera_name: Cow<'static, str>,
 | 
			
		||||
    camera_buffer: Option<BufferId>,
 | 
			
		||||
    staging_buffer: Option<BufferId>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn camera_node_system(
 | 
			
		||||
@ -74,27 +76,7 @@ pub fn camera_node_system(
 | 
			
		||||
    query: Query<(&Camera, &Transform)>,
 | 
			
		||||
) {
 | 
			
		||||
    let render_resource_context = &**render_resource_context;
 | 
			
		||||
    state.camera_buffer = Some(match state.camera_buffer {
 | 
			
		||||
        Some(buffer) => buffer,
 | 
			
		||||
        None => {
 | 
			
		||||
            let size = std::mem::size_of::<[[f32; 4]; 4]>();
 | 
			
		||||
            let buffer = render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
                size,
 | 
			
		||||
                buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
 | 
			
		||||
                ..Default::default()
 | 
			
		||||
            });
 | 
			
		||||
            render_resource_bindings.set(
 | 
			
		||||
                &state.camera_name,
 | 
			
		||||
                RenderResourceBinding::Buffer {
 | 
			
		||||
                    buffer,
 | 
			
		||||
                    range: 0..size as u64,
 | 
			
		||||
                    dynamic_index: None,
 | 
			
		||||
                },
 | 
			
		||||
            );
 | 
			
		||||
            state.camera_buffer = Some(buffer);
 | 
			
		||||
            buffer
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    let (camera, transform) = if let Some(camera_entity) = active_cameras.get(&state.camera_name) {
 | 
			
		||||
        (
 | 
			
		||||
            query.get::<Camera>(camera_entity).unwrap(),
 | 
			
		||||
@ -104,24 +86,55 @@ pub fn camera_node_system(
 | 
			
		||||
        return;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let staging_buffer = if let Some(staging_buffer) = state.staging_buffer {
 | 
			
		||||
        render_resource_context.map_buffer(staging_buffer);
 | 
			
		||||
        staging_buffer
 | 
			
		||||
    } else {
 | 
			
		||||
        let size = std::mem::size_of::<[[f32; 4]; 4]>();
 | 
			
		||||
        let buffer = render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
            size,
 | 
			
		||||
            buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        });
 | 
			
		||||
        render_resource_bindings.set(
 | 
			
		||||
            &state.camera_name,
 | 
			
		||||
            RenderResourceBinding::Buffer {
 | 
			
		||||
                buffer,
 | 
			
		||||
                range: 0..size as u64,
 | 
			
		||||
                dynamic_index: None,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        state.camera_buffer = Some(buffer);
 | 
			
		||||
 | 
			
		||||
        let staging_buffer = render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
            size,
 | 
			
		||||
            buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
 | 
			
		||||
            mapped_at_creation: true,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        state.staging_buffer = Some(staging_buffer);
 | 
			
		||||
        staging_buffer
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
 | 
			
		||||
    let camera_matrix: [f32; 16] =
 | 
			
		||||
        (camera.projection_matrix * transform.value.inverse()).to_cols_array();
 | 
			
		||||
 | 
			
		||||
    let tmp_buffer = render_resource_context.create_buffer_mapped(
 | 
			
		||||
        BufferInfo {
 | 
			
		||||
            size: matrix_size,
 | 
			
		||||
            buffer_usage: BufferUsage::COPY_SRC,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        },
 | 
			
		||||
    render_resource_context.write_mapped_buffer(
 | 
			
		||||
        staging_buffer,
 | 
			
		||||
        0..matrix_size as u64,
 | 
			
		||||
        &mut |data, _renderer| {
 | 
			
		||||
            data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    render_resource_context.unmap_buffer(staging_buffer);
 | 
			
		||||
 | 
			
		||||
    let camera_buffer = state.camera_buffer.unwrap();
 | 
			
		||||
    state
 | 
			
		||||
        .command_queue
 | 
			
		||||
        .copy_buffer_to_buffer(tmp_buffer, 0, camera_buffer, 0, matrix_size as u64);
 | 
			
		||||
    state.command_queue.free_buffer(tmp_buffer);
 | 
			
		||||
    state.command_queue.copy_buffer_to_buffer(
 | 
			
		||||
        staging_buffer,
 | 
			
		||||
        0,
 | 
			
		||||
        camera_buffer,
 | 
			
		||||
        0,
 | 
			
		||||
        matrix_size as u64,
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,8 @@ where
 | 
			
		||||
    T: render_resource::RenderResources,
 | 
			
		||||
{
 | 
			
		||||
    uniform_arrays: Vec<Option<(String, BufferArrayStatus)>>,
 | 
			
		||||
    staging_buffer: Option<BufferId>,
 | 
			
		||||
    staging_buffer_size: usize,
 | 
			
		||||
    _marker: PhantomData<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -73,6 +75,8 @@ where
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            uniform_arrays: Default::default(),
 | 
			
		||||
            staging_buffer: Default::default(),
 | 
			
		||||
            staging_buffer_size: 0,
 | 
			
		||||
            _marker: Default::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -166,6 +170,7 @@ where
 | 
			
		||||
            let buffer = render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
                size: total_size,
 | 
			
		||||
                buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
 | 
			
		||||
                ..Default::default()
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            buffer_array_status.current_item_capacity = new_capacity;
 | 
			
		||||
@ -181,7 +186,7 @@ where
 | 
			
		||||
            buffer_array_status.buffer = Some(buffer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn update_staging_buffer_offsets(&mut self) -> usize {
 | 
			
		||||
    fn update_staging_buffer(&mut self, render_resource_context: &dyn RenderResourceContext) {
 | 
			
		||||
        let mut size = 0;
 | 
			
		||||
        for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() {
 | 
			
		||||
            if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status {
 | 
			
		||||
@ -190,7 +195,24 @@ where
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        size
 | 
			
		||||
        if self.staging_buffer_size != size {
 | 
			
		||||
            if let Some(staging_buffer) = self.staging_buffer {
 | 
			
		||||
                render_resource_context.remove_buffer(staging_buffer);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if size > 0 {
 | 
			
		||||
                let staging_buffer = render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
                    buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
 | 
			
		||||
                    size,
 | 
			
		||||
                    ..Default::default()
 | 
			
		||||
                });
 | 
			
		||||
                self.staging_buffer = Some(staging_buffer);
 | 
			
		||||
            } else {
 | 
			
		||||
                self.staging_buffer = None;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            self.staging_buffer_size = size;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn setup_uniform_buffer_resources(
 | 
			
		||||
@ -412,7 +434,9 @@ fn render_resources_node_system<T: RenderResources>(
 | 
			
		||||
    state
 | 
			
		||||
        .uniform_buffer_arrays
 | 
			
		||||
        .setup_buffer_arrays(render_resource_context, state.dynamic_uniforms);
 | 
			
		||||
    let staging_buffer_size = state.uniform_buffer_arrays.update_staging_buffer_offsets();
 | 
			
		||||
    state
 | 
			
		||||
        .uniform_buffer_arrays
 | 
			
		||||
        .update_staging_buffer(render_resource_context);
 | 
			
		||||
 | 
			
		||||
    for (uniforms, draw, render_pipelines) in &mut query.iter() {
 | 
			
		||||
        if !draw.is_visible {
 | 
			
		||||
@ -426,28 +450,11 @@ fn render_resources_node_system<T: RenderResources>(
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if staging_buffer_size == 0 {
 | 
			
		||||
        let mut staging_buffer: [u8; 0] = [];
 | 
			
		||||
        for (uniforms, draw, render_pipelines) in &mut query.iter() {
 | 
			
		||||
            if !draw.is_visible {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            state.uniform_buffer_arrays.setup_uniform_buffer_resources(
 | 
			
		||||
                &uniforms,
 | 
			
		||||
                state.dynamic_uniforms,
 | 
			
		||||
                render_resource_context,
 | 
			
		||||
                &mut render_pipelines.bindings,
 | 
			
		||||
                &mut staging_buffer,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        let staging_buffer = render_resource_context.create_buffer_mapped(
 | 
			
		||||
            BufferInfo {
 | 
			
		||||
                buffer_usage: BufferUsage::COPY_SRC,
 | 
			
		||||
                size: staging_buffer_size,
 | 
			
		||||
                ..Default::default()
 | 
			
		||||
            },
 | 
			
		||||
    if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer {
 | 
			
		||||
        render_resource_context.map_buffer(staging_buffer);
 | 
			
		||||
        render_resource_context.write_mapped_buffer(
 | 
			
		||||
            staging_buffer,
 | 
			
		||||
            0..state.uniform_buffer_arrays.staging_buffer_size as u64,
 | 
			
		||||
            &mut |mut staging_buffer, _render_resource_context| {
 | 
			
		||||
                for (uniforms, draw, render_pipelines) in &mut query.iter() {
 | 
			
		||||
                    if !draw.is_visible {
 | 
			
		||||
@ -464,11 +471,27 @@ fn render_resources_node_system<T: RenderResources>(
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        render_resource_context.unmap_buffer(staging_buffer);
 | 
			
		||||
 | 
			
		||||
        state
 | 
			
		||||
            .uniform_buffer_arrays
 | 
			
		||||
            .copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer);
 | 
			
		||||
        state.command_queue.free_buffer(staging_buffer);
 | 
			
		||||
    } else {
 | 
			
		||||
        // TODO: can we just remove this?
 | 
			
		||||
        let mut staging_buffer: [u8; 0] = [];
 | 
			
		||||
        for (uniforms, draw, render_pipelines) in &mut query.iter() {
 | 
			
		||||
            if !draw.is_visible {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            state.uniform_buffer_arrays.setup_uniform_buffer_resources(
 | 
			
		||||
                &uniforms,
 | 
			
		||||
                state.dynamic_uniforms,
 | 
			
		||||
                render_resource_context,
 | 
			
		||||
                &mut render_pipelines.bindings,
 | 
			
		||||
                &mut staging_buffer,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -576,7 +599,7 @@ fn asset_render_resources_node_system<T: RenderResources>(
 | 
			
		||||
    state
 | 
			
		||||
        .uniform_buffer_arrays
 | 
			
		||||
        .setup_buffer_arrays(render_resource_context, state.dynamic_uniforms);
 | 
			
		||||
    let staging_buffer_size = state.uniform_buffer_arrays.update_staging_buffer_offsets();
 | 
			
		||||
    state.uniform_buffer_arrays.update_staging_buffer(render_resource_context);
 | 
			
		||||
 | 
			
		||||
    for asset_handle in modified_assets.iter() {
 | 
			
		||||
        let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
 | 
			
		||||
@ -589,28 +612,11 @@ fn asset_render_resources_node_system<T: RenderResources>(
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if staging_buffer_size == 0 {
 | 
			
		||||
        let mut staging_buffer: [u8; 0] = [];
 | 
			
		||||
        for asset_handle in modified_assets.iter() {
 | 
			
		||||
            let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
 | 
			
		||||
            let mut render_resource_bindings =
 | 
			
		||||
                asset_render_resource_bindings.get_or_insert_mut(*asset_handle);
 | 
			
		||||
            // TODO: only setup buffer if we haven't seen this handle before
 | 
			
		||||
            state.uniform_buffer_arrays.setup_uniform_buffer_resources(
 | 
			
		||||
                &asset,
 | 
			
		||||
                state.dynamic_uniforms,
 | 
			
		||||
                render_resource_context,
 | 
			
		||||
                &mut render_resource_bindings,
 | 
			
		||||
                &mut staging_buffer,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        let staging_buffer = render_resource_context.create_buffer_mapped(
 | 
			
		||||
            BufferInfo {
 | 
			
		||||
                buffer_usage: BufferUsage::COPY_SRC,
 | 
			
		||||
                size: staging_buffer_size,
 | 
			
		||||
                ..Default::default()
 | 
			
		||||
            },
 | 
			
		||||
    if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer {
 | 
			
		||||
        render_resource_context.map_buffer(staging_buffer);
 | 
			
		||||
        render_resource_context.write_mapped_buffer(
 | 
			
		||||
            staging_buffer,
 | 
			
		||||
            0..state.uniform_buffer_arrays.staging_buffer_size as u64,
 | 
			
		||||
            &mut |mut staging_buffer, _render_resource_context| {
 | 
			
		||||
                for asset_handle in modified_assets.iter() {
 | 
			
		||||
                    let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
 | 
			
		||||
@ -627,11 +633,26 @@ fn asset_render_resources_node_system<T: RenderResources>(
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        render_resource_context.unmap_buffer(staging_buffer);
 | 
			
		||||
 | 
			
		||||
        state
 | 
			
		||||
            .uniform_buffer_arrays
 | 
			
		||||
            .copy_staging_buffer_to_final_buffers(&mut state.command_queue, staging_buffer);
 | 
			
		||||
        state.command_queue.free_buffer(staging_buffer);
 | 
			
		||||
    } else {
 | 
			
		||||
        let mut staging_buffer: [u8; 0] = [];
 | 
			
		||||
        for asset_handle in modified_assets.iter() {
 | 
			
		||||
            let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
 | 
			
		||||
            let mut render_resource_bindings =
 | 
			
		||||
                asset_render_resource_bindings.get_or_insert_mut(*asset_handle);
 | 
			
		||||
            // TODO: only setup buffer if we haven't seen this handle before
 | 
			
		||||
            state.uniform_buffer_arrays.setup_uniform_buffer_resources(
 | 
			
		||||
                &asset,
 | 
			
		||||
                state.dynamic_uniforms,
 | 
			
		||||
                render_resource_context,
 | 
			
		||||
                &mut render_resource_bindings,
 | 
			
		||||
                &mut staging_buffer,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (asset_handle, _draw, render_pipelines) in &mut query.iter() {
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@ impl BufferId {
 | 
			
		||||
pub struct BufferInfo {
 | 
			
		||||
    pub size: usize,
 | 
			
		||||
    pub buffer_usage: BufferUsage,
 | 
			
		||||
    pub mapped_at_creation: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for BufferInfo {
 | 
			
		||||
@ -20,6 +21,7 @@ impl Default for BufferInfo {
 | 
			
		||||
        BufferInfo {
 | 
			
		||||
            size: 0,
 | 
			
		||||
            buffer_usage: BufferUsage::empty(),
 | 
			
		||||
            mapped_at_creation: false,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -30,19 +30,26 @@ impl SharedBuffers {
 | 
			
		||||
    ) -> Option<RenderResourceBinding> {
 | 
			
		||||
        if let Some(size) = render_resource.buffer_byte_len() {
 | 
			
		||||
            // PERF: this buffer will be slow
 | 
			
		||||
            let staging_buffer = self.render_resource_context.create_buffer_mapped(
 | 
			
		||||
                BufferInfo {
 | 
			
		||||
                    size,
 | 
			
		||||
                    buffer_usage: BufferUsage::COPY_SRC,
 | 
			
		||||
                },
 | 
			
		||||
            let staging_buffer = self.render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
                size,
 | 
			
		||||
                buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
 | 
			
		||||
                mapped_at_creation: true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            self.render_resource_context.write_mapped_buffer(
 | 
			
		||||
                staging_buffer,
 | 
			
		||||
                0..size as u64,
 | 
			
		||||
                &mut |data, _renderer| {
 | 
			
		||||
                    render_resource.write_buffer_bytes(data);
 | 
			
		||||
                },
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            self.render_resource_context.unmap_buffer(staging_buffer);
 | 
			
		||||
 | 
			
		||||
            let destination_buffer = self.render_resource_context.create_buffer(BufferInfo {
 | 
			
		||||
                size,
 | 
			
		||||
                buffer_usage: BufferUsage::COPY_DST | buffer_usage,
 | 
			
		||||
                ..Default::default()
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            let mut command_queue = self.command_queue.write().unwrap();
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ use bevy_asset::{Assets, Handle, HandleUntyped};
 | 
			
		||||
use bevy_window::{Window, WindowId};
 | 
			
		||||
use std::{
 | 
			
		||||
    collections::HashMap,
 | 
			
		||||
    ops::Range,
 | 
			
		||||
    sync::{Arc, RwLock},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -52,15 +53,18 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
 | 
			
		||||
        self.add_buffer_info(buffer, buffer_info);
 | 
			
		||||
        buffer
 | 
			
		||||
    }
 | 
			
		||||
    fn create_buffer_mapped(
 | 
			
		||||
    fn write_mapped_buffer(
 | 
			
		||||
        &self,
 | 
			
		||||
        buffer_info: BufferInfo,
 | 
			
		||||
        setup_data: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
 | 
			
		||||
    ) -> BufferId {
 | 
			
		||||
        let mut buffer = vec![0; buffer_info.size];
 | 
			
		||||
        setup_data(&mut buffer, self);
 | 
			
		||||
        BufferId::new()
 | 
			
		||||
        id: BufferId,
 | 
			
		||||
        _range: Range<u64>,
 | 
			
		||||
        write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
 | 
			
		||||
    ) {
 | 
			
		||||
        let size = self.buffer_info.read().unwrap().get(&id).unwrap().size;
 | 
			
		||||
        let mut buffer = vec![0; size];
 | 
			
		||||
        write(&mut buffer, self);
 | 
			
		||||
    }
 | 
			
		||||
    fn map_buffer(&self, _id: BufferId) {}
 | 
			
		||||
    fn unmap_buffer(&self, _id: BufferId) {}
 | 
			
		||||
    fn create_buffer_with_data(&self, buffer_info: BufferInfo, _data: &[u8]) -> BufferId {
 | 
			
		||||
        let buffer = BufferId::new();
 | 
			
		||||
        self.add_buffer_info(buffer, buffer_info);
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ use crate::{
 | 
			
		||||
use bevy_asset::{Assets, Handle, HandleUntyped};
 | 
			
		||||
use bevy_window::{Window, WindowId};
 | 
			
		||||
use downcast_rs::{impl_downcast, Downcast};
 | 
			
		||||
use std::ops::Range;
 | 
			
		||||
 | 
			
		||||
pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
 | 
			
		||||
    fn create_swap_chain(&self, window: &Window);
 | 
			
		||||
@ -17,11 +18,20 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
 | 
			
		||||
    fn create_texture(&self, texture_descriptor: TextureDescriptor) -> TextureId;
 | 
			
		||||
    fn create_buffer(&self, buffer_info: BufferInfo) -> BufferId;
 | 
			
		||||
    // TODO: remove RenderResourceContext here
 | 
			
		||||
    fn create_buffer_mapped(
 | 
			
		||||
    fn write_mapped_buffer(
 | 
			
		||||
        &self,
 | 
			
		||||
        buffer_info: BufferInfo,
 | 
			
		||||
        setup_data: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
 | 
			
		||||
    ) -> BufferId;
 | 
			
		||||
        id: BufferId,
 | 
			
		||||
        range: Range<u64>,
 | 
			
		||||
        write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
 | 
			
		||||
    );
 | 
			
		||||
    fn map_buffer(
 | 
			
		||||
        &self,
 | 
			
		||||
        id: BufferId,
 | 
			
		||||
    );
 | 
			
		||||
    fn unmap_buffer(
 | 
			
		||||
        &self,
 | 
			
		||||
        id: BufferId,
 | 
			
		||||
    );
 | 
			
		||||
    fn create_buffer_with_data(&self, buffer_info: BufferInfo, data: &[u8]) -> BufferId;
 | 
			
		||||
    fn create_shader_module(&self, shader_handle: Handle<Shader>, shaders: &Assets<Shader>);
 | 
			
		||||
    fn create_shader_module_from_source(&self, shader_handle: Handle<Shader>, shader: &Shader);
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ use bevy_render::{
 | 
			
		||||
    texture::{Extent3d, SamplerDescriptor, TextureDescriptor},
 | 
			
		||||
};
 | 
			
		||||
use bevy_window::{Window, WindowId};
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use std::{ops::Range, sync::Arc};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct WgpuRenderResourceContext {
 | 
			
		||||
@ -167,43 +167,12 @@ impl RenderResourceContext for WgpuRenderResourceContext {
 | 
			
		||||
            label: None,
 | 
			
		||||
            size: buffer_info.size as u64,
 | 
			
		||||
            usage: buffer_info.buffer_usage.wgpu_into(),
 | 
			
		||||
            mapped_at_creation: false,
 | 
			
		||||
            mapped_at_creation: buffer_info.mapped_at_creation,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let id = BufferId::new();
 | 
			
		||||
        buffer_infos.insert(id, buffer_info);
 | 
			
		||||
        buffers.insert(id, buffer);
 | 
			
		||||
        id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn create_buffer_mapped(
 | 
			
		||||
        &self,
 | 
			
		||||
        buffer_info: BufferInfo,
 | 
			
		||||
        setup_data: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
 | 
			
		||||
    ) -> BufferId {
 | 
			
		||||
        let usage: wgpu::BufferUsage = buffer_info.buffer_usage.wgpu_into();
 | 
			
		||||
        let buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
 | 
			
		||||
            size: buffer_info.size as u64,
 | 
			
		||||
            usage: usage | wgpu::BufferUsage::MAP_WRITE,
 | 
			
		||||
            label: None,
 | 
			
		||||
            mapped_at_creation: false,
 | 
			
		||||
        });
 | 
			
		||||
        let buffer_slice = buffer.slice(..);
 | 
			
		||||
        let data = buffer_slice.map_async(wgpu::MapMode::Write);
 | 
			
		||||
        self.device.poll(wgpu::Maintain::Wait);
 | 
			
		||||
        if let Ok(()) = pollster::block_on(data) {
 | 
			
		||||
            let mut data = buffer_slice.get_mapped_range_mut();
 | 
			
		||||
            setup_data(&mut data, self);
 | 
			
		||||
        } else {
 | 
			
		||||
            panic!("failed to map buffer to host");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        buffer.unmap();
 | 
			
		||||
        let id = BufferId::new();
 | 
			
		||||
        let mut buffer_infos = self.resources.buffer_infos.write().unwrap();
 | 
			
		||||
        let mut buffers = self.resources.buffers.write().unwrap();
 | 
			
		||||
        buffer_infos.insert(id, buffer_info);
 | 
			
		||||
        buffers.insert(id, buffer);
 | 
			
		||||
        buffers.insert(id, Arc::new(buffer));
 | 
			
		||||
        id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -219,7 +188,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
 | 
			
		||||
 | 
			
		||||
        let id = BufferId::new();
 | 
			
		||||
        buffer_infos.insert(id, buffer_info);
 | 
			
		||||
        buffers.insert(id, buffer);
 | 
			
		||||
        buffers.insert(id, Arc::new(buffer));
 | 
			
		||||
        id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -522,4 +491,34 @@ impl RenderResourceContext for WgpuRenderResourceContext {
 | 
			
		||||
            .get(&buffer)
 | 
			
		||||
            .cloned()
 | 
			
		||||
    }
 | 
			
		||||
    fn write_mapped_buffer(
 | 
			
		||||
        &self,
 | 
			
		||||
        id: BufferId,
 | 
			
		||||
        range: Range<u64>,
 | 
			
		||||
        write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext),
 | 
			
		||||
    ) {
 | 
			
		||||
        let buffer = {
 | 
			
		||||
            let buffers = self.resources.buffers.read().unwrap();
 | 
			
		||||
            buffers.get(&id).unwrap().clone()
 | 
			
		||||
        };
 | 
			
		||||
        let buffer_slice = buffer.slice(range);
 | 
			
		||||
        let mut data = buffer_slice.get_mapped_range_mut();
 | 
			
		||||
        write(&mut data, self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn map_buffer(&self, id: BufferId) {
 | 
			
		||||
        let buffers = self.resources.buffers.read().unwrap();
 | 
			
		||||
        let buffer = buffers.get(&id).unwrap();
 | 
			
		||||
        let buffer_slice = buffer.slice(..);
 | 
			
		||||
        let data = buffer_slice.map_async(wgpu::MapMode::Write);
 | 
			
		||||
        self.device.poll(wgpu::Maintain::Wait);
 | 
			
		||||
        if let Err(_) = pollster::block_on(data) {
 | 
			
		||||
            panic!("failed to map buffer to host");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn unmap_buffer(&self, id: BufferId) {
 | 
			
		||||
        let buffers = self.resources.buffers.read().unwrap();
 | 
			
		||||
        let buffer = buffers.get(&id).unwrap();
 | 
			
		||||
        buffer.unmap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ pub struct WgpuBindGroupInfo {
 | 
			
		||||
/// Single threaded implementations don't need to worry about these lifetimes constraints at all. RenderPasses can use a RenderContext's
 | 
			
		||||
/// WgpuResources directly. RenderContext already has a lifetime greater than the RenderPass.
 | 
			
		||||
pub struct WgpuResourcesReadLock<'a> {
 | 
			
		||||
    pub buffers: RwLockReadGuard<'a, HashMap<BufferId, wgpu::Buffer>>,
 | 
			
		||||
    pub buffers: RwLockReadGuard<'a, HashMap<BufferId, Arc<wgpu::Buffer>>>,
 | 
			
		||||
    pub textures: RwLockReadGuard<'a, HashMap<TextureId, wgpu::TextureView>>,
 | 
			
		||||
    pub swap_chain_frames: RwLockReadGuard<'a, HashMap<TextureId, wgpu::SwapChainFrame>>,
 | 
			
		||||
    pub render_pipelines:
 | 
			
		||||
@ -61,7 +61,7 @@ impl<'a> WgpuResourcesReadLock<'a> {
 | 
			
		||||
 | 
			
		||||
/// Stores read only references to WgpuResource collections. See WgpuResourcesReadLock docs for context on why this exists
 | 
			
		||||
pub struct WgpuResourceRefs<'a> {
 | 
			
		||||
    pub buffers: &'a HashMap<BufferId, wgpu::Buffer>,
 | 
			
		||||
    pub buffers: &'a HashMap<BufferId, Arc<wgpu::Buffer>>,
 | 
			
		||||
    pub textures: &'a HashMap<TextureId, wgpu::TextureView>,
 | 
			
		||||
    pub swap_chain_frames: &'a HashMap<TextureId, wgpu::SwapChainFrame>,
 | 
			
		||||
    pub render_pipelines: &'a HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
 | 
			
		||||
@ -75,7 +75,7 @@ pub struct WgpuResources {
 | 
			
		||||
    pub window_surfaces: Arc<RwLock<HashMap<WindowId, wgpu::Surface>>>,
 | 
			
		||||
    pub window_swap_chains: Arc<RwLock<HashMap<WindowId, wgpu::SwapChain>>>,
 | 
			
		||||
    pub swap_chain_frames: Arc<RwLock<HashMap<TextureId, wgpu::SwapChainFrame>>>,
 | 
			
		||||
    pub buffers: Arc<RwLock<HashMap<BufferId, wgpu::Buffer>>>,
 | 
			
		||||
    pub buffers: Arc<RwLock<HashMap<BufferId, Arc<wgpu::Buffer>>>>,
 | 
			
		||||
    pub texture_views: Arc<RwLock<HashMap<TextureId, wgpu::TextureView>>>,
 | 
			
		||||
    pub textures: Arc<RwLock<HashMap<TextureId, wgpu::Texture>>>,
 | 
			
		||||
    pub samplers: Arc<RwLock<HashMap<SamplerId, wgpu::Sampler>>>,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user