Skip to content

Commit a99e6cf

Browse files
Revert to original CoarseCache
1 parent b09ea41 commit a99e6cf

1 file changed

Lines changed: 81 additions & 3 deletions

File tree

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

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,84 @@ public void Dispose()
119119
}
120120
}
121121

122+
/// <summary>
123+
/// A coarse cache for color distance lookups that uses a fixed-size lookup table.
124+
/// </summary>
125+
/// <remarks>
126+
/// This cache uses a fixed lookup table with 2,097,152 bins, each storing a 2-byte value,
127+
/// resulting in a worst-case memory usage of approximately 4 MB. Lookups and insertions are
128+
/// performed in constant time (O(1)) via direct table indexing. This design is optimized for
129+
/// speed while maintaining a predictable, fixed memory footprint.
130+
/// </remarks>
131+
internal unsafe struct CoarseCache : IColorIndexCache<CoarseCache>
132+
{
133+
private const int IndexRBits = 5;
134+
private const int IndexGBits = 5;
135+
private const int IndexBBits = 5;
136+
private const int IndexABits = 6;
137+
private const int IndexRCount = 1 << IndexRBits; // 32 bins for red
138+
private const int IndexGCount = 1 << IndexGBits; // 32 bins for green
139+
private const int IndexBCount = 1 << IndexBBits; // 32 bins for blue
140+
private const int IndexACount = 1 << IndexABits; // 64 bins for alpha
141+
private const int TotalBins = IndexRCount * IndexGCount * IndexBCount * IndexACount; // 2,097,152 bins
142+
143+
private readonly IMemoryOwner<short> binsOwner;
144+
private readonly short* binsPointer;
145+
private MemoryHandle binsHandle;
146+
147+
private CoarseCache(MemoryAllocator allocator)
148+
{
149+
this.binsOwner = allocator.Allocate<short>(TotalBins);
150+
this.binsOwner.GetSpan().Fill(-1);
151+
this.binsHandle = this.binsOwner.Memory.Pin();
152+
this.binsPointer = (short*)this.binsHandle.Pointer;
153+
}
154+
155+
/// <inheritdoc/>
156+
public static CoarseCache Create(MemoryAllocator allocator) => new(allocator);
157+
158+
/// <inheritdoc/>
159+
[MethodImpl(InliningOptions.ShortMethod)]
160+
public readonly bool TryAdd(Rgba32 color, short value)
161+
{
162+
this.binsPointer[GetCoarseIndex(color)] = value;
163+
return true;
164+
}
165+
166+
/// <inheritdoc/>
167+
[MethodImpl(InliningOptions.ShortMethod)]
168+
public readonly bool TryGetValue(Rgba32 color, out short value)
169+
{
170+
value = this.binsPointer[GetCoarseIndex(color)];
171+
return value > -1; // Coarse match found
172+
}
173+
174+
[MethodImpl(InliningOptions.ShortMethod)]
175+
private static int GetCoarseIndex(Rgba32 color)
176+
{
177+
int rIndex = color.R >> (8 - IndexRBits);
178+
int gIndex = color.G >> (8 - IndexGBits);
179+
int bIndex = color.B >> (8 - IndexBBits);
180+
int aIndex = color.A >> (8 - IndexABits);
181+
182+
return (aIndex * IndexRCount * IndexGCount * IndexBCount) +
183+
(rIndex * IndexGCount * IndexBCount) +
184+
(gIndex * IndexBCount) +
185+
bIndex;
186+
}
187+
188+
/// <inheritdoc/>
189+
public readonly void Clear()
190+
=> this.binsOwner.GetSpan().Fill(-1);
191+
192+
/// <inheritdoc/>
193+
public void Dispose()
194+
{
195+
this.binsHandle.Dispose();
196+
this.binsOwner.Dispose();
197+
}
198+
}
199+
122200
/// <summary>
123201
/// <para>
124202
/// CoarseCache is a fast, low-memory lookup structure for caching palette indices associated with RGBA values,
@@ -147,7 +225,7 @@ public void Dispose()
147225
/// making it ideal for applications such as color distance caching in images with a limited palette (up to 256 entries).
148226
/// </para>
149227
/// </summary>
150-
internal unsafe struct CoarseCache : IColorIndexCache<CoarseCache>
228+
internal unsafe struct CoarseCacheLite : IColorIndexCache<CoarseCacheLite>
151229
{
152230
// Use 5 bits per channel for R, G, and B: 32 levels each.
153231
// Total buckets = 32^3 = 32768.
@@ -158,15 +236,15 @@ internal unsafe struct CoarseCache : IColorIndexCache<CoarseCache>
158236
private readonly AlphaBucket* buckets;
159237
private MemoryHandle bucketHandle;
160238

161-
private CoarseCache(MemoryAllocator allocator)
239+
private CoarseCacheLite(MemoryAllocator allocator)
162240
{
163241
this.bucketsOwner = allocator.Allocate<AlphaBucket>(BucketCount, AllocationOptions.Clean);
164242
this.bucketHandle = this.bucketsOwner.Memory.Pin();
165243
this.buckets = (AlphaBucket*)this.bucketHandle.Pointer;
166244
}
167245

168246
/// <inheritdoc/>
169-
public static CoarseCache Create(MemoryAllocator allocator) => new(allocator);
247+
public static CoarseCacheLite Create(MemoryAllocator allocator) => new(allocator);
170248

171249
/// <inheritdoc/>
172250
public readonly bool TryAdd(Rgba32 color, short paletteIndex)

0 commit comments

Comments
 (0)