Browse Source

Use Readonly Span for bgra data

pull/1552/head
Brian Popow 5 years ago
parent
commit
ea911998ef
  1. 42
      src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs
  2. 4
      src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs
  3. 14
      src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs
  4. 56
      src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
  5. 4
      src/ImageSharp/Formats/WebP/Lossless/Vp8LHashChain.cs

42
src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs

@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
public static Vp8LBackwardRefs GetBackwardReferences(
int width,
int height,
Span<uint> bgra,
ReadOnlySpan<uint> bgra,
int quality,
int lz77TypesToTry,
ref int cacheBits,
@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// The local color cache is also disabled for the lower (smaller then 25) quality.
/// </summary>
/// <returns>Best cache size.</returns>
private static int CalculateBestCacheSize(Span<uint> bgra, int quality, Vp8LBackwardRefs refs, int bestCacheBits)
private static int CalculateBestCacheSize(ReadOnlySpan<uint> bgra, int quality, Vp8LBackwardRefs refs, int bestCacheBits)
{
int cacheBitsMax = (quality <= 25) ? 0 : bestCacheBits;
if (cacheBitsMax == 0)
@ -227,7 +227,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
return bestCacheBits;
}
private static void BackwardReferencesTraceBackwards(int xSize, int ySize, Span<uint> bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refsSrc, Vp8LBackwardRefs refsDst)
private static void BackwardReferencesTraceBackwards(
int xSize,
int ySize,
ReadOnlySpan<uint> bgra,
int cacheBits,
Vp8LHashChain hashChain,
Vp8LBackwardRefs refsSrc,
Vp8LBackwardRefs refsDst)
{
int distArraySize = xSize * ySize;
ushort[] distArray = new ushort[distArraySize];
@ -238,7 +245,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
BackwardReferencesHashChainFollowChosenPath(bgra, cacheBits, chosenPath, chosenPathSize, hashChain, refsDst);
}
private static void BackwardReferencesHashChainDistanceOnly(int xSize, int ySize, Span<uint> bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refs, ushort[] distArray)
private static void BackwardReferencesHashChainDistanceOnly(
int xSize,
int ySize,
ReadOnlySpan<uint> bgra,
int cacheBits,
Vp8LHashChain hashChain,
Vp8LBackwardRefs refs,
ushort[] distArray)
{
int pixCount = xSize * ySize;
bool useColorCache = cacheBits > 0;
@ -346,7 +360,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
return chosenPathSize;
}
private static void BackwardReferencesHashChainFollowChosenPath(Span<uint> bgra, int cacheBits, Span<ushort> chosenPath, int chosenPathSize, Vp8LHashChain hashChain, Vp8LBackwardRefs backwardRefs)
private static void BackwardReferencesHashChainFollowChosenPath(ReadOnlySpan<uint> bgra, int cacheBits, Span<ushort> chosenPath, int chosenPathSize, Vp8LHashChain hashChain, Vp8LBackwardRefs backwardRefs)
{
bool useColorCache = cacheBits > 0;
var colorCache = new ColorCache();
@ -402,7 +416,15 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
}
private static void AddSingleLiteralWithCostModel(Span<uint> bgra, ColorCache colorCache, CostModel costModel, int idx, bool useColorCache, float prevCost, float[] cost, ushort[] distArray)
private static void AddSingleLiteralWithCostModel(
ReadOnlySpan<uint> bgra,
ColorCache colorCache,
CostModel costModel,
int idx,
bool useColorCache,
float prevCost,
float[] cost,
ushort[] distArray)
{
double costVal = prevCost;
uint color = bgra[idx];
@ -430,7 +452,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
}
private static void BackwardReferencesLz77(int xSize, int ySize, Span<uint> bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refs)
private static void BackwardReferencesLz77(int xSize, int ySize, ReadOnlySpan<uint> bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refs)
{
int iLastCheck = -1;
bool useColorCache = cacheBits > 0;
@ -508,7 +530,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// Compute an LZ77 by forcing matches to happen within a given distance cost.
/// We therefore limit the algorithm to the lowest 32 values in the PlaneCode definition.
/// </summary>
private static void BackwardReferencesLz77Box(int xSize, int ySize, Span<uint> bgra, int cacheBits, Vp8LHashChain hashChainBest, Vp8LHashChain hashChain, Vp8LBackwardRefs refs)
private static void BackwardReferencesLz77Box(int xSize, int ySize, ReadOnlySpan<uint> bgra, int cacheBits, Vp8LHashChain hashChainBest, Vp8LHashChain hashChain, Vp8LBackwardRefs refs)
{
int pixelCount = xSize * ySize;
int[] windowOffsets = new int[WindowOffsetsSizeMax];
@ -686,7 +708,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
BackwardReferencesLz77(xSize, ySize, bgra, cacheBits, hashChain, refs);
}
private static void BackwardReferencesRle(int xSize, int ySize, Span<uint> bgra, int cacheBits, Vp8LBackwardRefs refs)
private static void BackwardReferencesRle(int xSize, int ySize, ReadOnlySpan<uint> bgra, int cacheBits, Vp8LBackwardRefs refs)
{
int pixelCount = xSize * ySize;
bool useColorCache = cacheBits > 0;
@ -739,7 +761,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <summary>
/// Update (in-place) backward references for the specified cacheBits.
/// </summary>
private static void BackwardRefsWithLocalCache(Span<uint> bgra, int cacheBits, Vp8LBackwardRefs refs)
private static void BackwardRefsWithLocalCache(ReadOnlySpan<uint> bgra, int cacheBits, Vp8LBackwardRefs refs)
{
int pixelIndex = 0;
var colorCache = new ColorCache();

4
src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs

@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// is bestLenMatch, and the index itself otherwise.
/// If no two elements are the same, it returns maxLimit.
/// </summary>
public static int FindMatchLength(Span<uint> array1, Span<uint> array2, int bestLenMatch, int maxLimit)
public static int FindMatchLength(ReadOnlySpan<uint> array1, ReadOnlySpan<uint> array2, int bestLenMatch, int maxLimit)
{
// Before 'expensive' linear match, check if the two arrays match at the
// current best length index.
@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
[MethodImpl(InliningOptions.ShortMethod)]
public static int VectorMismatch(Span<uint> array1, Span<uint> array2, int length)
public static int VectorMismatch(ReadOnlySpan<uint> array1, ReadOnlySpan<uint> array2, int length)
{
int matchLen = 0;

14
src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs

@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int width,
int height,
int bits,
Span<uint> argb,
Span<uint> argbScratch,
Span<uint> bgra,
Span<uint> bgraScratch,
Span<uint> image,
int nearLosslessQuality,
bool exact,
@ -66,8 +66,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
tileY,
bits,
histo,
argbScratch,
argb,
bgraScratch,
bgra,
maxQuantization,
exact,
usedSubtractGreen,
@ -82,8 +82,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
height,
bits,
image,
argbScratch,
argb,
bgraScratch,
bgra,
maxQuantization,
exact,
usedSubtractGreen);
@ -559,7 +559,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
if (maxQuantization > 1)
{
// Compute max_diffs for the lower row now, because that needs the
// contents of argb for the current row, which we will overwrite with
// contents of bgra for the current row, which we will overwrite with
// residuals before proceeding with the next row.
Span<byte> tmp8 = currentMaxDiffs;
currentMaxDiffs = lowerMaxDiffs;

56
src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs

@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
/// <summary>
/// Gets memory for the transformed image data.
/// Gets the memory for the encoded output image data.
/// </summary>
public IMemoryOwner<uint> Bgra { get; }
@ -236,19 +236,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int height = image.Height;
// Convert image pixels to bgra array.
this.ConvertPixelsToBgra(image, width, height);
Span<uint> bgra = this.Bgra.GetSpan();
using IMemoryOwner<Bgra32> bgraRowBuffer = this.memoryAllocator.Allocate<Bgra32>(width);
Span<Bgra32> bgraRow = bgraRowBuffer.GetSpan();
int idx = 0;
for (int y = 0; y < height; y++)
{
Span<TPixel> rowSpan = image.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32(this.configuration, rowSpan, bgraRow);
for (int x = 0; x < width; x++)
{
bgra[idx++] = bgraRow[x].PackedValue;
}
}
// Analyze image (entropy, numPalettes etc).
CrunchConfig[] crunchConfigs = this.EncoderAnalyze(bgra, width, height, out bool redAndBlueAlwaysZero);
@ -337,6 +326,31 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
this.BitWriterSwap(ref bitWriterBest, ref this.bitWriter);
}
/// <summary>
/// Converts the pixels of the image to bgra.
/// </summary>
/// <typeparam name="TPixel">The type of the pixels.</typeparam>
/// <param name="image">The image to convert.</param>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
private void ConvertPixelsToBgra<TPixel>(Image<TPixel> image, int width, int height)
where TPixel : unmanaged, IPixel<TPixel>
{
Span<uint> bgra = this.Bgra.GetSpan();
using IMemoryOwner<Bgra32> bgraRowBuffer = this.memoryAllocator.Allocate<Bgra32>(width);
Span<Bgra32> bgraRow = bgraRowBuffer.GetSpan();
int idx = 0;
for (int y = 0; y < height; y++)
{
Span<TPixel> rowSpan = image.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32(this.configuration, rowSpan, bgraRow);
for (int x = 0; x < width; x++)
{
bgra[idx++] = bgraRow[x].PackedValue;
}
}
}
/// <summary>
/// Analyzes the image and decides which transforms should be used.
/// </summary>
@ -344,7 +358,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <param name="width">The image width.</param>
/// <param name="height">The image height.</param>
/// <param name="redAndBlueAlwaysZero">Indicates if red and blue are always zero.</param>
private CrunchConfig[] EncoderAnalyze(Span<uint> bgra, int width, int height, out bool redAndBlueAlwaysZero)
private CrunchConfig[] EncoderAnalyze(ReadOnlySpan<uint> bgra, int width, int height, out bool redAndBlueAlwaysZero)
{
// Check if we only deal with a small number of colors and should use a palette.
bool usePalette = this.AnalyzeAndCreatePalette(bgra, width, height);
@ -407,7 +421,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
return crunchConfigs.ToArray();
}
private void EncodeImage(Span<uint> bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs[] refsArray, int width, int height, bool useCache, CrunchConfig config, int cacheBits, int histogramBits)
private void EncodeImage(ReadOnlySpan<uint> bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs[] refsArray, int width, int height, bool useCache, CrunchConfig config, int cacheBits, int histogramBits)
{
int histogramImageXySize = LosslessUtils.SubSampleSize(width, histogramBits) * LosslessUtils.SubSampleSize(height, histogramBits);
ushort[] histogramSymbols = new ushort[histogramImageXySize];
@ -929,7 +943,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <param name="transformBits">The transformation bits.</param>
/// <param name="redAndBlueAlwaysZero">Indicates if red and blue are always zero.</param>
/// <returns>The entropy mode to use.</returns>
private EntropyIx AnalyzeEntropy(Span<uint> bgra, int width, int height, bool usePalette, int paletteSize, int transformBits, out bool redAndBlueAlwaysZero)
private EntropyIx AnalyzeEntropy(ReadOnlySpan<uint> bgra, int width, int height, bool usePalette, int paletteSize, int transformBits, out bool redAndBlueAlwaysZero)
{
if (usePalette && paletteSize <= 16)
{
@ -942,10 +956,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
using IMemoryOwner<uint> histoBuffer = this.memoryAllocator.Allocate<uint>((int)HistoIx.HistoTotal * 256);
Span<uint> histo = histoBuffer.Memory.Span;
uint pixPrev = bgra[0]; // Skip the first pixel.
Span<uint> prevRow = null;
ReadOnlySpan<uint> prevRow = null;
for (int y = 0; y < height; y++)
{
Span<uint> currentRow = bgra.Slice(y * width, width);
ReadOnlySpan<uint> currentRow = bgra.Slice(y * width, width);
for (int x = 0; x < width; x++)
{
uint pix = currentRow[x];
@ -1087,7 +1101,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <param name="width">The image width.</param>
/// <param name="height">The image height.</param>
/// <returns>true, if a palette should be used.</returns>
private bool AnalyzeAndCreatePalette(Span<uint> bgra, int width, int height)
private bool AnalyzeAndCreatePalette(ReadOnlySpan<uint> bgra, int width, int height)
{
Span<uint> palette = this.Palette.Memory.Span;
this.PaletteSize = this.GetColorPalette(bgra, width, height, palette);
@ -1117,12 +1131,12 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <param name="height">The image height.</param>
/// <param name="palette">The span to store the palette into.</param>
/// <returns>The number of palette entries.</returns>
private int GetColorPalette(Span<uint> bgra, int width, int height, Span<uint> palette)
private int GetColorPalette(ReadOnlySpan<uint> bgra, int width, int height, Span<uint> palette)
{
var colors = new HashSet<uint>();
for (int y = 0; y < height; y++)
{
Span<uint> bgraRow = bgra.Slice(y * width, width);
ReadOnlySpan<uint> bgraRow = bgra.Slice(y * width, width);
for (int x = 0; x < width; x++)
{
colors.Add(bgraRow[x]);

4
src/ImageSharp/Formats/WebP/Lossless/Vp8LHashChain.cs

@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// </summary>
public int Size { get; }
public void Fill(MemoryAllocator memoryAllocator, Span<uint> bgra, int quality, int xSize, int ySize)
public void Fill(MemoryAllocator memoryAllocator, ReadOnlySpan<uint> bgra, int quality, int xSize, int ySize)
{
int size = xSize * ySize;
int iterMax = GetMaxItersForQuality(quality);
@ -249,7 +249,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <param name="bgra">An Span with two pixels.</param>
/// <returns>The hash.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static uint GetPixPairHash64(Span<uint> bgra)
private static uint GetPixPairHash64(ReadOnlySpan<uint> bgra)
{
uint key = bgra[1] * HashMultiplierHi;
key += bgra[0] * HashMultiplierLo;

Loading…
Cancel
Save