// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction; using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction.ChromaFromLuma; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Heif; /// /// Measures frame-wide AV1 chroma-from-luma prediction at each available intrinsic tier. /// [Config(typeof(Configuration))] [MemoryDiagnoser(displayGenColumns: false)] [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] [CategoriesColumn] public class Av1ChromaFromLumaBenchmarks { /// /// The coded frame width, which is an exact multiple of the maximum CfL block side. /// 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 maximum CfL block side in chroma samples. /// private const int BlockSize = 32; /// /// The fixed-stride Q3 luma residual surface reused by each benchmark block. /// private readonly short[] lumaQ3 = new short[BlockSize * BlockSize]; /// /// The frame-wide 8-bit DC prediction surface. /// private readonly byte[] destination8 = new byte[Width * Height]; /// /// The frame-wide 12-bit DC prediction surface. /// private readonly short[] destination12 = new short[Width * Height]; /// /// Populates deterministic Q3 residuals and DC predictions outside the measured traversal. /// [GlobalSetup] public void Setup() { for (int index = 0; index < this.lumaQ3.Length; index++) { this.lumaQ3[index] = (short)(((index * 4051) % 65521) - 32760); } this.destination8.AsSpan().Fill(137); this.destination12.AsSpan().Fill(2101); } /// /// Measures frame-wide 8-bit chroma-from-luma prediction. /// /// The final reconstructed sample, keeping the frame output observable. [Benchmark] [BenchmarkCategory("8Bit")] public byte Predict8BitFrame() { for (int row = 0; row < Height; row += BlockSize) { for (int column = 0; column < Width; column += BlockSize) { Av1ChromaFromLumaPredictor.Predict(this.lumaQ3, this.destination8.AsSpan((row * Width) + column), Width, 11, BlockSize, BlockSize); } } return this.destination8[^1]; } /// /// Measures frame-wide 12-bit chroma-from-luma prediction. /// /// The final reconstructed sample, keeping the frame output observable. [Benchmark] [BenchmarkCategory("12Bit")] public short Predict12BitFrame() { for (int row = 0; row < Height; row += BlockSize) { for (int column = 0; column < Width; column += BlockSize) { Av1ChromaFromLumaPredictor.Predict(this.lumaQ3, this.destination12.AsSpan((row * Width) + column), Width, 11, 12, BlockSize, BlockSize); } } return this.destination12[^1]; } /// /// Configures production-process measurements for the default, AVX2, Vector128, and scalar paths. /// public sealed class Configuration : ManualConfig { /// /// Initializes a new instance of the class. /// public Configuration() { this.AddJob( Job.ShortRun .WithId("Hardware") .AsBaseline()); this.AddJob( Job.ShortRun .WithId("Avx2") .WithEnvironmentVariable("DOTNET_EnableAVX512F", "0")); this.AddJob( Job.ShortRun .WithId("Vector128") .WithEnvironmentVariable("DOTNET_EnableAVX512F", "0") .WithEnvironmentVariable("DOTNET_EnableAVX2", "0")); this.AddJob( Job.ShortRun .WithId("Scalar") .WithEnvironmentVariable("DOTNET_EnableHWIntrinsic", "0")); } } }