batchTransformRgba method

void batchTransformRgba(
  1. covariant List<int> rIn,
  2. covariant List<int> gIn,
  3. covariant List<int> bIn,
  4. covariant List<int> aIn,
  5. covariant List<int> rOut,
  6. covariant List<int> gOut,
  7. covariant List<int> bOut,
  8. covariant List<int> aOut,
  9. int count,
)

Batch-transform RGBA values using Float32x4 SIMD.

Processes count RGBA pixels from the parallel input lists and writes to the parallel output lists. Uses Float32x4 to process 4 pixels at once (SoA layout: one Float32x4 holds a single channel across 4 pixels).

All lists must have at least count elements.

Implementation

void batchTransformRgba(
  covariant List<int> rIn,
  covariant List<int> gIn,
  covariant List<int> bIn,
  covariant List<int> aIn,
  covariant List<int> rOut,
  covariant List<int> gOut,
  covariant List<int> bOut,
  covariant List<int> aOut,
  int count,
) {
  // Pre-load matrix rows as splatted vectors for the 4×4 linear part.
  final mCol0 = Float32x4.splat(_values[0]);
  final mCol1 = Float32x4.splat(_values[1]);
  final mCol2 = Float32x4.splat(_values[2]);
  final mCol3 = Float32x4.splat(_values[3]);
  final biasR = Float32x4.splat(_values[4]);
  final mCol5 = Float32x4.splat(_values[5]);
  final mCol6 = Float32x4.splat(_values[6]);
  final mCol7 = Float32x4.splat(_values[7]);
  final mCol8 = Float32x4.splat(_values[8]);
  final biasG = Float32x4.splat(_values[9]);
  final mCol10 = Float32x4.splat(_values[10]);
  final mCol11 = Float32x4.splat(_values[11]);
  final mCol12 = Float32x4.splat(_values[12]);
  final mCol13 = Float32x4.splat(_values[13]);
  final biasB = Float32x4.splat(_values[14]);
  final mCol15 = Float32x4.splat(_values[15]);
  final mCol16 = Float32x4.splat(_values[16]);
  final mCol17 = Float32x4.splat(_values[17]);
  final mCol18 = Float32x4.splat(_values[18]);
  final biasA = Float32x4.splat(_values[19]);

  var i = 0;
  for (; i + 3 < count; i += 4) {
    // Load 4 pixels in SoA layout.
    final rr = Float32x4(
      rIn[i].toDouble(),
      rIn[i + 1].toDouble(),
      rIn[i + 2].toDouble(),
      rIn[i + 3].toDouble(),
    );
    final gg = Float32x4(
      gIn[i].toDouble(),
      gIn[i + 1].toDouble(),
      gIn[i + 2].toDouble(),
      gIn[i + 3].toDouble(),
    );
    final bb = Float32x4(
      bIn[i].toDouble(),
      bIn[i + 1].toDouble(),
      bIn[i + 2].toDouble(),
      bIn[i + 3].toDouble(),
    );
    final aa = Float32x4(
      aIn[i].toDouble(),
      aIn[i + 1].toDouble(),
      aIn[i + 2].toDouble(),
      aIn[i + 3].toDouble(),
    );

    // Out = row · (r, g, b, a)^T + bias  (all lanes in parallel).
    final outR = rr * mCol0 + gg * mCol1 + bb * mCol2 + aa * mCol3 + biasR;
    final outG = rr * mCol5 + gg * mCol6 + bb * mCol7 + aa * mCol8 + biasG;
    final outB =
        rr * mCol10 + gg * mCol11 + bb * mCol12 + aa * mCol13 + biasB;
    final outA =
        rr * mCol15 + gg * mCol16 + bb * mCol17 + aa * mCol18 + biasA;

    // Extract lanes back to integers.
    rOut[i] = outR.x.round().clamp(0, 255);
    rOut[i + 1] = outR.y.round().clamp(0, 255);
    rOut[i + 2] = outR.z.round().clamp(0, 255);
    rOut[i + 3] = outR.w.round().clamp(0, 255);

    gOut[i] = outG.x.round().clamp(0, 255);
    gOut[i + 1] = outG.y.round().clamp(0, 255);
    gOut[i + 2] = outG.z.round().clamp(0, 255);
    gOut[i + 3] = outG.w.round().clamp(0, 255);

    bOut[i] = outB.x.round().clamp(0, 255);
    bOut[i + 1] = outB.y.round().clamp(0, 255);
    bOut[i + 2] = outB.z.round().clamp(0, 255);
    bOut[i + 3] = outB.w.round().clamp(0, 255);

    aOut[i] = outA.x.round().clamp(0, 255);
    aOut[i + 1] = outA.y.round().clamp(0, 255);
    aOut[i + 2] = outA.z.round().clamp(0, 255);
    aOut[i + 3] = outA.w.round().clamp(0, 255);
  }

  // Scalar tail for remaining <4 pixels.
  for (; i < count; i++) {
    final pixel = _transformRgbaF64(
      rIn[i].toDouble(),
      gIn[i].toDouble(),
      bIn[i].toDouble(),
      aIn[i].toDouble(),
    );
    rOut[i] = pixel.r;
    gOut[i] = pixel.g;
    bOut[i] = pixel.b;
    aOut[i] = pixel.a;
  }
}