1010
1111namespace SixLabors . ImageSharp . Formats . Webp . Lossless ;
1212
13- internal sealed class Vp8LHistogram : IDisposable
13+ internal sealed unsafe class Vp8LHistogram : IDisposable
1414{
1515 private const uint NonTrivialSym = 0xffffffff ;
16- private readonly IMemoryOwner < uint > buffer ;
16+ private readonly IMemoryOwner < uint > ? bufferOwner ;
17+ private readonly Memory < uint > buffer ;
18+ private readonly MemoryHandle bufferHandle ;
19+
20+ private readonly uint * red ;
21+ private readonly uint * blue ;
22+ private readonly uint * alpha ;
23+ private readonly uint * distance ;
24+ private readonly uint * literal ;
25+ private readonly uint * isUsed ;
26+
1727 private const int RedSize = WebpConstants . NumLiteralCodes ;
1828 private const int BlueSize = WebpConstants . NumLiteralCodes ;
1929 private const int AlphaSize = WebpConstants . NumLiteralCodes ;
2030 private const int DistanceSize = WebpConstants . NumDistanceCodes ;
2131 public const int LiteralSize = WebpConstants . NumLiteralCodes + WebpConstants . NumLengthCodes + ( 1 << WebpConstants . MaxColorCacheBits ) + 1 ;
2232 private const int UsedSize = 5 ; // 5 for literal, red, blue, alpha, distance
2333 public const int BufferSize = RedSize + BlueSize + AlphaSize + DistanceSize + LiteralSize + UsedSize ;
24- private readonly bool isSetMember ;
25-
26- /// <summary>
27- /// Initializes a new instance of the <see cref="Vp8LHistogram"/> class.
28- /// </summary>
29- /// <param name="memoryAllocator">The memory allocator.</param>
30- /// <param name="refs">The backward references to initialize the histogram with.</param>
31- /// <param name="paletteCodeBits">The palette code bits.</param>
32- public Vp8LHistogram ( MemoryAllocator memoryAllocator , Vp8LBackwardRefs refs , int paletteCodeBits )
33- : this ( memoryAllocator , paletteCodeBits ) => this . StoreRefs ( refs ) ;
34-
35- /// <summary>
36- /// Initializes a new instance of the <see cref="Vp8LHistogram"/> class.
37- /// </summary>
38- /// <param name="memoryAllocator">The memory allocator.</param>
39- /// <param name="paletteCodeBits">The palette code bits.</param>
40- public Vp8LHistogram ( MemoryAllocator memoryAllocator , int paletteCodeBits )
41- {
42- this . buffer = memoryAllocator . Allocate < uint > ( BufferSize , AllocationOptions . Clean ) ;
43- this . PaletteCodeBits = paletteCodeBits ;
44- }
4534
4635 /// <summary>
4736 /// Initializes a new instance of the <see cref="Vp8LHistogram"/> class.
@@ -52,7 +41,7 @@ public Vp8LHistogram(MemoryAllocator memoryAllocator, int paletteCodeBits)
5241 /// <param name="buffer">The backing buffer.</param>
5342 /// <param name="refs">The backward references to initialize the histogram with.</param>
5443 /// <param name="paletteCodeBits">The palette code bits.</param>
55- public Vp8LHistogram ( IMemoryOwner < uint > buffer , Vp8LBackwardRefs refs , int paletteCodeBits )
44+ public Vp8LHistogram ( Memory < uint > buffer , Vp8LBackwardRefs refs , int paletteCodeBits )
5645 : this ( buffer , paletteCodeBits ) => this . StoreRefs ( refs ) ;
5746
5847 /// <summary>
@@ -63,11 +52,20 @@ public Vp8LHistogram(IMemoryOwner<uint> buffer, Vp8LBackwardRefs refs, int palet
6352 /// </remarks>
6453 /// <param name="buffer">The backing buffer.</param>
6554 /// <param name="paletteCodeBits">The palette code bits.</param>
66- public Vp8LHistogram ( IMemoryOwner < uint > buffer , int paletteCodeBits )
55+ /// <param name="bufferOwner">Optional buffer owner to dispose.</param>
56+ public Vp8LHistogram ( Memory < uint > buffer , int paletteCodeBits , IMemoryOwner < uint > ? bufferOwner = null )
6757 {
58+ this . bufferOwner = bufferOwner ;
6859 this . buffer = buffer ;
60+ this . bufferHandle = this . buffer . Pin ( ) ;
6961 this . PaletteCodeBits = paletteCodeBits ;
70- this . isSetMember = true ;
62+
63+ this . red = ( uint * ) this . bufferHandle . Pointer ;
64+ this . blue = this . red + RedSize ;
65+ this . alpha = this . blue + BlueSize ;
66+ this . distance = this . alpha + AlphaSize ;
67+ this . literal = this . distance + DistanceSize ;
68+ this . isUsed = this . literal + LiteralSize ;
7169 }
7270
7371 /// <summary>
@@ -95,22 +93,43 @@ public Vp8LHistogram(IMemoryOwner<uint> buffer, int paletteCodeBits)
9593 /// </summary>
9694 public double BlueCost { get ; set ; }
9795
98- public Span < uint > Red => this . buffer . GetSpan ( ) [ .. RedSize ] ;
96+ public Span < uint > Red => new ( this . red , RedSize ) ;
9997
100- public Span < uint > Blue => this . buffer . GetSpan ( ) . Slice ( RedSize , BlueSize ) ;
98+ public Span < uint > Blue => new ( this . blue , BlueSize ) ;
10199
102- public Span < uint > Alpha => this . buffer . GetSpan ( ) . Slice ( RedSize + BlueSize , AlphaSize ) ;
100+ public Span < uint > Alpha => new ( this . alpha , AlphaSize ) ;
103101
104- public Span < uint > Distance => this . buffer . GetSpan ( ) . Slice ( RedSize + BlueSize + AlphaSize , DistanceSize ) ;
102+ public Span < uint > Distance => new ( this . distance , DistanceSize ) ;
105103
106- public Span < uint > Literal => this . buffer . GetSpan ( ) . Slice ( RedSize + BlueSize + AlphaSize + DistanceSize , LiteralSize ) ;
104+ public Span < uint > Literal => new ( this . literal , LiteralSize ) ;
107105
108106 public uint TrivialSymbol { get ; set ; }
109107
110- private Span < uint > IsUsedSpan => this . buffer . GetSpan ( ) . Slice ( RedSize + BlueSize + AlphaSize + DistanceSize + LiteralSize , UsedSize ) ;
108+ private Span < uint > IsUsedSpan => new ( this . isUsed , UsedSize ) ;
109+
110+ private Span < uint > TotalSpan => new ( this . red , BufferSize ) ;
111111
112112 public bool IsDisposed { get ; set ; }
113113
114+ /// <summary>
115+ /// Creates an <see cref="Vp8LHistogram"/> that is not a member of a <see cref="Vp8LHistogramSet"/>.
116+ /// </summary>
117+ public static Vp8LHistogram Create ( MemoryAllocator memoryAllocator , int paletteCodeBits )
118+ {
119+ IMemoryOwner < uint > bufferOwner = memoryAllocator . Allocate < uint > ( BufferSize , AllocationOptions . Clean ) ;
120+ return new Vp8LHistogram ( bufferOwner . Memory , paletteCodeBits , bufferOwner ) ;
121+ }
122+
123+ /// <summary>
124+ /// Creates an <see cref="Vp8LHistogram"/> that is not a member of a <see cref="Vp8LHistogramSet"/>.
125+ /// </summary>
126+ public static Vp8LHistogram Create ( MemoryAllocator memoryAllocator , Vp8LBackwardRefs refs , int paletteCodeBits )
127+ {
128+ Vp8LHistogram histogram = Create ( memoryAllocator , paletteCodeBits ) ;
129+ histogram . StoreRefs ( refs ) ;
130+ return histogram ;
131+ }
132+
114133 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
115134 public bool IsUsed ( int index ) => this . IsUsedSpan [ index ] == 1u ;
116135
@@ -140,7 +159,7 @@ public void CopyTo(Vp8LHistogram other)
140159
141160 public void Clear ( )
142161 {
143- this . buffer . Clear ( ) ;
162+ this . TotalSpan . Clear ( ) ;
144163 this . PaletteCodeBits = 0 ;
145164 this . BitCost = 0 ;
146165 this . LiteralCost = 0 ;
@@ -607,11 +626,8 @@ public void Dispose()
607626 {
608627 if ( ! this . IsDisposed )
609628 {
610- if ( ! this . isSetMember )
611- {
612- this . buffer . Dispose ( ) ;
613- }
614-
629+ this . bufferHandle . Dispose ( ) ;
630+ this . bufferOwner ? . Dispose ( ) ;
615631 this . IsDisposed = true ;
616632 }
617633 }
0 commit comments