Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
cb9527f
fix(cmp_texture): lock the marshaling of CMP_Texture
ProbablePrime Jul 18, 2025
d6b07b6
chore(style): uneeded usings
ProbablePrime Jul 18, 2025
2946ae8
feat(mipset): add a copy from fn
ProbablePrime Jul 18, 2025
80e8f6f
tweak(CMP_ConverTexture): tweak usage of options ptr
ProbablePrime Jul 18, 2025
e3132ce
feat(mips): expose CMP_MipSetToTexture from native
ProbablePrime Jul 18, 2025
cbb0dcc
fix(initialize): only initialize once
ProbablePrime Jul 18, 2025
9063d88
feat(savetexture): expose save_texture variant that actually takes a …
ProbablePrime Jul 19, 2025
f6c6e74
feat(harness): some tweaks to make the test utilities easier to operate.
ProbablePrime Jul 19, 2025
515fdc3
fix(tests): fix test images link
ProbablePrime Jul 19, 2025
9af0a70
fix(tests): add CompressDecompress test.
ProbablePrime Jul 19, 2025
037dc2d
fixup!: roundtrip snapshot file
ProbablePrime Jul 19, 2025
67511db
feat(tests): Add a HUGE Amount of tests and snapshots and scoring.
ProbablePrime Jul 20, 2025
4de2c22
feat(tests): tweak CI for tests.
ProbablePrime Jul 20, 2025
c30d245
fix(tests): adjust filter to be opt-in
ProbablePrime Jul 20, 2025
94c5fee
fix(cmp_mipset): Prevent Access Violations when CMP_MipSet is dispose…
ProbablePrime Jul 20, 2025
9dceae1
fix(ci): lower quality exlusion rules so tests dont take 3 years in CI
ProbablePrime Jul 20, 2025
d506311
fix(tests): further tweak tests to maybe not take 3 years
ProbablePrime Jul 20, 2025
af20af6
fix(ci): further simplify stuff
ProbablePrime Jul 20, 2025
14b69ff
fix(ci): comment out the wings image for now
ProbablePrime Jul 20, 2025
bbbf9ff
tweak(tests): list the roundtrip ones as smoke tests
ProbablePrime Jul 20, 2025
fbabe1e
tweak(utilties): automatically dispose of the set if enabled?
ProbablePrime Jul 20, 2025
f79555c
feat(*): new natives
ProbablePrime Jul 20, 2025
ce8a86f
fix(linux): additional new natives
ProbablePrime Jul 20, 2025
d52c8b8
tweak(tests): mark NativeTests as smoke
ProbablePrime Jul 20, 2025
a5331a5
fix(ci): on linux install Sssimulacra deps
ProbablePrime Jul 20, 2025
342f13b
fix(linux): rpath updates from native land
ProbablePrime Jul 21, 2025
c3a1cec
fix(linux): temporarily log some stuff to help identify issues
ProbablePrime Jul 21, 2025
60cab5c
fix(linux): new natives with double free bug fixed
ProbablePrime Jul 21, 2025
d7a2269
fix(CMP_MipLevel): skeleton dispose code to start looking at the cras…
ProbablePrime Jul 21, 2025
dc6970a
fix(CMP_MIPLevel): we should not be de-allocating this manually. Leav…
ProbablePrime Jul 21, 2025
fc10e28
fix(tests): do not new a CMP_MipLevel
ProbablePrime Jul 21, 2025
4febd84
tweak(tests): tag all roundtrip as smoke
ProbablePrime Jul 21, 2025
5eece93
fix(linux): finally resolve the CMP_MIP freeing issues.
ProbablePrime Jul 21, 2025
310477c
fix(ci): back to running the full tests
ProbablePrime Jul 21, 2025
84aa5e9
fixup!: cleanup logs
ProbablePrime Jul 21, 2025
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
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ jobs:
- uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.x
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- uses: gerlero/apt-install@v1
if: startsWith(matrix.os, 'ubuntu') == true
with:
packages: libhwy-dev liblcms2-dev libjpeg-turbo8-dev libpng-dev libjpeg-dev zlib1g-dev libgif-dev
- name: Test
run: dotnet test --no-restore --configuration Release
run: dotnet test --no-restore --configuration Release --filter CI!=false --logger "console;verbosity=detailed"
- name: Upload Test Results
if: failure()
uses: actions/upload-artifact@v4
Expand Down
1 change: 1 addition & 0 deletions Compressonator.NET.Tests/Compressonator.NET.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="MSTest" Version="3.8.3" />
<PackageReference Include="Verify.MSTest" Version="30.0.0" />
<PackageReference Include="YellowDogMan.ssimulacra2.NET" Version="0.1.1" />
<PackageReference Include="YellowDogMan.Verify.Marshaling" Version="0.2.0" />
</ItemGroup>

