Browse Source

CostsManager now uses MemoryAllocator

pull/1846/head
Brian Popow 5 years ago
parent
commit
b8925e1aaf
  1. 32
      src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs
  2. 57
      src/ImageSharp/Formats/Webp/Lossless/CostManager.cs

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -102,7 +103,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
if ((lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard || lz77TypeBest == (int)Vp8LLz77Type.Lz77Box) && quality >= 25) if ((lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard || lz77TypeBest == (int)Vp8LLz77Type.Lz77Box) && quality >= 25)
{ {
Vp8LHashChain hashChainTmp = lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard ? hashChain : hashChainBox; Vp8LHashChain hashChainTmp = lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard ? hashChain : hashChainBox;
BackwardReferencesTraceBackwards(width, height, bgra, cacheBits, hashChainTmp, best, worst); BackwardReferencesTraceBackwards(width, height, memoryAllocator, bgra, cacheBits, hashChainTmp, best, worst);
var histo = new Vp8LHistogram(worst, cacheBits); var histo = new Vp8LHistogram(worst, cacheBits);
double bitCostTrace = histo.EstimateBits(stats, bitsEntropy); double bitCostTrace = histo.EstimateBits(stats, bitsEntropy);
if (bitCostTrace < bitCostBest) if (bitCostTrace < bitCostBest)
@ -236,6 +237,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private static void BackwardReferencesTraceBackwards( private static void BackwardReferencesTraceBackwards(
int xSize, int xSize,
int ySize, int ySize,
MemoryAllocator memoryAllocator,
ReadOnlySpan<uint> bgra, ReadOnlySpan<uint> bgra,
int cacheBits, int cacheBits,
Vp8LHashChain hashChain, Vp8LHashChain hashChain,
@ -243,22 +245,24 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
Vp8LBackwardRefs refsDst) Vp8LBackwardRefs refsDst)
{ {
int distArraySize = xSize * ySize; int distArraySize = xSize * ySize;
ushort[] distArray = new ushort[distArraySize]; using IMemoryOwner<ushort> distArrayBuffer = memoryAllocator.Allocate<ushort>(distArraySize);
Span<ushort> distArray = distArrayBuffer.GetSpan();
BackwardReferencesHashChainDistanceOnly(xSize, ySize, bgra, cacheBits, hashChain, refsSrc, distArray); BackwardReferencesHashChainDistanceOnly(xSize, ySize, memoryAllocator, bgra, cacheBits, hashChain, refsSrc, distArrayBuffer);
int chosenPathSize = TraceBackwards(distArray, distArraySize); int chosenPathSize = TraceBackwards(distArray, distArraySize);
Span<ushort> chosenPath = distArray.AsSpan(distArraySize - chosenPathSize); Span<ushort> chosenPath = distArray.Slice(distArraySize - chosenPathSize);
BackwardReferencesHashChainFollowChosenPath(bgra, cacheBits, chosenPath, chosenPathSize, hashChain, refsDst); BackwardReferencesHashChainFollowChosenPath(bgra, cacheBits, chosenPath, chosenPathSize, hashChain, refsDst);
} }
private static void BackwardReferencesHashChainDistanceOnly( private static void BackwardReferencesHashChainDistanceOnly(
int xSize, int xSize,
int ySize, int ySize,
MemoryAllocator memoryAllocator,
ReadOnlySpan<uint> bgra, ReadOnlySpan<uint> bgra,
int cacheBits, int cacheBits,
Vp8LHashChain hashChain, Vp8LHashChain hashChain,
Vp8LBackwardRefs refs, Vp8LBackwardRefs refs,
ushort[] distArray) IMemoryOwner<ushort> distArrayBuffer)
{ {
int pixCount = xSize * ySize; int pixCount = xSize * ySize;
bool useColorCache = cacheBits > 0; bool useColorCache = cacheBits > 0;
@ -277,22 +281,24 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
} }
costModel.Build(xSize, cacheBits, refs); costModel.Build(xSize, cacheBits, refs);
var costManager = new CostManager(distArray, pixCount, costModel); var costManager = new CostManager(memoryAllocator, distArrayBuffer, pixCount, costModel);
Span<float> costManagerCosts = costManager.Costs.GetSpan();
Span<ushort> distArray = distArrayBuffer.GetSpan();
// We loop one pixel at a time, but store all currently best points to non-processed locations from this point. // We loop one pixel at a time, but store all currently best points to non-processed locations from this point.
distArray[0] = 0; distArray[0] = 0;
// Add first pixel as literal. // Add first pixel as literal.
AddSingleLiteralWithCostModel(bgra, colorCache, costModel, 0, useColorCache, 0.0f, costManager.Costs, distArray); AddSingleLiteralWithCostModel(bgra, colorCache, costModel, 0, useColorCache, 0.0f, costManagerCosts, distArray);
for (int i = 1; i < pixCount; i++) for (int i = 1; i < pixCount; i++)
{ {
float prevCost = costManager.Costs[i - 1]; float prevCost = costManagerCosts[i - 1];
int offset = hashChain.FindOffset(i); int offset = hashChain.FindOffset(i);
int len = hashChain.FindLength(i); int len = hashChain.FindLength(i);
// Try adding the pixel as a literal. // Try adding the pixel as a literal.
AddSingleLiteralWithCostModel(bgra, colorCache, costModel, i, useColorCache, prevCost, costManager.Costs, distArray); AddSingleLiteralWithCostModel(bgra, colorCache, costModel, i, useColorCache, prevCost, costManagerCosts, distArray);
// If we are dealing with a non-literal. // If we are dealing with a non-literal.
if (len >= 2) if (len >= 2)
@ -336,7 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
costManager.UpdateCostAtIndex(j - 1, false); costManager.UpdateCostAtIndex(j - 1, false);
costManager.UpdateCostAtIndex(j, false); costManager.UpdateCostAtIndex(j, false);
costManager.PushInterval(costManager.Costs[j - 1] + offsetCost, j, lenJ); costManager.PushInterval(costManagerCosts[j - 1] + offsetCost, j, lenJ);
reach = j + lenJ - 1; reach = j + lenJ - 1;
} }
} }
@ -348,7 +354,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
} }
} }
private static int TraceBackwards(ushort[] distArray, int distArraySize) private static int TraceBackwards(Span<ushort> distArray, int distArraySize)
{ {
int chosenPathSize = 0; int chosenPathSize = 0;
int pathPos = distArraySize; int pathPos = distArraySize;
@ -428,8 +434,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int idx, int idx,
bool useColorCache, bool useColorCache,
float prevCost, float prevCost,
float[] cost, Span<float> cost,
ushort[] distArray) Span<ushort> distArray)
{ {
double costVal = prevCost; double costVal = prevCost;
uint color = bgra[idx]; uint color = bgra[idx];

57
src/ImageSharp/Formats/Webp/Lossless/CostManager.cs

@ -1,7 +1,10 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Webp.Lossless namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{ {
@ -10,21 +13,23 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// It caches the different CostCacheInterval, caches the different /// It caches the different CostCacheInterval, caches the different
/// GetLengthCost(costModel, k) in costCache and the CostInterval's. /// GetLengthCost(costModel, k) in costCache and the CostInterval's.
/// </summary> /// </summary>
internal class CostManager internal class CostManager : IDisposable
{ {
private bool disposed;
private CostInterval head; private CostInterval head;
private const int FreeIntervalsStartCount = 25; private const int FreeIntervalsStartCount = 25;
private readonly Stack<CostInterval> freeIntervals = new(FreeIntervalsStartCount); private readonly Stack<CostInterval> freeIntervals = new(FreeIntervalsStartCount);
public CostManager(ushort[] distArray, int pixCount, CostModel costModel) public CostManager(MemoryAllocator memoryAllocator, IMemoryOwner<ushort> distArray, int pixCount, CostModel costModel)
{ {
int costCacheSize = pixCount > BackwardReferenceEncoder.MaxLength ? BackwardReferenceEncoder.MaxLength : pixCount; int costCacheSize = pixCount > BackwardReferenceEncoder.MaxLength ? BackwardReferenceEncoder.MaxLength : pixCount;
this.CacheIntervals = new List<CostCacheInterval>(); this.CacheIntervals = new List<CostCacheInterval>();
this.CostCache = new List<double>(); this.CostCache = new List<double>();
this.Costs = new float[pixCount]; this.Costs = memoryAllocator.Allocate<float>(pixCount);
this.DistArray = distArray; this.DistArray = distArray;
this.Count = 0; this.Count = 0;
@ -73,10 +78,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
} }
// Set the initial costs high for every pixel as we will keep the minimum. // Set the initial costs high for every pixel as we will keep the minimum.
for (int i = 0; i < pixCount; i++) this.Costs.GetSpan().Fill(1e38f);
{
this.Costs[i] = 1e38f;
}
} }
/// <summary> /// <summary>
@ -91,9 +93,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
public int CacheIntervalsSize { get; } public int CacheIntervalsSize { get; }
public float[] Costs { get; } public IMemoryOwner<float> Costs { get; }
public ushort[] DistArray { get; } public IMemoryOwner<ushort> DistArray { get; }
public List<CostCacheInterval> CacheIntervals { get; } public List<CostCacheInterval> CacheIntervals { get; }
@ -137,6 +139,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// interval logic, just serialize it right away. This constant is empirical. // interval logic, just serialize it right away. This constant is empirical.
int skipDistance = 10; int skipDistance = 10;
Span<float> costs = this.Costs.GetSpan();
Span<ushort> distArray = this.DistArray.GetSpan();
if (len < skipDistance) if (len < skipDistance)
{ {
for (int j = position; j < position + len; j++) for (int j = position; j < position + len; j++)
@ -144,10 +148,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int k = j - position; int k = j - position;
float costTmp = (float)(distanceCost + this.CostCache[k]); float costTmp = (float)(distanceCost + this.CostCache[k]);
if (this.Costs[j] > costTmp) if (costs[j] > costTmp)
{ {
this.Costs[j] = costTmp; costs[j] = costTmp;
this.DistArray[j] = (ushort)(k + 1); distArray[j] = (ushort)(k + 1);
} }
} }
@ -314,12 +318,35 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// </summary> /// </summary>
private void UpdateCost(int i, int position, float cost) private void UpdateCost(int i, int position, float cost)
{ {
Span<float> costs = this.Costs.GetSpan();
Span<ushort> distArray = this.DistArray.GetSpan();
int k = i - position; int k = i - position;
if (this.Costs[i] > cost) if (costs[i] > cost)
{
costs[i] = cost;
distArray[i] = (ushort)(k + 1);
}
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{ {
this.Costs[i] = cost; if (disposing)
this.DistArray[i] = (ushort)(k + 1); {
this.Costs.Dispose();
}
this.disposed = true;
} }
} }
/// <inheritdoc />
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
this.Dispose(disposing: true);
GC.SuppressFinalize(this);
}
} }
} }

Loading…
Cancel
Save