1use crate::{error::BufferError, pixel::PixelFormat};
4
5pub const DEFAULT_MAX_HOST_ALLOCATION_BYTES: usize = 512 * 1024 * 1024;
7
8pub fn ensure_allocation_within_cap(
10 len: usize,
11 cap: usize,
12 what: &'static str,
13) -> Result<usize, BufferError> {
14 if len > cap {
15 return Err(BufferError::AllocationTooLarge {
16 requested: len,
17 cap,
18 what,
19 });
20 }
21 Ok(len)
22}
23
24pub fn strided_output_len(
29 dimensions: (u32, u32),
30 stride: usize,
31 fmt: PixelFormat,
32) -> Result<usize, BufferError> {
33 if dimensions.0 == 0 || dimensions.1 == 0 {
34 return Ok(0);
35 }
36
37 let row_bytes = row_bytes(dimensions.0, fmt)?;
38 stride
39 .checked_mul(dimensions.1 as usize - 1)
40 .and_then(|prefix| prefix.checked_add(row_bytes))
41 .ok_or(BufferError::SizeOverflow {
42 what: "strided output size",
43 })
44}
45
46pub fn strided_output_len_capped(
48 dimensions: (u32, u32),
49 stride: usize,
50 fmt: PixelFormat,
51 cap: usize,
52 what: &'static str,
53) -> Result<usize, BufferError> {
54 let len = strided_output_len(dimensions, stride, fmt)?;
55 ensure_allocation_within_cap(len, cap, what)
56}
57
58pub fn validate_strided_output_buffer(
60 dimensions: (u32, u32),
61 out_len: usize,
62 stride: usize,
63 fmt: PixelFormat,
64) -> Result<(), BufferError> {
65 if dimensions.0 == 0 || dimensions.1 == 0 {
66 return Ok(());
67 }
68
69 let row_bytes = row_bytes(dimensions.0, fmt)?;
70 if stride < row_bytes {
71 return Err(BufferError::StrideTooSmall { row_bytes, stride });
72 }
73 let required = strided_output_len(dimensions, stride, fmt)?;
74 if out_len < required {
75 return Err(BufferError::OutputTooSmall {
76 required,
77 have: out_len,
78 });
79 }
80 Ok(())
81}
82
83pub fn copy_tight_pixels_to_strided_output(
88 src: &[u8],
89 dimensions: (u32, u32),
90 fmt: PixelFormat,
91 out: &mut [u8],
92 stride: usize,
93) -> Result<(), BufferError> {
94 if dimensions.0 == 0 || dimensions.1 == 0 {
95 return Ok(());
96 }
97
98 let row_bytes = row_bytes(dimensions.0, fmt)?;
99 let height = dimensions.1 as usize;
100 let required_src = row_bytes
101 .checked_mul(height)
102 .ok_or(BufferError::SizeOverflow {
103 what: "tight source size",
104 })?;
105 if src.len() < required_src {
106 return Err(BufferError::InputTooSmall {
107 required: required_src,
108 have: src.len(),
109 });
110 }
111 validate_strided_output_buffer(dimensions, out.len(), stride, fmt)?;
112
113 for y in 0..dimensions.1 as usize {
114 let src_row = &src[y * row_bytes..(y + 1) * row_bytes];
115 let dst_start = y * stride;
116 out[dst_start..dst_start + row_bytes].copy_from_slice(src_row);
117 }
118
119 Ok(())
120}
121
122fn row_bytes(width: u32, fmt: PixelFormat) -> Result<usize, BufferError> {
123 (width as usize)
124 .checked_mul(fmt.bytes_per_pixel())
125 .ok_or(BufferError::SizeOverflow {
126 what: "row byte count",
127 })
128}