Build a `size × size` BRDF LUT as packed Rg16Float texels. Each row is constant `roughness` (v axis), each column constant `NdotV` (u axis). Output is row-major suitable for write_texture. Splits across `available_parallelism()` threads since cells are independent — keeps startup latency manageable even at 1024 spp.
(size: usize)
| 126 | /// across `available_parallelism()` threads since cells are |
| 127 | /// independent — keeps startup latency manageable even at 1024 spp. |
| 128 | pub fn build_brdf_lut(size: usize) -> Vec<u16> { |
| 129 | #[cfg(not(target_arch = "wasm32"))] |
| 130 | { |
| 131 | let nthreads = std::thread::available_parallelism().map(|n| n.get()).unwrap_or(4); |
| 132 | let rows_per_thread = (size + nthreads - 1) / nthreads; |
| 133 | let mut all_rows: Vec<Option<Vec<Vec<u16>>>> = (0..nthreads).map(|_| None).collect(); |
| 134 | std::thread::scope(|s| { |
| 135 | let mut handles = Vec::with_capacity(nthreads); |
| 136 | for t in 0..nthreads { |
| 137 | let y_start = t * rows_per_thread; |
| 138 | let y_end = ((t + 1) * rows_per_thread).min(size); |
| 139 | let h = s.spawn(move || { |
| 140 | (y_start..y_end).map(|y| build_brdf_lut_row(y, size)).collect::<Vec<_>>() |
| 141 | }); |
| 142 | handles.push(h); |
| 143 | } |
| 144 | for (t, h) in handles.into_iter().enumerate() { |
| 145 | all_rows[t] = Some(h.join().unwrap()); |
| 146 | } |
| 147 | }); |
| 148 | all_rows.into_iter().flatten().flatten().flatten().collect() |
| 149 | } |
| 150 | #[cfg(target_arch = "wasm32")] |
| 151 | { |
| 152 | (0..size).flat_map(|y| build_brdf_lut_row(y, size)).collect() |
| 153 | } |
| 154 | } |
no test coverage detected