From c0bbd0631e76d5bec285dddb5aaca2b0b36cc2ad Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 10 Mar 2020 20:18:15 +0100 Subject: [PATCH] Vp8Decoder now uses memory allocator --- src/ImageSharp/Formats/WebP/LossyUtils.cs | 92 +++++------ src/ImageSharp/Formats/WebP/Vp8Decoder.cs | 82 +++++----- .../Formats/WebP/WebPLossyDecoder.cs | 151 +++++++++--------- 3 files changed, 171 insertions(+), 154 deletions(-) diff --git a/src/ImageSharp/Formats/WebP/LossyUtils.cs b/src/ImageSharp/Formats/WebP/LossyUtils.cs index a8f6eb98d..7222cfa7b 100644 --- a/src/ImageSharp/Formats/WebP/LossyUtils.cs +++ b/src/ImageSharp/Formats/WebP/LossyUtils.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void DC16(Span dst, byte[] yuv, int offset) + public static void DC16(Span dst, Span yuv, int offset) { int dc = 16; for (int j = 0; j < 16; ++j) @@ -28,15 +28,15 @@ namespace SixLabors.ImageSharp.Formats.WebP Put16(dc >> 5, dst); } - public static void TM16(Span dst, byte[] yuv, int offset) + public static void TM16(Span dst, Span yuv, int offset) { TrueMotion(dst, yuv, offset, 16); } - public static void VE16(Span dst, byte[] yuv, int offset) + public static void VE16(Span dst, Span yuv, int offset) { // vertical - Span src = yuv.AsSpan(offset - WebPConstants.Bps, 16); + Span src = yuv.Slice(offset - WebPConstants.Bps, 16); for (int j = 0; j < 16; ++j) { // memcpy(dst + j * BPS, dst - BPS, 16); @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void HE16(Span dst, byte[] yuv, int offset) + public static void HE16(Span dst, Span yuv, int offset) { // horizontal for (int j = 16; j > 0; --j) @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void DC16NoTop(Span dst, byte[] yuv, int offset) + public static void DC16NoTop(Span dst, Span yuv, int offset) { // DC with top samples not available. int dc = 8; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Put16(dc >> 4, dst); } - public static void DC16NoLeft(Span dst, byte[] yuv, int offset) + public static void DC16NoLeft(Span dst, Span yuv, int offset) { // DC with left samples not available. int dc = 8; @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Put16(0x80, dst); } - public static void DC8uv(Span dst, byte[] yuv, int offset) + public static void DC8uv(Span dst, Span yuv, int offset) { int dc0 = 8; for (int i = 0; i < 8; ++i) @@ -101,16 +101,16 @@ namespace SixLabors.ImageSharp.Formats.WebP Put8x8uv((byte)(dc0 >> 4), dst); } - public static void TM8uv(Span dst, byte[] yuv, int offset) + public static void TM8uv(Span dst, Span yuv, int offset) { // TrueMotion TrueMotion(dst, yuv, offset, 8); } - public static void VE8uv(Span dst, byte[] yuv, int offset) + public static void VE8uv(Span dst, Span yuv, int offset) { // vertical - Span src = yuv.AsSpan(offset - WebPConstants.Bps, 8); + Span src = yuv.Slice(offset - WebPConstants.Bps, 8); for (int j = 0; j < 8; ++j) { @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void HE8uv(Span dst, byte[] yuv, int offset) + public static void HE8uv(Span dst, Span yuv, int offset) { // horizontal for (int j = 0; j < 8; ++j) @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void DC8uvNoTop(Span dst, byte[] yuv, int offset) + public static void DC8uvNoTop(Span dst, Span yuv, int offset) { // DC with no top samples. int dc0 = 4; @@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Put8x8uv((byte)(dc0 >> 3), dst); } - public static void DC8uvNoLeft(Span dst, byte[] yuv, int offset) + public static void DC8uvNoLeft(Span dst, Span yuv, int offset) { // DC with no left samples. int dc0 = 4; @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Put8x8uv(0x80, dst); } - public static void DC4(Span dst, byte[] yuv, int offset) + public static void DC4(Span dst, Span yuv, int offset) { int dc = 4; for (int i = 0; i < 4; ++i) @@ -180,12 +180,12 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void TM4(Span dst, byte[] yuv, int offset) + public static void TM4(Span dst, Span yuv, int offset) { TrueMotion(dst, yuv, offset, 4); } - public static void VE4(Span dst, byte[] yuv, int offset) + public static void VE4(Span dst, Span yuv, int offset) { // vertical int topOffset = offset - WebPConstants.Bps; @@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void HE4(Span dst, byte[] yuv, int offset) + public static void HE4(Span dst, Span yuv, int offset) { // horizontal byte a = yuv[offset - 1 - WebPConstants.Bps]; @@ -221,7 +221,7 @@ namespace SixLabors.ImageSharp.Formats.WebP BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(3 * WebPConstants.Bps), val); } - public static void RD4(Span dst, byte[] yuv, int offset) + public static void RD4(Span dst, Span yuv, int offset) { // Down-right byte i = yuv[offset - 1]; @@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Dst(dst, 3, 0, Avg3(d, c, b)); } - public static void VR4(Span dst, byte[] yuv, int offset) + public static void VR4(Span dst, Span yuv, int offset) { // Vertical-Right byte i = yuv[offset - 1]; @@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Dst(dst, 3, 1, Avg3(b, c, d)); } - public static void LD4(Span dst, byte[] yuv, int offset) + public static void LD4(Span dst, Span yuv, int offset) { // Down-Left byte a = yuv[offset - WebPConstants.Bps]; @@ -328,7 +328,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Dst(dst, 3, 3, Avg3(g, h, h)); } - public static void VL4(Span dst, byte[] yuv, int offset) + public static void VL4(Span dst, Span yuv, int offset) { // Vertical-Left byte a = yuv[offset - WebPConstants.Bps]; @@ -364,7 +364,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Dst(dst, 3, 3, Avg3(f, g, h)); } - public static void HD4(Span dst, byte[] yuv, int offset) + public static void HD4(Span dst, Span yuv, int offset) { // Horizontal-Down byte i = yuv[offset - 1]; @@ -400,7 +400,7 @@ namespace SixLabors.ImageSharp.Formats.WebP Dst(dst, 1, 3, Avg3(l, k, j)); } - public static void HU4(Span dst, byte[] yuv, int offset) + public static void HU4(Span dst, Span yuv, int offset) { // Horizontal-Up byte i = yuv[offset - 1]; @@ -537,11 +537,11 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - private static void TrueMotion(Span dst, byte[] yuv, int offset, int size) + private static void TrueMotion(Span dst, Span yuv, int offset, int size) { // For information about how true motion works, see rfc6386, page 52. ff and section 20.14. int topOffset = offset - WebPConstants.Bps; - Span top = yuv.AsSpan(topOffset); + Span top = yuv.Slice(topOffset); byte p = yuv[topOffset - 1]; int leftOffset = offset - 1; byte left = yuv[leftOffset]; @@ -559,7 +559,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } // Simple In-loop filtering (Paragraph 15.2) - public static void SimpleVFilter16(byte[] p, int offset, int stride, int thresh) + public static void SimpleVFilter16(Span p, int offset, int stride, int thresh) { int thresh2 = (2 * thresh) + 1; for (int i = 0; i < 16; ++i) @@ -571,7 +571,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void SimpleHFilter16(byte[] p, int offset, int stride, int thresh) + public static void SimpleHFilter16(Span p, int offset, int stride, int thresh) { int thresh2 = (2 * thresh) + 1; for (int i = 0; i < 16; ++i) @@ -583,7 +583,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void SimpleVFilter16i(byte[] p, int offset, int stride, int thresh) + public static void SimpleVFilter16i(Span p, int offset, int stride, int thresh) { for (int k = 3; k > 0; --k) { @@ -592,7 +592,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void SimpleHFilter16i(byte[] p, int offset, int stride, int thresh) + public static void SimpleHFilter16i(Span p, int offset, int stride, int thresh) { for (int k = 3; k > 0; --k) { @@ -601,17 +601,17 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void VFilter16(byte[] p, int offset, int stride, int thresh, int ithresh, int hevThresh) + public static void VFilter16(Span p, int offset, int stride, int thresh, int ithresh, int hevThresh) { FilterLoop26(p, offset, stride, 1, 16, thresh, ithresh, hevThresh); } - public static void HFilter16(byte[] p, int offset, int stride, int thresh, int ithresh, int hevThresh) + public static void HFilter16(Span p, int offset, int stride, int thresh, int ithresh, int hevThresh) { FilterLoop26(p, offset, 1, stride, 16, thresh, ithresh, hevThresh); } - public static void VFilter16i(byte[] p, int offset, int stride, int thresh, int ithresh, int hevThresh) + public static void VFilter16i(Span p, int offset, int stride, int thresh, int ithresh, int hevThresh) { for (int k = 3; k > 0; --k) { @@ -620,7 +620,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - public static void HFilter16i(byte[] p, int offset, int stride, int thresh, int ithresh, int hevThresh) + public static void HFilter16i(Span p, int offset, int stride, int thresh, int ithresh, int hevThresh) { for (int k = 3; k > 0; --k) { @@ -630,25 +630,25 @@ namespace SixLabors.ImageSharp.Formats.WebP } // 8-pixels wide variant, for chroma filtering. - public static void VFilter8(byte[] u, byte[] v, int offset, int stride, int thresh, int ithresh, int hevThresh) + public static void VFilter8(Span u, Span v, int offset, int stride, int thresh, int ithresh, int hevThresh) { FilterLoop26(u, offset, stride, 1, 8, thresh, ithresh, hevThresh); FilterLoop26(v, offset, stride, 1, 8, thresh, ithresh, hevThresh); } - public static void HFilter8(byte[] u, byte[] v, int offset, int stride, int thresh, int ithresh, int hevThresh) + public static void HFilter8(Span u, Span v, int offset, int stride, int thresh, int ithresh, int hevThresh) { FilterLoop26(u, offset, 1, stride, 8, thresh, ithresh, hevThresh); FilterLoop26(v, offset, 1, stride, 8, thresh, ithresh, hevThresh); } - public static void VFilter8i(byte[] u, byte[] v, int offset, int stride, int thresh, int ithresh, int hevThresh) + public static void VFilter8i(Span u, Span v, int offset, int stride, int thresh, int ithresh, int hevThresh) { FilterLoop24(u, offset + (4 * stride), stride, 1, 8, thresh, ithresh, hevThresh); FilterLoop24(v, offset + (4 * stride), stride, 1, 8, thresh, ithresh, hevThresh); } - public static void HFilter8i(byte[] u, byte[] v, int offset, int stride, int thresh, int ithresh, int hevThresh) + public static void HFilter8i(Span u, Span v, int offset, int stride, int thresh, int ithresh, int hevThresh) { FilterLoop24(u, offset + 4, 1, stride, 8, thresh, ithresh, hevThresh); FilterLoop24(v, offset + 4, 1, stride, 8, thresh, ithresh, hevThresh); @@ -684,7 +684,7 @@ namespace SixLabors.ImageSharp.Formats.WebP // Complex In-loop filtering (Paragraph 15.3) private static void FilterLoop24( - byte[] p, + Span p, int offset, int hStride, int vStride, @@ -713,7 +713,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } private static void FilterLoop26( - byte[] p, + Span p, int offset, int hStride, int vStride, @@ -741,7 +741,7 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - private static void DoFilter2(byte[] p, int offset, int step) + private static void DoFilter2(Span p, int offset, int step) { // 4 pixels in, 2 pixels out. int p1 = p[offset - (2 * step)]; @@ -755,7 +755,7 @@ namespace SixLabors.ImageSharp.Formats.WebP p[offset] = WebPLookupTables.Clip1[q0 - a1]; } - private static void DoFilter4(byte[] p, int offset, int step) + private static void DoFilter4(Span p, int offset, int step) { // 4 pixels in, 4 pixels out. int p1 = p[offset - (2 * step)]; @@ -772,7 +772,7 @@ namespace SixLabors.ImageSharp.Formats.WebP p[offset + step] = WebPLookupTables.Clip1[q1 - a3]; } - private static void DoFilter6(byte[] p, int offset, int step) + private static void DoFilter6(Span p, int offset, int step) { // 6 pixels in, 6 pixels out. int p2 = p[offset - (3 * step)]; @@ -795,7 +795,7 @@ namespace SixLabors.ImageSharp.Formats.WebP p[offset + (2 * step)] = WebPLookupTables.Clip1[q2 - a3]; } - private static bool NeedsFilter(byte[] p, int offset, int step, int t) + private static bool NeedsFilter(Span p, int offset, int step, int t) { int p1 = p[offset + (-2 * step)]; int p0 = p[offset - step]; @@ -804,7 +804,7 @@ namespace SixLabors.ImageSharp.Formats.WebP return ((4 * WebPLookupTables.Abs0[p0 - q0]) + WebPLookupTables.Abs0[p1 - q1]) <= t; } - private static bool NeedsFilter2(byte[] p, int offset, int step, int t, int it) + private static bool NeedsFilter2(Span p, int offset, int step, int t, int it) { int p3 = p[offset - (4 * step)]; int p2 = p[offset - (3 * step)]; @@ -824,7 +824,7 @@ namespace SixLabors.ImageSharp.Formats.WebP WebPLookupTables.Abs0[q2 - q1] <= it && WebPLookupTables.Abs0[q1 - q0] <= it; } - private static bool Hev(byte[] p, int offset, int step, int thresh) + private static bool Hev(Span p, int offset, int step, int thresh) { int p1 = p[offset - (2 * step)]; int p0 = p[offset - step]; diff --git a/src/ImageSharp/Formats/WebP/Vp8Decoder.cs b/src/ImageSharp/Formats/WebP/Vp8Decoder.cs index 91a508b96..584f24b89 100644 --- a/src/ImageSharp/Formats/WebP/Vp8Decoder.cs +++ b/src/ImageSharp/Formats/WebP/Vp8Decoder.cs @@ -1,12 +1,17 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Buffers; + +using SixLabors.Memory; + namespace SixLabors.ImageSharp.Formats.WebP { /// /// Holds information for decoding a lossy webp image. /// - internal class Vp8Decoder + internal class Vp8Decoder : IDisposable { private Vp8MacroBlock leftMacroBlock; @@ -17,7 +22,8 @@ namespace SixLabors.ImageSharp.Formats.WebP /// The picture header. /// The segment header. /// The probabilities. - public Vp8Decoder(Vp8FrameHeader frameHeader, Vp8PictureHeader pictureHeader, Vp8SegmentHeader segmentHeader, Vp8Proba probabilities) + /// Used for allocating memory for the pixel data output and the temporary buffers. + public Vp8Decoder(Vp8FrameHeader frameHeader, Vp8PictureHeader pictureHeader, Vp8SegmentHeader segmentHeader, Vp8Proba probabilities, MemoryAllocator memoryAllocator) { this.FilterHeader = new Vp8FilterHeader(); this.FrameHeader = frameHeader; @@ -57,34 +63,22 @@ namespace SixLabors.ImageSharp.Formats.WebP uint width = pictureHeader.Width; uint height = pictureHeader.Height; - // TODO: use memory allocator int extraRows = WebPConstants.FilterExtraRows[(int)LoopFilter.Complex]; // assuming worst case: complex filter int extraY = extraRows * this.CacheYStride; int extraUv = (extraRows / 2) * this.CacheUvStride; - this.YuvBuffer = new byte[(WebPConstants.Bps * 17) + (WebPConstants.Bps * 9) + extraY]; - this.CacheY = new byte[(16 * this.CacheYStride) + extraY]; - this.CacheU = new byte[(16 * this.CacheUvStride) + extraUv]; - this.CacheV = new byte[(16 * this.CacheUvStride) + extraUv]; - this.TmpYBuffer = new byte[width]; - this.TmpUBuffer = new byte[width]; - this.TmpVBuffer = new byte[width]; - this.Pixels = new byte[width * height * 4]; - - for (int i = 0; i < this.YuvBuffer.Length; i++) - { - this.YuvBuffer[i] = 205; - } - - for (int i = 0; i < this.CacheY.Length; i++) - { - this.CacheY[i] = 205; - } - - for (int i = 0; i < this.CacheU.Length; i++) - { - this.CacheU[i] = 205; - this.CacheV[i] = 205; - } + this.YuvBuffer = memoryAllocator.Allocate((WebPConstants.Bps * 17) + (WebPConstants.Bps * 9) + extraY); + this.CacheY = memoryAllocator.Allocate((16 * this.CacheYStride) + extraY); + this.CacheU = memoryAllocator.Allocate((16 * this.CacheUvStride) + extraUv); + this.CacheV = memoryAllocator.Allocate((16 * this.CacheUvStride) + extraUv); + this.TmpYBuffer = memoryAllocator.Allocate((int)width); + this.TmpUBuffer = memoryAllocator.Allocate((int)width); + this.TmpVBuffer = memoryAllocator.Allocate((int)width); + this.Pixels = memoryAllocator.Allocate((int)(width * height * 4)); + + this.YuvBuffer.Memory.Span.Fill(205); + this.CacheY.Memory.Span.Fill(205); + this.CacheU.Memory.Span.Fill(205); + this.CacheV.Memory.Span.Fill(205); this.Vp8BitReaders = new Vp8BitReader[WebPConstants.MaxNumPartitions]; } @@ -206,19 +200,19 @@ namespace SixLabors.ImageSharp.Formats.WebP public LoopFilter Filter { get; set; } /// - /// Gets or sets the filter strengths. + /// Gets the filter strengths. /// public Vp8FilterInfo[,] FilterStrength { get; } - public byte[] YuvBuffer { get; } + public IMemoryOwner YuvBuffer { get; } public Vp8TopSamples[] YuvTopSamples { get; } - public byte[] CacheY { get; } + public IMemoryOwner CacheY { get; } - public byte[] CacheU { get; } + public IMemoryOwner CacheU { get; } - public byte[] CacheV { get; } + public IMemoryOwner CacheV { get; } public int CacheYOffset { get; set; } @@ -228,13 +222,16 @@ namespace SixLabors.ImageSharp.Formats.WebP public int CacheUvStride { get; } - public byte[] TmpYBuffer { get; } + public IMemoryOwner TmpYBuffer { get; } - public byte[] TmpUBuffer { get; } + public IMemoryOwner TmpUBuffer { get; } - public byte[] TmpVBuffer { get; } + public IMemoryOwner TmpVBuffer { get; } - public byte[] Pixels { get; } + /// + /// Gets the pixel buffer where the decoded pixel data will be stored. + /// + public IMemoryOwner Pixels { get; } /// /// Gets or sets filter strength info. @@ -348,5 +345,18 @@ namespace SixLabors.ImageSharp.Formats.WebP } } } + + /// + public void Dispose() + { + this.YuvBuffer.Dispose(); + this.CacheY.Dispose(); + this.CacheU.Dispose(); + this.CacheV.Dispose(); + this.TmpYBuffer.Dispose(); + this.TmpUBuffer.Dispose(); + this.TmpVBuffer.Dispose(); + this.Pixels.Dispose(); + } } } diff --git a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs index 8b9a3569c..03faaaa7c 100644 --- a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs +++ b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs @@ -55,39 +55,46 @@ namespace SixLabors.ImageSharp.Formats.WebP var proba = new Vp8Proba(); Vp8SegmentHeader vp8SegmentHeader = this.ParseSegmentHeader(proba); - var decoder = new Vp8Decoder(info.Vp8FrameHeader, pictureHeader, vp8SegmentHeader, proba); - Vp8Io io = InitializeVp8Io(decoder, pictureHeader); + using (var decoder = new Vp8Decoder(info.Vp8FrameHeader, pictureHeader, vp8SegmentHeader, proba, this.memoryAllocator)) + { + Vp8Io io = InitializeVp8Io(decoder, pictureHeader); - // Paragraph 9.4: Parse the filter specs. - this.ParseFilterHeader(decoder); - decoder.PrecomputeFilterStrengths(); + // Paragraph 9.4: Parse the filter specs. + this.ParseFilterHeader(decoder); + decoder.PrecomputeFilterStrengths(); - // Paragraph 9.5: Parse partitions. - this.ParsePartitions(decoder); + // Paragraph 9.5: Parse partitions. + this.ParsePartitions(decoder); - // Paragraph 9.6: Dequantization Indices. - this.ParseDequantizationIndices(decoder); + // Paragraph 9.6: Dequantization Indices. + this.ParseDequantizationIndices(decoder); - // Ignore the value of update probabilities. - this.bitReader.ReadBool(); + // Ignore the value of update probabilities. + this.bitReader.ReadBool(); - // Paragraph 13.4: Parse probabilities. - this.ParseProbabilities(decoder); + // Paragraph 13.4: Parse probabilities. + this.ParseProbabilities(decoder); - // Decode image data. - this.ParseFrame(decoder, io); + // Decode image data. + this.ParseFrame(decoder, io); - if (info.Features?.Alpha is true) - { - using (var alphaDecoder = new AlphaDecoder(width, height, info.Features.AlphaData, info.Features.AlphaChunkHeader, this.memoryAllocator)) + if (info.Features?.Alpha is true) { - alphaDecoder.Decode(); - this.DecodePixelValues(width, height, decoder.Pixels, pixels, alphaDecoder.Alpha); + using (var alphaDecoder = new AlphaDecoder( + width, + height, + info.Features.AlphaData, + info.Features.AlphaChunkHeader, + this.memoryAllocator)) + { + alphaDecoder.Decode(); + this.DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels, alphaDecoder.Alpha); + } + } + else + { + this.DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels); } - } - else - { - this.DecodePixelValues(width, height, decoder.Pixels, pixels); } } @@ -252,10 +259,10 @@ namespace SixLabors.ImageSharp.Formats.WebP int uOff = yOff + (WebPConstants.Bps * 16) + WebPConstants.Bps; int vOff = uOff + 16; - byte[] yuv = dec.YuvBuffer; - Span yDst = dec.YuvBuffer.AsSpan(yOff); - Span uDst = dec.YuvBuffer.AsSpan(uOff); - Span vDst = dec.YuvBuffer.AsSpan(vOff); + Span yuv = dec.YuvBuffer.Memory.Span; + Span yDst = yuv.Slice(yOff); + Span uDst = yuv.Slice(uOff); + Span vDst = yuv.Slice(vOff); // Initialize left-most block. for (int i = 0; i < 16; ++i) @@ -278,19 +285,19 @@ namespace SixLabors.ImageSharp.Formats.WebP { // We only need to do this init once at block (0,0). // Afterward, it remains valid for the whole topmost row. - Span tmp = dec.YuvBuffer.AsSpan(yOff - WebPConstants.Bps - 1, 16 + 4 + 1); + Span tmp = yuv.Slice(yOff - WebPConstants.Bps - 1, 16 + 4 + 1); for (int i = 0; i < tmp.Length; ++i) { tmp[i] = 127; } - tmp = dec.YuvBuffer.AsSpan(uOff - WebPConstants.Bps - 1, 8 + 1); + tmp = yuv.Slice(uOff - WebPConstants.Bps - 1, 8 + 1); for (int i = 0; i < tmp.Length; ++i) { tmp[i] = 127; } - tmp = dec.YuvBuffer.AsSpan(vOff - WebPConstants.Bps - 1, 8 + 1); + tmp = yuv.Slice(vOff - WebPConstants.Bps - 1, 8 + 1); for (int i = 0; i < tmp.Length; ++i) { tmp[i] = 127; @@ -310,17 +317,17 @@ namespace SixLabors.ImageSharp.Formats.WebP { int srcIdx = (i * WebPConstants.Bps) + 12 + yOff; int dstIdx = (i * WebPConstants.Bps) - 4 + yOff; - yuv.AsSpan(srcIdx, 4).CopyTo(yuv.AsSpan(dstIdx)); + yuv.Slice(srcIdx, 4).CopyTo(yuv.Slice(dstIdx)); } for (int i = -1; i < 8; ++i) { int srcIdx = (i * WebPConstants.Bps) + 4 + uOff; int dstIdx = (i * WebPConstants.Bps) - 4 + uOff; - yuv.AsSpan(srcIdx, 4).CopyTo(yuv.AsSpan(dstIdx)); + yuv.Slice(srcIdx, 4).CopyTo(yuv.Slice(dstIdx)); srcIdx = (i * WebPConstants.Bps) + 4 + vOff; dstIdx = (i * WebPConstants.Bps) - 4 + vOff; - yuv.AsSpan(srcIdx, 4).CopyTo(yuv.AsSpan(dstIdx)); + yuv.Slice(srcIdx, 4).CopyTo(yuv.Slice(dstIdx)); } } @@ -330,15 +337,15 @@ namespace SixLabors.ImageSharp.Formats.WebP uint bits = block.NonZeroY; if (mby > 0) { - topYuv.Y.CopyTo(yuv.AsSpan(yOff - WebPConstants.Bps)); - topYuv.U.CopyTo(yuv.AsSpan(uOff - WebPConstants.Bps)); - topYuv.V.CopyTo(yuv.AsSpan(vOff - WebPConstants.Bps)); + topYuv.Y.CopyTo(yuv.Slice(yOff - WebPConstants.Bps)); + topYuv.U.CopyTo(yuv.Slice(uOff - WebPConstants.Bps)); + topYuv.V.CopyTo(yuv.Slice(vOff - WebPConstants.Bps)); } // Predict and add residuals. if (block.IsI4x4) { - Span topRight = yuv.AsSpan(yOff - WebPConstants.Bps + 16); + Span topRight = yuv.Slice(yOff - WebPConstants.Bps + 16); if (mby > 0) { if (mbx >= dec.MbWidth - 1) @@ -356,14 +363,14 @@ namespace SixLabors.ImageSharp.Formats.WebP } // Replicate the top-right pixels below. - Span topRightUint = MemoryMarshal.Cast(yuv.AsSpan(yOff - WebPConstants.Bps + 16)); + Span topRightUint = MemoryMarshal.Cast(yuv.Slice(yOff - WebPConstants.Bps + 16)); topRightUint[WebPConstants.Bps] = topRightUint[2 * WebPConstants.Bps] = topRightUint[3 * WebPConstants.Bps] = topRightUint[0]; // Predict and add residuals for all 4x4 blocks in turn. for (int n = 0; n < 16; ++n, bits <<= 2) { int offset = yOff + WebPConstants.Scan[n]; - Span dst = yuv.AsSpan(offset); + Span dst = yuv.Slice(offset); byte lumaMode = block.Modes[n]; switch (lumaMode) { @@ -487,9 +494,9 @@ namespace SixLabors.ImageSharp.Formats.WebP } // Transfer reconstructed samples from yuv_buffer cache to final destination. - Span yOut = dec.CacheY.AsSpan(dec.CacheYOffset + (mbx * 16)); - Span uOut = dec.CacheU.AsSpan(dec.CacheUvOffset + (mbx * 8)); - Span vOut = dec.CacheV.AsSpan(dec.CacheUvOffset + (mbx * 8)); + Span yOut = dec.CacheY.Memory.Span.Slice(dec.CacheYOffset + (mbx * 16)); + Span uOut = dec.CacheU.Memory.Span.Slice(dec.CacheUvOffset + (mbx * 8)); + Span vOut = dec.CacheV.Memory.Span.Slice(dec.CacheUvOffset + (mbx * 8)); for (int j = 0; j < 16; ++j) { yDst.Slice(j * WebPConstants.Bps, Math.Min(16, yOut.Length)).CopyTo(yOut.Slice(j * dec.CacheYStride)); @@ -529,22 +536,22 @@ namespace SixLabors.ImageSharp.Formats.WebP int offset = dec.CacheYOffset + (mbx * 16); if (mbx > 0) { - LossyUtils.SimpleHFilter16(dec.CacheY, offset, yBps, limit + 4); + LossyUtils.SimpleHFilter16(dec.CacheY.Memory.Span, offset, yBps, limit + 4); } if (filterInfo.UseInnerFiltering > 0) { - LossyUtils.SimpleHFilter16i(dec.CacheY, offset, yBps, limit); + LossyUtils.SimpleHFilter16i(dec.CacheY.Memory.Span, offset, yBps, limit); } if (mby > 0) { - LossyUtils.SimpleVFilter16(dec.CacheY, offset, yBps, limit + 4); + LossyUtils.SimpleVFilter16(dec.CacheY.Memory.Span, offset, yBps, limit + 4); } if (filterInfo.UseInnerFiltering > 0) { - LossyUtils.SimpleVFilter16i(dec.CacheY, offset, yBps, limit); + LossyUtils.SimpleVFilter16i(dec.CacheY.Memory.Span, offset, yBps, limit); } } else if (dec.Filter is LoopFilter.Complex) @@ -555,26 +562,26 @@ namespace SixLabors.ImageSharp.Formats.WebP int hevThresh = filterInfo.HighEdgeVarianceThreshold; if (mbx > 0) { - LossyUtils.HFilter16(dec.CacheY, yOffset, yBps, limit + 4, iLevel, hevThresh); - LossyUtils.HFilter8(dec.CacheU, dec.CacheV, uvOffset, uvBps, limit + 4, iLevel, hevThresh); + LossyUtils.HFilter16(dec.CacheY.Memory.Span, yOffset, yBps, limit + 4, iLevel, hevThresh); + LossyUtils.HFilter8(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit + 4, iLevel, hevThresh); } if (filterInfo.UseInnerFiltering > 0) { - LossyUtils.HFilter16i(dec.CacheY, yOffset, yBps, limit, iLevel, hevThresh); - LossyUtils.HFilter8i(dec.CacheU, dec.CacheV, uvOffset, uvBps, limit, iLevel, hevThresh); + LossyUtils.HFilter16i(dec.CacheY.Memory.Span, yOffset, yBps, limit, iLevel, hevThresh); + LossyUtils.HFilter8i(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit, iLevel, hevThresh); } if (mby > 0) { - LossyUtils.VFilter16(dec.CacheY, yOffset, yBps, limit + 4, iLevel, hevThresh); - LossyUtils.VFilter8(dec.CacheU, dec.CacheV, uvOffset, uvBps, limit + 4, iLevel, hevThresh); + LossyUtils.VFilter16(dec.CacheY.Memory.Span, yOffset, yBps, limit + 4, iLevel, hevThresh); + LossyUtils.VFilter8(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit + 4, iLevel, hevThresh); } if (filterInfo.UseInnerFiltering > 0) { - LossyUtils.VFilter16i(dec.CacheY, yOffset, yBps, limit, iLevel, hevThresh); - LossyUtils.VFilter8i(dec.CacheU, dec.CacheV, uvOffset, uvBps, limit, iLevel, hevThresh); + LossyUtils.VFilter16i(dec.CacheY.Memory.Span, yOffset, yBps, limit, iLevel, hevThresh); + LossyUtils.VFilter8i(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit, iLevel, hevThresh); } } } @@ -584,9 +591,9 @@ namespace SixLabors.ImageSharp.Formats.WebP int extraYRows = WebPConstants.FilterExtraRows[(int)dec.Filter]; int ySize = extraYRows * dec.CacheYStride; int uvSize = (extraYRows / 2) * dec.CacheUvStride; - Span yDst = dec.CacheY.AsSpan(); - Span uDst = dec.CacheU.AsSpan(); - Span vDst = dec.CacheV.AsSpan(); + Span yDst = dec.CacheY.Memory.Span; + Span uDst = dec.CacheU.Memory.Span; + Span vDst = dec.CacheV.Memory.Span; int mby = dec.MbY; bool isFirstRow = mby is 0; bool isLastRow = mby >= dec.BottomRightMbY - 1; @@ -609,9 +616,9 @@ namespace SixLabors.ImageSharp.Formats.WebP } else { - io.Y = dec.CacheY.AsSpan(dec.CacheYOffset); - io.U = dec.CacheU.AsSpan(dec.CacheUvOffset); - io.V = dec.CacheV.AsSpan(dec.CacheUvOffset); + io.Y = dec.CacheY.Memory.Span.Slice(dec.CacheYOffset); + io.U = dec.CacheU.Memory.Span.Slice(dec.CacheUvOffset); + io.V = dec.CacheV.Memory.Span.Slice(dec.CacheUvOffset); } if (!isLastRow) @@ -639,28 +646,28 @@ namespace SixLabors.ImageSharp.Formats.WebP // Rotate top samples if needed. if (!isLastRow) { - yDst.Slice(16 * dec.CacheYStride, ySize).CopyTo(dec.CacheY.AsSpan()); - uDst.Slice(8 * dec.CacheUvStride, uvSize).CopyTo(dec.CacheU.AsSpan()); - vDst.Slice(8 * dec.CacheUvStride, uvSize).CopyTo(dec.CacheV.AsSpan()); + yDst.Slice(16 * dec.CacheYStride, ySize).CopyTo(dec.CacheY.Memory.Span); + uDst.Slice(8 * dec.CacheUvStride, uvSize).CopyTo(dec.CacheU.Memory.Span); + vDst.Slice(8 * dec.CacheUvStride, uvSize).CopyTo(dec.CacheV.Memory.Span); } } private int EmitRgb(Vp8Decoder dec, Vp8Io io) { - byte[] buf = dec.Pixels; + Span buf = dec.Pixels.Memory.Span; int numLinesOut = io.MbH; // a priori guess. Span curY = io.Y; Span curU = io.U; Span curV = io.V; - byte[] tmpYBuffer = dec.TmpYBuffer; - byte[] tmpUBuffer = dec.TmpUBuffer; - byte[] tmpVBuffer = dec.TmpVBuffer; - Span topU = tmpUBuffer.AsSpan(); - Span topV = tmpVBuffer.AsSpan(); + Span tmpYBuffer = dec.TmpYBuffer.Memory.Span; + Span tmpUBuffer = dec.TmpUBuffer.Memory.Span; + Span tmpVBuffer = dec.TmpVBuffer.Memory.Span; + Span topU = tmpUBuffer; + Span topV = tmpVBuffer; int bpp = 3; int bufferStride = bpp * io.Width; int dstStartIdx = io.MbY * bufferStride; - Span dst = buf.AsSpan(dstStartIdx); + Span dst = buf.Slice(dstStartIdx); int yEnd = io.MbY + io.MbH; int mbw = io.MbW; int uvw = (mbw + 1) / 2; @@ -674,7 +681,7 @@ namespace SixLabors.ImageSharp.Formats.WebP else { // We can finish the left-over line from previous call. - this.UpSample(tmpYBuffer.AsSpan(), curY, topU, topV, curU, curV, buf.AsSpan(dstStartIdx - bufferStride), dst, mbw); + this.UpSample(tmpYBuffer, curY, topU, topV, curU, curV, buf.Slice(dstStartIdx - bufferStride), dst, mbw); numLinesOut++; }