Skip to content

Commit 1861783

Browse files
author
github-actions
committed
Merge branch 'release/3.3.2'
2 parents 80efff6 + 8888580 commit 1861783

11 files changed

+440
-164
lines changed

src/PiWeb.Volume/Block/BlockInfo.cs

+5-6
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,13 @@ internal readonly record struct BlockInfo( ushort ValueCount, bool IsFirstValueS
5555
#region methods
5656

5757
/// <summary>
58-
/// Reads the <see cref="BlockInfo"/> from the specified <paramref name="reader"/>.
58+
/// Reads the <see cref="BlockInfo"/> from the specified <paramref name="value"/>.
5959
/// </summary>
60-
public static BlockInfo Read( BinaryReader reader )
60+
public static BlockInfo Create( ushort value )
6161
{
62-
var resultLength = reader.ReadUInt16();
63-
var valueCount = resultLength & ValueCountMask;
64-
var isFirstValueShort = ( resultLength & IsFirstValueShortMask ) >> IsFirstValueShortOffset;
65-
var areOtherValuesShort = ( resultLength & AreOtherValuesShortMask ) >> AreOtherValuesShortOffset;
62+
var valueCount = value & ValueCountMask;
63+
var isFirstValueShort = ( value & IsFirstValueShortMask ) >> IsFirstValueShortOffset;
64+
var areOtherValuesShort = ( value & AreOtherValuesShortMask ) >> AreOtherValuesShortOffset;
6665

6766
return new BlockInfo( (ushort)valueCount, isFirstValueShort > 0, areOtherValuesShort > 0 );
6867
}

src/PiWeb.Volume/Block/BlockVolume.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ public override void GetSlice(
190190
CancellationToken ct = default )
191191
{
192192
var sw = Stopwatch.StartNew();
193-
var sliceRangeCollector = new BlockVolumeSliceRangeCollector( this, slice, buffer );
194-
sliceRangeCollector.CollectSliceRanges( progress, ct );
193+
var sliceCollector = new BlockVolumeSliceCollector( this, slice, buffer );
194+
sliceCollector.CollectSlice( progress, ct );
195195

196196
logger?.Log( LogLevel.Info, $"Extracted '{slice}' in {sw.ElapsedMilliseconds} ms." );
197197
}

src/PiWeb.Volume/Block/BlockVolumeDecoder.cs

+87-56
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace Zeiss.PiWeb.Volume.Block;
1515

1616
using System;
1717
using System.Buffers;
18-
using System.IO;
1918
using System.Runtime.InteropServices;
19+
using System.Runtime.Intrinsics;
2020
using System.Threading;
2121
using System.Threading.Tasks;
2222

@@ -41,37 +41,49 @@ internal static void Decode( byte[] data,
4141
IProgress<VolumeSliceDefinition>? progress = null,
4242
CancellationToken ct = default )
4343
{
44-
var reader = new BinaryReader( new MemoryStream( data ) );
45-
var (_, sizeX, sizeY, sizeZ, quantization) = BlockVolumeMetaData.Read( reader );
44+
var header = BlockVolumeMetaData.Create( data );
45+
var (_, sizeX, sizeY, sizeZ, quantization) = header;
4646
var (bcx, bcy, bcz) = BlockVolume.GetBlockCount( sizeX, sizeY, sizeZ );
4747
var blockCount = bcx * bcy;
4848
var encodedBlockInfos = new EncodedBlockInfo[ blockCount ];
49+
var position = BlockVolumeMetaData.HeaderLength;
50+
var dataSpan = data.AsSpan();
51+
52+
Quantization.Invert( quantization );
4953

5054
for( ushort biz = 0; biz < bcz; biz++ )
5155
{
5256
ct.ThrowIfCancellationRequested();
5357

54-
var layerLength = reader.ReadInt32();
58+
var layerLength = MemoryMarshal.Read<int>( dataSpan.Slice( position, sizeof( int ) ) );
59+
position += sizeof( int );
5560
if( layerPredicate?.Invoke( biz ) is false )
5661
{
57-
reader.BaseStream.Seek( layerLength, SeekOrigin.Current );
62+
position += layerLength;
5863
continue;
5964
}
6065

61-
ReadBlockInfos( reader, blockCount, encodedBlockInfos );
66+
ReadLayer( dataSpan, position, blockCount, encodedBlockInfos );
6267
DecodeLayer( data, encodedBlockInfos, bcx, bcy, biz, quantization, blockPredicate, blockAction );
6368

6469
progress?.Report( new VolumeSliceDefinition( Direction.Z, (ushort)( biz * BlockVolume.N ) ) );
70+
71+
position += layerLength;
6572
}
6673
}
6774

68-
private static void ReadBlockInfos( BinaryReader reader, int blockCount, EncodedBlockInfo[] encodedBlockInfos )
75+
private static void ReadLayer( ReadOnlySpan<byte> dataSpan, int position, int blockCount, EncodedBlockInfo[] encodedBlockInfos )
6976
{
7077
for( var i = 0; i < blockCount; i++ )
7178
{
72-
var encodedBlockInfo = EncodedBlockInfo.Read( reader );
73-
reader.BaseStream.Seek( encodedBlockInfo.Info.Length, SeekOrigin.Current );
79+
var value = MemoryMarshal.Read<ushort>( dataSpan[ position.. ] );
80+
81+
position += sizeof( ushort );
82+
83+
var encodedBlockInfo = new EncodedBlockInfo( position, BlockInfo.Create( value ) );
7484
encodedBlockInfos[ i ] = encodedBlockInfo;
85+
86+
position += encodedBlockInfo.Info.Length;
7587
}
7688
}
7789

@@ -85,50 +97,71 @@ private static void DecodeLayer(
8597
BlockPredicate? blockPredicate,
8698
BlockAction blockAction )
8799
{
88-
Parallel.For( 0, blockCountX * blockCountY, () => (
89-
ArrayPool<double>.Shared.Rent( BlockVolume.N3 ),
90-
ArrayPool<double>.Shared.Rent( BlockVolume.N3 ),
91-
ArrayPool<byte>.Shared.Rent( BlockVolume.N3 )
92-
), ( index, _, buffers ) =>
93-
{
94-
var blockIndexX = index % blockCountX;
95-
var blockIndexY = index / blockCountX;
96-
var blockIndex = new BlockIndex( (ushort)blockIndexX, (ushort)blockIndexY, blockIndexZ );
100+
#if DEBUG
101+
var buffers = new DecodingBuffers();
102+
for( var index = 0; index < blockCountX * blockCountY; index++ )
103+
{
104+
#else
105+
Parallel.For( 0, blockCountX * blockCountY, () => new DecodingBuffers(), ( index, _, buffers ) =>
106+
{
107+
#endif
108+
var blockIndexX = index % blockCountX;
109+
var blockIndexY = index / blockCountX;
110+
var blockIndex = new BlockIndex( (ushort)blockIndexX, (ushort)blockIndexY, blockIndexZ );
97111

98-
if( blockPredicate?.Invoke( blockIndex ) == false )
99-
return buffers;
112+
if( blockPredicate?.Invoke( blockIndex ) == false )
113+
#if DEBUG
114+
continue;
115+
#else
116+
return buffers;
117+
#endif
100118

101-
var doubleBuffer1 = buffers.Item1.AsSpan( 0, BlockVolume.N3 );
102-
var doubleBuffer2 = buffers.Item2.AsSpan( 0, BlockVolume.N3 );
103-
var byteBuffer = buffers.Item3.AsSpan( 0, BlockVolume.N3 );
104-
var encodedBlockInfo = encodedBlockInfos[ index ];
119+
var inputSpan = buffers.InputBuffer.AsSpan( 0, BlockVolume.N3 );
120+
var outputSpan = buffers.OutputBuffer.AsSpan( 0, BlockVolume.N3 );
121+
var resultSpan = buffers.ResultBuffer.AsSpan( 0, BlockVolume.N3 );
122+
var encodedBlockInfo = encodedBlockInfos[ index ];
105123

106-
//1. Dediscretization
107-
ReadBlock( encodedBlocks.AsSpan(), encodedBlockInfo, doubleBuffer1 );
124+
//1. Dediscretization
125+
ReadBlock( encodedBlocks.AsSpan(), encodedBlockInfo, inputSpan );
108126

109-
//2. ZigZag
110-
ZigZag.Reverse( doubleBuffer1, doubleBuffer2 );
127+
//2. ZigZag
128+
ZigZag.Reverse( inputSpan, outputSpan );
111129

112-
//3. Quantization
113-
Quantization.Apply( quantization.AsSpan(), doubleBuffer2 );
130+
var nonEmptyVectors = FindNonEmptyVectors( outputSpan );
114131

115-
//4. Cosine transform
116-
DiscreteCosineTransform.Transform( doubleBuffer2, doubleBuffer1, true );
132+
//3. Quantization
133+
Quantization.Apply( quantization.AsSpan(), outputSpan );
117134

118-
//5. Discretization
119-
for( var i = 0; i < BlockVolume.N3; i++ )
120-
byteBuffer[ i ] = (byte)Math.Clamp( doubleBuffer1[ i ], byte.MinValue, byte.MaxValue );
135+
//4. Cosine transform
136+
DiscreteCosineTransform.Transform( outputSpan, inputSpan, true, nonEmptyVectors );
121137

122-
blockAction( byteBuffer, blockIndex );
138+
//5. Discretization
139+
for( var i = 0; i < BlockVolume.N3; i++ )
140+
resultSpan[ i ] = (byte)Math.Clamp( inputSpan[ i ], byte.MinValue, byte.MaxValue );
123141

124-
return buffers;
125-
},
126-
buffers =>
127-
{
128-
ArrayPool<double>.Shared.Return( buffers.Item1 );
129-
ArrayPool<double>.Shared.Return( buffers.Item2 );
130-
ArrayPool<byte>.Shared.Return( buffers.Item3 );
131-
} );
142+
blockAction( resultSpan, blockIndex );
143+
#if DEBUG
144+
}
145+
146+
buffers.Return();
147+
#else
148+
return buffers;
149+
}, buffers => buffers.Return() );
150+
#endif
151+
}
152+
153+
private static ulong FindNonEmptyVectors( Span<double> values )
154+
{
155+
var vectors = MemoryMarshal.Cast<double, Vector512<double>>( values );
156+
var result = 0UL;
157+
158+
for( ushort i = 0; i < BlockVolume.N2; i++ )
159+
{
160+
if( Vector512.Sum( Vector512.Abs( vectors[ i ] ) ) > 1e-12 )
161+
result |= 1UL << i;
162+
}
163+
164+
return result;
132165
}
133166

134167
private static void ReadBlock( ReadOnlySpan<byte> data, EncodedBlockInfo blockInfo, Span<double> result )
@@ -167,24 +200,22 @@ private static void ReadBlock( ReadOnlySpan<byte> data, EncodedBlockInfo blockIn
167200

168201
#endregion
169202

170-
private readonly record struct EncodedBlockInfo( int StartIndex, BlockInfo Info )
203+
private readonly struct DecodingBuffers()
171204
{
172-
#region methods
205+
public double[] InputBuffer { get; } = ArrayPool<double>.Shared.Rent( BlockVolume.N3 );
206+
public double[] OutputBuffer { get; } = ArrayPool<double>.Shared.Rent( BlockVolume.N3 );
207+
public byte[] ResultBuffer { get; } = ArrayPool<byte>.Shared.Rent( BlockVolume.N3 );
173208

174-
/// <summary>
175-
/// Reads the encoded block info from the specified <paramref name="reader"/>
176-
/// </summary>
177-
public static EncodedBlockInfo Read( BinaryReader reader )
209+
public void Return()
178210
{
179-
var info = BlockInfo.Read( reader );
180-
var startIndex = (int)reader.BaseStream.Position;
181-
182-
return new EncodedBlockInfo( startIndex, info );
211+
ArrayPool<double>.Shared.Return( InputBuffer );
212+
ArrayPool<double>.Shared.Return( OutputBuffer );
213+
ArrayPool<byte>.Shared.Return( ResultBuffer );
183214
}
184-
185-
#endregion
186215
}
187216

217+
private readonly record struct EncodedBlockInfo( int StartIndex, BlockInfo Info );
218+
188219
internal delegate void BlockAction( ReadOnlySpan<byte> data, BlockIndex index );
189220

190221
internal delegate bool BlockPredicate( BlockIndex index );

src/PiWeb.Volume/Block/BlockVolumeDecompressor.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,13 @@ private void CopyBlockToResult( ReadOnlySpan<byte> block, BlockIndex index )
7979
for( var bz = 0; bz < sz; bz++ )
8080
{
8181
var gz = index.Z * BlockVolume.N + bz;
82+
var oz = bz * BlockVolume.N2;
8283
var sliceData = _Result[ gz ].AsSpan();
8384

8485
for( var by = 0; by < sy; by++ )
8586
{
8687
var gy = index.Y * BlockVolume.N + by;
87-
block.Slice( bz * BlockVolume.N2 + by * BlockVolume.N, sx ).CopyTo( sliceData.Slice( gy * _SizeX + gx, sx ) );
88+
block.Slice( oz + by * BlockVolume.N, sx ).CopyTo( sliceData.Slice( gy * _SizeX + gx, sx ) );
8889
}
8990
}
9091
}

src/PiWeb.Volume/Block/BlockVolumeMetaData.cs

+22-10
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ namespace Zeiss.PiWeb.Volume.Block;
1414

1515
using System;
1616
using System.IO;
17+
using System.Runtime.InteropServices;
1718

1819
#endregion
1920

2021
/// <summary>
2122
/// Holds information that are needed to encode and decode a block volume.
2223
/// </summary>
23-
public readonly record struct BlockVolumeMetaData( uint Version, ushort SizeX, ushort SizeY, ushort SizeZ, double[] Quantization )
24+
public record BlockVolumeMetaData( uint Version, ushort SizeX, ushort SizeY, ushort SizeZ, double[] Quantization )
2425
{
2526
#region methods
2627

@@ -40,26 +41,37 @@ public void Write( BinaryWriter writer )
4041
}
4142

4243
/// <summary>
43-
/// Reads the metadata from the specified <paramref name="reader"/>
44+
/// Reads the metadata from the specified <paramref name="data"/>
4445
/// </summary>
45-
public static BlockVolumeMetaData Read( BinaryReader reader )
46+
public static BlockVolumeMetaData Create( ReadOnlySpan<byte> data )
4647
{
47-
var header = reader.ReadUInt32();
48+
var position = 0;
49+
var header = MemoryMarshal.Read<uint>( data[ position.. ] );
50+
position += sizeof( uint );
4851
if( header != BlockVolume.FileHeader )
4952
throw new FormatException( $"Encountered unexpected file header 0x{header:x8}, expected 0x{BlockVolume.FileHeader:x8}" );
5053

51-
var version = reader.ReadUInt32();
54+
var version = MemoryMarshal.Read<uint>( data[ position.. ] );
55+
position += sizeof( uint );
5256
if( version != BlockVolume.Version )
5357
throw new FormatException( $"Encountered unexpected file header '{version}', expected {BlockVolume.Version}" );
5458

55-
var sizeX = reader.ReadUInt16();
56-
var sizeY = reader.ReadUInt16();
57-
var sizeZ = reader.ReadUInt16();
59+
var sizeX = MemoryMarshal.Read<ushort>( data[ position.. ] );
60+
position += sizeof( ushort );
61+
var sizeY = MemoryMarshal.Read<ushort>( data[ position.. ] );
62+
position += sizeof( ushort );
63+
var sizeZ = MemoryMarshal.Read<ushort>( data[ position.. ] );
64+
position += sizeof( ushort );
5865

59-
var quantization = Block.Quantization.Read( reader, true );
66+
var quantization = MemoryMarshal.Cast<byte, double>( data.Slice( position, BlockVolume.N3 * sizeof( double ) ) );
6067

61-
return new BlockVolumeMetaData( version, sizeX, sizeY, sizeZ, quantization );
68+
return new BlockVolumeMetaData( version, sizeX, sizeY, sizeZ, quantization.ToArray() );
6269
}
6370

6471
#endregion
72+
73+
/// <summary>
74+
/// The number of bytes the header consists of.
75+
/// </summary>
76+
public static int HeaderLength => 2 * sizeof( uint ) + 3 * sizeof( ushort ) + BlockVolume.N3 * sizeof( double );
6577
}

0 commit comments

Comments
 (0)