// 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 complete coded-frame traversal through HEVC inverse-transform reconstruction.
///
[MemoryDiagnoser(displayGenColumns: false)]
public class HevcInverseTransformBenchmarks
{
///
/// The coded frame width, which is an exact multiple of the maximum transform-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 base-two logarithm of the benchmark transform-block side.
///
private const int BlockLog2 = 5;
///
/// The transform-block side in samples.
///
private const int BlockSize = 1 << BlockLog2;
///
/// The deterministic dequantized coefficients reused by each benchmark block.
///
private readonly int[] coefficients = new int[BlockSize * BlockSize];
///
/// The frame-wide predicted and reconstructed samples.
///
private readonly ushort[] destination = new ushort[Width * Height];
///
/// The maximum-block inverse-transform scratch reused throughout each coded frame.
///
private readonly int[] scratch = new int[HevcInverseTransformer.GetScratchLength(BlockLog2, BlockLog2)];
///
/// Populates a dense, deterministic twelve-bit transform workload outside the measured frame traversal.
///
[GlobalSetup]
public void Setup()
{
for (int i = 0; i < this.coefficients.Length; i++)
{
this.coefficients[i] = (((i * 37) + 11) % 127) - 63;
}
this.destination.AsSpan().Fill(2048);
}
///
/// Measures factorized inverse DCT, both transpositions, and saturated prediction addition for a coded frame.
///
/// The final reconstructed sample, keeping the frame output observable.
[Benchmark]
public ushort TransformFrame()
{
for (int y = 0; y < Height; y += BlockSize)
{
for (int x = 0; x < Width; x += BlockSize)
{
HevcInverseTransformer.TransformAdd(
this.coefficients,
this.destination.AsSpan((y * Width) + x),
Width,
BlockLog2,
BlockLog2,
12,
18,
false,
this.scratch);
}
}
return this.destination[^1];
}
}