Browse Source

Optimize ScaledCopyTo for common scale factors

pull/3115/head
James Jackson-South 3 months ago
parent
commit
420ae7444c
  1. 339
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor2.cs
  2. 281
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor4.cs
  3. 154
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor8.cs

339
src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor2.cs

@ -66,32 +66,335 @@ internal sealed class DownScalingComponentProcessor2 : ComponentProcessor
[MethodImpl(InliningOptions.ShortMethod)]
public static void ScaledCopyTo(ref Block8x8F block, ref float destRef, int destStrideWidth, int horizontalScale, int verticalScale)
{
// TODO: Optimize: implement all cases with scale-specific, loopless code!
if (horizontalScale == 1 && verticalScale == 1)
{
CopyTo1x1Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 2 && verticalScale == 2)
{
CopyTo2x2Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 2 && verticalScale == 1)
{
CopyTo2x1Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 1 && verticalScale == 2)
{
CopyTo1x2Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 4 && verticalScale == 1)
{
CopyTo4x1Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 4 && verticalScale == 2)
{
CopyTo4x2Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 1 && verticalScale == 4)
{
CopyTo1x4Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 2 && verticalScale == 4)
{
CopyTo2x4Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 4 && verticalScale == 4)
{
CopyTo4x4Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
// The common 1x, 2x, and 4x integral scales are specialized above.
// Uncommon legal factor-3 scales use the generic fallback.
CopyArbitraryScale(ref block, ref destRef, (uint)destStrideWidth, (uint)horizontalScale, (uint)verticalScale);
}
/// <summary>
/// Copies a 4x4 reduced block directly into the destination buffer when no chroma expansion is needed.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo1x1Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
CopyRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 1u, 1u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 2u, 2u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 3u, 3u, areaStride);
}
/// <summary>
/// Copies a 4x4 reduced block into the destination buffer while doubling only the horizontal axis.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x1Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
WidenRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 1u, 1u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 2u, 2u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 3u, 3u, areaStride);
}
/// <summary>
/// Copies a 4x4 reduced block into the destination buffer while doubling only the vertical axis.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo1x2Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
CopyRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 1u, 2u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 1u, 3u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 2u, 4u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 2u, 5u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 3u, 6u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 3u, 7u, areaStride);
}
/// <summary>
/// Copies a 4x4 reduced block into the destination buffer while doubling both axes.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x2Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
WidenRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 1u, 2u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 1u, 3u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 2u, 4u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 2u, 5u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 3u, 6u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 3u, 7u, areaStride);
}
[MethodImpl(InliningOptions.ColdPath)]
static void CopyArbitraryScale(ref Block8x8F block, ref float areaOrigin, uint areaStride, uint horizontalScale, uint verticalScale)
/// <summary>
/// Copies a 4x4 reduced block into the destination buffer while quadrupling only the horizontal axis.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x1Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
ExpandRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 1u, 1u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 2u, 2u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 3u, 3u, areaStride);
}
/// <summary>
/// Copies a 4x4 reduced block into the destination buffer while quadrupling horizontally and doubling vertically.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x2Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
ExpandRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 1u, 2u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 1u, 3u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 2u, 4u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 2u, 5u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 3u, 6u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 3u, 7u, areaStride);
}
/// <summary>
/// Copies a 4x4 reduced block into the destination buffer while quadrupling only the vertical axis.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo1x4Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
CopyRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 0u, 2u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 0u, 3u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 1u, 4u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 1u, 5u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 1u, 6u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 1u, 7u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 2u, 8u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 2u, 9u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 2u, 10u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 2u, 11u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 3u, 12u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 3u, 13u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 3u, 14u, areaStride);
CopyRow4(ref sourceBase, ref areaOrigin, 3u, 15u, areaStride);
}
/// <summary>
/// Copies a 4x4 reduced block into the destination buffer while doubling horizontally and quadrupling vertically.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x4Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
WidenRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 0u, 2u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 0u, 3u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 1u, 4u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 1u, 5u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 1u, 6u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 1u, 7u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 2u, 8u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 2u, 9u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 2u, 10u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 2u, 11u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 3u, 12u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 3u, 13u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 3u, 14u, areaStride);
WidenRow4(ref sourceBase, ref areaOrigin, 3u, 15u, areaStride);
}
/// <summary>
/// Copies a 4x4 reduced block into the destination buffer while quadrupling both axes.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x4Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
ExpandRow4(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 0u, 2u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 0u, 3u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 1u, 4u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 1u, 5u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 1u, 6u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 1u, 7u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 2u, 8u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 2u, 9u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 2u, 10u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 2u, 11u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 3u, 12u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 3u, 13u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 3u, 14u, areaStride);
ExpandRow4(ref sourceBase, ref areaOrigin, 3u, 15u, areaStride);
}
/// <summary>
/// Copies one four-sample row from the reduced block to the destination row.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyRow4(ref float sourceBase, ref float areaOrigin, nuint sourceRow, nuint destRow, uint areaStride)
{
ref float source = ref Unsafe.Add(ref sourceBase, sourceRow * 8u);
ref float dest = ref Unsafe.Add(ref areaOrigin, destRow * areaStride);
Unsafe.CopyBlock(
ref Unsafe.As<float, byte>(ref dest),
ref Unsafe.As<float, byte>(ref source),
4u * sizeof(float));
}
/// <summary>
/// Expands one four-sample row to eight samples by duplicating each source value horizontally.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void WidenRow4(ref float sourceBase, ref float areaOrigin, nuint sourceRow, nuint destRow, uint areaStride)
{
ref float source = ref Unsafe.Add(ref sourceBase, sourceRow * 8u);
ref float dest = ref Unsafe.Add(ref areaOrigin, destRow * areaStride);
float value0 = source;
float value1 = Unsafe.Add(ref source, 1u);
float value2 = Unsafe.Add(ref source, 2u);
float value3 = Unsafe.Add(ref source, 3u);
dest = value0;
Unsafe.Add(ref dest, 1u) = value0;
Unsafe.Add(ref dest, 2u) = value1;
Unsafe.Add(ref dest, 3u) = value1;
Unsafe.Add(ref dest, 4u) = value2;
Unsafe.Add(ref dest, 5u) = value2;
Unsafe.Add(ref dest, 6u) = value3;
Unsafe.Add(ref dest, 7u) = value3;
}
/// <summary>
/// Expands one four-sample row to sixteen samples by duplicating each source value four times horizontally.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void ExpandRow4(ref float sourceBase, ref float areaOrigin, nuint sourceRow, nuint destRow, uint areaStride)
{
ref float source = ref Unsafe.Add(ref sourceBase, sourceRow * 8u);
ref float dest = ref Unsafe.Add(ref areaOrigin, destRow * areaStride);
float value0 = source;
float value1 = Unsafe.Add(ref source, 1u);
float value2 = Unsafe.Add(ref source, 2u);
float value3 = Unsafe.Add(ref source, 3u);
dest = value0;
Unsafe.Add(ref dest, 1u) = value0;
Unsafe.Add(ref dest, 2u) = value0;
Unsafe.Add(ref dest, 3u) = value0;
Unsafe.Add(ref dest, 4u) = value1;
Unsafe.Add(ref dest, 5u) = value1;
Unsafe.Add(ref dest, 6u) = value1;
Unsafe.Add(ref dest, 7u) = value1;
Unsafe.Add(ref dest, 8u) = value2;
Unsafe.Add(ref dest, 9u) = value2;
Unsafe.Add(ref dest, 10u) = value2;
Unsafe.Add(ref dest, 11u) = value2;
Unsafe.Add(ref dest, 12u) = value3;
Unsafe.Add(ref dest, 13u) = value3;
Unsafe.Add(ref dest, 14u) = value3;
Unsafe.Add(ref dest, 15u) = value3;
}
/// <summary>
/// Replicates each reduced sample into an arbitrary integral expansion rectangle for uncommon subsampling ratios.
/// </summary>
[MethodImpl(InliningOptions.ColdPath)]
private static void CopyArbitraryScale(ref Block8x8F block, ref float areaOrigin, uint areaStride, uint horizontalScale, uint verticalScale)
{
for (nuint y = 0u; y < 4u; y++)
{
for (nuint y = 0; y < 4; y++)
nuint yy = y * verticalScale;
nuint y8 = y * 8u;
for (nuint x = 0u; x < 4u; x++)
{
nuint yy = y * verticalScale;
nuint y8 = y * 8;
nuint xx = x * horizontalScale;
for (nuint x = 0; x < 4; x++)
{
nuint xx = x * horizontalScale;
float value = block[y8 + x];
float value = block[y8 + x];
for (nuint i = 0u; i < verticalScale; i++)
{
nuint baseIdx = ((yy + i) * areaStride) + xx;
for (nuint i = 0; i < verticalScale; i++)
for (nuint j = 0u; j < horizontalScale; j++)
{
nuint baseIdx = ((yy + i) * areaStride) + xx;
for (nuint j = 0; j < horizontalScale; j++)
{
// area[xx + j, yy + i] = value;
Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
}
// area[xx + j, yy + i] = value;
Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
}
}
}

281
src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor4.cs

@ -66,32 +66,277 @@ internal sealed class DownScalingComponentProcessor4 : ComponentProcessor
[MethodImpl(InliningOptions.ShortMethod)]
public static void ScaledCopyTo(ref Block8x8F block, ref float destRef, int destStrideWidth, int horizontalScale, int verticalScale)
{
// TODO: Optimize: implement all cases with scale-specific, loopless code!
if (horizontalScale == 1 && verticalScale == 1)
{
CopyTo1x1Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 2 && verticalScale == 2)
{
CopyTo2x2Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 2 && verticalScale == 1)
{
CopyTo2x1Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 1 && verticalScale == 2)
{
CopyTo1x2Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 4 && verticalScale == 1)
{
CopyTo4x1Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 4 && verticalScale == 2)
{
CopyTo4x2Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 1 && verticalScale == 4)
{
CopyTo1x4Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 2 && verticalScale == 4)
{
CopyTo2x4Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 4 && verticalScale == 4)
{
CopyTo4x4Scale(ref block, ref destRef, (uint)destStrideWidth);
return;
}
// The common 1x, 2x, and 4x integral scales are specialized above.
// Uncommon legal factor-3 scales use the generic fallback.
CopyArbitraryScale(ref block, ref destRef, (uint)destStrideWidth, (uint)horizontalScale, (uint)verticalScale);
}
/// <summary>
/// Copies a 2x2 reduced block directly into the destination buffer when no chroma expansion is needed.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo1x1Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
CopyRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 1u, 1u, areaStride);
}
/// <summary>
/// Copies a 2x2 reduced block into the destination buffer while doubling only the horizontal axis.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x1Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
WidenRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 1u, 1u, areaStride);
}
/// <summary>
/// Copies a 2x2 reduced block into the destination buffer while doubling only the vertical axis.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo1x2Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
CopyRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 1u, 2u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 1u, 3u, areaStride);
}
/// <summary>
/// Copies a 2x2 reduced block into the destination buffer while doubling both axes.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x2Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
WidenRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 1u, 2u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 1u, 3u, areaStride);
}
[MethodImpl(InliningOptions.ColdPath)]
static void CopyArbitraryScale(ref Block8x8F block, ref float areaOrigin, uint areaStride, uint horizontalScale, uint verticalScale)
/// <summary>
/// Copies a 2x2 reduced block into the destination buffer while quadrupling only the horizontal axis.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x1Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
ExpandRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 1u, 1u, areaStride);
}
/// <summary>
/// Copies a 2x2 reduced block into the destination buffer while quadrupling horizontally and doubling vertically.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x2Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
ExpandRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 1u, 2u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 1u, 3u, areaStride);
}
/// <summary>
/// Copies a 2x2 reduced block into the destination buffer while quadrupling only the vertical axis.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo1x4Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
CopyRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 0u, 2u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 0u, 3u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 1u, 4u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 1u, 5u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 1u, 6u, areaStride);
CopyRow2(ref sourceBase, ref areaOrigin, 1u, 7u, areaStride);
}
/// <summary>
/// Copies a 2x2 reduced block into the destination buffer while doubling horizontally and quadrupling vertically.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x4Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
WidenRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 0u, 2u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 0u, 3u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 1u, 4u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 1u, 5u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 1u, 6u, areaStride);
WidenRow2(ref sourceBase, ref areaOrigin, 1u, 7u, areaStride);
}
/// <summary>
/// Copies a 2x2 reduced block into the destination buffer while quadrupling both axes.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x4Scale(ref Block8x8F block, ref float areaOrigin, uint areaStride)
{
ref float sourceBase = ref Unsafe.As<Block8x8F, float>(ref block);
ExpandRow2(ref sourceBase, ref areaOrigin, 0u, 0u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 0u, 1u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 0u, 2u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 0u, 3u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 1u, 4u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 1u, 5u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 1u, 6u, areaStride);
ExpandRow2(ref sourceBase, ref areaOrigin, 1u, 7u, areaStride);
}
/// <summary>
/// Copies one two-sample row from the reduced block to the destination row.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyRow2(ref float sourceBase, ref float areaOrigin, nuint sourceRow, nuint destRow, uint areaStride)
{
ref float source = ref Unsafe.Add(ref sourceBase, sourceRow * 8u);
ref float dest = ref Unsafe.Add(ref areaOrigin, destRow * areaStride);
Unsafe.CopyBlock(
ref Unsafe.As<float, byte>(ref dest),
ref Unsafe.As<float, byte>(ref source),
2u * sizeof(float));
}
/// <summary>
/// Expands one two-sample row to four samples by duplicating each source value horizontally.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void WidenRow2(ref float sourceBase, ref float areaOrigin, nuint sourceRow, nuint destRow, uint areaStride)
{
ref float source = ref Unsafe.Add(ref sourceBase, sourceRow * 8u);
ref float dest = ref Unsafe.Add(ref areaOrigin, destRow * areaStride);
float value0 = source;
float value1 = Unsafe.Add(ref source, 1u);
dest = value0;
Unsafe.Add(ref dest, 1u) = value0;
Unsafe.Add(ref dest, 2u) = value1;
Unsafe.Add(ref dest, 3u) = value1;
}
/// <summary>
/// Expands one two-sample row to eight samples by duplicating each source value four times horizontally.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void ExpandRow2(ref float sourceBase, ref float areaOrigin, nuint sourceRow, nuint destRow, uint areaStride)
{
ref float source = ref Unsafe.Add(ref sourceBase, sourceRow * 8u);
ref float dest = ref Unsafe.Add(ref areaOrigin, destRow * areaStride);
float value0 = source;
float value1 = Unsafe.Add(ref source, 1u);
dest = value0;
Unsafe.Add(ref dest, 1u) = value0;
Unsafe.Add(ref dest, 2u) = value0;
Unsafe.Add(ref dest, 3u) = value0;
Unsafe.Add(ref dest, 4u) = value1;
Unsafe.Add(ref dest, 5u) = value1;
Unsafe.Add(ref dest, 6u) = value1;
Unsafe.Add(ref dest, 7u) = value1;
}
/// <summary>
/// Replicates each reduced sample into an arbitrary integral expansion rectangle for uncommon subsampling ratios.
/// </summary>
[MethodImpl(InliningOptions.ColdPath)]
private static void CopyArbitraryScale(ref Block8x8F block, ref float areaOrigin, uint areaStride, uint horizontalScale, uint verticalScale)
{
for (nuint y = 0u; y < 2u; y++)
{
for (nuint y = 0; y < 2; y++)
nuint yy = y * verticalScale;
nuint y8 = y * 8u;
for (nuint x = 0u; x < 2u; x++)
{
nuint yy = y * verticalScale;
nuint y8 = y * 8;
nuint xx = x * horizontalScale;
for (nuint x = 0; x < 2; x++)
{
nuint xx = x * horizontalScale;
float value = block[y8 + x];
float value = block[y8 + x];
for (nuint i = 0u; i < verticalScale; i++)
{
nuint baseIdx = ((yy + i) * areaStride) + xx;
for (nuint i = 0; i < verticalScale; i++)
for (nuint j = 0u; j < horizontalScale; j++)
{
nuint baseIdx = ((yy + i) * areaStride) + xx;
for (nuint j = 0; j < horizontalScale; j++)
{
// area[xx + j, yy + i] = value;
Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
}
// area[xx + j, yy + i] = value;
Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
}
}
}

154
src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor8.cs

@ -63,16 +63,56 @@ internal sealed class DownScalingComponentProcessor8 : ComponentProcessor
return;
}
if (horizontalScale == 2 && verticalScale == 1)
{
CopyTo2x1Scale(value, ref destRef);
return;
}
if (horizontalScale == 1 && verticalScale == 2)
{
CopyTo1x2Scale(value, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 2 && verticalScale == 2)
{
destRef = value;
Unsafe.Add(ref destRef, 1) = value;
Unsafe.Add(ref destRef, 0 + (uint)destStrideWidth) = value;
Unsafe.Add(ref destRef, 1 + (uint)destStrideWidth) = value;
CopyTo2x2Scale(value, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 4 && verticalScale == 1)
{
CopyTo4x1Scale(value, ref destRef);
return;
}
if (horizontalScale == 4 && verticalScale == 2)
{
CopyTo4x2Scale(value, ref destRef, (uint)destStrideWidth);
return;
}
// TODO: Optimize: implement all cases with scale-specific, loopless code!
if (horizontalScale == 1 && verticalScale == 4)
{
CopyTo1x4Scale(value, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 2 && verticalScale == 4)
{
CopyTo2x4Scale(value, ref destRef, (uint)destStrideWidth);
return;
}
if (horizontalScale == 4 && verticalScale == 4)
{
CopyTo4x4Scale(value, ref destRef, (uint)destStrideWidth);
return;
}
// The common 1x, 2x, and 4x integral scales are specialized above.
// Uncommon legal factor-3 scales use the generic fallback.
for (nuint y = 0; y < (uint)verticalScale; y++)
{
for (nuint x = 0; x < (uint)horizontalScale; x++)
@ -83,4 +123,108 @@ internal sealed class DownScalingComponentProcessor8 : ComponentProcessor
destRef = ref Unsafe.Add(ref destRef, (uint)destStrideWidth);
}
}
/// <summary>
/// Writes a single source value to two horizontally adjacent samples.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x1Scale(float value, ref float areaOrigin)
{
areaOrigin = value;
Unsafe.Add(ref areaOrigin, 1u) = value;
}
/// <summary>
/// Writes a single source value to two vertically adjacent samples.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo1x2Scale(float value, ref float areaOrigin, uint areaStride)
{
areaOrigin = value;
Unsafe.Add(ref areaOrigin, areaStride) = value;
}
/// <summary>
/// Writes a single source value to a 2x2 rectangle.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x2Scale(float value, ref float areaOrigin, uint areaStride)
{
areaOrigin = value;
Unsafe.Add(ref areaOrigin, 1u) = value;
Unsafe.Add(ref areaOrigin, areaStride) = value;
Unsafe.Add(ref areaOrigin, areaStride + 1u) = value;
}
/// <summary>
/// Writes a single source value to four horizontally adjacent samples.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x1Scale(float value, ref float areaOrigin)
{
areaOrigin = value;
Unsafe.Add(ref areaOrigin, 1u) = value;
Unsafe.Add(ref areaOrigin, 2u) = value;
Unsafe.Add(ref areaOrigin, 3u) = value;
}
/// <summary>
/// Writes a single source value to a 4x2 rectangle.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x2Scale(float value, ref float areaOrigin, uint areaStride)
{
CopyTo4x1Scale(value, ref areaOrigin);
ref float nextRow = ref Unsafe.Add(ref areaOrigin, areaStride);
CopyTo4x1Scale(value, ref nextRow);
}
/// <summary>
/// Writes a single source value to four vertically adjacent samples.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo1x4Scale(float value, ref float areaOrigin, uint areaStride)
{
areaOrigin = value;
Unsafe.Add(ref areaOrigin, areaStride) = value;
Unsafe.Add(ref areaOrigin, areaStride * 2u) = value;
Unsafe.Add(ref areaOrigin, areaStride * 3u) = value;
}
/// <summary>
/// Writes a single source value to a 2x4 rectangle.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo2x4Scale(float value, ref float areaOrigin, uint areaStride)
{
CopyTo2x1Scale(value, ref areaOrigin);
ref float row1 = ref Unsafe.Add(ref areaOrigin, areaStride);
CopyTo2x1Scale(value, ref row1);
ref float row2 = ref Unsafe.Add(ref areaOrigin, areaStride * 2u);
CopyTo2x1Scale(value, ref row2);
ref float row3 = ref Unsafe.Add(ref areaOrigin, areaStride * 3u);
CopyTo2x1Scale(value, ref row3);
}
/// <summary>
/// Writes a single source value to a 4x4 rectangle.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static void CopyTo4x4Scale(float value, ref float areaOrigin, uint areaStride)
{
CopyTo4x1Scale(value, ref areaOrigin);
ref float row1 = ref Unsafe.Add(ref areaOrigin, areaStride);
CopyTo4x1Scale(value, ref row1);
ref float row2 = ref Unsafe.Add(ref areaOrigin, areaStride * 2u);
CopyTo4x1Scale(value, ref row2);
ref float row3 = ref Unsafe.Add(ref areaOrigin, areaStride * 3u);
CopyTo4x1Scale(value, ref row3);
}
}

Loading…
Cancel
Save