22// Licensed under the Apache License, Version 2.0.
33
44using System ;
5+ using System . Buffers ;
56using System . Collections . Generic ;
7+ using SixLabors . ImageSharp . Memory ;
68
79namespace SixLabors . ImageSharp . Formats . Webp . Lossless
810{
9- internal class BackwardReferenceEncoder
11+ internal static class BackwardReferenceEncoder
1012 {
1113 /// <summary>
1214 /// Maximum bit length.
@@ -41,6 +43,7 @@ public static Vp8LBackwardRefs GetBackwardReferences(
4143 int quality ,
4244 int lz77TypesToTry ,
4345 ref int cacheBits ,
46+ MemoryAllocator memoryAllocator ,
4447 Vp8LHashChain hashChain ,
4548 Vp8LBackwardRefs best ,
4649 Vp8LBackwardRefs worst )
@@ -69,7 +72,7 @@ public static Vp8LBackwardRefs GetBackwardReferences(
6972 BackwardReferencesLz77 ( width , height , bgra , 0 , hashChain , worst ) ;
7073 break ;
7174 case Vp8LLz77Type . Lz77Box :
72- hashChainBox = new Vp8LHashChain ( width * height ) ;
75+ hashChainBox = new Vp8LHashChain ( memoryAllocator , width * height ) ;
7376 BackwardReferencesLz77Box ( width , height , bgra , 0 , hashChain , hashChainBox , worst ) ;
7477 break ;
7578 }
@@ -100,7 +103,7 @@ public static Vp8LBackwardRefs GetBackwardReferences(
100103 if ( ( lz77TypeBest == ( int ) Vp8LLz77Type . Lz77Standard || lz77TypeBest == ( int ) Vp8LLz77Type . Lz77Box ) && quality >= 25 )
101104 {
102105 Vp8LHashChain hashChainTmp = lz77TypeBest == ( int ) Vp8LLz77Type . Lz77Standard ? hashChain : hashChainBox ;
103- BackwardReferencesTraceBackwards ( width , height , bgra , cacheBits , hashChainTmp , best , worst ) ;
106+ BackwardReferencesTraceBackwards ( width , height , memoryAllocator , bgra , cacheBits , hashChainTmp , best , worst ) ;
104107 var histo = new Vp8LHistogram ( worst , cacheBits ) ;
105108 double bitCostTrace = histo . EstimateBits ( stats , bitsEntropy ) ;
106109 if ( bitCostTrace < bitCostBest )
@@ -111,6 +114,8 @@ public static Vp8LBackwardRefs GetBackwardReferences(
111114
112115 BackwardReferences2DLocality ( width , best ) ;
113116
117+ hashChainBox ? . Dispose ( ) ;
118+
114119 return best ;
115120 }
116121
@@ -234,29 +239,32 @@ private static int CalculateBestCacheSize(ReadOnlySpan<uint> bgra, int quality,
234239 private static void BackwardReferencesTraceBackwards (
235240 int xSize ,
236241 int ySize ,
242+ MemoryAllocator memoryAllocator ,
237243 ReadOnlySpan < uint > bgra ,
238244 int cacheBits ,
239245 Vp8LHashChain hashChain ,
240246 Vp8LBackwardRefs refsSrc ,
241247 Vp8LBackwardRefs refsDst )
242248 {
243249 int distArraySize = xSize * ySize ;
244- ushort [ ] distArray = new ushort [ distArraySize ] ;
250+ using IMemoryOwner < ushort > distArrayBuffer = memoryAllocator . Allocate < ushort > ( distArraySize ) ;
251+ Span < ushort > distArray = distArrayBuffer . GetSpan ( ) ;
245252
246- BackwardReferencesHashChainDistanceOnly ( xSize , ySize , bgra , cacheBits , hashChain , refsSrc , distArray ) ;
253+ BackwardReferencesHashChainDistanceOnly ( xSize , ySize , memoryAllocator , bgra , cacheBits , hashChain , refsSrc , distArrayBuffer ) ;
247254 int chosenPathSize = TraceBackwards ( distArray , distArraySize ) ;
248- Span < ushort > chosenPath = distArray . AsSpan ( distArraySize - chosenPathSize ) ;
255+ Span < ushort > chosenPath = distArray . Slice ( distArraySize - chosenPathSize ) ;
249256 BackwardReferencesHashChainFollowChosenPath ( bgra , cacheBits , chosenPath , chosenPathSize , hashChain , refsDst ) ;
250257 }
251258
252259 private static void BackwardReferencesHashChainDistanceOnly (
253260 int xSize ,
254261 int ySize ,
262+ MemoryAllocator memoryAllocator ,
255263 ReadOnlySpan < uint > bgra ,
256264 int cacheBits ,
257265 Vp8LHashChain hashChain ,
258266 Vp8LBackwardRefs refs ,
259- ushort [ ] distArray )
267+ IMemoryOwner < ushort > distArrayBuffer )
260268 {
261269 int pixCount = xSize * ySize ;
262270 bool useColorCache = cacheBits > 0 ;
@@ -275,22 +283,24 @@ private static void BackwardReferencesHashChainDistanceOnly(
275283 }
276284
277285 costModel . Build ( xSize , cacheBits , refs ) ;
278- var costManager = new CostManager ( distArray , pixCount , costModel ) ;
286+ using var costManager = new CostManager ( memoryAllocator , distArrayBuffer , pixCount , costModel ) ;
287+ Span < float > costManagerCosts = costManager . Costs . GetSpan ( ) ;
288+ Span < ushort > distArray = distArrayBuffer . GetSpan ( ) ;
279289
280290 // We loop one pixel at a time, but store all currently best points to non-processed locations from this point.
281291 distArray [ 0 ] = 0 ;
282292
283293 // Add first pixel as literal.
284- AddSingleLiteralWithCostModel ( bgra , colorCache , costModel , 0 , useColorCache , 0.0f , costManager . Costs , distArray ) ;
294+ AddSingleLiteralWithCostModel ( bgra , colorCache , costModel , 0 , useColorCache , 0.0f , costManagerCosts , distArray ) ;
285295
286296 for ( int i = 1 ; i < pixCount ; i ++ )
287297 {
288- float prevCost = costManager . Costs [ i - 1 ] ;
298+ float prevCost = costManagerCosts [ i - 1 ] ;
289299 int offset = hashChain . FindOffset ( i ) ;
290300 int len = hashChain . FindLength ( i ) ;
291301
292302 // Try adding the pixel as a literal.
293- AddSingleLiteralWithCostModel ( bgra , colorCache , costModel , i , useColorCache , prevCost , costManager . Costs , distArray ) ;
303+ AddSingleLiteralWithCostModel ( bgra , colorCache , costModel , i , useColorCache , prevCost , costManagerCosts , distArray ) ;
294304
295305 // If we are dealing with a non-literal.
296306 if ( len >= 2 )
@@ -334,7 +344,7 @@ private static void BackwardReferencesHashChainDistanceOnly(
334344 costManager . UpdateCostAtIndex ( j - 1 , false ) ;
335345 costManager . UpdateCostAtIndex ( j , false ) ;
336346
337- costManager . PushInterval ( costManager . Costs [ j - 1 ] + offsetCost , j , lenJ ) ;
347+ costManager . PushInterval ( costManagerCosts [ j - 1 ] + offsetCost , j , lenJ ) ;
338348 reach = j + lenJ - 1 ;
339349 }
340350 }
@@ -346,7 +356,7 @@ private static void BackwardReferencesHashChainDistanceOnly(
346356 }
347357 }
348358
349- private static int TraceBackwards ( ushort [ ] distArray , int distArraySize )
359+ private static int TraceBackwards ( Span < ushort > distArray , int distArraySize )
350360 {
351361 int chosenPathSize = 0 ;
352362 int pathPos = distArraySize ;
@@ -426,8 +436,8 @@ private static void AddSingleLiteralWithCostModel(
426436 int idx ,
427437 bool useColorCache ,
428438 float prevCost ,
429- float [ ] cost ,
430- ushort [ ] distArray )
439+ Span < float > cost ,
440+ Span < ushort > distArray )
431441 {
432442 double costVal = prevCost ;
433443 uint color = bgra [ idx ] ;
@@ -617,7 +627,8 @@ private static void BackwardReferencesLz77Box(int xSize, int ySize, ReadOnlySpan
617627 }
618628 }
619629
620- hashChain . OffsetLength [ 0 ] = 0 ;
630+ Span < uint > hashChainOffsetLength = hashChain . OffsetLength . GetSpan ( ) ;
631+ hashChainOffsetLength [ 0 ] = 0 ;
621632 for ( i = 1 ; i < pixelCount ; i ++ )
622633 {
623634 int ind ;
@@ -695,19 +706,19 @@ private static void BackwardReferencesLz77Box(int xSize, int ySize, ReadOnlySpan
695706
696707 if ( bestLength <= MinLength )
697708 {
698- hashChain . OffsetLength [ i ] = 0 ;
709+ hashChainOffsetLength [ i ] = 0 ;
699710 bestOffsetPrev = 0 ;
700711 bestLengthPrev = 0 ;
701712 }
702713 else
703714 {
704- hashChain . OffsetLength [ i ] = ( uint ) ( ( bestOffset << MaxLengthBits ) | bestLength ) ;
715+ hashChainOffsetLength [ i ] = ( uint ) ( ( bestOffset << MaxLengthBits ) | bestLength ) ;
705716 bestOffsetPrev = bestOffset ;
706717 bestLengthPrev = bestLength ;
707718 }
708719 }
709720
710- hashChain . OffsetLength [ 0 ] = 0 ;
721+ hashChainOffsetLength [ 0 ] = 0 ;
711722 BackwardReferencesLz77 ( xSize , ySize , bgra , cacheBits , hashChain , refs ) ;
712723 }
713724
0 commit comments