Browse Source

Remove more allocations and add tasks.

pull/2546/head
James Jackson-South 3 years ago
parent
commit
63829e8437
  1. 23
      src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs
  2. 23
      src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs
  3. 7
      src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs

23
src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs

@ -52,6 +52,8 @@ internal static class BackwardReferenceEncoder
Vp8LHashChain? hashChainBox = null; Vp8LHashChain? hashChainBox = null;
Vp8LStreaks stats = new(); Vp8LStreaks stats = new();
Vp8LBitEntropy bitsEntropy = new(); Vp8LBitEntropy bitsEntropy = new();
ColorCache[] colorCache = new ColorCache[WebpConstants.MaxColorCacheBits + 1];
for (int lz77Type = 1; lz77TypesToTry > 0; lz77TypesToTry &= ~lz77Type, lz77Type <<= 1) for (int lz77Type = 1; lz77TypesToTry > 0; lz77TypesToTry &= ~lz77Type, lz77Type <<= 1)
{ {
int cacheBitsTmp = cacheBitsInitial; int cacheBitsTmp = cacheBitsInitial;
@ -76,7 +78,7 @@ internal static class BackwardReferenceEncoder
} }
// Next, try with a color cache and update the references. // Next, try with a color cache and update the references.
cacheBitsTmp = CalculateBestCacheSize(memoryAllocator, bgra, quality, worst, cacheBitsTmp); cacheBitsTmp = CalculateBestCacheSize(memoryAllocator, colorCache, bgra, quality, worst, cacheBitsTmp);
if (cacheBitsTmp > 0) if (cacheBitsTmp > 0)
{ {
BackwardRefsWithLocalCache(bgra, cacheBitsTmp, worst); BackwardRefsWithLocalCache(bgra, cacheBitsTmp, worst);
@ -123,6 +125,7 @@ internal static class BackwardReferenceEncoder
/// <returns>Best cache size.</returns> /// <returns>Best cache size.</returns>
private static int CalculateBestCacheSize( private static int CalculateBestCacheSize(
MemoryAllocator memoryAllocator, MemoryAllocator memoryAllocator,
Span<ColorCache> colorCache,
ReadOnlySpan<uint> bgra, ReadOnlySpan<uint> bgra,
uint quality, uint quality,
Vp8LBackwardRefs refs, Vp8LBackwardRefs refs,
@ -138,12 +141,8 @@ internal static class BackwardReferenceEncoder
double entropyMin = MaxEntropy; double entropyMin = MaxEntropy;
int pos = 0; int pos = 0;
// TODO: Pass from outer loop and clear. using Vp8LHistogramSet histos = new(memoryAllocator, colorCache.Length, 0);
ColorCache[] colorCache = new ColorCache[WebpConstants.MaxColorCacheBits + 1]; for (int i = 0; i < colorCache.Length; i++)
// TODO: Use fixed size.
using Vp8LHistogramSet histos = new(memoryAllocator, WebpConstants.MaxColorCacheBits + 1, 0);
for (int i = 0; i <= WebpConstants.MaxColorCacheBits; i++)
{ {
histos[i].PaletteCodeBits = i; histos[i].PaletteCodeBits = i;
colorCache[i] = new ColorCache(i); colorCache[i] = new ColorCache(i);
@ -448,12 +447,12 @@ internal static class BackwardReferenceEncoder
int ix = useColorCache ? colorCache!.Contains(color) : -1; int ix = useColorCache ? colorCache!.Contains(color) : -1;
if (ix >= 0) if (ix >= 0)
{ {
double mul0 = 0.68; const double mul0 = 0.68;
costVal += costModel.GetCacheCost((uint)ix) * mul0; costVal += costModel.GetCacheCost((uint)ix) * mul0;
} }
else else
{ {
double mul1 = 0.82; const double mul1 = 0.82;
if (useColorCache) if (useColorCache)
{ {
colorCache!.Insert(color); colorCache!.Insert(color);
@ -700,10 +699,8 @@ internal static class BackwardReferenceEncoder
bestLength = MaxLength; bestLength = MaxLength;
break; break;
} }
else
{ bestLength = currLength;
bestLength = currLength;
}
} }
} }
} }

23
src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable #nullable disable
using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -45,9 +46,9 @@ internal static class HistogramEncoder
int imageHistoRawSize = histoXSize * histoYSize; int imageHistoRawSize = histoXSize * histoYSize;
const int entropyCombineNumBins = BinSize; const int entropyCombineNumBins = BinSize;
// TODO: Allocations! using IMemoryOwner<ushort> tmp = memoryAllocator.Allocate<ushort>(imageHistoRawSize * 2, AllocationOptions.Clean);
ushort[] mapTmp = new ushort[imageHistoRawSize]; Span<ushort> mapTmp = tmp.Slice(0, imageHistoRawSize);
ushort[] clusterMappings = new ushort[imageHistoRawSize]; Span<ushort> clusterMappings = tmp.Slice(imageHistoRawSize, imageHistoRawSize);
using Vp8LHistogramSet origHisto = new(memoryAllocator, imageHistoRawSize, cacheBits); using Vp8LHistogramSet origHisto = new(memoryAllocator, imageHistoRawSize, cacheBits);
@ -60,13 +61,12 @@ internal static class HistogramEncoder
bool entropyCombine = numUsed > entropyCombineNumBins * 2 && quality < 100; bool entropyCombine = numUsed > entropyCombineNumBins * 2 && quality < 100;
if (entropyCombine) if (entropyCombine)
{ {
ushort[] binMap = mapTmp;
int numClusters = numUsed; int numClusters = numUsed;
double combineCostFactor = GetCombineCostFactor(imageHistoRawSize, quality); double combineCostFactor = GetCombineCostFactor(imageHistoRawSize, quality);
HistogramAnalyzeEntropyBin(imageHisto, binMap); HistogramAnalyzeEntropyBin(imageHisto, mapTmp);
// Collapse histograms with similar entropy. // Collapse histograms with similar entropy.
HistogramCombineEntropyBin(imageHisto, histogramSymbols, clusterMappings, tmpHisto, binMap, entropyCombineNumBins, combineCostFactor); HistogramCombineEntropyBin(imageHisto, histogramSymbols, clusterMappings, tmpHisto, mapTmp, entropyCombineNumBins, combineCostFactor);
OptimizeHistogramSymbols(clusterMappings, numClusters, mapTmp, histogramSymbols); OptimizeHistogramSymbols(clusterMappings, numClusters, mapTmp, histogramSymbols);
} }
@ -128,7 +128,7 @@ internal static class HistogramEncoder
/// Partition histograms to different entropy bins for three dominant (literal, /// Partition histograms to different entropy bins for three dominant (literal,
/// red and blue) symbol costs and compute the histogram aggregate bitCost. /// red and blue) symbol costs and compute the histogram aggregate bitCost.
/// </summary> /// </summary>
private static void HistogramAnalyzeEntropyBin(Vp8LHistogramSet histograms, ushort[] binMap) private static void HistogramAnalyzeEntropyBin(Vp8LHistogramSet histograms, Span<ushort> binMap)
{ {
int histoSize = histograms.Count; int histoSize = histograms.Count;
DominantCostRange costRange = new(); DominantCostRange costRange = new();
@ -198,9 +198,9 @@ internal static class HistogramEncoder
private static void HistogramCombineEntropyBin( private static void HistogramCombineEntropyBin(
Vp8LHistogramSet histograms, Vp8LHistogramSet histograms,
Span<ushort> clusters, Span<ushort> clusters,
ushort[] clusterMappings, Span<ushort> clusterMappings,
Vp8LHistogram curCombo, Vp8LHistogram curCombo,
ushort[] binMap, ReadOnlySpan<ushort> binMap,
int numBins, int numBins,
double combineCostFactor) double combineCostFactor)
{ {
@ -276,7 +276,7 @@ internal static class HistogramEncoder
/// Given a Histogram set, the mapping of clusters 'clusterMapping' and the /// Given a Histogram set, the mapping of clusters 'clusterMapping' and the
/// current assignment of the cells in 'symbols', merge the clusters and assign the smallest possible clusters values. /// current assignment of the cells in 'symbols', merge the clusters and assign the smallest possible clusters values.
/// </summary> /// </summary>
private static void OptimizeHistogramSymbols(ushort[] clusterMappings, int numClusters, ushort[] clusterMappingsTmp, Span<ushort> symbols) private static void OptimizeHistogramSymbols(Span<ushort> clusterMappings, int numClusters, Span<ushort> clusterMappingsTmp, Span<ushort> symbols)
{ {
bool doContinue = true; bool doContinue = true;
@ -303,7 +303,7 @@ internal static class HistogramEncoder
// Create a mapping from a cluster id to its minimal version. // Create a mapping from a cluster id to its minimal version.
int clusterMax = 0; int clusterMax = 0;
clusterMappingsTmp.AsSpan().Clear(); clusterMappingsTmp.Clear();
// Re-map the ids. // Re-map the ids.
for (int i = 0; i < symbols.Length; i++) for (int i = 0; i < symbols.Length; i++)
@ -515,7 +515,6 @@ internal static class HistogramEncoder
histograms.DisposeAt(idx2); histograms.DisposeAt(idx2);
// Remove pairs intersecting the just combined best pair. // Remove pairs intersecting the just combined best pair.
// TODO: Reversing this will avoid the need to remove from the end of the list.
for (int i = 0; i < histoPriorityList.Count;) for (int i = 0; i < histoPriorityList.Count;)
{ {
HistogramPair p = histoPriorityList[i]; HistogramPair p = histoPriorityList[i];

7
src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs

@ -885,7 +885,7 @@ internal class Vp8LEncoder : IDisposable
private void StoreFullHuffmanCode(Span<HuffmanTree> huffTree, HuffmanTreeToken[] tokens, HuffmanTreeCode tree) private void StoreFullHuffmanCode(Span<HuffmanTree> huffTree, HuffmanTreeToken[] tokens, HuffmanTreeCode tree)
{ {
// TODO: Allocations. // TODO: Allocations. This method is called in a loop.
int i; int i;
byte[] codeLengthBitDepth = new byte[WebpConstants.CodeLengthCodes]; byte[] codeLengthBitDepth = new byte[WebpConstants.CodeLengthCodes];
short[] codeLengthBitDepthSymbols = new short[WebpConstants.CodeLengthCodes]; short[] codeLengthBitDepthSymbols = new short[WebpConstants.CodeLengthCodes];
@ -1628,6 +1628,7 @@ internal class Vp8LEncoder : IDisposable
} }
} }
// TODO: Allocations.
int end = 5 * histogramImage.Count; int end = 5 * histogramImage.Count;
for (int i = 0; i < end; i++) for (int i = 0; i < end; i++)
{ {
@ -1641,9 +1642,9 @@ internal class Vp8LEncoder : IDisposable
} }
// Create Huffman trees. // Create Huffman trees.
// TODO: Allocations. Size here has a max and can be sliced. // TODO: Allocations.
bool[] bufRle = new bool[maxNumSymbols]; bool[] bufRle = new bool[maxNumSymbols];
Span<HuffmanTree> huffTree = stackalloc HuffmanTree[3 * maxNumSymbols]; HuffmanTree[] huffTree = new HuffmanTree[3 * maxNumSymbols];
for (int i = 0; i < histogramImage.Count; i++) for (int i = 0; i < histogramImage.Count; i++)
{ {

Loading…
Cancel
Save