Expand Down
3 changes: 2 additions & 1 deletion Compressonator.NET.Tests/EnumTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ public class EnumTests
// If there's an enum mismatch, it can lead to unreliable undefined behavior.
// We test both classes, because they use different compilation chains, and could get out of sync.
[TestEnum(typeof(CMP_FORMAT))]
[DataTestMethod]
[TestMethod]
[TestProperty("CI", "true")]
public void TestCMP_FORMAT(CMP_FORMAT format)
{
Assert.IsTrue(SDK_NativeMethods.CMP_IsValidFormat(format), $"CMP_Format must be valid for: {format}");
Expand Down
30 changes: 30 additions & 0 deletions Compressonator.NET.Tests/GCAsset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace Compressonator.NET.Tests;

// Please don't use this outside of tests.
// Largely from: https://stackoverflow.com/a/9827349 + other answers on the same question.
// Also: https://stackoverflow.com/questions/3829928/under-what-circumstances-we-need-to-call-gc-collect-twice from why we GC.Collect Twice.
internal static class GCAssert
{
public static void AssertGarbageCollectable<T>(Func<T> create)
where T : class
{
WeakReference reference = CreateAndDropReference(create);

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

Assert.IsFalse(reference.IsAlive, $"{typeof(T).Name} should have been garbage collected");
}

private static WeakReference CreateAndDropReference<T>(Func<T> create)
where T : class
{
var obj = create();

if (obj is IDisposable disposable)
disposable.Dispose();

return new WeakReference(obj);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
FieldName: CMP_Texture,
Size: 48,
Nested: [
{
FieldName: size,
Size: 4,
Type: UInt32
},
{
FieldName: width,
Size: 4,
Offset: 4,
Type: UInt32
},
{
FieldName: height,
Size: 4,
Offset: 8,
Type: UInt32
},
{
FieldName: pitch,
Size: 4,
Offset: 12,
Type: UInt32
},
{
FieldName: format,
Size: 4,
Offset: 16,
Type: CMP_FORMAT
},
{
FieldName: transcodeFormat,
Size: 4,
Offset: 20,
Type: CMP_FORMAT
},
{
FieldName: blockHeight,
Size: 1,
Offset: 24,
Type: Byte
},
{
FieldName: blockWidth,
Size: 1,
Offset: 25,
Type: Byte
},
{
FieldName: blockDepth,
Size: 1,
Offset: 26,
Type: Byte
},
{
FieldName: dataSize,
Size: 4,
Offset: 28,
Type: UInt32
},
{
FieldName: data,
Size: 8,
Offset: 32,
Type: IntPtr
},
{
FieldName: mipSet,
Size: 8,
Offset: 40,
Type: IntPtr
}
],
Type: struct
}
2 changes: 1 addition & 1 deletion Compressonator.NET.Tests/Marshaling/MarshalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ public void TestCMP_FORMAT()
[DataRow(12, typeof(KernelPerformanceStats))]
[DataRow(388, typeof(KernelDeviceInfo))]
[DataRow(48, typeof(AMD_CMD))]
[DataRow(48, typeof(CMP_Texture))]
[DataTestMethod]
public async Task TestStructs(int correctSize, Type t)
{
Assert.AreEqual(correctSize, Marshal.SizeOf(t), $"{nameof(t)} must marshal as {correctSize} bytes");

await VerifyMemoryLayout(t);
}
}
59 changes: 59 additions & 0 deletions Compressonator.NET.Tests/NativeTests.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
namespace Compressonator.NET.Tests;

[TestCategory("Smoke")]
[TestClass]
public sealed class NativeTests
{
[TestMethod]
[Priority(1)]
[TestProperty("CI", "true")]
public void TestSDKNative()
{
Assert.IsTrue(SDK_NativeMethods.IsSupported, "SDK Native methods should be supported");
}

[TestMethod]
[Priority(1)]
[TestProperty("CI", "true")]
public void TestFrameworkNative()
{
Assert.IsTrue(FrameworkNativeMethods.IsSupported, "Framework Native Methods should be supported.");
Expand All @@ -18,9 +23,63 @@ public void TestFrameworkNative()
/// <summary>
/// Test that this method just doesn't throw any exceptions.
/// </summary>
[TestProperty("CI", "true")]
[TestMethod]
public void TestLibraryInitialization()
{
FrameworkNativeMethods.CMP_InitFramework();
}

[TestProperty("CI", "true")]
[TestMethod]
// This was causing some CI Crashes, let's write a test
public void TestFreeingMipMaps()
{
var mip = new CMP_MipSet();
mip.Dispose();

// We don't have any assertions, it just must not throw.
}

[TestProperty("CI", "true")]
[TestMethod]
// This was causing some CI Crashes, let's write a test
public void TestFreeingMipMapsMultipleTimes()
{
var mip = new CMP_MipSet();
FrameworkNativeMethods.CMP_FreeMipSet(mip);
FrameworkNativeMethods.CMP_FreeMipSet(mip);

// We don't have any assertions, it just must not throw.
}

[TestProperty("CI", "true")]
[TestMethod]
// This was causing some CI Crashes, let's write a test
public void TestMipSetDisposeTwice()
{
var mip = new CMP_MipSet();
mip.Dispose();
mip.Dispose();

// We don't have any assertions, it just must not throw.
}

// The structure of GCAssert.AssertGarbageCollectable requires a factory due to its use of WeakReferences
// This structure, wraps the factory in a nice way, that's easier to type :)
public static IEnumerable<object[]> GCTests()
{
static object[] w<T>(Func<T> factory) where T : class => new object[] { typeof(T), factory };

yield return w(() => new CMP_MipSet());
yield return w(() => new CMP_Texture());
}

[TestMethod]
[TestProperty("CI", "true")]
[DynamicData(nameof(GCTests))]
public void TestGC(Type t, Func<object> typeCreator)
{
GCAssert.AssertGarbageCollectable(typeCreator);
}
}
29 changes: 11 additions & 18 deletions Compressonator.NET.Tests/Snapshot/CompressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Compressonator.NET.Tests.Snapshot;
[TestClass]
public class CompressionTests : SnapshotTestingBase
{
public const CMP_FORMAT DEFAULT_SOURCE_FORMAT = CMP_FORMAT.RGBA_8888;
public const CMP_FORMAT DEFAULT_SOURCE_FORMAT = SnapshotUtilities.DEFAULT_SOURCE_FORMAT;

public const float DEFAULT_BC67COMPRESSION_QUALITY = 0.05f;
public const float RESONITE_BC67COMPRESSION_QUALITY = 0.6f;
Expand Down Expand Up @@ -68,7 +68,7 @@ public class CompressionTests : SnapshotTestingBase
[DataRow(CMP_FORMAT.BC7, DEFAULT_SOURCE_FORMAT, "Resources/flowers.png", RESONITE_BC67COMPRESSION_QUALITY)]
[DataRow(CMP_FORMAT.BC7, DEFAULT_SOURCE_FORMAT, "Resources/helicopter.png", RESONITE_BC67COMPRESSION_QUALITY)]


[TestProperty("CI", "true")]
[DataTestMethod]
public async Task TestCompression(
CMP_FORMAT targetFormat,
Expand All @@ -82,17 +82,14 @@ public async Task TestCompression(
// see: https://github.com/Yellow-Dog-Man/Compressonator.NET/issues/20
settings.UniqueForOSPlatform();

if (IsSlow(targetFormat))
{
if (quality > DEFAULT_BC67COMPRESSION_QUALITY)
Assert.Inconclusive($"BC6H & BC7 Tests at higher qualities than {DEFAULT_BC67COMPRESSION_QUALITY} due to how long they take.");
}
TestUtilities.GuardCITests(targetFormat, quality);

//// see: https://github.com/Yellow-Dog-Man/Compressonator.NET/issues/21
//if (targetFormat == CMP_FORMAT.BC2 && inputFileRelativePath == "Resources/rainbow.png")
// settings.UniqueForOSPlatform();

var (res, mipSetIn) = SnapshotUtilities.Load(inputFileRelativePath, targetFormat, sourceFormat);
var (res, mipSetIn) = SnapshotUtilities.Load(inputFileRelativePath, sourceFormat, mipLevels: 3);
Assert.IsTrue(SDK_NativeMethods.CMP_IsValidFormat(targetFormat), "Target format must be supported by native library");

CMP_MipSet mipSetOut = new();
CMP_ERROR cmpStatus = CMP_ERROR.CMP_OK;
Expand All @@ -119,28 +116,24 @@ public async Task TestCompression(
[DataRow(CMP_FORMAT.BC5, DEFAULT_SOURCE_FORMAT, "Resources/rainbow.png")]
[DataRow(CMP_FORMAT.BC6H, DEFAULT_SOURCE_FORMAT, "Resources/rainbow.png")]
[DataRow(CMP_FORMAT.BC7, DEFAULT_SOURCE_FORMAT, "Resources/rainbow.png")]
[DataTestMethod]
[TestMethod]
[TestProperty("CI", "true")]
public async Task TestProcessTexture(CMP_FORMAT targetFormat,
CMP_FORMAT sourceFormat,
string inputFileRelativePath,
float quality = 0.9f,
uint maxThreads = 0)
{
TestUtilities.GuardCITests(targetFormat, quality);
VerifySettings settings = new VerifySettings();
// see: https://github.com/Yellow-Dog-Man/Compressonator.NET/issues/21
if (targetFormat == CMP_FORMAT.BC2 && inputFileRelativePath == "Resources/rainbow.png")
settings.UniqueForOSPlatform();

if (IsSlow(targetFormat))
{
settings.UniqueForOSPlatform();
// See: https://github.com/Yellow-Dog-Man/Compressonator.NET/issues/17
// See; https://github.com/Yellow-Dog-Man/compressonator/issues/10
Assert.Inconclusive("BC6H & BC67 Tests are disabled for this test.");
}



var (res, mipSetIn) = SnapshotUtilities.Load(inputFileRelativePath, targetFormat, sourceFormat);
var (res, mipSetIn) = SnapshotUtilities.Load(inputFileRelativePath, sourceFormat);
Assert.IsTrue(SDK_NativeMethods.CMP_IsValidFormat(targetFormat), "Target format must be supported by native library");

CMP_MipSet mipSetOut = new();
CMP_ERROR cmpStatus = CMP_ERROR.CMP_OK;
Expand Down
60 changes: 60 additions & 0 deletions Compressonator.NET.Tests/Snapshot/QualityEvaluationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Compressonator.NET.Tests.Snapshot;

namespace Compressonator.NET.Tests;

/// <summary>
/// These tests output PNGs, rather than DDS files. This means you can more easily evaluate qualities in your browser etc.
/// </summary>
[TestClass]
public class QualityEvaluationTests: SnapshotTestingBase
{
static List<string> paths = new List<string>()
{
"Resources/rainbow.png",
"Resources/carrots.png",
"Resources/colorpatch.png",
"Resources/squares.png",

//"Resources/wings.png",
//"Resources/tulipbody.png"
};

[DataRow(CMP_FORMAT.BC1, 1f)]
[DataRow(CMP_FORMAT.BC2, 1f)]
[DataRow(CMP_FORMAT.BC3, 1f)]
[DataRow(CMP_FORMAT.BC4, 1f)]
[DataRow(CMP_FORMAT.BC5, 1f)]

[DataRow(CMP_FORMAT.BC6H, 0.05f)]
[DataRow(CMP_FORMAT.BC6H, 0.10f)]
[DataRow(CMP_FORMAT.BC6H, 0.25f)]

[DataRow(CMP_FORMAT.BC7, 0.05f)]
[DataRow(CMP_FORMAT.BC7, 0.10f)]
[DataRow(CMP_FORMAT.BC7, 0.2f)]
[DataRow(CMP_FORMAT.BC7, 0.25f)]
[TestMethod]
[TestProperty("CI", "false")]
public async Task VerifyTexture(CMP_FORMAT targetFormat, float quality, bool disabled = false)
{
TestUtilities.GuardCITests(targetFormat, quality);

if (disabled)
Assert.Inconclusive($"This test is disabled");

foreach (string path in paths)
{
var settings = new VerifySettings();
settings.UseDirectory("QualityEvaluationTests/"+ Path.GetFileName(path));
settings.UseFileName($"{targetFormat}-{quality}");

/// TMP: REMOVE IT!
settings.AutoVerify();
var distortedPath = CurrentFile.Relative(SnapshotUtilities.GetFileNameForTest("png"));

CMP_Texture distortedTexture = SnapshotUtilities.RoundTripWithCompression(path, targetFormat, quality);

await SnapshotUtilities.SaveVerifyDelete(distortedTexture, "png", settings);
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion Compressonator.NET.Tests/Snapshot/Resources/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ Renamed to keep snapshot file lengths smaller.
- rainbow.png
- noise.png
- square.png
- colorpatch.png

# Test Images
- paperclips.png
The images in this archive are part of the TESTIMAGES project: http://testimages.tecnick.com
The images in this archive are part of the TESTIMAGES project: https://testimages.org/
Copyright (C) 2011-2014 Nicola Asuni - Tecnick.com LTD

# Misc
Expand Down
Loading