MCPcopy Create free account
hub / github.com/FastLED/FastLED / pnoise2d_raw_simd4_vec

Method pnoise2d_raw_simd4_vec

src/fl/math/noise/perlin_s16x16_simd.cpp.hpp:19–76  ·  view source on GitHub ↗

Primary overload: accepts SIMD registers directly. Performs SIMD floor/frac/wrap, then exits to scalar for fade/perm/grad/lerp (SSE2 has no integer gather), and re-packs the result into a SIMD register.

Source from the content-addressed store, hash-verified

17// Performs SIMD floor/frac/wrap, then exits to scalar for fade/perm/grad/lerp
18// (SSE2 has no integer gather), and re-packs the result into a SIMD register.
19fl::simd::simd_u32x4 perlin_s16x16_simd::pnoise2d_raw_simd4_vec(
20 fl::simd::simd_u32x4 nx_vec, fl::simd::simd_u32x4 ny_vec,
21 const fl::i32 *fade_lut, const fl::u8 *perm)
22{
23 // SIMD: Extract integer floor (shift right by FP_BITS)
24 fl::simd::simd_u32x4 X_vec = fl::simd::srl_u32_4(nx_vec, FP_BITS);
25 fl::simd::simd_u32x4 Y_vec = fl::simd::srl_u32_4(ny_vec, FP_BITS);
26
27 // SIMD: Extract fractional part and shift to HP_BITS
28 // Convert from Q16.16 to Q8.24 by shifting left 8 bits
29 fl::simd::simd_u32x4 mask_fp = fl::simd::set1_u32_4(FP_ONE - 1);
30 fl::simd::simd_u32x4 x_frac_vec = fl::simd::and_u32_4(nx_vec, mask_fp);
31 fl::simd::simd_u32x4 y_frac_vec = fl::simd::and_u32_4(ny_vec, mask_fp);
32
33 // Use the new sll_u32_4 operation for left shift
34 x_frac_vec = fl::simd::sll_u32_4(x_frac_vec, 8);
35 y_frac_vec = fl::simd::sll_u32_4(y_frac_vec, 8);
36
37 // SIMD: Wrap to [0, 255]
38 fl::simd::simd_u32x4 mask_255 = fl::simd::set1_u32_4(255);
39 X_vec = fl::simd::and_u32_4(X_vec, mask_255);
40 Y_vec = fl::simd::and_u32_4(Y_vec, mask_255);
41 // ── [end SIMD coordinate arithmetic] ──────────────────────────────────────
42
43 // ── [BOUNDARY D+E: SIMD extract → per-lane scalar → SIMD re-pack] ───────
44 // Extract coordinates directly from SIMD registers (no intermediate arrays).
45 // Each lane does: fade LUT, perm table, grad, lerp — fully self-contained.
46 // SSE2 has no integer gather, so scalar random-access is unavoidable.
47 constexpr int SHIFT = HP_BITS - fl::s16x16::FRAC_BITS;
48 auto lane = [&](int i) -> fl::i32 {
49 fl::u32 Xi = fl::simd::extract_u32_4(X_vec, i);
50 fl::u32 Yi = fl::simd::extract_u32_4(Y_vec, i);
51 fl::i32 xf = static_cast<fl::i32>(fl::simd::extract_u32_4(x_frac_vec, i));
52 fl::i32 yf = static_cast<fl::i32>(fl::simd::extract_u32_4(y_frac_vec, i));
53
54 fl::i32 u = perlin_s16x16::fade(xf, fade_lut);
55 fl::i32 v = perlin_s16x16::fade(yf, fade_lut);
56
57 int A = perm[Xi & 255] + Yi;
58 int AA = perm[A & 255];
59 int AB = perm[(A + 1) & 255];
60 int B = perm[(Xi + 1) & 255] + Yi;
61 int BA = perm[B & 255];
62 int BB = perm[(B + 1) & 255];
63
64 fl::i32 g_aa = perlin_s16x16::grad(perm[AA & 255], xf, yf);
65 fl::i32 g_ba = perlin_s16x16::grad(perm[BA & 255], xf - HP_ONE, yf);
66 fl::i32 g_ab = perlin_s16x16::grad(perm[AB & 255], xf, yf - HP_ONE);
67 fl::i32 g_bb = perlin_s16x16::grad(perm[BB & 255], xf - HP_ONE, yf - HP_ONE);
68 fl::i32 lerp1 = perlin_s16x16::lerp(u, g_aa, g_ba);
69 fl::i32 lerp2 = perlin_s16x16::lerp(u, g_ab, g_bb);
70 return perlin_s16x16::lerp(v, lerp1, lerp2) >> SHIFT;
71 };
72 return fl::simd::set_u32_4(
73 static_cast<fl::u32>(lane(0)), static_cast<fl::u32>(lane(1)),
74 static_cast<fl::u32>(lane(2)), static_cast<fl::u32>(lane(3)));
75 // ── [end BOUNDARY D+E] ───────────────────────────────────────────────────
76}

Callers

nothing calls this directly

Calls 3

fadeFunction · 0.85
gradFunction · 0.50
lerpFunction · 0.50

Tested by

no test coverage detected