Skip to main content

mesh_sieve/accelerator/
section.rs

1//! Explicit section transfers.
2
3use crate::data::section::Section;
4use crate::data::storage::Storage;
5
6use super::plan::{checked_u32, upload};
7use super::{AcceleratorBackend, AcceleratorError, DeviceBuffer, DeviceValue};
8
9/// A section layout and its values resident in backend-owned memory.
10pub struct DeviceSection<T: DeviceValue, B: AcceleratorBackend> {
11    /// Source atlas structural version.
12    pub atlas_version: u64,
13    /// Source mesh topology version supplied by the caller.
14    pub topology_version: u64,
15    /// Per-point offsets in atlas iteration order.
16    pub offsets: B::Buffer<u32>,
17    /// Per-point lengths in atlas iteration order.
18    pub lengths: B::Buffer<u32>,
19    /// Flat field values.
20    pub values: B::Buffer<T>,
21    /// Number of atlas points.
22    pub point_count: usize,
23    /// Number of scalar values.
24    pub value_count: usize,
25}
26
27impl<T: DeviceValue, B: AcceleratorBackend> DeviceSection<T, B> {
28    /// Upload atlas metadata and values from a host-accessible section.
29    pub fn upload_from<S: Storage<T>>(
30        backend: &B,
31        section: &Section<T, S>,
32        topology_version: u64,
33    ) -> Result<Self, AcceleratorError> {
34        checked_u32(section.atlas().len(), "atlas point count")?;
35        checked_u32(section.atlas().total_len(), "section value count")?;
36        let mut offsets = Vec::with_capacity(section.atlas().len());
37        let mut lengths = Vec::with_capacity(section.atlas().len());
38        for (offset, len) in section.atlas().iter_spans() {
39            offsets.push(checked_u32(offset, "atlas offset")?);
40            lengths.push(checked_u32(len, "atlas slice length")?);
41        }
42        Ok(Self {
43            atlas_version: section.atlas().version(),
44            topology_version,
45            offsets: upload(backend, &offsets)?,
46            lengths: upload(backend, &lengths)?,
47            values: upload(backend, section.as_flat_slice())?,
48            point_count: section.atlas().len(),
49            value_count: section.atlas().total_len(),
50        })
51    }
52
53    /// Refresh values without rebuilding layout metadata.
54    pub fn refresh_values_from<S: Storage<T>>(
55        &mut self,
56        backend: &B,
57        section: &Section<T, S>,
58        topology_version: u64,
59    ) -> Result<(), AcceleratorError> {
60        self.validate(section.atlas().version(), topology_version)?;
61        if section.as_flat_slice().len() != self.values.len() {
62            return Err(AcceleratorError::LengthMismatch {
63                expected: self.values.len(),
64                found: section.as_flat_slice().len(),
65            });
66        }
67        backend
68            .upload_into(section.as_flat_slice(), &mut self.values)
69            .map_err(|e| AcceleratorError::DeviceTransferFailed(e.to_string()))
70    }
71
72    /// Download values into a section with the same atlas layout.
73    pub fn download_into<S: Storage<T> + Clone>(
74        &self,
75        backend: &B,
76        section: &mut Section<T, S>,
77        topology_version: u64,
78    ) -> Result<(), AcceleratorError>
79    where
80        T: Clone + Default,
81    {
82        self.validate(section.atlas().version(), topology_version)?;
83        let mut host = vec![T::zeroed(); self.value_count];
84        backend
85            .download(&self.values, &mut host)
86            .map_err(|e| AcceleratorError::DeviceTransferFailed(e.to_string()))?;
87        section
88            .try_scatter_in_order(&host)
89            .map_err(|e| AcceleratorError::InvalidPlan(e.to_string()))
90    }
91
92    /// Validate both structural epochs used to construct this section.
93    pub fn validate(
94        &self,
95        atlas_version: u64,
96        topology_version: u64,
97    ) -> Result<(), AcceleratorError> {
98        if self.atlas_version != atlas_version {
99            return Err(AcceleratorError::StaleAtlasPlan {
100                expected: self.atlas_version,
101                found: atlas_version,
102            });
103        }
104        if self.topology_version != topology_version {
105            return Err(AcceleratorError::StaleTopologyPlan {
106                expected: self.topology_version,
107                found: topology_version,
108            });
109        }
110        Ok(())
111    }
112}