1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Merge pull request #743 from Artemis-RGB/improvement/Quantizer

Removed the need for enabled unsafe blocks in Core; Added try/finally…
This commit is contained in:
RobertBeekman 2022-11-21 12:49:59 +01:00 committed by GitHub
commit b530ae1023
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 98 additions and 84 deletions

View File

@ -12,7 +12,6 @@
<PackageId>ArtemisRGB.Core</PackageId>
<PluginApiVersion>1</PluginApiVersion>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>

View File

@ -1,6 +1,7 @@
using SkiaSharp;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Artemis.Core.ColorScience;
@ -19,7 +20,7 @@ internal readonly struct ColorRanges
}
}
internal class ColorCube
internal readonly struct ColorCube
{
private const int BYTES_PER_COLOR = 4;
private static readonly int ELEMENTS_PER_VECTOR = Vector<byte>.Count / BYTES_PER_COLOR;
@ -27,19 +28,16 @@ internal class ColorCube
private readonly int _from;
private readonly int _length;
private SortTarget _currentOrder = SortTarget.None;
private readonly SortTarget _currentOrder = SortTarget.None;
public ColorCube(in Span<SKColor> fullColorList, int from, int length, SortTarget preOrdered)
{
this._from = from;
this._length = length;
OrderColors(fullColorList.Slice(from, length), preOrdered);
}
if (length < 2) return;
private void OrderColors(in Span<SKColor> colors, SortTarget preOrdered)
{
if (colors.Length < 2) return;
Span<SKColor> colors = fullColorList.Slice(from, length);
ColorRanges colorRanges = GetColorRanges(colors);
if ((colorRanges.RedRange > colorRanges.GreenRange) && (colorRanges.RedRange > colorRanges.BlueRange))
@ -65,29 +63,21 @@ internal class ColorCube
}
}
private unsafe ColorRanges GetColorRanges(in ReadOnlySpan<SKColor> colors)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ColorRanges GetColorRanges(in ReadOnlySpan<SKColor> colors)
{
if (Vector.IsHardwareAccelerated && (colors.Length >= Vector<byte>.Count))
{
int chunks = colors.Length / ELEMENTS_PER_VECTOR;
int missingElements = colors.Length - (chunks * ELEMENTS_PER_VECTOR);
int vectorElements = (chunks * ELEMENTS_PER_VECTOR);
int missingElements = colors.Length - vectorElements;
Vector<byte> max = Vector<byte>.Zero;
Vector<byte> min = new(byte.MaxValue);
ReadOnlySpan<byte> colorBytes = MemoryMarshal.AsBytes(colors);
fixed (byte* colorPtr = &MemoryMarshal.GetReference(colorBytes))
foreach (Vector<byte> currentVector in MemoryMarshal.Cast<SKColor, Vector<byte>>(colors[..vectorElements]))
{
byte* current = colorPtr;
for (int i = 0; i < chunks; i++)
{
Vector<byte> currentVector = *(Vector<byte>*)current;
max = Vector.Max(max, currentVector);
min = Vector.Min(min, currentVector);
current += BYTES_PER_VECTOR;
}
max = Vector.Max(max, currentVector);
min = Vector.Min(min, currentVector);
}
byte redMin = byte.MaxValue;
@ -144,7 +134,7 @@ internal class ColorCube
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Split(in Span<SKColor> fullColorList, out ColorCube a, out ColorCube b)
{
Span<SKColor> colors = fullColorList.Slice(_from, _length);
@ -155,6 +145,7 @@ internal class ColorCube
b = new ColorCube(fullColorList, _from + median, colors.Length - median, _currentOrder);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal SKColor GetAverageColor(in ReadOnlySpan<SKColor> fullColorList)
{
ReadOnlySpan<SKColor> colors = fullColorList.Slice(_from, _length);

View File

@ -9,94 +9,112 @@ internal static class QuantizerSort
{
#region Methods
public static void SortRed(in Span<SKColor> span)
public static void SortRed(in Span<SKColor> colors)
{
Span<int> counts = stackalloc int[256];
foreach (SKColor t in span)
foreach (SKColor t in colors)
counts[t.Red]++;
SKColor[] bucketsArray = ArrayPool<SKColor>.Shared.Rent(span.Length);
Span<SKColor> buckets = bucketsArray.AsSpan().Slice(0, span.Length);
Span<int> currentBucketIndex = stackalloc int[256];
SKColor[] bucketsArray = ArrayPool<SKColor>.Shared.Rent(colors.Length);
int offset = 0;
for (int i = 0; i < counts.Length; i++)
try
{
currentBucketIndex[i] = offset;
offset += counts[i];
}
Span<SKColor> buckets = bucketsArray.AsSpan().Slice(0, colors.Length);
Span<int> currentBucketIndex = stackalloc int[256];
foreach (SKColor color in span)
int offset = 0;
for (int i = 0; i < counts.Length; i++)
{
currentBucketIndex[i] = offset;
offset += counts[i];
}
foreach (SKColor color in colors)
{
int index = color.Red;
int bucketIndex = currentBucketIndex[index];
currentBucketIndex[index]++;
buckets[bucketIndex] = color;
}
buckets.CopyTo(colors);
}
finally
{
int index = color.Red;
int bucketIndex = currentBucketIndex[index];
currentBucketIndex[index]++;
buckets[bucketIndex] = color;
ArrayPool<SKColor>.Shared.Return(bucketsArray);
}
buckets.CopyTo(span);
ArrayPool<SKColor>.Shared.Return(bucketsArray);
}
public static void SortGreen(in Span<SKColor> span)
public static void SortGreen(in Span<SKColor> colors)
{
Span<int> counts = stackalloc int[256];
foreach (SKColor t in span)
foreach (SKColor t in colors)
counts[t.Green]++;
SKColor[] bucketsArray = ArrayPool<SKColor>.Shared.Rent(span.Length);
Span<SKColor> buckets = bucketsArray.AsSpan().Slice(0, span.Length);
Span<int> currentBucketIndex = stackalloc int[256];
SKColor[] bucketsArray = ArrayPool<SKColor>.Shared.Rent(colors.Length);
int offset = 0;
for (int i = 0; i < counts.Length; i++)
try
{
currentBucketIndex[i] = offset;
offset += counts[i];
}
Span<SKColor> buckets = bucketsArray.AsSpan().Slice(0, colors.Length);
Span<int> currentBucketIndex = stackalloc int[256];
foreach (SKColor color in span)
int offset = 0;
for (int i = 0; i < counts.Length; i++)
{
currentBucketIndex[i] = offset;
offset += counts[i];
}
foreach (SKColor color in colors)
{
int index = color.Green;
int bucketIndex = currentBucketIndex[index];
currentBucketIndex[index]++;
buckets[bucketIndex] = color;
}
buckets.CopyTo(colors);
}
finally
{
int index = color.Green;
int bucketIndex = currentBucketIndex[index];
currentBucketIndex[index]++;
buckets[bucketIndex] = color;
ArrayPool<SKColor>.Shared.Return(bucketsArray);
}
buckets.CopyTo(span);
ArrayPool<SKColor>.Shared.Return(bucketsArray);
}
public static void SortBlue(in Span<SKColor> span)
public static void SortBlue(in Span<SKColor> colors)
{
Span<int> counts = stackalloc int[256];
foreach (SKColor t in span)
foreach (SKColor t in colors)
counts[t.Blue]++;
SKColor[] bucketsArray = ArrayPool<SKColor>.Shared.Rent(span.Length);
Span<SKColor> buckets = bucketsArray.AsSpan().Slice(0, span.Length);
Span<int> currentBucketIndex = stackalloc int[256];
SKColor[] bucketsArray = ArrayPool<SKColor>.Shared.Rent(colors.Length);
int offset = 0;
for (int i = 0; i < counts.Length; i++)
try
{
currentBucketIndex[i] = offset;
offset += counts[i];
}
Span<SKColor> buckets = bucketsArray.AsSpan().Slice(0, colors.Length);
Span<int> currentBucketIndex = stackalloc int[256];
foreach (SKColor color in span)
int offset = 0;
for (int i = 0; i < counts.Length; i++)
{
currentBucketIndex[i] = offset;
offset += counts[i];
}
foreach (SKColor color in colors)
{
int index = color.Blue;
int bucketIndex = currentBucketIndex[index];
currentBucketIndex[index]++;
buckets[bucketIndex] = color;
}
buckets.CopyTo(colors);
}
finally
{
int index = color.Blue;
int bucketIndex = currentBucketIndex[index];
currentBucketIndex[index]++;
buckets[bucketIndex] = color;
ArrayPool<SKColor>.Shared.Return(bucketsArray);
}
buckets.CopyTo(span);
ArrayPool<SKColor>.Shared.Return(bucketsArray);
}
#endregion

View File

@ -66,9 +66,15 @@ namespace Artemis.Core.ColorScience
else
{
SortColor[] sortColorArray = ArrayPool<SortColor>.Shared.Rent(colors.Length);
Span<SortColor> sortColors = sortColorArray.AsSpan(0, colors.Length);
Sort(colors, sortColors, referenceColor);
ArrayPool<SortColor>.Shared.Return(sortColorArray);
try
{
Span<SortColor> sortColors = sortColorArray.AsSpan(0, colors.Length);
Sort(colors, sortColors, referenceColor);
}
finally
{
ArrayPool<SortColor>.Shared.Return(sortColorArray);
}
}
}