// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.PixelBlenders; /// /// Compares straight-alpha and associated-alpha bulk pixel blending. /// [Config(typeof(Config.Short))] public class AssociatedAlphaPixelBlenderBenchmark { private const int PixelCount = 1024; private readonly Rgba32[] unassociatedDestination = new Rgba32[PixelCount]; private readonly Rgba32[] unassociatedBackground = new Rgba32[PixelCount]; private readonly Rgba32[] unassociatedSource = new Rgba32[PixelCount]; private readonly Rgba32P[] associatedDestination = new Rgba32P[PixelCount]; private readonly Rgba32P[] associatedBackground = new Rgba32P[PixelCount]; private readonly Rgba32P[] associatedSource = new Rgba32P[PixelCount]; private readonly float[] amounts = new float[PixelCount]; private readonly Vector4[] unassociatedWorkingBuffer = new Vector4[PixelCount * 3]; private readonly Vector4[] associatedWorkingBuffer = new Vector4[PixelCount * 3]; private PixelBlender unassociatedBlender; private PixelBlender associatedBlender; /// /// Gets or sets the color-blending mode measured by the benchmark. /// [ParamsAllValues] public PixelColorBlendingMode ColorMode { get; set; } /// /// Gets or sets the alpha-composition mode measured by the benchmark. /// [ParamsAllValues] public PixelAlphaCompositionMode AlphaMode { get; set; } /// /// Initializes equivalent straight-alpha and associated-alpha rows. /// [GlobalSetup] public void Setup() { this.unassociatedBlender = PixelOperations.Instance.GetPixelBlender(this.ColorMode, this.AlphaMode); this.associatedBlender = PixelOperations.Instance.GetPixelBlender(this.ColorMode, this.AlphaMode); Random random = new(42); for (int i = 0; i < PixelCount; i++) { Rgba32 background = new((byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(64, 256)); Rgba32 source = new((byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(64, 256)); this.unassociatedBackground[i] = background; this.unassociatedSource[i] = source; this.associatedBackground[i] = Rgba32P.FromRgba32(background); this.associatedSource[i] = Rgba32P.FromRgba32(source); this.amounts[i] = random.NextSingle(); } } /// /// Blends one row stored with straight alpha. /// /// The last destination pixel. [Benchmark(Description = "Straight alpha", Baseline = true)] public Rgba32 BlendUnassociated() { this.unassociatedBlender.Blend( Configuration.Default, this.unassociatedDestination, this.unassociatedBackground, this.unassociatedSource, this.amounts, this.unassociatedWorkingBuffer); return this.unassociatedDestination[^1]; } /// /// Blends one row stored with associated alpha. /// /// The last destination pixel. [Benchmark(Description = "Associated alpha")] public Rgba32P BlendAssociated() { this.associatedBlender.Blend( Configuration.Default, this.associatedDestination, this.associatedBackground, this.associatedSource, this.amounts, this.associatedWorkingBuffer); return this.associatedDestination[^1]; } }