Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnetcore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
build-and-test:

name: build-and-test
runs-on: ubuntu-latest
runs-on: windows-latest

steps:
- uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions BCnEnc.Net/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("BCnEncTests")]
[assembly: InternalsVisibleTo("BCnEncTests.Framework")]
10 changes: 9 additions & 1 deletion BCnEnc.Net/BCnEncoder.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks>
<LangVersion>8.0</LangVersion>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
Expand Down Expand Up @@ -49,5 +50,12 @@ Supported formats are:
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="PolySharp" Version="1.15.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Bcl.Numerics" Version="10.0.3" />
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions BCnEnc.Net/Decoder/BcDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public Task<Memory2D<ColorRgba32>> Decode2DAsync(Stream inputStream, Cancellatio
/// <returns>The awaitable operation to retrieve the decoded image.</returns>
public Task<Memory2D<ColorRgba32>[]> DecodeAllMipMaps2DAsync(Stream inputStream, CancellationToken token = default)
{
return Task.Run(() => DecodeFromStreamInternal2D(inputStream, false, token), token);
return Task.Run(() => DecodeFromStreamInternal2D(inputStream, true, token), token);
}

/// <summary>
Expand Down Expand Up @@ -675,7 +675,7 @@ public Task<Memory2D<ColorRgbFloat>> DecodeHdr2DAsync(Stream inputStream, Cancel
/// <returns>The awaitable operation to retrieve the decoded image.</returns>
public Task<Memory2D<ColorRgbFloat>[]> DecodeAllMipMapsHdr2DAsync(Stream inputStream, CancellationToken token = default)
{
return Task.Run(() => DecodeFromStreamInternalHdr2D(inputStream, false, token), token);
return Task.Run(() => DecodeFromStreamInternalHdr2D(inputStream, true, token), token);
}

/// <summary>
Expand Down
55 changes: 41 additions & 14 deletions BCnEnc.Net/Encoder/Bptc/BptcEncodingHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
using System.Text;
using BCnEncoder.Shared;

#if NETSTANDARD2_0
using MemoryMarshal = BCnEncoder.Shared.MemoryMarshalPolyfills;
#endif

namespace BCnEncoder.Encoder.Bptc
{
internal static class BptcEncodingHelpers
Expand All @@ -20,7 +24,7 @@ public static int InterpolateInt(int e0, int e1, int index, int indexPrecision)
var aWeights2 = ColorInterpolationWeights2;
var aWeights3 = ColorInterpolationWeights3;
var aWeights4 = ColorInterpolationWeights4;

if (indexPrecision == 2)
return (((64 - aWeights2[index]) * e0 + aWeights2[index] * e1 + 32) >> 6);
if (indexPrecision == 3)
Expand Down Expand Up @@ -50,22 +54,33 @@ public static int[] Rank2SubsetPartitions(ClusterIndices4X4 reducedIndicesBlock,
{
var output = Enumerable.Range(0, smallIndex ? 32 : 64).ToArray();

// Copy struct to array before the closure so that reducedIndicesBlock is not
// heap-captured. On .NET Framework, MemoryMarshalPolyfills.CreateSpan uses
// Unsafe.AsPointer, which is only GC-safe for stack-allocated structs.
#if NETSTANDARD2_0
var indices = new int[16];
reducedIndicesBlock.AsSpan.CopyTo(indices);
#endif

int CalculatePartitionError(int partitionIndex)
{
{
#if NETSTANDARD2_1
var indices = reducedIndicesBlock.AsSpan;
#endif

var error = 0;
ReadOnlySpan<int> partitionTable = Bc7Block.Subsets2PartitionTable[partitionIndex];
Span<int> subset0 = stackalloc int[numDistinctClusters];
Span<int> subset1 = stackalloc int[numDistinctClusters];
var max0Idx = 0;
var max1Idx = 0;

//Calculate largest cluster index for each subset
//Calculate largest cluster index for each subset
for (var i = 0; i < 16; i++)
{
if (partitionTable[i] == 0)
{
var r = reducedIndicesBlock[i];
var r = indices[i];
subset0[r]++;
var count = subset0[r];
if (count > subset0[max0Idx])
Expand All @@ -75,7 +90,7 @@ int CalculatePartitionError(int partitionIndex)
}
else
{
var r = reducedIndicesBlock[i];
var r = indices[i];
subset1[r]++;
var count = subset1[r];
if (count > subset1[max1Idx])
Expand All @@ -90,11 +105,11 @@ int CalculatePartitionError(int partitionIndex)
{
if (partitionTable[i] == 0)
{
if (reducedIndicesBlock[i] != max0Idx) error++;
if (indices[i] != max0Idx) error++;
}
else
{
if (reducedIndicesBlock[i] != max1Idx) error++;
if (indices[i] != max1Idx) error++;
}
}

Expand All @@ -110,8 +125,20 @@ public static int[] Rank3SubsetPartitions(ClusterIndices4X4 reducedIndicesBlock,
{
var output = Enumerable.Range(0, 64).ToArray();

// Copy struct to array before the closure so that reducedIndicesBlock is not
// heap-captured. On .NET Framework, MemoryMarshalPolyfills.CreateSpan uses
// Unsafe.AsPointer, which is only GC-safe for stack-allocated structs.
#if NETSTANDARD2_0
var indices = new int[16];
reducedIndicesBlock.AsSpan.CopyTo(indices);
#endif

int CalculatePartitionError(int partitionIndex)
{
#if NETSTANDARD2_1
var indices = reducedIndicesBlock.AsSpan;
#endif

var error = 0;
ReadOnlySpan<int> partitionTable = Bc7Block.Subsets3PartitionTable[partitionIndex];

Expand All @@ -122,12 +149,12 @@ int CalculatePartitionError(int partitionIndex)
var max1Idx = 0;
var max2Idx = 0;

//Calculate largest cluster index for each subset
//Calculate largest cluster index for each subset
for (var i = 0; i < 16; i++)
{
if (partitionTable[i] == 0)
{
var r = reducedIndicesBlock[i];
var r = indices[i];
subset0[r]++;
var count = subset0[r];
if (count > subset0[max0Idx])
Expand All @@ -137,7 +164,7 @@ int CalculatePartitionError(int partitionIndex)
}
else if (partitionTable[i] == 1)
{
var r = reducedIndicesBlock[i];
var r = indices[i];
subset1[r]++;
var count = subset1[r];
if (count > subset1[max1Idx])
Expand All @@ -147,7 +174,7 @@ int CalculatePartitionError(int partitionIndex)
}
else
{
var r = reducedIndicesBlock[i];
var r = indices[i];
subset2[r]++;
var count = subset2[r];
if (count > subset2[max2Idx])
Expand All @@ -162,15 +189,15 @@ int CalculatePartitionError(int partitionIndex)
{
if (partitionTable[i] == 0)
{
if (reducedIndicesBlock[i] != max0Idx) error++;
if (indices[i] != max0Idx) error++;
}
else if (partitionTable[i] == 1)
{
if (reducedIndicesBlock[i] != max1Idx) error++;
if (indices[i] != max1Idx) error++;
}
else
{
if (reducedIndicesBlock[i] != max2Idx) error++;
if (indices[i] != max2Idx) error++;
}
}

Expand Down
4 changes: 4 additions & 0 deletions BCnEnc.Net/Encoder/LeastSquares.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
using BCnEncoder.Encoder.Bptc;
using BCnEncoder.Shared;

#if NETSTANDARD2_0
using Math = BCnEncoder.Shared.MathPolyfills;
#endif

namespace BCnEncoder.Encoder
{
/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion BCnEnc.Net/Shared/Colors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ public static ColorLab XyzToLab(ColorXyz xyz)

private static float PivotXyz(float n)
{
var i = MathF.Cbrt(n);
var i = MathCbrt.Cbrt(n);
return n > 0.008856f ? i : 7.787f * n + 16 / 116f;
}
}
Expand Down
2 changes: 1 addition & 1 deletion BCnEnc.Net/Shared/HdrImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private static string ReadFromStream(Stream stream)
c = (char)b;
buffer[i++] = c;
} while (c != (char)10);
return new string(buffer.AsSpan().Slice(0, i)).Trim();
return new string(buffer, 0, i).Trim();
}

private static void WriteLineToStream(BinaryWriter br, string s)
Expand Down
8 changes: 6 additions & 2 deletions BCnEnc.Net/Shared/LinearClustering.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using System;
using System.Collections.Generic;

#if NETSTANDARD2_0
using Array = BCnEncoder.Shared.ArrayPolyfills;
#endif

namespace BCnEncoder.Shared
{
/// <summary>
Expand Down Expand Up @@ -133,7 +137,7 @@
return ClusterPixels(floats, width, height, clusters, m, maxIterations, enforceConnectivity);

//Grid interval S
var s = MathF.Sqrt(pixels.Length / (float)clusters);

Check warning on line 140 in BCnEnc.Net/Shared/LinearClustering.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Unreachable code detected

Check warning on line 140 in BCnEnc.Net/Shared/LinearClustering.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Unreachable code detected
var clusterIndices = new int[pixels.Length];

var labXys = ConvertToLabXy(pixels, width, height);
Expand Down Expand Up @@ -194,7 +198,7 @@
if (enforceConnectivity) {
clusterIndices = EnforceConnectivity(clusterIndices, width, height, clusters);
}

return clusterIndices;
}

Expand Down Expand Up @@ -427,7 +431,7 @@
{
ReadOnlySpan<int> neighborX = new[] { -1, 0, 1, 0 };
ReadOnlySpan<int> neighborY = new[] { 0, -1, 0, 1 };

var sSquared = width * height / clusters;

var clusterX = new List<int>(sSquared);
Expand Down
18 changes: 8 additions & 10 deletions BCnEnc.Net/Shared/MipMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,14 @@ public static void CalculateMipLevelSize(int width, int height, int mipIdx, out
mipHeight = Math.Max(1, height >> mipIdx);
}

private static ColorRgba32[,] ResizeToHalf(ReadOnlySpan2D<ColorRgba32> pixelsRgba)
private static Memory2D<ColorRgba32> ResizeToHalf(ReadOnlySpan2D<ColorRgba32> pixelsRgba)
{

var oldWidth = pixelsRgba.Width;
var oldHeight = pixelsRgba.Height;
var newWidth = Math.Max(1, oldWidth >> 1);
var newHeight = Math.Max(1, oldHeight >> 1);

var result = new ColorRgba32[newHeight, newWidth];
var result = new ColorRgba32[newHeight * newWidth];

int ClampW(int x) => Math.Max(0, Math.Min(oldWidth - 1, x));
int ClampH(int y) => Math.Max(0, Math.Min(oldHeight - 1, y));
Expand All @@ -186,22 +185,21 @@ public static void CalculateMipLevelSize(int width, int height, int mipIdx, out
var ll = pixelsRgba[ClampH(y2 * 2 + 1), ClampW(x2 * 2)].ToFloat();
var lr = pixelsRgba[ClampH(y2 * 2 + 1), ClampW(x2 * 2 + 1)].ToFloat();

result[y2, x2] = ((ul + ur + ll + lr) / 4).ToRgba32();
result[y2 * newWidth + x2] = ((ul + ur + ll + lr) / 4).ToRgba32();
}
}

return result;
return ((Memory<ColorRgba32>)result).AsMemory2D(newHeight, newWidth);
}

private static ColorRgbFloat[,] ResizeToHalf(ReadOnlySpan2D<ColorRgbFloat> pixelsRgba)
private static Memory2D<ColorRgbFloat> ResizeToHalf(ReadOnlySpan2D<ColorRgbFloat> pixelsRgba)
{

var oldWidth = pixelsRgba.Width;
var oldHeight = pixelsRgba.Height;
var newWidth = Math.Max(1, oldWidth >> 1);
var newHeight = Math.Max(1, oldHeight >> 1);

var result = new ColorRgbFloat[newHeight, newWidth];
var result = new ColorRgbFloat[newHeight * newWidth];

int ClampW(int x) => Math.Max(0, Math.Min(oldWidth - 1, x));
int ClampH(int y) => Math.Max(0, Math.Min(oldHeight - 1, y));
Expand All @@ -215,11 +213,11 @@ public static void CalculateMipLevelSize(int width, int height, int mipIdx, out
var ll = pixelsRgba[ClampH(y2 * 2 + 1), ClampW(x2 * 2)];
var lr = pixelsRgba[ClampH(y2 * 2 + 1), ClampW(x2 * 2 + 1)];

result[y2, x2] = ((ul + ur + ll + lr) / 4);
result[y2 * newWidth + x2] = ((ul + ur + ll + lr) / 4);
}
}

return result;
return ((Memory<ColorRgbFloat>)result).AsMemory2D(newHeight, newWidth);
}
}
}
Loading
Loading