using System; using System.Numerics; using System.Runtime.InteropServices; using RGB.NET.Core; namespace RGB.NET.Presets.Textures.Sampler; /// /// Represents a sampled that averages multiple byte-data entries. /// public class AverageByteSampler : ISampler { #region Constants private static readonly int INT_VECTOR_LENGTH = Vector.Count; #endregion #region Methods /// public unsafe void Sample(in SamplerInfo info, in Span pixelData) { int count = info.Width * info.Height; if (count == 0) return; ReadOnlySpan data = info.Data; int dataLength = pixelData.Length; Span sums = stackalloc uint[dataLength]; if (Vector.IsHardwareAccelerated && (data.Length >= Vector.Count) && (dataLength <= Vector.Count)) { int elementsPerVector = Vector.Count / dataLength; int valuesPerVector = elementsPerVector * dataLength; int chunks = data.Length / valuesPerVector; int missingElements = data.Length - (chunks * valuesPerVector); Vector sum1 = Vector.Zero; Vector sum2 = Vector.Zero; Vector sum3 = Vector.Zero; Vector sum4 = Vector.Zero; fixed (byte* colorPtr = &MemoryMarshal.GetReference(data)) { byte* current = colorPtr; for (int i = 0; i < chunks; i++) { Vector bytes = *(Vector*)current; Vector.Widen(bytes, out Vector short1, out Vector short2); Vector.Widen(short1, out Vector int1, out Vector int2); Vector.Widen(short2, out Vector int3, out Vector int4); sum1 = Vector.Add(sum1, int1); sum2 = Vector.Add(sum2, int2); sum3 = Vector.Add(sum3, int3); sum4 = Vector.Add(sum4, int4); current += valuesPerVector; } } int value = 0; int sumIndex = 0; for (int j = 0; (j < INT_VECTOR_LENGTH) && (value < valuesPerVector); j++) { sums[sumIndex] += sum1[j]; ++sumIndex; ++value; if (sumIndex >= dataLength) sumIndex = 0; } for (int j = 0; (j < INT_VECTOR_LENGTH) && (value < valuesPerVector); j++) { sums[sumIndex] += sum2[j]; ++sumIndex; ++value; if (sumIndex >= dataLength) sumIndex = 0; } for (int j = 0; (j < INT_VECTOR_LENGTH) && (value < valuesPerVector); j++) { sums[sumIndex] += sum3[j]; ++sumIndex; ++value; if (sumIndex >= dataLength) sumIndex = 0; } for (int j = 0; (j < INT_VECTOR_LENGTH) && (value < valuesPerVector); j++) { sums[sumIndex] += sum4[j]; ++sumIndex; ++value; if (sumIndex >= dataLength) sumIndex = 0; } int offset = chunks * valuesPerVector; for (int i = 0; i < missingElements; i += dataLength) for (int j = 0; j < sums.Length; j++) sums[j] += data[offset + i + j]; } else { for (int i = 0; i < data.Length; i += dataLength) for (int j = 0; j < sums.Length; j++) sums[j] += data[i + j]; } float divisor = count * byte.MaxValue; for (int i = 0; i < pixelData.Length; i++) pixelData[i] = (sums[i] / divisor).GetByteValueFromPercentage(); } #endregion }