Browse Source

Revert to original CoarseCache

pull/2894/head
James Jackson-South 1 year ago
parent
commit
a99e6cf380
  1. 84
      src/ImageSharp/Processing/Processors/Quantization/IColorIndexCache.cs

84
src/ImageSharp/Processing/Processors/Quantization/IColorIndexCache.cs

@ -119,6 +119,84 @@ internal unsafe struct HybridCache : IColorIndexCache<HybridCache>
}
}
/// <summary>
/// A coarse cache for color distance lookups that uses a fixed-size lookup table.
/// </summary>
/// <remarks>
/// This cache uses a fixed lookup table with 2,097,152 bins, each storing a 2-byte value,
/// resulting in a worst-case memory usage of approximately 4 MB. Lookups and insertions are
/// performed in constant time (O(1)) via direct table indexing. This design is optimized for
/// speed while maintaining a predictable, fixed memory footprint.
/// </remarks>
internal unsafe struct CoarseCache : IColorIndexCache<CoarseCache>
{
private const int IndexRBits = 5;
private const int IndexGBits = 5;
private const int IndexBBits = 5;
private const int IndexABits = 6;
private const int IndexRCount = 1 << IndexRBits; // 32 bins for red
private const int IndexGCount = 1 << IndexGBits; // 32 bins for green
private const int IndexBCount = 1 << IndexBBits; // 32 bins for blue
private const int IndexACount = 1 << IndexABits; // 64 bins for alpha
private const int TotalBins = IndexRCount * IndexGCount * IndexBCount * IndexACount; // 2,097,152 bins
private readonly IMemoryOwner<short> binsOwner;
private readonly short* binsPointer;
private MemoryHandle binsHandle;
private CoarseCache(MemoryAllocator allocator)
{
this.binsOwner = allocator.Allocate<short>(TotalBins);
this.binsOwner.GetSpan().Fill(-1);
this.binsHandle = this.binsOwner.Memory.Pin();
this.binsPointer = (short*)this.binsHandle.Pointer;
}
/// <inheritdoc/>
public static CoarseCache Create(MemoryAllocator allocator) => new(allocator);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool TryAdd(Rgba32 color, short value)
{
this.binsPointer[GetCoarseIndex(color)] = value;
return true;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool TryGetValue(Rgba32 color, out short value)
{
value = this.binsPointer[GetCoarseIndex(color)];
return value > -1; // Coarse match found
}
[MethodImpl(InliningOptions.ShortMethod)]
private static int GetCoarseIndex(Rgba32 color)
{
int rIndex = color.R >> (8 - IndexRBits);
int gIndex = color.G >> (8 - IndexGBits);
int bIndex = color.B >> (8 - IndexBBits);
int aIndex = color.A >> (8 - IndexABits);
return (aIndex * IndexRCount * IndexGCount * IndexBCount) +
(rIndex * IndexGCount * IndexBCount) +
(gIndex * IndexBCount) +
bIndex;
}
/// <inheritdoc/>
public readonly void Clear()
=> this.binsOwner.GetSpan().Fill(-1);
/// <inheritdoc/>
public void Dispose()
{
this.binsHandle.Dispose();
this.binsOwner.Dispose();
}
}
/// <summary>
/// <para>
/// CoarseCache is a fast, low-memory lookup structure for caching palette indices associated with RGBA values,
@ -147,7 +225,7 @@ internal unsafe struct HybridCache : IColorIndexCache<HybridCache>
/// making it ideal for applications such as color distance caching in images with a limited palette (up to 256 entries).
/// </para>
/// </summary>
internal unsafe struct CoarseCache : IColorIndexCache<CoarseCache>
internal unsafe struct CoarseCacheLite : IColorIndexCache<CoarseCacheLite>
{
// Use 5 bits per channel for R, G, and B: 32 levels each.
// Total buckets = 32^3 = 32768.
@ -158,7 +236,7 @@ internal unsafe struct CoarseCache : IColorIndexCache<CoarseCache>
private readonly AlphaBucket* buckets;
private MemoryHandle bucketHandle;
private CoarseCache(MemoryAllocator allocator)
private CoarseCacheLite(MemoryAllocator allocator)
{
this.bucketsOwner = allocator.Allocate<AlphaBucket>(BucketCount, AllocationOptions.Clean);
this.bucketHandle = this.bucketsOwner.Memory.Pin();
@ -166,7 +244,7 @@ internal unsafe struct CoarseCache : IColorIndexCache<CoarseCache>
}
/// <inheritdoc/>
public static CoarseCache Create(MemoryAllocator allocator) => new(allocator);
public static CoarseCacheLite Create(MemoryAllocator allocator) => new(allocator);
/// <inheritdoc/>
public readonly bool TryAdd(Rgba32 color, short paletteIndex)

Loading…
Cancel
Save