mirror of https://github.com/SixLabors/ImageSharp
1 changed files with 100 additions and 0 deletions
@ -0,0 +1,100 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jxl.Processing.RenderPipeline; |
|||
|
|||
internal sealed class GaborishStage : RenderPipelineStageBase |
|||
{ |
|||
private InlineArray9<float> weights; |
|||
|
|||
public GaborishStage(Configuration configuration, JxlLoopFilter lf) |
|||
: base(configuration) |
|||
{ |
|||
this.Settings = RenderPipelineStageConfiguration.CreateSymmetricBorderOnly(1); |
|||
|
|||
this.weights[0] = 1; |
|||
this.weights[1] = lf.GaborishXWeight1; |
|||
this.weights[2] = lf.GaborishXWeight2; |
|||
this.weights[3] = 1; |
|||
this.weights[4] = lf.GaborishYWeight1; |
|||
this.weights[5] = lf.GaborishYWeight2; |
|||
this.weights[6] = 1; |
|||
this.weights[7] = lf.GaborishBWeight1; |
|||
this.weights[8] = lf.GaborishBWeight2; |
|||
|
|||
// Normalization
|
|||
for (int c = 0; c < 3; c++) |
|||
{ |
|||
int c3 = c * 3; // prevent repeated multiplication
|
|||
|
|||
float div = this.weights[c3] + (4 * (this.weights[c3 + 1] + this.weights[c3 + 2])); |
|||
float mul = 1.0f / div; |
|||
|
|||
this.weights[c3] *= mul; |
|||
this.weights[c3 + 1] *= mul; |
|||
this.weights[c3 + 2] *= mul; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string Name => "Gab"; |
|||
|
|||
public override void ProcessRow(Buffer2D<Memory<float>> inputRows, Buffer2D<Memory<float>> outputRows, int xExtraLeft, int xExtraRight, int width, int xPos, int yPos) |
|||
{ |
|||
int xStart = -JxlMath.RoundUpTo(xExtraLeft, Vector<float>.Count); |
|||
int xEnd = width + xExtraRight; |
|||
|
|||
for (int c = 0; c < 3; c++) |
|||
{ |
|||
int c3 = c * 3; // prevent repeated multiplication
|
|||
|
|||
Span<float> rowT = this.GetInputRow(inputRows, c, -1); |
|||
Span<float> rowM = this.GetInputRow(inputRows, c, 0); |
|||
Span<float> rowB = this.GetInputRow(inputRows, c, 1); |
|||
Span<float> rowOut = GetOutputRow(outputRows, c, 0); |
|||
|
|||
Vector<float> w0 = Vector.Create(this.weights[c3]); |
|||
Vector<float> w1 = Vector.Create(this.weights[c3 + 1]); |
|||
Vector<float> w2 = Vector.Create(this.weights[c3 + 2]); |
|||
|
|||
// Ref for performance
|
|||
ref float refRowT = ref MemoryMarshal.GetReference(rowT); |
|||
ref float refRowM = ref MemoryMarshal.GetReference(rowM); |
|||
ref float refRowB = ref MemoryMarshal.GetReference(rowB); |
|||
ref float refRowOut = ref MemoryMarshal.GetReference(rowOut); |
|||
|
|||
for (int x = xStart; x < xEnd; x += Vector<float>.Count) |
|||
{ |
|||
Vector<float> t = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowT, x)); |
|||
Vector<float> tl = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowT, x - 1)); |
|||
Vector<float> tr = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowT, x + 1)); |
|||
|
|||
Vector<float> m = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowM, x)); |
|||
Vector<float> l = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowM, x - 1)); |
|||
Vector<float> r = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowM, x + 1)); |
|||
|
|||
Vector<float> b = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowB, x)); |
|||
Vector<float> bl = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowB, x - 1)); |
|||
Vector<float> br = Vector.LoadUnsafe(ref Unsafe.Add(ref refRowB, x + 1)); |
|||
|
|||
Vector<float> sum0 = m; |
|||
Vector<float> sum1 = (l + r) + (t + b); |
|||
Vector<float> sum2 = (tl + tr) + (bl + br); |
|||
|
|||
Vector<float> pixels = (sum2 * w2) + ((sum1 * w1) + (sum0 * w0)); |
|||
pixels.StoreUnsafe(ref Unsafe.Add(ref refRowOut, x)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override RenderPipelineChannelMode GetChannelMode(int channel) => |
|||
channel < 3 |
|||
? RenderPipelineChannelMode.InPlace |
|||
: RenderPipelineChannelMode.Ignored; |
|||
} |
|||
Loading…
Reference in new issue