// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Heif.Hevc; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Heif; /// /// Measures frame-wide preparation of complete and partially substituted HEVC intra references. /// [MemoryDiagnoser(displayGenColumns: false)] public class HevcIntraReferencePreparationBenchmarks { /// /// The coded frame width. /// private const int Width = 1920; /// /// The coded frame height including the final padded coding-tree row for a 1080-line presentation. /// private const int Height = 1088; /// /// The base-two logarithm of the benchmark prediction-block side. /// private const int BlockLog2 = 5; /// /// The prediction-block side in samples. /// private const int BlockSize = 1 << BlockLog2; /// /// The availability-unit side in samples. /// private const int UnitSize = 4; /// /// The number of availability units surrounding one benchmark block. /// private const int AvailabilityUnitCount = ((BlockSize * 2) / UnitSize * 2) + 1; /// /// The complete reference availability pattern. /// private readonly bool[] completeAvailability = new bool[AvailabilityUnitCount]; /// /// The partial availability pattern exercising forward substitution. /// private readonly bool[] partialAvailability = new bool[AvailabilityUnitCount]; /// /// The reusable top reference destination. /// private readonly ushort[] top = new ushort[(BlockSize * 2) + 1]; /// /// The reusable left reference destination. /// private readonly ushort[] left = new ushort[(BlockSize * 2) + 1]; /// /// The reusable reference-line scratch storage. /// private readonly ushort[] scratch = new ushort[HevcIntraPredictor.GetReferenceScratchLength(BlockLog2, UnitSize)]; /// /// The reconstructed picture providing benchmark reference samples. /// private HevcPictureBuffer picture; /// /// Allocates and initializes the reconstructed benchmark picture outside measured operations. /// [GlobalSetup] public void Setup() { this.picture = new HevcPictureBuffer( Configuration.Default, Width + (BlockSize * 2), Height + (BlockSize * 2), 12, 12, 1, false); for (int y = 0; y < this.picture.Height; y++) { Span row = this.picture.GetRowSpan(HevcPlane.Y, y); for (int x = 0; x < row.Length; x++) { row[x] = (ushort)(((37 * x) + (53 * y)) & 4095); } } this.completeAvailability.AsSpan().Fill(true); for (int i = 0; i < this.partialAvailability.Length; i++) { this.partialAvailability[i] = (i & 3) != 0; } } /// /// Releases the reconstructed benchmark picture. /// [GlobalCleanup] public void Cleanup() => this.picture.Dispose(); /// /// Measures the complete-border fast path across a padded 1080p coded frame. /// /// A prepared reference sample, keeping the result observable. [Benchmark(Baseline = true)] public ushort PrepareCompleteFrame() => this.PrepareFrame(this.completeAvailability); /// /// Measures partial-unit collection and substitution across a padded 1080p coded frame. /// /// A prepared reference sample, keeping the result observable. [Benchmark] public ushort PreparePartialFrame() => this.PrepareFrame(this.partialAvailability); /// /// Prepares references for every maximum-size block in the benchmark frame. /// /// The repeated availability pattern. /// The final prepared reference sample. private ushort PrepareFrame(ReadOnlySpan availability) { for (int y = 0; y < Height; y += BlockSize) { for (int x = 0; x < Width; x += BlockSize) { HevcIntraPredictor.PrepareReferenceSamples( this.picture, HevcPlane.Y, x + BlockSize, y + BlockSize, BlockLog2, UnitSize, UnitSize, availability, this.top, this.left, this.scratch); } } return this.left[^1]; } }