Skip to content

Commit

Permalink
Corrected logic in HuffmanScan to Emit bytes. (Decoding still is inco…
Browse files Browse the repository at this point in the history
…rrect).

Add more BitReader tests
Correct logic in BitReader to throw when writing more than 64 bits of a 64 bit value.

More work in JpegState for encoding and decoding, closer to having something working but not quite there yet...

Block.CopyScaled
  • Loading branch information
juliusfriedman committed Nov 1, 2024
1 parent 514b74a commit e0d5847
Show file tree
Hide file tree
Showing 8 changed files with 581 additions and 96 deletions.
152 changes: 152 additions & 0 deletions Codecs/Image/Jpeg/Classes/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1413,4 +1413,156 @@ public override int GetHashCode()
}

#endregion

#region ScaledCopy

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ScaledCopyFrom(ref float areaOrigin, int areaStride) =>
CopyFrom1x1Scale(ref Unsafe.As<float, byte>(ref areaOrigin), ref Array[Offset], areaStride);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ScaledCopyTo(ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale)
{
if (horizontalScale == 1 && verticalScale == 1)
{
CopyTo1x1Scale(ref Array[Offset], ref Unsafe.As<float, byte>(ref areaOrigin), areaStride);
return;
}

if (horizontalScale == 2 && verticalScale == 2)
{
CopyTo2x2Scale(ref areaOrigin, areaStride);
return;
}

// TODO: Optimize: implement all cases with scale-specific, loopless code!
CopyArbitraryScale(ref areaOrigin, (uint)areaStride, (uint)horizontalScale, (uint)verticalScale);
}

private void CopyTo2x2Scale(ref float areaOrigin, int areaStride)
{
ref Vector2 destBase = ref Unsafe.As<float, Vector2>(ref areaOrigin);
nuint destStride = (uint)areaStride / 2;

var vector = V0L;

WidenCopyRowImpl2x2(ref vector, ref destBase, 0, destStride);
WidenCopyRowImpl2x2(ref vector, ref destBase, 1, destStride);
WidenCopyRowImpl2x2(ref vector, ref destBase, 2, destStride);
WidenCopyRowImpl2x2(ref vector, ref destBase, 3, destStride);
WidenCopyRowImpl2x2(ref vector, ref destBase, 4, destStride);
WidenCopyRowImpl2x2(ref vector, ref destBase, 5, destStride);
WidenCopyRowImpl2x2(ref vector, ref destBase, 6, destStride);
WidenCopyRowImpl2x2(ref vector, ref destBase, 7, destStride);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void WidenCopyRowImpl2x2(ref Vector4 selfBase, ref Vector2 destBase, nuint row, nuint destStride)
{
ref Vector4 sLeft = ref Unsafe.Add(ref selfBase, 2 * row);
ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1);

nuint offset = 2 * row * destStride;
ref Vector4 dTopLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset));
ref Vector4 dBottomLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset + destStride));

var xyLeft = new Vector4(sLeft.X);
xyLeft.Z = sLeft.Y;
xyLeft.W = sLeft.Y;

var zwLeft = new Vector4(sLeft.Z);
zwLeft.Z = sLeft.W;
zwLeft.W = sLeft.W;

var xyRight = new Vector4(sRight.X);
xyRight.Z = sRight.Y;
xyRight.W = sRight.Y;

var zwRight = new Vector4(sRight.Z);
zwRight.Z = sRight.W;
zwRight.W = sRight.W;

dTopLeft = xyLeft;
Unsafe.Add(ref dTopLeft, 1) = zwLeft;
Unsafe.Add(ref dTopLeft, 2) = xyRight;
Unsafe.Add(ref dTopLeft, 3) = zwRight;

dBottomLeft = xyLeft;
Unsafe.Add(ref dBottomLeft, 1) = zwLeft;
Unsafe.Add(ref dBottomLeft, 2) = xyRight;
Unsafe.Add(ref dBottomLeft, 3) = zwRight;
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyArbitraryScale(ref float areaOrigin, uint areaStride, uint horizontalScale, uint verticalScale)
{
for (nuint y = 0; y < 8; y++)
{
nuint yy = y * verticalScale;
nuint y8 = y * 8;

for (nuint x = 0; x < 8; x++)
{
nuint xx = x * horizontalScale;

float value = this[(int)(y8 + x)];
nuint baseIdx = (yy * areaStride) + xx;

for (nuint i = 0; i < verticalScale; i++, baseIdx += areaStride)
{
for (nuint j = 0; j < horizontalScale; j++)
{
// area[xx + j, yy + i] = value;
Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
}
}
}
}
}

private static void CopyTo1x1Scale(ref byte origin, ref byte dest, int areaStride)
{
int destStride = areaStride * sizeof(float);

CopyRowImpl(ref origin, ref dest, destStride, 0);
CopyRowImpl(ref origin, ref dest, destStride, 1);
CopyRowImpl(ref origin, ref dest, destStride, 2);
CopyRowImpl(ref origin, ref dest, destStride, 3);
CopyRowImpl(ref origin, ref dest, destStride, 4);
CopyRowImpl(ref origin, ref dest, destStride, 5);
CopyRowImpl(ref origin, ref dest, destStride, 6);
CopyRowImpl(ref origin, ref dest, destStride, 7);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void CopyRowImpl(ref byte origin, ref byte dest, int destStride, int row)
{
origin = ref Unsafe.Add(ref origin, (uint)row * 8 * sizeof(float));
dest = ref Unsafe.Add(ref dest, (uint)(row * destStride));
Unsafe.CopyBlock(ref dest, ref origin, 8 * sizeof(float));
}
}

private static void CopyFrom1x1Scale(ref byte origin, ref byte dest, int areaStride)
{
int destStride = areaStride * sizeof(float);

CopyRowImpl(ref origin, ref dest, destStride, 0);
CopyRowImpl(ref origin, ref dest, destStride, 1);
CopyRowImpl(ref origin, ref dest, destStride, 2);
CopyRowImpl(ref origin, ref dest, destStride, 3);
CopyRowImpl(ref origin, ref dest, destStride, 4);
CopyRowImpl(ref origin, ref dest, destStride, 5);
CopyRowImpl(ref origin, ref dest, destStride, 6);
CopyRowImpl(ref origin, ref dest, destStride, 7);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void CopyRowImpl(ref byte origin, ref byte dest, int sourceStride, int row)
{
origin = ref Unsafe.Add(ref origin, (uint)(row * sourceStride));
dest = ref Unsafe.Add(ref dest, (uint)row * 8 * sizeof(float));
Unsafe.CopyBlock(ref dest, ref origin, 8 * sizeof(float));
}
}

#endregion
}
Loading

0 comments on commit e0d5847

Please sign in to comment.