@ -1,63 +1,56 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers ;
using System.Runtime.CompilerServices ;
using System.Runtime.InteropServices ;
using System.Runtime.Intrinsics ;
using System.Runtime.Intrinsics.X86 ;
using SixLabors.ImageSharp.Memory ;
namespace SixLabors.ImageSharp.Formats.Webp.Lossless ;
internal sealed class Vp8LHistogram : IDeepCloneable
internal abstract unsafe class Vp8LHistogram
{
private const uint NonTrivialSym = 0xffffffff ;
private readonly uint * red ;
private readonly uint * blue ;
private readonly uint * alpha ;
private readonly uint * distance ;
private readonly uint * literal ;
private readonly uint * isUsed ;
private const int RedSize = WebpConstants . NumLiteralCodes ;
private const int BlueSize = WebpConstants . NumLiteralCodes ;
private const int AlphaSize = WebpConstants . NumLiteralCodes ;
private const int DistanceSize = WebpConstants . NumDistanceCodes ;
public const int LiteralSize = WebpConstants . NumLiteralCodes + WebpConstants . NumLengthCodes + ( 1 < < WebpConstants . MaxColorCacheBits ) + 1 ;
private const int UsedSize = 5 ; // 5 for literal, red, blue, alpha, distance
public const int BufferSize = RedSize + BlueSize + AlphaSize + DistanceSize + LiteralSize + UsedSize ;
/// <summary>
/// Initializes a new instance of the <see cref="Vp8LHistogram"/> class.
/// </summary>
/// <param name="other">The histogram to create an instance from.</param>
private Vp8LHistogram ( Vp8LHistogram other )
: this ( other . PaletteCodeBits )
{
other . Red . AsSpan ( ) . CopyTo ( this . Red ) ;
other . Blue . AsSpan ( ) . CopyTo ( this . Blue ) ;
other . Alpha . AsSpan ( ) . CopyTo ( this . Alpha ) ;
other . Literal . AsSpan ( ) . CopyTo ( this . Literal ) ;
other . Distance . AsSpan ( ) . CopyTo ( this . Distance ) ;
other . IsUsed . AsSpan ( ) . CopyTo ( this . IsUsed ) ;
this . LiteralCost = other . LiteralCost ;
this . RedCost = other . RedCost ;
this . BlueCost = other . BlueCost ;
this . BitCost = other . BitCost ;
this . TrivialSymbol = other . TrivialSymbol ;
this . PaletteCodeBits = other . PaletteCodeBits ;
}
/// <summary>
/// Initializes a new instance of the <see cref="Vp8LHistogram"/> class.
/// </summary>
/// <param name="basePointer">The base pointer to the backing memory.</param>
/// <param name="refs">The backward references to initialize the histogram with.</param>
/// <param name="paletteCodeBits">The palette code bits.</param>
public Vp8LHistogram ( Vp8LBackwardRefs refs , int paletteCodeBits )
: this ( paletteCodeBits ) = > this . StoreRefs ( refs ) ;
protected Vp8LHistogram ( uint * basePointer , Vp8LBackwardRefs refs , int paletteCodeBits )
: this ( basePointer , paletteCodeBits ) = > this . StoreRefs ( refs ) ;
/// <summary>
/// Initializes a new instance of the <see cref="Vp8LHistogram"/> class.
/// </summary>
/// <param name="basePointer">The base pointer to the backing memory.</param>
/// <param name="paletteCodeBits">The palette code bits.</param>
public Vp8LHistogram ( int paletteCodeBits )
protected Vp8LHistogram ( uint * basePointer , int paletteCodeBits )
{
this . PaletteCodeBits = paletteCodeBits ;
this . Red = new uint [ WebpConstants . NumLiteralCodes + 1 ] ;
this . Blue = new uint [ WebpConstants . NumLiteralCodes + 1 ] ;
this . Alpha = new uint [ WebpConstants . NumLiteralCodes + 1 ] ;
this . Distance = new uint [ WebpConstants . NumDistanceCodes ] ;
int literalSize = WebpConstants . NumLiteralCodes + WebpConstants . NumLengthCodes + ( 1 < < WebpConstants . MaxColorCacheBits ) ;
this . Literal = new uint [ literalSize + 1 ] ;
// 5 for literal, red, blue, alpha, distance.
this . IsUsed = new bool [ 5 ] ;
this . red = basePointer ;
this . blue = this . red + RedSize ;
this . alpha = this . blue + BlueSize ;
this . distance = this . alpha + AlphaSize ;
this . literal = this . distance + DistanceSize ;
this . isUsed = this . literal + LiteralSize ;
}
/// <summary>
@ -85,22 +78,59 @@ internal sealed class Vp8LHistogram : IDeepCloneable
/// </summary>
public double BlueCost { get ; set ; }
public uint [ ] Red { get ; }
public Span < uint > Red = > new ( this . red , RedSize ) ;
public uint [ ] Blue { get ; }
public Span < uint > Blue = > new ( this . blue , BlueSize ) ;
public uint [ ] Alpha { get ; }
public Span < uint > Alpha = > new ( this . alpha , AlphaSize ) ;
public uint [ ] Literal { get ; }
public Span < uint > Distance = > new ( this . distance , DistanceSize ) ;
public uint [ ] Distance { get ; }
public Span < uint > Literal = > new ( this . literal , LiteralSize ) ;
public uint TrivialSymbol { get ; set ; }
public bool [ ] IsUsed { get ; }
private Span < uint > IsUsedSpan = > new ( this . isUsed , UsedSize ) ;
private Span < uint > TotalSpan = > new ( this . red , BufferSize ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsUsed ( int index ) = > this . IsUsedSpan [ index ] = = 1 u ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IsUsed ( int index , bool value ) = > this . IsUsedSpan [ index ] = value ? 1 u : 0 ;
/// <summary>
/// Creates a copy of the given <see cref="Vp8LHistogram"/> class.
/// </summary>
/// <param name="other">The histogram to copy to.</param>
public void CopyTo ( Vp8LHistogram other )
{
this . Red . CopyTo ( other . Red ) ;
this . Blue . CopyTo ( other . Blue ) ;
this . Alpha . CopyTo ( other . Alpha ) ;
this . Literal . CopyTo ( other . Literal ) ;
this . Distance . CopyTo ( other . Distance ) ;
this . IsUsedSpan . CopyTo ( other . IsUsedSpan ) ;
other . LiteralCost = this . LiteralCost ;
other . RedCost = this . RedCost ;
other . BlueCost = this . BlueCost ;
other . BitCost = this . BitCost ;
other . TrivialSymbol = this . TrivialSymbol ;
other . PaletteCodeBits = this . PaletteCodeBits ;
}
/// <inheritdoc/>
public IDeepCloneable DeepClone ( ) = > new Vp8LHistogram ( this ) ;
public void Clear ( )
{
this . TotalSpan . Clear ( ) ;
this . PaletteCodeBits = 0 ;
this . BitCost = 0 ;
this . LiteralCost = 0 ;
this . RedCost = 0 ;
this . BlueCost = 0 ;
this . TrivialSymbol = 0 ;
}
/// <summary>
/// Collect all the references into a histogram (without reset).
@ -108,10 +138,9 @@ internal sealed class Vp8LHistogram : IDeepCloneable
/// <param name="refs">The backward references.</param>
public void StoreRefs ( Vp8LBackwardRefs refs )
{
using List < PixOrCopy > . Enumerator c = refs . Refs . GetEnumerator ( ) ;
while ( c . MoveNext ( ) )
for ( int i = 0 ; i < refs . Refs . Count ; i + + )
{
this . AddSinglePixOrCopy ( c . Current , false ) ;
this . AddSinglePixOrCopy ( refs . Refs [ i ] , false ) ;
}
}
@ -163,12 +192,12 @@ internal sealed class Vp8LHistogram : IDeepCloneable
{
uint notUsed = 0 ;
return
PopulationCost ( this . Literal , this . NumCodes ( ) , ref notUsed , ref this . IsUsed [ 0 ] , stats , bitsEntropy )
+ PopulationCost ( this . Red , WebpConstants . NumLiteralCodes , ref notUsed , ref this . IsUsed [ 1 ] , stats , bitsEntropy )
+ PopulationCost ( this . Blue , WebpConstants . NumLiteralCodes , ref notUsed , ref this . IsUsed [ 2 ] , stats , bitsEntropy )
+ PopulationCost ( this . Alpha , WebpConstants . NumLiteralCodes , ref notUsed , ref this . IsUsed [ 3 ] , stats , bitsEntropy )
+ PopulationCost ( this . Distance , WebpConstants . NumDistanceCodes , ref notUsed , ref this . IsUsed [ 4 ] , stats , bitsEntropy )
+ ExtraCost ( this . Literal . AsSpan ( WebpConstants . NumLiteralCodes ) , WebpConstants . NumLengthCodes )
this . PopulationCost ( this . Literal , this . NumCodes ( ) , ref notUsed , 0 , stats , bitsEntropy )
+ this . PopulationCost ( this . Red , WebpConstants . NumLiteralCodes , ref notUsed , 1 , stats , bitsEntropy )
+ this . PopulationCost ( this . Blue , WebpConstants . NumLiteralCodes , ref notUsed , 2 , stats , bitsEntropy )
+ this . PopulationCost ( this . Alpha , WebpConstants . NumLiteralCodes , ref notUsed , 3 , stats , bitsEntropy )
+ this . PopulationCost ( this . Distance , WebpConstants . NumDistanceCodes , ref notUsed , 4 , stats , bitsEntropy )
+ ExtraCost ( this . Literal [ WebpConstants . NumLiteralCodes . . ] , WebpConstants . NumLengthCodes )
+ ExtraCost ( this . Distance , WebpConstants . NumDistanceCodes ) ;
}
@ -177,12 +206,12 @@ internal sealed class Vp8LHistogram : IDeepCloneable
uint alphaSym = 0 , redSym = 0 , blueSym = 0 ;
uint notUsed = 0 ;
double alphaCost = PopulationCost ( this . Alpha , WebpConstants . NumLiteralCodes , ref alphaSym , ref this . IsUsed [ 3 ] , stats , bitsEntropy ) ;
double distanceCost = PopulationCost ( this . Distance , WebpConstants . NumDistanceCodes , ref notUsed , ref this . IsUsed [ 4 ] , stats , bitsEntropy ) + ExtraCost ( this . Distance , WebpConstants . NumDistanceCodes ) ;
double alphaCost = this . PopulationCost ( this . Alpha , WebpConstants . NumLiteralCodes , ref alphaSym , 3 , stats , bitsEntropy ) ;
double distanceCost = this . PopulationCost ( this . Distance , WebpConstants . NumDistanceCodes , ref notUsed , 4 , stats , bitsEntropy ) + ExtraCost ( this . Distance , WebpConstants . NumDistanceCodes ) ;
int numCodes = this . NumCodes ( ) ;
this . LiteralCost = PopulationCost ( this . Literal , numCodes , ref notUsed , ref this . IsUsed [ 0 ] , stats , bitsEntropy ) + ExtraCost ( this . Literal . AsSpan ( WebpConstants . NumLiteralCodes ) , WebpConstants . NumLengthCodes ) ;
this . RedCost = PopulationCost ( this . Red , WebpConstants . NumLiteralCodes , ref redSym , ref this . IsUsed [ 1 ] , stats , bitsEntropy ) ;
this . BlueCost = PopulationCost ( this . Blue , WebpConstants . NumLiteralCodes , ref blueSym , ref this . IsUsed [ 2 ] , stats , bitsEntropy ) ;
this . LiteralCost = this . PopulationCost ( this . Literal , numCodes , ref notUsed , 0 , stats , bitsEntropy ) + ExtraCost ( this . Literal [ WebpConstants . NumLiteralCodes . . ] , WebpConstants . NumLengthCodes ) ;
this . RedCost = this . PopulationCost ( this . Red , WebpConstants . NumLiteralCodes , ref redSym , 1 , stats , bitsEntropy ) ;
this . BlueCost = this . PopulationCost ( this . Blue , WebpConstants . NumLiteralCodes , ref blueSym , 2 , stats , bitsEntropy ) ;
this . BitCost = this . LiteralCost + this . RedCost + this . BlueCost + alphaCost + distanceCost ;
if ( ( alphaSym | redSym | blueSym ) = = NonTrivialSym )
{
@ -234,7 +263,7 @@ internal sealed class Vp8LHistogram : IDeepCloneable
for ( int i = 0 ; i < 5 ; i + + )
{
output . IsUsed [ i ] = this . IsUsed [ i ] | b . IsUsed [ i ] ;
output . IsUsed ( i , this . IsUsed ( i ) | b . IsUsed ( i ) ) ;
}
output . TrivialSymbol = this . TrivialSymbol = = b . TrivialSymbol
@ -247,9 +276,9 @@ internal sealed class Vp8LHistogram : IDeepCloneable
bool trivialAtEnd = false ;
cost = costInitial ;
cost + = GetCombinedEntropy ( this . Literal , b . Literal , this . NumCodes ( ) , this . IsUsed [ 0 ] , b . IsUsed [ 0 ] , false , stats , bitEntropy ) ;
cost + = GetCombinedEntropy ( this . Literal , b . Literal , this . NumCodes ( ) , this . IsUsed ( 0 ) , b . IsUsed ( 0 ) , false , stats , bitEntropy ) ;
cost + = ExtraCostCombined ( this . Literal . AsSpan ( WebpConstants . NumLiteralCodes ) , b . Literal . AsSpan ( WebpConstants . NumLiteralCodes ) , WebpConstants . NumLengthCodes ) ;
cost + = ExtraCostCombined ( this . Literal [ WebpConstants . NumLiteralCodes . . ] , b . Literal [ WebpConstants . NumLiteralCodes . . ] , WebpConstants . NumLengthCodes ) ;
if ( cost > costThreshold )
{
@ -270,155 +299,158 @@ internal sealed class Vp8LHistogram : IDeepCloneable
}
}
cost + = GetCombinedEntropy ( this . Red , b . Red , WebpConstants . NumLiteralCodes , this . IsUsed [ 1 ] , b . IsUsed [ 1 ] , trivialAtEnd , stats , bitEntropy ) ;
cost + = GetCombinedEntropy ( this . Red , b . Red , WebpConstants . NumLiteralCodes , this . IsUsed ( 1 ) , b . IsUsed ( 1 ) , trivialAtEnd , stats , bitEntropy ) ;
if ( cost > costThreshold )
{
return false ;
}
cost + = GetCombinedEntropy ( this . Blue , b . Blue , WebpConstants . NumLiteralCodes , this . IsUsed [ 2 ] , b . IsUsed [ 2 ] , trivialAtEnd , stats , bitEntropy ) ;
cost + = GetCombinedEntropy ( this . Blue , b . Blue , WebpConstants . NumLiteralCodes , this . IsUsed ( 2 ) , b . IsUsed ( 2 ) , trivialAtEnd , stats , bitEntropy ) ;
if ( cost > costThreshold )
{
return false ;
}
cost + = GetCombinedEntropy ( this . Alpha , b . Alpha , WebpConstants . NumLiteralCodes , this . IsUsed [ 3 ] , b . IsUsed [ 3 ] , trivialAtEnd , stats , bitEntropy ) ;
cost + = GetCombinedEntropy ( this . Alpha , b . Alpha , WebpConstants . NumLiteralCodes , this . IsUsed ( 3 ) , b . IsUsed ( 3 ) , trivialAtEnd , stats , bitEntropy ) ;
if ( cost > costThreshold )
{
return false ;
}
cost + = GetCombinedEntropy ( this . Distance , b . Distance , WebpConstants . NumDistanceCodes , this . IsUsed [ 4 ] , b . IsUsed [ 4 ] , false , stats , bitEntropy ) ;
cost + = GetCombinedEntropy ( this . Distance , b . Distance , WebpConstants . NumDistanceCodes , this . IsUsed ( 4 ) , b . IsUsed ( 4 ) , false , stats , bitEntropy ) ;
if ( cost > costThreshold )
{
return false ;
}
cost + = ExtraCostCombined ( this . Distance , b . Distance , WebpConstants . NumDistanceCodes ) ;
if ( cost > costThreshold )
{
return false ;
}
return true ;
return cost < = costThreshold ;
}
private void AddLiteral ( Vp8LHistogram b , Vp8LHistogram output , int literalSize )
{
if ( this . IsUsed [ 0 ] )
if ( this . IsUsed ( 0 ) )
{
if ( b . IsUsed [ 0 ] )
if ( b . IsUsed ( 0 ) )
{
AddVector ( this . Literal , b . Literal , output . Literal , literalSize ) ;
}
else
{
this . Literal . AsSpan ( 0 , literalSize ) . CopyTo ( output . Literal ) ;
this . Literal [ . . literalSize ] . CopyTo ( output . Literal ) ;
}
}
else if ( b . IsUsed [ 0 ] )
else if ( b . IsUsed ( 0 ) )
{
b . Literal . AsSpan ( 0 , literalSize ) . CopyTo ( output . Literal ) ;
b . Literal [ . . literalSize ] . CopyTo ( output . Literal ) ;
}
else
{
output . Literal . AsSpan ( 0 , literalSize ) . Clear ( ) ;
output . Literal [ . . literalSize ] . Clear ( ) ;
}
}
private void AddRed ( Vp8LHistogram b , Vp8LHistogram output , int size )
{
if ( this . IsUsed [ 1 ] )
if ( this . IsUsed ( 1 ) )
{
if ( b . IsUsed [ 1 ] )
if ( b . IsUsed ( 1 ) )
{
AddVector ( this . Red , b . Red , output . Red , size ) ;
}
else
{
this . Red . AsSpan ( 0 , size ) . CopyTo ( output . Red ) ;
this . Red [ . . size ] . CopyTo ( output . Red ) ;
}
}
else if ( b . IsUsed [ 1 ] )
else if ( b . IsUsed ( 1 ) )
{
b . Red . AsSpan ( 0 , size ) . CopyTo ( output . Red ) ;
b . Red [ . . size ] . CopyTo ( output . Red ) ;
}
else
{
output . Red . AsSpan ( 0 , size ) . Clear ( ) ;
output . Red [ . . size ] . Clear ( ) ;
}
}
private void AddBlue ( Vp8LHistogram b , Vp8LHistogram output , int size )
{
if ( this . IsUsed [ 2 ] )
if ( this . IsUsed ( 2 ) )
{
if ( b . IsUsed [ 2 ] )
if ( b . IsUsed ( 2 ) )
{
AddVector ( this . Blue , b . Blue , output . Blue , size ) ;
}
else
{
this . Blue . AsSpan ( 0 , size ) . CopyTo ( output . Blue ) ;
this . Blue [ . . size ] . CopyTo ( output . Blue ) ;
}
}
else if ( b . IsUsed [ 2 ] )
else if ( b . IsUsed ( 2 ) )
{
b . Blue . AsSpan ( 0 , size ) . CopyTo ( output . Blue ) ;
b . Blue [ . . size ] . CopyTo ( output . Blue ) ;
}
else
{
output . Blue . AsSpan ( 0 , size ) . Clear ( ) ;
output . Blue [ . . size ] . Clear ( ) ;
}
}
private void AddAlpha ( Vp8LHistogram b , Vp8LHistogram output , int size )
{
if ( this . IsUsed [ 3 ] )
if ( this . IsUsed ( 3 ) )
{
if ( b . IsUsed [ 3 ] )
if ( b . IsUsed ( 3 ) )
{
AddVector ( this . Alpha , b . Alpha , output . Alpha , size ) ;
}
else
{
this . Alpha . AsSpan ( 0 , size ) . CopyTo ( output . Alpha ) ;
this . Alpha [ . . size ] . CopyTo ( output . Alpha ) ;
}
}
else if ( b . IsUsed [ 3 ] )
else if ( b . IsUsed ( 3 ) )
{
b . Alpha . AsSpan ( 0 , size ) . CopyTo ( output . Alpha ) ;
b . Alpha [ . . size ] . CopyTo ( output . Alpha ) ;
}
else
{
output . Alpha . AsSpan ( 0 , size ) . Clear ( ) ;
output . Alpha [ . . size ] . Clear ( ) ;
}
}
private void AddDistance ( Vp8LHistogram b , Vp8LHistogram output , int size )
{
if ( this . IsUsed [ 4 ] )
if ( this . IsUsed ( 4 ) )
{
if ( b . IsUsed [ 4 ] )
if ( b . IsUsed ( 4 ) )
{
AddVector ( this . Distance , b . Distance , output . Distance , size ) ;
}
else
{
this . Distance . AsSpan ( 0 , size ) . CopyTo ( output . Distance ) ;
this . Distance [ . . size ] . CopyTo ( output . Distance ) ;
}
}
else if ( b . IsUsed [ 4 ] )
else if ( b . IsUsed ( 4 ) )
{
b . Distance . AsSpan ( 0 , size ) . CopyTo ( output . Distance ) ;
b . Distance [ . . size ] . CopyTo ( output . Distance ) ;
}
else
{
output . Distance . AsSpan ( 0 , size ) . Clear ( ) ;
output . Distance [ . . size ] . Clear ( ) ;
}
}
private static double GetCombinedEntropy ( uint [ ] x , uint [ ] y , int length , bool isXUsed , bool isYUsed , bool trivialAtEnd , Vp8LStreaks stats , Vp8LBitEntropy bitEntropy )
private static double GetCombinedEntropy (
Span < uint > x ,
Span < uint > y ,
int length ,
bool isXUsed ,
bool isYUsed ,
bool trivialAtEnd ,
Vp8LStreaks stats ,
Vp8LBitEntropy bitEntropy )
{
stats . Clear ( ) ;
bitEntropy . Init ( ) ;
@ -450,18 +482,15 @@ internal sealed class Vp8LHistogram : IDeepCloneable
bitEntropy . GetEntropyUnrefined ( x , length , stats ) ;
}
}
else if ( isYUsed )
{
bitEntropy . GetEntropyUnrefined ( y , length , stats ) ;
}
else
{
if ( isYUsed )
{
bitEntropy . GetEntropyUnrefined ( y , length , stats ) ;
}
else
{
stats . Counts [ 0 ] = 1 ;
stats . Streaks [ 0 ] [ length > 3 ? 1 : 0 ] = length ;
bitEntropy . Init ( ) ;
}
stats . Counts [ 0 ] = 1 ;
stats . Streaks [ 0 ] [ length > 3 ? 1 : 0 ] = length ;
bitEntropy . Init ( ) ;
}
return bitEntropy . BitsEntropyRefine ( ) + stats . FinalHuffmanCost ( ) ;
@ -482,7 +511,7 @@ internal sealed class Vp8LHistogram : IDeepCloneable
/// <summary>
/// Get the symbol entropy for the distribution 'population'.
/// </summary>
private static double PopulationCost ( uint [ ] population , int length , ref uint trivialSym , ref bool isUsed , Vp8LStreaks stats , Vp8LBitEntropy bitEntropy )
private double PopulationCost ( Span < uint > population , int length , ref uint trivialSym , int isUsedIndex , Vp8LStreaks stats , Vp8LBitEntropy bitEntropy )
{
bitEntropy . Init ( ) ;
stats . Clear ( ) ;
@ -491,7 +520,7 @@ internal sealed class Vp8LHistogram : IDeepCloneable
trivialSym = ( bitEntropy . NoneZeros = = 1 ) ? bitEntropy . NoneZeroCode : NonTrivialSym ;
// The histogram is used if there is at least one non-zero streak.
isUsed = stats . Streaks [ 1 ] [ 0 ] ! = 0 | | stats . Streaks [ 1 ] [ 1 ] ! = 0 ;
this . IsUsed ( isUsedIndex , stats . Streaks [ 1 ] [ 0 ] ! = 0 | | stats . Streaks [ 1 ] [ 1 ] ! = 0 ) ;
return bitEntropy . BitsEntropyRefine ( ) + stats . FinalHuffmanCost ( ) ;
}
@ -557,3 +586,56 @@ internal sealed class Vp8LHistogram : IDeepCloneable
}
}
}
internal sealed unsafe class OwnedVp8LHistogram : Vp8LHistogram , IDisposable
{
private readonly IMemoryOwner < uint > bufferOwner ;
private MemoryHandle bufferHandle ;
private bool isDisposed ;
private OwnedVp8LHistogram (
IMemoryOwner < uint > bufferOwner ,
ref MemoryHandle bufferHandle ,
uint * basePointer ,
int paletteCodeBits )
: base ( basePointer , paletteCodeBits )
{
this . bufferOwner = bufferOwner ;
this . bufferHandle = bufferHandle ;
}
/// <summary>
/// Creates an <see cref="OwnedVp8LHistogram"/> that is not a member of a <see cref="Vp8LHistogramSet"/>.
/// </summary>
/// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="paletteCodeBits">The palette code bits.</param>
public static OwnedVp8LHistogram Create ( MemoryAllocator memoryAllocator , int paletteCodeBits )
{
IMemoryOwner < uint > bufferOwner = memoryAllocator . Allocate < uint > ( BufferSize , AllocationOptions . Clean ) ;
MemoryHandle bufferHandle = bufferOwner . Memory . Pin ( ) ;
return new OwnedVp8LHistogram ( bufferOwner , ref bufferHandle , ( uint * ) bufferHandle . Pointer , paletteCodeBits ) ;
}
/// <summary>
/// Creates an <see cref="OwnedVp8LHistogram"/> that is not a member of a <see cref="Vp8LHistogramSet"/>.
/// </summary>
/// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="refs">The backward references to initialize the histogram with.</param>
/// <param name="paletteCodeBits">The palette code bits.</param>
public static OwnedVp8LHistogram Create ( MemoryAllocator memoryAllocator , Vp8LBackwardRefs refs , int paletteCodeBits )
{
OwnedVp8LHistogram histogram = Create ( memoryAllocator , paletteCodeBits ) ;
histogram . StoreRefs ( refs ) ;
return histogram ;
}
public void Dispose ( )
{
if ( ! this . isDisposed )
{
this . bufferHandle . Dispose ( ) ;
this . bufferOwner . Dispose ( ) ;
this . isDisposed = true ;
}
}
}