1use alloc::vec;
27use alloc::vec::Vec;
28
29use gfx::{Surface, FMT_ARGB};
30use img_core::resample::{from_work, to_work};
31use rt::fx::{cvtd64, cvttd, maxsd, minsd};
32use simd::{Kernel, Simd, Sse2};
33
34use crate::lut::luma;
35use crate::*;
36
37pub const FXL_GAMMA: u32 = 1; pub const FXL_ZERO: u32 = 2; pub const KT_COPY: u32 = 0;
40pub const KT_FIR: u32 = 1;
41pub const KT_BOX: u32 = 2;
42pub const KN_MAXTAPS: usize = 255;
43pub const KN_MAXBOX: usize = 8;
44const FIR_MAXVAR12: i32 = 432; const SEP_MAXBYTES: u64 = 16_777_216; pub const DSF_F32: u32 = 1; static EXPC: [f64; 13] = [
51 2.08767569878680989792e-09,
52 2.50521083854417187751e-08,
53 2.75573192239858906526e-07,
54 2.75573192239858906526e-06,
55 2.48015873015873015873e-05,
56 1.98412698412698412698e-04,
57 1.38888888888888888889e-03,
58 8.33333333333333333333e-03,
59 4.16666666666666666667e-02,
60 1.66666666666666666667e-01,
61 0.5,
62 1.0,
63 1.0,
64];
65static LNC: [f64; 11] = [
66 0.0952380952380952380952,
67 0.105263157894736842105,
68 0.117647058823529411765,
69 0.133333333333333333333,
70 0.153846153846153846154,
71 0.181818181818181818182,
72 0.222222222222222222222,
73 0.285714285714285714286,
74 0.4,
75 0.666666666666666666667,
76 2.0,
77];
78const LN2HI: f64 = f64::from_bits(0x3FE6_2E42_FEE0_0000);
79const LN2LO: f64 = f64::from_bits(0x3DEA_39EF_3579_3C76);
80
81pub fn exp(x: f64) -> f64 {
83 let x = maxsd(minsd(x, 709.0), -708.0);
84 let k = cvtd64(x * 1.4426950408889634074);
85 let kd = k as f64;
86 let mut r = x - kd * LN2HI;
87 r -= kd * LN2LO;
88 let mut p = EXPC[0];
89 for c in &EXPC[1..] {
90 p = p * r + *c;
91 }
92 p * f64::from_bits(((k + 1023) as u64) << 52)
93}
94
95pub fn ln(x: f64) -> f64 {
97 if !(x > 0.0) {
98 return -745.0;
99 }
100 let b = x.to_bits();
101 let ex = (b >> 52) as i32 & 0x7FF;
102 if ex == 0 {
103 return -745.0;
104 }
105 let mut e = ex - 1023;
106 let mut m = b & 0x000F_FFFF_FFFF_FFFF | 0x3FF0_0000_0000_0000;
107 if m >= 0x3FF6_A09E_667F_3BCD {
108 m -= 0x0010_0000_0000_0000;
109 e += 1;
110 }
111 let m = f64::from_bits(m);
112 let s = (m - 1.0) / (m + 1.0);
113 let z = s * s;
114 let mut p = LNC[0];
115 for c in &LNC[1..] {
116 p = p * z + *c;
117 }
118 let lnm = p * s;
119 let ed = e as f64;
120 ed * LN2HI + (lnm + ed * LN2LO)
121}
122
123pub fn pow(x: f64, y: f64) -> f64 {
125 if !(x > 0.0) {
126 return 0.0;
127 }
128 exp(ln(x) * y)
129}
130
131pub fn roi(a: &FxArgs) -> Option<[i32; 4]> {
135 let r = [a.x0.max(0), a.y0.max(0), a.x1.min(a.src.w), a.y1.min(a.src.h)];
136 if r[0] < r[2] && r[1] < r[3] { Some(r) } else { None }
137}
138
139pub fn copy_roi(a: &FxArgs, dst: &mut Dst) -> i32 {
141 let Some(r) = roi(a) else {
142 return 0;
143 };
144 for y in r[1]..r[3] {
145 if a.cancelled() {
146 return ERR_CANCEL;
147 }
148 let s = &a.src_row(y)[r[0] as usize * 4..r[2] as usize * 4];
149 dst_px(dst, y, r[0], r[2] - r[0]).copy_from_slice(s);
150 }
151 0
152}
153
154#[inline]
156pub fn dst_px<'d>(dst: &'d mut Dst, y: i32, x0: i32, n: i32) -> &'d mut [u8] {
157 let o = (x0 - dst.x0) as usize * 4;
158 &mut dst.row(y)[o..o + n as usize * 4]
159}
160
161#[inline]
163pub fn pint(a: &FxArgs, slot: usize, lo: i32, hi: i32) -> i32 {
164 a.params.int(slot & (FX_NSLOTS - 1), lo, hi)
165}
166
167#[inline]
169pub fn pdbl(a: &FxArgs, slot: usize) -> f64 {
170 let v = a.params.f(slot & (FX_NSLOTS - 1));
171 if (v.to_bits() >> 52) & 0x7FF == 0x7FF {
172 return 0.0;
173 }
174 minsd(maxsd(v, -1000000.0), 1000000.0)
175}
176
177pub fn load_row(dst: &mut [i16], src: &Surface, y: i32, x0: i32, x1: i32, mode: u32) {
182 let n = x1 - x0;
183 if n <= 0 {
184 return;
185 }
186 let mut y = y;
187 if y >= src.h || y < 0 {
188 if mode & FXL_ZERO != 0 {
189 dst[..n as usize * 4].fill(0);
190 return;
191 }
192 y = if y < 0 { 0 } else { src.h - 1 };
193 }
194 let row = row(src, y);
195 let g = mode & FXL_GAMMA;
196 let nl = (-x0).clamp(0, n);
197 let nr = (x1 - src.w).clamp(0, n);
198 let nm = n - nl - nr;
199 if nm > 0 {
200 let c = (x0 + nl) as usize * 4;
201 to_work(&mut dst[nl as usize * 4..], &row[c..], nm as usize, FMT_ARGB, g);
202 }
203 if nl > 0 {
204 let v: [i16; 4] = if mode & FXL_ZERO != 0 {
205 [0; 4]
206 } else if nm > 0 {
207 dst[nl as usize * 4..nl as usize * 4 + 4].try_into().unwrap()
208 } else {
209 to_work(&mut dst[..4], row, 1, FMT_ARGB, g);
210 dst[..4].try_into().unwrap()
211 };
212 for p in dst[..nl as usize * 4].chunks_exact_mut(4) {
213 p.copy_from_slice(&v);
214 }
215 }
216 if nr > 0 {
217 let f = (nl + nm) as usize * 4;
218 let v: [i16; 4] = if mode & FXL_ZERO != 0 {
219 [0; 4]
220 } else if nm > 0 {
221 dst[f - 4..f].try_into().unwrap()
222 } else {
223 to_work(&mut dst[f..f + 4], &row[(src.w as usize - 1) * 4..], 1, FMT_ARGB, g);
224 dst[f..f + 4].try_into().unwrap()
225 };
226 for p in dst[f..f + nr as usize * 4].chunks_exact_mut(4) {
227 p.copy_from_slice(&v);
228 }
229 }
230}
231
232#[inline]
236pub fn var12(r: i32) -> i32 {
237 if r <= 0 { 0 } else { (r + 2).wrapping_mul(r) * 2 }
238}
239
240#[derive(Clone)]
242pub struct Kern {
243 pub typ: u32,
244 pub halo: i32,
245 pub n: i32, pub w: [i16; 256], pub h: [i32; KN_MAXBOX], }
249
250impl Kern {
251 pub fn copy() -> Kern {
253 Kern { typ: KT_COPY, halo: 0, n: 0, w: [0; 256], h: [0; KN_MAXBOX] }
254 }
255
256 pub fn boxk(h: i32) -> Kern {
258 let mut k = Kern::copy();
259 if h > 0 {
260 k.typ = KT_BOX;
261 k.halo = h;
262 k.n = 1;
263 k.h[0] = h;
264 }
265 k
266 }
267
268 pub fn gauss(var12: i32) -> Kern {
275 let mut k = Kern::copy();
276 if var12 <= 0 {
277 return k;
278 }
279 if var12 <= FIR_MAXVAR12 {
280 let x = rt::fx::sqrtd(var12 as f64 * 0.75);
281 let mut h = cvttd(x);
282 if x > h as f64 {
283 h += 1;
284 }
285 let h = h.clamp(1, 18);
286 let c = -6.0 / var12 as f64;
287 let mut g = [0f64; 19];
288 for (i, gv) in g.iter_mut().enumerate().take(h as usize + 1) {
289 *gv = exp(((i * i) as i32) as f64 * c);
290 }
291 let mut sum = g[0];
292 for &gv in g.iter().take(h as usize + 1).skip(1) {
293 sum += gv + gv;
294 }
295 let inv = 16384.0 / sum;
296 let hu = h as usize;
297 let mut total = 0i32;
298 for (i, &gv) in g.iter().enumerate().take(hu + 1) {
299 let q = cvttd(gv * inv + 0.5);
300 k.w[hu + i] = q as i16;
301 k.w[hu - i] = q as i16;
302 total += q;
303 if i != 0 {
304 total += q;
305 }
306 }
307 k.w[hu] = k.w[hu].wrapping_add((16384 - total) as i16);
308 k.w[2 * hu + 1] = 0;
309 k.typ = KT_FIR;
310 k.halo = h;
311 k.n = 2 * h + 1;
312 return k;
313 }
314 let mut wl = 1i32;
315 while (wl + 2) * (wl + 2) * 3 <= var12 + 3 {
316 wl += 2;
317 }
318 let num = wl * wl * 3 + wl * 12 + 9 - var12;
319 let den = wl * 4 + 4;
320 let m = (((2 * num + den) as u32) / ((2 * den) as u32)).min(3) as i32;
321 let mut halo = 0;
322 for b in 0..3 {
323 let w = if b < m { wl } else { wl + 2 };
324 k.h[b as usize] = w >> 1;
325 halo += w >> 1;
326 }
327 k.typ = KT_BOX;
328 k.halo = halo;
329 k.n = 3;
330 k
331 }
332
333 #[inline]
335 fn fir_taps(&self) -> usize {
336 let n = (self.n as usize).min(KN_MAXTAPS);
337 n.div_ceil(2) * 2
338 }
339}
340
341#[inline(always)]
344fn sat16(v: i32) -> i16 {
345 v.clamp(-32768, 32767) as i16
346}
347
348#[inline(always)]
350fn pair_w(w: &[i16], p: usize) -> u32 {
351 w[2 * p] as u16 as u32 | (w[2 * p + 1] as u16 as u32) << 16
352}
353
354#[inline(always)]
356fn pair<S: Simd>(s: S, v: S::V) -> S::V {
357 s.shuf16::<0xD8>(s.shuf32::<0xD8>(v))
358}
359
360#[inline(always)]
362fn fir_h_px(dst: &mut [i16], src: &[i16], i: usize, w: &[i16]) {
363 let mut acc = [0i32; 4];
364 for (j, &wj) in w.iter().enumerate() {
365 if wj == 0 {
366 continue;
367 }
368 let p = &src[(i + j) * 4..(i + j) * 4 + 4];
369 for c in 0..4 {
370 acc[c] = acc[c].wrapping_add(p[c] as i32 * wj as i32);
371 }
372 }
373 for c in 0..4 {
374 dst[i * 4 + c] = sat16(acc[c].wrapping_add(8192) >> 14);
375 }
376}
377
378struct FirHK<'a> {
381 dst: &'a mut [i16],
382 src: &'a [i16],
383 n: usize,
384 w: &'a [i16],
385}
386
387impl Kernel for FirHK<'_> {
388 type Out = ();
389 #[inline(always)]
390 fn run<S: Simd>(self, s: S) {
391 let FirHK { dst, src, n, w } = self;
392 let np = w.len() / 2;
393 let step = S::BYTES / 8;
394 let r = s.splat32(8192);
395 let mut i = 0;
396 while i + step <= n && (i + step + 2 * np) * 4 <= src.len() {
397 let (mut lo, mut hi) = (s.zero(), s.zero());
398 for p in 0..np {
399 let wv = s.splat32(pair_w(w, p));
400 let a = pair(s, s.load_i16(&src[(i + 2 * p) * 4..]));
401 let b = pair(s, s.load_i16(&src[(i + 1 + 2 * p) * 4..]));
402 lo = s.add32(lo, s.madd16(a, wv));
403 hi = s.add32(hi, s.madd16(b, wv));
404 }
405 let lo = s.sra32::<14>(s.add32(lo, r));
406 let hi = s.sra32::<14>(s.add32(hi, r));
407 s.store_i16(&mut dst[i * 4..], s.packs32(lo, hi));
408 i += step;
409 }
410 while i < n {
411 fir_h_px(dst, src, i, w);
412 i += 1;
413 }
414 }
415}
416
417fn fir_h(dst: &mut [i16], src: &[i16], n: usize, w: &[i16]) {
419 simd::dispatch(FirHK { dst, src, n, w });
420}
421
422type V = <Sse2 as Simd>::V;
423
424#[inline(always)]
426fn box_mean(v: V, inv: V) -> V {
427 let x = Sse2;
428 x.cvtr_f32_i32(x.mulf(x.cvt_i32_f32(v), inv))
429}
430
431#[inline(always)]
433fn store2(dst: &mut [i16], a: V, b: V, two: bool) {
434 let x = Sse2;
435 if two {
436 x.store_i16(dst, x.packs32(a, b));
437 } else {
438 let mut t = [0i16; 8];
439 x.store_i16(&mut t, x.packs32(a, a));
440 dst[..4].copy_from_slice(&t[..4]);
441 }
442}
443
444fn box_h(dst: &mut [i16], src: &[i16], n: usize, h: i32) {
447 if n == 0 {
448 return;
449 }
450 let x = Sse2;
451 let z = x.zero();
452 let w = (2 * h + 1) as usize;
453 let inv = x.splatf(1.0f32 / w as i32 as f32);
454 let px = |i: usize| x.unpacklo16(x.load_i16(&src[i * 4..]), z);
455 let mut sum = z;
456 for k in 0..w {
457 sum = x.add32(sum, px(k));
458 }
459 let mut i = 0;
460 while i < n {
461 let v0 = box_mean(sum, inv);
462 if i + 1 == n {
463 store2(&mut dst[i * 4..], v0, v0, false);
464 break;
465 }
466 sum = x.sub32(x.add32(sum, px(i + w)), px(i));
467 let v1 = box_mean(sum, inv);
468 store2(&mut dst[i * 4..], v0, v1, true);
469 if i + 2 < n {
470 sum = x.sub32(x.add32(sum, px(i + 1 + w)), px(i + 1));
471 }
472 i += 2;
473 }
474}
475
476struct FirVK<'a> {
478 out: &'a mut [i16],
479 src: &'a [i16],
480 rows: &'a [usize],
481 n: usize,
482 tw: usize,
483 w: &'a [i16],
484}
485
486impl Kernel for FirVK<'_> {
487 type Out = ();
488 #[inline(always)]
489 fn run<S: Simd>(self, s: S) {
490 let FirVK { out, src, rows, n, tw, w } = self;
491 let np = w.len() / 2;
492 let step = S::BYTES / 8;
493 let r = s.splat32(8192);
494 for k in 0..n {
495 let o = &mut out[k * tw * 4..(k + 1) * tw * 4];
496 let mut x = 0;
497 while x + step <= tw {
498 let (mut lo, mut hi) = (s.zero(), s.zero());
499 for p in 0..np {
500 let wv = s.splat32(pair_w(w, p));
501 let a = s.load_i16(&src[rows[k + 2 * p] + x * 4..]);
502 let b = s.load_i16(&src[rows[k + 2 * p + 1] + x * 4..]);
503 lo = s.add32(lo, s.madd16(s.unpacklo16(a, b), wv));
504 hi = s.add32(hi, s.madd16(s.unpackhi16(a, b), wv));
505 }
506 let lo = s.sra32::<14>(s.add32(lo, r));
507 let hi = s.sra32::<14>(s.add32(hi, r));
508 s.store_i16(&mut o[x * 4..], s.packs32(lo, hi));
509 x += step;
510 }
511 for i in x * 4..tw * 4 {
512 let mut a = 0i32;
513 for (j, &wj) in w.iter().enumerate() {
514 if wj != 0 {
515 a = a.wrapping_add(src[rows[k + j] + i] as i32 * wj as i32);
516 }
517 }
518 o[i] = sat16(a.wrapping_add(8192) >> 14);
519 }
520 }
521 }
522}
523
524fn fir_v(out: &mut [i16], src: &[i16], rows: &[usize], n: usize, tw: usize, w: &[i16]) {
527 simd::dispatch(FirVK { out, src, rows, n, tw, w });
528}
529
530fn box_v(out: &mut [i16], src: &[i16], rows: &[usize], n: usize, tw: usize, h: i32, acc: &mut [i32]) {
533 let x = Sse2;
534 let w = (2 * h + 1) as usize;
535 let inv = x.splatf(1.0f32 / w as i32 as f32);
536 let acc = &mut acc[..tw * 4];
537 acc.fill(0);
538 for &r in rows.iter().take(w) {
539 for (a, &p) in acc.iter_mut().zip(src[r..r + tw * 4].iter()) {
540 *a = a.wrapping_add(p as u16 as i32);
541 }
542 }
543 for k in 0..n {
544 let o = &mut out[k * tw * 4..(k + 1) * tw * 4];
545 let mut i = 0;
546 while i < tw {
547 let a = box_mean(x.load_i32(&acc[i * 4..]), inv);
548 if i + 1 < tw {
549 let b = box_mean(x.load_i32(&acc[(i + 1) * 4..]), inv);
550 store2(&mut o[i * 4..], a, b, true);
551 } else {
552 store2(&mut o[i * 4..], a, a, false);
553 }
554 i += 2;
555 }
556 if k + 1 < n {
557 let (lv, en) = (&src[rows[k]..rows[k] + tw * 4], &src[rows[k + w]..rows[k + w] + tw * 4]);
558 for ((a, &e), &l) in acc.iter_mut().zip(en.iter()).zip(lv.iter()) {
559 *a = a.wrapping_add(e as u16 as i32).wrapping_sub(l as u16 as i32);
560 }
561 }
562 }
563}
564
565pub struct Sep<'a> {
569 pub src: &'a Surface,
570 pub job: Option<&'a (dyn Cancel + Sync)>,
571 pub kh: &'a Kern,
572 pub kv: Option<&'a Kern>,
573 pub x0: i32,
574 pub y0: i32,
575 pub x1: i32,
576 pub y1: i32,
577 pub mode: u32,
578 pub custom_load: bool,
580}
581
582impl<'a> Sep<'a> {
583 pub fn new(a: &FxArgs<'a>, k: &'a Kern) -> Option<Sep<'a>> {
586 let r = roi(a)?;
587 Some(Sep { src: a.src, job: a.job, kh: k, kv: None, x0: r[0], y0: r[1], x1: r[2], y1: r[3], mode: 0, custom_load: false })
588 }
589 #[inline]
590 fn cancelled(&self) -> bool {
591 self.job.is_some_and(|j| j.cancelled())
592 }
593}
594
595pub trait SepIo {
597 fn load(&mut self, _sep: &Sep, _w16: &mut [i16], _y: i32, _x0: i32, _x1: i32) {}
599 fn emit(&mut self, sep: &Sep, y: i32, row: &[i16]);
601}
602
603pub struct EmitArgb<'d, 'e>(pub &'d mut Dst<'e>);
605
606impl SepIo for EmitArgb<'_, '_> {
607 fn emit(&mut self, sep: &Sep, y: i32, row: &[i16]) {
608 let n = sep.x1 - sep.x0;
609 from_work(dst_px(self.0, y, sep.x0, n), row, n as usize, FMT_ARGB, sep.mode & FXL_GAMMA);
610 }
611}
612
613pub fn sep_run(sep: &Sep, io: &mut impl SepIo) -> i32 {
617 let kh = sep.kh;
618 let kv = sep.kv.unwrap_or(kh);
619 let (hx, hy) = (kh.halo, kv.halo);
620 let tw = sep.x1 - sep.x0;
621 if tw <= 0 || sep.y1 <= sep.y0 {
622 return 0;
623 }
624 let l = (tw + 2 * hx) as usize;
625 let tw = tw as usize;
626 let rb = tw as u64 * 8;
627 let mut s = 256i32;
628 while s > 16 && (s + 2 * hy) as u64 * rb > SEP_MAXBYTES {
629 s >>= 1;
630 }
631 let nrmax = (s + 2 * hy) as usize;
632 let imgh = sep.src.h;
633 let clamp = !sep.custom_load && sep.mode & FXL_ZERO == 0;
634 let vbox = kv.typ == KT_BOX;
636 let (l4, big) = ((l + 4) * 4, nrmax * tw * 4);
637 let nb = if vbox { big } else { 0 };
638 let mut buf = vec![0i16; 3 * l4 + big + 2 * nb + s as usize * tw * 4];
639 let (inb, rest) = buf.split_at_mut(l4);
640 let (ha, rest) = rest.split_at_mut(l4);
641 let (hb, rest) = rest.split_at_mut(l4);
642 let (t, rest) = rest.split_at_mut(big);
643 let (b1, rest) = rest.split_at_mut(nb);
644 let (b2, out) = rest.split_at_mut(nb);
645 let mut tabs = vec![0usize; 2 * nrmax + 2];
647 let (pt, ident) = tabs.split_at_mut(nrmax + 2);
648 for (k, v) in ident.iter_mut().enumerate() {
649 *v = k * tw * 4;
650 }
651 let mut acc = vec![0i32; if vbox { tw * 4 } else { 0 }];
652 let wh: &[i16] = &kh.w[..kh.fir_taps()];
653 let wv: &[i16] = &kv.w[..kv.fir_taps()];
654 let mut sy0 = sep.y0;
655 while sy0 < sep.y1 {
656 let sy1 = (sy0 + s).min(sep.y1);
657 let ra = sy0 - hy;
658 let rbnd = sy1 + hy;
659 let (ta, tb) = if clamp { (ra.max(0), rbnd.min(imgh)) } else { (ra, rbnd) };
660 for (k, y) in (ta..tb).enumerate() {
662 if sep.cancelled() {
663 return ERR_CANCEL;
664 }
665 let (x0, x1) = (sep.x0 - hx, sep.x1 + hx);
666 if sep.custom_load {
667 io.load(sep, inb, y, x0, x1);
668 } else {
669 load_row(inb, sep.src, y, x0, x1, sep.mode);
670 }
671 let trow = &mut t[k * tw * 4..(k + 1) * tw * 4];
672 match kh.typ {
673 KT_FIR => fir_h(trow, inb, tw, wh),
674 KT_BOX => {
675 let mut len = l;
676 let nb = (kh.n as usize).min(KN_MAXBOX);
677 for b in 0..nb {
678 let h = kh.h[b];
679 let nlen = len - 2 * h as usize;
680 let last = b + 1 >= kh.n as usize;
681 match (b, last) {
683 (0, true) => box_h(trow, inb, nlen, h),
684 (0, false) => box_h(ha, inb, nlen, h),
685 (_, true) if b % 2 == 1 => box_h(trow, ha, nlen, h),
686 (_, true) => box_h(trow, hb, nlen, h),
687 (_, false) if b % 2 == 1 => box_h(hb, ha, nlen, h),
688 (_, false) => box_h(ha, hb, nlen, h),
689 }
690 len = nlen;
691 }
692 }
693 _ => trow.copy_from_slice(&inb[..tw * 4]),
694 }
695 }
696 let nv = (rbnd - ra) as usize;
698 for (k, v) in pt[..nv].iter_mut().enumerate() {
699 let y = (ra + k as i32).clamp(ta, tb - 1) - ta;
700 *v = y as usize * tw * 4;
701 }
702 pt[nv] = pt[nv - 1];
703 pt[nv + 1] = pt[nv - 1];
704 let ptr: &[usize] = &pt[..nv + 2];
705 let nrows = (sy1 - sy0) as usize;
706 let res: Option<&[i16]> = match kv.typ {
708 KT_FIR => {
709 fir_v(out, t, ptr, nrows, tw, wv);
710 Some(&*out)
711 }
712 KT_BOX => {
713 let nb = (kv.n as usize).min(KN_MAXBOX);
716 let mut nin = nv;
717 for b in 0..nb {
718 let h = kv.h[b];
719 let nprev = nin;
720 nin -= 2 * h as usize;
721 let last = b + 1 >= kv.n as usize;
722 if b == 0 {
723 box_v(if last { &mut *out } else { &mut *b1 }, t, ptr, nin, tw, h, &mut acc);
724 } else if b % 2 == 1 {
725 box_v(if last { &mut *out } else { &mut *b2 }, b1, &ident[..nprev], nin, tw, h, &mut acc);
726 } else {
727 box_v(if last { &mut *out } else { &mut *b1 }, b2, &ident[..nprev], nin, tw, h, &mut acc);
728 }
729 }
730 Some(&*out)
731 }
732 _ => None,
733 };
734 for k in 0..nrows {
736 if sep.cancelled() {
737 return ERR_CANCEL;
738 }
739 let row: &[i16] = match res {
740 Some(o) => &o[k * tw * 4..(k + 1) * tw * 4],
741 None => &t[ptr[k]..ptr[k] + tw * 4],
742 };
743 io.emit(sep, sy0 + k as i32, row);
744 }
745 sy0 = sy1;
746 }
747 0
748}
749
750pub fn disc_edges(r: i32) -> (Vec<i32>, i32) {
755 let cutoff = ((2 * r + 1) * (2 * r + 1) + 2) >> 2;
756 let mut e = vec![0i32; r.max(0) as usize + 1];
757 let mut area = 0;
758 for v in 0..=r.max(0) {
759 let mut u = 0;
760 while u < r && (u + 1) * (u + 1) + v * v <= cutoff {
761 u += 1;
762 }
763 e[v as usize] = u;
764 area += if v == 0 { 2 * u + 1 } else { 2 * (2 * u + 1) };
765 }
766 (e, area)
767}
768
769pub struct Disc<'a> {
771 pub src: &'a Surface,
772 pub job: Option<&'a (dyn Cancel + Sync)>,
773 pub r: i32,
774 pub flags: u32,
775 pub x0: i32,
776 pub y0: i32,
777 pub x1: i32,
778 pub y1: i32,
779 pub mode: u32,
780 pub area: i32,
782 pub custom_prep: bool,
784}
785
786impl<'a> Disc<'a> {
787 pub fn new(a: &FxArgs<'a>, r: i32) -> Option<Disc<'a>> {
789 let rc = roi(a)?;
790 Some(Disc { src: a.src, job: a.job, r, flags: 0, x0: rc[0], y0: rc[1], x1: rc[2], y1: rc[3], mode: 0, area: 0, custom_prep: false })
791 }
792 #[inline]
793 fn cancelled(&self) -> bool {
794 self.job.is_some_and(|j| j.cancelled())
795 }
796}
797
798#[non_exhaustive]
800pub enum DiscRow<'r> {
801 I(&'r mut [i32]),
802 F(&'r mut [f32]),
803}
804
805pub trait DiscIo {
807 fn prep(&mut self, _d: &Disc, _v: &mut [i32], _y: i32, _x0: i32, _x1: i32) {}
809 fn emit(&mut self, d: &Disc, y: i32, row: DiscRow);
810}
811
812pub struct DiscArgb<'d, 'e>(pub &'d mut Dst<'e>);
815
816impl DiscIo for DiscArgb<'_, '_> {
817 fn emit(&mut self, d: &Disc, y: i32, row: DiscRow) {
818 let n = d.x1 - d.x0;
819 if n <= 0 {
820 return;
821 }
822 let inv = Sse2.splatf(1.0f32 / d.area as f32);
823 let DiscRow::I(r) = row else {
824 return;
825 };
826 let mut w = [0i16; DE_CHUNK * 4];
828 let mut x = 0usize;
829 for c in r[..n as usize * 4].chunks(DE_CHUNK * 4) {
830 let m = c.len() / 4;
831 for (o, q) in w.chunks_exact_mut(8).zip(c.chunks(8)) {
832 let sv = Sse2;
833 let a = sv.cvtr_f32_i32(sv.mulf(sv.cvt_i32_f32(sv.load_i32(&q[..4])), inv));
834 let b = if q.len() == 8 { sv.cvtr_f32_i32(sv.mulf(sv.cvt_i32_f32(sv.load_i32(&q[4..])), inv)) } else { a };
835 sv.store_i16(o, sv.packs32(a, b));
836 }
837 from_work(dst_px(self.0, y, d.x0 + x as i32, m as i32), &w[..m * 4], m, FMT_ARGB, d.mode & FXL_GAMMA);
838 x += m;
839 }
840 }
841}
842
843pub(crate) const DE_CHUNK: usize = 256;
845
846pub fn disc_run(d: &mut Disc, io: &mut impl DiscIo) -> i32 {
851 let r = d.r.clamp(0, 1000);
852 let tw = d.x1 - d.x0;
853 if tw <= 0 || d.y1 <= d.y0 {
854 return 0;
855 }
856 let l = (tw + 2 * r) as usize;
857 let tw = tw as usize;
858 let prb = (l as u64 + 1) * 16;
859 let imgh = d.src.h;
860 let mut s = 128i32;
861 while s > 8 && (s + 2 * r) as u64 * prb > SEP_MAXBYTES {
862 s >>= 1;
863 }
864 let nrmax = (s + 2 * r) as usize;
865 let (e, area) = disc_edges(r);
866 d.area = area;
867 let pw = (l + 1) * 4; let f32m = d.flags & DSF_F32 != 0;
870 let nv = if d.custom_prep { (l + 4) * 4 } else { 0 };
871 let na = if f32m { 0 } else { tw * 4 };
872 let mut ibuf = vec![0i32; nv + nrmax * pw + na];
873 let (v, rest) = ibuf.split_at_mut(nv);
874 let (p, acc_i) = rest.split_at_mut(nrmax * pw);
875 let mut w16 = vec![0i16; if d.custom_prep { 0 } else { (l + 4) * 4 }];
876 let mut acc_f = vec![0f32; if f32m { tw * 4 } else { 0 }];
877 let mut sy0 = d.y0;
878 while sy0 < d.y1 {
879 let sy1 = (sy0 + s).min(d.y1);
880 let ra = sy0 - r;
881 let ta = ra.max(0);
882 let tb = (sy1 + r).min(imgh);
883 for (k, y) in (ta..tb).enumerate() {
885 if d.cancelled() {
886 return ERR_CANCEL;
887 }
888 let (x0, x1) = (d.x0 - r, d.x1 + r);
889 let pr = &mut p[k * pw..(k + 1) * pw];
890 pr[..4].fill(0);
891 let x = Sse2;
892 let mut sum = x.zero();
893 if d.custom_prep {
894 io.prep(d, v, y, x0, x1);
895 for (o, q) in pr[4..].chunks_exact_mut(4).zip(v[..l * 4].chunks_exact(4)) {
896 sum = x.add32(sum, x.load_i32(q));
897 x.store_i32(o, sum);
898 }
899 } else {
900 load_row(&mut w16, d.src, y, x0, x1, d.mode);
901 let z = x.zero();
903 for (i, o) in pr[4..].chunks_exact_mut(4).enumerate() {
904 sum = x.add32(sum, x.unpacklo16(x.load_i16(&w16[i * 4..]), z));
905 x.store_i32(o, sum);
906 }
907 }
908 }
909 let nrows = (sy1 - sy0) as usize;
910 for kk in 0..nrows {
911 if d.cancelled() {
912 return ERR_CANCEL;
913 }
914 acc_i.fill(0);
915 acc_f.fill(0.0);
916 for j in 0..=(2 * r) as usize {
917 let vv = j as i32 - r;
918 let ev = e[vv.unsigned_abs() as usize] as usize;
919 let y = (ra + (kk + j) as i32).clamp(ta, tb - 1) - ta;
920 let pr = &p[y as usize * pw..(y as usize + 1) * pw];
921 let ho = (r as usize + ev + 1) * 4;
922 let lo = (r as usize - ev) * 4;
923 let (hi, lo) = (&pr[ho..ho + tw * 4], &pr[lo..lo + tw * 4]);
924 if f32m {
925 for ((a, &h), &l) in acc_f.iter_mut().zip(hi).zip(lo) {
926 *a += h.wrapping_sub(l) as f32;
927 }
928 } else {
929 for ((a, &h), &l) in acc_i.iter_mut().zip(hi).zip(lo) {
930 *a = a.wrapping_add(h.wrapping_sub(l));
931 }
932 }
933 }
934 let row = if f32m { DiscRow::F(&mut acc_f) } else { DiscRow::I(&mut *acc_i) };
935 io.emit(d, sy0 + kk as i32, row);
936 }
937 sy0 = sy1;
938 }
939 0
940}
941
942pub fn bac_init(b: i32, c: i32) -> ([i32; 256], u32) {
948 let (mul, div) = if c < 0 {
949 (c + 100, 100)
950 } else if c == 0 {
951 (1, 1)
952 } else {
953 (100, 100 - c)
954 };
955 let mut tab = [0i32; 256];
956 if div == 0 {
957 for (i, t) in tab.iter_mut().enumerate() {
958 *t = if i as i32 + b < 128 { 0 } else { 255 };
959 }
960 return (tab, 2);
961 }
962 let mode = if div == 100 { 0 } else { 1 };
963 for (i, t) in tab.iter_mut().enumerate() {
964 let i = i as i32;
965 let mut v = i - 127;
966 if mode != 0 {
967 v += b;
968 }
969 let mut r = v.wrapping_mul(mul) / div + 127 - i;
970 if mode == 0 {
971 r += b;
972 }
973 *t = r;
974 }
975 (tab, mode)
976}
977
978pub fn bac_row_inplace(row: &mut [u8], tab: &[i32; 256], mode: u32) {
981 for i in 0..row.len() / 4 {
982 let p = px(row, i);
983 let t = tab[luma(p) as usize];
984 let o = if mode == 2 {
985 (t as u32).wrapping_mul(0x010101) | p & 0xFF00_0000
986 } else {
987 let mut o = p & 0xFF00_0000;
988 for sh in [0, 8, 16] {
989 let v = ((p >> sh & 255) as i32 + t).clamp(0, 255) as u32;
990 o |= v << sh;
991 }
992 o
993 };
994 put(row, i, o);
995 }
996}
997
998pub fn desat_row(dst: &mut [u8], src: &[u8]) {
1000 for i in 0..src.len() / 4 {
1001 let p = px(src, i);
1002 put(dst, i, luma(p) * 0x010101 | p & 0xFF00_0000);
1003 }
1004}
1005
1006pub fn desat_inplace(row: &mut [u8]) {
1008 for i in 0..row.len() / 4 {
1009 let p = px(row, i);
1010 put(row, i, luma(p) * 0x010101 | p & 0xFF00_0000);
1011 }
1012}
1013
1014struct BlurBac<'d, 'e, 'f, F: FnMut(&mut Dst, i32, i32, &mut [u8])> {
1015 dst: &'d mut Dst<'e>,
1016 tab: [i32; 256],
1017 mode: u32,
1018 tmp: Vec<u8>,
1019 f: &'f mut F,
1020}
1021
1022impl<F: FnMut(&mut Dst, i32, i32, &mut [u8])> SepIo for BlurBac<'_, '_, '_, F> {
1023 fn emit(&mut self, sep: &Sep, y: i32, row: &[i16]) {
1024 let n = (sep.x1 - sep.x0) as usize;
1025 from_work(&mut self.tmp[..n * 4], row, n, FMT_ARGB, 0);
1026 bac_row_inplace(&mut self.tmp[..n * 4], &self.tab, self.mode);
1027 (self.f)(self.dst, y, sep.x0, &mut self.tmp[..n * 4]);
1028 }
1029}
1030
1031pub fn blurbac(a: &FxArgs, dst: &mut Dst, r: i32, b: i32, c: i32, mut f: impl FnMut(&mut Dst, i32, i32, &mut [u8])) -> i32 {
1035 let (tab, mode) = bac_init(b, c);
1036 let k = Kern::gauss(var12(r));
1037 let Some(sep) = Sep::new(a, &k) else {
1038 return 0;
1039 };
1040 let n = (sep.x1 - sep.x0) as usize;
1041 let mut io = BlurBac { dst, tab, mode, tmp: vec![0u8; n * 4 + 64], f: &mut f };
1042 sep_run(&sep, &mut io)
1043}
1044
1045#[inline]
1047pub fn w16_of(p: u32) -> [i16; 4] {
1048 let mut w = [0i16; 4];
1049 to_work(&mut w, &p.to_le_bytes(), 1, FMT_ARGB, 0);
1050 w
1051}