Skip to content

Commit 5953a2b

Browse files
committed
Use Span in EtcDecoder
* Resolves #58
1 parent 4b398e6 commit 5953a2b

2 files changed

Lines changed: 36 additions & 100 deletions

File tree

AssetRipper.TextureDecoder/AssetRipper.TextureDecoder.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
<PropertyGroup>
44
<IsTrimmable>true</IsTrimmable>
5-
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
65
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
76

87
<PackageId>AssetRipper.TextureDecoder</PackageId>

AssetRipper.TextureDecoder/Etc/EtcDecoder.cs

Lines changed: 36 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,14 @@ public static int DecompressETC(ReadOnlySpan<byte> input, int width, int height,
88
return DecompressETC(input, width, height, output);
99
}
1010

11-
public unsafe static int DecompressETC(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
11+
public static int DecompressETC(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
1212
{
1313
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
1414
if (input.Length < requiredLength)
1515
{
1616
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
1717
}
1818

19-
fixed (byte* outputPtr = output)
20-
{
21-
return DecompressETC(input, width, height, outputPtr);
22-
}
23-
}
24-
25-
private unsafe static int DecompressETC(ReadOnlySpan<byte> input, int width, int height, byte* output)
26-
{
2719
int bcw = (width + 3) / 4;
2820
int bch = (height + 3) / 4;
2921
int clen_last = (width + 3) % 4 + 1;
@@ -35,16 +27,15 @@ private unsafe static int DecompressETC(ReadOnlySpan<byte> input, int width, int
3527
{
3628
DecodeEtc1Block(input.Slice(inputOffset, 8), buf);
3729
int clen = s < bcw - 1 ? 4 : clen_last;
38-
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
39-
30+
int outputOffset = t * 16 * width + s * 16;
31+
Span<uint> outputPtr = MemoryMarshal.Cast<byte, uint>(output.Slice(outputOffset));
32+
4033
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
4134
{
4235
for (int j = 0; j < clen; j++)
4336
{
44-
outputPtr[j] = buf[j + 4 * i];
37+
outputPtr[j + i * width] = buf[j + 4 * i];
4538
}
46-
47-
outputPtr += width;
4839
}
4940
}
5041
}
@@ -57,22 +48,14 @@ public static int DecompressETC2(ReadOnlySpan<byte> input, int width, int height
5748
return DecompressETC2(input, width, height, output);
5849
}
5950

60-
public unsafe static int DecompressETC2(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
51+
public static int DecompressETC2(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
6152
{
6253
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
6354
if (input.Length < requiredLength)
6455
{
6556
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
6657
}
6758

68-
fixed (byte* outputPtr = output)
69-
{
70-
return DecompressETC2(input, width, height, outputPtr);
71-
}
72-
}
73-
74-
private unsafe static int DecompressETC2(ReadOnlySpan<byte> input, int width, int height, byte* output)
75-
{
7659
int bcw = (width + 3) / 4;
7760
int bch = (height + 3) / 4;
7861
int clen_last = (width + 3) % 4 + 1;
@@ -84,16 +67,15 @@ private unsafe static int DecompressETC2(ReadOnlySpan<byte> input, int width, in
8467
{
8568
DecodeEtc2Block(input.Slice(inputOffset, 8), buf);
8669
int clen = s < bcw - 1 ? 4 : clen_last;
87-
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
88-
70+
int outputOffset = t * 16 * width + s * 16;
71+
Span<uint> outputPtr = MemoryMarshal.Cast<byte, uint>(output.Slice(outputOffset));
72+
8973
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
9074
{
9175
for (int j = 0; j < clen; j++)
9276
{
93-
outputPtr[j] = buf[j + 4 * i];
77+
outputPtr[j + i * width] = buf[j + 4 * i];
9478
}
95-
96-
outputPtr += width;
9779
}
9880
}
9981
}
@@ -106,22 +88,14 @@ public static int DecompressETC2A1(ReadOnlySpan<byte> input, int width, int heig
10688
return DecompressETC2A1(input, width, height, output);
10789
}
10890

109-
public unsafe static int DecompressETC2A1(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
91+
public static int DecompressETC2A1(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
11092
{
11193
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
11294
if (input.Length < requiredLength)
11395
{
11496
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
11597
}
11698

117-
fixed (byte* outputPtr = output)
118-
{
119-
return DecompressETC2A1(input, width, height, outputPtr);
120-
}
121-
}
122-
123-
private unsafe static int DecompressETC2A1(ReadOnlySpan<byte> input, int width, int height, byte* output)
124-
{
12599
int bcw = (width + 3) / 4;
126100
int bch = (height + 3) / 4;
127101
int clen_last = (width + 3) % 4 + 1;
@@ -133,16 +107,15 @@ private unsafe static int DecompressETC2A1(ReadOnlySpan<byte> input, int width,
133107
{
134108
DecodeEtc2a1Block(input.Slice(inputOffset, 8), buf);
135109
int clen = s < bcw - 1 ? 4 : clen_last;
136-
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
137-
110+
int outputOffset = t * 16 * width + s * 16;
111+
Span<uint> outputPtr = MemoryMarshal.Cast<byte, uint>(output.Slice(outputOffset));
112+
138113
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
139114
{
140115
for (int j = 0; j < clen; j++)
141116
{
142-
outputPtr[j] = buf[j + 4 * i];
117+
outputPtr[j + i * width] = buf[j + 4 * i];
143118
}
144-
145-
outputPtr += width;
146119
}
147120
}
148121
}
@@ -155,22 +128,14 @@ public static int DecompressETC2A8(ReadOnlySpan<byte> input, int width, int heig
155128
return DecompressETC2A8(input, width, height, output);
156129
}
157130

158-
public unsafe static int DecompressETC2A8(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
131+
public static int DecompressETC2A8(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
159132
{
160133
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 16;
161134
if (input.Length < requiredLength)
162135
{
163136
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
164137
}
165138

166-
fixed (byte* outputPtr = output)
167-
{
168-
return DecompressETC2A8(input, width, height, outputPtr);
169-
}
170-
}
171-
172-
private unsafe static int DecompressETC2A8(ReadOnlySpan<byte> input, int width, int height, byte* output)
173-
{
174139
int bcw = (width + 3) / 4;
175140
int bch = (height + 3) / 4;
176141
int clen_last = (width + 3) % 4 + 1;
@@ -183,16 +148,15 @@ private unsafe static int DecompressETC2A8(ReadOnlySpan<byte> input, int width,
183148
DecodeEtc2Block(input.Slice(inputOffset + 8, 8), buf);
184149
DecodeEtc2a8Block(input.Slice(inputOffset + 0, 8), buf);
185150
int clen = s < bcw - 1 ? 4 : clen_last;
186-
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
187-
151+
int outputOffset = t * 16 * width + s * 16;
152+
Span<uint> outputPtr = MemoryMarshal.Cast<byte, uint>(output.Slice(outputOffset));
153+
188154
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
189155
{
190156
for (int j = 0; j < clen; j++)
191157
{
192-
outputPtr[j] = buf[j + 4 * i];
158+
outputPtr[j + i * width] = buf[j + 4 * i];
193159
}
194-
195-
outputPtr += width;
196160
}
197161
}
198162
}
@@ -205,22 +169,14 @@ public static int DecompressEACRUnsigned(ReadOnlySpan<byte> input, int width, in
205169
return DecompressEACRUnsigned(input, width, height, output);
206170
}
207171

208-
public unsafe static int DecompressEACRUnsigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
172+
public static int DecompressEACRUnsigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
209173
{
210174
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
211175
if (input.Length < requiredLength)
212176
{
213177
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
214178
}
215179

216-
fixed (byte* outputPtr = output)
217-
{
218-
return DecompressEACRUnsigned(input, width, height, outputPtr);
219-
}
220-
}
221-
222-
private unsafe static int DecompressEACRUnsigned(ReadOnlySpan<byte> input, int width, int height, byte* output)
223-
{
224180
int bcw = (width + 3) / 4;
225181
int bch = (height + 3) / 4;
226182
int clen_last = (width + 3) % 4 + 1;
@@ -236,16 +192,15 @@ private unsafe static int DecompressEACRUnsigned(ReadOnlySpan<byte> input, int w
236192
{
237193
DecodeEacUnsignedBlock(input.Slice(inputOffset, 8), buf, 2);
238194
int clen = s < bcw - 1 ? 4 : clen_last;
239-
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
240-
195+
int outputOffset = t * 16 * width + s * 16;
196+
Span<uint> outputPtr = MemoryMarshal.Cast<byte, uint>(output.Slice(outputOffset));
197+
241198
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
242199
{
243200
for (int j = 0; j < clen; j++)
244201
{
245-
outputPtr[j] = buf[j + 4 * i];
202+
outputPtr[j + i * width] = buf[j + 4 * i];
246203
}
247-
248-
outputPtr += width;
249204
}
250205
}
251206
}
@@ -258,22 +213,14 @@ public static int DecompressEACRSigned(ReadOnlySpan<byte> input, int width, int
258213
return DecompressEACRSigned(input, width, height, output);
259214
}
260215

261-
public unsafe static int DecompressEACRSigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
216+
public static int DecompressEACRSigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
262217
{
263218
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
264219
if (input.Length < requiredLength)
265220
{
266221
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
267222
}
268223

269-
fixed (byte* outputPtr = output)
270-
{
271-
return DecompressEACRSigned(input, width, height, outputPtr);
272-
}
273-
}
274-
275-
private unsafe static int DecompressEACRSigned(ReadOnlySpan<byte> input, int width, int height, byte* output)
276-
{
277224
int bcw = (width + 3) / 4;
278225
int bch = (height + 3) / 4;
279226
int clen_last = (width + 3) % 4 + 1;
@@ -289,16 +236,15 @@ private unsafe static int DecompressEACRSigned(ReadOnlySpan<byte> input, int wid
289236
{
290237
DecodeEacSignedBlock(input.Slice(inputOffset, 8), buf, 2);
291238
int clen = s < bcw - 1 ? 4 : clen_last;
292-
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
293-
239+
int outputOffset = t * 16 * width + s * 16;
240+
Span<uint> outputPtr = MemoryMarshal.Cast<byte, uint>(output.Slice(outputOffset));
241+
294242
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
295243
{
296244
for (int j = 0; j < clen; j++)
297245
{
298-
outputPtr[j] = buf[j + 4 * i];
246+
outputPtr[j + i * width] = buf[j + 4 * i];
299247
}
300-
301-
outputPtr += width;
302248
}
303249
}
304250
}
@@ -311,7 +257,7 @@ public static int DecompressEACRGUnsigned(ReadOnlySpan<byte> input, int width, i
311257
return DecompressEACRGUnsigned(input, width, height, output);
312258
}
313259

314-
public unsafe static int DecompressEACRGUnsigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
260+
public static int DecompressEACRGUnsigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
315261
{
316262
int bcw = (width + 3) / 4;
317263
int bch = (height + 3) / 4;
@@ -356,22 +302,14 @@ public static int DecompressEACRGSigned(ReadOnlySpan<byte> input, int width, int
356302
return DecompressEACRGSigned(input, width, height, output);
357303
}
358304

359-
public unsafe static int DecompressEACRGSigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
305+
public static int DecompressEACRGSigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
360306
{
361307
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 16;
362308
if (input.Length < requiredLength)
363309
{
364310
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
365311
}
366312

367-
fixed (byte* outputPtr = output)
368-
{
369-
return DecompressEACRGSigned(input, width, height, outputPtr);
370-
}
371-
}
372-
373-
private unsafe static int DecompressEACRGSigned(ReadOnlySpan<byte> input, int width, int height, byte* output)
374-
{
375313
int bcw = (width + 3) / 4;
376314
int bch = (height + 3) / 4;
377315
int clen_last = (width + 3) % 4 + 1;
@@ -388,16 +326,15 @@ private unsafe static int DecompressEACRGSigned(ReadOnlySpan<byte> input, int wi
388326
DecodeEacSignedBlock(input.Slice(inputOffset + 0, 8), buf, 2);
389327
DecodeEacSignedBlock(input.Slice(inputOffset + 8, 8), buf, 1);
390328
int clen = s < bcw - 1 ? 4 : clen_last;
391-
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
392-
329+
int outputOffset = t * 16 * width + s * 16;
330+
Span<uint> outputPtr = MemoryMarshal.Cast<byte, uint>(output.Slice(outputOffset));
331+
393332
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
394333
{
395334
for (int j = 0; j < clen; j++)
396335
{
397-
outputPtr[j] = buf[j + 4 * i];
336+
outputPtr[j + i * width] = buf[j + 4 * i];
398337
}
399-
400-
outputPtr += width;
401338
}
402339
}
403340
}

0 commit comments

Comments
 (0)